Skip to content

Commit 3eda0a4

Browse files
authored
Merge pull request #687 from nginx-proxy/fix/679-v2
fix(reflect): handle deep get of map with dot(s) in key name
2 parents 1089849 + e15e65a commit 3eda0a4

File tree

4 files changed

+74
-5
lines changed

4 files changed

+74
-5
lines changed

internal/template/groupby_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ var groupByContainers = []*context.RuntimeContainer{
2929
ID: "3",
3030
},
3131
{
32-
ID: "4",
32+
Env: map[string]string{},
33+
ID: "4",
3334
},
3435
}
3536

@@ -170,6 +171,10 @@ func TestGroupByMulti(t *testing.T) {
170171
},
171172
ID: "3",
172173
},
174+
{
175+
Env: map[string]string{},
176+
ID: "4",
177+
},
173178
}
174179

175180
groups, _ := groupByMulti(containers, "Env.VIRTUAL_HOST", ",")

internal/template/reflect.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,29 @@ func deepGetImpl(v reflect.Value, path []string) interface{} {
4141
case reflect.Struct:
4242
return deepGetImpl(v.FieldByName(path[0]), path[1:])
4343
case reflect.Map:
44-
return deepGetImpl(v.MapIndex(reflect.ValueOf(path[0])), path[1:])
44+
// If the first part of the path is a key in the map, we use it directly
45+
if mapValue := v.MapIndex(reflect.ValueOf(path[0])); mapValue.IsValid() {
46+
return deepGetImpl(mapValue, path[1:])
47+
}
48+
49+
// If the first part of the path is not a key in the map, we try to find a valid key by joining the path parts
50+
var builder strings.Builder
51+
for i, pathPart := range path {
52+
if i > 0 {
53+
builder.WriteString(".")
54+
}
55+
builder.WriteString(pathPart)
56+
joinedPath := builder.String()
57+
58+
if mapValue := v.MapIndex(reflect.ValueOf(joinedPath)); mapValue.IsValid() {
59+
if i == len(path) {
60+
return mapValue.Interface()
61+
}
62+
return deepGetImpl(mapValue, path[i+1:])
63+
}
64+
}
65+
66+
return nil
4567
case reflect.Slice, reflect.Array:
4668
i, err := parseAllocateInt(path[0])
4769
if err != nil {

internal/template/reflect_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ func TestDeepGet(t *testing.T) {
6262
path string
6363
want interface{}
6464
}{
65+
{
66+
"map of string",
67+
map[string]string{
68+
"Env": "quux",
69+
},
70+
"Env",
71+
"quux",
72+
},
6573
{
6674
"map key empty string",
6775
map[string]map[string]map[string]string{
@@ -74,6 +82,28 @@ func TestDeepGet(t *testing.T) {
7482
"...",
7583
"foo",
7684
},
85+
{
86+
"map with dot in key",
87+
map[string]map[string]string{
88+
"Env": {
89+
"foo.bar.baz.qux": "quux",
90+
},
91+
},
92+
"Env.foo.bar.baz.qux",
93+
"quux",
94+
},
95+
{
96+
"nested maps with dot in keys",
97+
map[string]map[string]map[string]string{
98+
"Env": {
99+
"foo.bar": {
100+
"baz.qux": "quux",
101+
},
102+
},
103+
},
104+
"Env.foo.bar.baz.qux",
105+
"quux",
106+
},
77107
{"struct", s, "X", "foo"},
78108
{"pointer to struct", sp, "X", "foo"},
79109
{"double pointer to struct", &sp, ".X", nil},

internal/template/sort_test.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,26 +55,36 @@ func TestSortObjectsByKeys(t *testing.T) {
5555
Env: map[string]string{
5656
"VIRTUAL_HOST": "bar.localhost",
5757
},
58+
Labels: map[string]string{
59+
"com.docker.compose.container_number": "1",
60+
},
5861
ID: "11",
5962
}
6063
o1 := &context.RuntimeContainer{
6164
Created: time.Date(2021, 1, 2, 0, 0, 10, 0, time.UTC),
6265
Env: map[string]string{
6366
"VIRTUAL_HOST": "foo.localhost",
6467
},
68+
Labels: map[string]string{
69+
"com.docker.compose.container_number": "11",
70+
},
6571
ID: "1",
6672
}
6773
o2 := &context.RuntimeContainer{
6874
Created: time.Date(2021, 1, 2, 0, 0, 0, 0, time.UTC),
6975
Env: map[string]string{
7076
"VIRTUAL_HOST": "baz.localhost",
7177
},
72-
ID: "3",
78+
Labels: map[string]string{},
79+
ID: "3",
7380
}
7481
o3 := &context.RuntimeContainer{
7582
Created: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
7683
Env: map[string]string{},
77-
ID: "8",
84+
Labels: map[string]string{
85+
"com.docker.compose.container_number": "2",
86+
},
87+
ID: "8",
7888
}
7989
containers := []*context.RuntimeContainer{o0, o1, o2, o3}
8090

@@ -85,9 +95,11 @@ func TestSortObjectsByKeys(t *testing.T) {
8595
want []interface{}
8696
}{
8797
{"Asc simple", sortObjectsByKeysAsc, "ID", []interface{}{o1, o2, o3, o0}},
88-
{"Asc complex", sortObjectsByKeysAsc, "Env.VIRTUAL_HOST", []interface{}{o3, o0, o2, o1}},
8998
{"Desc simple", sortObjectsByKeysDesc, "ID", []interface{}{o0, o3, o2, o1}},
99+
{"Asc complex", sortObjectsByKeysAsc, "Env.VIRTUAL_HOST", []interface{}{o3, o0, o2, o1}},
90100
{"Desc complex", sortObjectsByKeysDesc, "Env.VIRTUAL_HOST", []interface{}{o1, o2, o0, o3}},
101+
{"Asc complex w/ dots in key name", sortObjectsByKeysAsc, "Labels.com.docker.compose.container_number", []interface{}{o2, o0, o3, o1}},
102+
{"Desc complex w/ dots in key name", sortObjectsByKeysDesc, "Labels.com.docker.compose.container_number", []interface{}{o1, o3, o0, o2}},
91103
{"Asc time", sortObjectsByKeysAsc, "Created", []interface{}{o3, o0, o2, o1}},
92104
{"Desc time", sortObjectsByKeysDesc, "Created", []interface{}{o1, o2, o0, o3}},
93105
} {

0 commit comments

Comments
 (0)