-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Add top-level --completion flag, and integrate completion for plugins #3254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,6 @@ import ( | |
| pluginmanager "github.com/docker/cli/cli-plugins/manager" | ||
| "github.com/docker/cli/cli/command" | ||
| "github.com/docker/cli/cli/command/commands" | ||
| cliflags "github.com/docker/cli/cli/flags" | ||
| "github.com/docker/cli/cli/version" | ||
| "github.com/docker/docker/api/types/versions" | ||
| "github.com/docker/docker/client" | ||
|
|
@@ -27,12 +26,6 @@ var allowedAliases = map[string]struct{}{ | |
| } | ||
|
|
||
| func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand { | ||
| var ( | ||
| opts *cliflags.ClientOptions | ||
| flags *pflag.FlagSet | ||
| helpCmd *cobra.Command | ||
| ) | ||
|
|
||
| cmd := &cobra.Command{ | ||
| Use: "docker [OPTIONS] COMMAND [ARG...]", | ||
| Short: "A self-sufficient runtime for containers", | ||
|
|
@@ -44,15 +37,32 @@ func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand { | |
| return command.ShowHelp(dockerCli.Err())(cmd, args) | ||
| } | ||
| return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'", args[0]) | ||
|
|
||
| }, | ||
| PersistentPreRunE: func(cmd *cobra.Command, args []string) error { | ||
| // Handle shell completion for plugin commands by forwarding the | ||
| // arguments to the plugin. Supporting completion is currently | ||
| // optional for plugins, so we ignore errors (if any). | ||
| if len(args) > 0 && cmd.Name() == cobra.ShellCompRequestCmd || cmd.Name() == cobra.ShellCompNoDescRequestCmd { | ||
| if _, _, err := cmd.Root().Find(args); err != nil { | ||
| // No such command. Try if we have a plugin that has this command | ||
| if err := tryPluginRun(dockerCli, cmd, args[0]); err == nil { | ||
| // We're done. Exit here to prevent the regular command | ||
| // from being executed. | ||
| os.Exit(0) | ||
| } | ||
| // Didn't find a plugin for this command either. Continue as | ||
| // usual, and have the default __complete / __completeNoDesc | ||
| // command handle the completion. | ||
| return nil | ||
| } | ||
| } | ||
| return isSupported(cmd, dockerCli) | ||
| }, | ||
| Version: fmt.Sprintf("%s, build %s", version.Version, version.GitCommit), | ||
| DisableFlagsInUseLine: true, | ||
| } | ||
| opts, flags, helpCmd = cli.SetupRootCommand(cmd) | ||
| opts, flags, helpCmd := cli.SetupRootCommand(cmd) | ||
| flags.String("completion", "", "Print the shell completion script for the specified shell (bash, fish, powershell, or zsh) and quit") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: we mention
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok my bad,
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, it falls back to the auto-generated Cobra completion |
||
| flags.BoolP("version", "v", false, "Print version information and quit") | ||
|
|
||
| setFlagErrorFunc(dockerCli, cmd) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5486,11 +5486,8 @@ _docker_wait() { | |
| _docker_container_wait | ||
| } | ||
|
|
||
| COMPOSE_PLUGIN_PATH=$(docker info --format '{{json .ClientInfo.Plugins}}' | sed -n 's/.*"Path":"\([^"]\+docker-compose\)".*/\1/p') | ||
|
|
||
| _docker_compose() { | ||
| local completionCommand="__completeNoDesc" | ||
| local resultArray=($COMPOSE_PLUGIN_PATH $completionCommand compose) | ||
| __completeNoDesc() { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need to check if I updated this correctly. The intent is to:
|
||
| local resultArray=(docker __completeNoDesc $1) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of hard-coding would call |
||
| for value in "${words[@]:2}"; do | ||
| if [ -z "$value" ]; then | ||
| resultArray+=( "''" ) | ||
|
|
@@ -5503,6 +5500,18 @@ _docker_compose() { | |
| COMPREPLY=( $(compgen -W "${result}" -- "$current") ) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using I've had the same issue in my completion scripts 😄 |
||
| } | ||
|
|
||
| _docker_buildx() { | ||
| __completeNoDesc buildx | ||
| } | ||
|
|
||
| _docker_compose() { | ||
| __completeNoDesc compose | ||
| } | ||
|
|
||
| _docker_scan() { | ||
| __completeNoDesc scan | ||
| } | ||
|
|
||
| _docker() { | ||
| local previous_extglob_setting=$(shopt -p extglob) | ||
| shopt -s extglob | ||
|
|
@@ -5572,11 +5581,8 @@ _docker() { | |
| wait | ||
| ) | ||
|
|
||
| local known_plugin_commands=() | ||
|
|
||
| if [ -f "$COMPOSE_PLUGIN_PATH" ] ; then | ||
| known_plugin_commands+=("compose") | ||
| fi | ||
| PLUGINS_INSTALLED=$(docker info --format '{{range .ClientInfo.Plugins}}{{ .Name }} {{end}}') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: shouldn't we have a curated list here instead?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so. Every plugin should have the posibility to hook into completion.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps; otoh, if the plugin is there, adding completion for it doesn't really harm I guess.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually; currently that won't work, because we have the dedicated |
||
| local known_plugin_commands=($PLUGINS_INSTALLED) | ||
|
|
||
| local experimental_server_commands=( | ||
| checkpoint | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package completion | ||
|
|
||
| import ( | ||
| _ "embed" // needed to make embed work | ||
| "errors" | ||
| ) | ||
|
|
||
| var ( | ||
| //go:embed bash/docker | ||
| completionBash string | ||
|
|
||
| //go:embed fish/docker.fish | ||
| completionFish string | ||
|
|
||
| //go:embed zsh/_docker | ||
| completionZsh string | ||
|
|
||
| completions = map[string]string{ | ||
| "bash": completionBash, | ||
| "fish": completionFish, | ||
| "zsh": completionZsh, | ||
| } | ||
| ) | ||
|
|
||
| // Get returns the completion script for the given shell (bash, fish, or zsh). | ||
| func Get(shell string) (string, error) { | ||
| cs, ok := completions[shell] | ||
| if !ok { | ||
| return "", errors.New("no completion available for: " + shell) | ||
| } | ||
| return cs, nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine, but FYI, the "__completeNoDesc" form is an alias of the same Cobra command (
__complete). This means that in both casescmd.Name()will becobra.ShellCompRequestCmd, so you could simply check for that.