mirror of
https://github.com/spf13/viper
synced 2024-12-23 12:07:02 +00:00
Change implementation of find sub-tree to work with deep trees
* The previous implementation had an issue with nested structures deeper than one level. It would copy keys over instead of the expected object structure. In the example in this commit, UnmarshalKey("clothing") was returning "pants.size":"35" instead of "pants"{"size":"35"}
This commit is contained in:
parent
b7a4909ef7
commit
e5459cc690
2 changed files with 51 additions and 3 deletions
12
viper.go
12
viper.go
|
@ -1009,9 +1009,15 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
|
||||||
// it could also be a key prefix, search for that prefix to get the values from
|
// it could also be a key prefix, search for that prefix to get the values from
|
||||||
// pflags that match it
|
// pflags that match it
|
||||||
sub := make(map[string]interface{})
|
sub := make(map[string]interface{})
|
||||||
for key, val := range v.pflags {
|
for _, key := range v.AllKeys() {
|
||||||
if flagDefault && strings.HasPrefix(key, lcaseKey) {
|
if strings.HasPrefix(key, lcaseKey) {
|
||||||
sub[strings.TrimPrefix(key, lcaseKey+".")] = val.ValueString()
|
value := v.Get(key)
|
||||||
|
keypath := strings.Split(lcaseKey, v.keyDelim)
|
||||||
|
path := strings.Split(key, v.keyDelim)[len(keypath)-1:]
|
||||||
|
lastKey := strings.ToLower(path[len(path)-1])
|
||||||
|
deepestMap := deepSearch(sub, path[1:len(path)-1])
|
||||||
|
// set innermost value
|
||||||
|
deepestMap[lastKey] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(sub) != 0 {
|
if len(sub) != 0 {
|
||||||
|
|
|
@ -875,7 +875,49 @@ func TestSubPflags(t *testing.T) {
|
||||||
v.BindPFlag("eyes", &pflag.Flag{Value: newStringValue("brown"), Changed: true})
|
v.BindPFlag("eyes", &pflag.Flag{Value: newStringValue("brown"), Changed: true})
|
||||||
v.BindPFlag("beard", &pflag.Flag{Value: newStringValue("yes"), Changed: true})
|
v.BindPFlag("beard", &pflag.Flag{Value: newStringValue("yes"), Changed: true})
|
||||||
|
|
||||||
|
type pants struct {
|
||||||
|
Size string
|
||||||
|
}
|
||||||
|
|
||||||
|
type clothing struct {
|
||||||
|
Jacket string
|
||||||
|
Trousers string
|
||||||
|
Pants pants
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
Name string
|
||||||
|
Clothing clothing
|
||||||
|
Age int
|
||||||
|
Eyes string
|
||||||
|
Beard bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var c cfg
|
||||||
|
v.Unmarshal(&c)
|
||||||
|
assert.Equal(t, v.Get("name"), c.Name)
|
||||||
|
assert.Equal(t, v.Get("clothing.jacket"), c.Clothing.Jacket)
|
||||||
|
assert.Equal(t, v.Get("clothing.trousers"), c.Clothing.Trousers)
|
||||||
|
assert.Equal(t, v.Get("clothing.pants.size"), c.Clothing.Pants.Size)
|
||||||
|
assert.Equal(t, v.GetInt("age"), c.Age)
|
||||||
|
assert.Equal(t, v.Get("eyes"), c.Eyes)
|
||||||
|
assert.Equal(t, v.GetBool("beard"), c.Beard)
|
||||||
|
|
||||||
|
var cloth clothing
|
||||||
|
v.UnmarshalKey("clothing", &cloth)
|
||||||
|
assert.Equal(t, c.Clothing, cloth)
|
||||||
|
|
||||||
|
var p pants
|
||||||
|
v.UnmarshalKey("clothing.pants", &p)
|
||||||
|
assert.Equal(t, c.Clothing.Pants, p)
|
||||||
|
|
||||||
|
var size string
|
||||||
|
v.UnmarshalKey("clothing.pants.size", &size)
|
||||||
|
assert.Equal(t, c.Clothing.Pants.Size, size)
|
||||||
|
|
||||||
subv := v.Sub("clothing")
|
subv := v.Sub("clothing")
|
||||||
|
assert.Equal(t, v.Get("clothing.jacket"), subv.Get("jacket"))
|
||||||
|
assert.Equal(t, v.Get("clothing.trousers"), subv.Get("trousers"))
|
||||||
assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
|
assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
|
||||||
|
|
||||||
subv = v.Sub("clothing.pants")
|
subv = v.Sub("clothing.pants")
|
||||||
|
|
Loading…
Reference in a new issue