Skip to content

Commit a4734c0

Browse files
authored
Merge pull request #43 from gitpod-io/to/path-env
Ensure that `EnvVarCombineMergeUnique` keeps order
2 parents 7a3bd09 + 9a56c6d commit a4734c0

File tree

2 files changed

+201
-7
lines changed

2 files changed

+201
-7
lines changed

pkg/dazzle/combiner.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -311,14 +311,26 @@ func mergeEnv(base *ociv1.Image, others []*ociv1.Image, vars []EnvVarCombination
311311
case EnvVarCombineMerge:
312312
envs[k] += ":" + v
313313
case EnvVarCombineMergeUnique:
314-
vs := make(map[string]struct{})
315-
for _, s := range strings.Split(envValue, ":") {
316-
vs[s] = struct{}{}
314+
var vs []string
315+
vs = append(vs, strings.Split(envValue, ":")...)
316+
vs = append(vs, strings.Split(v, ":")...)
317+
318+
var (
319+
vss []string
320+
idx = make(map[string]struct{})
321+
)
322+
lenVS := len(vs) - 1
323+
for i := range vs {
324+
v := vs[lenVS-i]
325+
if _, exists := idx[v]; exists {
326+
continue
327+
}
328+
idx[v] = struct{}{}
329+
vss = append(vss, v)
317330
}
318-
vs[v] = struct{}{}
319-
vss := make([]string, 0, len(vs))
320-
for s := range vs {
321-
vss = append(vss, s)
331+
332+
for i, j := 0, len(vss)-1; i < j; i, j = i+1, j-1 {
333+
vss[i], vss[j] = vss[j], vss[i]
322334
}
323335
envs[k] = strings.Join(vss, ":")
324336
}

pkg/dazzle/combiner_test.go

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright © 2020 Gitpod
2+
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package dazzle
22+
23+
import (
24+
"testing"
25+
26+
"github.com/google/go-cmp/cmp"
27+
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
28+
)
29+
30+
func TestMergeEnv(t *testing.T) {
31+
tests := []struct {
32+
name string
33+
base *ociv1.Image
34+
others []*ociv1.Image
35+
vars []EnvVarCombination
36+
expect []string
37+
}{
38+
{
39+
name: "EnvVarCombineMergeUnique",
40+
base: &ociv1.Image{
41+
Config: ociv1.ImageConfig{
42+
Env: []string{
43+
"PATH=first:second:third:common-value",
44+
},
45+
},
46+
},
47+
others: []*ociv1.Image{
48+
{
49+
Config: ociv1.ImageConfig{
50+
Env: []string{
51+
"PATH=fourth:fifth:common-value",
52+
},
53+
},
54+
},
55+
{
56+
Config: ociv1.ImageConfig{
57+
Env: []string{
58+
"PATH=sixth:sixth:common-value",
59+
},
60+
},
61+
},
62+
{
63+
Config: ociv1.ImageConfig{
64+
Env: []string{
65+
"PATH=eighth:seventh:eighth:common-value",
66+
},
67+
},
68+
},
69+
},
70+
vars: []EnvVarCombination{
71+
{
72+
Name: "PATH",
73+
Action: EnvVarCombineMergeUnique,
74+
},
75+
},
76+
expect: []string{"PATH=first:second:third:fourth:fifth:sixth:seventh:eighth:common-value"},
77+
},
78+
{
79+
name: "EnvVarCombineMerge",
80+
base: &ociv1.Image{
81+
Config: ociv1.ImageConfig{
82+
Env: []string{
83+
"PATH=first:second:third:common-value",
84+
},
85+
},
86+
},
87+
others: []*ociv1.Image{
88+
{
89+
Config: ociv1.ImageConfig{
90+
Env: []string{
91+
"PATH=fourth:fifth:common-value",
92+
},
93+
},
94+
},
95+
{
96+
Config: ociv1.ImageConfig{
97+
Env: []string{
98+
"PATH=sixth:sixth:common-value",
99+
},
100+
},
101+
},
102+
{
103+
Config: ociv1.ImageConfig{
104+
Env: []string{
105+
"PATH=eighth:seventh:eighth:common-value",
106+
},
107+
},
108+
},
109+
},
110+
vars: []EnvVarCombination{
111+
{
112+
Name: "PATH",
113+
Action: EnvVarCombineMerge,
114+
},
115+
},
116+
expect: []string{"PATH=first:second:third:common-value:fourth:fifth:common-value:sixth:sixth:common-value:eighth:seventh:eighth:common-value"},
117+
},
118+
{
119+
name: "EnvVarCombineUseLast",
120+
base: &ociv1.Image{
121+
Config: ociv1.ImageConfig{
122+
Env: []string{
123+
"PATH=first:second:third:common-value",
124+
},
125+
},
126+
},
127+
others: []*ociv1.Image{
128+
{
129+
Config: ociv1.ImageConfig{
130+
Env: []string{
131+
"PATH=fourth:fifth:common-value",
132+
},
133+
},
134+
},
135+
},
136+
vars: []EnvVarCombination{
137+
{
138+
Name: "PATH",
139+
Action: EnvVarCombineUseLast,
140+
},
141+
},
142+
expect: []string{"PATH=fourth:fifth:common-value"},
143+
},
144+
{
145+
name: "EnvVarCombineUseFirst",
146+
base: &ociv1.Image{
147+
Config: ociv1.ImageConfig{
148+
Env: []string{
149+
"PATH=first:second:third:common-value",
150+
},
151+
},
152+
},
153+
others: []*ociv1.Image{
154+
{
155+
Config: ociv1.ImageConfig{
156+
Env: []string{
157+
"PATH=fourth:fifth:common-value",
158+
},
159+
},
160+
},
161+
},
162+
vars: []EnvVarCombination{
163+
{
164+
Name: "PATH",
165+
Action: EnvVarCombineUseFirst,
166+
},
167+
},
168+
expect: []string{"PATH=first:second:third:common-value"},
169+
},
170+
}
171+
for _, test := range tests {
172+
t.Run(test.name, func(t *testing.T) {
173+
envs, err := mergeEnv(test.base, test.others, test.vars)
174+
if err != nil {
175+
t.Fatal(err)
176+
}
177+
if diff := cmp.Diff(envs, test.expect); len(diff) != 0 {
178+
t.Errorf("mergeEnv() mismatch (-want +got):\n%s", diff)
179+
}
180+
})
181+
}
182+
}

0 commit comments

Comments
 (0)