Skip to content

Commit

Permalink
Adjust parsing of flags when the output is a generic map[string]string
Browse files Browse the repository at this point in the history
  • Loading branch information
bruno-de-queiroz authored Feb 13, 2025
1 parent d116c5c commit 7e1b633
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
45 changes: 45 additions & 0 deletions flag/flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,51 @@ func TestDecode(t *testing.T) {
},
},
},
{
desc: "map string with '.' in key",
args: []string{"--foo.name.value=bar"},
element: &struct {
Foo map[string]string
}{},
expected: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"name.value": "bar",
},
},
},
{
desc: "map string with '.' in key and multiple entries",
args: []string{"--foo.name.value=bar", "--foo.name.value2=bar2"},
element: &struct {
Foo map[string]string
}{},
expected: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"name.value": "bar",
"name.value2": "bar2",
},
},
},
{
desc: "map string with '.' in key and multiple mixed entries",
args: []string{"--foo.name.value=bar", "--foo.name.value2=bar2", "--foo.name2=bar3"},
element: &struct {
Foo map[string]string
}{},
expected: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"name.value": "bar",
"name.value2": "bar2",
"name2": "bar3",
},
},
},
{
desc: "map struct",
args: []string{"--foo.name.value=bar"},
Expand Down
33 changes: 33 additions & 0 deletions flag/flagparser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,39 @@ func TestParse(t *testing.T) {
"traefik.foo.Name": "Bar",
},
},
{
desc: "map string with '.' in key",
args: []string{"--foo.name.value=bar"},
element: &struct {
Foo map[string]string
}{},
expected: map[string]string{
"traefik.foo.name.value": "bar",
},
},
{
desc: "map string with '.' in key and multiple entries",
args: []string{"--foo.name.value=bar", "--foo.name2.value2=baz"},
element: &struct {
Foo map[string]string
}{},
expected: map[string]string{
"traefik.foo.name.value": "bar",
"traefik.foo.name2.value2": "baz",
},
},
{
desc: "map string with '.' in key and multiple mixed entries",
args: []string{"--foo.name.value=bar", "--foo.name2.value2=baz", "--foo.name3=bay"},
element: &struct {
Foo map[string]string
}{},
expected: map[string]string{
"traefik.foo.name.value": "bar",
"traefik.foo.name2.value2": "baz",
"traefik.foo.name3": "bay",
},
},
{
desc: "map struct",
args: []string{"--foo.name.value=bar"},
Expand Down
19 changes: 19 additions & 0 deletions parser/element_fill.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,17 @@ func (f filler) setSliceAsStruct(field reflect.Value, node *Node) error {
return nil
}

func (f filler) fillRecursively(parent string, node *Node, field reflect.Value) {
if len(node.Children) == 0 {
field.SetMapIndex(reflect.ValueOf(parent), reflect.ValueOf(node.Value))
return
}

for _, child := range node.Children {
f.fillRecursively(parent+"."+child.Name, child, field)
}
}

func (f filler) setMap(field reflect.Value, node *Node) error {
if field.IsNil() {
field.Set(reflect.MakeMap(field.Type()))
Expand All @@ -312,6 +323,14 @@ func (f filler) setMap(field reflect.Value, node *Node) error {
return nil
}

if field.Type().Elem().Kind() == reflect.String {
for _, child := range node.Children {
f.fillRecursively(child.Name, child, field)
}

return nil
}

for _, child := range node.Children {
ptrValue := reflect.New(reflect.PointerTo(field.Type().Elem()))

Expand Down
91 changes: 91 additions & 0 deletions parser/element_fill_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,97 @@ func TestFill(t *testing.T) {
},
},
},
{
desc: "map string with key containing '.'",
node: &Node{
Name: "traefik",
Kind: reflect.Struct,
Children: []*Node{
{
Name: "Foo",
FieldName: "Foo",
Kind: reflect.Map,
Children: []*Node{
{Name: "name", Kind: reflect.Map, Children: []*Node{{Name: "value", Value: "hii", Kind: reflect.String}}},
},
},
},
},
element: &struct {
Foo map[string]string
}{},
expected: expected{
element: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"name.value": "hii",
},
},
},
},
{
desc: "map string with keys containing '.' and multiple entries",
node: &Node{
Name: "traefik",
Kind: reflect.Struct,
Children: []*Node{
{
Name: "Foo",
FieldName: "Foo",
Kind: reflect.Map,
Children: []*Node{
{Name: "name1", Kind: reflect.Map, Children: []*Node{{Name: "value", Value: "hii", Kind: reflect.String}, {Name: "value2", Value: "hii", Kind: reflect.String}}},
},
},
},
},
element: &struct {
Foo map[string]string
}{},
expected: expected{
element: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"name1.value": "hii",
"name1.value2": "hii",
},
},
},
},
{
desc: "map string with keys containing '.' and multiple mixed entries",
node: &Node{
Name: "traefik",
Kind: reflect.Struct,
Children: []*Node{
{
Name: "Foo",
FieldName: "Foo",
Kind: reflect.Map,
Children: []*Node{
{Name: "name1", Kind: reflect.Map, Children: []*Node{{Name: "value", Value: "hii", Kind: reflect.String}, {Name: "value2", Value: "hii", Kind: reflect.String}}},
{Name: "name2", Kind: reflect.String, Value: "hii"},
},
},
},
},
element: &struct {
Foo map[string]string
}{},
expected: expected{
element: &struct {
Foo map[string]string
}{
Foo: map[string]string{
"name1.value": "hii",
"name1.value2": "hii",
"name2": "hii",
},
},
},
},
{
desc: "map struct",
node: &Node{
Expand Down

0 comments on commit 7e1b633

Please sign in to comment.