Merge pull request #24 from DataDog/maxime/add-all-settings-without-default

Add a AllSettingsWithoutDefault method
This commit is contained in:
maxime mouial 2022-07-13 14:25:48 +02:00 committed by GitHub
commit bd499f9c47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 83 additions and 15 deletions

View file

@ -609,15 +609,36 @@ func (v *Viper) Get(key string) interface{} {
return val return val
} }
// GetSkipDefault returns an interface. For a specific value use one of the Get____ methods.
func GetSkipDefault(key string) interface{} { return v.GetSkipDefault(key) }
func (v *Viper) GetSkipDefault(key string) interface{} {
val, _ := v.GetESkipDefault(key)
return val
}
// GetE is like Get but also returns parsing errors. // GetE is like Get but also returns parsing errors.
func GetE(key string) (interface{}, error) { return v.GetE(key) } func GetE(key string) (interface{}, error) { return v.GetE(key) }
func (v *Viper) GetE(key string) (interface{}, error) { func (v *Viper) GetE(key string) (interface{}, error) {
lcaseKey := strings.ToLower(key) lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey) val := v.find(lcaseKey, false)
if val == nil { if val == nil {
return nil, nil return nil, nil
} }
return v.castByDefValue(lcaseKey, val)
}
// GetESkipDefault is like GetE but ignors defaults.
func GetESkipDefault(key string) (interface{}, error) { return v.GetESkipDefault(key) }
func (v *Viper) GetESkipDefault(key string) (interface{}, error) {
lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey, true)
if val == nil {
return nil, nil
}
return v.castByDefValue(lcaseKey, val)
}
func (v *Viper) castByDefValue(lcaseKey string, val interface{}) (interface{}, error) {
if v.typeByDefValue { if v.typeByDefValue {
// TODO(bep) this branch isn't covered by a single test. // TODO(bep) this branch isn't covered by a single test.
valType := val valType := val
@ -654,7 +675,7 @@ func (v *Viper) GetE(key string) (interface{}, error) {
func GetRaw(key string) interface{} { return v.GetRaw(key) } func GetRaw(key string) interface{} { return v.GetRaw(key) }
func (v *Viper) GetRaw(key string) interface{} { func (v *Viper) GetRaw(key string) interface{} {
lcaseKey := strings.ToLower(key) lcaseKey := strings.ToLower(key)
return v.find(lcaseKey) return v.find(lcaseKey, false)
} }
// Sub returns new Viper instance representing a sub tree of this instance. // Sub returns new Viper instance representing a sub tree of this instance.
@ -983,9 +1004,10 @@ func (v *Viper) BindEnv(input ...string) error {
// Given a key, find the value. // Given a key, find the value.
// Viper will check in the following order: // Viper will check in the following order:
// flag, env, config file, key/value store, default. // flag, env, config file, key/value store, default.
// If skipDefault is set to true, find will ignore default values.
// Viper will check to see if an alias exists first. // Viper will check to see if an alias exists first.
// Note: this assumes a lower-cased key given. // Note: this assumes a lower-cased key given.
func (v *Viper) find(lcaseKey string) interface{} { func (v *Viper) find(lcaseKey string, skipDefault bool) interface{} {
var ( var (
val interface{} val interface{}
@ -1079,12 +1101,14 @@ func (v *Viper) find(lcaseKey string) interface{} {
} }
// Default next // Default next
val = v.searchMap(v.defaults, path) if !skipDefault {
if val != nil { val = v.searchMap(v.defaults, path)
return val if val != nil {
} return val
if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" { }
return nil if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" {
return nil
}
} }
// last chance: if no other value is returned and a flag does exist for the value, // last chance: if no other value is returned and a flag does exist for the value,
@ -1123,7 +1147,7 @@ func readAsCSV(val string) ([]string, error) {
func IsSet(key string) bool { return v.IsSet(key) } func IsSet(key string) bool { return v.IsSet(key) }
func (v *Viper) IsSet(key string) bool { func (v *Viper) IsSet(key string) bool {
lcaseKey := strings.ToLower(key) lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey) val := v.find(lcaseKey, false)
return val != nil return val != nil
} }
@ -1820,13 +1844,22 @@ outer:
// AllSettings merges all settings and returns them as a map[string]interface{}. // AllSettings merges all settings and returns them as a map[string]interface{}.
func AllSettings() map[string]interface{} { return v.AllSettings() } func AllSettings() map[string]interface{} { return v.AllSettings() }
func (v *Viper) AllSettings() map[string]interface{} { func (v *Viper) AllSettings() map[string]interface{} {
return v.allSettings(v.Get)
}
// AllSettingsWithoutDefault merges all settings and returns them as a map[string]interface{}.
func AllSettingsWithoutDefault() map[string]interface{} { return v.AllSettingsWithoutDefault() }
func (v *Viper) AllSettingsWithoutDefault() map[string]interface{} {
return v.allSettings(v.GetSkipDefault)
}
func (v *Viper) allSettings(getter func(string) interface{}) map[string]interface{} {
m := map[string]interface{}{} m := map[string]interface{}{}
// start from the list of keys, and construct the map one value at a time // start from the list of keys, and construct the map one value at a time
for _, k := range v.AllKeys() { for _, k := range v.AllKeys() {
value := v.Get(k) value := getter(k)
if value == nil { if value == nil {
// should not happen, since AllKeys() returns only keys holding a value, // should only happens if we `getter` ignors defaults
// check just in case anything changes
continue continue
} }

View file

@ -561,6 +561,41 @@ clothing.winter:
` `
v := New() v := New()
v.SetConfigType("yaml") v.SetConfigType("yaml")
v.SetDefault("test", "example")
r := strings.NewReader(exampleYaml)
if err := v.unmarshalReader(r, v.config); err != nil {
panic(err)
}
expectedAll := map[string]interface{}{"hacker": true, "name": "steve", "test": "example", "hobbies": []interface{}{"skate.boarding", "snowboarding"}, "clothing.summer": map[string]interface{}{"jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "clothing.winter": map[string]interface{}{"jacket": "wool", "pants": map[string]interface{}{"size": "medium"}}}
expectedKeys := sort.StringSlice{"hacker", "name", "test", "hobbies", "clothing.summer.jacket", "clothing.summer.pants.size", "clothing.winter.jacket", "clothing.winter.pants.size"}
expectedKeys.Sort()
keys := sort.StringSlice(v.AllKeys())
keys.Sort()
assert.Equal(t, expectedKeys, keys)
assert.Equal(t, expectedAll, v.AllSettings())
}
func TestAllSettingsWithDelimiterInKeysWithoutDefault(t *testing.T) {
exampleYaml := `Hacker: true
name: steve
hobbies:
- skate.boarding
- snowboarding
clothing.summer:
jacket: leather
pants:
size: large
clothing.winter:
jacket: wool
pants:
size: medium
`
v := New()
v.SetConfigType("yaml")
v.SetDefault("test", "example")
r := strings.NewReader(exampleYaml) r := strings.NewReader(exampleYaml)
if err := v.unmarshalReader(r, v.config); err != nil { if err := v.unmarshalReader(r, v.config); err != nil {
@ -568,13 +603,13 @@ clothing.winter:
} }
expectedAll := map[string]interface{}{"hacker": true, "name": "steve", "hobbies": []interface{}{"skate.boarding", "snowboarding"}, "clothing.summer": map[string]interface{}{"jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "clothing.winter": map[string]interface{}{"jacket": "wool", "pants": map[string]interface{}{"size": "medium"}}} expectedAll := map[string]interface{}{"hacker": true, "name": "steve", "hobbies": []interface{}{"skate.boarding", "snowboarding"}, "clothing.summer": map[string]interface{}{"jacket": "leather", "pants": map[string]interface{}{"size": "large"}}, "clothing.winter": map[string]interface{}{"jacket": "wool", "pants": map[string]interface{}{"size": "medium"}}}
expectedKeys := sort.StringSlice{"hacker", "name", "hobbies", "clothing.summer.jacket", "clothing.summer.pants.size", "clothing.winter.jacket", "clothing.winter.pants.size"} expectedKeys := sort.StringSlice{"hacker", "name", "test", "hobbies", "clothing.summer.jacket", "clothing.summer.pants.size", "clothing.winter.jacket", "clothing.winter.pants.size"}
expectedKeys.Sort() expectedKeys.Sort()
keys := sort.StringSlice(v.AllKeys()) keys := sort.StringSlice(v.AllKeys())
keys.Sort() keys.Sort()
assert.Equal(t, expectedKeys, keys) assert.Equal(t, expectedKeys, keys)
assert.Equal(t, expectedAll, v.AllSettings()) assert.Equal(t, expectedAll, v.AllSettingsWithoutDefault())
} }
func TestAliasesOfAliases(t *testing.T) { func TestAliasesOfAliases(t *testing.T) {