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 package manager
import ( import (
"fmt"
"os"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -31,12 +34,13 @@ const (
// AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid // AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid
// plugin. The command stubs will have several annotations added, see // plugin. The command stubs will have several annotations added, see
// `CommandAnnotationPlugin*`. // `CommandAnnotationPlugin*`.
func AddPluginCommandStubs(dockerCli command.Cli, cmd *cobra.Command) error { func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) error {
plugins, err := ListPlugins(dockerCli, cmd) plugins, err := ListPlugins(dockerCli, rootCmd)
if err != nil { if err != nil {
return err return err
} }
for _, p := range plugins { for _, p := range plugins {
p := p
vendor := p.Vendor vendor := p.Vendor
if vendor == "" { if vendor == "" {
vendor = "unknown" vendor = "unknown"
@ -49,11 +53,41 @@ func AddPluginCommandStubs(dockerCli command.Cli, cmd *cobra.Command) error {
if p.Err != nil { if p.Err != nil {
annotations[CommandAnnotationPluginInvalid] = p.Err.Error() annotations[CommandAnnotationPluginInvalid] = p.Err.Error()
} }
cmd.AddCommand(&cobra.Command{ rootCmd.AddCommand(&cobra.Command{
Use: p.Name, Use: p.Name,
Short: p.ShortDescription, Short: p.ShortDescription,
Run: func(_ *cobra.Command, _ []string) {}, Run: func(_ *cobra.Command, _ []string) {},
Annotations: annotations, 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 return nil

View File

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

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
units "github.com/docker/go-units" 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))) fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil return nil
}, },
Annotations: map[string]string{"version": "1.39"}, Annotations: map[string]string{"version": "1.39"},
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "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/command/formatter"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -25,6 +26,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, args[0], opts) return runList(dockerCli, args[0], opts)
}, },
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
} }
flags := cmd.Flags() 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 package config
import ( import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "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 // NewConfigCommand returns a cobra command for `config` subcommands
@ -27,3 +28,18 @@ func NewConfigCommand(dockerCli command.Cli) *cobra.Command {
) )
return cmd 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 opts.Names = args
return RunConfigInspect(dockerCli, opts) 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) 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"
"github.com/docker/cli/cli/command" "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/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
@ -32,6 +33,7 @@ func newConfigListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return RunConfigList(dockerCli, listOpts) return RunConfigList(dockerCli, listOpts)
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

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

View File

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

View File

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

View File

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

View File

@ -4,9 +4,11 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"os"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -52,6 +54,7 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
options.Command = args[1:] options.Command = args[1:]
return RunExec(dockerCli, options) return RunExec(dockerCli, options)
}, },
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
Annotations: map[string]string{ Annotations: map[string]string{
"category-top": "2", "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.StringVarP(&options.Workdir, "workdir", "w", "", "Working directory inside the container")
flags.SetAnnotation("workdir", "version", []string{"1.35"}) 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 return cmd
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,6 +7,8 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "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/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -27,6 +29,9 @@ func NewPauseCommand(dockerCli command.Cli) *cobra.Command {
opts.containers = args opts.containers = args
return runPause(dockerCli, &opts) 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"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -34,6 +35,7 @@ func NewPortCommand(dockerCli command.Cli) *cobra.Command {
} }
return runPort(dockerCli, &opts) return runPort(dockerCli, &opts)
}, },
ValidArgsFunction: completion.ContainerNames(dockerCli, false),
} }
return cmd return cmd
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
units "github.com/docker/go-units" units "github.com/docker/go-units"
"github.com/spf13/cobra" "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))) fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil return nil
}, },
Annotations: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

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

View File

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

View File

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

View File

