From fd954f266c1e7ca3bfb4e2a808e109dbde7fcb4b Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Thu, 17 Jul 2025 10:47:01 +0200 Subject: [PATCH] show build progress during watch rebuild Signed-off-by: Nicolas De Loof --- cmd/compose/build.go | 2 +- cmd/compose/up.go | 1 + docs/reference/compose_build.md | 2 +- docs/reference/compose_up.md | 1 + docs/reference/docker_compose_build.yaml | 2 +- docs/reference/docker_compose_up.yaml | 10 ++++++++++ pkg/api/api.go | 3 +++ pkg/compose/build_bake.go | 10 +++++++--- pkg/compose/watch.go | 14 ++++++++++---- 9 files changed, 35 insertions(+), 10 deletions(-) diff --git a/cmd/compose/build.go b/cmd/compose/build.go index fc2e5f6f1..bd3767aee 100644 --- a/cmd/compose/build.go +++ b/cmd/compose/build.go @@ -121,7 +121,7 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) } flags := cmd.Flags() flags.BoolVar(&opts.push, "push", false, "Push service images") - flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT") + flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress the build output") flags.BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image") flags.StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables for services") flags.StringVar(&opts.ssh, "ssh", "", "Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent)") diff --git a/cmd/compose/up.go b/cmd/compose/up.go index dcde8b4ae..0c8066d05 100644 --- a/cmd/compose/up.go +++ b/cmd/compose/up.go @@ -165,6 +165,7 @@ func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c flags.BoolVar(&create.recreateDeps, "always-recreate-deps", false, "Recreate dependent containers. Incompatible with --no-recreate.") flags.BoolVarP(&create.noInherit, "renew-anon-volumes", "V", false, "Recreate anonymous volumes instead of retrieving data from the previous containers") flags.BoolVar(&create.quietPull, "quiet-pull", false, "Pull without printing progress information") + flags.BoolVar(&build.quiet, "quiet-build", false, "Suppress the build output") flags.StringArrayVar(&up.attach, "attach", []string{}, "Restrict attaching to the specified services. Incompatible with --attach-dependencies.") flags.StringArrayVar(&up.noAttach, "no-attach", []string{}, "Do not attach (stream logs) to the specified services") flags.BoolVar(&up.attachDependencies, "attach-dependencies", false, "Automatically attach to log output of dependent services") diff --git a/docs/reference/compose_build.md b/docs/reference/compose_build.md index af804aced..a715974df 100644 --- a/docs/reference/compose_build.md +++ b/docs/reference/compose_build.md @@ -25,7 +25,7 @@ run `docker compose build` to rebuild it. | `--provenance` | `string` | | Add a provenance attestation | | `--pull` | `bool` | | Always attempt to pull a newer version of the image | | `--push` | `bool` | | Push service images | -| `-q`, `--quiet` | `bool` | | Don't print anything to STDOUT | +| `-q`, `--quiet` | `bool` | | Suppress the build output | | `--sbom` | `string` | | Add a SBOM attestation | | `--ssh` | `string` | | Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) | | `--with-dependencies` | `bool` | | Also build dependencies (transitively) | diff --git a/docs/reference/compose_up.md b/docs/reference/compose_up.md index b831cb16d..b7f17a0fa 100644 --- a/docs/reference/compose_up.md +++ b/docs/reference/compose_up.md @@ -44,6 +44,7 @@ If the process is interrupted using `SIGINT` (ctrl + C) or `SIGTERM`, the contai | `--no-recreate` | `bool` | | If containers already exist, don't recreate them. Incompatible with --force-recreate. | | `--no-start` | `bool` | | Don't start the services after creating them | | `--pull` | `string` | `policy` | Pull image before running ("always"\|"missing"\|"never") | +| `--quiet-build` | `bool` | | Suppress the build output | | `--quiet-pull` | `bool` | | Pull without printing progress information | | `--remove-orphans` | `bool` | | Remove containers for services not defined in the Compose file | | `-V`, `--renew-anon-volumes` | `bool` | | Recreate anonymous volumes instead of retrieving data from the previous containers | diff --git a/docs/reference/docker_compose_build.yaml b/docs/reference/docker_compose_build.yaml index 2efe0d9f6..e645a40aa 100644 --- a/docs/reference/docker_compose_build.yaml +++ b/docs/reference/docker_compose_build.yaml @@ -158,7 +158,7 @@ options: shorthand: q value_type: bool default_value: "false" - description: Don't print anything to STDOUT + description: Suppress the build output deprecated: false hidden: false experimental: false diff --git a/docs/reference/docker_compose_up.yaml b/docs/reference/docker_compose_up.yaml index 47e0c5259..8c78a8fa6 100644 --- a/docs/reference/docker_compose_up.yaml +++ b/docs/reference/docker_compose_up.yaml @@ -211,6 +211,16 @@ options: experimentalcli: false kubernetes: false swarm: false + - option: quiet-build + value_type: bool + default_value: "false" + description: Suppress the build output + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false - option: quiet-pull value_type: bool default_value: "false" diff --git a/pkg/api/api.go b/pkg/api/api.go index 3bd197578..a48b5ab5f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -19,6 +19,7 @@ package api import ( "context" "fmt" + "io" "slices" "strings" "time" @@ -176,6 +177,8 @@ type BuildOptions struct { Provenance string // SBOM generate a SBOM attestation SBOM string + // Out is the stream to write build progress + Out io.Writer } // Apply mutates project according to build options diff --git a/pkg/compose/build_bake.go b/pkg/compose/build_bake.go index acb4bd717..d4bb893a9 100644 --- a/pkg/compose/build_bake.go +++ b/pkg/compose/build_bake.go @@ -130,10 +130,14 @@ type buildStatus struct { func (s *composeService) doBuildBake(ctx context.Context, project *types.Project, serviceToBeBuild types.Services, options api.BuildOptions) (map[string]string, error) { //nolint:gocyclo eg := errgroup.Group{} ch := make(chan *client.SolveStatus) - out := s.dockerCli.Out() displayMode := progressui.DisplayMode(options.Progress) - if !out.IsTerminal() { - displayMode = progressui.PlainMode + out := options.Out + if out == nil { + cout := s.dockerCli.Out() + if !cout.IsTerminal() { + displayMode = progressui.PlainMode + } + out = cout } display, err := progressui.NewDisplay(out, displayMode) if err != nil { diff --git a/pkg/compose/watch.go b/pkg/compose/watch.go index f8edf3418..60281dd0e 100644 --- a/pkg/compose/watch.go +++ b/pkg/compose/watch.go @@ -29,14 +29,17 @@ import ( gsync "sync" "time" - "github.com/compose-spec/compose-go/v2/types" - "github.com/compose-spec/compose-go/v2/utils" - ccli "github.com/docker/cli/cli/command/container" pathutil "github.com/docker/compose/v2/internal/paths" "github.com/docker/compose/v2/internal/sync" "github.com/docker/compose/v2/internal/tracing" "github.com/docker/compose/v2/pkg/api" + "github.com/docker/compose/v2/pkg/progress" + cutils "github.com/docker/compose/v2/pkg/utils" "github.com/docker/compose/v2/pkg/watch" + + "github.com/compose-spec/compose-go/v2/types" + "github.com/compose-spec/compose-go/v2/utils" + ccli "github.com/docker/cli/cli/command/container" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/image" @@ -61,7 +64,6 @@ func NewWatcher(project *types.Project, options api.UpOptions, w WatchFunc, cons if service.Develop != nil && service.Develop.Watch != nil { build := options.Create.Build - build.Quiet = true return &Watcher{ project: project, options: api.WatchOptions{ @@ -598,6 +600,10 @@ func (s *composeService) rebuild(ctx context.Context, project *types.Project, se options.LogTo.Log(api.WatchLogger, fmt.Sprintf("Rebuilding service(s) %q after changes were detected...", services)) // restrict the build to ONLY this service, not any of its dependencies options.Build.Services = services + options.Build.Progress = progress.ModePlain + options.Build.Out = cutils.GetWriter(func(line string) { + options.LogTo.Log(api.WatchLogger, line) + }) var ( imageNameToIdMap map[string]string