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.
This commit is contained in:
Nate Finch 2014-08-05 07:35:21 -04:00 committed by spf13
parent 3cf05f93ef
commit 2b24bea958
2 changed files with 52 additions and 13 deletions

View File

@ -107,20 +107,23 @@ func MarshalKey(key string, rawVal interface{}) error {
} }
// Marshals the config into a Struct // Marshals the config into a Struct
func Marshal(rawVal interface{}) (err error) { func Marshal(rawVal interface{}) error {
err = mapstructure.Decode(defaults, rawVal) err := mapstructure.Decode(defaults, rawVal)
if err != nil { if err != nil {
return return err
} }
err = mapstructure.Decode(config, rawVal) err = mapstructure.Decode(config, rawVal)
if err != nil { if err != nil {
return return err
} }
err = mapstructure.Decode(override, rawVal) err = mapstructure.Decode(override, rawVal)
if err != nil { if err != nil {
return return err
} }
return
insensativiseMaps()
return nil
} }
// Bind a specific key to a flag (as used by cobra) // 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) alias = strings.ToLower(alias)
if alias != key && alias != realKey(key) { if alias != key && alias != realKey(key) {
_, exists := aliases[alias] _, exists := aliases[alias]
if !exists { 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 aliases[alias] = key
} }
} else { } else {
@ -310,17 +329,26 @@ func MarshallReader(in io.Reader) {
} }
} }
insensativiseMap() insensativiseMap(config)
} }
func insensativiseMap() { func insensativiseMaps() {
for key, _ := range config { insensativiseMap(config)
if key != strings.ToLower(key) { insensativiseMap(defaults)
registerAlias(key, key) 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. // Name for the config file.
// Does not include extension. // Does not include extension.
func SetConfigName(in string) { func SetConfigName(in string) {

View File

@ -21,7 +21,9 @@ hobbies:
clothing: clothing:
jacket: leather jacket: leather
trousers: denim trousers: denim
age: 35`) age: 35
beard: true
`)
var tomlExample = []byte(` var tomlExample = []byte(`
title = "TOML Example" title = "TOML Example"
@ -87,6 +89,15 @@ func TestAliases(t *testing.T) {
assert.Equal(t, 45, Get("age")) 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) { func TestYML(t *testing.T) {
Reset() Reset()
SetConfigType("yml") SetConfigType("yml")