forked from mirror/cobra
Qualify custom bash func name (#730)
* Qualify custom bash func name - fixes issue where multiple cobra apps using custom bash completion would have their __custom_func collide - support fallback to plain __custom_func to maintain compatibility #694 * Improve tests for bash completion __custom_func - check for the correct number of occurrences of function name #694
This commit is contained in:
parent
ff0d02e855
commit
6fd8e29b07
|
@ -129,7 +129,13 @@ __%[1]s_handle_reply()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
|
if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
|
||||||
declare -F __custom_func >/dev/null && __custom_func
|
if declare -F __%[1]s_custom_func >/dev/null; then
|
||||||
|
# try command name qualified custom func
|
||||||
|
__%[1]s_custom_func
|
||||||
|
else
|
||||||
|
# otherwise fall back to unqualified for compatibility
|
||||||
|
declare -F ___custom_func >/dev/null && __custom_func
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# available in bash-completion >= 2, not always present on macOS
|
# available in bash-completion >= 2, not always present on macOS
|
||||||
|
|
|
@ -82,7 +82,7 @@ __kubectl_get_resource()
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
__custom_func() {
|
__kubectl_custom_func() {
|
||||||
case ${last_command} in
|
case ${last_command} in
|
||||||
kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
|
kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
|
||||||
__kubectl_get_resource
|
__kubectl_get_resource
|
||||||
|
@ -109,7 +109,7 @@ Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
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!
|
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!
|
||||||
|
|
||||||
## Have the completions code complete your 'nouns'
|
## Have the completions code complete your 'nouns'
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,13 @@ func check(t *testing.T, found, expected string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkNumOccurrences(t *testing.T, found, expected string, expectedOccurrences int) {
|
||||||
|
numOccurrences := strings.Count(found, expected)
|
||||||
|
if numOccurrences != expectedOccurrences {
|
||||||
|
t.Errorf("Expecting to contain %d occurrences of: \n %q\nGot %d:\n %q\n", expectedOccurrences, expected, numOccurrences, found)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkRegex(t *testing.T, found, pattern string) {
|
func checkRegex(t *testing.T, found, pattern string) {
|
||||||
matched, err := regexp.MatchString(pattern, found)
|
matched, err := regexp.MatchString(pattern, found)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -53,7 +60,7 @@ func runShellCheck(s string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// World worst custom function, just keep telling you to enter hello!
|
// World worst custom function, just keep telling you to enter hello!
|
||||||
const bashCompletionFunc = `__custom_func() {
|
const bashCompletionFunc = `__root_custom_func() {
|
||||||
COMPREPLY=( "hello" )
|
COMPREPLY=( "hello" )
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -150,7 +157,10 @@ func TestBashCompletions(t *testing.T) {
|
||||||
// check for required flags
|
// check for required flags
|
||||||
check(t, output, `must_have_one_flag+=("--introot=")`)
|
check(t, output, `must_have_one_flag+=("--introot=")`)
|
||||||
check(t, output, `must_have_one_flag+=("--persistent-filename=")`)
|
check(t, output, `must_have_one_flag+=("--persistent-filename=")`)
|
||||||
// check for custom completion function
|
// check for custom completion function with both qualified and unqualified name
|
||||||
|
checkNumOccurrences(t, output, `__custom_func`, 2) // 1. check existence, 2. invoke
|
||||||
|
checkNumOccurrences(t, output, `__root_custom_func`, 3) // 1. check existence, 2. invoke, 3. actual definition
|
||||||
|
// check for custom completion function body
|
||||||
check(t, output, `COMPREPLY=( "hello" )`)
|
check(t, output, `COMPREPLY=( "hello" )`)
|
||||||
// check for required nouns
|
// check for required nouns
|
||||||
check(t, output, `must_have_one_noun+=("pod")`)
|
check(t, output, `must_have_one_noun+=("pod")`)
|
||||||
|
|
Loading…
Reference in New Issue