cobra: New zsh completion script seems broken
I just tried the zsh completion as merged recently via #646. Unfortunately, I couldn’t get it to work for example with skaffold (https://github.com/corneliusweig/skaffold/tree/upgrade-cobra).
The generated completion script looks ok (see below), but when I type skaffold <Tab><Tab>, I only get files from my current directory as suggestion instead of subcommands and options. I have sourced the generated completion script in a running zsh via source skaffold-completion.zsh.
/cc @rsteube @babysnakes (because you were active on the referenced PR)
#compdef _skaffold skaffold
function _skaffold {
local -a commands
_arguments -C \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:' \
"1: :->cmnds" \
"*::arg:->args"
case $state in
cmnds)
commands=(
"build:Builds the artifacts"
"completion:Output shell completion for the given shell (bash or zsh)"
"config:A set of commands for interacting with the Skaffold config."
"debug:Runs a pipeline file in debug mode"
"delete:Delete the deployed resources"
"deploy:Deploys the artifacts"
"dev:Runs a pipeline file in development mode"
"diagnose:Run a diagnostic on Skaffold"
"fix:Converts old Skaffold config to newest schema version"
"help:Help about any command"
"init:Automatically generate Skaffold configuration for deploying an application"
"run:Runs a pipeline file"
"version:Print the version information"
)
_describe "command" commands
;;
esac
case "$words[1]" in
build)
_skaffold_build
;;
completion)
_skaffold_completion
;;
config)
_skaffold_config
;;
debug)
_skaffold_debug
;;
delete)
_skaffold_delete
;;
deploy)
_skaffold_deploy
;;
dev)
_skaffold_dev
;;
diagnose)
_skaffold_diagnose
;;
fix)
_skaffold_fix
;;
help)
_skaffold_help
;;
init)
_skaffold_init
;;
run)
_skaffold_run
;;
version)
_skaffold_version
;;
esac
}
function _skaffold_build {
_arguments \
'(*-b *--build-image)'{\*-b,\*--build-image}'[Choose which artifacts to build. Artifacts with image names that contain the expression will be built only. Default is to build sources for all artifacts]:' \
'--cache-artifacts[Set to true to enable caching of artifacts]' \
'--cache-file[Specify the location of the cache file (default $HOME/.skaffold/cache)]:' \
'(-d --default-repo)'{-d,--default-repo}'[Default repository value (overrides global config)]:' \
'--enable-rpc[Enable gRPC for exposing Skaffold events (true by default for `skaffold dev`)]' \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'*--insecure-registry[Target registries for built images which are not secure]:' \
'(-n --namespace)'{-n,--namespace}'[Run deployments in the specified namespace]:' \
'(-o --output)'{-o,--output}'[Used in conjuction with --quiet flag. Format output with go-template. For full struct documentation, see https://godoc.org/github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/flags#BuildOutput]:' \
'(*-p *--profile)'{\*-p,\*--profile}'[Activate profiles by name]:' \
'(-q --quiet)'{-q,--quiet}'[Suppress the build output and print image built on success. See --output to format output.]' \
'--rpc-http-port[tcp port to expose event REST API over HTTP]:' \
'--rpc-port[tcp port to expose event API]:' \
'--skip-tests[Whether to skip the tests after building]' \
'--toot[Emit a terminal beep after the deploy is complete]' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_completion {
_arguments \
'(-h --help)'{-h,--help}'[help for completion]' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:' \
'1: :("bash" "zsh")'
}
function _skaffold_config {
local -a commands
_arguments -C \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:' \
"1: :->cmnds" \
"*::arg:->args"
case $state in
cmnds)
commands=(
"list:List all values set in the global Skaffold config"
"set:Set a value in the global Skaffold config"
"unset:Unset a value in the global Skaffold config"
)
_describe "command" commands
;;
esac
case "$words[1]" in
list)
_skaffold_config_list
;;
set)
_skaffold_config_set
;;
unset)
_skaffold_config_unset
;;
esac
}
function _skaffold_config_list {
_arguments \
'(-a --all)'{-a,--all}'[Show values for all kubecontexts]' \
'(-c --config)'{-c,--config}'[Path to Skaffold config]:' \
'(-k --kube-context)'{-k,--kube-context}'[Kubectl context to set values against]:' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_config_set {
_arguments \
'(-c --config)'{-c,--config}'[Path to Skaffold config]:' \
'(-g --global)'{-g,--global}'[Set value for global config]' \
'(-k --kube-context)'{-k,--kube-context}'[Kubectl context to set values against]:' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_config_unset {
_arguments \
'(-c --config)'{-c,--config}'[Path to Skaffold config]:' \
'(-g --global)'{-g,--global}'[Set value for global config]' \
'(-k --kube-context)'{-k,--kube-context}'[Kubectl context to set values against]:' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_debug {
_arguments \
'--cache-artifacts[Set to true to enable caching of artifacts]' \
'--cache-file[Specify the location of the cache file (default $HOME/.skaffold/cache)]:' \
'--cleanup[Delete deployments after dev or debug mode is interrupted]' \
'(-d --default-repo)'{-d,--default-repo}'[Default repository value (overrides global config)]:' \
'--enable-rpc[Enable gRPC for exposing Skaffold events (true by default for `skaffold dev`)]' \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'--force[Recreate kubernetes resources if necessary for deployment (warning: might cause downtime!)]' \
'*--insecure-registry[Target registries for built images which are not secure]:' \
'(*-l *--label)'{\*-l,\*--label}'[Add custom labels to deployed objects. Set multiple times for multiple labels]:' \
'(-n --namespace)'{-n,--namespace}'[Run deployments in the specified namespace]:' \
'--no-prune[Skip removing images and containers built by Skaffold]' \
'--no-prune-children[Skip removing layers reused by Skaffold]' \
'--port-forward[Port-forward exposed container ports within pods]' \
'(*-p *--profile)'{\*-p,\*--profile}'[Activate profiles by name]:' \
'--rpc-http-port[tcp port to expose event REST API over HTTP]:' \
'--rpc-port[tcp port to expose event API]:' \
'--skip-tests[Whether to skip the tests after building]' \
'--tail[Stream logs from deployed objects]' \
'--toot[Emit a terminal beep after the deploy is complete]' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_delete {
_arguments \
'(-d --default-repo)'{-d,--default-repo}'[Default repository value (overrides global config)]:' \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'(-n --namespace)'{-n,--namespace}'[Run deployments in the specified namespace]:' \
'(*-p *--profile)'{\*-p,\*--profile}'[Activate profiles by name]:' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_deploy {
_arguments \
'(-a --build-artifacts)'{-a,--build-artifacts}'[Filepath containing build output.
E.g. build.out created by running skaffold build --quiet {{json .}} > build.out]:' \
'(-d --default-repo)'{-d,--default-repo}'[Default repository value (overrides global config)]:' \
'--enable-rpc[Enable gRPC for exposing Skaffold events (true by default for `skaffold dev`)]' \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'--force[Recreate kubernetes resources if necessary for deployment (default false, warning: might cause downtime!)]' \
'(-i --images)'{-i,--images}'[A list of pre-built images to deploy]:' \
'(*-l *--label)'{\*-l,\*--label}'[Add custom labels to deployed objects. Set multiple times for multiple labels]:' \
'(-n --namespace)'{-n,--namespace}'[Run deployments in the specified namespace]:' \
'(*-p *--profile)'{\*-p,\*--profile}'[Activate profiles by name]:' \
'--rpc-http-port[tcp port to expose event REST API over HTTP]:' \
'--rpc-port[tcp port to expose event API]:' \
'--tail[Stream logs from deployed objects (default false)]' \
'--toot[Emit a terminal beep after the deploy is complete]' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_dev {
_arguments \
'--cache-artifacts[Set to true to enable caching of artifacts]' \
'--cache-file[Specify the location of the cache file (default $HOME/.skaffold/cache)]:' \
'--cleanup[Delete deployments after dev or debug mode is interrupted]' \
'(-d --default-repo)'{-d,--default-repo}'[Default repository value (overrides global config)]:' \
'--enable-rpc[Enable gRPC for exposing Skaffold events (true by default for `skaffold dev`)]' \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'--force[Recreate kubernetes resources if necessary for deployment (warning: might cause downtime!)]' \
'*--insecure-registry[Target registries for built images which are not secure]:' \
'(*-l *--label)'{\*-l,\*--label}'[Add custom labels to deployed objects. Set multiple times for multiple labels]:' \
'(-n --namespace)'{-n,--namespace}'[Run deployments in the specified namespace]:' \
'--no-prune[Skip removing images and containers built by Skaffold]' \
'--no-prune-children[Skip removing layers reused by Skaffold]' \
'--port-forward[Port-forward exposed container ports within pods]' \
'(*-p *--profile)'{\*-p,\*--profile}'[Activate profiles by name]:' \
'--rpc-http-port[tcp port to expose event REST API over HTTP]:' \
'--rpc-port[tcp port to expose event API]:' \
'--skip-tests[Whether to skip the tests after building]' \
'--tail[Stream logs from deployed objects]' \
'--toot[Emit a terminal beep after the deploy is complete]' \
'--trigger[How are changes detected? (polling, manual or notify)]:' \
'(*-w *--watch-image)'{\*-w,\*--watch-image}'[Choose which artifacts to watch. Artifacts with image names that contain the expression will be watched only. Default is to watch sources for all artifacts]:' \
'(-i --watch-poll-interval)'{-i,--watch-poll-interval}'[Interval (in ms) between two checks for file changes]:' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_diagnose {
_arguments \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'(*-p *--profile)'{\*-p,\*--profile}'[Activate profiles by name]:' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_fix {
_arguments \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'--overwrite[Overwrite original config with fixed config]' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_help {
_arguments \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_init {
_arguments \
'--analyze[Print all discoverable Dockerfiles and images in JSON format to stdout]' \
'(*-a *--artifact)'{\*-a,\*--artifact}'['\''='\''-delimited dockerfile/image pair to generate build artifact
(example: --artifact=/web/Dockerfile.web=gcr.io/web-project/image)]:' \
'--compose-file[Initialize from a docker-compose file]:' \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'--force[Force the generation of the Skaffold config]' \
'--skip-build[Skip generating build artifacts in Skaffold config]' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_run {
_arguments \
'--cache-artifacts[Set to true to enable caching of artifacts]' \
'--cache-file[Specify the location of the cache file (default $HOME/.skaffold/cache)]:' \
'--cleanup[Delete deployments after dev or debug mode is interrupted]' \
'(-d --default-repo)'{-d,--default-repo}'[Default repository value (overrides global config)]:' \
'--enable-rpc[Enable gRPC for exposing Skaffold events (true by default for `skaffold dev`)]' \
'(-f --filename)'{-f,--filename}'[Filename or URL to the pipeline file]:' \
'--force[Recreate kubernetes resources if necessary for deployment (warning: might cause downtime!)]' \
'*--insecure-registry[Target registries for built images which are not secure]:' \
'(*-l *--label)'{\*-l,\*--label}'[Add custom labels to deployed objects. Set multiple times for multiple labels]:' \
'(-n --namespace)'{-n,--namespace}'[Run deployments in the specified namespace]:' \
'--no-prune[Skip removing images and containers built by Skaffold]' \
'--no-prune-children[Skip removing layers reused by Skaffold]' \
'(*-p *--profile)'{\*-p,\*--profile}'[Activate profiles by name]:' \
'--rpc-http-port[tcp port to expose event REST API over HTTP]:' \
'--rpc-port[tcp port to expose event API]:' \
'--skip-tests[Whether to skip the tests after building]' \
'(-t --tag)'{-t,--tag}'[The optional custom tag to use for images which overrides the current Tagger configuration]:' \
'--tail[Stream logs from deployed objects (default false)]' \
'--toot[Emit a terminal beep after the deploy is complete]' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
function _skaffold_version {
_arguments \
'(-o --output)'{-o,--output}'[Format output with go-template. For full struct documentation, see https://godoc.org/github.com/GoogleContainerTools/skaffold/pkg/skaffold/version#Info]:' \
'--color[Specify the default output color in ANSI escape codes]:' \
'(-v --verbosity)'{-v,--verbosity}'[Log level (debug, info, warn, error, fatal, panic)]:'
}
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 3
- Comments: 19 (11 by maintainers)
can do - just a sec
Hey @babysnakes, thanks for your quick response. Indeed it works also on my system, when I do
skaffold completion zsh > $fpath/_skaffoldcompinitSo that is resolved then.
Now what about the direct sourcing, though. I was looking at the old code from the skaffold completion (which uses a zsh wrapper around the bash completion, see below). I wonder why that works without the indirection via a file. In other words, just doing a
source <(skaffold completion zsh)with the old version works without having to callcompinitor saving the output to a file on $fpath. Can you figure out why? I don’t know zsh completions at all 😕@corneliusweig i don’t remember it exactly but i did notice a small side effect with the explicit
compdefcall (or the missing_skaffoldcall). I think it was that when usingfpaththe completion initially needed a second<tab>to actually work (so on the very first try it probably just loaded the script).so instead of:
compdef _skaffold skaffoldmaybe sth. like this (compquote is only available during completion, else assume file is direcly sourced):if compquote '' 2>/dev/null; then _skaffold; else compdef _skaffold skaffold; fibtw. i did some more work on this here: https://github.com/rsteube/carapace
@babysnakes That does not seem to work either. I am using zsh 5.6.2 with oh-my-zsh.
I think that being able to source the generated script is a major use-case for cobra completion. For example, that is how
kubectl,minikube, orskaffoldrecommend to set up completion. Usually these commands would be put in your zshrc, so that one always gets the latest completion script. The indirection via a file seems unnecessary to me and it has the danger of becoming outdated.@rsteube Thanks for investigating this! I think it is safe to assume that
compinithas already been correctly initialized when a user tries tosource <(cobracmd completion zsh)or so. That means, that thecompdefstuff could be moved into the completion template like so:In my manual test that worked like a charm.
The question is: does the extra
compdefcall have any undesired side-effects when somebody puts the script into a file?@corneliusweig i think the magic happens here:
autoload -U +X bashcompinit && bashcompinitand the completion is probably then registered by_complete skaffold 2>/dev/null. Seems zsh supports bash completions which is why that script looks so unfamiliar to me: https://stackoverflow.com/a/3251836Regarding adding the completion without fpath this seems to be actually possible with manual invocation of
compdef(didn’t know about it so far), you still have to initialize the completion system first though. So something similar to this might work:This is certainly easier to use but skips all the caching mechanisms of zsh regarding the completion system. AFAIK those from fpath ~get cached~ in a
~.zcompdumpfile which speeds up terminal load time (each time you open a new terminal there is a noticable delay before you can start typing). Invoking a command to generate the completion adds even more to that.see http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Use-of-compinit
(seems i had some assumptions wrong regarding the
.zcompdumpfile, look at the documentation for a correct explanation)Hey @corneliusweig, Let’s tackle the sourcing issue later (I’m not even sure what it takes, I have to look).
First let’s get it working. I installed docker with oh-my-zsh - default installation, didn’t do anything beside the install command - and at first it didn’t work. however, after I ran
compinitit did work (checkout this ticket). Does it help in your case? if not can you typescaffoldand thenCTRL-X ?and send me the generated file?