1# Generating Bash Completions For Your Own cobra.Command
2
3Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows:
4
5```go
6package main
7
8import (
9	"io/ioutil"
10	"os"
11
12	"k8s.io/kubernetes/pkg/kubectl/cmd"
13	"k8s.io/kubernetes/pkg/kubectl/cmd/util"
14)
15
16func main() {
17	kubectl := cmd.NewKubectlCommand(util.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
18	kubectl.GenBashCompletionFile("out.sh")
19}
20```
21
22`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
24## Creating your own custom functions
25
26Some more actual code that works in kubernetes:
27
28```bash
29const (
30        bash_completion_func = `__kubectl_parse_get()
31{
32    local kubectl_output out
33    if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
34        out=($(echo "${kubectl_output}" | awk '{print $1}'))
35        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
36    fi
37}
38
39__kubectl_get_resource()
40{
41    if [[ ${#nouns[@]} -eq 0 ]]; then
42        return 1
43    fi
44    __kubectl_parse_get ${nouns[${#nouns[@]} -1]}
45    if [[ $? -eq 0 ]]; then
46        return 0
47    fi
48}
49
50__custom_func() {
51    case ${last_command} in
52        kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
53            __kubectl_get_resource
54            return
55            ;;
56        *)
57            ;;
58    esac
59}
60`)
61```
62
63And then I set that in my command definition:
64
65```go
66cmds := &cobra.Command{
67	Use:   "kubectl",
68	Short: "kubectl controls the Kubernetes cluster manager",
69	Long: `kubectl controls the Kubernetes cluster manager.
70
71Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
72	Run: runHelp,
73	BashCompletionFunction: bash_completion_func,
74}
75```
76
77The `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
79## Have the completions code complete your 'nouns'
80
81In 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:
82
83```go
84validArgs []string = { "pod", "node", "service", "replicationcontroller" }
85
86cmd := &cobra.Command{
87	Use:     "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
88	Short:   "Display one or many resources",
89	Long:    get_long,
90	Example: get_example,
91	Run: func(cmd *cobra.Command, args []string) {
92		err := RunGet(f, out, cmd, args)
93		util.CheckErr(err)
94	},
95	ValidArgs: validArgs,
96}
97```
98
99Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like
100
101```bash
102# kubectl get [tab][tab]
103node                 pod                    replicationcontroller  service
104```
105
106## Plural form and shortcuts for nouns
107
108If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
109
110```go
111argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
112
113cmd := &cobra.Command{
114    ...
115	ValidArgs:  validArgs,
116	ArgAliases: argAliases
117}
118```
119
120The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by
121the completion algorithm if entered manually, e.g. in:
122
123```bash
124# kubectl get rc [tab][tab]
125backend        frontend       database
126```
127
128Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns
129in this example again instead of the replication controllers.
130
131## Mark flags as required
132
133Most 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.
134
135```go
136cmd.MarkFlagRequired("pod")
137cmd.MarkFlagRequired("container")
138```
139
140and you'll get something like
141
142```bash
143# kubectl exec [tab][tab][tab]
144-c            --container=  -p            --pod=
145```
146
147# Specify valid filename extensions for flags that take a filename
148
149In 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.
150
151```go
152	annotations := []string{"json", "yaml", "yml"}
153	annotation := make(map[string][]string)
154	annotation[cobra.BashCompFilenameExt] = annotations
155
156	flag := &pflag.Flag{
157		Name:        "filename",
158		Shorthand:   "f",
159		Usage:       usage,
160		Value:       value,
161		DefValue:    value.String(),
162		Annotations: annotation,
163	}
164	cmd.Flags().AddFlag(flag)
165```
166
167Now when you run a command with this filename flag you'll get something like
168
169```bash
170# kubectl create -f
171test/                         example/                      rpmbuild/
172hello.yml                     test.json
173```
174
175So while there are many other files in the CWD it only shows me subdirs and those with valid extensions.
176
177# Specify custom flag completion
178
179Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specify
180a custom flag completion function with cobra.BashCompCustom:
181
182```go
183	annotation := make(map[string][]string)
184	annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
185
186	flag := &pflag.Flag{
187		Name:        "namespace",
188		Usage:       usage,
189		Annotations: annotation,
190	}
191	cmd.Flags().AddFlag(flag)
192```
193
194In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction`
195value, e.g.:
196
197```bash
198__kubectl_get_namespaces()
199{
200    local template
201    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
202    local kubectl_out
203    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
204        COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
205    fi
206}
207```
208# Using bash aliases for commands
209
210You can also configure the `bash aliases` for the commands and they will also support completions.
211
212```bash
213alias aliasname=origcommand
214complete -o default -F __start_origcommand aliasname
215
216# and now when you run `aliasname` completion will make
217# suggestions as it did for `origcommand`.
218
219$) aliasname <tab><tab>
220completion     firstcommand   secondcommand
221```
222