Skip to content

Commit

Permalink
Add ability to append to slice during config file merge
Browse files Browse the repository at this point in the history
If key ends in "+" the value of the key is appended to previous
values found.  If values are string instead of a slice they are
automatically converted to a slice of one string.

Signed-off-by: Darren Shepherd <darren@rancher.com>
  • Loading branch information
ibuildthecloud authored and brandond committed Apr 27, 2021
1 parent 7a10a99 commit 8f1a20c
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 21 deletions.
63 changes: 47 additions & 16 deletions pkg/configfilearg/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,12 @@ func readConfigFile(file string) (result []string, _ error) {
files = append([]string{file}, files...)
}

keySeen := map[string]bool{}
for i := len(files) - 1; i >= 0; i-- {
file := files[i]
var (
keySeen = map[string]bool{}
keyOrder []string
values = map[string]interface{}{}
)
for _, file := range files {
bytes, err := readConfigFileData(file)
if err != nil {
return nil, err
Expand All @@ -157,30 +160,58 @@ func readConfigFile(file string) (result []string, _ error) {

for _, i := range data {
k, v := convert.ToString(i.Key), i.Value
if keySeen[k] {
continue
}
keySeen[k] = true
isAppend := strings.HasSuffix(k, "+")
k = strings.TrimSuffix(k, "+")

prefix := "--"
if len(k) == 1 {
prefix = "-"
if !keySeen[k] {
keySeen[k] = true
keyOrder = append(keyOrder, k)
}

if slice, ok := v.([]interface{}); ok {
for _, v := range slice {
result = append(result, prefix+k+"="+convert.ToString(v))
}
if oldValue, ok := values[k]; ok && isAppend {
values[k] = append(toSlice(oldValue), toSlice(v)...)
} else {
str := convert.ToString(v)
result = append(result, prefix+k+"="+str)
values[k] = v
}
}
}

for _, k := range keyOrder {
v := values[k]

prefix := "--"
if len(k) == 1 {
prefix = "-"
}

if slice, ok := v.([]interface{}); ok {
for _, v := range slice {
result = append(result, prefix+k+"="+convert.ToString(v))
}
} else {
str := convert.ToString(v)
result = append(result, prefix+k+"="+str)
}
}

return
}

func toSlice(v interface{}) []interface{} {
switch k := v.(type) {
case string:
return []interface{}{k}
case []interface{}:
return k
default:
str := strings.TrimSpace(convert.ToString(v))
if str == "" {
return nil
}
return []interface{}{str}
}
}

func readConfigFileData(file string) ([]byte, error) {
u, err := url.Parse(file)
if err != nil {
Expand Down
23 changes: 20 additions & 3 deletions pkg/configfilearg/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,15 @@ func TestParse(t *testing.T) {
"-c=b",
"--isfalse=false",
"--islast=true",
"--b-string=one",
"--b-string=two",
"--c-slice=one",
"--c-slice=two",
"--c-slice=three",
"--d-slice=three",
"--d-slice=four",
"--e-slice=one",
"--e-slice=two",
}

defParser := Parser{
Expand Down Expand Up @@ -224,9 +233,17 @@ func TestParse(t *testing.T) {
FlagNames: []string{"-c", "--config"},
DefaultConfig: "missing",
},
input: []string{"before", "server", "before", "-c", "./testdata/data.yaml.d/02-data.yaml", "after"},
output: []string{"before", "server", "--foo-bar=bar-foo", "before", "-c", "./testdata/data.yaml.d/02-data.yaml", "after"},
what: "read single config file",
input: []string{"before", "server", "before", "-c", "./testdata/data.yaml.d/02-data.yaml", "after"},
output: []string{"before", "server",
"--foo-bar=bar-foo",
"--b-string=two",
"--c-slice=three",
"--d-slice=three",
"--d-slice=four",
"--e-slice=one",
"--e-slice=two",
"before", "-c", "./testdata/data.yaml.d/02-data.yaml", "after"},
what: "read single config file",
},
}

Expand Down
9 changes: 8 additions & 1 deletion pkg/configfilearg/testdata/data.yaml.d/01-data.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,11 @@ a-slice:
- "1.5"
- "2"
- ""
- three
- three
b-string: one
c-slice:
- one
- two
d-slice:
- one
- two
11 changes: 10 additions & 1 deletion pkg/configfilearg/testdata/data.yaml.d/02-data.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
foo-bar: bar-foo
foo-bar: bar-foo
b-string+: two
c-slice+:
- three
d-slice:
- three
- four
e-slice+:
- one
- two

0 comments on commit 8f1a20c

Please sign in to comment.