mirror of
https://github.com/taigrr/jety.git
synced 2026-04-02 03:19:03 -07:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7335ecd39c | |||
| 4c8d8960be |
23
jety.go
23
jety.go
@@ -4,7 +4,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -33,7 +32,8 @@ type (
|
|||||||
configPath string
|
configPath string
|
||||||
configFileUsed string
|
configFileUsed string
|
||||||
configType configType
|
configType configType
|
||||||
mapConfig map[string]ConfigMap
|
overrideConfig map[string]ConfigMap
|
||||||
|
fileConfig map[string]ConfigMap
|
||||||
defaultConfig map[string]ConfigMap
|
defaultConfig map[string]ConfigMap
|
||||||
envConfig map[string]ConfigMap
|
envConfig map[string]ConfigMap
|
||||||
combinedConfig map[string]ConfigMap
|
combinedConfig map[string]ConfigMap
|
||||||
@@ -50,7 +50,8 @@ var (
|
|||||||
func NewConfigManager() *ConfigManager {
|
func NewConfigManager() *ConfigManager {
|
||||||
cm := ConfigManager{}
|
cm := ConfigManager{}
|
||||||
cm.envConfig = make(map[string]ConfigMap)
|
cm.envConfig = make(map[string]ConfigMap)
|
||||||
cm.mapConfig = make(map[string]ConfigMap)
|
cm.overrideConfig = make(map[string]ConfigMap)
|
||||||
|
cm.fileConfig = make(map[string]ConfigMap)
|
||||||
cm.defaultConfig = make(map[string]ConfigMap)
|
cm.defaultConfig = make(map[string]ConfigMap)
|
||||||
cm.combinedConfig = make(map[string]ConfigMap)
|
cm.combinedConfig = make(map[string]ConfigMap)
|
||||||
envSet := os.Environ()
|
envSet := os.Environ()
|
||||||
@@ -99,13 +100,21 @@ func (c *ConfigManager) collapse() {
|
|||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
ccm := make(map[string]ConfigMap)
|
ccm := make(map[string]ConfigMap)
|
||||||
|
// Precedence (highest to lowest): overrides (Set) > env > file > defaults
|
||||||
for k, v := range c.defaultConfig {
|
for k, v := range c.defaultConfig {
|
||||||
ccm[k] = v
|
ccm[k] = v
|
||||||
if _, ok := c.envConfig[k]; ok {
|
}
|
||||||
ccm[k] = c.envConfig[k]
|
for k, v := range c.fileConfig {
|
||||||
|
ccm[k] = v
|
||||||
|
}
|
||||||
|
for k := range c.defaultConfig {
|
||||||
|
if v, ok := c.envConfig[k]; ok {
|
||||||
|
ccm[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maps.Copy(ccm, c.mapConfig)
|
for k, v := range c.overrideConfig {
|
||||||
|
ccm[k] = v
|
||||||
|
}
|
||||||
c.combinedConfig = ccm
|
c.combinedConfig = ccm
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +225,7 @@ func (c *ConfigManager) ReadInConfig() error {
|
|||||||
conf[lower] = ConfigMap{Key: k, Value: v}
|
conf[lower] = ConfigMap{Key: k, Value: v}
|
||||||
}
|
}
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
c.mapConfig = conf
|
c.fileConfig = conf
|
||||||
c.configFileUsed = configFile
|
c.configFileUsed = configFile
|
||||||
c.mutex.Unlock()
|
c.mutex.Unlock()
|
||||||
c.collapse()
|
c.collapse()
|
||||||
|
|||||||
60
jety_test.go
60
jety_test.go
@@ -66,7 +66,7 @@ func TestNewConfigManager(t *testing.T) {
|
|||||||
if cm.envConfig == nil {
|
if cm.envConfig == nil {
|
||||||
t.Error("envConfig not initialized")
|
t.Error("envConfig not initialized")
|
||||||
}
|
}
|
||||||
if cm.mapConfig == nil {
|
if cm.overrideConfig == nil {
|
||||||
t.Error("mapConfig not initialized")
|
t.Error("mapConfig not initialized")
|
||||||
}
|
}
|
||||||
if cm.defaultConfig == nil {
|
if cm.defaultConfig == nil {
|
||||||
@@ -554,7 +554,7 @@ func TestEnvOverridesDefault(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigFileOverridesEnv(t *testing.T) {
|
func TestEnvOverridesConfigFile(t *testing.T) {
|
||||||
os.Setenv("PORT", "5000")
|
os.Setenv("PORT", "5000")
|
||||||
defer os.Unsetenv("PORT")
|
defer os.Unsetenv("PORT")
|
||||||
|
|
||||||
@@ -575,9 +575,9 @@ func TestConfigFileOverridesEnv(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config file should override env and default
|
// Env should override config file (env > file > defaults)
|
||||||
if got := cm.GetInt("port"); got != 9000 {
|
if got := cm.GetInt("port"); got != 5000 {
|
||||||
t.Errorf("GetInt(port) = %d, want 9000 (from file)", got)
|
t.Errorf("GetInt(port) = %d, want 5000 (env overrides file)", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1347,3 +1347,53 @@ func TestPackageLevelSetEnvPrefixOverrides(t *testing.T) {
|
|||||||
t.Fatalf("subprocess failed: %v\n%s", err, out)
|
t.Fatalf("subprocess failed: %v\n%s", err, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrecedenceChain(t *testing.T) {
|
||||||
|
// Verify: Set > env > file > defaults
|
||||||
|
os.Setenv("PORT", "5000")
|
||||||
|
os.Setenv("HOST", "envhost")
|
||||||
|
os.Setenv("LOG", "envlog")
|
||||||
|
defer os.Unsetenv("PORT")
|
||||||
|
defer os.Unsetenv("HOST")
|
||||||
|
defer os.Unsetenv("LOG")
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
configFile := filepath.Join(dir, "config.yaml")
|
||||||
|
if err := os.WriteFile(configFile, []byte("port: 9000\nhost: filehost\nlog: filelog\nname: filename"), 0o644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cm := NewConfigManager()
|
||||||
|
cm.SetDefault("port", 8080)
|
||||||
|
cm.SetDefault("host", "defaulthost")
|
||||||
|
cm.SetDefault("log", "defaultlog")
|
||||||
|
cm.SetDefault("name", "defaultname")
|
||||||
|
cm.SetDefault("extra", "defaultextra")
|
||||||
|
|
||||||
|
cm.SetConfigFile(configFile)
|
||||||
|
if err := cm.SetConfigType("yaml"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := cm.ReadInConfig(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cm.Set("port", 1111) // Set overrides everything
|
||||||
|
|
||||||
|
// port: Set(1111) > env(5000) > file(9000) > default(8080) → 1111
|
||||||
|
if got := cm.GetInt("port"); got != 1111 {
|
||||||
|
t.Errorf("port: got %d, want 1111 (Set overrides all)", got)
|
||||||
|
}
|
||||||
|
// host: env(envhost) > file(filehost) > default(defaulthost) → envhost
|
||||||
|
if got := cm.GetString("host"); got != "envhost" {
|
||||||
|
t.Errorf("host: got %q, want envhost (env overrides file)", got)
|
||||||
|
}
|
||||||
|
// name: file(filename) > default(defaultname) → filename
|
||||||
|
if got := cm.GetString("name"); got != "filename" {
|
||||||
|
t.Errorf("name: got %q, want filename (file overrides default)", got)
|
||||||
|
}
|
||||||
|
// extra: only default → defaultextra
|
||||||
|
if got := cm.GetString("extra"); got != "defaultextra" {
|
||||||
|
t.Errorf("extra: got %q, want defaultextra (default)", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
12
setters.go
12
setters.go
@@ -8,7 +8,7 @@ func (c *ConfigManager) SetBool(key string, value bool) {
|
|||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
lower := strings.ToLower(key)
|
lower := strings.ToLower(key)
|
||||||
c.mapConfig[lower] = ConfigMap{Key: key, Value: value}
|
c.overrideConfig[lower] = ConfigMap{Key: key, Value: value}
|
||||||
c.combinedConfig[lower] = ConfigMap{Key: key, Value: value}
|
c.combinedConfig[lower] = ConfigMap{Key: key, Value: value}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ func (c *ConfigManager) SetString(key string, value string) {
|
|||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
lower := strings.ToLower(key)
|
lower := strings.ToLower(key)
|
||||||
c.mapConfig[lower] = ConfigMap{Key: key, Value: value}
|
c.overrideConfig[lower] = ConfigMap{Key: key, Value: value}
|
||||||
c.combinedConfig[lower] = ConfigMap{Key: key, Value: value}
|
c.combinedConfig[lower] = ConfigMap{Key: key, Value: value}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ func (c *ConfigManager) Set(key string, value any) {
|
|||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
lower := strings.ToLower(key)
|
lower := strings.ToLower(key)
|
||||||
c.mapConfig[lower] = ConfigMap{Key: key, Value: value}
|
c.overrideConfig[lower] = ConfigMap{Key: key, Value: value}
|
||||||
c.combinedConfig[lower] = ConfigMap{Key: key, Value: value}
|
c.combinedConfig[lower] = ConfigMap{Key: key, Value: value}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,14 +33,14 @@ func (c *ConfigManager) SetDefault(key string, value any) {
|
|||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
lower := strings.ToLower(key)
|
lower := strings.ToLower(key)
|
||||||
c.defaultConfig[lower] = ConfigMap{Key: key, Value: value}
|
c.defaultConfig[lower] = ConfigMap{Key: key, Value: value}
|
||||||
if _, ok := c.mapConfig[lower]; !ok {
|
if _, ok := c.overrideConfig[lower]; !ok {
|
||||||
if envVal, ok := c.envConfig[lower]; ok {
|
if envVal, ok := c.envConfig[lower]; ok {
|
||||||
c.mapConfig[lower] = ConfigMap{Key: key, Value: envVal.Value}
|
c.overrideConfig[lower] = ConfigMap{Key: key, Value: envVal.Value}
|
||||||
c.combinedConfig[lower] = ConfigMap{Key: key, Value: envVal.Value}
|
c.combinedConfig[lower] = ConfigMap{Key: key, Value: envVal.Value}
|
||||||
} else {
|
} else {
|
||||||
c.combinedConfig[lower] = ConfigMap{Key: key, Value: value}
|
c.combinedConfig[lower] = ConfigMap{Key: key, Value: value}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.combinedConfig[lower] = c.mapConfig[lower]
|
c.combinedConfig[lower] = c.overrideConfig[lower]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user