Skip to content

Commit 3120ba5

Browse files
authored
Keep order of env in crane mutate (#1683)
1 parent afd15f1 commit 3120ba5

2 files changed

Lines changed: 75 additions & 13 deletions

File tree

cmd/crane/cmd/mutate.go

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ import (
3030
func NewCmdMutate(options *[]crane.Option) *cobra.Command {
3131
var labels map[string]string
3232
var annotations map[string]string
33+
var envVars keyToValue
3334
var entrypoint, cmd []string
34-
var envVars map[string]string
3535
var newLayers []string
3636
var outFile string
3737
var newRef string
@@ -163,7 +163,7 @@ func NewCmdMutate(options *[]crane.Option) *cobra.Command {
163163
}
164164
mutateCmd.Flags().StringToStringVarP(&annotations, "annotation", "a", nil, "New annotations to add")
165165
mutateCmd.Flags().StringToStringVarP(&labels, "label", "l", nil, "New labels to add")
166-
mutateCmd.Flags().StringToStringVarP(&envVars, "env", "e", nil, "New envvar to add")
166+
mutateCmd.Flags().VarP(&envVars, "env", "e", "New envvar to add")
167167
mutateCmd.Flags().StringSliceVar(&entrypoint, "entrypoint", nil, "New entrypoint to set")
168168
mutateCmd.Flags().StringSliceVar(&cmd, "cmd", nil, "New cmd to set")
169169
mutateCmd.Flags().StringVar(&newRepo, "repo", "", "Repository to push the mutated image to. If provided, push by digest to this repository.")
@@ -186,29 +186,91 @@ func validateKeyVals(kvPairs map[string]string) error {
186186
}
187187

188188
// setEnvVars override envvars in a config
189-
func setEnvVars(cfg *v1.ConfigFile, envVars map[string]string) error {
189+
func setEnvVars(cfg *v1.ConfigFile, envVars keyToValue) error {
190+
eMap := envVars.Map()
190191
newEnv := make([]string, 0, len(cfg.Config.Env))
192+
isWindows := cfg.OS == "windows"
193+
194+
// Keep the old values.
191195
for _, old := range cfg.Config.Env {
192-
split := strings.SplitN(old, "=", 2)
193-
if len(split) != 2 {
196+
oldKey, _, ok := strings.Cut(old, "=")
197+
if !ok {
194198
return fmt.Errorf("invalid key value pair in config: %s", old)
195199
}
196-
// keep order so override if specified again
197-
oldKey := split[0]
198-
if v, ok := envVars[oldKey]; ok {
199-
newEnv = append(newEnv, fmt.Sprintf("%s=%s", oldKey, v))
200-
delete(envVars, oldKey)
200+
201+
if v, ok := eMap[oldKey]; ok {
202+
// Override in place to keep ordering of original env.
203+
newEnv = append(newEnv, oldKey+"="+v)
204+
205+
// Remove this from eMap so we don't add it twice.
206+
delete(eMap, oldKey)
201207
} else {
202208
newEnv = append(newEnv, old)
203209
}
204210
}
205-
isWindows := cfg.OS == "windows"
206-
for k, v := range envVars {
211+
212+
// Append the new values.
213+
for _, e := range envVars.values {
214+
k, v := e.key, e.value
215+
216+
if _, ok := eMap[k]; !ok {
217+
// If we come across a value not in eMap, it means we replaced the
218+
// old env in-place and deleted it from eMap, so we can skip adding.
219+
continue
220+
}
221+
207222
if isWindows {
208223
k = strings.ToUpper(k)
209224
}
225+
210226
newEnv = append(newEnv, fmt.Sprintf("%s=%s", k, v))
211227
}
228+
212229
cfg.Config.Env = newEnv
213230
return nil
214231
}
232+
233+
type env struct {
234+
key string
235+
value string
236+
}
237+
238+
type keyToValue struct {
239+
values []env
240+
changed bool
241+
mapped map[string]string
242+
}
243+
244+
func (o *keyToValue) Set(val string) error {
245+
before, after, ok := strings.Cut(val, "=")
246+
if !ok {
247+
return fmt.Errorf("%s must be formatted as key=value", val)
248+
}
249+
250+
if !o.changed {
251+
o.values = []env{}
252+
o.mapped = map[string]string{}
253+
}
254+
255+
o.values = append(o.values, env{before, after})
256+
o.mapped[before] = after
257+
o.changed = true
258+
259+
return nil
260+
}
261+
262+
func (o *keyToValue) Type() string {
263+
return "keyToValue"
264+
}
265+
266+
func (o *keyToValue) String() string {
267+
ss := make([]string, 0, len(o.values))
268+
for _, e := range o.values {
269+
ss = append(ss, e.key+"="+e.value)
270+
}
271+
return strings.Join(ss, ",")
272+
}
273+
274+
func (o *keyToValue) Map() map[string]string {
275+
return o.mapped
276+
}

cmd/crane/doc/crane_mutate.md

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)