This commit is contained in:
Adam Sherwood 2023-02-27 21:58:33 -04:00 committed by GitHub
commit 77ac5f7aa7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 122 additions and 1 deletions

View file

@ -1097,6 +1097,27 @@ func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConf
return decode(v.Get(key), defaultDecoderConfig(rawVal, opts...))
}
// UnmarshalKeyWithMeta performs UnmarshalKey and provides access to the
// mapstructure.Metadata in an additional return value.
func UnmarshalKeyWithMeta(key string, rawVal interface{}) (mapstructure.Metadata, error) {
return v.UnmarshalKeyWithMeta(key, rawVal)
}
func (v *Viper) UnmarshalKeyWithMeta(key string, rawVal interface{}) (mapstructure.Metadata, error) {
var meta mapstructure.Metadata
config := defaultDecoderConfig(rawVal)
config.Metadata = &meta
err := decode(v.Get(key), config)
if err != nil {
return meta, err
}
v.insensitiviseMaps()
return meta, nil
}
// Unmarshal unmarshals the config into a Struct. Make sure that the tags
// on the fields of the structure are properly set.
func Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error {
@ -1107,7 +1128,28 @@ func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error
return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...))
}
// defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot
// UnmarshalWithMeta performs Unmarshal and provides access to the
// mapstructure.Metadata in an additional return value.
func UnmarshalWithMeta(rawVal interface{}) (mapstructure.Metadata, error) {
return v.UnmarshalWithMeta(rawVal)
}
func (v *Viper) UnmarshalWithMeta(rawVal interface{}) (mapstructure.Metadata, error) {
var meta mapstructure.Metadata
config := defaultDecoderConfig(rawVal)
config.Metadata = &meta
err := decode(v.AllSettings(), config)
if err != nil {
return meta, err
}
v.insensitiviseMaps()
return meta, nil
}
// defaultDecoderConfig returns default mapsstructure.DecoderConfig with support
// of time.Duration values & string slices
func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *mapstructure.DecoderConfig {
c := &mapstructure.DecoderConfig{

View file

@ -518,6 +518,85 @@ func TestUnmarshaling(t *testing.T) {
assert.Equal(t, 35, Get("age"))
}
func ExampleUnmarshalWithMeta() {
v := New()
type Lib struct {
Name string
Awesome bool
Useful bool
}
var libsCfg struct {
Libs map[string]Lib
}
v.config = map[string]interface{}{
"libs": map[string]interface{}{
"viper": map[string]interface{}{
"name": "Viper",
"awesome": true,
"tagline": "Go configuration with fangs!",
},
},
"numbers": []int{4, 8, 15, 16, 23, 42},
}
meta, _ := v.UnmarshalWithMeta(&libsCfg)
// The keys slice is not stable. Sorting them in lexicographical
// order allows comparison.
sort.Strings(meta.Keys)
sort.Strings(meta.Unused)
fmt.Printf("%#v\n", meta.Keys)
fmt.Printf("%#v", meta.Unused)
// Output:
// []string{"Libs", "Libs[viper]", "Libs[viper]", "Libs[viper].Awesome", "Libs[viper].Name"}
// []string{"Libs[viper].tagline", "numbers"}
}
func ExampleUnmarshalKeyWithMeta() {
v := New()
var lib struct {
Name string
Awesome bool
Useful bool
}
v.config = map[string]interface{}{
"libs": map[string]interface{}{
"viper": map[string]interface{}{
"name": "Viper",
"awesome": true,
"tagline": "Go configuration with fangs!",
},
},
}
meta, _ := v.UnmarshalKeyWithMeta("libs.viper", &lib)
fmt.Println(meta.Keys)
fmt.Println(meta.Unused)
// Output:
// [Name Awesome]
// [tagline]
}
func TestUnmarshalKeyWithMeta(t *testing.T) {
v := New()
v.SetConfigType("yaml")
err := v.ReadConfig(bytes.NewBuffer(yamlExample))
if err != nil {
t.Fatal(err)
}
var clothes struct {
Jacket string
Pants interface{}
}
meta, err := v.UnmarshalKeyWithMeta("clothing", &clothes)
if err != nil {
t.Fatal(err)
}
keys := []string{"Jacket", "Pants"}
unused := []string{"trousers"}
sort.Strings(meta.Keys)
sort.Strings(meta.Unused)
assert.Equal(t, keys, meta.Keys, "keys decoded")
assert.Equal(t, unused, meta.Unused, "keys in config not in struct")
}
func TestUnmarshalExact(t *testing.T) {
vip := New()
target := &testUnmarshalExtra{}