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" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"slices"
"strconv" "strconv"
"strings" "strings"
"sync" "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 // searchMapWithAliases recursively searches for slice field in source map and
// replace them with the environment variable value if it exists. // replace them with the environment variable value if it exists.
// //
// Returns replaced values. // Returns replaced values, and a boolean if the value was found in
func (v *Viper) searchAndReplaceSliceValueWithEnv(source any, envKey string) any { // environment varaible.
func (v *Viper) searchAndReplaceSliceValueWithEnv(source any, envKey string) (any, bool) {
switch sourceValue := source.(type) { switch sourceValue := source.(type) {
case []any: case []any:
var newSliceValues []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) 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: 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) newSliceValues = append(newSliceValues, newVal)
exists = append(exists, found || existDefault)
default: default:
if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok { if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
newSliceValues = append(newSliceValues, newVal) newSliceValues = append(newSliceValues, newVal)
exists = append(exists, true)
} else { } 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: case map[string]any:
var newMapValues map[string]any = make(map[string]any) var newMapValues map[string]any = make(map[string]any)
var exists []bool
for key, mapValue := range sourceValue { for key, mapValue := range sourceValue {
envKey := envKey + v.keyDelim + key envKey := envKey + v.keyDelim + key
switch existingValue := mapValue.(type) { switch existingValue := mapValue.(type) {
case map[string]any: case map[string]any:
newVal := v.searchAndReplaceSliceValueWithEnv(existingValue, envKey) newVal, found := v.searchAndReplaceSliceValueWithEnv(existingValue, envKey)
if !found {
return newMapValues, false
}
newMapValues[key] = newVal newMapValues[key] = newVal
exists = append(exists, found)
default: default:
if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok { if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
newMapValues[key] = newVal newMapValues[key] = newVal
exists = append(exists, true)
} else { } else {
exists = append(exists, false)
newMapValues[key] = existingValue newMapValues[key] = existingValue
} }
} }
} }
return newMapValues return newMapValues, slices.Contains(exists, true)
default: default:
if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok { if newVal, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
return newVal return newVal, true
} else { } 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 // Check for Env override again, to handle slices
if v.automaticEnvApplied { if v.automaticEnvApplied {
val = v.searchAndReplaceSliceValueWithEnv(val, lcaseKey) val, _ = v.searchAndReplaceSliceValueWithEnv(val, lcaseKey)
} }
if v.typeByDefValue { if v.typeByDefValue {

View file

@ -2668,6 +2668,7 @@ func TestSliceIndexAutomaticEnv(t *testing.T) {
t.Setenv("MODES_2", "300") t.Setenv("MODES_2", "300")
t.Setenv("CLIENTS_1_NAME", "baz") t.Setenv("CLIENTS_1_NAME", "baz")
t.Setenv("PROXY_CLIENTS_0_NAME", "ProxyFoo") t.Setenv("PROXY_CLIENTS_0_NAME", "ProxyFoo")
t.Setenv("PROXY_CLIENTS_3_NAME", "ProxyNew")
SetEnvKeyReplacer(strings.NewReplacer(".", "_")) SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
AutomaticEnv() AutomaticEnv()
@ -2683,6 +2684,7 @@ func TestSliceIndexAutomaticEnv(t *testing.T) {
assert.Equal(t, "foo", config.Clients[0].Name) assert.Equal(t, "foo", config.Clients[0].Name)
assert.Equal(t, "baz", config.Clients[1].Name) assert.Equal(t, "baz", config.Clients[1].Name)
assert.Equal(t, "ProxyFoo", config.Proxy.Clients[0].Name) assert.Equal(t, "ProxyFoo", config.Proxy.Clients[0].Name)
assert.Equal(t, "ProxyNew", config.Proxy.Clients[3].Name)
} }
func TestIsPathShadowedInFlatMap(t *testing.T) { func TestIsPathShadowedInFlatMap(t *testing.T) {