@ -4,11 +4,13 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"os"
"strings" "strings"
"syscall" "syscall"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "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) return runRun(dockerCli, cmd.Flags(), &opts, copts)
}, },
ValidArgsFunction: completion.ImageNames(dockerCli),
Annotations: map[string]string{ Annotations: map[string]string{
"category-top": "1", "category-top": "1",
}, },
@ -67,6 +70,23 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
command.AddPlatformFlag(flags, &opts.platform) command.AddPlatformFlag(flags, &opts.platform)
command.AddTrustVerificationFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled()) command.AddTrustVerificationFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
copts = addFlags(flags) 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 return cmd
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -125,7 +125,7 @@ func (c *ContainerContext) ID() string {
// slash (/) prefix stripped. Additional names for the container (related to the // slash (/) prefix stripped. Additional names for the container (related to the
// legacy `--link` feature) are omitted. // legacy `--link` feature) are omitted.
func (c *ContainerContext) Names() string { func (c *ContainerContext) Names() string {
names := stripNamePrefix(c.c.Names) names := StripNamePrefix(c.c.Names)
if c.trunc { if c.trunc {
for _, name := range names { for _, name := range names {
if len(strings.Split(name, "/")) == 1 { if len(strings.Split(name, "/")) == 1 {
@ -137,6 +137,15 @@ func (c *ContainerContext) Names() string {
return strings.Join(names, ",") 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, // Image returns the container's image reference. If the trunc option is set,
// the image's registry digest can be included. // the image's registry digest can be included.
func (c *ContainerContext) Image() string { func (c *ContainerContext) Image() string {

View File

@ -45,12 +45,3 @@ type HeaderContext struct {
func (c *HeaderContext) FullHeader() interface{} { func (c *HeaderContext) FullHeader() interface{} {
return c.Header 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{ Annotations: map[string]string{
"category-top": "4", "category-top": "4",
}, },
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveFilterDirs
},
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -1,10 +1,9 @@
package image package image
import ( import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/spf13/cobra"
) )
// NewImageCommand returns a cobra command for `image` subcommands // 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"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -28,6 +29,7 @@ func NewLoadCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runLoad(dockerCli, opts) return runLoad(dockerCli, opts)
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
units "github.com/docker/go-units" units "github.com/docker/go-units"
"github.com/spf13/cobra" "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))) fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil return nil
}, },
Annotations: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

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

View File

@ -1,10 +1,9 @@
package network package network
import ( import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/spf13/cobra"
) )
// NewNetworkCommand returns a cobra command for `network` subcommands // 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"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -37,6 +38,13 @@ func newConnectCommand(dockerCli command.Cli) *cobra.Command {
options.container = args[1] options.container = args[1]
return runConnect(dockerCli, options) 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() flags := cmd.Flags()

View File

@ -5,6 +5,8 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -26,6 +28,13 @@ func newDisconnectCommand(dockerCli command.Cli) *cobra.Command {
opts.container = args[1] opts.container = args[1]
return runDisconnect(dockerCli, opts) 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() 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) 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"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/inspect" "github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -28,6 +29,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
opts.names = args opts.names = args
return runInspect(dockerCli, opts) return runInspect(dockerCli, opts)
}, },
ValidArgsFunction: completion.NetworkNames(dockerCli),
} }
cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp) 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"
"github.com/docker/cli/cli/command" "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/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
@ -32,6 +33,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options) return runList(dockerCli, options)
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

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

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "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/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
@ -31,6 +32,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options) return runList(dockerCli, options)
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only display IDs") 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"
"github.com/docker/cli/cli/command" "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/idresolver"
"github.com/docker/cli/cli/command/task" "github.com/docker/cli/cli/command/task"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
@ -40,6 +41,7 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
return runPs(dockerCli, options) return runPs(dockerCli, options)
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Do not truncate output") 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"
"github.com/docker/cli/cli/command" "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/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
@ -31,6 +32,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options) return runList(dockerCli, options)
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -1,10 +1,11 @@
package secret package secret
import ( import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "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 // NewSecretCommand returns a cobra command for `secret` subcommands
@ -27,3 +28,18 @@ func NewSecretCommand(dockerCli command.Cli) *cobra.Command {
) )
return cmd 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 opts.names = args
return runSecretInspect(dockerCli, opts) 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) 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 { RunE: func(cmd *cobra.Command, args []string) error {
return runSecretList(dockerCli, options) 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() flags := cmd.Flags()

View File

@ -27,6 +27,9 @@ func newSecretRemoveCommand(dockerCli command.Cli) *cobra.Command {
} }
return runSecretRemove(dockerCli, opts) 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 package service
import ( import (
"github.com/spf13/cobra"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "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 // NewServiceCommand returns a cobra command for `service` subcommands
@ -32,3 +33,18 @@ func NewServiceCommand(dockerCli command.Cli) *cobra.Command {
) )
return cmd 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) 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() flags := cmd.Flags()

View File

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

View File

@ -48,6 +48,9 @@ func newLogsCommand(dockerCli command.Cli) *cobra.Command {
return runLogs(dockerCli, &opts) return runLogs(dockerCli, &opts)
}, },
Annotations: map[string]string{"version": "1.29"}, 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() flags := cmd.Flags()

View File

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

View File

@ -22,6 +22,9 @@ func newRollbackCommand(dockerCli command.Cli) *cobra.Command {
return runRollback(dockerCli, options, args[0]) return runRollback(dockerCli, options, args[0])
}, },
Annotations: map[string]string{"version": "1.31"}, 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() flags := cmd.Flags()

