Adopt Cobra completion v2 to support completion by CLI plugins

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2022-03-30 15:27:25 +02:00 committed by Sebastiaan van Stijn
parent 2b4ffb301b
commit cbec75e2f3
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
93 changed files with 538 additions and 61 deletions

View File

@ -1,6 +1,9 @@
package manager
import (
"fmt"
"os"
"github.com/docker/cli/cli/command"
"github.com/spf13/cobra"
)
@ -31,12 +34,13 @@ const (
// AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid
// plugin. The command stubs will have several annotations added, see
// `CommandAnnotationPlugin*`.
func AddPluginCommandStubs(dockerCli command.Cli, cmd *cobra.Command) error {
plugins, err := ListPlugins(dockerCli, cmd)
func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) error {
plugins, err := ListPlugins(dockerCli, rootCmd)
if err != nil {
return err
}
for _, p := range plugins {
p := p
vendor := p.Vendor
if vendor == "" {
vendor = "unknown"
@ -49,11 +53,41 @@ func AddPluginCommandStubs(dockerCli command.Cli, cmd *cobra.Command) error {
if p.Err != nil {
annotations[CommandAnnotationPluginInvalid] = p.Err.Error()
}
cmd.AddCommand(&cobra.Command{
Use: p.Name,
Short: p.ShortDescription,
Run: func(_ *cobra.Command, _ []string) {},
Annotations: annotations,
rootCmd.AddCommand(&cobra.Command{
Use: p.Name,
Short: p.ShortDescription,
Run: func(_ *cobra.Command, _ []string) {},
Annotations: annotations,
DisableFlagParsing: true,
RunE: func(cmd *cobra.Command, args []string) error {
flags := rootCmd.PersistentFlags()
flags.SetOutput(nil)
err := flags.Parse(args)
if err != nil {
return err
}
if flags.Changed("help") {
cmd.HelpFunc()(rootCmd, args)
return nil
}
return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'", cmd.Name())
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// Delegate completion to plugin
cargs := []string{p.Path, cobra.ShellCompRequestCmd, p.Name}
cargs = append(cargs, args...)
cargs = append(cargs, toComplete)
os.Args = cargs
runCommand, err := PluginRunCommand(dockerCli, p.Name, cmd)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
err = runCommand.Run()
if err == nil {
os.Exit(0) // plugin already rendered complete data
}
return nil, cobra.ShellCompDirectiveError
},
})
}
return nil

View File

@ -125,6 +125,11 @@ func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta
},
TraverseChildren: true,
DisableFlagsInUseLine: true,
CompletionOptions: cobra.CompletionOptions{
DisableDefaultCmd: false,
HiddenDefaultCmd: true,
DisableDescriptions: true,
},
}
opts, flags := cli.SetupPluginRootCommand(cmd)

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
units "github.com/docker/go-units"
@ -39,7 +40,8 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil
},
Annotations: map[string]string{"version": "1.39"},
Annotations: map[string]string{"version": "1.39"},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
@ -25,6 +26,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, args[0], opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
flags := cmd.Flags()

View File

@ -0,0 +1,99 @@
package completion
import (
"os"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/spf13/cobra"
)
// ValidArgsFn a function to be used by cobra command as `ValidArgsFunction` to offer command line completion
type ValidArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)
// ImageNames offers completion for images present within the local store
func ImageNames(dockerCli command.Cli) ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCli.Client().ImageList(cmd.Context(), types.ImageListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var names []string
for _, image := range list {
names = append(names, image.RepoTags...)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
}
// ContainerNames offers completion for container names and IDs
// By default, only names are returned.
// Set DOCKER_COMPLETION_SHOW_CONTAINER_IDS=yes to also complete IDs.
func ContainerNames(dockerCli command.Cli, all bool, filters ...func(types.Container) bool) ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCli.Client().ContainerList(cmd.Context(), types.ContainerListOptions{
All: all,
})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
showContainerIDs := os.Getenv("DOCKER_COMPLETION_SHOW_CONTAINER_IDS") == "yes"
var names []string
for _, container := range list {
skip := false
for _, fn := range filters {
if !fn(container) {
skip = true
break
}
}
if skip {
continue
}
if showContainerIDs {
names = append(names, container.ID)
}
names = append(names, formatter.StripNamePrefix(container.Names)...)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
}
// VolumeNames offers completion for volumes
func VolumeNames(dockerCli command.Cli) ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCli.Client().VolumeList(cmd.Context(), filters.Args{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var names []string
for _, volume := range list.Volumes {
names = append(names, volume.Name)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
}
// NetworkNames offers completion for networks
func NetworkNames(dockerCli command.Cli) ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCli.Client().NetworkList(cmd.Context(), types.NetworkListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var names []string
for _, network := range list {
names = append(names, network.Name)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
}
// NoComplete is used for commands where there's no relevant completion
func NoComplete(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveNoFileComp
}

View File

@ -1,10 +1,11 @@
package config
import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
)
// NewConfigCommand returns a cobra command for `config` subcommands
@ -27,3 +28,18 @@ func NewConfigCommand(dockerCli command.Cli) *cobra.Command {
)
return cmd
}
// completeNames offers completion for swarm configs
func completeNames(dockerCli command.Cli) completion.ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCli.Client().ConfigList(cmd.Context(), types.ConfigListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var names []string
for _, config := range list {
names = append(names, config.ID)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
}

View File

@ -29,6 +29,9 @@ func newConfigInspectCommand(dockerCli command.Cli) *cobra.Command {
opts.Names = args
return RunConfigInspect(dockerCli, opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
cmd.Flags().StringVarP(&opts.Format, "format", "f", "", flagsHelper.InspectFormatHelp)

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
@ -32,6 +33,7 @@ func newConfigListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return RunConfigList(dockerCli, listOpts)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -28,6 +28,9 @@ func newConfigRemoveCommand(dockerCli command.Cli) *cobra.Command {
}
return RunConfigRemove(dockerCli, opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
@ -54,6 +55,7 @@ func NewAttachCommand(dockerCli command.Cli) *cobra.Command {
opts.container = args[0]
return runAttach(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
@ -36,6 +37,7 @@ func NewCommitCommand(dockerCli command.Cli) *cobra.Command {
}
return runCommit(dockerCli, &options)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
flags := cmd.Flags()

View File

@ -10,6 +10,7 @@ import (
"github.com/containerd/containerd/platforms"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/opts"
"github.com/docker/distribution/reference"
@ -56,6 +57,7 @@ func NewCreateCommand(dockerCli command.Cli) *cobra.Command {
}
return runCreate(dockerCli, cmd.Flags(), &opts, copts)
},
ValidArgsFunction: completion.ImageNames(dockerCli),
}
flags := cmd.Flags()

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -26,6 +27,7 @@ func NewDiffCommand(dockerCli command.Cli) *cobra.Command {
opts.container = args[0]
return runDiff(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
}

View File

@ -4,9 +4,11 @@ import (
"context"
"fmt"
"io"
"os"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
@ -52,6 +54,7 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
options.Command = args[1:]
return RunExec(dockerCli, options)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
Annotations: map[string]string{
"category-top": "2",
},
@ -73,6 +76,19 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVarP(&options.Workdir, "workdir", "w", "", "Working directory inside the container")
flags.SetAnnotation("workdir", "version", []string{"1.35"})
cmd.RegisterFlagCompletionFunc(
"env",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return os.Environ(), cobra.ShellCompDirectiveNoFileComp
},
)
cmd.RegisterFlagCompletionFunc(
"env-file",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveDefault // _filedir
},
)
return cmd
}

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -27,6 +28,7 @@ func NewExportCommand(dockerCli command.Cli) *cobra.Command {
opts.container = args[0]
return runExport(dockerCli, opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true),
}
flags := cmd.Flags()

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/spf13/cobra"
@ -28,6 +29,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
opts.refs = args
return runInspect(dockerCli, opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true),
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -29,6 +30,7 @@ func NewKillCommand(dockerCli command.Cli) *cobra.Command {
opts.containers = args
return runKill(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
@ -40,6 +41,7 @@ func NewPsCommand(dockerCli command.Cli) *cobra.Command {
Annotations: map[string]string{
"category-top": "3",
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stdcopy"
"github.com/spf13/cobra"
@ -34,6 +35,7 @@ func NewLogsCommand(dockerCli command.Cli) *cobra.Command {
opts.container = args[0]
return runLogs(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true),
}
flags := cmd.Flags()

View File

@ -7,6 +7,8 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -27,6 +29,9 @@ func NewPauseCommand(dockerCli command.Cli) *cobra.Command {
opts.containers = args
return runPause(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(container types.Container) bool {
return container.State != "paused"
}),
}
}

View File

@ -8,6 +8,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/go-connections/nat"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -34,6 +35,7 @@ func NewPortCommand(dockerCli command.Cli) *cobra.Command {
}
return runPort(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
return cmd
}

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
units "github.com/docker/go-units"
"github.com/spf13/cobra"
@ -35,7 +36,8 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil
},
Annotations: map[string]string{"version": "1.25"},
Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -29,6 +30,7 @@ func NewRenameCommand(dockerCli command.Cli) *cobra.Command {
opts.newName = args[1]
return runRename(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true),
}
return cmd
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types/container"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -32,6 +33,7 @@ func NewRestartCommand(dockerCli command.Cli) *cobra.Command {
opts.nSecondsChanged = cmd.Flags().Changed("time")
return runRestart(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true),
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
@ -33,6 +34,7 @@ func NewRmCommand(dockerCli command.Cli) *cobra.Command {
opts.containers = args
return runRm(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true),
}
flags := cmd.Flags()

View File

@ -4,11 +4,13 @@ import (
"context"
"fmt"
"io"
"os"
"strings"
"syscall"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
@ -43,6 +45,7 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
}
return runRun(dockerCli, cmd.Flags(), &opts, copts)
},
ValidArgsFunction: completion.ImageNames(dockerCli),
Annotations: map[string]string{
"category-top": "1",
},
@ -67,6 +70,23 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
command.AddPlatformFlag(flags, &opts.platform)
command.AddTrustVerificationFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
copts = addFlags(flags)
cmd.RegisterFlagCompletionFunc(
"env",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return os.Environ(), cobra.ShellCompDirectiveNoFileComp
},
)
cmd.RegisterFlagCompletionFunc(
"env-file",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveDefault
},
)
cmd.RegisterFlagCompletionFunc(
"network",
completion.NetworkNames(dockerCli),
)
return cmd
}

View File

@ -8,6 +8,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/moby/sys/signal"
"github.com/moby/term"
@ -43,6 +44,9 @@ func NewStartCommand(dockerCli command.Cli) *cobra.Command {
opts.Containers = args
return RunStart(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true, func(container types.Container) bool {
return container.State == "exited" || container.State == "created"
}),
}
flags := cmd.Flags()

View File

@ -10,6 +10,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types"
@ -39,6 +40,7 @@ func NewStatsCommand(dockerCli command.Cli) *cobra.Command {
opts.containers = args
return runStats(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types/container"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -32,6 +33,7 @@ func NewStopCommand(dockerCli command.Cli) *cobra.Command {
opts.timeChanged = cmd.Flags().Changed("time")
return runStop(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter/tabwriter"
"github.com/spf13/cobra"
)
@ -30,6 +31,7 @@ func NewTopCommand(dockerCli command.Cli) *cobra.Command {
opts.args = args[1:]
return runTop(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
flags := cmd.Flags()

View File

@ -7,6 +7,8 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -27,6 +29,9 @@ func NewUnpauseCommand(dockerCli command.Cli) *cobra.Command {
opts.containers = args
return runUnpause(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(container types.Container) bool {
return container.State == "paused"
}),
}
return cmd
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
containertypes "github.com/docker/docker/api/types/container"
"github.com/pkg/errors"
@ -48,6 +49,7 @@ func NewUpdateCommand(dockerCli command.Cli) *cobra.Command {
options.nFlag = cmd.Flags().NFlag()
return runUpdate(dockerCli, &options)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true),
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -27,6 +28,7 @@ func NewWaitCommand(dockerCli command.Cli) *cobra.Command {
opts.containers = args
return runWait(dockerCli, &opts)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
}
return cmd

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/context/docker"
flagsHelper "github.com/docker/cli/cli/flags"
@ -30,6 +31,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, opts)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/spf13/cobra"
)
@ -17,6 +18,7 @@ func newShowCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runShow(dockerCli)
},
ValidArgsFunction: completion.NoComplete,
}
return cmd
}

View File

@ -125,7 +125,7 @@ func (c *ContainerContext) ID() string {
// slash (/) prefix stripped. Additional names for the container (related to the
// legacy `--link` feature) are omitted.
func (c *ContainerContext) Names() string {
names := stripNamePrefix(c.c.Names)
names := StripNamePrefix(c.c.Names)
if c.trunc {
for _, name := range names {
if len(strings.Split(name, "/")) == 1 {
@ -137,6 +137,15 @@ func (c *ContainerContext) Names() string {
return strings.Join(names, ",")
}
// StripNamePrefix removes prefix from string, typically container names as returned by `ContainersList` API
func StripNamePrefix(ss []string) []string {
sss := make([]string, len(ss))
for i, s := range ss {
sss[i] = s[1:]
}
return sss
}
// Image returns the container's image reference. If the trunc option is set,
// the image's registry digest can be included.
func (c *ContainerContext) Image() string {

View File

@ -45,12 +45,3 @@ type HeaderContext struct {
func (c *HeaderContext) FullHeader() interface{} {
return c.Header
}
func stripNamePrefix(ss []string) []string {
sss := make([]string, len(ss))
for i, s := range ss {
sss[i] = s[1:]
}
return sss
}

View File

@ -108,6 +108,9 @@ func NewBuildCommand(dockerCli command.Cli) *cobra.Command {
Annotations: map[string]string{
"category-top": "4",
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveFilterDirs
},
}
flags := cmd.Flags()

View File

@ -1,10 +1,9 @@
package image
import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/spf13/cobra"
)
// NewImageCommand returns a cobra command for `image` subcommands

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
@ -28,6 +29,7 @@ func NewLoadCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runLoad(dockerCli, opts)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
units "github.com/docker/go-units"
"github.com/spf13/cobra"
@ -37,7 +38,8 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil
},
Annotations: map[string]string{"version": "1.25"},
Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/streams"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
@ -38,6 +39,7 @@ func NewPushCommand(dockerCli command.Cli) *cobra.Command {
Annotations: map[string]string{
"category-top": "6",
},
ValidArgsFunction: completion.ImageNames(dockerCli),
}
flags := cmd.Flags()

View File

@ -1,10 +1,9 @@
package network
import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/spf13/cobra"
)
// NewNetworkCommand returns a cobra command for `network` subcommands

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types/network"
"github.com/spf13/cobra"
@ -37,6 +38,13 @@ func newConnectCommand(dockerCli command.Cli) *cobra.Command {
options.container = args[1]
return runConnect(dockerCli, options)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return completion.NetworkNames(dockerCli)(cmd, args, toComplete)
}
network := args[0]
return completion.ContainerNames(dockerCli, true, not(isConnected(network)))(cmd, args, toComplete)
},
}
flags := cmd.Flags()

View File

@ -5,6 +5,8 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
)
@ -26,6 +28,13 @@ func newDisconnectCommand(dockerCli command.Cli) *cobra.Command {
opts.container = args[1]
return runDisconnect(dockerCli, opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return completion.NetworkNames(dockerCli)(cmd, args, toComplete)
}
network := args[0]
return completion.ContainerNames(dockerCli, true, isConnected(network))(cmd, args, toComplete)
},
}
flags := cmd.Flags()
@ -39,3 +48,20 @@ func runDisconnect(dockerCli command.Cli, opts disconnectOptions) error {
return client.NetworkDisconnect(context.Background(), opts.network, opts.container, opts.force)
}
func isConnected(network string) func(types.Container) bool {
return func(container types.Container) bool {
if container.NetworkSettings == nil {
return false
}
_, ok := container.NetworkSettings.Networks[network]
return ok
}
}
func not(fn func(types.Container) bool) func(types.Container) bool {
return func(container types.Container) bool {
ok := fn(container)
return !ok
}
}

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types"
@ -28,6 +29,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
opts.names = args
return runInspect(dockerCli, opts)
},
ValidArgsFunction: completion.NetworkNames(dockerCli),
}
cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
@ -32,6 +33,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/errdefs"
"github.com/spf13/cobra"
@ -26,6 +27,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runRemove(dockerCli, args, &opts)
},
ValidArgsFunction: completion.NetworkNames(dockerCli),
}
flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
@ -31,6 +32,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()
flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only display IDs")

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/idresolver"
"github.com/docker/cli/cli/command/task"
"github.com/docker/cli/opts"
@ -40,6 +41,7 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
return runPs(dockerCli, options)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Do not truncate output")

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
@ -31,6 +32,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -1,10 +1,11 @@
package secret
import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
)
// NewSecretCommand returns a cobra command for `secret` subcommands
@ -27,3 +28,18 @@ func NewSecretCommand(dockerCli command.Cli) *cobra.Command {
)
return cmd
}
// completeNames offers completion for swarm secrets
func completeNames(dockerCli command.Cli) completion.ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCli.Client().SecretList(cmd.Context(), types.SecretListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var names []string
for _, secret := range list {
names = append(names, secret.ID)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
}

View File

@ -28,6 +28,9 @@ func newSecretInspectCommand(dockerCli command.Cli) *cobra.Command {
opts.names = args
return runSecretInspect(dockerCli, opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)

View File

@ -31,6 +31,9 @@ func newSecretListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runSecretList(dockerCli, options)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()

View File

@ -27,6 +27,9 @@ func newSecretRemoveCommand(dockerCli command.Cli) *cobra.Command {
}
return runSecretRemove(dockerCli, opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
}

View File

@ -1,10 +1,11 @@
package service
import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
)
// NewServiceCommand returns a cobra command for `service` subcommands
@ -32,3 +33,18 @@ func NewServiceCommand(dockerCli command.Cli) *cobra.Command {
)
return cmd
}
// CompletionFn offers completion for swarm services
func CompletionFn(dockerCli command.Cli) completion.ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCli.Client().ServiceList(cmd.Context(), types.ServiceListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var names []string
for _, service := range list {
names = append(names, service.ID)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
}

View File

@ -35,6 +35,9 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
}
return runInspect(dockerCli, opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return CompletionFn(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
@ -32,6 +33,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -48,6 +48,9 @@ func newLogsCommand(dockerCli command.Cli) *cobra.Command {
return runLogs(dockerCli, &opts)
},
Annotations: map[string]string{"version": "1.29"},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return CompletionFn(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()

View File

@ -37,6 +37,9 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
options.services = args
return runPS(dockerCli, options)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return CompletionFn(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()
flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only display task IDs")

View File

@ -21,6 +21,9 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runRemove(dockerCli, args)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return CompletionFn(dockerCli)(cmd, args, toComplete)
},
}
cmd.Flags()

View File

@ -22,6 +22,9 @@ func newRollbackCommand(dockerCli command.Cli) *cobra.Command {
return runRollback(dockerCli, options, args[0])
},
Annotations: map[string]string{"version": "1.31"},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return CompletionFn(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()

View File

@ -28,6 +28,9 @@ func newScaleCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runScale(dockerCli, options, args)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return CompletionFn(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()

View File

@ -33,6 +33,9 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runUpdate(dockerCli, cmd.Flags(), options, args[0])
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return CompletionFn(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()

View File

@ -5,6 +5,8 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/stack/swarm"
"github.com/spf13/cobra"
)
@ -42,3 +44,18 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command {
flags.MarkDeprecated("orchestrator", "option will be ignored")
return cmd
}
// completeNames offers completion for swarm stacks
func completeNames(dockerCli command.Cli) completion.ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := swarm.GetStacks(dockerCli)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var names []string
for _, stack := range list {
names = append(names, stack.Name)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
}

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/stack/loader"
"github.com/docker/cli/cli/command/stack/options"
composeLoader "github.com/docker/cli/cli/compose/loader"
@ -34,6 +35,7 @@ func newConfigCommand(dockerCli command.Cli) *cobra.Command {
_, err = fmt.Fprintf(dockerCli.Out(), "%s", cfg)
return err
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -30,6 +30,9 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command {
}
return RunDeploy(dockerCli, cmd.Flags(), config, opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/stack/formatter"
"github.com/docker/cli/cli/command/stack/options"
"github.com/docker/cli/cli/command/stack/swarm"
@ -24,6 +25,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return RunList(cmd, dockerCli, opts)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -25,6 +25,9 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
}
return RunPs(dockerCli, cmd.Flags(), opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()
flags.BoolVar(&opts.NoTrunc, "no-trunc", false, "Do not truncate output")

View File

@ -24,6 +24,9 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
}
return RunRemove(dockerCli, cmd.Flags(), opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
return cmd
}

View File

@ -32,6 +32,9 @@ func newServicesCommand(dockerCli command.Cli) *cobra.Command {
}
return RunServices(dockerCli, cmd.Flags(), opts)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completeNames(dockerCli)(cmd, args, toComplete)
},
}
flags := cmd.Flags()
flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")

View File

@ -8,6 +8,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/swarm/progress"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/pkg/jsonmessage"
@ -39,6 +40,7 @@ func newCACommand(dockerCli command.Cli) *cobra.Command {
"version": "1.30",
"swarm": "manager",
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -8,6 +8,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -43,6 +44,7 @@ func newInitCommand(dockerCli command.Cli) *cobra.Command {
"version": "1.24",
"swarm": "", // swarm init does not require swarm to be active, and is always available on API 1.24 and up
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/spf13/cobra"
)
@ -27,6 +28,7 @@ func newLeaveCommand(dockerCli command.Cli) *cobra.Command {
"version": "1.24",
"swarm": "active",
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -9,6 +9,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors"
@ -28,6 +29,7 @@ func newUnlockCommand(dockerCli command.Cli) *cobra.Command {
"version": "1.24",
"swarm": "manager",
},
ValidArgsFunction: completion.NoComplete,
}
return cmd

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -31,6 +32,7 @@ func newUnlockKeyCommand(dockerCli command.Cli) *cobra.Command {
"version": "1.24",
"swarm": "manager",
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -32,6 +33,7 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
"version": "1.24",
"swarm": "manager",
},
ValidArgsFunction: completion.NoComplete,
}
cmd.Flags().BoolVar(&opts.autolock, flagAutolock, false, "Change manager autolocking setting (true|false)")

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types"
@ -27,7 +28,8 @@ func newDiskUsageCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runDiskUsage(dockerCli, opts)
},
Annotations: map[string]string{"version": "1.25"},
Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -22,6 +23,7 @@ func newDialStdioCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runDialStdio(dockerCli)
},
ValidArgsFunction: completion.NoComplete,
}
return cmd
}

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
"github.com/docker/cli/templates"
"github.com/docker/docker/api/types"
@ -36,6 +37,7 @@ func NewEventsCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runEvents(dockerCli, &options)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/cli/cli"
pluginmanager "github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/debug"
"github.com/docker/cli/templates"
"github.com/docker/docker/api/types"
@ -57,6 +58,7 @@ func NewInfoCommand(dockerCli command.Cli) *cobra.Command {
Annotations: map[string]string{
"category-top": "12",
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -9,6 +9,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/builder"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/container"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/command/network"
@ -40,7 +41,8 @@ func newPruneCommand(dockerCli command.Cli) *cobra.Command {
options.pruneBuildCache = versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.31")
return runPrune(dockerCli, options)
},
Annotations: map[string]string{"version": "1.25"},
Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -10,6 +10,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter/tabwriter"
"github.com/docker/cli/cli/version"
"github.com/docker/cli/templates"
@ -97,6 +98,7 @@ func NewVersionCommand(dockerCli command.Cli) *cobra.Command {
Annotations: map[string]string{
"category-top": "10",
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/spf13/cobra"
@ -26,6 +27,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
opts.names = args
return runInspect(dockerCli, opts)
},
ValidArgsFunction: completion.VolumeNames(dockerCli),
}
cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
@ -30,6 +31,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options)
},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts"
units "github.com/docker/go-units"
"github.com/spf13/cobra"
@ -35,7 +36,8 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil
},
Annotations: map[string]string{"version": "1.25"},
Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
}
flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -31,6 +32,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
opts.volumes = args
return runRemove(dockerCli, &opts)
},
ValidArgsFunction: completion.VolumeNames(dockerCli),
}
flags := cmd.Flags()

