From 3174f49dc250cc0dc083d78f10af0d1a31e91c0c Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Thu, 25 Feb 2021 19:38:11 -0300 Subject: [PATCH 1/4] Add completion to shells Signed-off-by: Ulysses Souza --- cli/cmd/compose/completion.go | 86 +++++++++++++++++++++++++++++++++++ cmd/compose/compose.go | 5 +- 2 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 cli/cmd/compose/completion.go diff --git a/cli/cmd/compose/completion.go b/cli/cmd/compose/completion.go new file mode 100644 index 00000000..4d6b5b92 --- /dev/null +++ b/cli/cmd/compose/completion.go @@ -0,0 +1,86 @@ +/* + 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 ( + "os" + + "github.com/spf13/cobra" +) + +func completionCommand() *cobra.Command { + return &cobra.Command{ + Use: "completion [bash|zsh|fish|powershell]", + Short: "Generate completion script", + Long: `To load completions: + +Bash: + + $ source <(docker compose completion bash) + + # To load completions for each session, execute once: + # Linux: + $ docker compose completion bash > /etc/bash_completion.d/docker_compose + # macOS: + $ docker compose completion bash > /usr/local/etc/bash_completion.d/docker_compose + +Zsh: + + # If shell completion is not already enabled in your environment, + # you will need to enable it. You can execute the following once: + + $ echo "autoload -U compinit; compinit" >> ~/.zshrc + + # To load completions for each session, execute once: + $ docker compose completion zsh > "${fpath[1]}/_docker_compose" + + # You will need to start a new shell for this setup to take effect. + +fish: + + $ docker compose completion fish | source + + # To load completions for each session, execute once: + $ docker compose completion fish > ~/.config/fish/completions/docker_compose.fish + +PowerShell: + + PS> docker compose completion powershell | Out-String | Invoke-Expression + + # To load completions for every new session, run: + PS> docker compose completion powershell > docker_compose.ps1 + # and source this file from your PowerShell profile. +`, + DisableFlagsInUseLine: true, + ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, + Args: cobra.ExactValidArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + var err error + switch args[0] { + case "bash": + err = cmd.Root().GenBashCompletion(os.Stdout) + case "zsh": + err = cmd.Root().GenZshCompletion(os.Stdout) + case "fish": + err = cmd.Root().GenFishCompletion(os.Stdout, true) + case "powershell": + err = cmd.Root().GenPowerShellCompletion(os.Stdout) + } + return err + }, + } +} diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index b2f4213f..6d292b81 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -41,10 +41,10 @@ import ( "github.com/docker/compose-cli/pkg/compose" ) -//Command defines a compose CLI command as a func with args +// Command defines a compose CLI command as a func with args type Command func(context.Context, []string) error -//Adapt a Command func to cobra library +// Adapt a Command func to cobra library func Adapt(fn Command) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() @@ -276,6 +276,7 @@ func RootCommand(contextType string, backend api.Service) *cobra.Command { portCommand(&opts, backend), imagesCommand(&opts, backend), versionCommand(), + completionCommand(), ) if contextType == store.LocalContextType || contextType == store.DefaultContextType { From 37961c51ca13d45c8869c6a889b13c0cc9e6b775 Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Wed, 9 Jun 2021 16:35:33 -0300 Subject: [PATCH 2/4] Add completion to "compose ps" Signed-off-by: Ulysses Souza --- cli/main.go | 21 +++++++++++---------- {cli/cmd => cmd}/compose/completion.go | 0 cmd/compose/compose.go | 3 +++ cmd/compose/ps.go | 11 +++++++++++ 4 files changed, 25 insertions(+), 10 deletions(-) rename {cli/cmd => cmd}/compose/completion.go (100%) diff --git a/cli/main.go b/cli/main.go index e98568d4..4a4dd2ca 100644 --- a/cli/main.go +++ b/cli/main.go @@ -68,6 +68,9 @@ var ( "serve": {}, "version": {}, "backend-metadata": {}, + // Special hidden commands used by cobra for completion + "__complete": {}, + "__completeNoDesc": {}, } unknownCommandRegexp = regexp.MustCompile(`unknown docker command: "([^"]*)"`) ) @@ -167,7 +170,7 @@ func main() { }) // populate the opts with the global flags - flags.Parse(os.Args[1:]) //nolint: errcheck + flags.Parse(os.Args[1:]) // nolint: errcheck level, err := logrus.ParseLevel(opts.LogLevel) if err != nil { @@ -223,18 +226,16 @@ func main() { volume.Command(ctype), ) - if ctype != store.DefaultContextType { - // On default context, "compose" is implemented by CLI Plugin - proxy := api.NewServiceProxy().WithService(service.ComposeService()) - command := compose2.RootCommand(ctype, proxy) + // On default context, "compose" is implemented by CLI Plugin + proxy := api.NewServiceProxy().WithService(service.ComposeService()) + command := compose2.RootCommand(ctype, proxy) - if ctype == store.AciContextType { - customizeCliForACI(command, proxy) - } - - root.AddCommand(command) + if ctype == store.AciContextType { + customizeCliForACI(command, proxy) } + root.AddCommand(command) + if err = root.ExecuteContext(ctx); err != nil { handleError(ctx, err, ctype, currentContext, cc, root) } diff --git a/cli/cmd/compose/completion.go b/cmd/compose/completion.go similarity index 100% rename from cli/cmd/compose/completion.go rename to cmd/compose/completion.go diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 6d292b81..c0404be2 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -44,6 +44,9 @@ import ( // Command defines a compose CLI command as a func with args type Command func(context.Context, []string) error +// ValidArgsFn defines a completion func to be returned to fetch completion options +type ValidArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) + // Adapt a Command func to cobra library func Adapt(fn Command) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { diff --git a/cmd/compose/ps.go b/cmd/compose/ps.go index 5249fcf2..e5310aad 100644 --- a/cmd/compose/ps.go +++ b/cmd/compose/ps.go @@ -76,6 +76,7 @@ func psCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runPs(ctx, backend, args, opts) }), + ValidArgsFunction: psCompletion(p), } flags := cmd.Flags() flags.StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json]") @@ -184,3 +185,13 @@ func filterByStatus(containers []api.ContainerSummary, status string) []api.Cont } return filtered } + +func psCompletion(p *projectOptions) ValidArgsFn { + return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + project, err := p.toProject(nil) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return project.ServiceNames(), cobra.ShellCompDirectiveNoFileComp + } +} From 72b66fb5c1976c111568e8eea8709402d82bd12f Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Thu, 10 Jun 2021 09:28:06 -0300 Subject: [PATCH 3/4] Add 'no completion' or 'service' completion Signed-off-by: Ulysses Souza --- cmd/compose/build.go | 1 + cmd/compose/completion.go | 20 ++++++++++++++++++++ cmd/compose/compose.go | 3 --- cmd/compose/convert.go | 1 + cmd/compose/cp.go | 1 + cmd/compose/create.go | 1 + cmd/compose/down.go | 1 + cmd/compose/events.go | 1 + cmd/compose/exec.go | 1 + cmd/compose/images.go | 1 + cmd/compose/kill.go | 1 + cmd/compose/list.go | 1 + cmd/compose/logs.go | 3 ++- cmd/compose/pause.go | 2 ++ cmd/compose/port.go | 1 + cmd/compose/ps.go | 12 ++++++------ cmd/compose/pull.go | 1 + cmd/compose/push.go | 1 + cmd/compose/remove.go | 1 + cmd/compose/restart.go | 1 + cmd/compose/run.go | 1 + cmd/compose/start.go | 1 + cmd/compose/stop.go | 1 + cmd/compose/top.go | 3 ++- cmd/compose/up.go | 1 + 25 files changed, 51 insertions(+), 11 deletions(-) diff --git a/cmd/compose/build.go b/cmd/compose/build.go index bd1a4119..aefe3d0f 100644 --- a/cmd/compose/build.go +++ b/cmd/compose/build.go @@ -61,6 +61,7 @@ func buildCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runBuild(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT") cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.") diff --git a/cmd/compose/completion.go b/cmd/compose/completion.go index 4d6b5b92..e3bd75ef 100644 --- a/cmd/compose/completion.go +++ b/cmd/compose/completion.go @@ -82,5 +82,25 @@ PowerShell: } return err }, + Hidden: true, + } +} + +// validArgsFn defines a completion func to be returned to fetch completion options +type validArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) + +func noCompletion() validArgsFn { + return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return nil, cobra.ShellCompDirectiveNoFileComp + } +} + +func serviceCompletion(p *projectOptions) validArgsFn { + return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + project, err := p.toProject(nil) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return project.ServiceNames(), cobra.ShellCompDirectiveNoFileComp } } diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index c0404be2..6d292b81 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -44,9 +44,6 @@ import ( // Command defines a compose CLI command as a func with args type Command func(context.Context, []string) error -// ValidArgsFn defines a completion func to be returned to fetch completion options -type ValidArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) - // Adapt a Command func to cobra library func Adapt(fn Command) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { diff --git a/cmd/compose/convert.go b/cmd/compose/convert.go index 8dd606aa..e7fedd1f 100644 --- a/cmd/compose/convert.go +++ b/cmd/compose/convert.go @@ -85,6 +85,7 @@ func convertCommand(p *projectOptions, backend api.Service) *cobra.Command { return runConvert(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } flags := cmd.Flags() flags.StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]") diff --git a/cmd/compose/cp.go b/cmd/compose/cp.go index 7a84209c..99f0952f 100644 --- a/cmd/compose/cp.go +++ b/cmd/compose/cp.go @@ -60,6 +60,7 @@ func copyCommand(p *projectOptions, backend api.Service) *cobra.Command { opts.destination = args[1] return runCopy(ctx, backend, opts) }), + ValidArgsFunction: serviceCompletion(p), } flags := copyCmd.Flags() diff --git a/cmd/compose/create.go b/cmd/compose/create.go index 04dd3125..77c3087c 100644 --- a/cmd/compose/create.go +++ b/cmd/compose/create.go @@ -64,6 +64,7 @@ func createCommand(p *projectOptions, backend api.Service) *cobra.Command { QuietPull: false, }) }), + ValidArgsFunction: serviceCompletion(p), } flags := cmd.Flags() flags.BoolVar(&opts.Build, "build", false, "Build images before starting containers.") diff --git a/cmd/compose/down.go b/cmd/compose/down.go index a4ca24a8..e851fb8c 100644 --- a/cmd/compose/down.go +++ b/cmd/compose/down.go @@ -57,6 +57,7 @@ func downCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runDown(ctx, backend, opts) }), + ValidArgsFunction: noCompletion(), } flags := downCmd.Flags() flags.BoolVar(&opts.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file.") diff --git a/cmd/compose/events.go b/cmd/compose/events.go index dec921e7..6f7368e9 100644 --- a/cmd/compose/events.go +++ b/cmd/compose/events.go @@ -43,6 +43,7 @@ func eventsCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runEvents(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } cmd.Flags().BoolVar(&opts.json, "json", false, "Output events as a stream of json objects") diff --git a/cmd/compose/exec.go b/cmd/compose/exec.go index ce6220f6..653a4441 100644 --- a/cmd/compose/exec.go +++ b/cmd/compose/exec.go @@ -61,6 +61,7 @@ func execCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runExec(ctx, backend, opts) }), + ValidArgsFunction: serviceCompletion(p), } runCmd.Flags().BoolVarP(&opts.detach, "detach", "d", false, "Detached mode: Run command in the background.") diff --git a/cmd/compose/images.go b/cmd/compose/images.go index ea77e912..4da71f7e 100644 --- a/cmd/compose/images.go +++ b/cmd/compose/images.go @@ -48,6 +48,7 @@ func imagesCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runImages(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } imgCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs") return imgCmd diff --git a/cmd/compose/kill.go b/cmd/compose/kill.go index 977cd88a..d4b33a11 100644 --- a/cmd/compose/kill.go +++ b/cmd/compose/kill.go @@ -33,6 +33,7 @@ func killCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: p.WithProject(func(ctx context.Context, project *types.Project) error { return backend.Kill(ctx, project, opts) }), + ValidArgsFunction: serviceCompletion(p), } flags := cmd.Flags() diff --git a/cmd/compose/list.go b/cmd/compose/list.go index 56ba30de..83b51ceb 100644 --- a/cmd/compose/list.go +++ b/cmd/compose/list.go @@ -46,6 +46,7 @@ func listCommand(contextType string, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runList(ctx, backend, opts) }), + ValidArgsFunction: noCompletion(), } lsCmd.Flags().StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json].") lsCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs.") diff --git a/cmd/compose/logs.go b/cmd/compose/logs.go index 44040fa5..88ee5d5b 100644 --- a/cmd/compose/logs.go +++ b/cmd/compose/logs.go @@ -44,11 +44,12 @@ func logsCommand(p *projectOptions, contextType string, backend api.Service) *co projectOptions: p, } logsCmd := &cobra.Command{ - Use: "logs [service...]", + Use: "logs [SERVICE...]", Short: "View output from containers", RunE: Adapt(func(ctx context.Context, args []string) error { return runLogs(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } flags := logsCmd.Flags() flags.BoolVarP(&opts.follow, "follow", "f", false, "Follow log output.") diff --git a/cmd/compose/pause.go b/cmd/compose/pause.go index 66ec751e..52c7fbb6 100644 --- a/cmd/compose/pause.go +++ b/cmd/compose/pause.go @@ -38,6 +38,7 @@ func pauseCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runPause(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } return cmd } @@ -67,6 +68,7 @@ func unpauseCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runUnPause(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } return cmd } diff --git a/cmd/compose/port.go b/cmd/compose/port.go index e1556d96..37ce0019 100644 --- a/cmd/compose/port.go +++ b/cmd/compose/port.go @@ -52,6 +52,7 @@ func portCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runPort(ctx, backend, opts, args[0]) }), + ValidArgsFunction: serviceCompletion(p), } cmd.Flags().StringVar(&opts.protocol, "protocol", "tcp", "tcp or udp") cmd.Flags().IntVar(&opts.index, "index", 1, "index of the container if service has multiple replicas") diff --git a/cmd/compose/ps.go b/cmd/compose/ps.go index e5310aad..70a99789 100644 --- a/cmd/compose/ps.go +++ b/cmd/compose/ps.go @@ -67,8 +67,8 @@ func psCommand(p *projectOptions, backend api.Service) *cobra.Command { opts := psOptions{ projectOptions: p, } - cmd := &cobra.Command{ - Use: "ps [options] [SERVICE...]", + psCmd := &cobra.Command{ + Use: "ps [SERVICE...]", Short: "List containers", PreRunE: func(cmd *cobra.Command, args []string) error { return opts.parseFilter() @@ -76,9 +76,9 @@ func psCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runPs(ctx, backend, args, opts) }), - ValidArgsFunction: psCompletion(p), + ValidArgsFunction: serviceCompletion(p), } - flags := cmd.Flags() + flags := psCmd.Flags() flags.StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json]") flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property") flags.StringVar(&opts.Status, "status", "", "Filter services by status") @@ -86,7 +86,7 @@ func psCommand(p *projectOptions, backend api.Service) *cobra.Command { flags.BoolVar(&opts.Services, "services", false, "Display services") flags.BoolVarP(&opts.All, "all", "a", false, "Show all stopped containers (including those created by the run command)") flags.Lookup("filter").Hidden = true - return cmd + return psCmd } func runPs(ctx context.Context, backend api.Service, services []string, opts psOptions) error { @@ -186,7 +186,7 @@ func filterByStatus(containers []api.ContainerSummary, status string) []api.Cont return filtered } -func psCompletion(p *projectOptions) ValidArgsFn { +func psCompletion(p *projectOptions) validArgsFn { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { project, err := p.toProject(nil) if err != nil { diff --git a/cmd/compose/pull.go b/cmd/compose/pull.go index 6d3417ca..c7213cc6 100644 --- a/cmd/compose/pull.go +++ b/cmd/compose/pull.go @@ -54,6 +54,7 @@ func pullCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runPull(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } flags := cmd.Flags() flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Pull without printing progress information") diff --git a/cmd/compose/push.go b/cmd/compose/push.go index 5632bb64..906578dd 100644 --- a/cmd/compose/push.go +++ b/cmd/compose/push.go @@ -41,6 +41,7 @@ func pushCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runPush(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } pushCmd.Flags().BoolVar(&opts.Ignorefailures, "ignore-push-failures", false, "Push what it can and ignores images with push failures") diff --git a/cmd/compose/remove.go b/cmd/compose/remove.go index a52b4f71..924cdab2 100644 --- a/cmd/compose/remove.go +++ b/cmd/compose/remove.go @@ -46,6 +46,7 @@ Any data which is not in a volume will be lost.`, RunE: Adapt(func(ctx context.Context, args []string) error { return runRemove(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } f := cmd.Flags() f.BoolVarP(&opts.force, "force", "f", false, "Don't ask to confirm removal") diff --git a/cmd/compose/restart.go b/cmd/compose/restart.go index 891c2f0b..8a022ed9 100644 --- a/cmd/compose/restart.go +++ b/cmd/compose/restart.go @@ -40,6 +40,7 @@ func restartCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runRestart(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } flags := restartCmd.Flags() flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds") diff --git a/cmd/compose/run.go b/cmd/compose/run.go index 0b79927a..cdaeeab0 100644 --- a/cmd/compose/run.go +++ b/cmd/compose/run.go @@ -126,6 +126,7 @@ func runCommand(p *projectOptions, backend api.Service) *cobra.Command { } return runRun(ctx, backend, project, opts) }), + ValidArgsFunction: serviceCompletion(p), } flags := cmd.Flags() flags.BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID") diff --git a/cmd/compose/start.go b/cmd/compose/start.go index 57e48f81..d3d46245 100644 --- a/cmd/compose/start.go +++ b/cmd/compose/start.go @@ -37,6 +37,7 @@ func startCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runStart(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } return startCmd } diff --git a/cmd/compose/stop.go b/cmd/compose/stop.go index d8a08c2f..81b90ad9 100644 --- a/cmd/compose/stop.go +++ b/cmd/compose/stop.go @@ -44,6 +44,7 @@ func stopCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runStop(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } flags := cmd.Flags() flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds") diff --git a/cmd/compose/top.go b/cmd/compose/top.go index ab81dd64..441deeaa 100644 --- a/cmd/compose/top.go +++ b/cmd/compose/top.go @@ -39,11 +39,12 @@ func topCommand(p *projectOptions, backend api.Service) *cobra.Command { projectOptions: p, } topCmd := &cobra.Command{ - Use: "top", + Use: "top [SERVICES...]", Short: "Display the running processes", RunE: Adapt(func(ctx context.Context, args []string) error { return runTop(ctx, backend, opts, args) }), + ValidArgsFunction: serviceCompletion(p), } return topCmd } diff --git a/cmd/compose/up.go b/cmd/compose/up.go index a1e7fcbf..4cdffa74 100644 --- a/cmd/compose/up.go +++ b/cmd/compose/up.go @@ -120,6 +120,7 @@ func upCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: p.WithServices(func(ctx context.Context, project *types.Project, services []string) error { return runUp(ctx, backend, create, up, project, services) }), + ValidArgsFunction: serviceCompletion(p), } flags := upCmd.Flags() flags.StringArrayVarP(&up.Environment, "environment", "e", []string{}, "Environment variables") From c28aec2308a24f589814cf4ac55a225d144f557d Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Tue, 22 Jun 2021 18:18:25 -0300 Subject: [PATCH 4/4] Filter completions by toComplete variable Signed-off-by: Ulysses Souza --- cmd/compose/completion.go | 74 +++++---------------------------------- cmd/compose/compose.go | 1 - cmd/compose/ps.go | 10 ------ 3 files changed, 8 insertions(+), 77 deletions(-) diff --git a/cmd/compose/completion.go b/cmd/compose/completion.go index e3bd75ef..891539b6 100644 --- a/cmd/compose/completion.go +++ b/cmd/compose/completion.go @@ -17,75 +17,11 @@ package compose import ( - "os" + "strings" "github.com/spf13/cobra" ) -func completionCommand() *cobra.Command { - return &cobra.Command{ - Use: "completion [bash|zsh|fish|powershell]", - Short: "Generate completion script", - Long: `To load completions: - -Bash: - - $ source <(docker compose completion bash) - - # To load completions for each session, execute once: - # Linux: - $ docker compose completion bash > /etc/bash_completion.d/docker_compose - # macOS: - $ docker compose completion bash > /usr/local/etc/bash_completion.d/docker_compose - -Zsh: - - # If shell completion is not already enabled in your environment, - # you will need to enable it. You can execute the following once: - - $ echo "autoload -U compinit; compinit" >> ~/.zshrc - - # To load completions for each session, execute once: - $ docker compose completion zsh > "${fpath[1]}/_docker_compose" - - # You will need to start a new shell for this setup to take effect. - -fish: - - $ docker compose completion fish | source - - # To load completions for each session, execute once: - $ docker compose completion fish > ~/.config/fish/completions/docker_compose.fish - -PowerShell: - - PS> docker compose completion powershell | Out-String | Invoke-Expression - - # To load completions for every new session, run: - PS> docker compose completion powershell > docker_compose.ps1 - # and source this file from your PowerShell profile. -`, - DisableFlagsInUseLine: true, - ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, - Args: cobra.ExactValidArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - var err error - switch args[0] { - case "bash": - err = cmd.Root().GenBashCompletion(os.Stdout) - case "zsh": - err = cmd.Root().GenZshCompletion(os.Stdout) - case "fish": - err = cmd.Root().GenFishCompletion(os.Stdout, true) - case "powershell": - err = cmd.Root().GenPowerShellCompletion(os.Stdout) - } - return err - }, - Hidden: true, - } -} - // validArgsFn defines a completion func to be returned to fetch completion options type validArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) @@ -101,6 +37,12 @@ func serviceCompletion(p *projectOptions) validArgsFn { if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } - return project.ServiceNames(), cobra.ShellCompDirectiveNoFileComp + var serviceNames []string + for _, s := range project.ServiceNames() { + if toComplete == "" || strings.HasPrefix(s, toComplete) { + serviceNames = append(serviceNames, s) + } + } + return serviceNames, cobra.ShellCompDirectiveNoFileComp } } diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 6d292b81..85fa4f7a 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -276,7 +276,6 @@ func RootCommand(contextType string, backend api.Service) *cobra.Command { portCommand(&opts, backend), imagesCommand(&opts, backend), versionCommand(), - completionCommand(), ) if contextType == store.LocalContextType || contextType == store.DefaultContextType { diff --git a/cmd/compose/ps.go b/cmd/compose/ps.go index 70a99789..9bb9a6e5 100644 --- a/cmd/compose/ps.go +++ b/cmd/compose/ps.go @@ -185,13 +185,3 @@ func filterByStatus(containers []api.ContainerSummary, status string) []api.Cont } return filtered } - -func psCompletion(p *projectOptions) validArgsFn { - return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - project, err := p.toProject(nil) - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return project.ServiceNames(), cobra.ShellCompDirectiveNoFileComp - } -}