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