Skip to content

Commit dec2718

Browse files
committed
[Windows] nerdctl build - Replace default type=docker with type=image
- Use default image name only when user has not specified one Signed-off-by: Christine Murimi <[email protected]>
1 parent 088fe02 commit dec2718

File tree

3 files changed

+69
-40
lines changed

3 files changed

+69
-40
lines changed

cmd/nerdctl/builder/builder_build_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ CMD ["echo", "nerdctl-build-test-string"]`, testutil.CommonImage)
7979
Expected: test.Expects(0, nil, expect.Equals("nerdctl-build-test-string\n")),
8080
},
8181
{
82-
Description: "Successfully build with output docker, main tag still works",
82+
Description: "Successfully build with output image, main tag still works",
8383
Setup: func(data test.Data, helpers test.Helpers) {
84-
helpers.Ensure("build", data.Get("buildCtx"), "-t", data.Identifier(), "--output=type=docker,name="+data.Identifier("ignored"))
84+
helpers.Ensure("build", data.Get("buildCtx"), "-t", data.Identifier(), "--output=type=image,name="+data.Identifier("ignored"))
8585
},
8686
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
8787
return helpers.Command("run", "--rm", data.Identifier())
@@ -92,17 +92,17 @@ CMD ["echo", "nerdctl-build-test-string"]`, testutil.CommonImage)
9292
Expected: test.Expects(0, nil, expect.Equals("nerdctl-build-test-string\n")),
9393
},
9494
{
95-
Description: "Successfully build with output docker, name cannot be used",
95+
Description: "Successfully build with output docker, named image",
9696
Setup: func(data test.Data, helpers test.Helpers) {
97-
helpers.Ensure("build", data.Get("buildCtx"), "-t", data.Identifier(), "--output=type=docker,name="+data.Identifier("ignored"))
97+
helpers.Ensure("build", data.Get("buildCtx"), "--output=type=docker,name="+data.Identifier())
9898
},
9999
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
100-
return helpers.Command("run", "--rm", data.Identifier("ignored"))
100+
return helpers.Command("run", "--rm", data.Identifier())
101101
},
102102
Cleanup: func(data test.Data, helpers test.Helpers) {
103103
helpers.Anyhow("rmi", "-f", data.Identifier())
104104
},
105-
Expected: test.Expects(-1, nil, nil),
105+
Expected: test.Expects(0, nil, test.Equals("nerdctl-build-test-string\n")),
106106
},
107107
},
108108
}

