Skip to content

Instantly share code, notes, and snippets.

@xtao
Forked from eparis/gist:2380a2daa7ff6c0b52a6
Last active May 14, 2024 08:07
Show Gist options
  • Save xtao/a98a88fb21036b1900d7 to your computer and use it in GitHub Desktop.
Save xtao/a98a88fb21036b1900d7 to your computer and use it in GitHub Desktop.
etcdctl bash completions
#!/bin/bash
__debug()
{
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
fi
}
__index_of_word()
{
local w word=$1
shift
index=0
for w in "$@"; do
[[ $w = "$word" ]] && return
index=$((index+1))
done
index=-1
}
__contains_word()
{
local w word=$1; shift
for w in "$@"; do
[[ $w = "$word" ]] && return
done
return 1
}
__handle_reply()
{
__debug "${FUNCNAME}"
case $cur in
-*)
compopt -o nospace
local allflags
if [ ${#must_have_one_flag[@]} -ne 0 ]; then
allflags=("${must_have_one_flag[@]}")
else
allflags=("${flags[*]} ${two_word_flags[*]}")
fi
COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") )
[[ $COMPREPLY == *= ]] || compopt +o nospace
return 0;
;;
esac
# check if we are handling a flag with special work handling
local index
__index_of_word "${prev}" "${flags_with_completion[@]}"
if [[ ${index} -ge 0 ]]; then
${flags_completion[${index}]}
return
fi
# we are parsing a flag and don't have a special handler, no completion
if [[ ${cur} != "${words[cword]}" ]]; then
return
fi
local completions
if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
completions=("${must_have_one_flag[@]}")
elif [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
completions=("${must_have_one_noun[@]}")
else
completions=("${commands[@]}")
fi
COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") )
if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
declare -F __custom_func >/dev/null && __custom_func
fi
}
# The arguments should be in the form "ext1|ext2|extn"
__handle_filename_extension_flag()
{
local ext="$1"
_filedir "@(${ext})"
}
__handle_flag()
{
__debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
# if a command required a flag, and we found it, unset must_have_one_flag()
local flagname=${words[c]}
# if the word contained an =
if [[ ${words[c]} == *"="* ]]; then
flagname=${flagname%=*} # strip everything after the =
flagname="${flagname}=" # but put the = back
fi
__debug "${FUNCNAME}: looking for ${flagname}"
if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then
must_have_one_flag=()
fi
# skip the argument to a two word flag
if __contains_word "${words[c]}" "${two_word_flags[@]}"; then
c=$((c+1))
# if we are looking for a flags value, don't show commands
if [[ $c -eq $cword ]]; then
commands=()
fi
fi
# skip the flag itself
c=$((c+1))
}
__handle_noun()
{
__debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
must_have_one_noun=()
fi
nouns+=("${words[c]}")
c=$((c+1))
}
__handle_command()
{
__debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
local next_command
if [[ -n ${last_command} ]]; then
next_command="_${last_command}_${words[c]}"
else
next_command="_${words[c]}"
fi
c=$((c+1))
__debug "${FUNCNAME}: looking for ${next_command}"
declare -F $next_command >/dev/null && $next_command
}
__handle_word()
{
if [[ $c -ge $cword ]]; then
__handle_reply
return
fi
__debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
if [[ "${words[c]}" == -* ]]; then
__handle_flag
elif __contains_word "${words[c]}" "${commands[@]}"; then
__handle_command
else
__handle_noun
fi
__handle_word
}
__etcdctl_get_path()
{
compopt +o nospace
local etcdctl_out
if etcdctl_out=$(etcdctl ls "${dir}" 2>/dev/null); then
COMPREPLY=( $( compgen -W "${etcdctl_out[*]}" -- "${cur}" ) )
echo "dir=${dir} comp=${COMPREPLY[@]}" >> /tmp/debug
if [[ ${#COMPREPLY[@]} -gt 0 ]]; then
compopt -o nospace
return 0
fi
fi
return 1
}
__etcdctl_complete_path()
{
if [[ ${#nouns[@]} -gt 0 ]]; then
return 1
fi
local dir
dir="${cur}"
echo -n "one: " >> /tmp/debug
__etcdctl_get_path && return
echo -n "two: " >> /tmp/debug
dir=$(dirname ${cur} 2>/dev/null)
__etcdctl_get_path && return
}
__custom_func() {
case ${last_command} in
etcdctl_ls | etcdctl_get | etcdctl_set | etcdctl_rm | etcdctl_rmdir )
__etcdctl_complete_path
return
;;
*)
;;
esac
}
_etcdctl_backup()
{
last_command="etcdctl_backup"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--backup-dir=")
flags+=("--data-dir=")
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_cluster-health()
{
last_command="etcdctl_cluster-health"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_mk()
{
last_command="etcdctl_mk"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--ttl=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_mkdir()
{
last_command="etcdctl_mkdir"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--ttl=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_rm()
{
last_command="etcdctl_rm"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--dir")
flags+=("--help")
flags+=("-h")
flags+=("--recursive")
flags+=("--with-index=")
flags+=("--with-value=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_rmdir()
{
last_command="etcdctl_rmdir"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_get()
{
last_command="etcdctl_get"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--sort")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_ls()
{
last_command="etcdctl_ls"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--p")
flags+=("--recursive")
flags+=("--sort")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_set()
{
last_command="etcdctl_set"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--swap-with-index=")
flags+=("--swap-with-value=")
flags+=("--ttl=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_setdir()
{
last_command="etcdctl_setdir"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--ttl=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_update()
{
last_command="etcdctl_update"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--ttl=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_updatedir()
{
last_command="etcdctl_updatedir"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--ttl=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_watch()
{
last_command="etcdctl_watch"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--after-index=")
flags+=("--forever")
flags+=("--help")
flags+=("-h")
flags+=("--recursive")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_exec-watch()
{
last_command="etcdctl_exec-watch"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--after-index=")
flags+=("--help")
flags+=("-h")
flags+=("--recursive")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_member_list()
{
last_command="etcdctl_member_list"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_member_add()
{
last_command="etcdctl_member_add"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_member_remove()
{
last_command="etcdctl_member_remove"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_member()
{
last_command="etcdctl_member"
commands=()
commands+=("list")
commands+=("add")
commands+=("remove")
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_import()
{
last_command="etcdctl_import"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--c=")
flags+=("--help")
flags+=("-h")
flags+=("--snap=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_genbash()
{
last_command="etcdctl_genbash"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
flags+=("--outfile=")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl_help()
{
last_command="etcdctl_help"
commands=()
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_noun=()
}
_etcdctl()
{
last_command="etcdctl"
commands=()
commands+=("backup")
commands+=("cluster-health")
commands+=("mk")
commands+=("mkdir")
commands+=("rm")
commands+=("rmdir")
commands+=("get")
commands+=("ls")
commands+=("set")
commands+=("setdir")
commands+=("update")
commands+=("updatedir")
commands+=("watch")
commands+=("exec-watch")
commands+=("member")
commands+=("import")
commands+=("genbash")
commands+=("help")
flags=()
two_word_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--ca-file=")
flags+=("--cert-file=")
flags+=("--debug")
flags+=("--help")
flags+=("-h")
flags+=("--key-file=")
flags+=("--no-sync")
flags+=("--output=")
two_word_flags+=("-o")
flags+=("--peers=")
two_word_flags+=("-C")
must_have_one_flag=()
must_have_one_noun=()
}
__start_etcdctl()
{
local cur prev words cword
#_init_completion -s || return
local cur=$2 prev=$3 words=("${COMP_WORDS[@]}") cword=$COMP_CWORD
local c=0
local flags=()
local two_word_flags=()
local flags_with_completion=()
local flags_completion=()
local commands=("etcdctl")
local must_have_one_flag=()
local must_have_one_noun=()
local last_command
local nouns=()
__handle_word
}
complete -F __start_etcdctl etcdctl
# ex: ts=4 sw=4 et filetype=sh
@kuchaguangjie
Copy link

This is not up to date now. e.g lease command is not found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment