From b80bb0586e42dbb6adc2190cb84881138b61eb53 Mon Sep 17 00:00:00 2001 From: Guillaume Lours <705411+glours@users.noreply.github.com> Date: Wed, 29 Oct 2025 18:34:25 +0100 Subject: [PATCH] Migrate CLI commands to use LoadProject API Simplifying the codebase and eliminating duplicate backend creation. Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com> --- cmd/compose/bridge.go | 8 +++- cmd/compose/build.go | 11 ++--- cmd/compose/completion.go | 14 +++++- cmd/compose/compose.go | 91 ++++++++++++++++----------------------- cmd/compose/config.go | 81 +++++++++++++++++++++++++++------- cmd/compose/publish.go | 18 ++++---- cmd/compose/pull.go | 11 ++--- cmd/compose/push.go | 11 ++--- cmd/compose/run.go | 19 ++++---- cmd/compose/scale.go | 11 ++--- cmd/compose/viz.go | 12 +++--- cmd/compose/watch.go | 15 +++---- 12 files changed, 179 insertions(+), 123 deletions(-) diff --git a/cmd/compose/bridge.go b/cmd/compose/bridge.go index 22f78b689..bd0d11b2a 100644 --- a/cmd/compose/bridge.go +++ b/cmd/compose/bridge.go @@ -30,6 +30,7 @@ import ( "github.com/docker/compose/v2/cmd/formatter" "github.com/docker/compose/v2/pkg/bridge" + "github.com/docker/compose/v2/pkg/compose" ) func bridgeCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command { @@ -62,7 +63,12 @@ func convertCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command { } func runConvert(ctx context.Context, dockerCli command.Cli, p *ProjectOptions, opts bridge.ConvertOptions) error { - project, _, err := p.ToProject(ctx, dockerCli, nil) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, _, err := p.ToProject(ctx, dockerCli, backend, nil) if err != nil { return err } diff --git a/cmd/compose/build.go b/cmd/compose/build.go index 7307efb43..0212b6ddd 100644 --- a/cmd/compose/build.go +++ b/cmd/compose/build.go @@ -150,8 +150,13 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Back } func runBuild(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts buildOptions, services []string) error { + backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) + if err != nil { + return err + } + opts.All = true // do not drop resources as build may involve some dependencies by additional_contexts - project, _, err := opts.ToProject(ctx, dockerCli, nil, cli.WithResolvedPaths(true), cli.WithoutEnvironmentResolution) + project, _, err := opts.ToProject(ctx, dockerCli, backend, nil, cli.WithoutEnvironmentResolution) if err != nil { return err } @@ -166,9 +171,5 @@ func runBuild(ctx context.Context, dockerCli command.Cli, backendOptions *Backen } apiBuildOptions.Attestations = true - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } return backend.Build(ctx, project, apiBuildOptions) } diff --git a/cmd/compose/completion.go b/cmd/compose/completion.go index 59bfdd885..9f206bde5 100644 --- a/cmd/compose/completion.go +++ b/cmd/compose/completion.go @@ -38,7 +38,12 @@ func noCompletion() validArgsFn { func completeServiceNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { p.Offline = true - project, _, err := p.ToProject(cmd.Context(), dockerCli, nil) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + project, _, err := p.ToProject(cmd.Context(), dockerCli, backend, nil) if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } @@ -79,7 +84,12 @@ func completeProjectNames(dockerCli command.Cli, backendOptions *BackendOptions) func completeProfileNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { p.Offline = true - project, _, err := p.ToProject(cmd.Context(), dockerCli, nil) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + project, _, err := p.ToProject(cmd.Context(), dockerCli, backend, nil) if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 7ebaa0cac..bcafe1583 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -159,12 +159,12 @@ func (o *ProjectOptions) WithProject(fn ProjectFunc, dockerCli command.Cli) func // WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services func (o *ProjectOptions) WithServices(dockerCli command.Cli, fn ProjectServicesFunc) func(cmd *cobra.Command, args []string) error { return Adapt(func(ctx context.Context, args []string) error { - options := []cli.ProjectOptionsFn{ - cli.WithResolvedPaths(true), - cli.WithoutEnvironmentResolution, + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err } - project, metrics, err := o.ToProject(ctx, dockerCli, args, options...) + project, metrics, err := o.ToProject(ctx, dockerCli, backend, args, cli.WithoutEnvironmentResolution) if err != nil { return err } @@ -236,7 +236,12 @@ func (o *ProjectOptions) projectOrName(ctx context.Context, dockerCli command.Cl name := o.ProjectName var project *types.Project if len(o.ConfigPaths) > 0 || o.ProjectName == "" { - p, _, err := o.ToProject(ctx, dockerCli, services, cli.WithDiscardEnvFile, cli.WithoutEnvironmentResolution) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return nil, "", err + } + + p, _, err := o.ToProject(ctx, dockerCli, backend, services, cli.WithDiscardEnvFile, cli.WithoutEnvironmentResolution) if err != nil { envProjectName := os.Getenv(ComposeProjectName) if envProjectName != "" { @@ -260,7 +265,12 @@ func (o *ProjectOptions) toProjectName(ctx context.Context, dockerCli command.Cl return envProjectName, nil } - project, _, err := o.ToProject(ctx, dockerCli, nil) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return "", err + } + + project, _, err := o.ToProject(ctx, dockerCli, backend, nil) if err != nil { return "", err } @@ -285,19 +295,14 @@ func (o *ProjectOptions) ToModel(ctx context.Context, dockerCli command.Cli, ser return options.LoadModel(ctx) } -func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, services []string, po ...cli.ProjectOptionsFn) (*types.Project, tracing.Metrics, error) { //nolint:gocyclo +// ToProject loads a Compose project using the LoadProject API. +// Accepts optional cli.ProjectOptionsFn to control loader behavior. +func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, backend api.Compose, services []string, po ...cli.ProjectOptionsFn) (*types.Project, tracing.Metrics, error) { var metrics tracing.Metrics remotes := o.remoteLoaders(dockerCli) - for _, r := range remotes { - po = append(po, cli.WithResourceLoader(r)) - } - options, err := o.toProjectOptions(po...) - if err != nil { - return nil, metrics, err - } - - options.WithListeners(func(event string, metadata map[string]any) { + // Setup metrics listener to collect project data + metricsListener := func(event string, metadata map[string]any) { switch event { case "extends": metrics.CountExtends++ @@ -318,50 +323,28 @@ func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, s } } } - }) - - if o.Compatibility || utils.StringToBool(options.Environment[ComposeCompatibility]) { - api.Separator = "_" } - project, err := options.LoadProject(ctx) + loadOpts := api.ProjectLoadOptions{ + ProjectName: o.ProjectName, + ConfigPaths: o.ConfigPaths, + WorkingDir: o.ProjectDir, + EnvFiles: o.EnvFiles, + Profiles: o.Profiles, + Services: services, + Offline: o.Offline, + All: o.All, + Compatibility: o.Compatibility, + ProjectOptionsFns: po, + LoadListeners: []api.LoadListener{metricsListener}, + } + + project, err := backend.LoadProject(ctx, loadOpts) if err != nil { return nil, metrics, err } - if project.Name == "" { - return nil, metrics, errors.New("project name can't be empty. Use `--project-name` to set a valid name") - } - - project, err = project.WithServicesEnabled(services...) - if err != nil { - return nil, metrics, err - } - - for name, s := range project.Services { - s.CustomLabels = map[string]string{ - api.ProjectLabel: project.Name, - api.ServiceLabel: name, - api.VersionLabel: api.ComposeVersion, - api.WorkingDirLabel: project.WorkingDir, - api.ConfigFilesLabel: strings.Join(project.ComposeFiles, ","), - api.OneoffLabel: "False", // default, will be overridden by `run` command - } - if len(o.EnvFiles) != 0 { - s.CustomLabels[api.EnvironmentFileLabel] = strings.Join(o.EnvFiles, ",") - } - project.Services[name] = s - } - - project, err = project.WithSelectedServices(services) - if err != nil { - return nil, tracing.Metrics{}, err - } - - if !o.All { - project = project.WithoutUnnecessaryResources() - } - return project, metrics, err + return project, metrics, nil } func (o *ProjectOptions) remoteLoaders(dockerCli command.Cli) []loader.ResourceLoader { diff --git a/cmd/compose/config.go b/cmd/compose/config.go index 5edcb3db9..795d73c18 100644 --- a/cmd/compose/config.go +++ b/cmd/compose/config.go @@ -61,19 +61,19 @@ type configOptions struct { lockImageDigests bool } -func (o *configOptions) ToProject(ctx context.Context, dockerCli command.Cli, services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) { - po = append(po, o.ToProjectOptions()...) - project, _, err := o.ProjectOptions.ToProject(ctx, dockerCli, services, po...) +func (o *configOptions) ToProject(ctx context.Context, dockerCli command.Cli, backend api.Compose, services []string) (*types.Project, error) { + project, _, err := o.ProjectOptions.ToProject(ctx, dockerCli, backend, services, o.toProjectOptionsFns()...) return project, err } func (o *configOptions) ToModel(ctx context.Context, dockerCli command.Cli, services []string, po ...cli.ProjectOptionsFn) (map[string]any, error) { - po = append(po, o.ToProjectOptions()...) + po = append(po, o.toProjectOptionsFns()...) return o.ProjectOptions.ToModel(ctx, dockerCli, services, po...) } -func (o *configOptions) ToProjectOptions() []cli.ProjectOptionsFn { - return []cli.ProjectOptionsFn{ +// toProjectOptionsFns converts config options to cli.ProjectOptionsFn +func (o *configOptions) toProjectOptionsFns() []cli.ProjectOptionsFn { + fns := []cli.ProjectOptionsFn{ cli.WithInterpolation(!o.noInterpolate), cli.WithResolvedPaths(!o.noResolvePath), cli.WithNormalization(!o.noNormalize), @@ -81,6 +81,10 @@ func (o *configOptions) ToProjectOptions() []cli.ProjectOptionsFn { cli.WithDefaultProfiles(o.Profiles...), cli.WithDiscardEnvFile, } + if o.noResolveEnv { + fns = append(fns, cli.WithoutEnvironmentResolution) + } + return fns } func configCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command { @@ -197,7 +201,12 @@ func runConfig(ctx context.Context, dockerCli command.Cli, opts configOptions, s } func runConfigInterpolate(ctx context.Context, dockerCli command.Cli, opts configOptions, services []string) ([]byte, error) { - project, err := opts.ToProject(ctx, dockerCli, services) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return nil, err + } + + project, err := opts.ToProject(ctx, dockerCli, backend, services) if err != nil { return nil, err } @@ -353,7 +362,12 @@ func runServices(ctx context.Context, dockerCli command.Cli, opts configOptions) return nil } - project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, _, err := opts.ProjectOptions.ToProject(ctx, dockerCli, backend, nil, cli.WithoutEnvironmentResolution) if err != nil { return err } @@ -366,7 +380,12 @@ func runServices(ctx context.Context, dockerCli command.Cli, opts configOptions) } func runVolumes(ctx context.Context, dockerCli command.Cli, opts configOptions) error { - project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, _, err := opts.ProjectOptions.ToProject(ctx, dockerCli, backend, nil, cli.WithoutEnvironmentResolution) if err != nil { return err } @@ -377,7 +396,12 @@ func runVolumes(ctx context.Context, dockerCli command.Cli, opts configOptions) } func runNetworks(ctx context.Context, dockerCli command.Cli, opts configOptions) error { - project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, _, err := opts.ProjectOptions.ToProject(ctx, dockerCli, backend, nil, cli.WithoutEnvironmentResolution) if err != nil { return err } @@ -388,7 +412,12 @@ func runNetworks(ctx context.Context, dockerCli command.Cli, opts configOptions) } func runModels(ctx context.Context, dockerCli command.Cli, opts configOptions) error { - project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, _, err := opts.ProjectOptions.ToProject(ctx, dockerCli, backend, nil, cli.WithoutEnvironmentResolution) if err != nil { return err } @@ -405,7 +434,13 @@ func runHash(ctx context.Context, dockerCli command.Cli, opts configOptions) err if opts.hash != "*" { services = append(services, strings.Split(opts.hash, ",")...) } - project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution) + + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, _, err := opts.ProjectOptions.ToProject(ctx, dockerCli, backend, nil, cli.WithoutEnvironmentResolution) if err != nil { return err } @@ -440,7 +475,13 @@ func runHash(ctx context.Context, dockerCli command.Cli, opts configOptions) err func runProfiles(ctx context.Context, dockerCli command.Cli, opts configOptions, services []string) error { set := map[string]struct{}{} - project, err := opts.ToProject(ctx, dockerCli, services, cli.WithoutEnvironmentResolution) + + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, err := opts.ToProject(ctx, dockerCli, backend, services) if err != nil { return err } @@ -461,7 +502,12 @@ func runProfiles(ctx context.Context, dockerCli command.Cli, opts configOptions, } func runConfigImages(ctx context.Context, dockerCli command.Cli, opts configOptions, services []string) error { - project, err := opts.ToProject(ctx, dockerCli, services, cli.WithoutEnvironmentResolution) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, err := opts.ToProject(ctx, dockerCli, backend, services) if err != nil { return err } @@ -498,7 +544,12 @@ func runVariables(ctx context.Context, dockerCli command.Cli, opts configOptions } func runEnvironment(ctx context.Context, dockerCli command.Cli, opts configOptions, services []string) error { - project, err := opts.ToProject(ctx, dockerCli, services) + backend, err := compose.NewComposeService(dockerCli) + if err != nil { + return err + } + + project, err := opts.ToProject(ctx, dockerCli, backend, services) if err != nil { return err } diff --git a/cmd/compose/publish.go b/cmd/compose/publish.go index becd162ee..86d526f31 100644 --- a/cmd/compose/publish.go +++ b/cmd/compose/publish.go @@ -69,7 +69,16 @@ func publishCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Ba } func runPublish(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts publishOptions, repository string) error { - project, metrics, err := opts.ToProject(ctx, dockerCli, nil) + if opts.assumeYes { + backendOptions.Options = append(backendOptions.Options, compose.WithPrompt(compose.AlwaysOkPrompt())) + } + + backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) + if err != nil { + return err + } + + project, metrics, err := opts.ToProject(ctx, dockerCli, backend, nil) if err != nil { return err } @@ -78,13 +87,6 @@ func runPublish(ctx context.Context, dockerCli command.Cli, backendOptions *Back return errors.New("cannot publish compose file with local includes") } - if opts.assumeYes { - backendOptions.Options = append(backendOptions.Options, compose.WithPrompt(compose.AlwaysOkPrompt())) - } - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } return backend.Publish(ctx, project, repository, api.PublishOptions{ ResolveImageDigests: opts.resolveImageDigests || opts.app, Application: opts.app, diff --git a/cmd/compose/pull.go b/cmd/compose/pull.go index 9cf5e5d28..4e4e58b48 100644 --- a/cmd/compose/pull.go +++ b/cmd/compose/pull.go @@ -99,7 +99,12 @@ func (opts pullOptions) apply(project *types.Project, services []string) (*types } func runPull(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts pullOptions, services []string) error { - project, _, err := opts.ToProject(ctx, dockerCli, services, cli.WithoutEnvironmentResolution) + backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) + if err != nil { + return err + } + + project, _, err := opts.ToProject(ctx, dockerCli, backend, services, cli.WithoutEnvironmentResolution) if err != nil { return err } @@ -109,10 +114,6 @@ func runPull(ctx context.Context, dockerCli command.Cli, backendOptions *Backend return err } - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } return backend.Pull(ctx, project, api.PullOptions{ Quiet: opts.quiet, IgnoreFailures: opts.ignorePullFailures, diff --git a/cmd/compose/push.go b/cmd/compose/push.go index bbb4152da..c76d1eca0 100644 --- a/cmd/compose/push.go +++ b/cmd/compose/push.go @@ -55,7 +55,12 @@ func pushCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backe } func runPush(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts pushOptions, services []string) error { - project, _, err := opts.ToProject(ctx, dockerCli, services) + backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) + if err != nil { + return err + } + + project, _, err := opts.ToProject(ctx, dockerCli, backend, services) if err != nil { return err } @@ -67,10 +72,6 @@ func runPush(ctx context.Context, dockerCli command.Cli, backendOptions *Backend } } - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } return backend.Push(ctx, project, api.PushOptions{ IgnoreFailures: opts.Ignorefailures, Quiet: opts.Quiet, diff --git a/cmd/compose/run.go b/cmd/compose/run.go index 0894a8cba..ab528837b 100644 --- a/cmd/compose/run.go +++ b/cmd/compose/run.go @@ -22,6 +22,7 @@ import ( "os" "strings" + composecli "github.com/compose-spec/compose-go/v2/cli" "github.com/compose-spec/compose-go/v2/dotenv" "github.com/compose-spec/compose-go/v2/format" "github.com/docker/compose/v2/pkg/compose" @@ -29,7 +30,6 @@ import ( xprogress "github.com/moby/buildkit/util/progress/progressui" "github.com/sirupsen/logrus" - cgo "github.com/compose-spec/compose-go/v2/cli" "github.com/compose-spec/compose-go/v2/types" "github.com/docker/cli/cli/command" "github.com/docker/cli/opts" @@ -143,7 +143,7 @@ func (options runOptions) getEnvironment(resolve func(string) (string, bool)) (t return environment, nil } -func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command { +func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command { //nolint:gocyclo options := runOptions{ composeOptions: &composeOptions{ ProjectOptions: p, @@ -204,7 +204,12 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backen return nil }), RunE: Adapt(func(ctx context.Context, args []string) error { - project, _, err := p.ToProject(ctx, dockerCli, []string{options.Service}, cgo.WithResolvedPaths(true), cgo.WithoutEnvironmentResolution) + backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) + if err != nil { + return err + } + + project, _, err := p.ToProject(ctx, dockerCli, backend, []string{options.Service}, composecli.WithoutEnvironmentResolution) if err != nil { return err } @@ -219,7 +224,7 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backen } options.ignoreOrphans = utils.StringToBool(project.Environment[ComposeIgnoreOrphans]) - return runRun(ctx, backendOptions, project, options, createOpts, buildOpts, dockerCli) + return runRun(ctx, backend, project, options, createOpts, buildOpts, dockerCli) }), ValidArgsFunction: completeServiceNames(dockerCli, p), } @@ -267,7 +272,7 @@ func normalizeRunFlags(f *pflag.FlagSet, name string) pflag.NormalizedName { return pflag.NormalizedName(name) } -func runRun(ctx context.Context, backendOptions *BackendOptions, project *types.Project, options runOptions, createOpts createOptions, buildOpts buildOptions, dockerCli command.Cli) error { +func runRun(ctx context.Context, backend api.Compose, project *types.Project, options runOptions, createOpts createOptions, buildOpts buildOptions, dockerCli command.Cli) error { project, err := options.apply(project) if err != nil { return err @@ -339,10 +344,6 @@ func runRun(ctx context.Context, backendOptions *BackendOptions, project *types. } } - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } exitCode, err := backend.RunOneOffContainer(ctx, project, runOpts) if exitCode != 0 { errMsg := "" diff --git a/cmd/compose/scale.go b/cmd/compose/scale.go index 3f6c49272..df9030ae0 100644 --- a/cmd/compose/scale.go +++ b/cmd/compose/scale.go @@ -60,8 +60,13 @@ func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Back } func runScale(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts scaleOptions, serviceReplicaTuples map[string]int) error { + backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) + if err != nil { + return err + } + services := slices.Sorted(maps.Keys(serviceReplicaTuples)) - project, _, err := opts.ToProject(ctx, dockerCli, services) + project, _, err := opts.ToProject(ctx, dockerCli, backend, services) if err != nil { return err } @@ -81,10 +86,6 @@ func runScale(ctx context.Context, dockerCli command.Cli, backendOptions *Backen project.Services[key] = service } - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } return backend.Scale(ctx, project, api.ScaleOptions{Services: services}) } diff --git a/cmd/compose/viz.go b/cmd/compose/viz.go index 4bf0a5281..f55d12f3f 100644 --- a/cmd/compose/viz.go +++ b/cmd/compose/viz.go @@ -66,16 +66,18 @@ func vizCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backen func runViz(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts *vizOptions) error { _, _ = fmt.Fprintln(os.Stderr, "viz command is EXPERIMENTAL") - project, _, err := opts.ToProject(ctx, dockerCli, nil) + + backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) + if err != nil { + return err + } + + project, _, err := opts.ToProject(ctx, dockerCli, backend, nil) if err != nil { return err } // build graph - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } graphStr, _ := backend.Viz(ctx, project, api.VizOptions{ IncludeNetworks: opts.includeNetworks, IncludePorts: opts.includePorts, diff --git a/cmd/compose/watch.go b/cmd/compose/watch.go index 68d9004e0..70648fcda 100644 --- a/cmd/compose/watch.go +++ b/cmd/compose/watch.go @@ -66,7 +66,12 @@ func watchCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Back } func runWatch(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, watchOpts watchOptions, buildOpts buildOptions, services []string) error { - project, _, err := watchOpts.ToProject(ctx, dockerCli, services) + backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) + if err != nil { + return err + } + + project, _, err := watchOpts.ToProject(ctx, dockerCli, backend, services) if err != nil { return err } @@ -112,19 +117,11 @@ func runWatch(ctx context.Context, dockerCli command.Cli, backendOptions *Backen Services: services, }, } - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } if err := backend.Up(ctx, project, upOpts); err != nil { return err } } - backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...) - if err != nil { - return err - } outStream, errStream, _ := backend.GetConfiguredStreams() consumer := formatter.NewLogConsumer(ctx, outStream, errStream, false, false, false) return backend.Watch(ctx, project, api.WatchOptions{