diff --git a/build/build.go b/build/build.go index 2ab8484c..8c6d743f 100644 --- a/build/build.go +++ b/build/build.go @@ -20,6 +20,7 @@ import ( "github.com/moby/buildkit/session/upload/uploadprovider" specs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/tonistiigi/buildx/driver" "github.com/tonistiigi/buildx/util/progress" "golang.org/x/sync/errgroup" @@ -95,6 +96,14 @@ func Build(ctx context.Context, drivers []DriverInfo, opt map[string]Options, do _, isDefaultMobyDriver := d.(interface { IsDefaultMobyDriver() }) + + for _, opt := range opt { + if !isDefaultMobyDriver && len(opt.Exports) == 0 { + logrus.Warnf("No output specified for %s driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load", d.Factory().Name()) + break + } + } + c, err := driver.Boot(ctx, d, pw) if err != nil { close(pw.Status()) diff --git a/commands/build.go b/commands/build.go index 9ce12c18..2193147d 100644 --- a/commands/build.go +++ b/commands/build.go @@ -7,6 +7,7 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" + "github.com/moby/buildkit/client" "github.com/moby/buildkit/session/auth/authprovider" "github.com/moby/buildkit/util/appcontext" "github.com/pkg/errors" @@ -34,6 +35,9 @@ type buildOptions struct { extraHosts []string networkMode string + exportPush bool + exportLoad bool + // unimplemented squash bool quiet bool @@ -112,6 +116,41 @@ func runBuild(dockerCli command.Cli, in buildOptions) error { if err != nil { return err } + if in.exportPush { + if in.exportLoad { + return errors.Errorf("push and load may not be set together at the moment") + } + if len(outputs) == 0 { + outputs = []client.ExportEntry{{ + Type: "image", + Attrs: map[string]string{ + "push": "true", + }, + }} + } else { + switch outputs[0].Type { + case "image": + outputs[0].Attrs["push"] = "true" + default: + return errors.Errorf("push and %q output can't be used together", outputs[0].Type) + } + } + } + if in.exportLoad { + if len(outputs) == 0 { + outputs = []client.ExportEntry{{ + Type: "docker", + Attrs: map[string]string{}, + }} + } else { + switch outputs[0].Type { + case "docker": + default: + return errors.Errorf("load and %q output can't be used together", outputs[0].Type) + } + } + } + opts.Exports = outputs return buildTargets(ctx, dockerCli, map[string]build.Options{"default": opts}, in.progress) @@ -147,6 +186,9 @@ func buildCmd(dockerCli command.Cli) *cobra.Command { flags := cmd.Flags() + flags.BoolVar(&options.exportPush, "push", false, "Shorthand for --output=type=registry") + flags.BoolVar(&options.exportLoad, "load", false, "Shorthand for --output=type=docker") + flags.StringArrayVarP(&options.tags, "tag", "t", []string{}, "Name and optionally a tag in the 'name:tag' format") flags.StringArrayVar(&options.buildArgs, "build-arg", []string{}, "Set build-time variables") flags.StringVarP(&options.dockerfileName, "file", "f", "", "Name of the Dockerfile (Default is 'PATH/Dockerfile')")