@@ -61,18 +61,22 @@ func (p platformParser) DefaultSpec() platforms.Platform {
6161}
6262
6363func 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 )
6565 if err != nil {
6666 return err
6767 }
68- if cleanup != nil {
69- defer cleanup ()
68+ if buildCtlArgs . Cleanup != nil {
69+ defer buildCtlArgs . Cleanup ()
7070 }
7171
72+ buildctlBinary := buildCtlArgs .BuildctlBinary
73+ buildctlArgs := buildCtlArgs .BuildctlArgs
74+
7275 log .L .Debugf ("running %s %v" , buildctlBinary , buildctlArgs )
7376 buildctlCmd := exec .Command (buildctlBinary , buildctlArgs ... )
7477 buildctlCmd .Env = os .Environ ()
7578
79+ needsLoading := buildCtlArgs .NeedsLoading
7680 var buildctlStdout io.Reader
7781 if needsLoading {
7882 buildctlStdout , err = buildctlCmd .StdoutPipe ()
@@ -95,6 +99,8 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
9599 if err != nil {
96100 return err
97101 }
102+
103+ // Load the image into the containerd image store
98104 if err = loadImage (ctx , buildctlStdout , options .GOptions .Namespace , options .GOptions .Address , options .GOptions .Snapshotter , options .Stdout , platMC , options .Quiet ); err != nil {
99105 return err
100106 }
@@ -105,7 +111,7 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
105111 }
106112
107113 if options .IidFile != "" {
108- id , err := getDigestFromMetaFile (metaFile )
114+ id , err := getDigestFromMetaFile (buildCtlArgs . MetaFile )
109115 if err != nil {
110116 return err
111117 }
@@ -114,6 +120,7 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
114120 }
115121 }
116122
123+ tags := buildCtlArgs .Tags
117124 if len (tags ) > 1 {
118125 log .L .Debug ("Found more than 1 tag" )
119126 imageService := client .ImageService ()
@@ -160,11 +167,15 @@ func loadImage(ctx context.Context, in io.Reader, namespace, address, snapshotte
160167 client .Close ()
161168 }()
162169 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+ )
164175 if err != nil {
165176 if r .N == 0 {
166177 // Avoid confusing "unrecognized image format"
167- return errors . New ("no image was built" )
178+ return fmt . Errorf ("no image was built: %w" , err )
168179 }
169180 if errors .Is (err , images .ErrEmptyWalk ) {
170181 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
192203 return nil
193204}
194205
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+ }
197215
216+ func generateBuildctlArgs (ctx context.Context , client * containerd.Client , options types.BuilderBuildOptions ) (result BuildctlArgsResult , err error ) {
198217 buildctlBinary , err := buildkitutil .BuildctlBinary ()
199218 if err != nil {
200- return "" , nil , false , "" , nil , nil , err
219+ return result , err
201220 }
221+ result .BuildctlBinary = buildctlBinary
202222
203223 output := options .Output
204224 if output == "" {
205225 info , err := client .Server (ctx )
206226 if err != nil {
207- return "" , nil , false , "" , nil , nil , err
227+ return result , err
208228 }
209229 sharable , err := isImageSharable (options .BuildKitHost , options .GOptions .Namespace , info .UUID , options .GOptions .Snapshotter , options .Platform )
210230 if err != nil {
211- return "" , nil , false , "" , nil , nil , err
231+ return result , err
212232 }
213233 if sharable {
214234 output = "type=image,unpack=true" // ensure the target stage is unlazied (needed for any snapshotters)
215235 } 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"
217239 if len (options .Platform ) > 1 {
218240 // For avoiding `error: failed to solve: docker exporter does not currently support exporting manifest lists`
219241 // TODO: consider using type=oci for single-options.Platform build too
220242 output = "type=oci"
221243 }
222- needsLoading = true
223244 }
224245 } else {
225246 if ! strings .Contains (output , "type=" ) {
226247 // should accept --output <DIR> as an alias of --output
227248 // type=local,dest=<DIR>
228249 output = fmt .Sprintf ("type=local,dest=%s" , output )
229250 }
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
234256 }
235257 }
258+
259+ var tags []string
236260 if tags = strutil .DedupeStrSlice (options .Tag ); len (tags ) > 0 {
237261 ref := tags [0 ]
238262 parsedReference , err := referenceutil .Parse (ref )
239263 if err != nil {
240- return "" , nil , false , "" , nil , nil , err
264+ return result , err
241265 }
242266 output += ",name=" + parsedReference .String ()
243267
244268 // pick the first tag and add it to output
245269 for idx , tag := range tags {
246270 parsedReference , err = referenceutil .Parse (tag )
247271 if err != nil {
248- return "" , nil , false , "" , nil , nil , err
272+ return result , err
249273 }
250274 tags [idx ] = parsedReference .String ()
251275 }
252276 } else if len (tags ) == 0 {
253277 output = output + ",dangling-name-prefix=<none>"
254278 }
279+ result .Tags = tags
255280
256- buildctlArgs = buildkitutil .BuildctlBaseArgs (options .BuildKitHost )
257-
281+ buildctlArgs := buildkitutil .BuildctlBaseArgs (options .BuildKitHost )
258282 buildctlArgs = append (buildctlArgs , []string {
259283 "build" ,
260284 "--progress=" + options .Progress ,
@@ -271,9 +295,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
271295 var err error
272296 dir , err = buildkitutil .WriteTempDockerfile (options .Stdin )
273297 if err != nil {
274- return "" , nil , false , "" , nil , nil , err
298+ return result , err
275299 }
276- cleanup = func () {
300+ result . Cleanup = func () {
277301 os .RemoveAll (dir )
278302 }
279303 } else {
@@ -286,12 +310,12 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
286310 }
287311 dir , file , err = buildkitutil .BuildKitFile (dir , file )
288312 if err != nil {
289- return "" , nil , false , "" , nil , nil , err
313+ return result , err
290314 }
291315
292316 buildCtx , err := parseContextNames (options .ExtendedBuildContext )
293317 if err != nil {
294- return "" , nil , false , "" , nil , nil , err
318+ return result , err
295319 }
296320
297321 for k , v := range buildCtx {
@@ -306,7 +330,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
306330 if isOCILayout := strings .HasPrefix (v , "oci-layout://" ); isOCILayout {
307331 args , err := parseBuildContextFromOCILayout (k , v )
308332 if err != nil {
309- return "" , nil , false , "" , nil , nil , err
333+ return result , err
310334 }
311335
312336 buildctlArgs = append (buildctlArgs , args ... )
@@ -315,7 +339,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
315339
316340 path , err := filepath .Abs (v )
317341 if err != nil {
318- return "" , nil , false , "" , nil , nil , err
342+ return result , err
319343 }
320344 buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--local=%s=%s" , k , path ))
321345 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
362386 }
363387 }
364388 } else {
365- return "" , nil , false , "" , nil , nil , fmt .Errorf ("invalid build arg %q" , ba )
389+ return result , fmt .Errorf ("invalid build arg %q" , ba )
366390 }
367391 }
368392
@@ -405,7 +429,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
405429 optAttestType := strings .TrimPrefix (optAttestType , "type=" )
406430 buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--opt=attest:%s=%s" , optAttestType , optAttestAttrs ))
407431 } else {
408- return "" , nil , false , "" , nil , nil , fmt .Errorf ("attestation type not specified" )
432+ return result , fmt .Errorf ("attestation type not specified" )
409433 }
410434 }
411435
@@ -434,11 +458,11 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
434458 if options .IidFile != "" {
435459 file , err := os .CreateTemp ("" , "buildkit-meta-*" )
436460 if err != nil {
437- return "" , nil , false , "" , nil , cleanup , err
461+ return result , err
438462 }
439463 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 )
442466 }
443467
444468 if options .NetworkMode != "" {
@@ -453,7 +477,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
453477 }
454478 }
455479
456- return buildctlBinary , buildctlArgs , needsLoading , metaFile , tags , cleanup , nil
480+ result .BuildctlArgs = buildctlArgs
481+
482+ return result , nil
457483}
458484
459485func getDigestFromMetaFile (path string ) (string , error ) {
0 commit comments