diff --git a/configuration/parser.go b/configuration/parser.go index 6d6451800..1a9201986 100644 --- a/configuration/parser.go +++ b/configuration/parser.go @@ -166,6 +166,25 @@ func (p *Parser) overwriteFields(v reflect.Value, fullpath string, path []string return p.overwriteStruct(v, fullpath, path, payload) case reflect.Map: return p.overwriteMap(v, fullpath, path, payload) + case reflect.Slice: + idx, err := strconv.Atoi(path[0]) + if err != nil { + panic("non-numeric index: " + path[0]) + } + + if idx > v.Len() { + panic("undefined index: " + path[0]) + } + + // if there is no element or the current slice length + // is the same as the indexed variable create a new element, + // append it and then set it to the passed in env var value. + if v.Len() == 0 || idx == v.Len() { + typ := v.Type().Elem() + elem := reflect.New(typ).Elem() + v.Set(reflect.Append(v, elem)) + } + return p.overwriteFields(v.Index(idx), fullpath, path[1:], payload) case reflect.Interface: if v.NumMethod() == 0 { if !v.IsNil() { diff --git a/configuration/parser_test.go b/configuration/parser_test.go index 7f352483b..b2cb60c9d 100644 --- a/configuration/parser_test.go +++ b/configuration/parser_test.go @@ -8,21 +8,39 @@ import ( ) type localConfiguration struct { - Version Version `yaml:"version"` - Log *Log `yaml:"log"` + Version Version `yaml:"version"` + Log *Log `yaml:"log"` + Notifications []Notif `yaml:"notifications,omitempty"` } type Log struct { Formatter string `yaml:"formatter,omitempty"` } +type Notif struct { + Name string `yaml:"name"` +} + var expectedConfig = localConfiguration{ Version: "0.1", Log: &Log{ Formatter: "json", }, + Notifications: []Notif{ + {Name: "foo"}, + {Name: "bar"}, + {Name: "car"}, + }, } +const testConfig = `version: "0.1" +log: + formatter: "text" +notifications: + - name: "foo" + - name: "bar" + - name: "car"` + type ParserSuite struct{} var _ = check.Suite(new(ParserSuite)) @@ -43,17 +61,32 @@ func (suite *ParserSuite) TestParserOverwriteIninitializedPoiner(c *check.C) { }, }) - err := p.Parse([]byte(`{version: "0.1", log: {formatter: "text"}}`), &config) + err := p.Parse([]byte(testConfig), &config) c.Assert(err, check.IsNil) c.Assert(config, check.DeepEquals, expectedConfig) } +const testConfig2 = `version: "0.1" +log: + formatter: "text" +notifications: + - name: "val1" + - name: "val2" + - name: "car"` + func (suite *ParserSuite) TestParseOverwriteUnininitializedPoiner(c *check.C) { config := localConfiguration{} os.Setenv("REGISTRY_LOG_FORMATTER", "json") defer os.Unsetenv("REGISTRY_LOG_FORMATTER") + // override only first two notificationsvalues + // in the tetConfig: leave the last value unchanged. + os.Setenv("REGISTRY_NOTIFICATIONS_0_NAME", "foo") + defer os.Unsetenv("REGISTRY_NOTIFICATIONS_0_NAME") + os.Setenv("REGISTRY_NOTIFICATIONS_1_NAME", "bar") + defer os.Unsetenv("REGISTRY_NOTIFICATIONS_1_NAME") + p := NewParser("registry", []VersionedParseInfo{ { Version: "0.1", @@ -64,7 +97,7 @@ func (suite *ParserSuite) TestParseOverwriteUnininitializedPoiner(c *check.C) { }, }) - err := p.Parse([]byte(`{version: "0.1"}`), &config) + err := p.Parse([]byte(testConfig2), &config) c.Assert(err, check.IsNil) c.Assert(config, check.DeepEquals, expectedConfig) }