1 # Generating Bash Completions For Your Own cobra.Command
3 Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows:
12 "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
16 kubectl := cmd.NewFactory(nil).NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard)
17 kubectl.GenBashCompletionFile("out.sh")
21 `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.
23 ## Creating your own custom functions
25 Some more actual code that works in kubernetes:
29 bash_completion_func = `__kubectl_parse_get()
31 local kubectl_output out
32 if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
33 out=($(echo "${kubectl_output}" | awk '{print $1}'))
34 COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
38 __kubectl_get_resource()
40 if [[ ${#nouns[@]} -eq 0 ]]; then
43 __kubectl_parse_get ${nouns[${#nouns[@]} -1]}
44 if [[ $? -eq 0 ]]; then
50 case ${last_command} in
51 kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
52 __kubectl_get_resource
62 And then I set that in my command definition:
65 cmds := &cobra.Command{
67 Short: "kubectl controls the Kubernetes cluster manager",
68 Long: `kubectl controls the Kubernetes cluster manager.
70 Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
72 BashCompletionFunction: bash_completion_func,
76 The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__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 `__customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__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!
78 ## Have the completions code complete your 'nouns'
80 In the above example "pod" was assumed to already be typed. But 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:
83 validArgs []string = { "pod", "node", "service", "replicationcontroller" }
85 cmd := &cobra.Command{
86 Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
87 Short: "Display one or many resources",
90 Run: func(cmd *cobra.Command, args []string) {
91 err := RunGet(f, out, cmd, args)
98 Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like
101 # kubectl get [tab][tab]
102 node pod replicationcontroller service
105 ## Plural form and shortcuts for nouns
107 If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
110 argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
112 cmd := &cobra.Command{
114 ValidArgs: validArgs,
115 ArgAliases: argAliases
119 The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by
120 the completion algorithm if entered manually, e.g. in:
123 # kubectl get rc [tab][tab]
124 backend frontend database
127 Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns
128 in this example again instead of the replication controllers.
130 ## Mark flags as required
132 Most 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.
135 cmd.MarkFlagRequired("pod")
136 cmd.MarkFlagRequired("container")
139 and you'll get something like
142 # kubectl exec [tab][tab][tab]
143 -c --container= -p --pod=
146 # Specify valid filename extensions for flags that take a filename
148 In 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.
151 annotations := []string{"json", "yaml", "yml"}
152 annotation := make(map[string][]string)
153 annotation[cobra.BashCompFilenameExt] = annotations
160 DefValue: value.String(),
161 Annotations: annotation,
163 cmd.Flags().AddFlag(flag)
166 Now when you run a command with this filename flag you'll get something like
170 test/ example/ rpmbuild/
174 So while there are many other files in the CWD it only shows me subdirs and those with valid extensions.
176 # Specifiy custom flag completion
178 Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specifiy
179 a custom flag completion function with cobra.BashCompCustom:
182 annotation := make(map[string][]string)
183 annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"}
188 Annotations: annotation,
190 cmd.Flags().AddFlag(flag)
193 In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction`
197 __kubectl_get_namespaces()
200 template="{{ range .items }}{{ .metadata.name }} {{ end }}"
202 if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
203 COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )