ソースを参照

Merge pull request #1773 from ulyssessouza/completion

Nicolas De loof 4 年 前
コミット
3d83989f5d

+ 11 - 10
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)
 	}

+ 1 - 0
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.")

+ 48 - 0
cmd/compose/completion.go

@@ -0,0 +1,48 @@
+/*
+   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 (
+	"strings"
+
+	"github.com/spf13/cobra"
+)
+
+// 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
+		}
+		var serviceNames []string
+		for _, s := range project.ServiceNames() {
+			if toComplete == "" || strings.HasPrefix(s, toComplete) {
+				serviceNames = append(serviceNames, s)
+			}
+		}
+		return serviceNames, cobra.ShellCompDirectiveNoFileComp
+	}
+}

+ 2 - 2
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()

+ 1 - 0
cmd/compose/convert.go

@@ -86,6 +86,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]")

+ 1 - 0
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()

+ 1 - 0
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.")

+ 1 - 0
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.")

+ 1 - 0
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")

+ 1 - 0
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.")

+ 1 - 0
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

+ 1 - 0
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()

+ 1 - 0
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.")

+ 2 - 1
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.")

+ 2 - 0
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
 }

+ 1 - 0
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")

+ 5 - 4
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,8 +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: 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")
@@ -85,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 {

+ 1 - 0
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")

+ 1 - 0
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")
 

+ 1 - 0
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")

+ 1 - 0
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")

+ 1 - 0
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")

+ 1 - 0
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
 }

+ 1 - 0
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")

+ 2 - 1
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
 }

+ 1 - 0
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")