Add key delimiter setter

This commit is contained in:
Mark Sagi-Kazar 2019-11-06 12:40:41 +01:00 committed by Márk Sági-Kazár
parent b6ced70067
commit a73303ee89
2 changed files with 82 additions and 5 deletions

View file

@ -34,14 +34,14 @@ import (
"sync" "sync"
"time" "time"
yaml "gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/hashicorp/hcl" "github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/printer" "github.com/hashicorp/hcl/hcl/printer"
"github.com/magiconair/properties" "github.com/magiconair/properties"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
toml "github.com/pelletier/go-toml" "github.com/pelletier/go-toml"
"github.com/spf13/afero" "github.com/spf13/afero"
"github.com/spf13/cast" "github.com/spf13/cast"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
@ -245,6 +245,15 @@ func Reset() {
SupportedRemoteProviders = []string{"etcd", "consul"} SupportedRemoteProviders = []string{"etcd", "consul"}
} }
// SetKeyDelimiter sets the delimiter used for determining key parts.
// By default it's value is ".".
func SetKeyDelimiter(keyDelim string) { v.SetKeyDelimiter(keyDelim) }
func (v *Viper) SetKeyDelimiter(keyDelim string) {
if keyDelim != "" {
v.keyDelim = keyDelim
}
}
type defaultRemoteProvider struct { type defaultRemoteProvider struct {
provider string provider string
endpoint string endpoint string
@ -1720,7 +1729,7 @@ func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}
func (v *Viper) watchKeyValueConfigOnChannel() error { func (v *Viper) watchKeyValueConfigOnChannel() error {
for _, rp := range v.remoteProviders { for _, rp := range v.remoteProviders {
respc, _ := RemoteConfig.WatchChannel(rp) respc, _ := RemoteConfig.WatchChannel(rp)
//Todo: Add quit channel // Todo: Add quit channel
go func(rc <-chan *RemoteResponse) { go func(rc <-chan *RemoteResponse) {
for { for {
b := <-rc b := <-rc
@ -1756,7 +1765,7 @@ func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface
} }
// AllKeys returns all keys holding a value, regardless of where they are set. // AllKeys returns all keys holding a value, regardless of where they are set.
// Nested keys are returned with a v.keyDelim (= ".") separator // Nested keys are returned with a v.keyDelim separator
func AllKeys() []string { return v.AllKeys() } func AllKeys() []string { return v.AllKeys() }
func (v *Viper) AllKeys() []string { func (v *Viper) AllKeys() []string {
m := map[string]bool{} m := map[string]bool{}
@ -1779,7 +1788,7 @@ func (v *Viper) AllKeys() []string {
// flattenAndMergeMap recursively flattens the given map into a map[string]bool // flattenAndMergeMap recursively flattens the given map into a map[string]bool
// of key paths (used as a set, easier to manipulate than a []string): // of key paths (used as a set, easier to manipulate than a []string):
// - each path is merged into a single key string, delimited with v.keyDelim (= ".") // - each path is merged into a single key string, delimited with v.keyDelim
// - if a path is shadowed by an earlier value in the initial shadow map, // - if a path is shadowed by an earlier value in the initial shadow map,
// it is skipped. // it is skipped.
// The resulting set of paths is merged to the given shadow set at the same time. // The resulting set of paths is merged to the given shadow set at the same time.

View file

@ -2009,6 +2009,74 @@ func TestUnmarshal_DotSeparatorBackwardCompatibility(t *testing.T) {
assert.Equal(t, "cobra_flag", config.Foo.Bar) assert.Equal(t, "cobra_flag", config.Foo.Bar)
} }
var yamlExampleWithDot = []byte(`Hacker: true
name: steve
hobbies:
- skateboarding
- snowboarding
- go
clothing:
jacket: leather
trousers: denim
pants:
size: large
age: 35
eyes : brown
beard: true
emails:
steve@hacker.com:
created: 01/02/03
active: true
`)
func TestSetKeyDelimiter(t *testing.T) {
v := New()
v.SetKeyDelimiter("::")
v.SetConfigType("yaml")
r := strings.NewReader(string(yamlExampleWithDot))
err := v.unmarshalReader(r, v.config)
require.NoError(t, err)
values := map[string]interface{}{
"image": map[string]interface{}{
"repository": "someImage",
"tag": "1.0.0",
},
"ingress": map[string]interface{}{
"annotations": map[string]interface{}{
"traefik.frontend.rule.type": "PathPrefix",
"traefik.ingress.kubernetes.io/ssl-redirect": "true",
},
},
}
v.SetDefault("charts::values", values)
assert.Equal(t, "leather", v.GetString("clothing::jacket"))
assert.Equal(t, "01/02/03", v.GetString("emails::steve@hacker.com::created"))
type config struct {
Charts struct {
Values map[string]interface{}
}
}
expected := config{
Charts: struct {
Values map[string]interface{}
}{
Values: values,
},
}
var actual config
assert.NoError(t, v.Unmarshal(&actual))
assert.Equal(t, expected, actual)
}
func BenchmarkGetBool(b *testing.B) { func BenchmarkGetBool(b *testing.B) {
key := "BenchmarkGetBool" key := "BenchmarkGetBool"
v = New() v = New()