1# Generating Bash Completions For Your Own cobra.Command 2 3If you are using the generator you can create a completion command by running 4 5```bash 6cobra add completion 7``` 8 9Update the help text show how to install the bash_completion Linux show here [Kubectl docs show mac options](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion) 10 11Writing the shell script to stdout allows the most flexible use. 12 13```go 14// completionCmd represents the completion command 15var completionCmd = &cobra.Command{ 16 Use: "completion", 17 Short: "Generates bash completion scripts", 18 Long: `To load completion run 19 20. <(bitbucket completion) 21 22To configure your bash shell to load completions for each session add to your bashrc 23 24# ~/.bashrc or ~/.profile 25. <(bitbucket completion) 26`, 27 Run: func(cmd *cobra.Command, args []string) { 28 rootCmd.GenBashCompletion(os.Stdout); 29 }, 30} 31``` 32 33**Note:** The cobra generator may include messages printed to stdout for example if the config file is loaded, this will break the auto complete script 34 35 36## Example from kubectl 37 38Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows: 39 40```go 41package main 42 43import ( 44 "io/ioutil" 45 "os" 46 47 "k8s.io/kubernetes/pkg/kubectl/cmd" 48 "k8s.io/kubernetes/pkg/kubectl/cmd/util" 49) 50 51func main() { 52 kubectl := cmd.NewKubectlCommand(util.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) 53 kubectl.GenBashCompletionFile("out.sh") 54} 55``` 56 57`out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. 58 59## Have the completions code complete your 'nouns' 60 61### Static completion of nouns 62 63This method allows you to provide a pre-defined list of completion choices for your nouns using the `validArgs` field. 64For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. Simplified code from `kubectl get` looks like: 65 66```go 67validArgs []string = { "pod", "node", "service", "replicationcontroller" } 68 69cmd := &cobra.Command{ 70 Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", 71 Short: "Display one or many resources", 72 Long: get_long, 73 Example: get_example, 74 Run: func(cmd *cobra.Command, args []string) { 75 err := RunGet(f, out, cmd, args) 76 util.CheckErr(err) 77 }, 78 ValidArgs: validArgs, 79} 80``` 81 82Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like 83 84```bash 85# kubectl get [tab][tab] 86node pod replicationcontroller service 87``` 88 89### Plural form and shortcuts for nouns 90 91If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: 92 93```go 94argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } 95 96cmd := &cobra.Command{ 97 ... 98 ValidArgs: validArgs, 99 ArgAliases: argAliases 100} 101``` 102 103The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by 104the completion algorithm if entered manually, e.g. in: 105 106```bash 107# kubectl get rc [tab][tab] 108backend frontend database 109``` 110 111Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns 112in this example again instead of the replication controllers. 113 114### Dynamic completion of nouns 115 116In some cases it is not possible to provide a list of possible completions in advance. Instead, the list of completions must be determined at execution-time. Cobra provides two ways of defining such dynamic completion of nouns. Note that both these methods can be used along-side each other as long as they are not both used for the same command. 117 118**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion. It is therefore recommended to use *Custom Completions written in Go*. 119 120#### 1. Custom completions of nouns written in Go 121 122In a similar fashion as for static completions, you can use the `ValidArgsFunction` field to provide a Go function that Cobra will execute when it needs the list of completion choices for the nouns of a command. Note that either `ValidArgs` or `ValidArgsFunction` can be used for a single cobra command, but not both. 123Simplified code from `helm status` looks like: 124 125```go 126cmd := &cobra.Command{ 127 Use: "status RELEASE_NAME", 128 Short: "Display the status of the named release", 129 Long: status_long, 130 RunE: func(cmd *cobra.Command, args []string) { 131 RunGet(args[0]) 132 }, 133 ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 134 if len(args) != 0 { 135 return nil, cobra.ShellCompDirectiveNoFileComp 136 } 137 return getReleasesFromCluster(toComplete), cobra.ShellCompDirectiveNoFileComp 138 }, 139} 140``` 141Where `getReleasesFromCluster()` is a Go function that obtains the list of current Helm releases running on the Kubernetes cluster. 142Notice we put the `ValidArgsFunction` on the `status` subcommand. Let's assume the Helm releases on the cluster are: `harbor`, `notary`, `rook` and `thanos` then this dynamic completion will give results like 143 144```bash 145# helm status [tab][tab] 146harbor notary rook thanos 147``` 148You may have noticed the use of `cobra.ShellCompDirective`. These directives are bit fields allowing to control some shell completion behaviors for your particular completion. You can combine them with the bit-or operator such as `cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp` 149```go 150// Indicates an error occurred and completions should be ignored. 151ShellCompDirectiveError 152// Indicates that the shell should not add a space after the completion, 153// even if there is a single completion provided. 154ShellCompDirectiveNoSpace 155// Indicates that the shell should not provide file completion even when 156// no completion is provided. 157// This currently does not work for zsh or bash < 4 158ShellCompDirectiveNoFileComp 159// Indicates that the shell will perform its default behavior after completions 160// have been provided (this implies !ShellCompDirectiveNoSpace && !ShellCompDirectiveNoFileComp). 161ShellCompDirectiveDefault 162``` 163 164When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line. You therefore don't need to do this parsing yourself. For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function. 165 166##### Debugging 167 168Cobra achieves dynamic completions written in Go through the use of a hidden command called by the completion script. To debug your Go completion code, you can call this hidden command directly: 169```bash 170# helm __complete status har<ENTER> 171harbor 172:4 173Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr 174``` 175***Important:*** If the noun to complete is empty, you must pass an empty parameter to the `__complete` command: 176```bash 177# helm __complete status ""<ENTER> 178harbor 179notary 180rook 181thanos 182:4 183Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr 184``` 185Calling the `__complete` command directly allows you to run the Go debugger to troubleshoot your code. You can also add printouts to your code; Cobra provides the following functions to use for printouts in Go completion code: 186```go 187// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE 188// is set to a file path) and optionally prints to stderr. 189cobra.CompDebug(msg string, printToStdErr bool) { 190cobra.CompDebugln(msg string, printToStdErr bool) 191 192// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE 193// is set to a file path) and to stderr. 194cobra.CompError(msg string) 195cobra.CompErrorln(msg string) 196``` 197***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script. Instead, use the cobra-provided debugging traces functions mentioned above. 198 199#### 2. Custom completions of nouns written in Bash 200 201This method allows you to inject bash functions into the completion script. Those bash functions are responsible for providing the completion choices for your own completions. 202 203Some more actual code that works in kubernetes: 204 205```bash 206const ( 207 bash_completion_func = `__kubectl_parse_get() 208{ 209 local kubectl_output out 210 if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then 211 out=($(echo "${kubectl_output}" | awk '{print $1}')) 212 COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) 213 fi 214} 215 216__kubectl_get_resource() 217{ 218 if [[ ${#nouns[@]} -eq 0 ]]; then 219 return 1 220 fi 221 __kubectl_parse_get ${nouns[${#nouns[@]} -1]} 222 if [[ $? -eq 0 ]]; then 223 return 0 224 fi 225} 226 227__kubectl_custom_func() { 228 case ${last_command} in 229 kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) 230 __kubectl_get_resource 231 return 232 ;; 233 *) 234 ;; 235 esac 236} 237`) 238``` 239 240And then I set that in my command definition: 241 242```go 243cmds := &cobra.Command{ 244 Use: "kubectl", 245 Short: "kubectl controls the Kubernetes cluster manager", 246 Long: `kubectl controls the Kubernetes cluster manager. 247 248Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, 249 Run: runHelp, 250 BashCompletionFunction: bash_completion_func, 251} 252``` 253 254The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__kubectl_custom_func()` (`__<command-use>_custom_func()`) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__kubectl_customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__kubectl_custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! 255 256## Mark flags as required 257 258Most of the time completions will only show subcommands. But if a flag is required to make a subcommand work, you probably want it to show up when the user types [tab][tab]. Marking a flag as 'Required' is incredibly easy. 259 260```go 261cmd.MarkFlagRequired("pod") 262cmd.MarkFlagRequired("container") 263``` 264 265and you'll get something like 266 267```bash 268# kubectl exec [tab][tab][tab] 269-c --container= -p --pod= 270``` 271 272# Specify valid filename extensions for flags that take a filename 273 274In this example we use --filename= and expect to get a json or yaml file as the argument. To make this easier we annotate the --filename flag with valid filename extensions. 275 276```go 277 annotations := []string{"json", "yaml", "yml"} 278 annotation := make(map[string][]string) 279 annotation[cobra.BashCompFilenameExt] = annotations 280 281 flag := &pflag.Flag{ 282 Name: "filename", 283 Shorthand: "f", 284 Usage: usage, 285 Value: value, 286 DefValue: value.String(), 287 Annotations: annotation, 288 } 289 cmd.Flags().AddFlag(flag) 290``` 291 292Now when you run a command with this filename flag you'll get something like 293 294```bash 295# kubectl create -f 296test/ example/ rpmbuild/ 297hello.yml test.json 298``` 299 300So while there are many other files in the CWD it only shows me subdirs and those with valid extensions. 301 302# Specify custom flag completion 303 304As for nouns, Cobra provides two ways of defining dynamic completion of flags. Note that both these methods can be used along-side each other as long as they are not both used for the same flag. 305 306**Note**: *Custom Completions written in Go* will automatically work for other shell-completion scripts (e.g., Fish shell), while *Custom Completions written in Bash* will only work for Bash shell-completion. It is therefore recommended to use *Custom Completions written in Go*. 307 308## 1. Custom completions of flags written in Go 309 310To provide a Go function that Cobra will execute when it needs the list of completion choices for a flag, you must register the function in the following manner: 311 312```go 313flagName := "output" 314cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 315 return []string{"json", "table", "yaml"}, cobra.ShellCompDirectiveDefault 316}) 317``` 318Notice that calling `RegisterFlagCompletionFunc()` is done through the `command` with which the flag is associated. In our example this dynamic completion will give results like so: 319 320```bash 321# helm status --output [tab][tab] 322json table yaml 323``` 324 325### Debugging 326 327You can also easily debug your Go completion code for flags: 328```bash 329# helm __complete status --output "" 330json 331table 332yaml 333:4 334Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr 335``` 336***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script. Instead, use the cobra-provided debugging traces functions mentioned in the above section. 337 338## 2. Custom completions of flags written in Bash 339 340Alternatively, you can use bash code for flag custom completion. Similar to the filename 341completion and filtering using `cobra.BashCompFilenameExt`, you can specify 342a custom flag completion bash function with `cobra.BashCompCustom`: 343 344```go 345 annotation := make(map[string][]string) 346 annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"} 347 348 flag := &pflag.Flag{ 349 Name: "namespace", 350 Usage: usage, 351 Annotations: annotation, 352 } 353 cmd.Flags().AddFlag(flag) 354``` 355 356In addition add the `__kubectl_get_namespaces` implementation in the `BashCompletionFunction` 357value, e.g.: 358 359```bash 360__kubectl_get_namespaces() 361{ 362 local template 363 template="{{ range .items }}{{ .metadata.name }} {{ end }}" 364 local kubectl_out 365 if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then 366 COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) ) 367 fi 368} 369``` 370# Using bash aliases for commands 371 372You can also configure the `bash aliases` for the commands and they will also support completions. 373 374```bash 375alias aliasname=origcommand 376complete -o default -F __start_origcommand aliasname 377 378# and now when you run `aliasname` completion will make 379# suggestions as it did for `origcommand`. 380 381$) aliasname <tab><tab> 382completion firstcommand secondcommand 383``` 384