@@ -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,85 @@ 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
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 ()
241269 }
242- output += ",name=" + parsedReference .String ()
243270
244271 // pick the first tag and add it to output
245272 for idx , tag := range tags {
246273 parsedReference , err = referenceutil .Parse (tag )
247274 if err != nil {
248- return "" , nil , false , "" , nil , nil , err
275+ return result , err
249276 }
250277 tags [idx ] = parsedReference .String ()
251278 }
252279 } else if len (tags ) == 0 {
253280 output = output + ",dangling-name-prefix=<none>"
254281 }
282+ result .Tags = tags
255283
256- buildctlArgs = buildkitutil .BuildctlBaseArgs (options .BuildKitHost )
257-
284+ buildctlArgs := buildkitutil .BuildctlBaseArgs (options .BuildKitHost )
258285 buildctlArgs = append (buildctlArgs , []string {
259286 "build" ,
260287 "--progress=" + options .Progress ,
@@ -271,9 +298,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
271298 var err error
272299 dir , err = buildkitutil .WriteTempDockerfile (options .Stdin )
273300 if err != nil {
274- return "" , nil , false , "" , nil , nil , err
301+ return result , err
275302 }
276- cleanup = func () {
303+ result . Cleanup = func () {
277304 os .RemoveAll (dir )
278305 }
279306 } else {
@@ -286,12 +313,12 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
286313 }
287314 dir , file , err = buildkitutil .BuildKitFile (dir , file )
288315 if err != nil {
289- return "" , nil , false , "" , nil , nil , err
316+ return result , err
290317 }
291318
292319 buildCtx , err := parseContextNames (options .ExtendedBuildContext )
293320 if err != nil {
294- return "" , nil , false , "" , nil , nil , err
321+ return result , err
295322 }
296323
297324 for k , v := range buildCtx {
@@ -306,7 +333,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
306333 if isOCILayout := strings .HasPrefix (v , "oci-layout://" ); isOCILayout {
307334 args , err := parseBuildContextFromOCILayout (k , v )
308335 if err != nil {
309- return "" , nil , false , "" , nil , nil , err
336+ return result , err
310337 }
311338
312339 buildctlArgs = append (buildctlArgs , args ... )
@@ -315,7 +342,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
315342
316343 path , err := filepath .Abs (v )
317344 if err != nil {
318- return "" , nil , false , "" , nil , nil , err
345+ return result , err
319346 }
320347 buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--local=%s=%s" , k , path ))
321348 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
362389 }
363390 }
364391 } else {
365- return "" , nil , false , "" , nil , nil , fmt .Errorf ("invalid build arg %q" , ba )
392+ return result , fmt .Errorf ("invalid build arg %q" , ba )
366393 }
367394 }
368395
@@ -405,7 +432,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
405432 optAttestType := strings .TrimPrefix (optAttestType , "type=" )
406433 buildctlArgs = append (buildctlArgs , fmt .Sprintf ("--opt=attest:%s=%s" , optAttestType , optAttestAttrs ))
407434 } else {
408- return "" , nil , false , "" , nil , nil , fmt .Errorf ("attestation type not specified" )
435+ return result , fmt .Errorf ("attestation type not specified" )
409436 }
410437 }
411438
@@ -434,11 +461,11 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
434461 if options .IidFile != "" {
435462 file , err := os .CreateTemp ("" , "buildkit-meta-*" )
436463 if err != nil {
437- return "" , nil , false , "" , nil , cleanup , err
464+ return result , err
438465 }
439466 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 )
442469 }
443470
444471 if options .NetworkMode != "" {
@@ -453,7 +480,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
453480 }
454481 }
455482
456- return buildctlBinary , buildctlArgs , needsLoading , metaFile , tags , cleanup , nil
483+ result .BuildctlArgs = buildctlArgs
484+
485+ return result , nil
457486}
458487
459488func getDigestFromMetaFile (path string ) (string , error ) {
0 commit comments