View File

@ -28,6 +28,9 @@ func newScaleCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runScale(dockerCli, options, args) 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() flags := cmd.Flags()

View File

@ -33,6 +33,9 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runUpdate(dockerCli, cmd.Flags(), options, args[0]) 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() flags := cmd.Flags()

View File

@ -5,6 +5,8 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "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" "github.com/spf13/cobra"
) )
@ -42,3 +44,18 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command {
flags.MarkDeprecated("orchestrator", "option will be ignored") flags.MarkDeprecated("orchestrator", "option will be ignored")
return cmd 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"
"github.com/docker/cli/cli/command" "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/loader"
"github.com/docker/cli/cli/command/stack/options" "github.com/docker/cli/cli/command/stack/options"
composeLoader "github.com/docker/cli/cli/compose/loader" 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) _, err = fmt.Fprintf(dockerCli.Out(), "%s", cfg)
return err return err
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -30,6 +30,9 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command {
} }
return RunDeploy(dockerCli, cmd.Flags(), config, opts) 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() flags := cmd.Flags()

View File

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

View File

@ -25,6 +25,9 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command {
} }
return RunPs(dockerCli, cmd.Flags(), opts) 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 := cmd.Flags()
flags.BoolVar(&opts.NoTrunc, "no-trunc", false, "Do not truncate output") 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) 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 return cmd
} }

View File

@ -32,6 +32,9 @@ func newServicesCommand(dockerCli command.Cli) *cobra.Command {
} }
return RunServices(dockerCli, cmd.Flags(), opts) 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 := cmd.Flags()
flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs") 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"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/swarm/progress" "github.com/docker/cli/cli/command/swarm/progress"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
@ -39,6 +40,7 @@ func newCACommand(dockerCli command.Cli) *cobra.Command {
"version": "1.30", "version": "1.30",
"swarm": "manager", "swarm": "manager",
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

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

View File

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

View File

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

View File

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

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -32,6 +33,7 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
"version": "1.24", "version": "1.24",
"swarm": "manager", "swarm": "manager",
}, },
ValidArgsFunction: completion.NoComplete,
} }
cmd.Flags().BoolVar(&opts.autolock, flagAutolock, false, "Change manager autolocking setting (true|false)") 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"
"github.com/docker/cli/cli/command" "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/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types" "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 { RunE: func(cmd *cobra.Command, args []string) error {
return runDiskUsage(dockerCli, opts) return runDiskUsage(dockerCli, opts)
}, },
Annotations: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/builder" "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/container"
"github.com/docker/cli/cli/command/image" "github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/command/network" "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") options.pruneBuildCache = versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.31")
return runPrune(dockerCli, options) return runPrune(dockerCli, options)
}, },
Annotations: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

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

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/inspect" "github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -26,6 +27,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
opts.names = args opts.names = args
return runInspect(dockerCli, opts) return runInspect(dockerCli, opts)
}, },
ValidArgsFunction: completion.VolumeNames(dockerCli),
} }
cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp) 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"
"github.com/docker/cli/cli/command" "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/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags" flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
@ -30,6 +31,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, options) return runList(dockerCli, options)
}, },
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

@ -6,6 +6,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/opts" "github.com/docker/cli/opts"
units "github.com/docker/go-units" units "github.com/docker/go-units"
"github.com/spf13/cobra" "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))) fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil return nil
}, },
Annotations: map[string]string{"version": "1.25"}, Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: completion.NoComplete,
} }
flags := cmd.Flags() flags := cmd.Flags()

