mirror of
https://github.com/spf13/viper
synced 2024-12-22 11:37:02 +00:00
fix slice usage with env variables
This commit is contained in:
parent
568aa46942
commit
e01b6d7d0e
2 changed files with 48 additions and 12 deletions
58
viper.go
58
viper.go
|
@ -28,6 +28,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -692,52 +693,85 @@ func (v *Viper) searchMap(source map[string]any, path []string) any {
|
|||
// searchMapWithAliases recursively searches for slice field in source map and
|
||||
// replace them with the environment variable value if it exists.
|
||||
//
|
||||
// Returns replaced values.
|
||||
func (v *Viper) searchAndReplaceSliceValueWithEnv(source any, envKey string) any {
|
||||
// Returns replaced values, and a boolean if the value was found in
|
||||
// environment varaible.
|
||||
func (v *Viper) searchAndReplaceSliceValueWithEnv(source any, envKey string) (any, bool) {
|
||||
|
||||
switch sourceValue := source.(type) {
|
||||
case []any:
|
||||
var newSliceValues []any
|
||||
for i, sliceValue := range sourceValue {
|
||||
if len(sourceValue) <= 0 {
|
||||
return newSliceValues, false
|
||||
|
||||
}
|
||||
|
||||
var exists []bool
|
||||
for i := 0; ; i++ {
|
||||
envKey := envKey + v.keyDelim + strconv.Itoa(i)
|
||||
switch existingValue := sliceValue.(type) {
|
||||
var value any
|
||||
var existDefault = true
|
||||
if len(sourceValue) < i+1 {
|
||||
value = sourceValue[0]
|
||||
existDefault = false
|
||||
} else {
|
||||
value = sourceValue[i]
|
||||
}
|
||||
switch existingValue := value.(type) {
|
||||
case map[string]any:
|
||||
newVal := v.searchAndReplaceSliceValueWithEnv(existingValue, envKey)
|
||||
newVal, found := v.searchAndReplaceSliceValueWithEnv(existingValue, envKey)
|
||||
if !found && !existDefault {
|
||||
return newSliceValues, slices.Contains(exists, true)
|
||||
}
|
||||
newSliceValues = append(newSliceValues, newVal)
|
||||
exists = append(exists, found || existDefault)
|
||||
|
||||
default:
|
||||
if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
|
||||
newSliceValues = append(newSliceValues, newVal)
|
||||
exists = append(exists, true)
|
||||
} else {
|
||||
newSliceValues = append(newSliceValues, existingValue)
|
||||
exists = append(exists, false || existDefault)
|
||||
if existDefault {
|
||||
newSliceValues = append(newSliceValues, existingValue)
|
||||
} else {
|
||||
return newSliceValues, slices.Contains(exists, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return newSliceValues
|
||||
return newSliceValues, slices.Contains(exists, true)
|
||||
|
||||
case map[string]any:
|
||||
var newMapValues map[string]any = make(map[string]any)
|
||||
var exists []bool
|
||||
for key, mapValue := range sourceValue {
|
||||
envKey := envKey + v.keyDelim + key
|
||||
switch existingValue := mapValue.(type) {
|
||||
case map[string]any:
|
||||
newVal := v.searchAndReplaceSliceValueWithEnv(existingValue, envKey)
|
||||
newVal, found := v.searchAndReplaceSliceValueWithEnv(existingValue, envKey)
|
||||
if !found {
|
||||
return newMapValues, false
|
||||
}
|
||||
newMapValues[key] = newVal
|
||||
exists = append(exists, found)
|
||||
|
||||
default:
|
||||
if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
|
||||
newMapValues[key] = newVal
|
||||
exists = append(exists, true)
|
||||
} else {
|
||||
exists = append(exists, false)
|
||||
newMapValues[key] = existingValue
|
||||
}
|
||||
}
|
||||
}
|
||||
return newMapValues
|
||||
return newMapValues, slices.Contains(exists, true)
|
||||
|
||||
default:
|
||||
if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
|
||||
return newVal
|
||||
return newVal, true
|
||||
} else {
|
||||
return source
|
||||
return source, false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -961,7 +995,7 @@ func (v *Viper) Get(key string) any {
|
|||
|
||||
// Check for Env override again, to handle slices
|
||||
if v.automaticEnvApplied {
|
||||
val = v.searchAndReplaceSliceValueWithEnv(val, lcaseKey)
|
||||
val, _ = v.searchAndReplaceSliceValueWithEnv(val, lcaseKey)
|
||||
}
|
||||
|
||||
if v.typeByDefValue {
|
||||
|
|
|
@ -2668,6 +2668,7 @@ func TestSliceIndexAutomaticEnv(t *testing.T) {
|
|||
t.Setenv("MODES_2", "300")
|
||||
t.Setenv("CLIENTS_1_NAME", "baz")
|
||||
t.Setenv("PROXY_CLIENTS_0_NAME", "ProxyFoo")
|
||||
t.Setenv("PROXY_CLIENTS_3_NAME", "ProxyNew")
|
||||
|
||||
SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
AutomaticEnv()
|
||||
|
@ -2683,6 +2684,7 @@ func TestSliceIndexAutomaticEnv(t *testing.T) {
|
|||
assert.Equal(t, "foo", config.Clients[0].Name)
|
||||
assert.Equal(t, "baz", config.Clients[1].Name)
|
||||
assert.Equal(t, "ProxyFoo", config.Proxy.Clients[0].Name)
|
||||
assert.Equal(t, "ProxyNew", config.Proxy.Clients[3].Name)
|
||||
}
|
||||
|
||||
func TestIsPathShadowedInFlatMap(t *testing.T) {
|
||||
|
|
Loading…
Reference in a new issue