Pārlūkot izejas kodu

pass compose.Service to cobra commands, dependency-injection style

Signed-off-by: Nicolas De Loof <[email protected]>
Nicolas De Loof 4 gadi atpakaļ
vecāks
revīzija
0bdad7e551

+ 4 - 10
cli/cmd/compose/build.go

@@ -24,7 +24,6 @@ import (
 	"github.com/compose-spec/compose-go/types"
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/progress"
 )
@@ -40,7 +39,7 @@ type buildOptions struct {
 	memory   string
 }
 
-func buildCommand(p *projectOptions) *cobra.Command {
+func buildCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := buildOptions{
 		projectOptions: p,
 	}
@@ -58,7 +57,7 @@ func buildCommand(p *projectOptions) *cobra.Command {
 				}
 				os.Stdout = devnull
 			}
-			return runBuild(cmd.Context(), opts, args)
+			return runBuild(cmd.Context(), backend, opts, args)
 		},
 	}
 	cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT")
@@ -80,19 +79,14 @@ func buildCommand(p *projectOptions) *cobra.Command {
 	return cmd
 }
 
-func runBuild(ctx context.Context, opts buildOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runBuild(ctx context.Context, backend compose.Service, opts buildOptions, services []string) error {
 	project, err := opts.toProject(services)
 	if err != nil {
 		return err
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().Build(ctx, project, compose.BuildOptions{
+		return "", backend.Build(ctx, project, compose.BuildOptions{
 			Pull:     opts.pull,
 			Progress: opts.progress,
 			Args:     types.NewMapping(opts.args),

+ 25 - 24
cli/cmd/compose/compose.go

@@ -28,6 +28,7 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 
+	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/context/store"
 	"github.com/docker/compose-cli/cli/formatter"
 	"github.com/docker/compose-cli/cli/metrics"
@@ -105,7 +106,7 @@ func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.Proj
 }
 
 // Command returns the compose command with its child commands
-func Command(contextType string) *cobra.Command {
+func Command(contextType string, backend compose.Service) *cobra.Command {
 	opts := projectOptions{}
 	var ansi string
 	var noAnsi bool
@@ -146,34 +147,34 @@ func Command(contextType string) *cobra.Command {
 	}
 
 	command.AddCommand(
-		upCommand(&opts, contextType),
-		downCommand(&opts, contextType),
-		startCommand(&opts),
-		restartCommand(&opts),
-		stopCommand(&opts),
-		psCommand(&opts),
-		listCommand(contextType),
-		logsCommand(&opts, contextType),
-		convertCommand(&opts),
-		killCommand(&opts),
-		runCommand(&opts),
-		removeCommand(&opts),
-		execCommand(&opts),
-		pauseCommand(&opts),
-		unpauseCommand(&opts),
-		topCommand(&opts),
-		eventsCommand(&opts),
-		portCommand(&opts),
-		imagesCommand(&opts),
+		upCommand(&opts, contextType, backend),
+		downCommand(&opts, contextType, backend),
+		startCommand(&opts, backend),
+		restartCommand(&opts, backend),
+		stopCommand(&opts, backend),
+		psCommand(&opts, backend),
+		listCommand(contextType, backend),
+		logsCommand(&opts, contextType, backend),
+		convertCommand(&opts, backend),
+		killCommand(&opts, backend),
+		runCommand(&opts, backend),
+		removeCommand(&opts, backend),
+		execCommand(&opts, backend),
+		pauseCommand(&opts, backend),
+		unpauseCommand(&opts, backend),
+		topCommand(&opts, backend),
+		eventsCommand(&opts, backend),
+		portCommand(&opts, backend),
+		imagesCommand(&opts, backend),
 		versionCommand(),
 	)
 
 	if contextType == store.LocalContextType || contextType == store.DefaultContextType {
 		command.AddCommand(
-			buildCommand(&opts),
-			pushCommand(&opts),
-			pullCommand(&opts),
-			createCommand(&opts),
+			buildCommand(&opts, backend),
+			pushCommand(&opts, backend),
+			pullCommand(&opts, backend),
+			createCommand(&opts, backend),
 		)
 	}
 	command.Flags().SetInterspersed(false)

+ 4 - 10
cli/cmd/compose/convert.go

@@ -31,7 +31,6 @@ import (
 	"github.com/opencontainers/go-digest"
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/config"
 	"github.com/docker/compose-cli/utils"
@@ -52,7 +51,7 @@ type convertOptions struct {
 
 var addFlagsFuncs []func(cmd *cobra.Command, opts *convertOptions)
 
-func convertCommand(p *projectOptions) *cobra.Command {
+func convertCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := convertOptions{
 		projectOptions: p,
 	}
@@ -81,7 +80,7 @@ func convertCommand(p *projectOptions) *cobra.Command {
 				return runProfiles(opts, args)
 			}
 
-			return runConvert(cmd.Context(), opts, args)
+			return runConvert(cmd.Context(), backend, opts, args)
 		},
 	}
 	flags := cmd.Flags()
@@ -102,13 +101,8 @@ func convertCommand(p *projectOptions) *cobra.Command {
 	return cmd
 }
 
-func runConvert(ctx context.Context, opts convertOptions, services []string) error {
+func runConvert(ctx context.Context, backend compose.Service, opts convertOptions, services []string) error {
 	var json []byte
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
 	project, err := opts.toProject(services, cli.WithInterpolation(!opts.noInterpolate))
 	if err != nil {
 		return err
@@ -130,7 +124,7 @@ func runConvert(ctx context.Context, opts convertOptions, services []string) err
 		}
 	}
 
-	json, err = c.ComposeService().Convert(ctx, project, compose.ConvertOptions{
+	json, err = backend.Convert(ctx, project, compose.ConvertOptions{
 		Format: opts.Format,
 		Output: opts.Output,
 	})

+ 4 - 2
cli/cmd/compose/create.go

@@ -20,6 +20,8 @@ import (
 	"fmt"
 
 	"github.com/spf13/cobra"
+
+	"github.com/docker/compose-cli/api/compose"
 )
 
 type createOptions struct {
@@ -28,7 +30,7 @@ type createOptions struct {
 	noRecreate    bool
 }
 
-func createCommand(p *projectOptions) *cobra.Command {
+func createCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := createOptions{
 		composeOptions: &composeOptions{},
 	}
@@ -42,7 +44,7 @@ func createCommand(p *projectOptions) *cobra.Command {
 			if opts.forceRecreate && opts.noRecreate {
 				return fmt.Errorf("--force-recreate and --no-recreate are incompatible")
 			}
-			return runCreateStart(cmd.Context(), upOptions{
+			return runCreateStart(cmd.Context(), backend, upOptions{
 				composeOptions: &composeOptions{
 					projectOptions: p,
 					Build:          opts.Build,

+ 5 - 11
cli/cmd/compose/down.go

@@ -24,7 +24,6 @@ import (
 	"github.com/compose-spec/compose-go/types"
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/context/store"
 	"github.com/docker/compose-cli/api/progress"
@@ -39,7 +38,7 @@ type downOptions struct {
 	images        string
 }
 
-func downCommand(p *projectOptions, contextType string) *cobra.Command {
+func downCommand(p *projectOptions, contextType string, backend compose.Service) *cobra.Command {
 	opts := downOptions{
 		projectOptions: p,
 	}
@@ -53,7 +52,7 @@ func downCommand(p *projectOptions, contextType string) *cobra.Command {
 					return fmt.Errorf("invalid value for --rmi: %q", opts.images)
 				}
 			}
-			return runDown(cmd.Context(), opts)
+			return runDown(cmd.Context(), backend, opts)
 		},
 	}
 	flags := downCmd.Flags()
@@ -68,13 +67,8 @@ func downCommand(p *projectOptions, contextType string) *cobra.Command {
 	return downCmd
 }
 
-func runDown(ctx context.Context, opts downOptions) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
-	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
+func runDown(ctx context.Context, backend compose.Service, opts downOptions) error {
+	_, err := progress.Run(ctx, func(ctx context.Context) (string, error) {
 		name := opts.ProjectName
 		var project *types.Project
 		if opts.ProjectName == "" {
@@ -91,7 +85,7 @@ func runDown(ctx context.Context, opts downOptions) error {
 			timeoutValue := time.Duration(opts.timeout) * time.Second
 			timeout = &timeoutValue
 		}
-		return name, c.ComposeService().Down(ctx, name, compose.DownOptions{
+		return name, backend.Down(ctx, name, compose.DownOptions{
 			RemoveOrphans: opts.removeOrphans,
 			Project:       project,
 			Timeout:       timeout,

+ 4 - 10
cli/cmd/compose/events.go

@@ -21,7 +21,6 @@ import (
 	"encoding/json"
 	"fmt"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 
 	"github.com/spf13/cobra"
@@ -32,7 +31,7 @@ type eventsOpts struct {
 	json bool
 }
 
-func eventsCommand(p *projectOptions) *cobra.Command {
+func eventsCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := eventsOpts{
 		composeOptions: &composeOptions{
 			projectOptions: p,
@@ -42,7 +41,7 @@ func eventsCommand(p *projectOptions) *cobra.Command {
 		Use:   "events [options] [--] [SERVICE...]",
 		Short: "Receive real time events from containers.",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runEvents(cmd.Context(), opts, args)
+			return runEvents(cmd.Context(), backend, opts, args)
 		},
 	}
 
@@ -50,18 +49,13 @@ func eventsCommand(p *projectOptions) *cobra.Command {
 	return cmd
 }
 
-func runEvents(ctx context.Context, opts eventsOpts, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runEvents(ctx context.Context, backend compose.Service, opts eventsOpts, services []string) error {
 	project, err := opts.toProjectName()
 	if err != nil {
 		return err
 	}
 
-	return c.ComposeService().Events(ctx, project, compose.EventsOptions{
+	return backend.Events(ctx, project, compose.EventsOptions{
 		Services: services,
 		Consumer: func(event compose.Event) error {
 			if opts.json {

+ 4 - 10
cli/cmd/compose/exec.go

@@ -24,7 +24,6 @@ import (
 	"github.com/containerd/console"
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 )
 
@@ -43,7 +42,7 @@ type execOpts struct {
 	privileged bool
 }
 
-func execCommand(p *projectOptions) *cobra.Command {
+func execCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := execOpts{
 		composeOptions: &composeOptions{
 			projectOptions: p,
@@ -58,7 +57,7 @@ func execCommand(p *projectOptions) *cobra.Command {
 				opts.command = args[1:]
 			}
 			opts.service = args[0]
-			return runExec(cmd.Context(), opts)
+			return runExec(cmd.Context(), backend, opts)
 		},
 	}
 
@@ -74,12 +73,7 @@ func execCommand(p *projectOptions) *cobra.Command {
 	return runCmd
 }
 
-func runExec(ctx context.Context, opts execOpts) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runExec(ctx context.Context, backend compose.Service, opts execOpts) error {
 	project, err := opts.toProject(nil)
 	if err != nil {
 		return err
@@ -114,5 +108,5 @@ func runExec(ctx context.Context, opts execOpts) error {
 		execOpts.Writer = con
 		execOpts.Reader = con
 	}
-	return c.ComposeService().Exec(ctx, project, execOpts)
+	return backend.Exec(ctx, project, execOpts)
 }

+ 4 - 10
cli/cmd/compose/images.go

@@ -26,7 +26,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/cli/formatter"
 	"github.com/docker/compose-cli/utils"
@@ -40,7 +39,7 @@ type imageOptions struct {
 	Quiet bool
 }
 
-func imagesCommand(p *projectOptions) *cobra.Command {
+func imagesCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := imageOptions{
 		projectOptions: p,
 	}
@@ -48,25 +47,20 @@ func imagesCommand(p *projectOptions) *cobra.Command {
 		Use:   "images [SERVICE...]",
 		Short: "List images used by the created containers",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runImages(cmd.Context(), opts, args)
+			return runImages(cmd.Context(), backend, opts, args)
 		},
 	}
 	imgCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
 	return imgCmd
 }
 
-func runImages(ctx context.Context, opts imageOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runImages(ctx context.Context, backend compose.Service, opts imageOptions, services []string) error {
 	projectName, err := opts.toProjectName()
 	if err != nil {
 		return err
 	}
 
-	images, err := c.ComposeService().Images(ctx, projectName, compose.ImagesOptions{
+	images, err := backend.Images(ctx, projectName, compose.ImagesOptions{
 		Services: services,
 	})
 	if err != nil {

+ 4 - 9
cli/cmd/compose/kill.go

@@ -21,7 +21,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 )
 
@@ -30,7 +29,7 @@ type killOptions struct {
 	Signal string
 }
 
-func killCommand(p *projectOptions) *cobra.Command {
+func killCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := killOptions{
 		projectOptions: p,
 	}
@@ -38,7 +37,7 @@ func killCommand(p *projectOptions) *cobra.Command {
 		Use:   "kill [options] [SERVICE...]",
 		Short: "Force stop service containers.",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runKill(cmd.Context(), opts, args)
+			return runKill(cmd.Context(), backend, opts, args)
 		},
 	}
 
@@ -48,16 +47,12 @@ func killCommand(p *projectOptions) *cobra.Command {
 	return cmd
 }
 
-func runKill(ctx context.Context, opts killOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
+func runKill(ctx context.Context, backend compose.Service, opts killOptions, services []string) error {
 	project, err := opts.toProject(services)
 	if err != nil {
 		return err
 	}
-	return c.ComposeService().Kill(ctx, project, compose.KillOptions{
+	return backend.Kill(ctx, project, compose.KillOptions{
 		Signal: opts.Signal,
 	})
 }

+ 4 - 9
cli/cmd/compose/list.go

@@ -26,7 +26,6 @@ import (
 	"github.com/docker/cli/opts"
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/context/store"
 	"github.com/docker/compose-cli/cli/formatter"
@@ -39,13 +38,13 @@ type lsOptions struct {
 	Filter opts.FilterOpt
 }
 
-func listCommand(contextType string) *cobra.Command {
+func listCommand(contextType string, backend compose.Service) *cobra.Command {
 	opts := lsOptions{Filter: opts.NewFilterOpt()}
 	lsCmd := &cobra.Command{
 		Use:   "ls",
 		Short: "List running compose projects",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runList(cmd.Context(), opts)
+			return runList(cmd.Context(), backend, opts)
 		},
 	}
 	lsCmd.Flags().StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json].")
@@ -62,18 +61,14 @@ var acceptedListFilters = map[string]bool{
 	"name": true,
 }
 
-func runList(ctx context.Context, opts lsOptions) error {
+func runList(ctx context.Context, backend compose.Service, opts lsOptions) error {
 	filters := opts.Filter.Value()
 	err := filters.Validate(acceptedListFilters)
 	if err != nil {
 		return err
 	}
 
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-	stackList, err := c.ComposeService().List(ctx, compose.ListOptions{All: opts.All})
+	stackList, err := backend.List(ctx, compose.ListOptions{All: opts.All})
 	if err != nil {
 		return err
 	}

+ 4 - 10
cli/cmd/compose/logs.go

@@ -22,7 +22,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/context/store"
 	"github.com/docker/compose-cli/cli/formatter"
@@ -38,7 +37,7 @@ type logsOptions struct {
 	timestamps bool
 }
 
-func logsCommand(p *projectOptions, contextType string) *cobra.Command {
+func logsCommand(p *projectOptions, contextType string, backend compose.Service) *cobra.Command {
 	opts := logsOptions{
 		projectOptions: p,
 	}
@@ -46,7 +45,7 @@ func logsCommand(p *projectOptions, contextType string) *cobra.Command {
 		Use:   "logs [service...]",
 		Short: "View output from containers",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runLogs(cmd.Context(), opts, args)
+			return runLogs(cmd.Context(), backend, opts, args)
 		},
 	}
 	flags := logsCmd.Flags()
@@ -61,18 +60,13 @@ func logsCommand(p *projectOptions, contextType string) *cobra.Command {
 	return logsCmd
 }
 
-func runLogs(ctx context.Context, opts logsOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runLogs(ctx context.Context, backend compose.Service, opts logsOptions, services []string) error {
 	projectName, err := opts.toProjectName()
 	if err != nil {
 		return err
 	}
 	consumer := formatter.NewLogConsumer(ctx, os.Stdout, !opts.noColor, !opts.noPrefix)
-	return c.ComposeService().Logs(ctx, projectName, consumer, compose.LogOptions{
+	return backend.Logs(ctx, projectName, consumer, compose.LogOptions{
 		Services:   services,
 		Follow:     opts.follow,
 		Tail:       opts.tail,

+ 8 - 19
cli/cmd/compose/pause.go

@@ -21,7 +21,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/progress"
 )
@@ -30,7 +29,7 @@ type pauseOptions struct {
 	*projectOptions
 }
 
-func pauseCommand(p *projectOptions) *cobra.Command {
+func pauseCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := pauseOptions{
 		projectOptions: p,
 	}
@@ -38,25 +37,20 @@ func pauseCommand(p *projectOptions) *cobra.Command {
 		Use:   "pause [SERVICE...]",
 		Short: "pause services",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runPause(cmd.Context(), opts, args)
+			return runPause(cmd.Context(), backend, opts, args)
 		},
 	}
 	return cmd
 }
 
-func runPause(ctx context.Context, opts pauseOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runPause(ctx context.Context, backend compose.Service, opts pauseOptions, services []string) error {
 	project, err := opts.toProjectName()
 	if err != nil {
 		return err
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().Pause(ctx, project, compose.PauseOptions{
+		return "", backend.Pause(ctx, project, compose.PauseOptions{
 			Services: services,
 		})
 	})
@@ -67,7 +61,7 @@ type unpauseOptions struct {
 	*projectOptions
 }
 
-func unpauseCommand(p *projectOptions) *cobra.Command {
+func unpauseCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := unpauseOptions{
 		projectOptions: p,
 	}
@@ -75,25 +69,20 @@ func unpauseCommand(p *projectOptions) *cobra.Command {
 		Use:   "unpause [SERVICE...]",
 		Short: "unpause services",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runUnPause(cmd.Context(), opts, args)
+			return runUnPause(cmd.Context(), backend, opts, args)
 		},
 	}
 	return cmd
 }
 
-func runUnPause(ctx context.Context, opts unpauseOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runUnPause(ctx context.Context, backend compose.Service, opts unpauseOptions, services []string) error {
 	project, err := opts.toProjectName()
 	if err != nil {
 		return err
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().UnPause(ctx, project, compose.PauseOptions{
+		return "", backend.UnPause(ctx, project, compose.PauseOptions{
 			Services: services,
 		})
 	})

+ 4 - 10
cli/cmd/compose/port.go

@@ -23,7 +23,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 )
 
@@ -33,7 +32,7 @@ type portOptions struct {
 	index    int
 }
 
-func portCommand(p *projectOptions) *cobra.Command {
+func portCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := portOptions{
 		projectOptions: p,
 	}
@@ -46,7 +45,7 @@ func portCommand(p *projectOptions) *cobra.Command {
 			if err != nil {
 				return err
 			}
-			return runPort(cmd.Context(), opts, args[0], port)
+			return runPort(cmd.Context(), backend, opts, args[0], port)
 		},
 	}
 	cmd.Flags().StringVar(&opts.protocol, "protocol", "tcp", "tcp or udp")
@@ -54,17 +53,12 @@ func portCommand(p *projectOptions) *cobra.Command {
 	return cmd
 }
 
-func runPort(ctx context.Context, opts portOptions, service string, port int) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runPort(ctx context.Context, backend compose.Service, opts portOptions, service string, port int) error {
 	projectName, err := opts.toProjectName()
 	if err != nil {
 		return err
 	}
-	ip, port, err := c.ComposeService().Port(ctx, projectName, service, port, compose.PortOptions{
+	ip, port, err := backend.Port(ctx, projectName, service, port, compose.PortOptions{
 		Protocol: opts.protocol,
 		Index:    opts.index,
 	})

+ 4 - 10
cli/cmd/compose/ps.go

@@ -26,7 +26,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/cli/formatter"
 	"github.com/docker/compose-cli/utils"
@@ -40,7 +39,7 @@ type psOptions struct {
 	Services bool
 }
 
-func psCommand(p *projectOptions) *cobra.Command {
+func psCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := psOptions{
 		projectOptions: p,
 	}
@@ -48,7 +47,7 @@ func psCommand(p *projectOptions) *cobra.Command {
 		Use:   "ps",
 		Short: "List containers",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runPs(cmd.Context(), opts)
+			return runPs(cmd.Context(), backend, opts)
 		},
 	}
 	psCmd.Flags().StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json].")
@@ -58,17 +57,12 @@ func psCommand(p *projectOptions) *cobra.Command {
 	return psCmd
 }
 
-func runPs(ctx context.Context, opts psOptions) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runPs(ctx context.Context, backend compose.Service, opts psOptions) error {
 	projectName, err := opts.toProjectName()
 	if err != nil {
 		return err
 	}
-	containers, err := c.ComposeService().Ps(ctx, projectName, compose.PsOptions{
+	containers, err := backend.Ps(ctx, projectName, compose.PsOptions{
 		All: opts.All,
 	})
 	if err != nil {

+ 5 - 11
cli/cmd/compose/pull.go

@@ -24,7 +24,6 @@ import (
 	"github.com/morikuni/aec"
 	"github.com/spf13/cobra"
 
-	"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"
@@ -40,7 +39,7 @@ type pullOptions struct {
 	ignorePullFailures bool
 }
 
-func pullCommand(p *projectOptions) *cobra.Command {
+func pullCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := pullOptions{
 		projectOptions: p,
 	}
@@ -51,7 +50,7 @@ func pullCommand(p *projectOptions) *cobra.Command {
 			if opts.noParallel {
 				fmt.Fprint(os.Stderr, aec.Apply("option '--no-parallel' is DEPRECATED and will be ignored.\n", aec.RedF))
 			}
-			return runPull(cmd.Context(), opts, args)
+			return runPull(cmd.Context(), backend, opts, args)
 		},
 	}
 	flags := cmd.Flags()
@@ -65,12 +64,7 @@ func pullCommand(p *projectOptions) *cobra.Command {
 	return cmd
 }
 
-func runPull(ctx context.Context, opts pullOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runPull(ctx context.Context, backend compose.Service, opts pullOptions, services []string) error {
 	project, err := opts.toProject(services)
 	if err != nil {
 		return err
@@ -94,11 +88,11 @@ func runPull(ctx context.Context, opts pullOptions, services []string) error {
 	}
 
 	if opts.quiet {
-		return c.ComposeService().Pull(ctx, project, apiOpts)
+		return backend.Pull(ctx, project, apiOpts)
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().Pull(ctx, project, apiOpts)
+		return "", backend.Pull(ctx, project, apiOpts)
 	})
 	return err
 }

+ 4 - 10
cli/cmd/compose/push.go

@@ -21,7 +21,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/progress"
 )
@@ -33,7 +32,7 @@ type pushOptions struct {
 	Ignorefailures bool
 }
 
-func pushCommand(p *projectOptions) *cobra.Command {
+func pushCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := pushOptions{
 		projectOptions: p,
 	}
@@ -41,7 +40,7 @@ func pushCommand(p *projectOptions) *cobra.Command {
 		Use:   "push [SERVICE...]",
 		Short: "Push service images",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runPush(cmd.Context(), opts, args)
+			return runPush(cmd.Context(), backend, opts, args)
 		},
 	}
 	pushCmd.Flags().BoolVar(&opts.Ignorefailures, "ignore-push-failures", false, "Push what it can and ignores images with push failures")
@@ -49,19 +48,14 @@ func pushCommand(p *projectOptions) *cobra.Command {
 	return pushCmd
 }
 
-func runPush(ctx context.Context, opts pushOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runPush(ctx context.Context, backend compose.Service, opts pushOptions, services []string) error {
 	project, err := opts.toProject(services)
 	if err != nil {
 		return err
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().Push(ctx, project, compose.PushOptions{
+		return "", backend.Push(ctx, project, compose.PushOptions{
 			IgnoreFailures: opts.Ignorefailures,
 		})
 	})

+ 7 - 13
cli/cmd/compose/remove.go

@@ -21,7 +21,6 @@ import (
 	"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"
@@ -36,7 +35,7 @@ type removeOptions struct {
 	volumes bool
 }
 
-func removeCommand(p *projectOptions) *cobra.Command {
+func removeCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := removeOptions{
 		projectOptions: p,
 	}
@@ -50,7 +49,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: func(cmd *cobra.Command, args []string) error {
-			return runRemove(cmd.Context(), opts, args)
+			return runRemove(cmd.Context(), backend, opts, args)
 		},
 	}
 	f := cmd.Flags()
@@ -60,12 +59,7 @@ Any data which is not in a volume will be lost.`,
 	return cmd
 }
 
-func runRemove(ctx context.Context, opts removeOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runRemove(ctx context.Context, backend compose.Service, opts removeOptions, services []string) error {
 	project, err := opts.toProject(services)
 	if err != nil {
 		return err
@@ -73,7 +67,7 @@ func runRemove(ctx context.Context, opts removeOptions, services []string) error
 
 	if opts.stop {
 		_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-			err := c.ComposeService().Stop(ctx, project, compose.StopOptions{
+			err := backend.Stop(ctx, project, compose.StopOptions{
 				Services: services,
 			})
 			return "", err
@@ -83,8 +77,8 @@ func runRemove(ctx context.Context, opts removeOptions, services []string) error
 		}
 	}
 
-	reosurces, err := c.ComposeService().Remove(ctx, project, compose.RemoveOptions{
-		DryRun:   true,
+	reosurces, err := backend.Remove(ctx, project, compose.RemoveOptions{
+		DryRun: true,
 		Services: services,
 	})
 	if err != nil {
@@ -109,7 +103,7 @@ func runRemove(ctx context.Context, opts removeOptions, services []string) error
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		_, err = c.ComposeService().Remove(ctx, project, compose.RemoveOptions{
+		_, err = backend.Remove(ctx, project, compose.RemoveOptions{
 			Volumes: opts.volumes,
 			Force:   opts.force,
 		})

+ 4 - 10
cli/cmd/compose/restart.go

@@ -22,7 +22,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/progress"
 )
@@ -32,7 +31,7 @@ type restartOptions struct {
 	timeout int
 }
 
-func restartCommand(p *projectOptions) *cobra.Command {
+func restartCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := restartOptions{
 		projectOptions: p,
 	}
@@ -40,7 +39,7 @@ func restartCommand(p *projectOptions) *cobra.Command {
 		Use:   "restart",
 		Short: "Restart containers",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runRestart(cmd.Context(), opts, args)
+			return runRestart(cmd.Context(), backend, opts, args)
 		},
 	}
 	flags := restartCmd.Flags()
@@ -49,12 +48,7 @@ func restartCommand(p *projectOptions) *cobra.Command {
 	return restartCmd
 }
 
-func runRestart(ctx context.Context, opts restartOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runRestart(ctx context.Context, backend compose.Service, opts restartOptions, services []string) error {
 	project, err := opts.toProject(services)
 	if err != nil {
 		return err
@@ -62,7 +56,7 @@ func runRestart(ctx context.Context, opts restartOptions, services []string) err
 
 	timeout := time.Duration(opts.timeout) * time.Second
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().Restart(ctx, project, compose.RestartOptions{
+		return "", backend.Restart(ctx, project, compose.RestartOptions{
 			Timeout: &timeout,
 		})
 	})

+ 9 - 10
cli/cmd/compose/run.go

@@ -28,7 +28,6 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/docker/cli/cli"
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/progress"
 )
@@ -100,7 +99,7 @@ func (opts runOptions) apply(project *types.Project) error {
 	return nil
 }
 
-func runCommand(p *projectOptions) *cobra.Command {
+func runCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := runOptions{
 		composeOptions: &composeOptions{
 			projectOptions: p,
@@ -118,7 +117,7 @@ func runCommand(p *projectOptions) *cobra.Command {
 			if len(opts.publish) > 0 && opts.servicePorts {
 				return fmt.Errorf("--service-ports and --publish are incompatible")
 			}
-			return runRun(cmd.Context(), opts)
+			return runRun(cmd.Context(), backend, opts)
 		},
 	}
 	flags := cmd.Flags()
@@ -141,8 +140,8 @@ func runCommand(p *projectOptions) *cobra.Command {
 	return cmd
 }
 
-func runRun(ctx context.Context, opts runOptions) error {
-	c, project, err := setup(ctx, *opts.composeOptions, []string{opts.Service})
+func runRun(ctx context.Context, backend compose.Service, opts runOptions) error {
+	project, err := setup(*opts.composeOptions, []string{opts.Service})
 	if err != nil {
 		return err
 	}
@@ -153,7 +152,7 @@ func runRun(ctx context.Context, opts runOptions) error {
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", startDependencies(ctx, c, *project, opts.Service)
+		return "", startDependencies(ctx, backend, *project, opts.Service)
 	})
 	if err != nil {
 		return err
@@ -194,7 +193,7 @@ func runRun(ctx context.Context, opts runOptions) error {
 		UseNetworkAliases: opts.useAliases,
 		Index:             0,
 	}
-	exitCode, err := c.ComposeService().RunOneOffContainer(ctx, project, runOpts)
+	exitCode, err := backend.RunOneOffContainer(ctx, project, runOpts)
 	if exitCode != 0 {
 		errMsg := ""
 		if err != nil {
@@ -205,7 +204,7 @@ func runRun(ctx context.Context, opts runOptions) error {
 	return err
 }
 
-func startDependencies(ctx context.Context, c *client.Client, project types.Project, requestedServiceName string) error {
+func startDependencies(ctx context.Context, backend compose.Service, project types.Project, requestedServiceName string) error {
 	dependencies := types.Services{}
 	var requestedService types.ServiceConfig
 	for _, service := range project.Services {
@@ -218,10 +217,10 @@ func startDependencies(ctx context.Context, c *client.Client, project types.Proj
 
 	project.Services = dependencies
 	project.DisabledServices = append(project.DisabledServices, requestedService)
-	if err := c.ComposeService().Create(ctx, &project, compose.CreateOptions{}); err != nil {
+	if err := backend.Create(ctx, &project, compose.CreateOptions{}); err != nil {
 		return err
 	}
-	if err := c.ComposeService().Start(ctx, &project, compose.StartOptions{}); err != nil {
+	if err := backend.Start(ctx, &project, compose.StartOptions{}); err != nil {
 		return err
 	}
 	return nil

+ 4 - 10
cli/cmd/compose/start.go

@@ -19,7 +19,6 @@ package compose
 import (
 	"context"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/progress"
 
@@ -30,7 +29,7 @@ type startOptions struct {
 	*projectOptions
 }
 
-func startCommand(p *projectOptions) *cobra.Command {
+func startCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := startOptions{
 		projectOptions: p,
 	}
@@ -38,25 +37,20 @@ func startCommand(p *projectOptions) *cobra.Command {
 		Use:   "start [SERVICE...]",
 		Short: "Start services",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runStart(cmd.Context(), opts, args)
+			return runStart(cmd.Context(), backend, opts, args)
 		},
 	}
 	return startCmd
 }
 
-func runStart(ctx context.Context, opts startOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runStart(ctx context.Context, backend compose.Service, opts startOptions, services []string) error {
 	project, err := opts.toProject(services)
 	if err != nil {
 		return err
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().Start(ctx, project, compose.StartOptions{})
+		return "", backend.Start(ctx, project, compose.StartOptions{})
 	})
 	return err
 }

+ 5 - 11
cli/cmd/compose/stop.go

@@ -22,7 +22,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/progress"
 )
@@ -33,7 +32,7 @@ type stopOptions struct {
 	timeout     int
 }
 
-func stopCommand(p *projectOptions) *cobra.Command {
+func stopCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := stopOptions{
 		projectOptions: p,
 	}
@@ -42,7 +41,7 @@ func stopCommand(p *projectOptions) *cobra.Command {
 		Short: "Stop services",
 		RunE: func(cmd *cobra.Command, args []string) error {
 			opts.timeChanged = cmd.Flags().Changed("timeout")
-			return runStop(cmd.Context(), opts, args)
+			return runStop(cmd.Context(), backend, opts, args)
 		},
 	}
 	flags := cmd.Flags()
@@ -51,12 +50,7 @@ func stopCommand(p *projectOptions) *cobra.Command {
 	return cmd
 }
 
-func runStop(ctx context.Context, opts stopOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
-
+func runStop(ctx context.Context, backend compose.Service, opts stopOptions, services []string) error {
 	project, err := opts.toProject(services)
 	if err != nil {
 		return err
@@ -68,8 +62,8 @@ func runStop(ctx context.Context, opts stopOptions, services []string) error {
 		timeout = &timeoutValue
 	}
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().Stop(ctx, project, compose.StopOptions{
-			Timeout:  timeout,
+		return "", backend.Stop(ctx, project, compose.StopOptions{
+			Timeout: timeout,
 			Services: services,
 		})
 	})

+ 5 - 9
cli/cmd/compose/top.go

@@ -27,14 +27,14 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/docker/compose-cli/api/client"
+	"github.com/docker/compose-cli/api/compose"
 )
 
 type topOptions struct {
 	*projectOptions
 }
 
-func topCommand(p *projectOptions) *cobra.Command {
+func topCommand(p *projectOptions, backend compose.Service) *cobra.Command {
 	opts := topOptions{
 		projectOptions: p,
 	}
@@ -42,22 +42,18 @@ func topCommand(p *projectOptions) *cobra.Command {
 		Use:   "top",
 		Short: "Display the running processes",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return runTop(cmd.Context(), opts, args)
+			return runTop(cmd.Context(), backend, opts, args)
 		},
 	}
 	return topCmd
 }
 
-func runTop(ctx context.Context, opts topOptions, services []string) error {
-	c, err := client.New(ctx)
-	if err != nil {
-		return err
-	}
+func runTop(ctx context.Context, backend compose.Service, opts topOptions, services []string) error {
 	projectName, err := opts.toProjectName()
 	if err != nil {
 		return err
 	}
-	containers, err := c.ComposeService().Top(ctx, projectName, services)
+	containers, err := backend.Top(ctx, projectName, services)
 	if err != nil {
 		return err
 	}

+ 16 - 22
cli/cmd/compose/up.go

@@ -33,7 +33,6 @@ import (
 	"github.com/spf13/cobra"
 	"golang.org/x/sync/errgroup"
 
-	"github.com/docker/compose-cli/api/client"
 	"github.com/docker/compose-cli/api/compose"
 	"github.com/docker/compose-cli/api/context/store"
 	"github.com/docker/compose-cli/api/progress"
@@ -140,7 +139,7 @@ func (opts upOptions) apply(project *types.Project, services []string) error {
 	return nil
 }
 
-func upCommand(p *projectOptions, contextType string) *cobra.Command {
+func upCommand(p *projectOptions, contextType string, backend compose.Service) *cobra.Command {
 	opts := upOptions{
 		composeOptions: &composeOptions{
 			projectOptions: p,
@@ -168,9 +167,9 @@ func upCommand(p *projectOptions, contextType string) *cobra.Command {
 				if opts.recreateDeps && opts.noRecreate {
 					return fmt.Errorf("--always-recreate-deps and --no-recreate are incompatible")
 				}
-				return runCreateStart(cmd.Context(), opts, args)
+				return runCreateStart(cmd.Context(), backend, opts, args)
 			default:
-				return runUp(cmd.Context(), opts, args)
+				return runUp(cmd.Context(), backend, opts, args)
 			}
 		},
 	}
@@ -204,8 +203,8 @@ func upCommand(p *projectOptions, contextType string) *cobra.Command {
 	return upCmd
 }
 
-func runUp(ctx context.Context, opts upOptions, services []string) error {
-	c, project, err := setup(ctx, *opts.composeOptions, services)
+func runUp(ctx context.Context, backend compose.Service, opts upOptions, services []string) error {
+	project, err := setup(*opts.composeOptions, services)
 	if err != nil {
 		return err
 	}
@@ -216,7 +215,7 @@ func runUp(ctx context.Context, opts upOptions, services []string) error {
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		return "", c.ComposeService().Up(ctx, project, compose.UpOptions{
+		return "", backend.Up(ctx, project, compose.UpOptions{
 			Detach:    opts.Detach,
 			QuietPull: opts.quietPull,
 		})
@@ -224,8 +223,8 @@ func runUp(ctx context.Context, opts upOptions, services []string) error {
 	return err
 }
 
-func runCreateStart(ctx context.Context, opts upOptions, services []string) error {
-	c, project, err := setup(ctx, *opts.composeOptions, services)
+func runCreateStart(ctx context.Context, backend compose.Service, opts upOptions, services []string) error {
+	project, err := setup(*opts.composeOptions, services)
 	if err != nil {
 		return err
 	}
@@ -240,7 +239,7 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 	}
 
 	_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
-		err := c.ComposeService().Create(ctx, project, compose.CreateOptions{
+		err := backend.Create(ctx, project, compose.CreateOptions{
 			Services:             services,
 			RemoveOrphans:        opts.removeOrphans,
 			Recreate:             opts.recreateStrategy(),
@@ -253,7 +252,7 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 			return "", err
 		}
 		if opts.Detach {
-			err = c.ComposeService().Start(ctx, project, compose.StartOptions{})
+			err = backend.Start(ctx, project, compose.StartOptions{})
 		}
 		return "", err
 	})
@@ -285,10 +284,10 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 		_, err := progress.Run(ctx, func(ctx context.Context) (string, error) {
 			go func() {
 				<-signalChan
-				c.ComposeService().Kill(ctx, project, compose.KillOptions{}) // nolint:errcheck
+				backend.Kill(ctx, project, compose.KillOptions{}) // nolint:errcheck
 			}()
 
-			return "", c.ComposeService().Stop(ctx, project, compose.StopOptions{})
+			return "", backend.Stop(ctx, project, compose.StopOptions{})
 		})
 		return err
 	}
@@ -311,7 +310,7 @@ func runCreateStart(ctx context.Context, opts upOptions, services []string) erro
 		return err
 	})
 
-	err = c.ComposeService().Start(ctx, project, compose.StartOptions{
+	err = backend.Start(ctx, project, compose.StartOptions{
 		Attach: func(event compose.ContainerEvent) {
 			queue <- event
 		},
@@ -351,15 +350,10 @@ func setServiceScale(project *types.Project, name string, replicas int) error {
 	return fmt.Errorf("unknown service %q", name)
 }
 
-func setup(ctx context.Context, opts composeOptions, services []string) (*client.Client, *types.Project, error) {
-	c, err := client.New(ctx)
-	if err != nil {
-		return nil, nil, err
-	}
-
+func setup(opts composeOptions, services []string) (*types.Project, error) {
 	project, err := opts.toProject(services)
 	if err != nil {
-		return nil, nil, err
+		return nil, err
 	}
 
 	if opts.DomainName != "" {
@@ -397,7 +391,7 @@ func setup(ctx context.Context, opts composeOptions, services []string) (*client
 		project.Services = services
 	}
 
-	return c, project, nil
+	return project, nil
 }
 
 type printer struct {

+ 1 - 1
cli/main.go

@@ -221,7 +221,7 @@ func main() {
 
 	root.AddCommand(
 		run.Command(ctype),
-		compose.Command(ctype),
+		compose.Command(ctype, service.ComposeService()),
 		volume.Command(ctype),
 	)
 

+ 1 - 1
docs/yaml/main/generate.go

@@ -35,7 +35,7 @@ const descriptionSourcePath = "docs/reference/"
 
 func generateCliYaml(opts *options) error {
 	cmd := &cobra.Command{Use: "docker"}
-	cmd.AddCommand(compose.Command("local"))
+	cmd.AddCommand(compose.Command("local", nil))
 	disableFlagsInUseLine(cmd)
 	source := filepath.Join(opts.source, descriptionSourcePath)
 	if err := loadLongDescription(cmd, source); err != nil {