docs/command-reference.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,10 @@ Flags:
715715
- :whale: `--target`: Set the target build stage to build
716716
- :whale: `--build-arg`: Set build-time variables
717717
- :whale: `--no-cache`: Do not use cache when building the image
718-
- :whale: `--output=OUTPUT`: Output destination (format: type=local,dest=path)
718+
- :whale: `--output=OUTPUT`: Output destination (format: type=local,dest=path). See [buildctl output](https://github.com/moby/buildkit?tab=readme-ov-file#output) option for more details.
719+
720+
If this flag is not specified, it defaults to `type=image,name=docker.io/library/<TAG>:latest`.
721+
719722
- :whale: `type=local,dest=path/to/output-dir`: Local directory
720723
- :whale: `type=oci[,dest=path/to/output.tar]`: Docker/OCI dual-format tar ball (compatible with `docker buildx build`)
721724
- :whale: `type=docker[,dest=path/to/output.tar]`: Docker format tar ball (compatible with `docker buildx build`)

pkg/cmd/builder/build.go

+59-33
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,22 @@ func (p platformParser) DefaultSpec() platforms.Platform {
6262
}
6363

6464
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)
6666
if err != nil {
6767
return err
6868
}
69-
if cleanup != nil {
70-
defer cleanup()
69+
if buildCtlArgs.Cleanup != nil {
70+
defer buildCtlArgs.Cleanup()
7171
}
7272

73+
buildctlBinary := buildCtlArgs.BuildctlBinary
74+
buildctlArgs := buildCtlArgs.BuildctlArgs
75+
7376
log.L.Debugf("running %s %v", buildctlBinary, buildctlArgs)
7477
buildctlCmd := exec.Command(buildctlBinary, buildctlArgs...)
7578
buildctlCmd.Env = os.Environ()
7679

80+
needsLoading := buildCtlArgs.NeedsLoading
7781
var buildctlStdout io.Reader
7882
if needsLoading {
7983
buildctlStdout, err = buildctlCmd.StdoutPipe()
@@ -96,6 +100,8 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
96100
if err != nil {
97101
return err
98102
}
103+
104+
// Load the image into the containerd image store
99105
if err = loadImage(ctx, buildctlStdout, options.GOptions.Namespace, options.GOptions.Address, options.GOptions.Snapshotter, options.Stdout, platMC, options.Quiet); err != nil {
100106
return err
101107
}
@@ -106,7 +112,7 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
106112
}
107113

108114
if options.IidFile != "" {
109-
id, err := getDigestFromMetaFile(metaFile)
115+
id, err := getDigestFromMetaFile(buildCtlArgs.MetaFile)
110116
if err != nil {
111117
return err
112118
}
@@ -115,6 +121,7 @@ func Build(ctx context.Context, client *containerd.Client, options types.Builder
115121
}
116122
}
117123

124+
tags := buildCtlArgs.Tags
118125
if len(tags) > 1 {
119126
log.L.Debug("Found more than 1 tag")
120127
imageService := client.ImageService()
@@ -161,11 +168,15 @@ func loadImage(ctx context.Context, in io.Reader, namespace, address, snapshotte
161168
client.Close()
162169
}()
163170
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+
)
165176
if err != nil {
166177
if r.N == 0 {
167178
// Avoid confusing "unrecognized image format"
168-
return errors.New("no image was built")
179+
return fmt.Errorf("no image was built: %w", err)
169180
}
170181
if errors.Is(err, images.ErrEmptyWalk) {
171182
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
193204
return nil
194205
}
195206

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+
}
198216

217+
func generateBuildctlArgs(ctx context.Context, client *containerd.Client, options types.BuilderBuildOptions) (result BuildctlArgsResult, err error) {
199218
buildctlBinary, err := buildkitutil.BuildctlBinary()
200219
if err != nil {
201-
return "", nil, false, "", nil, nil, err
220+
return result, err
202221
}
222+
result.BuildctlBinary = buildctlBinary
203223

204224
output := options.Output
205225
if output == "" {
206226
info, err := client.Server(ctx)
207227
if err != nil {
208-
return "", nil, false, "", nil, nil, err
228+
return result, err
209229
}
210230
sharable, err := isImageSharable(options.BuildKitHost, options.GOptions.Namespace, info.UUID, options.GOptions.Snapshotter, options.Platform)
211231
if err != nil {
212-
return "", nil, false, "", nil, nil, err
232+
return result, err
213233
}
214234
if sharable {
215235
output = "type=image,unpack=true" // ensure the target stage is unlazied (needed for any snapshotters)
216236
} 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"
218240
if len(options.Platform) > 1 {
219241
// For avoiding `error: failed to solve: docker exporter does not currently support exporting manifest lists`
220242
// TODO: consider using type=oci for single-options.Platform build too
221243
output = "type=oci"
222244
}
223-
needsLoading = true
224245
}
225246
} else {
226247
if !strings.Contains(output, "type=") {
227248
// should accept --output <DIR> as an alias of --output
228249
// type=local,dest=<DIR>
229250
output = fmt.Sprintf("type=local,dest=%s", output)
230251
}
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
235257
}
236258
}
259+
260+
var tags []string
237261
if tags = strutil.DedupeStrSlice(options.Tag); len(tags) > 0 {
238262
ref := tags[0]
239263
parsedReference, err := referenceutil.Parse(ref)
240264
if err != nil {
241-
return "", nil, false, "", nil, nil, err
265+
return result, err
242266
}
243267
output += ",name=" + parsedReference.String()
244268

245269
// pick the first tag and add it to output
246270
for idx, tag := range tags {
247271
parsedReference, err = referenceutil.Parse(tag)
248272
if err != nil {
249-
return "", nil, false, "", nil, nil, err
273+
return result, err
250274
}
251275
tags[idx] = parsedReference.String()
252276
}
253277
} else if len(tags) == 0 {
254278
output = output + ",dangling-name-prefix=<none>"
255279
}
280+
result.Tags = tags
256281

