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
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) {

View file

@ -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})
}
}