From 73fad7c9db5dfff8488e79121ec4386887765daa Mon Sep 17 00:00:00 2001 From: Albert Vaca Date: Tue, 26 Mar 2019 15:14:00 +0100 Subject: [PATCH 1/3] Enable storing a set of known valid config keys This can be used to enforce a config schema --- viper.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/viper.go b/viper.go index b098dc8..6141bed 100644 --- a/viper.go +++ b/viper.go @@ -196,6 +196,7 @@ type Viper struct { pflags map[string]FlagValue env map[string]string aliases map[string]string + knownKeys map[string]interface{} typeByDefValue bool // Store read properties on the object so that we can write back in order with comments. @@ -218,6 +219,7 @@ func New() *Viper { v.pflags = make(map[string]FlagValue) v.env = make(map[string]string) v.aliases = make(map[string]string) + v.knownKeys = make(map[string]interface{}) v.typeByDefValue = false return v @@ -1036,6 +1038,8 @@ func (v *Viper) BindEnv(input ...string) error { v.env[key] = envkey + v.SetKnown(key) + return nil } @@ -1233,6 +1237,7 @@ func (v *Viper) registerAlias(alias string, key string) { } else { jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key)) } + v.SetKnown(alias) } func (v *Viper) realKey(key string) string { @@ -1269,6 +1274,27 @@ func (v *Viper) SetDefault(key string, value interface{}) { // set innermost value deepestMap[lastKey] = value + v.SetKnown(key) +} + +// SetKnown adds a key to the set of known valid config keys +func (v *Viper) SetKnown(key string) { + key = strings.ToLower(key) + splitPath := strings.Split(key, v.keyDelim) + for j := range splitPath { + subKey := strings.Join(splitPath[:j+1], v.keyDelim) + v.knownKeys[subKey] = struct{}{} + } +} + +// GetKnownKeys returns all the keys that meet at least one of these criteria: +// 1) have a default, 2) have an environment variable binded, 3) are an alias or 4) have been SetKnown() +func (v *Viper) GetKnownKeys() map[string]interface{} { + ret := make(map[string]interface{}) + for key, value := range v.knownKeys { + ret[key] = value + } + return ret } // Set sets the value for the key in the override register. From ead7a65a23c21eb6ed5c5fe29e0d5471b4667db4 Mon Sep 17 00:00:00 2001 From: Albert Vaca Date: Tue, 23 Apr 2019 12:40:19 +0200 Subject: [PATCH 2/3] Added missing global versions of SetKnown/GetKnown For consistency --- viper.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/viper.go b/viper.go index 6141bed..21a9a2e 100644 --- a/viper.go +++ b/viper.go @@ -1278,6 +1278,7 @@ func (v *Viper) SetDefault(key string, value interface{}) { } // SetKnown adds a key to the set of known valid config keys +func SetKnown(key string) { v.SetKnown(key) } func (v *Viper) SetKnown(key string) { key = strings.ToLower(key) splitPath := strings.Split(key, v.keyDelim) @@ -1289,6 +1290,7 @@ func (v *Viper) SetKnown(key string) { // GetKnownKeys returns all the keys that meet at least one of these criteria: // 1) have a default, 2) have an environment variable binded, 3) are an alias or 4) have been SetKnown() +func GetKnownKeys() map[string]interface{} { return v.GetKnownKeys() } func (v *Viper) GetKnownKeys() map[string]interface{} { ret := make(map[string]interface{}) for key, value := range v.knownKeys { From e8b327076752f8d9a164208aee987b84ebb1cf99 Mon Sep 17 00:00:00 2001 From: Albert Vaca Date: Tue, 23 Apr 2019 12:40:40 +0200 Subject: [PATCH 3/3] Added test for known keys --- viper_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/viper_test.go b/viper_test.go index d5296df..fd6a703 100644 --- a/viper_test.go +++ b/viper_test.go @@ -1739,3 +1739,23 @@ func BenchmarkGetBoolFromMap(b *testing.B) { } } } + +func TestKnownKeys(t *testing.T) { + v := New() + v.SetDefault("default", 45) + if _, ok := v.GetKnownKeys()["default"]; !ok { + t.Error("SetDefault didn't mark key as known") + } + v.BindEnv("bind", "my_env_var") + if _, ok := v.GetKnownKeys()["bind"]; !ok { + t.Error("BindEnv didn't mark key as known") + } + v.RegisterAlias("my_alias", "key") + if _, ok := v.GetKnownKeys()["my_alias"]; !ok { + t.Error("RegisterAlias didn't mark alias as known") + } + v.SetKnown("known") + if _, ok := v.GetKnownKeys()["known"]; !ok { + t.Error("SetKnown didn't mark key as known") + } +}