diff --git a/cli/command/image/build.go b/cli/command/image/build.go index d098c2a22b3a..6616e308b057 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -57,7 +57,7 @@ type buildOptions struct { isolation string quiet bool noCache bool - noConsole bool + console opts.NullableBool rm bool forceRm bool pull bool @@ -152,9 +152,9 @@ func NewBuildCommand(dockerCli command.Cli) *cobra.Command { flags.SetAnnotation("stream", "experimental", nil) flags.SetAnnotation("stream", "version", []string{"1.31"}) - flags.BoolVar(&options.noConsole, "no-console", false, "Show non-console output (with buildkit only)") - flags.SetAnnotation("no-console", "experimental", nil) - flags.SetAnnotation("no-console", "version", []string{"1.38"}) + flags.Var(&options.console, "console", "Show console output (with buildkit only) (true, false, auto)") + flags.SetAnnotation("console", "experimental", nil) + flags.SetAnnotation("console", "version", []string{"1.38"}) return cmd } diff --git a/cli/command/image/build_buildkit.go b/cli/command/image/build_buildkit.go index e5628be3781a..fb91971fefa6 100644 --- a/cli/command/image/build_buildkit.go +++ b/cli/command/image/build_buildkit.go @@ -191,7 +191,9 @@ func doBuild(ctx context.Context, eg *errgroup.Group, dockerCli command.Cli, opt displayStatus := func(displayCh chan *client.SolveStatus) { var c console.Console out := os.Stderr - if cons, err := console.ConsoleFromFile(out); err == nil && !options.noConsole { + // TODO: Handle interactive output in non-interactive environment. + consoleOpt := options.console.Value() + if cons, err := console.ConsoleFromFile(out); err == nil && (consoleOpt == nil || *consoleOpt) { c = cons } // not using shared context to not disrupt display but let is finish reporting errors diff --git a/opts/opts.go b/opts/opts.go index d915ec2f76d5..e0ae7e58fe30 100644 --- a/opts/opts.go +++ b/opts/opts.go @@ -6,6 +6,7 @@ import ( "net" "path" "regexp" + "strconv" "strings" "github.com/docker/docker/api/types/filters" @@ -486,3 +487,34 @@ func (m *MemSwapBytes) UnmarshalJSON(s []byte) error { b := MemBytes(*m) return b.UnmarshalJSON(s) } + +// NullableBool is a type for tri-state boolean options +type NullableBool struct { + b *bool +} + +func (n *NullableBool) Type() string { + return "" +} + +func (n *NullableBool) Value() *bool { + return n.b +} + +func (n *NullableBool) Set(value string) error { + if value != "auto" && value != "" { + if b, err := strconv.ParseBool(value); err != nil { + return err + } else { + n.b = &b + } + } + return nil +} + +func (n *NullableBool) String() string { + if n.b == nil { + return "auto" + } + return strconv.FormatBool(*n.b) +}