@@ -39,10 +39,10 @@ func GenerateImageSpecStage(imageSpec *config.ImageSpec, baseStageOptions *BaseS
39
39
}
40
40
41
41
func newImageSpecStage (imageSpec * config.ImageSpec , baseStageOptions * BaseStageOptions ) * ImageSpecStage {
42
- s := & ImageSpecStage {}
43
- s . imageSpec = imageSpec
44
- s . BaseStage = NewBaseStage (ImageSpec , baseStageOptions )
45
- return s
42
+ return & ImageSpecStage {
43
+ imageSpec : imageSpec ,
44
+ BaseStage : NewBaseStage (ImageSpec , baseStageOptions ),
45
+ }
46
46
}
47
47
48
48
func (s * ImageSpecStage ) IsBuildable () bool {
@@ -56,67 +56,55 @@ func (s *ImageSpecStage) IsMutable() bool {
56
56
func (s * ImageSpecStage ) PrepareImage (ctx context.Context , _ Conveyor , _ container_backend.ContainerBackend , prevBuiltImage , stageImage * StageImage , _ container_backend.BuildContextArchiver ) error {
57
57
if s .imageSpec != nil {
58
58
imageInfo := prevBuiltImage .Image .GetStageDesc ().Info
59
+ newConfig := s .baseConfig ()
59
60
60
- newConfig := image.Config {
61
- Author : s .imageSpec .Author ,
62
- User : s .imageSpec .User ,
63
- Entrypoint : s .imageSpec .Entrypoint ,
64
- Cmd : s .imageSpec .Cmd ,
65
- WorkingDir : s .imageSpec .WorkingDir ,
66
- StopSignal : s .imageSpec .StopSignal ,
67
- }
68
-
69
- // Entrypoint and Cmd handling.
70
61
{
71
- // If CMD is defined from the base image, setting ENTRYPOINT will reset CMD to an empty value.
72
- // In this scenario, CMD must be defined in the current image to have a value.
73
- // rel https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact
74
- if s .imageSpec .Entrypoint != nil {
75
- newConfig .Entrypoint = s .imageSpec .Entrypoint
76
- if s .imageSpec .Cmd == nil {
77
- newConfig .ClearCmd = true
78
- }
79
- }
80
-
81
- if s .imageSpec .Cmd != nil {
82
- newConfig .Cmd = s .imageSpec .Cmd
62
+ // labels
63
+ resultLabels , err := s .modifyLabels (ctx , imageInfo .Labels , s .imageSpec .Labels , s .imageSpec .RemoveLabels , s .imageSpec .KeepEssentialWerfLabels )
64
+ if err != nil {
65
+ return fmt .Errorf ("unable to modify labels: %s" , err )
83
66
}
84
-
85
- newConfig .ClearCmd = newConfig .ClearCmd || s .imageSpec .ClearCmd
86
- newConfig .ClearEntrypoint = newConfig .ClearEntrypoint || s .imageSpec .ClearEntrypoint
67
+ newConfig .Labels = resultLabels
87
68
}
88
69
89
- resultLabels , err := s .modifyLabels (ctx , imageInfo .Labels , s .imageSpec .Labels , s .imageSpec .RemoveLabels , s .imageSpec .KeepEssentialWerfLabels )
90
- if err != nil {
91
- return fmt .Errorf ("unable to modify labels: %s" , err )
70
+ {
71
+ // envs
72
+ resultEnvs , err := modifyEnv (imageInfo .Env , s .imageSpec .RemoveEnv , s .imageSpec .Env )
73
+ if err != nil {
74
+ return fmt .Errorf ("unable to modify env: %w" , err )
75
+ }
76
+ newConfig .Env = resultEnvs
92
77
}
93
78
94
- newConfig .Labels = resultLabels
95
- newConfig .Env , err = modifyEnv (imageInfo .Env , s .imageSpec .RemoveEnv , s .imageSpec .Env )
96
- if err != nil {
97
- return fmt .Errorf ("unable to modify env: %w" , err )
79
+ {
80
+ // volumes
81
+ newConfig .Volumes = modifyVolumes (imageInfo .Volumes , s .imageSpec .RemoveVolumes , s .imageSpec .Volumes )
98
82
}
99
- newConfig .Volumes = modifyVolumes (imageInfo .Volumes , s .imageSpec .RemoveVolumes , s .imageSpec .Volumes )
100
83
101
- if s .imageSpec .Expose != nil {
102
- newConfig .ExposedPorts = make (map [string ]struct {}, len (s .imageSpec .Expose ))
103
- for _ , expose := range s .imageSpec .Expose {
104
- newConfig .ExposedPorts [expose ] = struct {}{}
84
+ {
85
+ // expose
86
+ if s .imageSpec .Expose != nil {
87
+ newConfig .ExposedPorts = make (map [string ]struct {}, len (s .imageSpec .Expose ))
88
+ for _ , expose := range s .imageSpec .Expose {
89
+ newConfig .ExposedPorts [expose ] = struct {}{}
90
+ }
105
91
}
106
92
}
107
93
108
- if s .imageSpec .Healthcheck != nil {
109
- newConfig .HealthConfig = & image.HealthConfig {
110
- Test : s .imageSpec .Healthcheck .Test ,
111
- Interval : toDuration (s .imageSpec .Healthcheck .Interval ),
112
- Timeout : toDuration (s .imageSpec .Healthcheck .Timeout ),
113
- StartPeriod : toDuration (s .imageSpec .Healthcheck .StartPeriod ),
114
- Retries : s .imageSpec .Healthcheck .Retries ,
94
+ {
95
+ // healthcheck
96
+ if s .imageSpec .Healthcheck != nil {
97
+ newConfig .HealthConfig = & image.HealthConfig {
98
+ Test : s .imageSpec .Healthcheck .Test ,
99
+ Interval : toDuration (s .imageSpec .Healthcheck .Interval ),
100
+ Timeout : toDuration (s .imageSpec .Healthcheck .Timeout ),
101
+ StartPeriod : toDuration (s .imageSpec .Healthcheck .StartPeriod ),
102
+ Retries : s .imageSpec .Healthcheck .Retries ,
103
+ }
115
104
}
116
105
}
117
106
118
- newConfig .ClearHistory = s .imageSpec .ClearHistory
119
-
107
+ // set config
120
108
stageImage .Image .SetImageSpecConfig (& newConfig )
121
109
}
122
110
@@ -150,72 +138,79 @@ func (s *ImageSpecStage) GetDependencies(_ context.Context, _ Conveyor, _ contai
150
138
args = append (args , s .imageSpec .StopSignal )
151
139
args = append (args , fmt .Sprint (s .imageSpec .Healthcheck ))
152
140
153
- return util .Sha256Hash (args ... ), nil
154
- }
155
-
156
- func (s * ImageSpecStage ) modifyLabels (ctx context.Context , labels , addLabels map [string ]string , removeLabels []string , keepEssentialWerfLabels bool ) (map [string ]string , error ) {
157
- if labels == nil {
158
- labels = make (map [string ]string )
141
+ if s .imageSpec .ClearUser {
142
+ args = append (args , fmt .Sprint (s .imageSpec .ClearUser ))
159
143
}
160
144
161
- serviceLabels := s .stageImage .Image .GetBuildServiceLabels ()
162
- labels = util .MergeMaps (labels , serviceLabels )
163
-
164
- processedAddLabels := make (map [string ]string , len (addLabels ))
165
- data := labelsTemplateData {
166
- Project : s .projectName ,
167
- Image : s .imageName ,
145
+ if s .imageSpec .ClearWorkingDir {
146
+ args = append (args , fmt .Sprint (s .imageSpec .ClearWorkingDir ))
168
147
}
169
148
170
- for key , value := range addLabels {
171
- newKey , newValue , err := replaceLabelTemplate (key , value , data )
172
- if err != nil {
173
- return nil , err
174
- }
175
- processedAddLabels [newKey ] = newValue
149
+ if s .imageSpec .KeepEssentialWerfLabels {
150
+ args = append (args , fmt .Sprint (s .imageSpec .KeepEssentialWerfLabels ))
176
151
}
177
152
178
- labels = util .MergeMaps (labels , processedAddLabels )
153
+ return util .Sha256Hash (args ... ), nil
154
+ }
179
155
180
- exactMatches := make (map [string ]struct {})
181
- var regexPatterns []* regexp.Regexp
156
+ func (s * ImageSpecStage ) baseConfig () image.Config {
157
+ newConfig := image.Config {
158
+ Author : s .imageSpec .Author ,
159
+ User : s .imageSpec .User ,
160
+ Entrypoint : s .imageSpec .Entrypoint ,
161
+ Cmd : s .imageSpec .Cmd ,
162
+ WorkingDir : s .imageSpec .WorkingDir ,
163
+ StopSignal : s .imageSpec .StopSignal ,
164
+ ClearHistory : s .imageSpec .ClearHistory ,
165
+ ClearUser : s .imageSpec .ClearUser ,
166
+ ClearWorkingDir : s .imageSpec .ClearWorkingDir ,
167
+ }
182
168
183
- for _ , pattern := range removeLabels {
184
- if strings .HasPrefix (pattern , "/" ) && strings .HasSuffix (pattern , "/" ) {
185
- expr := fmt .Sprintf ("^%s$" , pattern [1 :len (pattern )- 1 ])
186
- re , err := regexp .Compile (expr )
187
- if err != nil {
188
- return nil , err
169
+ // Entrypoint and Cmd handling.
170
+ {
171
+ // If CMD is defined from the base image, setting ENTRYPOINT will reset CMD to an empty value.
172
+ // In this scenario, CMD must be defined in the current image to have a value.
173
+ // rel https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact
174
+ if s .imageSpec .Entrypoint != nil {
175
+ newConfig .Entrypoint = s .imageSpec .Entrypoint
176
+ if s .imageSpec .Cmd == nil {
177
+ newConfig .ClearCmd = true
189
178
}
190
- regexPatterns = append (regexPatterns , re )
191
- } else {
192
- exactMatches [pattern ] = struct {}{}
193
179
}
194
- }
195
180
196
- matchFunc := func (key string ) bool {
197
- if _ , found := exactMatches [key ]; found {
198
- return true
181
+ if s .imageSpec .Cmd != nil {
182
+ newConfig .Cmd = s .imageSpec .Cmd
199
183
}
200
- for _ , re := range regexPatterns {
201
- if re .MatchString (key ) {
202
- return true
203
- }
204
- }
205
- return false
184
+
185
+ newConfig .ClearCmd = newConfig .ClearCmd || s .imageSpec .ClearCmd
186
+ newConfig .ClearEntrypoint = newConfig .ClearEntrypoint || s .imageSpec .ClearEntrypoint
187
+ }
188
+ return newConfig
189
+ }
190
+
191
+ func (s * ImageSpecStage ) modifyLabels (ctx context.Context , labels , addLabels map [string ]string , removeLabels []string , keepEssentialWerfLabels bool ) (map [string ]string , error ) {
192
+ if labels == nil {
193
+ labels = make (map [string ]string )
194
+ }
195
+
196
+ serviceLabels := s .stageImage .Image .GetBuildServiceLabels ()
197
+ labels = util .MergeMaps (labels , serviceLabels )
198
+
199
+ exactMatches , regexPatterns , err := compileRemovePatterns (removeLabels )
200
+ if err != nil {
201
+ return nil , err
206
202
}
207
203
208
204
shouldPrintGlobalWarn := false
209
205
for key := range labels {
210
- if ! matchFunc (key ) {
206
+ if ! matchKey (key , exactMatches , regexPatterns ) {
211
207
continue
212
208
}
213
209
214
210
if key == image .WerfLabel || key == image .WerfParentStageID {
215
211
if ! keepEssentialWerfLabels {
216
212
shouldPrintGlobalWarn = true
217
213
}
218
-
219
214
continue
220
215
}
221
216
@@ -226,6 +221,22 @@ func (s *ImageSpecStage) modifyLabels(ctx context.Context, labels, addLabels map
226
221
global_warnings .GlobalWarningLn (ctx , werfLabelsGlobalWarning )
227
222
}
228
223
224
+ processedAddLabels := make (map [string ]string , len (addLabels ))
225
+ data := labelsTemplateData {
226
+ Project : s .projectName ,
227
+ Image : s .imageName ,
228
+ }
229
+
230
+ for key , value := range addLabels {
231
+ newKey , newValue , err := replaceLabelTemplate (key , value , data )
232
+ if err != nil {
233
+ return nil , err
234
+ }
235
+ processedAddLabels [newKey ] = newValue
236
+ }
237
+
238
+ labels = util .MergeMaps (labels , processedAddLabels )
239
+
229
240
return labels , nil
230
241
}
231
242
@@ -281,11 +292,17 @@ func modifyEnv(env, removeKeys []string, addKeysMap map[string]string) ([]string
281
292
"WERF_COMMIT_TIME_UNIX" ,
282
293
}... )
283
294
284
- for _ , key := range removeKeys {
285
- delete (baseEnvMap , key )
295
+ exactMatches , regexPatterns , err := compileRemovePatterns (removeKeys )
296
+ if err != nil {
297
+ return nil , err
298
+ }
299
+
300
+ for key := range baseEnvMap {
301
+ if matchKey (key , exactMatches , regexPatterns ) {
302
+ delete (baseEnvMap , key )
303
+ }
286
304
}
287
305
288
- // FIXME: (v3) This is a temporary solution to remove werf SSH_AUTH_SOCK that persist after build.
289
306
if envValue , hasEnv := baseEnvMap [ssh_agent .SSHAuthSockEnv ]; hasEnv && envValue == container_backend .SSHContainerAuthSockPath {
290
307
delete (baseEnvMap , ssh_agent .SSHAuthSockEnv )
291
308
}
@@ -330,3 +347,35 @@ func sortSliceWithNewSlice(original []string) []string {
330
347
func toDuration (seconds int ) time.Duration {
331
348
return time .Duration (seconds ) * time .Second
332
349
}
350
+
351
+ func compileRemovePatterns (removePatterns []string ) (map [string ]struct {}, []* regexp.Regexp , error ) {
352
+ exactMatches := make (map [string ]struct {})
353
+ var regexPatterns []* regexp.Regexp
354
+
355
+ for _ , pattern := range removePatterns {
356
+ if strings .HasPrefix (pattern , "/" ) && strings .HasSuffix (pattern , "/" ) {
357
+ expr := fmt .Sprintf ("^%s$" , pattern [1 :len (pattern )- 1 ])
358
+ re , err := regexp .Compile (expr )
359
+ if err != nil {
360
+ return nil , nil , err
361
+ }
362
+ regexPatterns = append (regexPatterns , re )
363
+ } else {
364
+ exactMatches [pattern ] = struct {}{}
365
+ }
366
+ }
367
+
368
+ return exactMatches , regexPatterns , nil
369
+ }
370
+
371
+ func matchKey (key string , exactMatches map [string ]struct {}, regexPatterns []* regexp.Regexp ) bool {
372
+ if _ , found := exactMatches [key ]; found {
373
+ return true
374
+ }
375
+ for _ , re := range regexPatterns {
376
+ if re .MatchString (key ) {
377
+ return true
378
+ }
379
+ }
380
+ return false
381
+ }
0 commit comments