From eb00885e487bf6e79468b631e9f1088015384b66 Mon Sep 17 00:00:00 2001 From: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com> Date: Tue, 29 Oct 2019 23:23:08 +0100 Subject: [PATCH 1/2] Use native zsh completion script generator So far, Skaffold used a wrapper code borrowed from kubectl to use the bash completion script for zsh. Cobra v0.0.5 introduced a native completion script generator for zsh. To support the `source <(...)` use-case, a minor tweak is necessary (also see https://github.com/spf13/cobra/pull/887) Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com> --- cmd/skaffold/app/cmd/completion.go | 180 +---------------------------- 1 file changed, 3 insertions(+), 177 deletions(-) diff --git a/cmd/skaffold/app/cmd/completion.go b/cmd/skaffold/app/cmd/completion.go index cd6a4801855..05491faf5cc 100644 --- a/cmd/skaffold/app/cmd/completion.go +++ b/cmd/skaffold/app/cmd/completion.go @@ -14,30 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -/* -NOTICE: The zsh wrapper code below is derived from the completion code -in kubectl (k8s.io/kubernetes/pkg/kubectl/cmd/completion/completion.go), -with the following license: - -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - package cmd import ( - "bytes" "fmt" "io" "os" @@ -65,157 +44,7 @@ const ( Additionally, you may want to output the completion to a file and source in your .bashrc ` - zshInitialization = `#compdef skaffold - -__skaffold_bash_source() { - alias shopt=':' - alias _expand=_bash_expand - alias _complete=_bash_comp - emulate -L sh - setopt kshglob noshglob braceexpand - - source "$@" -} - -__skaffold_type() { - # -t is not supported by zsh - if [ "$1" == "-t" ]; then - shift - - # fake Bash 4 to disable "complete -o nospace". Instead - # "compopt +-o nospace" is used in the code to toggle trailing - # spaces. We don't support that, but leave trailing spaces on - # all the time - if [ "$1" = "__skaffold_compopt" ]; then - echo builtin - return 0 - fi - fi - type "$@" -} - -__skaffold_compgen() { - local completions w - completions=( $(compgen "$@") ) || return $? - - # filter by given word as prefix - while [[ "$1" = -* && "$1" != -- ]]; do - shift - shift - done - if [[ "$1" == -- ]]; then - shift - fi - for w in "${completions[@]}"; do - if [[ "${w}" = "$1"* ]]; then - echo "${w}" - fi - done -} - -__skaffold_compopt() { - true # don't do anything. Not supported by bashcompinit in zsh -} - -__skaffold_ltrim_colon_completions() -{ - if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then - # Remove colon-word prefix from COMPREPLY items - local colon_word=${1%${1##*:}} - local i=${#COMPREPLY[*]} - while [[ $((--i)) -ge 0 ]]; do - COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} - done - fi -} - -__skaffold_get_comp_words_by_ref() { - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[${COMP_CWORD}-1]}" - words=("${COMP_WORDS[@]}") - cword=("${COMP_CWORD[@]}") -} - -__skaffold_filedir() { - local RET OLD_IFS w qw - - __skaffold_debug "_filedir $@ cur=$cur" - if [[ "$1" = \~* ]]; then - # somehow does not work. Maybe, zsh does not call this at all - eval echo "$1" - return 0 - fi - - OLD_IFS="$IFS" - IFS=$'\n' - if [ "$1" = "-d" ]; then - shift - RET=( $(compgen -d) ) - else - RET=( $(compgen -f) ) - fi - IFS="$OLD_IFS" - - IFS="," __skaffold_debug "RET=${RET[@]} len=${#RET[@]}" - - for w in ${RET[@]}; do - if [[ ! "${w}" = "${cur}"* ]]; then - continue - fi - if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then - qw="$(__skaffold_quote "${w}")" - if [ -d "${w}" ]; then - COMPREPLY+=("${qw}/") - else - COMPREPLY+=("${qw}") - fi - fi - done -} - -__skaffold_quote() { - if [[ $1 == \'* || $1 == \"* ]]; then - # Leave out first character - printf %q "${1:1}" - else - printf %q "$1" - fi -} - -autoload -U +X bashcompinit && bashcompinit - -# use word boundary patterns for BSD or GNU sed -LWORD='[[:<:]]' -RWORD='[[:>:]]' -if sed --help 2>&1 | grep -q GNU; then - LWORD='\<' - RWORD='\>' -fi - -__skaffold_convert_bash_to_zsh() { - sed \ - -e 's/declare -F/whence -w/' \ - -e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \ - -e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \ - -e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \ - -e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \ - -e "s/${LWORD}_filedir${RWORD}/__skaffold_filedir/g" \ - -e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__skaffold_get_comp_words_by_ref/g" \ - -e "s/${LWORD}__ltrim_colon_completions${RWORD}/__skaffold_ltrim_colon_completions/g" \ - -e "s/${LWORD}compgen${RWORD}/__skaffold_compgen/g" \ - -e "s/${LWORD}compopt${RWORD}/__skaffold_compopt/g" \ - -e "s/${LWORD}declare${RWORD}/builtin declare/g" \ - -e "s/\\\$(type${RWORD}/\$(__skaffold_type/g" \ - <<'BASH_COMPLETION_EOF' -` - - zshTail = ` -BASH_COMPLETION_EOF -} - -__skaffold_bash_source <(__skaffold_convert_bash_to_zsh) -_complete skaffold 2>/dev/null -` + zshCompdef = "\ncompdef _skaffold skaffold\n" ) func completion(cmd *cobra.Command, args []string) { @@ -245,11 +74,8 @@ func NewCmdCompletion() *cobra.Command { } func runCompletionZsh(cmd *cobra.Command, out io.Writer) { - io.WriteString(out, zshInitialization) - buf := new(bytes.Buffer) - rootCmd(cmd).GenBashCompletion(buf) - out.Write(buf.Bytes()) - io.WriteString(out, zshTail) + _ = rootCmd(cmd).GenZshCompletion(out) + _, _ = io.WriteString(out, zshCompdef) } func rootCmd(cmd *cobra.Command) *cobra.Command { From 0f4466dde91256c1085b2d1806dbadb283505245 Mon Sep 17 00:00:00 2001 From: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com> Date: Thu, 31 Oct 2019 10:29:38 +0100 Subject: [PATCH 2/2] Do not explicitly ignore write errors --- cmd/skaffold/app/cmd/completion.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/skaffold/app/cmd/completion.go b/cmd/skaffold/app/cmd/completion.go index 05491faf5cc..ccaed8c29f7 100644 --- a/cmd/skaffold/app/cmd/completion.go +++ b/cmd/skaffold/app/cmd/completion.go @@ -74,8 +74,8 @@ func NewCmdCompletion() *cobra.Command { } func runCompletionZsh(cmd *cobra.Command, out io.Writer) { - _ = rootCmd(cmd).GenZshCompletion(out) - _, _ = io.WriteString(out, zshCompdef) + rootCmd(cmd).GenZshCompletion(out) + io.WriteString(out, zshCompdef) } func rootCmd(cmd *cobra.Command) *cobra.Command {