From 91e63dea474b5a9e100687066e725dd1995e236d Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Doumenjou Date: Mon, 5 Aug 2019 15:22:03 +0200 Subject: [PATCH] Apply the case of the CLI flags for the configuration --- pkg/cli/commands_test.go | 88 ++++++++++++++++++------------ pkg/cli/loader_file.go | 9 ++- pkg/config/flag/flag_test.go | 14 +++++ pkg/config/flag/flagparser.go | 22 ++++++-- pkg/config/flag/flagparser_test.go | 84 ++++++++++++++++++++++++++++ 5 files changed, 174 insertions(+), 43 deletions(-) diff --git a/pkg/cli/commands_test.go b/pkg/cli/commands_test.go index e4f4a1d92..3796369ea 100644 --- a/pkg/cli/commands_test.go +++ b/pkg/cli/commands_test.go @@ -625,46 +625,62 @@ func Test_execute_configuration(t *testing.T) { } func Test_execute_configuration_file(t *testing.T) { - rootCmd := &Command{ - Name: "root", - Description: "This is a test", - Configuration: nil, - Run: func(_ []string) error { - return nil + testCases := []struct { + desc string + args []string + }{ + { + 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{ - Fuu: "test", + for _, test := range testCases { + 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) { diff --git a/pkg/cli/loader_file.go b/pkg/cli/loader_file.go index 86bbdc7be..2c0a04fe3 100644 --- a/pkg/cli/loader_file.go +++ b/pkg/cli/loader_file.go @@ -30,8 +30,15 @@ func (f *FileLoader) Load(args []string, cmd *Command) (bool, error) { } configFileFlag := "traefik.configfile" + if _, ok := ref["traefik.configFile"]; ok { + configFileFlag = "traefik.configFile" + } + 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) diff --git a/pkg/config/flag/flag_test.go b/pkg/config/flag/flag_test.go index c4683c7e8..171a3f714 100644 --- a/pkg/config/flag/flag_test.go +++ b/pkg/config/flag/flag_test.go @@ -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", args: []string{"--foo.name.value=bar"}, diff --git a/pkg/config/flag/flagparser.go b/pkg/config/flag/flagparser.go index 1009102cc..d28248315 100644 --- a/pkg/config/flag/flagparser.go +++ b/pkg/config/flag/flagparser.go @@ -16,6 +16,7 @@ func Parse(args []string, element interface{}) (map[string]string, error) { flagTypes: getFlagTypes(element), args: args, values: make(map[string]string), + keys: make(map[string]string), } for { @@ -35,6 +36,7 @@ type flagSet struct { flagTypes map[string]reflect.Kind args []string values map[string]string + keys map[string]string } func (f *flagSet) parseOne() (bool, error) { @@ -78,7 +80,8 @@ func (f *flagSet) parseOne() (bool, error) { 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") return true, nil } @@ -98,13 +101,20 @@ func (f *flagSet) parseOne() (bool, error) { } func (f *flagSet) setValue(name string, value string) { - n := strings.ToLower(parser.DefaultRootName + "." + name) - v, ok := f.values[n] + srcKey := parser.DefaultRootName + "." + name + neutralKey := strings.ToLower(srcKey) - if ok && f.flagTypes[name] == reflect.Slice { - f.values[n] = v + "," + value + key, ok := f.keys[neutralKey] + 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 } - f.values[n] = value + f.values[key] = value } diff --git a/pkg/config/flag/flagparser_test.go b/pkg/config/flag/flagparser_test.go index 46e2b4a62..8c45fdaf5 100644 --- a/pkg/config/flag/flagparser_test.go +++ b/pkg/config/flag/flagparser_test.go @@ -29,6 +29,16 @@ func TestParse(t *testing.T) { "traefik.foo": "true", }, }, + { + desc: "bool value capitalized", + args: []string{"--Foo"}, + element: &struct { + Foo bool + }{}, + expected: map[string]string{ + "traefik.Foo": "true", + }, + }, { desc: "equal", args: []string{"--foo=bar"}, @@ -39,6 +49,16 @@ func TestParse(t *testing.T) { "traefik.foo": "bar", }, }, + { + desc: "equal", + args: []string{"--Foo=Bar"}, + element: &struct { + Foo string + }{}, + expected: map[string]string{ + "traefik.Foo": "Bar", + }, + }, { desc: "space separated", args: []string{"--foo", "bar"}, @@ -49,6 +69,16 @@ func TestParse(t *testing.T) { "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", args: []string{"--foo=bir", "--", "--bar"}, @@ -91,6 +121,16 @@ func TestParse(t *testing.T) { "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", args: []string{"--foo.name.value=bar"}, @@ -199,6 +239,50 @@ func TestParse(t *testing.T) { "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 {