1 # Generating Bash Completions For Your Own cobra.Command |
1 # Generating Bash Completions For Your cobra.Command |
2 |
2 |
3 If you are using the generator you can create a completion command by running |
3 Please refer to [Shell Completions](shell_completions.md) for details. |
4 |
4 |
5 ```bash |
5 ## Bash legacy dynamic completions |
6 cobra add completion |
|
7 ``` |
|
8 |
6 |
9 Update 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) |
7 For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the `ValidArgsFunction` solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side `ValidArgsFunction` and `RegisterFlagCompletionFunc()`, as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution. |
10 |
8 |
11 Writing the shell script to stdout allows the most flexible use. |
9 **Note**: Cobra's default `completion` command uses bash completion V2. If you are currently using Cobra's legacy dynamic completion solution, you should not use the default `completion` command but continue using your own. |
12 |
10 |
13 ```go |
11 The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions. |
14 // completionCmd represents the completion command |
|
15 var completionCmd = &cobra.Command{ |
|
16 Use: "completion", |
|
17 Short: "Generates bash completion scripts", |
|
18 Long: `To load completion run |
|
19 |
12 |
20 . <(bitbucket completion) |
13 Some code that works in kubernetes: |
21 |
|
22 To 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 |
|
38 Generating 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 |
|
41 package main |
|
42 |
|
43 import ( |
|
44 "io/ioutil" |
|
45 "os" |
|
46 |
|
47 "k8s.io/kubernetes/pkg/kubectl/cmd" |
|
48 "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
|
49 ) |
|
50 |
|
51 func 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 ## Creating your own custom functions |
|
60 |
|
61 Some more actual code that works in kubernetes: |
|
62 |
14 |
63 ```bash |
15 ```bash |
64 const ( |
16 const ( |
65 bash_completion_func = `__kubectl_parse_get() |
17 bash_completion_func = `__kubectl_parse_get() |
66 { |
18 { |
109 } |
61 } |
110 ``` |
62 ``` |
111 |
63 |
112 The `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! |
64 The `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! |
113 |
65 |
114 ## Have the completions code complete your 'nouns' |
66 Similarly, for flags: |
115 |
|
116 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: |
|
117 |
|
118 ```go |
|
119 validArgs []string = { "pod", "node", "service", "replicationcontroller" } |
|
120 |
|
121 cmd := &cobra.Command{ |
|
122 Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", |
|
123 Short: "Display one or many resources", |
|
124 Long: get_long, |
|
125 Example: get_example, |
|
126 Run: func(cmd *cobra.Command, args []string) { |
|
127 err := RunGet(f, out, cmd, args) |
|
128 util.CheckErr(err) |
|
129 }, |
|
130 ValidArgs: validArgs, |
|
131 } |
|
132 ``` |
|
133 |
|
134 Notice we put the "ValidArgs" on the "get" subcommand. Doing so will give results like |
|
135 |
|
136 ```bash |
|
137 # kubectl get [tab][tab] |
|
138 node pod replicationcontroller service |
|
139 ``` |
|
140 |
|
141 ## Plural form and shortcuts for nouns |
|
142 |
|
143 If your nouns have a number of aliases, you can define them alongside `ValidArgs` using `ArgAliases`: |
|
144 |
|
145 ```go |
|
146 argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } |
|
147 |
|
148 cmd := &cobra.Command{ |
|
149 ... |
|
150 ValidArgs: validArgs, |
|
151 ArgAliases: argAliases |
|
152 } |
|
153 ``` |
|
154 |
|
155 The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by |
|
156 the completion algorithm if entered manually, e.g. in: |
|
157 |
|
158 ```bash |
|
159 # kubectl get rc [tab][tab] |
|
160 backend frontend database |
|
161 ``` |
|
162 |
|
163 Note that without declaring `rc` as an alias, the completion algorithm would show the list of nouns |
|
164 in this example again instead of the replication controllers. |
|
165 |
|
166 ## Mark flags as required |
|
167 |
|
168 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. |
|
169 |
|
170 ```go |
|
171 cmd.MarkFlagRequired("pod") |
|
172 cmd.MarkFlagRequired("container") |
|
173 ``` |
|
174 |
|
175 and you'll get something like |
|
176 |
|
177 ```bash |
|
178 # kubectl exec [tab][tab][tab] |
|
179 -c --container= -p --pod= |
|
180 ``` |
|
181 |
|
182 # Specify valid filename extensions for flags that take a filename |
|
183 |
|
184 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. |
|
185 |
|
186 ```go |
|
187 annotations := []string{"json", "yaml", "yml"} |
|
188 annotation := make(map[string][]string) |
|
189 annotation[cobra.BashCompFilenameExt] = annotations |
|
190 |
|
191 flag := &pflag.Flag{ |
|
192 Name: "filename", |
|
193 Shorthand: "f", |
|
194 Usage: usage, |
|
195 Value: value, |
|
196 DefValue: value.String(), |
|
197 Annotations: annotation, |
|
198 } |
|
199 cmd.Flags().AddFlag(flag) |
|
200 ``` |
|
201 |
|
202 Now when you run a command with this filename flag you'll get something like |
|
203 |
|
204 ```bash |
|
205 # kubectl create -f |
|
206 test/ example/ rpmbuild/ |
|
207 hello.yml test.json |
|
208 ``` |
|
209 |
|
210 So while there are many other files in the CWD it only shows me subdirs and those with valid extensions. |
|
211 |
|
212 # Specify custom flag completion |
|
213 |
|
214 Similar to the filename completion and filtering using cobra.BashCompFilenameExt, you can specify |
|
215 a custom flag completion function with cobra.BashCompCustom: |
|
216 |
67 |
217 ```go |
68 ```go |
218 annotation := make(map[string][]string) |
69 annotation := make(map[string][]string) |
219 annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"} |
70 annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"} |
220 |
71 |