From 2b24bea958e2d411fc25a82e44fbbcc3b6ed0441 Mon Sep 17 00:00:00 2001 From: Nate Finch Date: Tue, 5 Aug 2014 07:35:21 -0400 Subject: [PATCH] fix issue #8 This fixes the aliases in config files bug. Whenever we register an alias, if there is a value in the config (or defaults or override) for the alias, we move that value to the new "real key". Added a test for the bug, which fails without the changes and passes with the changes. This also fixes a bug in Hugo, where specifying "Taxonomies" in your config file doesn't get recognized, because Hugo aliases "Taxonomies" to "Indexes" which means that when the code does a Get("Taxnomies") it got translated to Get("Indexes"), which didn't exist in the original config map. --- viper.go | 50 +++++++++++++++++++++++++++++++++++++++----------- viper_test.go | 15 +++++++++++++-- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/viper.go b/viper.go index 44f3819..38bd17d 100644 --- a/viper.go +++ b/viper.go @@ -107,20 +107,23 @@ func MarshalKey(key string, rawVal interface{}) error { } // Marshals the config into a Struct -func Marshal(rawVal interface{}) (err error) { - err = mapstructure.Decode(defaults, rawVal) +func Marshal(rawVal interface{}) error { + err := mapstructure.Decode(defaults, rawVal) if err != nil { - return + return err } err = mapstructure.Decode(config, rawVal) if err != nil { - return + return err } err = mapstructure.Decode(override, rawVal) if err != nil { - return + return err } - return + + insensativiseMaps() + + return nil } // Bind a specific key to a flag (as used by cobra) @@ -224,7 +227,23 @@ func registerAlias(alias string, key string) { alias = strings.ToLower(alias) if alias != key && alias != realKey(key) { _, exists := aliases[alias] + if !exists { + // if we alias something that exists in one of the maps to another + // name, we'll never be able to get that value using the original + // name, so move the config value to the new realkey. + if val, ok := config[alias]; ok { + delete(config, alias) + config[key] = val + } + if val, ok := defaults[alias]; ok { + delete(defaults, alias) + defaults[key] = val + } + if val, ok := override[alias]; ok { + delete(override, alias) + override[key] = val + } aliases[alias] = key } } else { @@ -310,17 +329,26 @@ func MarshallReader(in io.Reader) { } } - insensativiseMap() + insensativiseMap(config) } -func insensativiseMap() { - for key, _ := range config { - if key != strings.ToLower(key) { - registerAlias(key, key) +func insensativiseMaps() { + insensativiseMap(config) + insensativiseMap(defaults) + insensativiseMap(override) +} + +func insensativiseMap(m map[string]interface{}) { + for key, val := range m { + lower := strings.ToLower(key) + if key != lower { + delete(m, key) + m[lower] = val } } } + // Name for the config file. // Does not include extension. func SetConfigName(in string) { diff --git a/viper_test.go b/viper_test.go index b077b5b..ad20da8 100644 --- a/viper_test.go +++ b/viper_test.go @@ -21,7 +21,9 @@ hobbies: clothing: jacket: leather trousers: denim -age: 35`) +age: 35 +beard: true +`) var tomlExample = []byte(` title = "TOML Example" @@ -87,6 +89,15 @@ func TestAliases(t *testing.T) { assert.Equal(t, 45, Get("age")) } +func TestAliasInConfigFile(t *testing.T) { + // the config file specifies "beard". If we make this an alias for + // "hasbeard", we still want the old config file to work with beard. + RegisterAlias("beard", "hasbeard") + assert.Equal(t, true, Get("hasbeard")) + Set("hasbeard", false) + assert.Equal(t, false, Get("beard")) +} + func TestYML(t *testing.T) { Reset() SetConfigType("yml") @@ -153,4 +164,4 @@ func TestMarshal(t *testing.T) { t.Fatalf("unable to decode into struct, %v", err) } assert.Equal(t, &C, &config{Name: "Steve", Port: 1234}) -} +} \ No newline at end of file