@@ -30,8 +30,8 @@ import (
3030func 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+ }
0 commit comments