120 lines
3.8 KiB
Go
120 lines
3.8 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type EffectiveConfigErrorKind string
|
|
|
|
const (
|
|
EffectiveConfigErrorResolvePath EffectiveConfigErrorKind = "resolve_path"
|
|
EffectiveConfigErrorLoadFile EffectiveConfigErrorKind = "load_file"
|
|
EffectiveConfigErrorApplyFile EffectiveConfigErrorKind = "apply_file"
|
|
EffectiveConfigErrorApplyEnv EffectiveConfigErrorKind = "apply_env"
|
|
)
|
|
|
|
type EffectiveConfigError struct {
|
|
Kind EffectiveConfigErrorKind
|
|
Err error
|
|
}
|
|
|
|
func (e *EffectiveConfigError) Error() string {
|
|
if e == nil || e.Err == nil {
|
|
return ""
|
|
}
|
|
return e.Err.Error()
|
|
}
|
|
|
|
func (e *EffectiveConfigError) Unwrap() error {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
return e.Err
|
|
}
|
|
|
|
type EffectiveConfig struct {
|
|
Config Config
|
|
ConfigPath string
|
|
ConfigSource string
|
|
ConfigVersion *int
|
|
}
|
|
|
|
func ResolveConfigPath(cliConfigPath string, cliConfigPathSet bool) (path string, source string, err error) {
|
|
return resolveConfigPathWithLookup(cliConfigPath, cliConfigPathSet, os.LookupEnv, os.Stat, DefaultConfigSearchPaths)
|
|
}
|
|
|
|
func LoadEffectiveConfig(cliConfigPath string, cliConfigPathSet bool) (EffectiveConfig, error) {
|
|
return loadEffectiveConfigWithLookup(cliConfigPath, cliConfigPathSet, os.LookupEnv, os.Stat, DefaultConfigSearchPaths)
|
|
}
|
|
|
|
func loadEffectiveConfigWithLookup(cliConfigPath string, cliConfigPathSet bool, lookup func(string) (string, bool), statPath func(string) (os.FileInfo, error), defaultSearchPaths []string) (EffectiveConfig, error) {
|
|
configPath, configSource, err := resolveConfigPathWithLookup(cliConfigPath, cliConfigPathSet, lookup, statPath, defaultSearchPaths)
|
|
if err != nil {
|
|
return EffectiveConfig{}, &EffectiveConfigError{Kind: EffectiveConfigErrorResolvePath, Err: err}
|
|
}
|
|
|
|
cfg := Default()
|
|
var configVersion *int
|
|
if configPath != "" {
|
|
fileCfg, fileErr := LoadFileConfig(configPath)
|
|
if fileErr != nil {
|
|
return EffectiveConfig{}, &EffectiveConfigError{Kind: EffectiveConfigErrorLoadFile, Err: fileErr}
|
|
}
|
|
if applyErr := cfg.ApplyFileConfig(fileCfg); applyErr != nil {
|
|
return EffectiveConfig{}, &EffectiveConfigError{Kind: EffectiveConfigErrorApplyFile, Err: applyErr}
|
|
}
|
|
configVersion = &fileCfg.Version
|
|
}
|
|
if applyEnvErr := cfg.applyEnvOverrides(lookup); applyEnvErr != nil {
|
|
return EffectiveConfig{}, &EffectiveConfigError{Kind: EffectiveConfigErrorApplyEnv, Err: applyEnvErr}
|
|
}
|
|
|
|
return EffectiveConfig{
|
|
Config: cfg,
|
|
ConfigPath: configPath,
|
|
ConfigSource: configSource,
|
|
ConfigVersion: configVersion,
|
|
}, nil
|
|
}
|
|
|
|
func resolveConfigPathWithLookup(cliConfigPath string, cliConfigPathSet bool, lookup func(string) (string, bool), statPath func(string) (os.FileInfo, error), defaultSearchPaths []string) (path string, source string, err error) {
|
|
if cliConfigPathSet {
|
|
path = strings.TrimSpace(cliConfigPath)
|
|
if path == "" {
|
|
return "", "", fmt.Errorf("--config requires a non-empty path")
|
|
}
|
|
if _, statErr := statPath(path); statErr != nil {
|
|
if os.IsNotExist(statErr) {
|
|
return "", "", fmt.Errorf("config file not found: %s", path)
|
|
}
|
|
return "", "", fmt.Errorf("cannot access config file %s: %w", path, statErr)
|
|
}
|
|
return path, "flag", nil
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_CONFIG"); ok {
|
|
path = strings.TrimSpace(raw)
|
|
if path == "" {
|
|
return "", "", fmt.Errorf("AUDITA_CONFIG must not be empty")
|
|
}
|
|
if _, statErr := statPath(path); statErr != nil {
|
|
if os.IsNotExist(statErr) {
|
|
return "", "", fmt.Errorf("config file not found: %s", path)
|
|
}
|
|
return "", "", fmt.Errorf("cannot access config file %s: %w", path, statErr)
|
|
}
|
|
return path, "env", nil
|
|
}
|
|
|
|
for _, defaultPath := range defaultSearchPaths {
|
|
if _, statErr := statPath(defaultPath); statErr == nil {
|
|
return defaultPath, "default", nil
|
|
} else if !os.IsNotExist(statErr) {
|
|
return "", "", fmt.Errorf("cannot access config file %s: %w", defaultPath, statErr)
|
|
}
|
|
}
|
|
return "", "", nil
|
|
}
|