diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 4acabd856..aa9d178d6 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -25,15 +25,14 @@ import ( "strings" "syscall" - "github.com/docker/compose/v2/cmd/formatter" - - "github.com/sirupsen/logrus" - "github.com/compose-spec/compose-go/cli" "github.com/compose-spec/compose-go/types" dockercli "github.com/docker/cli/cli" + "github.com/docker/cli/cli-plugins/manager" + "github.com/docker/compose/v2/cmd/formatter" "github.com/morikuni/aec" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -106,7 +105,7 @@ type ProjectFunc func(ctx context.Context, project *types.Project) error // ProjectServicesFunc does stuff within a types.Project and a selection of services type ProjectServicesFunc func(ctx context.Context, project *types.Project, services []string) error -// WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services +// WithProject creates a cobra run command from a ProjectFunc based on configured project options and selected services func (o *projectOptions) WithProject(fn ProjectFunc) func(cmd *cobra.Command, args []string) error { return o.WithServices(func(ctx context.Context, project *types.Project, services []string) error { return fn(ctx, project) @@ -209,6 +208,13 @@ func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.Proj cli.WithName(o.ProjectName))...) } +const pluginName = "compose" + +// RunningAsStandalone detects when running as a standalone program +func RunningAsStandalone() bool { + return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != pluginName +} + // RootCommand returns the compose command with its child commands func RootCommand(backend api.Service) *cobra.Command { opts := projectOptions{} @@ -217,9 +223,14 @@ func RootCommand(backend api.Service) *cobra.Command { noAnsi bool verbose bool ) + commandName := pluginName + if RunningAsStandalone() { + commandName = os.Args[0] + } + command := &cobra.Command{ Short: "Docker Compose", - Use: "compose", + Use: commandName, TraverseChildren: true, // By default (no Run/RunE in parent command) for typos in subcommands, cobra displays the help of parent command but exit(0) ! RunE: func(cmd *cobra.Command, args []string) error { @@ -234,11 +245,13 @@ func RootCommand(backend api.Service) *cobra.Command { }, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { parent := cmd.Root() - parentPrerun := parent.PersistentPreRunE - if parentPrerun != nil { - err := parentPrerun(cmd, args) - if err != nil { - return err + if parent != nil && parent.Name() != commandName { + parentPrerun := parent.PersistentPreRunE + if parentPrerun != nil { + err := parentPrerun(cmd, args) + if err != nil { + return err + } } } if noAnsi { diff --git a/cmd/main.go b/cmd/main.go index 00756fed2..35be9873f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,12 +17,16 @@ package main import ( + "fmt" + "os" + dockercli "github.com/docker/cli/cli" "github.com/docker/cli/cli-plugins/manager" "github.com/docker/cli/cli-plugins/plugin" "github.com/docker/cli/cli/command" "github.com/spf13/cobra" + cliFlags "github.com/docker/cli/cli/flags" commands "github.com/docker/compose/v2/cmd/compose" "github.com/docker/compose/v2/internal" "github.com/docker/compose/v2/pkg/api" @@ -34,7 +38,26 @@ func init() { "To provide feedback or request new features please open issues at https://github.com/docker/compose" } -func main() { +func standaloneMain() int { + dockerCli, err := command.NewDockerCli() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + return 1 + } + opts := cliFlags.NewClientOptions() + err = dockerCli.Initialize(opts) + if err != nil { + return 1 + } + lazyInit := api.NewServiceProxy().WithService(compose.NewComposeService(dockerCli.Client(), dockerCli.ConfigFile())) + rootCmd := commands.RootCommand(lazyInit) + if err := rootCmd.Execute(); err != nil { + return 1 + } + return 0 +} + +func pluginMain() { plugin.Run(func(dockerCli command.Cli) *cobra.Command { lazyInit := api.NewServiceProxy() cmd := commands.RootCommand(lazyInit) @@ -63,3 +86,10 @@ func main() { Version: internal.Version, }) } + +func main() { + if commands.RunningAsStandalone() { + os.Exit(standaloneMain()) + } + pluginMain() +} diff --git a/pkg/compose/compose.go b/pkg/compose/compose.go index 16bb53ae3..7c31218cd 100644 --- a/pkg/compose/compose.go +++ b/pkg/compose/compose.go @@ -32,6 +32,7 @@ import ( "github.com/sanathkr/go-yaml" ) +// Separator is used for naming components var Separator = "-" // NewComposeService create a local implementation of the compose.Service API