fix slice usage with env variables

This commit is contained in:
Theo Brigitte 2024-03-18 16:36:56 +01:00
parent 568aa46942
commit e01b6d7d0e
No known key found for this signature in database
GPG key ID: 62A81E0F3445587C
2 changed files with 48 additions and 12 deletions

View file

@ -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 {

View file

@ -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) {