Setup Compose service using functional parameters

This commit introduces WithMaxConcurrency and WithDryRun to replace direct mutators on composeService
commands and flags are translated into a set of functional parameters which are eventually applied
as a ComposeService is created just before being actually used by a command

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof
2025-10-23 15:25:32 +02:00
committed by Nicolas De loof
parent 3ce52883cb
commit 7f668bd7fe
43 changed files with 378 additions and 463 deletions

View File

@@ -1,5 +1,4 @@
/*
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.
@@ -16,12 +15,11 @@ package compose
import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/spf13/cobra"
)
// alphaCommand groups all experimental subcommands
func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
cmd := &cobra.Command{
Short: "Experimental commands",
Use: "alpha [COMMAND]",
@@ -31,9 +29,9 @@ func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
},
}
cmd.AddCommand(
vizCommand(p, dockerCli, backend),
publishCommand(p, dockerCli, backend),
generateCommand(p, backend),
vizCommand(p, dockerCli, backendOptions),
publishCommand(p, dockerCli, backendOptions),
generateCommand(p, dockerCli, backendOptions),
)
return cmd
}

View File

@@ -21,6 +21,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -35,7 +36,7 @@ type attachOpts struct {
proxy bool
}
func attachCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func attachCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := attachOpts{
composeOptions: &composeOptions{
ProjectOptions: p,
@@ -50,7 +51,7 @@ func attachCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
return runAttach(ctx, dockerCli, backend, opts)
return runAttach(ctx, dockerCli, backendOptions, opts)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -63,7 +64,7 @@ func attachCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return runCmd
}
func runAttach(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts attachOpts) error {
func runAttach(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts attachOpts) error {
projectName, err := opts.toProjectName(ctx, dockerCli)
if err != nil {
return err
@@ -76,5 +77,9 @@ func runAttach(ctx context.Context, dockerCli command.Cli, backend api.Compose,
NoStdin: opts.noStdin,
Proxy: opts.proxy,
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Attach(ctx, projectName, attachOpts)
}

View File

@@ -26,6 +26,7 @@ import (
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/cli/cli/command"
cliopts "github.com/docker/cli/opts"
"github.com/docker/compose/v2/pkg/compose"
ui "github.com/docker/compose/v2/pkg/progress"
"github.com/spf13/cobra"
@@ -90,7 +91,7 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions,
}, nil
}
func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func buildCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := buildOptions{
ProjectOptions: p,
}
@@ -115,7 +116,7 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
if cmd.Flags().Changed("progress") && opts.ssh == "" {
fmt.Fprint(os.Stderr, "--progress is a global compose flag, better use `docker compose --progress xx build ...\n")
}
return runBuild(ctx, dockerCli, backend, opts, args)
return runBuild(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -148,7 +149,7 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return cmd
}
func runBuild(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts buildOptions, services []string) error {
func runBuild(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts buildOptions, services []string) error {
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)
if err != nil {
@@ -165,5 +166,9 @@ func runBuild(ctx context.Context, dockerCli command.Cli, backend api.Compose, o
}
apiBuildOptions.Attestations = true
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Build(ctx, project, apiBuildOptions)
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/opts"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -39,7 +40,7 @@ type commitOptions struct {
index int
}
func commitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func commitCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
options := commitOptions{
ProjectOptions: p,
}
@@ -56,7 +57,7 @@ func commitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
return runCommit(ctx, dockerCli, backend, options)
return runCommit(ctx, dockerCli, backendOptions, options)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -73,12 +74,16 @@ func commitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return cmd
}
func runCommit(ctx context.Context, dockerCli command.Cli, backend api.Compose, options commitOptions) error {
func runCommit(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, options commitOptions) error {
projectName, err := options.toProjectName(ctx, dockerCli)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Commit(ctx, projectName, api.CommitOptions{
Service: options.service,
Reference: options.reference,

View File

@@ -22,6 +22,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -52,8 +53,13 @@ func completeServiceNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn
}
}
func completeProjectNames(backend api.Compose) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
func completeProjectNames(dockerCli command.Cli, backendOptions *BackendOptions) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
list, err := backend.List(cmd.Context(), api.ListOptions{
All: true,
})

View File

@@ -42,6 +42,7 @@ import (
"github.com/docker/compose/v2/cmd/formatter"
"github.com/docker/compose/v2/internal/tracing"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
ui "github.com/docker/compose/v2/pkg/progress"
"github.com/docker/compose/v2/pkg/remote"
"github.com/docker/compose/v2/pkg/utils"
@@ -415,8 +416,16 @@ func RunningAsStandalone() bool {
return len(os.Args) < 2 || os.Args[1] != metadata.MetadataSubcommandName && os.Args[1] != PluginName
}
type BackendOptions struct {
Options []compose.Option
}
func (o *BackendOptions) Add(option compose.Option) {
o.Options = append(o.Options, option)
}
// RootCommand returns the compose command with its child commands
func RootCommand(dockerCli command.Cli, backend api.Compose) *cobra.Command { //nolint:gocyclo
func RootCommand(dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command { //nolint:gocyclo
// filter out useless commandConn.CloseWrite warning message that can occur
// when using a remote context that is unreachable: "commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
// https://github.com/docker/cli/blob/e1f24d3c93df6752d3c27c8d61d18260f141310c/cli/connhelper/commandconn/commandconn.go#L203-L215
@@ -456,9 +465,7 @@ func RootCommand(dockerCli command.Cli, backend api.Compose) *cobra.Command { //
}
},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
parent := cmd.Root()
if parent != nil {
parentPrerun := parent.PersistentPreRunE
if parentPrerun != nil {
@@ -560,64 +567,61 @@ func RootCommand(dockerCli command.Cli, backend api.Compose) *cobra.Command { //
}
if parallel > 0 {
logrus.Debugf("Limiting max concurrency to %d jobs", parallel)
backend.MaxConcurrency(parallel)
backendOptions.Add(compose.WithMaxConcurrency(parallel))
}
// dry run detection
ctx, err = backend.DryRunMode(ctx, dryRun)
if err != nil {
return err
if dryRun {
backendOptions.Add(compose.WithDryRun)
}
cmd.SetContext(ctx)
return nil
},
}
c.AddCommand(
upCommand(&opts, dockerCli, backend),
downCommand(&opts, dockerCli, backend),
startCommand(&opts, dockerCli, backend),
restartCommand(&opts, dockerCli, backend),
stopCommand(&opts, dockerCli, backend),
psCommand(&opts, dockerCli, backend),
listCommand(dockerCli, backend),
logsCommand(&opts, dockerCli, backend),
upCommand(&opts, dockerCli, backendOptions),
downCommand(&opts, dockerCli, backendOptions),
startCommand(&opts, dockerCli, backendOptions),
restartCommand(&opts, dockerCli, backendOptions),
stopCommand(&opts, dockerCli, backendOptions),
psCommand(&opts, dockerCli, backendOptions),
listCommand(dockerCli, backendOptions),
logsCommand(&opts, dockerCli, backendOptions),
configCommand(&opts, dockerCli),
killCommand(&opts, dockerCli, backend),
runCommand(&opts, dockerCli, backend),
removeCommand(&opts, dockerCli, backend),
execCommand(&opts, dockerCli, backend),
attachCommand(&opts, dockerCli, backend),
exportCommand(&opts, dockerCli, backend),
commitCommand(&opts, dockerCli, backend),
pauseCommand(&opts, dockerCli, backend),
unpauseCommand(&opts, dockerCli, backend),
topCommand(&opts, dockerCli, backend),
eventsCommand(&opts, dockerCli, backend),
portCommand(&opts, dockerCli, backend),
imagesCommand(&opts, dockerCli, backend),
killCommand(&opts, dockerCli, backendOptions),
runCommand(&opts, dockerCli, backendOptions),
removeCommand(&opts, dockerCli, backendOptions),
execCommand(&opts, dockerCli, backendOptions),
attachCommand(&opts, dockerCli, backendOptions),
exportCommand(&opts, dockerCli, backendOptions),
commitCommand(&opts, dockerCli, backendOptions),
pauseCommand(&opts, dockerCli, backendOptions),
unpauseCommand(&opts, dockerCli, backendOptions),
topCommand(&opts, dockerCli, backendOptions),
eventsCommand(&opts, dockerCli, backendOptions),
portCommand(&opts, dockerCli, backendOptions),
imagesCommand(&opts, dockerCli, backendOptions),
versionCommand(dockerCli),
buildCommand(&opts, dockerCli, backend),
pushCommand(&opts, dockerCli, backend),
pullCommand(&opts, dockerCli, backend),
createCommand(&opts, dockerCli, backend),
copyCommand(&opts, dockerCli, backend),
waitCommand(&opts, dockerCli, backend),
scaleCommand(&opts, dockerCli, backend),
buildCommand(&opts, dockerCli, backendOptions),
pushCommand(&opts, dockerCli, backendOptions),
pullCommand(&opts, dockerCli, backendOptions),
createCommand(&opts, dockerCli, backendOptions),
copyCommand(&opts, dockerCli, backendOptions),
waitCommand(&opts, dockerCli, backendOptions),
scaleCommand(&opts, dockerCli, backendOptions),
statsCommand(&opts, dockerCli),
watchCommand(&opts, dockerCli, backend),
publishCommand(&opts, dockerCli, backend),
alphaCommand(&opts, dockerCli, backend),
watchCommand(&opts, dockerCli, backendOptions),
publishCommand(&opts, dockerCli, backendOptions),
alphaCommand(&opts, dockerCli, backendOptions),
bridgeCommand(&opts, dockerCli),
volumesCommand(&opts, dockerCli, backend),
volumesCommand(&opts, dockerCli, backendOptions),
)
c.Flags().SetInterspersed(false)
opts.addProjectFlags(c.Flags())
c.RegisterFlagCompletionFunc( //nolint:errcheck
"project-name",
completeProjectNames(backend),
completeProjectNames(dockerCli, backendOptions),
)
c.RegisterFlagCompletionFunc( //nolint:errcheck
"project-directory",

View File

@@ -22,6 +22,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -38,7 +39,7 @@ type copyOptions struct {
copyUIDGID bool
}
func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func copyCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := copyOptions{
ProjectOptions: p,
}
@@ -59,7 +60,7 @@ func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
RunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
opts.source = args[0]
opts.destination = args[1]
return runCopy(ctx, dockerCli, backend, opts)
return runCopy(ctx, dockerCli, backendOptions, opts)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -73,12 +74,16 @@ func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return copyCmd
}
func runCopy(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts copyOptions) error {
func runCopy(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts copyOptions) error {
name, err := opts.toProjectName(ctx, dockerCli)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Copy(ctx, name, api.CopyOptions{
Source: opts.source,
Destination: opts.destination,

View File

@@ -26,6 +26,7 @@ import (
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -51,7 +52,7 @@ type createOptions struct {
AssumeYes bool
}
func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func createCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := createOptions{}
buildOpts := buildOptions{
ProjectOptions: p,
@@ -70,7 +71,7 @@ func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return nil
}),
RunE: p.WithServices(dockerCli, func(ctx context.Context, project *types.Project, services []string) error {
return runCreate(ctx, dockerCli, backend, opts, buildOpts, project, services)
return runCreate(ctx, dockerCli, backendOptions, opts, buildOpts, project, services)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -95,7 +96,7 @@ func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return cmd
}
func runCreate(ctx context.Context, _ command.Cli, backend api.Compose, createOpts createOptions, buildOpts buildOptions, project *types.Project, services []string) error {
func runCreate(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, createOpts createOptions, buildOpts buildOptions, project *types.Project, services []string) error {
if err := createOpts.Apply(project); err != nil {
return err
}
@@ -109,6 +110,10 @@ func runCreate(ctx context.Context, _ command.Cli, backend api.Compose, createOp
build = &bo
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Create(ctx, project, api.CreateOptions{
Build: build,
Services: services,

View File

@@ -1,174 +0,0 @@
/*
Copyright 2023 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 compose
import (
"context"
"fmt"
"testing"
"github.com/compose-spec/compose-go/v2/types"
"github.com/davecgh/go-spew/spew"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
)
func TestRunCreate(t *testing.T) {
ctrl, ctx := gomock.WithContext(context.Background(), t)
backend := mocks.NewMockService(ctrl)
backend.EXPECT().Create(
gomock.Eq(ctx),
pullPolicy(""),
deepEqual(defaultCreateOptions(true)),
)
createOpts := createOptions{}
buildOpts := buildOptions{
ProjectOptions: &ProjectOptions{},
}
project := sampleProject()
err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
require.NoError(t, err)
}
func TestRunCreate_Build(t *testing.T) {
ctrl, ctx := gomock.WithContext(context.Background(), t)
backend := mocks.NewMockService(ctrl)
backend.EXPECT().Create(
gomock.Eq(ctx),
pullPolicy("build"),
deepEqual(defaultCreateOptions(true)),
)
createOpts := createOptions{
Build: true,
}
buildOpts := buildOptions{
ProjectOptions: &ProjectOptions{},
}
project := sampleProject()
err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
require.NoError(t, err)
}
func TestRunCreate_NoBuild(t *testing.T) {
ctrl, ctx := gomock.WithContext(context.Background(), t)
backend := mocks.NewMockService(ctrl)
backend.EXPECT().Create(
gomock.Eq(ctx),
pullPolicy(""),
deepEqual(defaultCreateOptions(false)),
)
createOpts := createOptions{
noBuild: true,
}
buildOpts := buildOptions{}
project := sampleProject()
err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
require.NoError(t, err)
}
func sampleProject() *types.Project {
return &types.Project{
Name: "test",
Services: types.Services{
"svc": {
Name: "svc",
Build: &types.BuildConfig{
Context: ".",
},
},
},
}
}
func defaultCreateOptions(includeBuild bool) api.CreateOptions {
var build *api.BuildOptions
if includeBuild {
bo := defaultBuildOptions()
build = &bo
}
return api.CreateOptions{
Build: build,
Services: nil,
RemoveOrphans: false,
IgnoreOrphans: false,
Recreate: "diverged",
RecreateDependencies: "diverged",
Inherit: true,
Timeout: nil,
QuietPull: false,
}
}
func defaultBuildOptions() api.BuildOptions {
return api.BuildOptions{
Args: make(types.MappingWithEquals),
Progress: "auto",
}
}
// deepEqual returns a nice diff on failure vs gomock.Eq when used
// on structs.
func deepEqual(x interface{}) gomock.Matcher {
return gomock.GotFormatterAdapter(
gomock.GotFormatterFunc(func(got interface{}) string {
return cmp.Diff(x, got)
}),
gomock.Eq(x),
)
}
func spewAdapter(m gomock.Matcher) gomock.Matcher {
return gomock.GotFormatterAdapter(
gomock.GotFormatterFunc(func(got interface{}) string {
return spew.Sdump(got)
}),
m,
)
}
type withPullPolicy struct {
policy string
}
func pullPolicy(policy string) gomock.Matcher {
return spewAdapter(withPullPolicy{policy: policy})
}
func (w withPullPolicy) Matches(x interface{}) bool {
proj, ok := x.(*types.Project)
if !ok || proj == nil || len(proj.Services) == 0 {
return false
}
for _, svc := range proj.Services {
if svc.PullPolicy != w.policy {
return false
}
}
return true
}
func (w withPullPolicy) String() string {
return fmt.Sprintf("has pull policy %q for all services", w.policy)
}

View File

@@ -23,6 +23,7 @@ import (
"time"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/docker/compose/v2/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -40,7 +41,7 @@ type downOptions struct {
images string
}
func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func downCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := downOptions{
ProjectOptions: p,
}
@@ -57,7 +58,7 @@ func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
return runDown(ctx, dockerCli, backend, opts, args)
return runDown(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: noCompletion(),
}
@@ -77,7 +78,7 @@ func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return downCmd
}
func runDown(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts downOptions, services []string) error {
func runDown(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts downOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
@@ -88,6 +89,10 @@ func runDown(ctx context.Context, dockerCli command.Cli, backend api.Compose, op
timeoutValue := time.Duration(opts.timeout) * time.Second
timeout = &timeoutValue
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Down(ctx, name, api.DownOptions{
RemoveOrphans: opts.removeOrphans,
Project: project,

View File

@@ -23,6 +23,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -34,7 +35,7 @@ type eventsOpts struct {
until string
}
func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := eventsOpts{
composeOptions: &composeOptions{
ProjectOptions: p,
@@ -44,7 +45,7 @@ func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
Use: "events [OPTIONS] [SERVICE...]",
Short: "Receive real time events from containers",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runEvents(ctx, dockerCli, backend, opts, args)
return runEvents(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -55,12 +56,16 @@ func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return cmd
}
func runEvents(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts eventsOpts, services []string) error {
func runEvents(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts eventsOpts, services []string) error {
name, err := opts.toProjectName(ctx, dockerCli)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Events(ctx, name, api.EventsOptions{
Services: services,
Since: opts.since,

View File

@@ -48,7 +48,7 @@ type execOpts struct {
interactive bool
}
func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func execCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := execOpts{
composeOptions: &composeOptions{
ProjectOptions: p,
@@ -64,7 +64,7 @@ func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
err := runExec(ctx, dockerCli, backend, opts)
err := runExec(ctx, dockerCli, backendOptions, opts)
if err != nil {
logrus.Debugf("%v", err)
var cliError cli.StatusError
@@ -100,7 +100,7 @@ func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return runCmd
}
func runExec(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts execOpts) error {
func runExec(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts execOpts) error {
projectName, err := opts.toProjectName(ctx, dockerCli)
if err != nil {
return err
@@ -126,6 +126,10 @@ func runExec(ctx context.Context, dockerCli command.Cli, backend api.Compose, op
Interactive: opts.interactive,
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
exitCode, err := backend.Exec(ctx, projectName, execOpts)
if exitCode != 0 {
errMsg := fmt.Sprintf("exit status %d", exitCode)

View File

@@ -20,6 +20,7 @@ import (
"context"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -33,7 +34,7 @@ type exportOptions struct {
index int
}
func exportCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func exportCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
options := exportOptions{
ProjectOptions: p,
}
@@ -46,7 +47,7 @@ func exportCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
return runExport(ctx, dockerCli, backend, options)
return runExport(ctx, dockerCli, backendOptions, options)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -58,7 +59,7 @@ func exportCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return cmd
}
func runExport(ctx context.Context, dockerCli command.Cli, backend api.Compose, options exportOptions) error {
func runExport(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, options exportOptions) error {
projectName, err := options.toProjectName(ctx, dockerCli)
if err != nil {
return err
@@ -70,5 +71,9 @@ func runExport(ctx context.Context, dockerCli command.Cli, backend api.Compose,
Output: options.output,
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Export(ctx, projectName, exportOptions)
}

View File

@@ -21,7 +21,9 @@ import (
"fmt"
"os"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -30,7 +32,7 @@ type generateOptions struct {
Format string
}
func generateCommand(p *ProjectOptions, backend api.Compose) *cobra.Command {
func generateCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := generateOptions{
ProjectOptions: p,
}
@@ -42,7 +44,7 @@ func generateCommand(p *ProjectOptions, backend api.Compose) *cobra.Command {
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
return runGenerate(ctx, backend, opts, args)
return runGenerate(ctx, dockerCli, backendOptions, opts, args)
}),
}
@@ -52,11 +54,16 @@ func generateCommand(p *ProjectOptions, backend api.Compose) *cobra.Command {
return cmd
}
func runGenerate(ctx context.Context, backend api.Compose, opts generateOptions, containers []string) error {
func runGenerate(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts generateOptions, containers []string) error {
_, _ = fmt.Fprintln(os.Stderr, "generate command is EXPERIMENTAL")
if len(containers) == 0 {
return fmt.Errorf("at least one container must be specified")
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
project, err := backend.Generate(ctx, api.GenerateOptions{
Containers: containers,
ProjectName: opts.ProjectName,
@@ -64,6 +71,7 @@ func runGenerate(ctx context.Context, backend api.Compose, opts generateOptions,
if err != nil {
return err
}
var content []byte
switch opts.Format {
case "json":

View File

@@ -27,6 +27,7 @@ import (
"github.com/containerd/platforms"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/go-units"
"github.com/spf13/cobra"
@@ -41,7 +42,7 @@ type imageOptions struct {
Format string
}
func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := imageOptions{
ProjectOptions: p,
}
@@ -49,7 +50,7 @@ func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
Use: "images [OPTIONS] [SERVICE...]",
Short: "List images used by the created containers",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runImages(ctx, dockerCli, backend, opts, args)
return runImages(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -58,12 +59,16 @@ func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose
return imgCmd
}
func runImages(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts imageOptions, services []string) error {
func runImages(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts imageOptions, services []string) error {
projectName, err := opts.toProjectName(ctx, dockerCli)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
images, err := backend.Images(ctx, projectName, api.ImagesOptions{
Services: services,
})

View File

@@ -21,6 +21,7 @@ import (
"os"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -33,7 +34,7 @@ type killOptions struct {
signal string
}
func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func killCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := killOptions{
ProjectOptions: p,
}
@@ -41,7 +42,7 @@ func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
Use: "kill [OPTIONS] [SERVICE...]",
Short: "Force stop service containers",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runKill(ctx, dockerCli, backend, opts, args)
return runKill(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -54,12 +55,16 @@ func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return cmd
}
func runKill(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts killOptions, services []string) error {
func runKill(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts killOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Kill(ctx, name, api.KillOptions{
RemoveOrphans: opts.removeOrphans,
Project: project,

View File

@@ -24,6 +24,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/cmd/formatter"
"github.com/docker/compose/v2/pkg/compose"
"github.com/docker/cli/opts"
"github.com/spf13/cobra"
@@ -38,13 +39,13 @@ type lsOptions struct {
Filter opts.FilterOpt
}
func listCommand(dockerCli command.Cli, backend api.Compose) *cobra.Command {
func listCommand(dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
lsOpts := lsOptions{Filter: opts.NewFilterOpt()}
lsCmd := &cobra.Command{
Use: "ls [OPTIONS]",
Short: "List running compose projects",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runList(ctx, dockerCli, backend, lsOpts)
return runList(ctx, dockerCli, backendOptions, lsOpts)
}),
Args: cobra.NoArgs,
ValidArgsFunction: noCompletion(),
@@ -61,13 +62,17 @@ var acceptedListFilters = map[string]bool{
"name": true,
}
func runList(ctx context.Context, dockerCli command.Cli, backend api.Compose, lsOpts lsOptions) error {
func runList(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, lsOpts lsOptions) error {
filters := lsOpts.Filter.Value()
err := filters.Validate(acceptedListFilters)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
stackList, err := backend.List(ctx, api.ListOptions{All: lsOpts.All})
if err != nil {
return err

View File

@@ -21,6 +21,7 @@ import (
"errors"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/cmd/formatter"
@@ -40,7 +41,7 @@ type logsOptions struct {
timestamps bool
}
func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func logsCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := logsOptions{
ProjectOptions: p,
}
@@ -48,7 +49,7 @@ func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
Use: "logs [OPTIONS] [SERVICE...]",
Short: "View output from containers",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runLogs(ctx, dockerCli, backend, opts, args)
return runLogs(ctx, dockerCli, backendOptions, opts, args)
}),
PreRunE: func(cmd *cobra.Command, args []string) error {
if opts.index > 0 && len(args) != 1 {
@@ -70,7 +71,7 @@ func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return logsCmd
}
func runLogs(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts logsOptions, services []string) error {
func runLogs(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts logsOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
@@ -86,6 +87,10 @@ func runLogs(ctx context.Context, dockerCli command.Cli, backend api.Compose, op
}
consumer := formatter.NewLogConsumer(ctx, dockerCli.Out(), dockerCli.Err(), !opts.noColor, !opts.noPrefix, false)
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Logs(ctx, name, consumer, api.LogOptions{
Project: project,
Services: services,

View File

@@ -20,6 +20,7 @@ import (
"context"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -29,7 +30,7 @@ type pauseOptions struct {
*ProjectOptions
}
func pauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func pauseCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := pauseOptions{
ProjectOptions: p,
}
@@ -37,19 +38,23 @@ func pauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
Use: "pause [SERVICE...]",
Short: "Pause services",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPause(ctx, dockerCli, backend, opts, args)
return runPause(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
return cmd
}
func runPause(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts pauseOptions, services []string) error {
func runPause(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts pauseOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Pause(ctx, name, api.PauseOptions{
Services: services,
Project: project,
@@ -60,7 +65,7 @@ type unpauseOptions struct {
*ProjectOptions
}
func unpauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func unpauseCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := unpauseOptions{
ProjectOptions: p,
}
@@ -68,19 +73,23 @@ func unpauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compos
Use: "unpause [SERVICE...]",
Short: "Unpause services",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runUnPause(ctx, dockerCli, backend, opts, args)
return runUnPause(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
return cmd
}
func runUnPause(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts unpauseOptions, services []string) error {
func runUnPause(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts unpauseOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.UnPause(ctx, name, api.PauseOptions{
Services: services,
Project: project,

View File

@@ -23,6 +23,7 @@ import (
"strings"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -35,7 +36,7 @@ type portOptions struct {
index int
}
func portCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func portCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := portOptions{
ProjectOptions: p,
}
@@ -53,7 +54,7 @@ func portCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return nil
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPort(ctx, dockerCli, backend, opts, args[0])
return runPort(ctx, dockerCli, backendOptions, opts, args[0])
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -62,11 +63,16 @@ func portCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return cmd
}
func runPort(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts portOptions, service string) error {
func runPort(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts portOptions, service string) error {
projectName, err := opts.toProjectName(ctx, dockerCli)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
ip, port, err := backend.Port(ctx, projectName, service, opts.port, api.PortOptions{
Protocol: opts.protocol,
Index: opts.index,

View File

@@ -26,6 +26,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/cli/cli/command"
cliformatter "github.com/docker/cli/cli/command/formatter"
@@ -64,7 +65,7 @@ func (p *psOptions) parseFilter() error {
return nil
}
func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func psCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := psOptions{
ProjectOptions: p,
}
@@ -75,7 +76,7 @@ func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *c
return opts.parseFilter()
},
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPs(ctx, dockerCli, backend, args, opts)
return runPs(ctx, dockerCli, backendOptions, args, opts)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -91,7 +92,7 @@ func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *c
return psCmd
}
func runPs(ctx context.Context, dockerCli command.Cli, backend api.Compose, services []string, opts psOptions) error {
func runPs(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, services []string, opts psOptions) error { //nolint:gocyclo
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
@@ -111,6 +112,10 @@ func runPs(ctx context.Context, dockerCli command.Cli, backend api.Compose, serv
}
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
containers, err := backend.Ps(ctx, name, api.PsOptions{
Project: project,
All: opts.All || len(opts.Status) != 0,

View File

@@ -1,87 +0,0 @@
/*
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 compose
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/streams"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
)
func TestPsTable(t *testing.T) {
ctx := context.Background()
dir := t.TempDir()
out := filepath.Join(dir, "output.txt")
f, err := os.Create(out)
if err != nil {
t.Fatal("could not create output file")
}
defer func() { _ = f.Close() }()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
backend := mocks.NewMockService(ctrl)
backend.EXPECT().
Ps(gomock.Eq(ctx), gomock.Any(), gomock.Any()).
DoAndReturn(func(ctx context.Context, projectName string, options api.PsOptions) ([]api.ContainerSummary, error) {
return []api.ContainerSummary{
{
ID: "abc123",
Name: "ABC",
Image: "foo/bar",
Publishers: api.PortPublishers{
{
TargetPort: 8080,
PublishedPort: 8080,
Protocol: "tcp",
},
{
TargetPort: 8443,
PublishedPort: 8443,
Protocol: "tcp",
},
},
},
}, nil
}).AnyTimes()
opts := psOptions{ProjectOptions: &ProjectOptions{ProjectName: "test"}}
stdout := streams.NewOut(f)
cli := mocks.NewMockCli(ctrl)
cli.EXPECT().Out().Return(stdout).AnyTimes()
cli.EXPECT().ConfigFile().Return(&configfile.ConfigFile{}).AnyTimes()
err = runPs(ctx, cli, backend, nil, opts)
require.NoError(t, err)
_, err = f.Seek(0, 0)
require.NoError(t, err)
output, err := os.ReadFile(out)
require.NoError(t, err)
assert.Contains(t, string(output), "8080/tcp, 8443/tcp")
}

View File

@@ -23,6 +23,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -37,7 +38,7 @@ type publishOptions struct {
app bool
}
func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func publishCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := publishOptions{
ProjectOptions: p,
}
@@ -45,7 +46,7 @@ func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compos
Use: "publish [OPTIONS] REPOSITORY[:TAG]",
Short: "Publish compose application",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPublish(ctx, dockerCli, backend, opts, args[0])
return runPublish(ctx, dockerCli, backendOptions, opts, args[0])
}),
Args: cli.ExactArgs(1),
}
@@ -67,7 +68,7 @@ func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compos
return cmd
}
func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts publishOptions, repository string) error {
func runPublish(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts publishOptions, repository string) error {
project, metrics, err := opts.ToProject(ctx, dockerCli, nil)
if err != nil {
return err
@@ -77,6 +78,10 @@ func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Compose,
return errors.New("cannot publish compose file with local includes")
}
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,

View File

@@ -24,6 +24,7 @@ import (
"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/compose/v2/pkg/compose"
"github.com/morikuni/aec"
"github.com/spf13/cobra"
@@ -42,7 +43,7 @@ type pullOptions struct {
policy string
}
func pullCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func pullCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := pullOptions{
ProjectOptions: p,
}
@@ -59,7 +60,7 @@ func pullCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return nil
},
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPull(ctx, dockerCli, backend, opts, args)
return runPull(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -97,7 +98,7 @@ func (opts pullOptions) apply(project *types.Project, services []string) (*types
return project, nil
}
func runPull(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts pullOptions, services []string) error {
func runPull(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts pullOptions, services []string) error {
project, _, err := opts.ToProject(ctx, dockerCli, services, cli.WithoutEnvironmentResolution)
if err != nil {
return err
@@ -108,6 +109,10 @@ func runPull(ctx context.Context, dockerCli command.Cli, backend api.Compose, op
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,

View File

@@ -21,6 +21,7 @@ import (
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -34,7 +35,7 @@ type pushOptions struct {
Quiet bool
}
func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func pushCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := pushOptions{
ProjectOptions: p,
}
@@ -42,7 +43,7 @@ func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
Use: "push [OPTIONS] [SERVICE...]",
Short: "Push service images",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPush(ctx, dockerCli, backend, opts, args)
return runPush(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -53,7 +54,7 @@ func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return pushCmd
}
func runPush(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts pushOptions, services []string) error {
func runPush(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts pushOptions, services []string) error {
project, _, err := opts.ToProject(ctx, dockerCli, services)
if err != nil {
return err
@@ -66,6 +67,10 @@ func runPush(ctx context.Context, dockerCli command.Cli, backend api.Compose, op
}
}
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,

View File

@@ -21,6 +21,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -31,7 +32,7 @@ type removeOptions struct {
volumes bool
}
func removeCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func removeCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := removeOptions{
ProjectOptions: p,
}
@@ -45,7 +46,7 @@ can override this with -v. To list all volumes, use "docker volume ls".
Any data which is not in a volume will be lost.`,
RunE: Adapt(func(ctx context.Context, args []string) error {
return runRemove(ctx, dockerCli, backend, opts, args)
return runRemove(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -59,12 +60,16 @@ Any data which is not in a volume will be lost.`,
return cmd
}
func runRemove(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts removeOptions, services []string) error {
func runRemove(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts removeOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Remove(ctx, name, api.RemoveOptions{
Services: services,
Force: opts.force,

View File

@@ -21,6 +21,7 @@ import (
"time"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -33,7 +34,7 @@ type restartOptions struct {
noDeps bool
}
func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func restartCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := restartOptions{
ProjectOptions: p,
}
@@ -44,7 +45,7 @@ func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compos
opts.timeChanged = cmd.Flags().Changed("timeout")
},
RunE: Adapt(func(ctx context.Context, args []string) error {
return runRestart(ctx, dockerCli, backend, opts, args)
return runRestart(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -55,7 +56,7 @@ func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compos
return restartCmd
}
func runRestart(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts restartOptions, services []string) error {
func runRestart(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts restartOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli)
if err != nil {
return err
@@ -74,6 +75,10 @@ func runRestart(ctx context.Context, dockerCli command.Cli, backend api.Compose,
timeout = &timeoutValue
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Restart(ctx, name, api.RestartOptions{
Timeout: timeout,
Services: services,

View File

@@ -24,6 +24,7 @@ import (
"github.com/compose-spec/compose-go/v2/dotenv"
"github.com/compose-spec/compose-go/v2/format"
"github.com/docker/compose/v2/pkg/compose"
xprogress "github.com/moby/buildkit/util/progress/progressui"
"github.com/sirupsen/logrus"
@@ -142,7 +143,7 @@ func (options runOptions) getEnvironment(resolve func(string) (string, bool)) (t
return environment, nil
}
func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
options := runOptions{
composeOptions: &composeOptions{
ProjectOptions: p,
@@ -218,7 +219,7 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *
}
options.ignoreOrphans = utils.StringToBool(project.Environment[ComposeIgnoreOrphans])
return runRun(ctx, backend, project, options, createOpts, buildOpts, dockerCli)
return runRun(ctx, backendOptions, project, options, createOpts, buildOpts, dockerCli)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -266,7 +267,7 @@ func normalizeRunFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(name)
}
func runRun(ctx context.Context, backend api.Compose, project *types.Project, options runOptions, createOpts createOptions, buildOpts buildOptions, dockerCli command.Cli) error {
func runRun(ctx context.Context, backendOptions *BackendOptions, project *types.Project, options runOptions, createOpts createOptions, buildOpts buildOptions, dockerCli command.Cli) error {
project, err := options.apply(project)
if err != nil {
return err
@@ -338,6 +339,10 @@ func runRun(ctx context.Context, backend api.Compose, project *types.Project, op
}
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
exitCode, err := backend.RunOneOffContainer(ctx, project, runOpts)
if exitCode != 0 {
errMsg := ""

View File

@@ -27,6 +27,7 @@ import (
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -35,7 +36,7 @@ type scaleOptions struct {
noDeps bool
}
func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := scaleOptions{
ProjectOptions: p,
}
@@ -48,7 +49,7 @@ func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
if err != nil {
return err
}
return runScale(ctx, dockerCli, backend, opts, serviceTuples)
return runScale(ctx, dockerCli, backendOptions, opts, serviceTuples)
}),
ValidArgsFunction: completeScaleArgs(dockerCli, p),
}
@@ -58,7 +59,7 @@ func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return scaleCmd
}
func runScale(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts scaleOptions, serviceReplicaTuples map[string]int) error {
func runScale(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts scaleOptions, serviceReplicaTuples map[string]int) error {
services := slices.Sorted(maps.Keys(serviceReplicaTuples))
project, _, err := opts.ToProject(ctx, dockerCli, services)
if err != nil {
@@ -80,6 +81,10 @@ func runScale(ctx context.Context, dockerCli command.Cli, backend api.Compose, o
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})
}

View File

@@ -21,6 +21,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -28,7 +29,7 @@ type startOptions struct {
*ProjectOptions
}
func startCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func startCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := startOptions{
ProjectOptions: p,
}
@@ -36,19 +37,23 @@ func startCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
Use: "start [SERVICE...]",
Short: "Start services",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runStart(ctx, dockerCli, backend, opts, args)
return runStart(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
return startCmd
}
func runStart(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts startOptions, services []string) error {
func runStart(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts startOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Start(ctx, name, api.StartOptions{
AttachTo: services,
Project: project,

View File

@@ -21,6 +21,7 @@ import (
"time"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -32,7 +33,7 @@ type stopOptions struct {
timeout int
}
func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func stopCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := stopOptions{
ProjectOptions: p,
}
@@ -43,7 +44,7 @@ func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
opts.timeChanged = cmd.Flags().Changed("timeout")
},
RunE: Adapt(func(ctx context.Context, args []string) error {
return runStop(ctx, dockerCli, backend, opts, args)
return runStop(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -53,7 +54,7 @@ func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return cmd
}
func runStop(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts stopOptions, services []string) error {
func runStop(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts stopOptions, services []string) error {
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
@@ -64,6 +65,10 @@ func runStop(ctx context.Context, dockerCli command.Cli, backend api.Compose, op
timeoutValue := time.Duration(opts.timeout) * time.Second
timeout = &timeoutValue
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Stop(ctx, name, api.StopOptions{
Timeout: timeout,
Services: services,

View File

@@ -25,6 +25,7 @@ import (
"text/tabwriter"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
@@ -34,7 +35,7 @@ type topOptions struct {
*ProjectOptions
}
func topCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func topCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := topOptions{
ProjectOptions: p,
}
@@ -42,7 +43,7 @@ func topCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *
Use: "top [SERVICES...]",
Short: "Display the running processes",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runTop(ctx, dockerCli, backend, opts, args)
return runTop(ctx, dockerCli, backendOptions, opts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -54,11 +55,16 @@ type (
topEntries map[string]string
)
func runTop(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts topOptions, services []string) error {
func runTop(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts topOptions, services []string) error {
projectName, err := opts.toProjectName(ctx, dockerCli)
if err != nil {
return err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
containers, err := backend.Top(ctx, projectName, services)
if err != nil {
return err

View File

@@ -26,6 +26,7 @@ import (
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/compose"
xprogress "github.com/moby/buildkit/util/progress/progressui"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -109,7 +110,7 @@ func (opts upOptions) OnExit() api.Cascade {
}
}
func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func upCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
up := upOptions{}
create := createOptions{}
build := buildOptions{ProjectOptions: p}
@@ -140,7 +141,7 @@ func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *c
return fmt.Errorf("no service selected")
}
return runUp(ctx, dockerCli, backend, create, up, build, project, services)
return runUp(ctx, dockerCli, backendOptions, create, up, build, project, services)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -228,7 +229,7 @@ func validateFlags(up *upOptions, create *createOptions) error {
func runUp(
ctx context.Context,
dockerCli command.Cli,
backend api.Compose,
backendOptions *BackendOptions,
createOptions createOptions,
upOptions upOptions,
buildOptions buildOptions,
@@ -280,6 +281,11 @@ func runUp(
AssumeYes: createOptions.AssumeYes,
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
if upOptions.noStart {
return backend.Create(ctx, project, create)
}

View File

@@ -24,6 +24,7 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -35,7 +36,7 @@ type vizOptions struct {
indentationStr string
}
func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func vizCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := vizOptions{
ProjectOptions: p,
}
@@ -51,7 +52,7 @@ func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *
return err
}),
RunE: Adapt(func(ctx context.Context, args []string) error {
return runViz(ctx, dockerCli, backend, &opts)
return runViz(ctx, dockerCli, backendOptions, &opts)
}),
}
@@ -63,7 +64,7 @@ func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *
return cmd
}
func runViz(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts *vizOptions) error {
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)
if err != nil {
@@ -71,6 +72,10 @@ func runViz(ctx context.Context, dockerCli command.Cli, backend api.Compose, opt
}
// 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,

View File

@@ -25,6 +25,7 @@ import (
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/flags"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -34,7 +35,7 @@ type volumesOptions struct {
Format string
}
func volumesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func volumesCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
options := volumesOptions{
ProjectOptions: p,
}
@@ -43,7 +44,7 @@ func volumesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compos
Use: "volumes [OPTIONS] [SERVICE...]",
Short: "List volumes",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runVol(ctx, dockerCli, backend, args, options)
return runVol(ctx, dockerCli, backendOptions, args, options)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -54,7 +55,7 @@ func volumesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compos
return cmd
}
func runVol(ctx context.Context, dockerCli command.Cli, backend api.Compose, services []string, options volumesOptions) error {
func runVol(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, services []string, options volumesOptions) error {
project, name, err := options.projectOrName(ctx, dockerCli, services...)
if err != nil {
return err
@@ -69,6 +70,10 @@ func runVol(ctx context.Context, dockerCli command.Cli, backend api.Compose, ser
}
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
volumes, err := backend.Volumes(ctx, name, api.VolumesOptions{
Services: services,
})

View File

@@ -23,6 +23,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/spf13/cobra"
)
@@ -34,7 +35,7 @@ type waitOptions struct {
downProject bool
}
func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func waitCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
opts := waitOptions{
ProjectOptions: p,
}
@@ -47,7 +48,7 @@ func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
Args: cli.RequiresMinArgs(1),
RunE: Adapt(func(ctx context.Context, services []string) error {
opts.services = services
statusCode, err = runWait(ctx, dockerCli, backend, &opts)
statusCode, err = runWait(ctx, dockerCli, backendOptions, &opts)
return err
}),
PostRun: func(cmd *cobra.Command, args []string) {
@@ -60,12 +61,16 @@ func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return cmd
}
func runWait(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts *waitOptions) (int64, error) {
func runWait(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, opts *waitOptions) (int64, error) {
_, name, err := opts.projectOrName(ctx, dockerCli)
if err != nil {
return 0, err
}
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return 0, err
}
return backend.Wait(ctx, name, api.WaitOptions{
Services: opts.services,
DownProjectOnContainerExit: opts.downProject,

View File

@@ -22,6 +22,7 @@ import (
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/compose/v2/cmd/formatter"
"github.com/docker/compose/v2/pkg/compose"
"github.com/docker/cli/cli/command"
"github.com/docker/compose/v2/internal/locker"
@@ -36,7 +37,7 @@ type watchOptions struct {
noUp bool
}
func watchCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
func watchCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {
watchOpts := watchOptions{
ProjectOptions: p,
}
@@ -53,7 +54,7 @@ func watchCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
if cmd.Parent().Name() == "alpha" {
logrus.Warn("watch command is now available as a top level command")
}
return runWatch(ctx, dockerCli, backend, watchOpts, buildOpts, args)
return runWatch(ctx, dockerCli, backendOptions, watchOpts, buildOpts, args)
}),
ValidArgsFunction: completeServiceNames(dockerCli, p),
}
@@ -64,7 +65,7 @@ func watchCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose)
return cmd
}
func runWatch(ctx context.Context, dockerCli command.Cli, backend api.Compose, watchOpts watchOptions, buildOpts buildOptions, services []string) error {
func runWatch(ctx context.Context, dockerCli command.Cli, backendOptions *BackendOptions, watchOpts watchOptions, buildOpts buildOptions, services []string) error {
project, _, err := watchOpts.ToProject(ctx, dockerCli, services)
if err != nil {
return err
@@ -111,12 +112,20 @@ func runWatch(ctx context.Context, dockerCli command.Cli, backend api.Compose, w
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
}
}
consumer := formatter.NewLogConsumer(ctx, dockerCli.Out(), dockerCli.Err(), false, false, false)
backend, err := compose.NewComposeService(dockerCli, backendOptions.Options...)
if err != nil {
return err
}
return backend.Watch(ctx, project, api.WatchOptions{
Build: &build,
LogTo: consumer,

View File

@@ -37,10 +37,13 @@ import (
func pluginMain() {
plugin.Run(
func(cli command.Cli) *cobra.Command {
backend := compose.NewComposeService(cli,
compose.WithPrompt(prompt.NewPrompt(cli.In(), cli.Out()).Confirm),
)
cmd := commands.RootCommand(cli, backend)
backendOptions := &commands.BackendOptions{
Options: []compose.Option{
compose.WithPrompt(prompt.NewPrompt(cli.In(), cli.Out()).Confirm),
},
}
cmd := commands.RootCommand(cli, backendOptions)
originalPreRunE := cmd.PersistentPreRunE
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
// initialize the cli instance