@@ -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,85 @@ 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
265
+ }
266
+ // Update the output with the the image name if it is not already set
267
+ if ! strings .Contains (output , "name=" ) {
268
+ output += ",name=" + parsedReference .String ()
241
269
}
242
- output += ",name=" + parsedReference .String ()
243
270
244
271
// pick the first tag and add it to output
245
272
for idx , tag := range tags {
246
273
parsedReference , err = referenceutil .Parse (tag )
247
274
if err != nil {
248
- return "" , nil , false , "" , nil , nil , err
275
+ return result , err
249
276
}
250
277
tags [idx ] = parsedReference .String ()
251
278
}
252
279
} else if len (tags ) == 0 {
253
280
output = output + ",dangling-name-prefix=<none>"
254
281
}
282
+ result .Tags = tags
255
283
256
- buildctlArgs = buildkitutil .BuildctlBaseArgs (options .BuildKitHost )
257
-
284
+ buildctlArgs := buildkitutil .BuildctlBaseArgs (options .BuildKitHost )
258
285
buildctlArgs = append (buildctlArgs , []string {
259
286
"build" ,
260
287
"--progress=" + options .Progress ,
@@ -271,9 +298,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
271
298
var err error
272
299
dir , err = buildkitutil .WriteTempDockerfile (options .Stdin )
273
300
if err != nil {
274
- return "" , nil , false , "" , nil , nil , err
301
+ return result , err
275
302
}
276
- cleanup = func () {
303
+ result . Cleanup = func () {
277
304
os .RemoveAll (dir )
278
305
}
279
306
} else {
@@ -286,12 +313,12 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
286
313
}
287
314
dir , file , err = buildkitutil .BuildKitFile (dir , file )
288
315
if err != nil {
289
- return "" , nil , false , "" , nil , nil , err
316
+ return result , err
290
317
}
291
318
292
319
buildCtx , err := parseContextNames (options .ExtendedBuildContext )
293
320
if err != nil {
294
- return "" , nil , false , "" , nil , nil , err
321
+ return result , err
295
322
}
296
323
297
324
for k , v := range buildCtx {
@@ -306,7 +333,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
306
333
if isOCILayout := strings .HasPrefix (v , "oci-layout://" ); isOCILayout {
307
334
args , err := parseBuildContextFromOCILayout (k , v )
308
335
if err != nil {
309
- return "" , nil , false , "" , nil , nil , err
336
+ return result , err
310
337
}
311
338
312
339
buildctlArgs = append (buildctlArgs , args ... )
@@ -315,7 +342,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
315
342
316
343
path , err := filepath .Abs (v )
317
344
if err != nil {
318
- return "" , nil , false , "" , nil , nil , err
345
+ return result , err
319
346
}
320
347
buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--local=%s=%s" , k , path ))
321
348
buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--opt=context:%s=local:%s" , k , k ))
@@ -362,7 +389,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
362
389
}
363
390
}
364
391
} else {
365
- return "" , nil , false , "" , nil , nil , fmt .Errorf ("invalid build arg %q" , ba )
392
+ return result , fmt .Errorf ("invalid build arg %q" , ba )
366
393
}
367
394
}
368
395
@@ -405,7 +432,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
405
432
optAttestType := strings .TrimPrefix (optAttestType , "type=" )
406
433
buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--opt=attest:%s=%s" , optAttestType , optAttestAttrs ))
407
434
} else {
408
- return "" , nil , false , "" , nil , nil , fmt .Errorf ("attestation type not specified" )
435
+ return result , fmt .Errorf ("attestation type not specified" )
409
436
}
410
437
}
411
438
@@ -434,11 +461,11 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
434
461
if options .IidFile != "" {
435
462
file , err := os .CreateTemp ("" , "buildkit-meta-*" )
436
463
if err != nil {
437
- return "" , nil , false , "" , nil , cleanup , err
464
+ return result , err
438
465
}
439
466
defer file .Close ()
440
- metaFile = file .Name ()
441
- buildctlArgs = append (buildctlArgs , "--metadata-file=" + metaFile )
467
+ result . MetaFile = file .Name ()
468
+ buildctlArgs = append (buildctlArgs , "--metadata-file=" + result . MetaFile )
442
469
}
443
470
444
471
if options .NetworkMode != "" {
@@ -453,7 +480,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
453
480
}
454
481
}
455
482
456
- return buildctlBinary , buildctlArgs , needsLoading , metaFile , tags , cleanup , nil
483
+ result .BuildctlArgs = buildctlArgs
484
+
485
+ return result , nil
457
486
}
458
487
459
488
func getDigestFromMetaFile (path string ) (string , error ) {
0 commit comments