completion.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package cmd
  14. import (
  15. "bytes"
  16. "io"
  17. "github.com/spf13/cobra"
  18. cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
  19. )
  20. const (
  21. completion_long = `Output shell completion code for the given shell (bash or zsh).
  22. This command prints shell code which must be evaluation to provide interactive
  23. completion of kubectl commands.
  24. `
  25. completion_example = `
  26. $ source <(kubectl completion bash)
  27. will load the kubectl completion code for bash. Note that this depends on the
  28. bash-completion framework. It must be sourced before sourcing the kubectl
  29. completion, e.g. on the Mac:
  30. $ brew install bash-completion
  31. $ source $(brew --prefix)/etc/bash_completion
  32. $ source <(kubectl completion bash)
  33. If you use zsh*, the following will load kubectl zsh completion:
  34. $ source <(kubectl completion zsh)
  35. * zsh completions are only supported in versions of zsh >= 5.2`
  36. )
  37. var (
  38. completion_shells = map[string]func(out io.Writer, cmd *cobra.Command) error{
  39. "bash": runCompletionBash,
  40. "zsh": runCompletionZsh,
  41. }
  42. )
  43. func NewCmdCompletion(f *cmdutil.Factory, out io.Writer) *cobra.Command {
  44. shells := []string{}
  45. for s := range completion_shells {
  46. shells = append(shells, s)
  47. }
  48. cmd := &cobra.Command{
  49. Use: "completion SHELL",
  50. Short: "Output shell completion code for the given shell (bash or zsh)",
  51. Long: completion_long,
  52. Example: completion_example,
  53. Run: func(cmd *cobra.Command, args []string) {
  54. err := RunCompletion(f, out, cmd, args)
  55. cmdutil.CheckErr(err)
  56. },
  57. ValidArgs: shells,
  58. }
  59. return cmd
  60. }
  61. func RunCompletion(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
  62. if len(args) == 0 {
  63. return cmdutil.UsageError(cmd, "Shell not specified.")
  64. }
  65. if len(args) > 1 {
  66. return cmdutil.UsageError(cmd, "Too many arguments. Expected only the shell type.")
  67. }
  68. run, found := completion_shells[args[0]]
  69. if !found {
  70. return cmdutil.UsageError(cmd, "Unsupported shell type %q.", args[0])
  71. }
  72. return run(out, cmd.Parent())
  73. }
  74. func runCompletionBash(out io.Writer, kubectl *cobra.Command) error {
  75. return kubectl.GenBashCompletion(out)
  76. }
  77. func runCompletionZsh(out io.Writer, kubectl *cobra.Command) error {
  78. zsh_initialilzation := `# Copyright 2016 The Kubernetes Authors.
  79. #
  80. # Licensed under the Apache License, Version 2.0 (the "License");
  81. # you may not use this file except in compliance with the License.
  82. # You may obtain a copy of the License at
  83. #
  84. # http://www.apache.org/licenses/LICENSE-2.0
  85. #
  86. # Unless required by applicable law or agreed to in writing, software
  87. # distributed under the License is distributed on an "AS IS" BASIS,
  88. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  89. # See the License for the specific language governing permissions and
  90. # limitations under the License.
  91. __kubectl_bash_source() {
  92. alias shopt=':'
  93. alias _expand=_bash_expand
  94. alias _complete=_bash_comp
  95. emulate -L sh
  96. setopt kshglob noshglob braceexpand
  97. source "$@"
  98. }
  99. __kubectl_type() {
  100. # -t is not supported by zsh
  101. if [ "$1" == "-t" ]; then
  102. shift
  103. # fake Bash 4 to disable "complete -o nospace". Instead
  104. # "compopt +-o nospace" is used in the code to toggle trailing
  105. # spaces. We don't support that, but leave trailing spaces on
  106. # all the time
  107. if [ "$1" = "__kubectl_compopt" ]; then
  108. echo builtin
  109. return 0
  110. fi
  111. fi
  112. type "$@"
  113. }
  114. __kubectl_compgen() {
  115. local completions w
  116. completions=( $(compgen "$@") ) || return $?
  117. # filter by given word as prefix
  118. while [[ "$1" = -* && "$1" != -- ]]; do
  119. shift
  120. shift
  121. done
  122. if [[ "$1" == -- ]]; then
  123. shift
  124. fi
  125. for w in "${completions[@]}"; do
  126. if [[ "${w}" = "$1"* ]]; then
  127. echo "${w}"
  128. fi
  129. done
  130. }
  131. __kubectl_compopt() {
  132. true # don't do anything. Not supported by bashcompinit in zsh
  133. }
  134. __kubectl_declare() {
  135. if [ "$1" == "-F" ]; then
  136. whence -w "$@"
  137. else
  138. builtin declare "$@"
  139. fi
  140. }
  141. __kubectl_ltrim_colon_completions()
  142. {
  143. if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
  144. # Remove colon-word prefix from COMPREPLY items
  145. local colon_word=${1%${1##*:}}
  146. local i=${#COMPREPLY[*]}
  147. while [[ $((--i)) -ge 0 ]]; do
  148. COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
  149. done
  150. fi
  151. }
  152. __kubectl_get_comp_words_by_ref() {
  153. cur="${COMP_WORDS[COMP_CWORD]}"
  154. prev="${COMP_WORDS[${COMP_CWORD}-1]}"
  155. words=("${COMP_WORDS[@]}")
  156. cword=("${COMP_CWORD[@]}")
  157. }
  158. __kubectl_filedir() {
  159. local RET OLD_IFS w qw
  160. __debug "_filedir $@ cur=$cur"
  161. if [[ "$1" = \~* ]]; then
  162. # somehow does not work. Maybe, zsh does not call this at all
  163. eval echo "$1"
  164. return 0
  165. fi
  166. OLD_IFS="$IFS"
  167. IFS=$'\n'
  168. if [ "$1" = "-d" ]; then
  169. shift
  170. RET=( $(compgen -d) )
  171. else
  172. RET=( $(compgen -f) )
  173. fi
  174. IFS="$OLD_IFS"
  175. IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
  176. for w in ${RET[@]}; do
  177. if [[ ! "${w}" = "${cur}"* ]]; then
  178. continue
  179. fi
  180. if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
  181. qw="$(__kubectl_quote "${w}")"
  182. if [ -d "${w}" ]; then
  183. COMPREPLY+=("${qw}/")
  184. else
  185. COMPREPLY+=("${qw}")
  186. fi
  187. fi
  188. done
  189. }
  190. __kubectl_quote() {
  191. if [[ $1 == \'* || $1 == \"* ]]; then
  192. # Leave out first character
  193. printf %q "${1:1}"
  194. else
  195. printf %q "$1"
  196. fi
  197. }
  198. autoload -U +X compinit && compinit
  199. autoload -U +X bashcompinit && bashcompinit
  200. # use word boundary patterns for BSD or GNU sed
  201. LWORD='[[:<:]]'
  202. RWORD='[[:>:]]'
  203. if sed --help 2>&1 | grep -q GNU; then
  204. LWORD='\<'
  205. RWORD='\>'
  206. fi
  207. __kubectl_bash_source <(sed \
  208. -e 's/declare -F/whence -w/' \
  209. -e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
  210. -e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
  211. -e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
  212. -e "s/${LWORD}_filedir${RWORD}/__kubectl_filedir/g" \
  213. -e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__kubectl_get_comp_words_by_ref/g" \
  214. -e "s/${LWORD}__ltrim_colon_completions${RWORD}/__kubectl_ltrim_colon_completions/g" \
  215. -e "s/${LWORD}compgen${RWORD}/__kubectl_compgen/g" \
  216. -e "s/${LWORD}compopt${RWORD}/__kubectl_compopt/g" \
  217. -e "s/${LWORD}declare${RWORD}/__kubectl_declare/g" \
  218. -e "s/\\\$(type${RWORD}/\$(__kubectl_type/g" \
  219. <<'BASH_COMPLETION_EOF'
  220. `
  221. out.Write([]byte(zsh_initialilzation))
  222. buf := new(bytes.Buffer)
  223. kubectl.GenBashCompletion(buf)
  224. out.Write(buf.Bytes())
  225. zsh_tail := `
  226. BASH_COMPLETION_EOF
  227. )
  228. `
  229. out.Write([]byte(zsh_tail))
  230. return nil
  231. }