diff --git a/aci/compose.go b/aci/compose.go index 6d3f12c8a..c7f82aba8 100644 --- a/aci/compose.go +++ b/aci/compose.go @@ -211,6 +211,6 @@ func (cs *aciComposeService) RunOneOffContainer(ctx context.Context, project *ty return 0, errdefs.ErrNotImplemented } -func (cs *aciComposeService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) error { - return errdefs.ErrNotImplemented +func (cs *aciComposeService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) ([]string, error) { + return nil, errdefs.ErrNotImplemented } diff --git a/api/client/compose.go b/api/client/compose.go index 970008e89..063da2081 100644 --- a/api/client/compose.go +++ b/api/client/compose.go @@ -84,6 +84,6 @@ func (c *composeService) RunOneOffContainer(ctx context.Context, project *types. return 0, errdefs.ErrNotImplemented } -func (c *composeService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) error { - return errdefs.ErrNotImplemented +func (c *composeService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) ([]string, error) { + return nil, errdefs.ErrNotImplemented } diff --git a/api/compose/api.go b/api/compose/api.go index 6d1a9a6b9..65cbbbe7f 100644 --- a/api/compose/api.go +++ b/api/compose/api.go @@ -54,7 +54,7 @@ type Service interface { // RunOneOffContainer creates a service oneoff container and starts its dependencies RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (int, error) // Remove executes the equivalent to a `compose rm` - Remove(ctx context.Context, project *types.Project, options RemoveOptions) error + Remove(ctx context.Context, project *types.Project, options RemoveOptions) ([]string, error) } // CreateOptions group options of the Create API @@ -101,6 +101,8 @@ type KillOptions struct { // RemoveOptions group options of the Remove API type RemoveOptions struct { + // DryRun just list removable resources + DryRun bool // Volumes remove anonymous volumes Volumes bool // Force don't ask to confirm removal diff --git a/cli/cmd/compose/remove.go b/cli/cmd/compose/remove.go index ba796ce60..af5040136 100644 --- a/cli/cmd/compose/remove.go +++ b/cli/cmd/compose/remove.go @@ -18,10 +18,13 @@ package compose import ( "context" + "fmt" + "strings" "github.com/docker/compose-cli/api/client" "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/progress" + "github.com/docker/compose-cli/utils/prompt" "github.com/spf13/cobra" ) @@ -68,17 +71,46 @@ func runRemove(ctx context.Context, opts removeOptions, services []string) error return err } - _, err = progress.Run(ctx, func(ctx context.Context) (string, error) { - if opts.stop { + if opts.stop { + _, err = progress.Run(ctx, func(ctx context.Context) (string, error) { err := c.ComposeService().Stop(ctx, project) - if err != nil { - return "", err - } + return "", err + }) + if err != nil { + return err } - return "", c.ComposeService().Remove(ctx, project, compose.RemoveOptions{ + } + + reosurces, err := c.ComposeService().Remove(ctx, project, compose.RemoveOptions{ + DryRun: true, + }) + if err != nil { + return err + } + + if len(reosurces) == 0 { + fmt.Println("No stopped containers") + return nil + } + msg := fmt.Sprintf("Going to remove %s", strings.Join(reosurces, ", ")) + if opts.force { + fmt.Println(msg) + } else { + confirm, err := prompt.User{}.Confirm(msg, false) + if err != nil { + return err + } + if !confirm { + return nil + } + } + + _, err = progress.Run(ctx, func(ctx context.Context) (string, error) { + _, err = c.ComposeService().Remove(ctx, project, compose.RemoveOptions{ Volumes: opts.volumes, Force: opts.force, }) + return "", err }) return err } diff --git a/ecs/local/compose.go b/ecs/local/compose.go index 06cbbf1fd..1cd0c9b60 100644 --- a/ecs/local/compose.go +++ b/ecs/local/compose.go @@ -176,6 +176,6 @@ func (e ecsLocalSimulation) RunOneOffContainer(ctx context.Context, project *typ return 0, errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose run") } -func (e ecsLocalSimulation) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) error { +func (e ecsLocalSimulation) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) ([]string, error) { return e.compose.Remove(ctx, project, options) } diff --git a/ecs/run.go b/ecs/run.go index 8bd3a762f..597f80783 100644 --- a/ecs/run.go +++ b/ecs/run.go @@ -29,6 +29,6 @@ func (b *ecsAPIService) RunOneOffContainer(ctx context.Context, project *types.P return 0, errdefs.ErrNotImplemented } -func (b *ecsAPIService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) error { - return errdefs.ErrNotImplemented +func (b *ecsAPIService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) ([]string, error) { + return nil, errdefs.ErrNotImplemented } diff --git a/kube/compose.go b/kube/compose.go index 1b06e03e5..77f1eceea 100644 --- a/kube/compose.go +++ b/kube/compose.go @@ -198,6 +198,6 @@ func (s *composeService) RunOneOffContainer(ctx context.Context, project *types. return 0, errdefs.ErrNotImplemented } -func (s *composeService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) error { - return errdefs.ErrNotImplemented +func (s *composeService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) ([]string, error) { + return nil, errdefs.ErrNotImplemented } diff --git a/local/compose/compose.go b/local/compose/compose.go index cc9bed3b3..038ac615c 100644 --- a/local/compose/compose.go +++ b/local/compose/compose.go @@ -23,31 +23,27 @@ import ( "strings" "github.com/docker/compose-cli/api/compose" - "github.com/docker/compose-cli/utils/prompt" + "github.com/docker/compose-cli/api/errdefs" "github.com/compose-spec/compose-go/types" moby "github.com/docker/docker/api/types" "github.com/docker/docker/client" "github.com/sanathkr/go-yaml" - - errdefs2 "github.com/docker/compose-cli/api/errdefs" ) // NewComposeService create a local implementation of the compose.Service API func NewComposeService(apiClient client.APIClient) compose.Service { return &composeService{ apiClient: apiClient, - ui: prompt.User{}, } } type composeService struct { apiClient client.APIClient - ui prompt.UI } func (s *composeService) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error { - return errdefs2.ErrNotImplemented + return errdefs.ErrNotImplemented } func getCanonicalContainerName(c moby.Container) string { diff --git a/local/compose/remove.go b/local/compose/remove.go index c06fca78c..76444eeb6 100644 --- a/local/compose/remove.go +++ b/local/compose/remove.go @@ -18,22 +18,20 @@ package compose import ( "context" - "fmt" - "strings" - - "github.com/compose-spec/compose-go/types" - moby "github.com/docker/docker/api/types" - "golang.org/x/sync/errgroup" "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/progress" status "github.com/docker/compose-cli/local/moby" + + "github.com/compose-spec/compose-go/types" + moby "github.com/docker/docker/api/types" + "golang.org/x/sync/errgroup" ) -func (s *composeService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) error { +func (s *composeService) Remove(ctx context.Context, project *types.Project, options compose.RemoveOptions) ([]string, error) { containers, err := s.getContainers(ctx, project, oneOffInclude) if err != nil { - return err + return nil, err } stoppedContainers := containers.filter(func(c moby.Container) bool { @@ -45,21 +43,8 @@ func (s *composeService) Remove(ctx context.Context, project *types.Project, opt names = append(names, getCanonicalContainerName(c)) }) - if len(stoppedContainers) == 0 { - fmt.Println("No stopped containers") - return nil - } - msg := fmt.Sprintf("Going to remove %s", strings.Join(names, ", ")) - if options.Force { - fmt.Println(msg) - } else { - confirm, err := s.ui.Confirm(msg, false) - if err != nil { - return err - } - if !confirm { - return nil - } + if options.DryRun { + return names, nil } w := progress.ContextWriter(ctx) @@ -79,5 +64,5 @@ func (s *composeService) Remove(ctx context.Context, project *types.Project, opt return err }) } - return eg.Wait() + return nil, eg.Wait() }