Files
golib/ezconf/ezconf.go

132 lines
3.9 KiB
Go

package ezconf
import (
"os"
"github.com/pkg/errors"
)
// EnvVar represents a single environment variable with its metadata
type EnvVar struct {
Name string // The environment variable name (e.g., "LOG_LEVEL")
Description string // Description of what this variable does
Required bool // Whether this variable is required
Default string // Default value if not set
CurrentValue string // Current value from environment (empty if not set)
Group string // Group name for organizing variables (e.g., "Database", "Logging")
}
// ConfigLoader manages configuration loading from multiple sources
type ConfigLoader struct {
configFuncs map[string]ConfigFunc // Map of config names to ConfigFromEnv functions
packagePaths []string // Paths to packages to parse for ENV comments
groupNames map[string]string // Map of package paths to group names
extraEnvVars []EnvVar // Additional environment variables to track
envVars []EnvVar // All extracted environment variables
configs map[string]interface{} // Loaded configurations
}
// ConfigFunc is a function that loads configuration from environment variables
type ConfigFunc func() (interface{}, error)
// New creates a new ConfigLoader
func New() *ConfigLoader {
return &ConfigLoader{
configFuncs: make(map[string]ConfigFunc),
packagePaths: make([]string, 0),
groupNames: make(map[string]string),
extraEnvVars: make([]EnvVar, 0),
envVars: make([]EnvVar, 0),
configs: make(map[string]interface{}),
}
}
// AddConfigFunc adds a ConfigFromEnv function to be called during loading.
// The name parameter is used as a key to retrieve the loaded config later.
func (cl *ConfigLoader) AddConfigFunc(name string, fn ConfigFunc) error {
if fn == nil {
return errors.New("config function cannot be nil")
}
if name == "" {
return errors.New("config name cannot be empty")
}
cl.configFuncs[name] = fn
return nil
}
// AddPackagePath adds a package directory path to parse for ENV comments
func (cl *ConfigLoader) AddPackagePath(path string) error {
if path == "" {
return errors.New("package path cannot be empty")
}
// Check if path exists
if _, err := os.Stat(path); os.IsNotExist(err) {
return errors.Errorf("package path does not exist: %s", path)
}
cl.packagePaths = append(cl.packagePaths, path)
return nil
}
// AddEnvVar adds an additional environment variable to track
func (cl *ConfigLoader) AddEnvVar(envVar EnvVar) {
cl.extraEnvVars = append(cl.extraEnvVars, envVar)
}
// Load loads all configurations and extracts environment variables
func (cl *ConfigLoader) Load() error {
// Parse packages for ENV comments
for _, pkgPath := range cl.packagePaths {
envVars, err := ParseConfigPackage(pkgPath)
if err != nil {
return errors.Wrapf(err, "failed to parse package: %s", pkgPath)
}
// Set group name for these variables from stored mapping
groupName := cl.groupNames[pkgPath]
if groupName == "" {
groupName = "Other"
}
for i := range envVars {
envVars[i].Group = groupName
}
cl.envVars = append(cl.envVars, envVars...)
}
// Add extra env vars
cl.envVars = append(cl.envVars, cl.extraEnvVars...)
// Populate current values from environment
for i := range cl.envVars {
cl.envVars[i].CurrentValue = os.Getenv(cl.envVars[i].Name)
}
// Load configurations
for name, fn := range cl.configFuncs {
cfg, err := fn()
if err != nil {
return errors.Wrapf(err, "failed to load config: %s", name)
}
cl.configs[name] = cfg
}
return nil
}
// GetConfig returns a loaded configuration by name
func (cl *ConfigLoader) GetConfig(name string) (interface{}, bool) {
cfg, ok := cl.configs[name]
return cfg, ok
}
// GetAllConfigs returns all loaded configurations
func (cl *ConfigLoader) GetAllConfigs() map[string]interface{} {
return cl.configs
}
// GetEnvVars returns all extracted environment variables
func (cl *ConfigLoader) GetEnvVars() []EnvVar {
return cl.envVars
}