257-
buildctlArgs = buildkitutil.BuildctlBaseArgs(options.BuildKitHost)
258-
282+
buildctlArgs := buildkitutil.BuildctlBaseArgs(options.BuildKitHost)
259283
buildctlArgs = append(buildctlArgs, []string{
260284
"build",
261285
"--progress=" + options.Progress,
@@ -272,9 +296,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
272296
var err error
273297
dir, err = buildkitutil.WriteTempDockerfile(options.Stdin)
274298
if err != nil {
275-
return "", nil, false, "", nil, nil, err
299+
return result, err
276300
}
277-
cleanup = func() {
301+
result.Cleanup = func() {
278302
os.RemoveAll(dir)
279303
}
280304
} else {
@@ -287,12 +311,12 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
287311
}
288312
dir, file, err = buildkitutil.BuildKitFile(dir, file)
289313
if err != nil {
290-
return "", nil, false, "", nil, nil, err
314+
return result, err
291315
}
292316

293317
buildCtx, err := parseContextNames(options.ExtendedBuildContext)
294318
if err != nil {
295-
return "", nil, false, "", nil, nil, err
319+
return result, err
296320
}
297321

298322
for k, v := range buildCtx {
@@ -307,7 +331,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
307331
if isOCILayout := strings.HasPrefix(v, "oci-layout://"); isOCILayout {
308332
args, err := parseBuildContextFromOCILayout(k, v)
309333
if err != nil {
310-
return "", nil, false, "", nil, nil, err
334+
return result, err
311335
}
312336

313337
buildctlArgs = append(buildctlArgs, args...)
@@ -316,7 +340,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
316340

317341
path, err := filepath.Abs(v)
318342
if err != nil {
319-
return "", nil, false, "", nil, nil, err
343+
return result, err
320344
}
321345
buildctlArgs = append(buildctlArgs, fmt.Sprintf("--local=%s=%s", k, path))
322346
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
363387
}
364388
}
365389
} else {
366-
return "", nil, false, "", nil, nil, fmt.Errorf("invalid build arg %q", ba)
390+
return result, fmt.Errorf("invalid build arg %q", ba)
367391
}
368392
}
369393

@@ -406,7 +430,7 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
406430
optAttestType := strings.TrimPrefix(optAttestType, "type=")
407431
buildctlArgs = append(buildctlArgs, fmt.Sprintf("--opt=attest:%s=%s", optAttestType, optAttestAttrs))
408432
} else {
409-
return "", nil, false, "", nil, nil, fmt.Errorf("attestation type not specified")
433+
return result, fmt.Errorf("attestation type not specified")
410434
}
411435
}
412436

@@ -435,11 +459,11 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
435459
if options.IidFile != "" {
436460
file, err := os.CreateTemp("", "buildkit-meta-*")
437461
if err != nil {
438-
return "", nil, false, "", nil, cleanup, err
462+
return result, err
439463
}
440464
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)
443467
}
444468

445469
if options.NetworkMode != "" {
@@ -462,7 +486,9 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
462486
buildctlArgs = append(buildctlArgs, "--opt=add-hosts="+strings.Join(extraHosts, ","))
463487
}
464488

465-
return buildctlBinary, buildctlArgs, needsLoading, metaFile, tags, cleanup, nil
489+
result.BuildctlArgs = buildctlArgs
490+
491+
return result, nil
466492
}
467493

468494
func getDigestFromMetaFile(path string) (string, error) {

0 commit comments

Comments
 (0)