Apply the case of the CLI flags for the configuration

This commit is contained in:
Jean-Baptiste Doumenjou 2019-08-05 15:22:03 +02:00 committed by Traefiker Bot
parent cd164de776
commit 91e63dea47
5 changed files with 174 additions and 43 deletions

View file

@ -625,46 +625,62 @@ func Test_execute_configuration(t *testing.T) {
} }
func Test_execute_configuration_file(t *testing.T) { func Test_execute_configuration_file(t *testing.T) {
rootCmd := &Command{ testCases := []struct {
Name: "root", desc string
Description: "This is a test", args []string
Configuration: nil, }{
Run: func(_ []string) error { {
return nil desc: "configFile arg in camel case",
args: []string{"", "sub1", "--configFile=./fixtures/config.toml"},
},
{
desc: "configfile arg in lower case",
args: []string{"", "sub1", "--configfile=./fixtures/config.toml"},
}, },
} }
element := &Yo{ for _, test := range testCases {
Fuu: "test", t.Run(test.desc, func(t *testing.T) {
rootCmd := &Command{
Name: "root",
Description: "This is a test",
Configuration: nil,
Run: func(_ []string) error {
return nil
},
}
element := &Yo{
Fuu: "test",
}
sub1 := &Command{
Name: "sub1",
Description: "sub1",
Configuration: element,
Resources: []ResourceLoader{&FileLoader{}, &FlagLoader{}},
Run: func(args []string) error {
return nil
},
}
err := rootCmd.AddCommand(sub1)
require.NoError(t, err)
err = execute(rootCmd, test.args, true)
require.NoError(t, err)
expected := &Yo{
Foo: "bar",
Fii: "bir",
Fuu: "test",
Yi: &Yi{
Foo: "foo",
Fii: "fii",
},
}
assert.Equal(t, expected, element)
})
} }
sub1 := &Command{
Name: "sub1",
Description: "sub1",
Configuration: element,
Resources: []ResourceLoader{&FileLoader{}, &FlagLoader{}},
Run: func(args []string) error {
return nil
},
}
err := rootCmd.AddCommand(sub1)
require.NoError(t, err)
args := []string{"", "sub1", "--configFile=./fixtures/config.toml"}
err = execute(rootCmd, args, true)
require.NoError(t, err)
expected := &Yo{
Foo: "bar",
Fii: "bir",
Fuu: "test",
Yi: &Yi{
Foo: "foo",
Fii: "fii",
},
}
assert.Equal(t, expected, element)
} }
func Test_execute_help(t *testing.T) { func Test_execute_help(t *testing.T) {

View file

@ -30,8 +30,15 @@ func (f *FileLoader) Load(args []string, cmd *Command) (bool, error) {
} }
configFileFlag := "traefik.configfile" configFileFlag := "traefik.configfile"
if _, ok := ref["traefik.configFile"]; ok {
configFileFlag = "traefik.configFile"
}
if f.ConfigFileFlag != "" { if f.ConfigFileFlag != "" {
configFileFlag = "traefik." + strings.ToLower(f.ConfigFileFlag) configFileFlag = "traefik." + f.ConfigFileFlag
if _, ok := ref[strings.ToLower(configFileFlag)]; ok {
configFileFlag = "traefik." + strings.ToLower(f.ConfigFileFlag)
}
} }
configFile, err := loadConfigFiles(ref[configFileFlag], cmd.Configuration) configFile, err := loadConfigFiles(ref[configFileFlag], cmd.Configuration)

View file

@ -136,6 +136,20 @@ func TestDecode(t *testing.T) {
}, },
}, },
}, },
{
desc: "map string case sensitive",
args: []string{"--foo.caseSensitiveName=barBoo"},
element: &struct {
Foo map[string]string
}{},
expected: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"caseSensitiveName": "barBoo",
},
},
},
{ {
desc: "map struct", desc: "map struct",
args: []string{"--foo.name.value=bar"}, args: []string{"--foo.name.value=bar"},

View file

@ -16,6 +16,7 @@ func Parse(args []string, element interface{}) (map[string]string, error) {
flagTypes: getFlagTypes(element), flagTypes: getFlagTypes(element),
args: args, args: args,
values: make(map[string]string), values: make(map[string]string),
keys: make(map[string]string),
} }
for { for {
@ -35,6 +36,7 @@ type flagSet struct {
flagTypes map[string]reflect.Kind flagTypes map[string]reflect.Kind
args []string args []string
values map[string]string values map[string]string
keys map[string]string
} }
func (f *flagSet) parseOne() (bool, error) { func (f *flagSet) parseOne() (bool, error) {
@ -78,7 +80,8 @@ func (f *flagSet) parseOne() (bool, error) {
return true, nil return true, nil
} }
if f.flagTypes[name] == reflect.Bool || f.flagTypes[name] == reflect.Ptr { n := strings.ToLower(name)
if f.flagTypes[n] == reflect.Bool || f.flagTypes[n] == reflect.Ptr {
f.setValue(name, "true") f.setValue(name, "true")
return true, nil return true, nil
} }
@ -98,13 +101,20 @@ func (f *flagSet) parseOne() (bool, error) {
} }
func (f *flagSet) setValue(name string, value string) { func (f *flagSet) setValue(name string, value string) {
n := strings.ToLower(parser.DefaultRootName + "." + name) srcKey := parser.DefaultRootName + "." + name
v, ok := f.values[n] neutralKey := strings.ToLower(srcKey)
if ok && f.flagTypes[name] == reflect.Slice { key, ok := f.keys[neutralKey]
f.values[n] = v + "," + value if !ok {
f.keys[neutralKey] = srcKey
key = srcKey
}
v, ok := f.values[key]
if ok && f.flagTypes[strings.ToLower(name)] == reflect.Slice {
f.values[key] = v + "," + value
return return
} }
f.values[n] = value f.values[key] = value
} }

View file

@ -29,6 +29,16 @@ func TestParse(t *testing.T) {
"traefik.foo": "true", "traefik.foo": "true",
}, },
}, },
{
desc: "bool value capitalized",
args: []string{"--Foo"},
element: &struct {
Foo bool
}{},
expected: map[string]string{
"traefik.Foo": "true",
},
},
{ {
desc: "equal", desc: "equal",
args: []string{"--foo=bar"}, args: []string{"--foo=bar"},
@ -39,6 +49,16 @@ func TestParse(t *testing.T) {
"traefik.foo": "bar", "traefik.foo": "bar",
}, },
}, },
{
desc: "equal",
args: []string{"--Foo=Bar"},
element: &struct {
Foo string
}{},
expected: map[string]string{
"traefik.Foo": "Bar",
},
},
{ {
desc: "space separated", desc: "space separated",
args: []string{"--foo", "bar"}, args: []string{"--foo", "bar"},
@ -49,6 +69,16 @@ func TestParse(t *testing.T) {
"traefik.foo": "bar", "traefik.foo": "bar",
}, },
}, },
{
desc: "space separated capitalized",
args: []string{"--Foo", "Bar"},
element: &struct {
Foo string
}{},
expected: map[string]string{
"traefik.Foo": "Bar",
},
},
{ {
desc: "space separated with end of parameter", desc: "space separated with end of parameter",
args: []string{"--foo=bir", "--", "--bar"}, args: []string{"--foo=bir", "--", "--bar"},
@ -91,6 +121,16 @@ func TestParse(t *testing.T) {
"traefik.foo.name": "bar", "traefik.foo.name": "bar",
}, },
}, },
{
desc: "map string capitalized",
args: []string{"--foo.Name=Bar"},
element: &struct {
Foo map[string]string
}{},
expected: map[string]string{
"traefik.foo.Name": "Bar",
},
},
{ {
desc: "map struct", desc: "map struct",
args: []string{"--foo.name.value=bar"}, args: []string{"--foo.name.value=bar"},
@ -199,6 +239,50 @@ func TestParse(t *testing.T) {
"traefik.foo": "true", "traefik.foo": "true",
}, },
}, },
{
desc: "map string case sensitive",
args: []string{"--foo.caseSensitiveName=barBoo"},
element: &struct {
Foo map[string]string
}{},
expected: map[string]string{
"traefik.foo.caseSensitiveName": "barBoo",
},
},
{
desc: "map struct with sub-map case senstitive",
args: []string{"--foo.Name1.bar.name2.value=firstValue", "--foo.naMe1.bar.name2.value=secondValue"},
element: &struct {
Foo map[string]struct {
Bar map[string]struct{ Value string }
}
}{},
expected: map[string]string{
"traefik.foo.Name1.bar.name2.value": "secondValue",
},
},
{
desc: "map struct with sub-map and different case",
args: []string{"--foo.Name1.bar.name2.value=firstValue", "--foo.naMe1.bar.name2.value=secondValue"},
element: &struct {
Foo map[string]struct {
Bar map[string]struct{ Value string }
}
}{},
expected: map[string]string{
"traefik.foo.Name1.bar.name2.value": "secondValue",
},
},
{
desc: "slice with several flags 2 and different cases.",
args: []string{"--foo", "bar", "--Foo", "baz"},
element: &struct {
Foo []string
}{},
expected: map[string]string{
"traefik.foo": "bar,baz",
},
},
} }
for _, test := range testCases { for _, test := range testCases {