diff --git a/cmd/compose/build.go b/cmd/compose/build.go index e8b2db40d..d7ef65ff5 100644 --- a/cmd/compose/build.go +++ b/cmd/compose/build.go @@ -27,8 +27,7 @@ import ( "github.com/compose-spec/compose-go/types" buildx "github.com/docker/buildx/util/progress" cliopts "github.com/docker/cli/opts" - "github.com/docker/compose/v2/pkg/progress" - "github.com/docker/compose/v2/pkg/utils" + ui "github.com/docker/compose/v2/pkg/progress" "github.com/spf13/cobra" "github.com/docker/compose/v2/pkg/api" @@ -37,14 +36,13 @@ import ( type buildOptions struct { *ProjectOptions composeOptions - quiet bool - pull bool - push bool - progress string - args []string - noCache bool - memory cliopts.MemBytes - ssh string + quiet bool + pull bool + push bool + args []string + noCache bool + memory cliopts.MemBytes + ssh string } func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, error) { @@ -60,7 +58,7 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, return api.BuildOptions{ Pull: opts.pull, Push: opts.push, - Progress: opts.progress, + Progress: ui.Mode, Args: types.NewMappingWithEquals(opts.args), NoCache: opts.noCache, Quiet: opts.quiet, @@ -69,14 +67,7 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, }, nil } -var printerModes = []string{ - buildx.PrinterModeAuto, - buildx.PrinterModeTty, - buildx.PrinterModePlain, - buildx.PrinterModeQuiet, -} - -func buildCommand(p *ProjectOptions, backend api.Service) *cobra.Command { +func buildCommand(p *ProjectOptions, progress *string, backend api.Service) *cobra.Command { opts := buildOptions{ ProjectOptions: p, } @@ -85,24 +76,21 @@ func buildCommand(p *ProjectOptions, backend api.Service) *cobra.Command { Short: "Build or rebuild services", PreRunE: Adapt(func(ctx context.Context, args []string) error { if opts.quiet { - opts.progress = buildx.PrinterModeQuiet + ui.Mode = ui.ModeQuiet devnull, err := os.Open(os.DevNull) if err != nil { return err } os.Stdout = devnull } - if !utils.StringContains(printerModes, opts.progress) { - return fmt.Errorf("unsupported --progress value %q", opts.progress) - } return nil }), RunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error { if cmd.Flags().Changed("ssh") && opts.ssh == "" { opts.ssh = "default" } - if progress.Mode == progress.ModePlain && !cmd.Flags().Changed("progress") { - opts.progress = buildx.PrinterModePlain + if cmd.Flags().Changed("progress") && opts.ssh == "" { + fmt.Fprint(os.Stderr, "--progress is a global compose flag, better use `docker compose --progress xx build ...") } return runBuild(ctx, backend, opts, args) }), @@ -111,7 +99,6 @@ func buildCommand(p *ProjectOptions, backend api.Service) *cobra.Command { cmd.Flags().BoolVar(&opts.push, "push", false, "Push service images.") cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT") cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.") - cmd.Flags().StringVar(&opts.progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", "))) cmd.Flags().StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables for services.") cmd.Flags().StringVar(&opts.ssh, "ssh", "", "Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent)") cmd.Flags().Bool("parallel", true, "Build images in parallel. DEPRECATED") @@ -124,6 +111,8 @@ func buildCommand(p *ProjectOptions, backend api.Service) *cobra.Command { cmd.Flags().Bool("no-rm", false, "Do not remove intermediate containers after a successful build. DEPRECATED") cmd.Flags().MarkHidden("no-rm") //nolint:errcheck cmd.Flags().VarP(&opts.memory, "memory", "m", "Set memory limit for the build container. Not supported by BuildKit.") + cmd.Flags().StringVar(progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of ui output (%s)`, strings.Join(printerModes, ", "))) + cmd.Flags().MarkHidden("progress") //nolint:errcheck return cmd } diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 680790d2f..0a2fc1fa8 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -26,6 +26,7 @@ import ( "strings" "syscall" + buildx "github.com/docker/buildx/util/progress" "github.com/docker/cli/cli/command" "github.com/compose-spec/compose-go/cli" @@ -43,7 +44,7 @@ import ( "github.com/docker/compose/v2/cmd/formatter" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/compose" - "github.com/docker/compose/v2/pkg/progress" + ui "github.com/docker/compose/v2/pkg/progress" "github.com/docker/compose/v2/pkg/utils" ) @@ -273,6 +274,7 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no version bool parallel int dryRun bool + progress string ) c := &cobra.Command{ Short: "Docker Compose", @@ -326,16 +328,36 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no formatter.SetANSIMode(streams, ansi) if noColor, ok := os.LookupEnv("NO_COLOR"); ok && noColor != "" { - progress.NoColor() + ui.NoColor() formatter.SetANSIMode(streams, formatter.Never) } switch ansi { case "never": - progress.Mode = progress.ModePlain + ui.Mode = ui.ModePlain case "always": - progress.Mode = progress.ModeTTY + ui.Mode = ui.ModeTTY } + + switch progress { + case ui.ModeAuto: + ui.Mode = ui.ModeAuto + case ui.ModeTTY: + if ansi == "never" { + return fmt.Errorf("can't use --progress tty while ANSI support is disabled") + } + ui.Mode = ui.ModeTTY + case ui.ModePlain: + if ansi == "always" { + return fmt.Errorf("can't use --progress plain while ANSI support is forced") + } + ui.Mode = ui.ModePlain + case ui.ModeQuiet, "none": + ui.Mode = ui.ModeQuiet + default: + return fmt.Errorf("unsupported --progress value %q", progress) + } + if opts.WorkDir != "" { if opts.ProjectDir != "" { return errors.New(`cannot specify DEPRECATED "--workdir" and "--project-directory". Please use only "--project-directory" instead`) @@ -404,7 +426,7 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no portCommand(&opts, streams, backend), imagesCommand(&opts, streams, backend), versionCommand(streams), - buildCommand(&opts, backend), + buildCommand(&opts, &progress, backend), pushCommand(&opts, backend), pullCommand(&opts, backend), createCommand(&opts, backend), @@ -425,6 +447,8 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no }, ) + c.Flags().StringVar(&progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", "))) + c.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`) c.Flags().IntVar(¶llel, "parallel", -1, `Control max parallelism, -1 for unlimited`) c.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information") @@ -460,3 +484,10 @@ func setEnvWithDotEnv(prjOpts *ProjectOptions) error { } return nil } + +var printerModes = []string{ + ui.ModeAuto, + ui.ModeTTY, + ui.ModePlain, + ui.ModeQuiet, +} diff --git a/docs/reference/compose.md b/docs/reference/compose.md index ae5a72e96..337ac3f14 100644 --- a/docs/reference/compose.md +++ b/docs/reference/compose.md @@ -46,6 +46,7 @@ Define and run multi-container applications with Docker. | `-f`, `--file` | `stringArray` | | Compose configuration files | | `--parallel` | `int` | `-1` | Control max parallelism, -1 for unlimited | | `--profile` | `stringArray` | | Specify a profile to enable | +| `--progress` | `string` | `auto` | Set type of progress output (auto, tty, plain, quiet) | | `--project-directory` | `string` | | Specify an alternate working directory
(default: the path of the, first specified, Compose file) | | `-p`, `--project-name` | `string` | | Project name | diff --git a/docs/reference/compose_build.md b/docs/reference/compose_build.md index 6612093a3..b978c83f6 100644 --- a/docs/reference/compose_build.md +++ b/docs/reference/compose_build.md @@ -11,7 +11,6 @@ Build or rebuild services | `--dry-run` | | | Execute command in dry run mode | | `-m`, `--memory` | `bytes` | `0` | Set memory limit for the build container. Not supported by BuildKit. | | `--no-cache` | | | Do not use cache when building the image | -| `--progress` | `string` | `auto` | Set type of progress output (auto, tty, plain, quiet) | | `--pull` | | | Always attempt to pull a newer version of the image. | | `--push` | | | Push service images. | | `-q`, `--quiet` | | | Don't print anything to STDOUT | diff --git a/docs/reference/docker_compose.yaml b/docs/reference/docker_compose.yaml index fc707d103..1f3a49ebd 100644 --- a/docs/reference/docker_compose.yaml +++ b/docs/reference/docker_compose.yaml @@ -280,6 +280,16 @@ options: experimentalcli: false kubernetes: false swarm: false + - option: progress + value_type: string + default_value: auto + description: Set type of progress output (auto, tty, plain, quiet) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false - option: project-directory value_type: string description: |- diff --git a/docs/reference/docker_compose_build.yaml b/docs/reference/docker_compose_build.yaml index 01f5ad2bb..efab6c055 100644 --- a/docs/reference/docker_compose_build.yaml +++ b/docs/reference/docker_compose_build.yaml @@ -90,9 +90,9 @@ options: - option: progress value_type: string default_value: auto - description: Set type of progress output (auto, tty, plain, quiet) + description: Set type of ui output (auto, tty, plain, quiet) deprecated: false - hidden: false + hidden: true experimental: false experimentalcli: false kubernetes: false diff --git a/pkg/progress/quiet.go b/pkg/progress/quiet.go new file mode 100644 index 000000000..5c5530d76 --- /dev/null +++ b/pkg/progress/quiet.go @@ -0,0 +1,37 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package progress + +import "context" + +type quiet struct{} + +func (q quiet) Start(_ context.Context) error { + return nil +} + +func (q quiet) Stop() { +} + +func (q quiet) Event(_ Event) { +} + +func (q quiet) Events(_ []Event) { +} + +func (q quiet) TailMsgf(_ string, _ ...interface{}) { +} diff --git a/pkg/progress/writer.go b/pkg/progress/writer.go index 14783c1b9..f1dec3c79 100644 --- a/pkg/progress/writer.go +++ b/pkg/progress/writer.go @@ -107,6 +107,8 @@ const ( ModeTTY = "tty" // ModePlain dump raw events to output ModePlain = "plain" + // ModeQuiet don't display events + ModeQuiet = "quiet" ) // Mode define how progress should be rendered, either as ModePlain or ModeTTY @@ -119,6 +121,9 @@ func NewWriter(ctx context.Context, out io.Writer, progressTitle string) (Writer if !ok { dryRun = false } + if Mode == ModeQuiet { + return quiet{}, nil + } f, isConsole := out.(console.File) // see https://github.com/docker/compose/issues/10560 if Mode == ModeAuto && isTerminal && isConsole { return newTTYWriter(f, dryRun, progressTitle)