@@ -61,18 +61,22 @@ func (p platformParser) DefaultSpec() platforms.Platform {
61
61
}
62
62
63
63
func Build (ctx context.Context , client * containerd.Client , options types.BuilderBuildOptions ) error {
64
- buildctlBinary , buildctlArgs , needsLoading , metaFile , tags , cleanup , err := generateBuildctlArgs (ctx , client , options )
64
+ buildCtlArgs , err := generateBuildctlArgs (ctx , client , options )
65
65
if err != nil {
66
66
return err
67
67
}
68
- if cleanup != nil {
69
- defer cleanup ()
68
+ if buildCtlArgs . Cleanup != nil {
69
+ defer buildCtlArgs . Cleanup ()
70
70
}
71
71
72
+ buildctlBinary := buildCtlArgs .BuildctlBinary
73
+ buildctlArgs := buildCtlArgs .BuildctlArgs
74
+
72
75
log .L .Debugf ("running %s %v" , buildctlBinary , buildctlArgs )
73
76
buildctlCmd := exec .Command (buildctlBinary , buildctlArgs ... )
74
77
buildctlCmd .Env = os .Environ ()
75
78
79
+ needsLoading := buildCtlArgs .NeedsLoading
76
80
var buildctlStdout io.Reader
77
81
if needsLoading {
78
82
buildctlStdout , err = buildctlCmd .StdoutPipe ()
@@ -95,6 +99,8 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
95
99
if err != nil {
96
100
return err
97
101
}
102
+
103
+ // Load the image into the containerd image store
98
104
if err = loadImage (ctx , buildctlStdout , options .GOptions .Namespace , options .GOptions .Address , options .GOptions .Snapshotter , options .Stdout , platMC , options .Quiet ); err != nil {
99
105
return err
100
106
}
@@ -105,7 +111,7 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
105
111
}
106
112
107
113
if options .IidFile != "" {
108
- id , err := getDigestFromMetaFile (metaFile )
114
+ id , err := getDigestFromMetaFile (buildCtlArgs . MetaFile )
109
115
if err != nil {
110
116
return err
111
117
}
@@ -114,6 +120,7 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
114
120
}
115
121
}
116
122
123
+ tags := buildCtlArgs .Tags
117
124
if len (tags ) > 1 {
118
125
log .L .Debug ("Found more than 1 tag" )
119
126
imageService := client .ImageService ()
@@ -160,11 +167,15 @@ func loadImage(ctx context.Context, in io.Reader, namespace, address, snapshotte
160
167
client .Close ()
161
168
}()
162
169
r := & readCounter {Reader : in }
163
- imgs , err := client .Import (ctx , r , containerd .WithDigestRef (archive .DigestTranslator (snapshotter )), containerd .WithSkipDigestRef (func (name string ) bool { return name != "" }), containerd .WithImportPlatform (platMC ))
170
+ imgs , err := client .Import (ctx , r ,
171
+ containerd .WithDigestRef (archive .DigestTranslator (snapshotter )),
172
+ containerd .WithSkipDigestRef (func (name string ) bool { return name != "" }),
173
+ containerd .WithImportPlatform (platMC ),
174
+ )
164
175
if err != nil {
165
176
if r .N == 0 {
166
177
// Avoid confusing "unrecognized image format"
167
- return errors . New ("no image was built" )
178
+ return fmt . Errorf ("no image was built: %w" , err )
168
179
}
169
180
if errors .Is (err , images .ErrEmptyWalk ) {
170
181
err = fmt .Errorf ("%w (Hint: set `--platform=PLATFORM` or `--all-platforms`)" , err )
@@ -192,69 +203,82 @@ func loadImage(ctx context.Context, in io.Reader, namespace, address, snapshotte
192
203
return nil
193
204
}
194
205
195
- func generateBuildctlArgs (ctx context.Context , client * containerd.Client , options types.BuilderBuildOptions ) (buildCtlBinary string ,
196
- buildctlArgs []string , needsLoading bool , metaFile string , tags []string , cleanup func (), err error ) {
206
+ type BuildctlArgsResult struct {
207
+ BuildctlArgs []string
208
+ BuildctlBinary string
209
+ Cleanup func ()
210
+ DestFile string
211
+ MetaFile string
212
+ NeedsLoading bool // Specifies whether the image needs to be loaded into the containerd image store
213
+ Tags []string
214
+ }
197
215
216
+ func generateBuildctlArgs (ctx context.Context , client * containerd.Client , options types.BuilderBuildOptions ) (result BuildctlArgsResult , err error ) {
198
217
buildctlBinary , err := buildkitutil .BuildctlBinary ()
199
218
if err != nil {
200
- return "" , nil , false , "" , nil , nil , err
219
+ return result , err
201
220
}
221
+ result .BuildctlBinary = buildctlBinary
202
222
203
223
output := options .Output
204
224
if output == "" {
205
225
info , err := client .Server (ctx )
206
226
if err != nil {
207
- return "" , nil , false , "" , nil , nil , err
227
+ return result , err
208
228
}
209
229
sharable , err := isImageSharable (options .BuildKitHost , options .GOptions .Namespace , info .UUID , options .GOptions .Snapshotter , options .Platform )
210
230
if err != nil {
211
- return "" , nil , false , "" , nil , nil , err
231
+ return result , err
212
232
}
213
233
if sharable {
214
234
output = "type=image,unpack=true" // ensure the target stage is unlazied (needed for any snapshotters)
215
235
} else {
216
- output = "type=docker"
236
+ // https://github.com/moby/buildkit?tab=readme-ov-file#output
237
+ // type=image is the native type for containerd
238
+ output = "type=image"
217
239
if len (options .Platform ) > 1 {
218
240
// For avoiding `error: failed to solve: docker exporter does not currently support exporting manifest lists`
219
241
// TODO: consider using type=oci for single-options.Platform build too
220
242
output = "type=oci"
221
243
}
222
- needsLoading = true
223
244
}
224
245
} else {
225
246
if ! strings .Contains (output , "type=" ) {
226
247
// should accept --output <DIR> as an alias of --output
227
248
// type=local,dest=<DIR>
228
249
output = fmt .Sprintf ("type=local,dest=%s" , output )
229
250
}
230
- if strings .Contains (output , "type=docker" ) || strings .Contains (output , "type=oci" ) {
231
- if ! strings .Contains (output , "dest=" ) {
232
- needsLoading = true
233
- }
251
+ }
252
+
253
+ if strings .Contains (output , "type=docker" ) || strings .Contains (output , "type=oci" ) {
254
+ if ! strings .Contains (output , "dest=" ) {
255
+ result .NeedsLoading = true
234
256
}
235
257
}
258
+
259
+ var tags []string
236
260
if tags = strutil .DedupeStrSlice (options .Tag ); len (tags ) > 0 {
237
261
ref := tags [0 ]
238
262
parsedReference , err := referenceutil .Parse (ref )
239
263
if err != nil {
240
- return "" , nil , false , "" , nil , nil , err
264
+ return result , err
241
265
}
242
266
output += ",name=" + parsedReference .String ()
243
267
244
268
// pick the first tag and add it to output
245
269
for idx , tag := range tags {
246
270
parsedReference , err = referenceutil .Parse (tag )
247
271
if err != nil {
248
- return "" , nil , false , "" , nil , nil , err
272
+ return result , err
249
273
}
250
274
tags [idx ] = parsedReference .String ()
251
275
}
252
276
} else if len (tags ) == 0 {
253
277
output = output + ",dangling-name-prefix=<none>"
254
278
}
279
+ result .Tags = tags
255
280
256
- buildctlArgs = buildkitutil .BuildctlBaseArgs (options .BuildKitHost )
257
-
281
+ buildctlArgs := buildkitutil .BuildctlBaseArgs (options .BuildKitHost )
258
282
buildctlArgs = append (buildctlArgs , []string {
259
283
"build" ,
260
284
"--progress=" + options .Progress ,
@@ -271,9 +295,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
271
295
var err error
272
296
dir , err = buildkitutil .WriteTempDockerfile (options .Stdin )
273
297
if err != nil {
274
- return "" , nil , false , "" , nil , nil , err
298
+ return result , err
275
299
}
276
- cleanup = func () {
300
+ result . Cleanup = func () {
277
301
os .RemoveAll (dir )
278
302
}
279
303
} else {
@@ -286,12 +310,12 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
286
310
}
287
311
dir , file , err = buildkitutil .BuildKitFile (dir , file )
288
312
if err != nil {
289
- return "" , nil , false , "" , nil , nil , err
313
+ return result , err
290
314
}
291
315
292
316
buildCtx , err := parseContextNames (options .ExtendedBuildContext )
293
317
if err != nil {
294
- return "" , nil , false , "" , nil , nil , err
318
+ return result , err
295
319
}
296
320
297
321
for k , v := range buildCtx {
@@ -306,7 +330,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
306
330
if isOCILayout := strings .HasPrefix (v , "oci-layout://" ); isOCILayout {
307
331
args , err := parseBuildContextFromOCILayout (k , v )
308
332
if err != nil {
309
- return "" , nil , false , "" , nil , nil , err
333
+ return result , err
310
334
}
311
335
312
336
buildctlArgs = append (buildctlArgs , args ... )
@@ -315,7 +339,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
315
339
316
340
path , err := filepath .Abs (v )
317
341
if err != nil {
318
- return "" , nil , false , "" , nil , nil , err
342
+ return result , err
319
343
}
320
344
buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--local=%s=%s" , k , path ))
321
345
buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--opt=context:%s=local:%s" , k , k ))
@@ -362,7 +386,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
362
386
}
363
387
}
364
388
} else {
365
- return "" , nil , false , "" , nil , nil , fmt .Errorf ("invalid build arg %q" , ba )
389
+ return result , fmt .Errorf ("invalid build arg %q" , ba )
366
390
}
367
391
}
368
392
@@ -405,7 +429,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
405
429
optAttestType := strings .TrimPrefix (optAttestType , "type=" )
406
430
buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--opt=attest:%s=%s" , optAttestType , optAttestAttrs ))
407
431
} else {
408
- return "" , nil , false , "" , nil , nil , fmt .Errorf ("attestation type not specified" )
432
+ return result , fmt .Errorf ("attestation type not specified" )
409
433
}
410
434
}
411
435
@@ -434,11 +458,11 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
434
458
if options .IidFile != "" {
435
459
file , err := os .CreateTemp ("" , "buildkit-meta-*" )
436
460
if err != nil {
437
- return "" , nil , false , "" , nil , cleanup , err
461
+ return result , err
438
462
}
439
463
defer file .Close ()
440
- metaFile = file .Name ()
441
- buildctlArgs = append (buildctlArgs , "--metadata-file=" + metaFile )
464
+ result . MetaFile = file .Name ()
465
+ buildctlArgs = append (buildctlArgs , "--metadata-file=" + result . MetaFile )
442
466
}
443
467
444
468
if options .NetworkMode != "" {
@@ -453,7 +477,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
453
477
}
454
478
}
455
479
456
- return buildctlBinary , buildctlArgs , needsLoading , metaFile , tags , cleanup , nil
480
+ result .BuildctlArgs = buildctlArgs
481
+
482
+ return result , nil
457
483
}
458
484
459
485
func getDigestFromMetaFile (path string ) (string , error ) {
0 commit comments