View File

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

View File

@ -118,6 +118,19 @@ func (s *store) List() ([]Metadata, error) {
return s.meta.list() 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 { func (s *store) CreateOrUpdate(meta Metadata) error {
return s.meta.createOrUpdate(meta) 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), Version: fmt.Sprintf("%s, build %s", version.Version, version.GitCommit),
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
CompletionOptions: cobra.CompletionOptions{
DisableDefaultCmd: false,
HiddenDefaultCmd: true,
DisableDescriptions: true,
},
} }
opts, flags, helpCmd = cli.SetupRootCommand(cmd) opts, flags, helpCmd = cli.SetupRootCommand(cmd)
registerCompletionFuncForGlobalFlags(dockerCli, cmd)
flags.BoolP("version", "v", false, "Print version information and quit") flags.BoolP("version", "v", false, "Print version information and quit")
setFlagErrorFunc(dockerCli, cmd) setFlagErrorFunc(dockerCli, cmd)
setupHelpCommand(dockerCli, cmd, helpCmd) setupHelpCommand(dockerCli, cmd, helpCmd)
@ -95,13 +100,10 @@ func setupHelpCommand(dockerCli command.Cli, rootCmd, helpCmd *cobra.Command) {
if len(args) > 0 { if len(args) > 0 {
helpcmd, err := pluginmanager.PluginRunCommand(dockerCli, args[0], rootCmd) helpcmd, err := pluginmanager.PluginRunCommand(dockerCli, args[0], rootCmd)
if err == nil { if err == nil {
err = helpcmd.Run() return helpcmd.Run()
if err != nil {
return err
}
} }
if !pluginmanager.IsNotFound(err) { if !pluginmanager.IsNotFound(err) {
return err return errors.Errorf("unknown help topic: %v", strings.Join(args, " "))
} }
} }
if origRunE != nil { 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) { func setHelpFunc(dockerCli command.Cli, cmd *cobra.Command) {
defaultHelpFunc := cmd.HelpFunc() defaultHelpFunc := cmd.HelpFunc()
cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) { cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
// Add a stub entry for every plugin so they are if ccmd.Annotations[pluginmanager.CommandAnnotationPlugin] == "true" {
// 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 {
err := tryRunPluginHelp(dockerCli, ccmd, args) err := tryRunPluginHelp(dockerCli, ccmd, args)
if err == nil { // Successfully ran the plugin
return
}
if !pluginmanager.IsNotFound(err) { if !pluginmanager.IsNotFound(err) {
ccmd.Println(err) ccmd.Println(err)
return
} }
cmd.PrintErrf("unknown help topic: %v\n", ccmd.Name())
return
} }
if err := isSupported(ccmd, dockerCli); err != nil { 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. // 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, // 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. // 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 return err
} }
err = pluginmanager.AddPluginCommandStubs(dockerCli, cmd)
if err != nil {
return err
}
args, os.Args, err = processAliases(dockerCli, cmd, args, os.Args) args, os.Args, err = processAliases(dockerCli, cmd, args, os.Args)
if err != nil { if err != nil {
return err return err
} }
if len(args) > 0 { 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]) err := tryPluginRun(dockerCli, cmd, args[0])
if !pluginmanager.IsNotFound(err) { if !pluginmanager.IsNotFound(err) {
return 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)) cli, err := command.NewDockerCli(command.WithInputStream(r), command.WithCombinedStreams(w))
assert.NilError(t, err) assert.NilError(t, err)
tcmd := newDockerCommand(cli) tcmd := newDockerCommand(cli)
tcmd.SetArgs(args) tcmd.SetArgs(args)
cmd, _, err := tcmd.HandleGlobalFlags() cmd, _, err := tcmd.HandleGlobalFlags()
assert.NilError(t, err) assert.NilError(t, err)

View File

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

View File

@ -11,7 +11,7 @@ import (
func TestContextList(t *testing.T) { func TestContextList(t *testing.T) {
cmd := icmd.Command("docker", "context", "ls") 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{ result := icmd.RunCmd(cmd).Assert(t, icmd.Expected{
Err: icmd.None, Err: icmd.None,
ExitCode: 0, ExitCode: 0,