Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: set default context builder if not specified #3676

Merged
merged 2 commits into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions cmd/docker/aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,27 @@ var allowedAliases = map[string]struct{}{
keyBuilderAlias: {},
}

func processAliases(dockerCli command.Cli, cmd *cobra.Command, args, osArgs []string) ([]string, []string, error) {
func processAliases(dockerCli command.Cli, cmd *cobra.Command, args, osArgs []string) ([]string, []string, []string, error) {
var err error
var envs []string
aliasMap := dockerCli.ConfigFile().Aliases
aliases := make([][2][]string, 0, len(aliasMap))

for k, v := range aliasMap {
if _, ok := allowedAliases[k]; !ok {
return args, osArgs, errors.Errorf("not allowed to alias %q (allowed: %#v)", k, allowedAliases)
return args, osArgs, envs, errors.Errorf("not allowed to alias %q (allowed: %#v)", k, allowedAliases)
}
if c, _, err := cmd.Find(strings.Split(v, " ")); err == nil {
if !pluginmanager.IsPluginCommand(c) {
return args, osArgs, errors.Errorf("not allowed to alias with builtin %q as target", v)
return args, osArgs, envs, errors.Errorf("not allowed to alias with builtin %q as target", v)
}
}
aliases = append(aliases, [2][]string{{k}, {v}})
}

args, osArgs, err = processBuilder(dockerCli, cmd, args, os.Args)
args, osArgs, envs, err = processBuilder(dockerCli, cmd, args, os.Args)
if err != nil {
return args, os.Args, err
return args, os.Args, envs, err
}

for _, al := range aliases {
Expand All @@ -49,5 +50,5 @@ func processAliases(dockerCli command.Cli, cmd *cobra.Command, args, osArgs []st
}
}

return args, osArgs, nil
return args, osArgs, envs, nil
}
55 changes: 46 additions & 9 deletions cmd/docker/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package main

import (
"fmt"
"io"
"os"
"strconv"
"strings"

pluginmanager "github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli/command"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

const (
Expand Down Expand Up @@ -40,15 +43,17 @@ func newBuilderError(warn bool, err error) error {
return fmt.Errorf("%s", errorMsg)
}

func processBuilder(dockerCli command.Cli, cmd *cobra.Command, args, osargs []string) ([]string, []string, error) {
var useLegacy, useBuilder bool
//nolint:gocyclo
func processBuilder(dockerCli command.Cli, cmd *cobra.Command, args, osargs []string) ([]string, []string, []string, error) {
var useLegacy, useBuilder, useAlias bool
var envs []string

// check DOCKER_BUILDKIT env var is present and
// if not assume we want to use the builder component
if v, ok := os.LookupEnv("DOCKER_BUILDKIT"); ok {
enabled, err := strconv.ParseBool(v)
if err != nil {
return args, osargs, errors.Wrap(err, "DOCKER_BUILDKIT environment variable expects boolean value")
return args, osargs, nil, errors.Wrap(err, "DOCKER_BUILDKIT environment variable expects boolean value")
}
if !enabled {
useLegacy = true
Expand All @@ -63,27 +68,28 @@ func processBuilder(dockerCli command.Cli, cmd *cobra.Command, args, osargs []st
aliasMap := dockerCli.ConfigFile().Aliases
if v, ok := aliasMap[keyBuilderAlias]; ok {
useBuilder = true
useAlias = true
builderAlias = v
}

// is this a build that should be forwarded to the builder?
fwargs, fwosargs, forwarded := forwardBuilder(builderAlias, args, osargs)
if !forwarded {
return args, osargs, nil
return args, osargs, nil, nil
}

// wcow build command must use the legacy builder
// if not opt-in through a builder component
if !useBuilder && dockerCli.ServerInfo().OSType == "windows" {
return args, osargs, nil
return args, osargs, nil, nil
}

if useLegacy {
// display warning if not wcow and continue
if dockerCli.ServerInfo().OSType != "windows" {
_, _ = fmt.Fprintln(dockerCli.Err(), newBuilderError(true, nil))
}
return args, osargs, nil
return args, osargs, nil, nil
}

// check plugin is available if cmd forwarded
Expand All @@ -94,14 +100,26 @@ func processBuilder(dockerCli command.Cli, cmd *cobra.Command, args, osargs []st
if perr != nil {
// if builder enforced with DOCKER_BUILDKIT=1, cmd must fail if plugin missing or broken
if useBuilder {
return args, osargs, newBuilderError(false, perr)
return args, osargs, nil, newBuilderError(false, perr)
}
// otherwise, display warning and continue
_, _ = fmt.Fprintln(dockerCli.Err(), newBuilderError(true, perr))
return args, osargs, nil
return args, osargs, nil, nil
}

return fwargs, fwosargs, nil
// If build subcommand is forwarded, user would expect "docker build" to
// always create a local docker image (default context builder). This is
// for better backward compatibility in case where a user could switch to
// a docker container builder with "docker buildx --use foo" which does
// not --load by default. Also makes sure that an arbitrary builder name
// is not being set in the command line or in the environment before
// setting the default context and keep "buildx install" behavior if being
// set (builder alias).
if forwarded && !useAlias && !hasBuilderName(args, os.Environ()) {
envs = append([]string{"BUILDX_BUILDER=" + dockerCli.CurrentContext()}, envs...)
}

return fwargs, fwosargs, envs, nil
}

func forwardBuilder(alias string, args, osargs []string) ([]string, []string, bool) {
Expand All @@ -127,3 +145,22 @@ func forwardBuilder(alias string, args, osargs []string) ([]string, []string, bo
}
return args, osargs, false
}

// hasBuilderName checks if a builder name is defined in args or env vars
func hasBuilderName(args []string, envs []string) bool {
var builder string
flagset := pflag.NewFlagSet("buildx", pflag.ContinueOnError)
flagset.Usage = func() {}
flagset.SetOutput(io.Discard)
flagset.StringVar(&builder, "builder", "", "")
_ = flagset.Parse(args)
if builder != "" {
return true
}
for _, e := range envs {
if strings.HasPrefix(e, "BUILDX_BUILDER=") && e != "BUILDX_BUILDER=" {
return true
}
}
return false
}
Loading