View File

@ -118,6 +118,19 @@ func (s *store) List() ([]Metadata, error) {
return s.meta.list()
}
// Names return Metadata names for a Lister
func Names(s Lister) ([]string, error) {
list, err := s.List()
if err != nil {
return nil, err
}
var names []string
for _, item := range list {
names = append(names, item.Name)
}
return names, nil
}
func (s *store) CreateOrUpdate(meta Metadata) error {
return s.meta.createOrUpdate(meta)
}

27
cmd/docker/completions.go Normal file
View File

@ -0,0 +1,27 @@
package main
import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/context/store"
"github.com/spf13/cobra"
)
func registerCompletionFuncForGlobalFlags(dockerCli *command.DockerCli, cmd *cobra.Command) {
cmd.RegisterFlagCompletionFunc(
"context",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
names, err := store.Names(dockerCli.ContextStore())
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return names, cobra.ShellCompDirectiveNoFileComp
},
)
cmd.RegisterFlagCompletionFunc(
"log-level",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
values := []string{"debug", "info", "warn", "error", "fatal"}
return values, cobra.ShellCompDirectiveNoFileComp
},
)
}

View File

@ -47,10 +47,15 @@ func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand {
},
Version: fmt.Sprintf("%s, build %s", version.Version, version.GitCommit),
DisableFlagsInUseLine: true,
CompletionOptions: cobra.CompletionOptions{
DisableDefaultCmd: false,
HiddenDefaultCmd: true,
DisableDescriptions: true,
},
}
opts, flags, helpCmd = cli.SetupRootCommand(cmd)
registerCompletionFuncForGlobalFlags(dockerCli, cmd)
flags.BoolP("version", "v", false, "Print version information and quit")
setFlagErrorFunc(dockerCli, cmd)
setupHelpCommand(dockerCli, cmd, helpCmd)
@ -95,13 +100,10 @@ func setupHelpCommand(dockerCli command.Cli, rootCmd, helpCmd *cobra.Command) {
if len(args) > 0 {
helpcmd, err := pluginmanager.PluginRunCommand(dockerCli, args[0], rootCmd)
if err == nil {
err = helpcmd.Run()
if err != nil {
return err
}
return helpcmd.Run()
}
if !pluginmanager.IsNotFound(err) {
return err
return errors.Errorf("unknown help topic: %v", strings.Join(args, " "))
}
}
if origRunE != nil {
@ -129,25 +131,13 @@ func tryRunPluginHelp(dockerCli command.Cli, ccmd *cobra.Command, cargs []string
func setHelpFunc(dockerCli command.Cli, cmd *cobra.Command) {
defaultHelpFunc := cmd.HelpFunc()
cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
// Add a stub entry for every plugin so they are
// included in the help output and so that
// `tryRunPluginHelp` can find them or if we fall
// through they will be included in the default help
// output.
if err := pluginmanager.AddPluginCommandStubs(dockerCli, ccmd.Root()); err != nil {
ccmd.Println(err)
return
}
if len(args) >= 1 {
if ccmd.Annotations[pluginmanager.CommandAnnotationPlugin] == "true" {
err := tryRunPluginHelp(dockerCli, ccmd, args)
if err == nil { // Successfully ran the plugin
return
}
if !pluginmanager.IsNotFound(err) {
ccmd.Println(err)
return
}
cmd.PrintErrf("unknown help topic: %v\n", ccmd.Name())
return
}
if err := isSupported(ccmd, dockerCli); err != nil {
@ -163,7 +153,7 @@ func setHelpFunc(dockerCli command.Cli, cmd *cobra.Command) {
})
}
func setValidateArgs(dockerCli *command.DockerCli, cmd *cobra.Command) {
func setValidateArgs(dockerCli command.Cli, cmd *cobra.Command) {
// The Args is handled by ValidateArgs in cobra, which does not allows a pre-hook.
// As a result, here we replace the existing Args validation func to a wrapper,
// where the wrapper will check to see if the feature is supported or not.
@ -228,13 +218,19 @@ func runDocker(dockerCli *command.DockerCli) error {
return err
}
err = pluginmanager.AddPluginCommandStubs(dockerCli, cmd)
if err != nil {
return err
}
args, os.Args, err = processAliases(dockerCli, cmd, args, os.Args)
if err != nil {
return err
}
if len(args) > 0 {
if _, _, err := cmd.Find(args); err != nil {
command, _, err := cmd.Find(args)
if err != nil || command.Annotations[pluginmanager.CommandAnnotationPlugin] == "true" {
err := tryPluginRun(dockerCli, cmd, args[0])
if !pluginmanager.IsNotFound(err) {
return err

View File

@ -42,6 +42,7 @@ func runCliCommand(t *testing.T, r io.ReadCloser, w io.Writer, args ...string) e
cli, err := command.NewDockerCli(command.WithInputStream(r), command.WithCombinedStreams(w))
assert.NilError(t, err)
tcmd := newDockerCommand(cli)
tcmd.SetArgs(args)
cmd, _, err := tcmd.HandleGlobalFlags()
assert.NilError(t, err)

View File

@ -83,7 +83,7 @@ func TestHelpBad(t *testing.T) {
res := icmd.RunCmd(run("help", "badmeta"))
res.Assert(t, icmd.Expected{
ExitCode: 1,
ExitCode: 0,
Out: icmd.None,
})
golden.Assert(t, res.Stderr(), "docker-help-badmeta-err.golden")
@ -105,13 +105,13 @@ func TestBadHelp(t *testing.T) {
Err: icmd.None,
})
// Short -h should be the same, modulo the deprecation message
exp := shortHFlagDeprecated + res.Stdout()
usage := res.Stdout()
res = icmd.RunCmd(run("badmeta", "-h"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
// This should be identical to the --help case above
Out: exp,
Err: icmd.None,
Out: usage,
Err: shortHFlagDeprecated,
})
}

View File

@ -11,7 +11,7 @@ import (
func TestContextList(t *testing.T) {
cmd := icmd.Command("docker", "context", "ls")
cmd.Env = append(cmd.Env, "DOCKER_CONFIG=./testdata/test-dockerconfig")
cmd.Env = append(cmd.Env, "DOCKER_CONFIG=testdata/test-dockerconfig")
result := icmd.RunCmd(cmd).Assert(t, icmd.Expected{
Err: icmd.None,
ExitCode: 0,