Spdk/scripts/bash-completion/spdk
Michal Berger 3b2eb02bc9 scripts/bash-completion: Adjustments for older Bash versions
Older versions of Bash don't handle -v option in array context very
well. Also, some of the compopt options are missing in older versions
so make sure stderr stays silent.

Signed-off-by: Michal Berger <michal.berger@intel.com>
Change-Id: I81989940e8b25e2dbeed91f97fed5aa65e7df656
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14130
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Krzysztof Karas <krzysztof.karas@intel.com>
2023-05-09 17:58:11 +08:00

269 lines
6.1 KiB
Plaintext

# shellcheck disable=SC2016,SC2207
_get_help() {
"$@" -h 2>&1
}
_get_help_opt() {
# Fetch all the optional parameters with help from _parse_help()
_parse_help - < <(printf '%s\n' "$@")
}
_get_help_pos() {
local pos
# Fetch all the positional parameters, i.e. get first word prefixed
# with 20h x 2. This may not be 100% accurate. Also, it won't return
# any usable strings, it's just meant to point out what type of
# mandatory argument given method depends on, like bdev_name, etc.
# TODO: separate completion for such arguments, e.g., get all bdevs
# for parameter like bdev_name?
while read -r; do
[[ $REPLY =~ ^\ {2}[^\ -] ]] || continue
read -r pos _ <<< "$REPLY" && echo "$pos"
done < <(printf '%s\n' "$@")
}
_get_default_rpc_methods() {
local aliases method names
# Don't squash whitespaces, slurp the entire line
while read -r; do
# Each method name seems to be prefixed with 20h x 4. Then it can
# be followed with list of aliases enclosed inside (). Example:
# ioat_scan_accel_module
[[ $REPLY =~ ^\ {4}([a-z]+(_[a-z]+)*)(\ *\((.+)\))? ]] || continue
names=("${BASH_REMATCH[1]}")
if [[ $SPDK_RPC_ALIASES == yes ]] && [[ -n ${BASH_REMATCH[4]} ]]; then
IFS=", " read -ra aliases <<< "${BASH_REMATCH[4]}"
names+=("${aliases[@]}")
fi
for method in "${names[@]}"; do
rpc_methods["$method"]=1
done
done < <(_get_help "$1" 2> /dev/null)
}
_get_rpc_methods() {
local method methods
_get_default_rpc_methods "$1"
methods=($("$1" -s "$rpc_sock" rpc_get_methods 2> /dev/null)) || return 0
((${#methods[@]} > 0)) || return 0
# Kill the json flavor
methods=("${methods[@]//+(\"|,| )/}")
unset -v "methods[0]" "methods[-1]" # []
for method in "${methods[@]}"; do
rpc_methods["$method"]=1
done
}
_get_help_rpc_method() {
local rpc=$1
local method=$2
local rpc_help opt
mapfile -t rpc_help < <(_get_help "$rpc" "$method")
_get_help_pos "${rpc_help[@]}"
_get_help_opt "${rpc_help[@]}"
}
_is_rpc_method() {
local word=$1
[[ -n $word && -n ${rpc_methods["$word"]} ]]
}
_method_in_words() {
for word in "${words[@]}"; do
if _is_rpc_method "$word"; then
echo "$word"
return 0
fi
done
return 1
}
_set_rpc_sock() {
# Look for unix sock each app creates upon its execution. In
# first instance, check the cmdline for an -s arg, if it's
# followed by the path to the sock, use it.
local word
for ((word = 0; word < ${#words[@]}; word++)); do
if [[ ${words[word]} == -s && -S ${words[word + 1]} ]]; then
rpc_sock=${words[word + 1]}
return 0
fi
done
# default .sock
[[ -S /var/tmp/spdk.sock ]] && rpc_sock=/var/tmp/spdk.sock
return 0
}
_spdk_opt_to_complete() {
local opt=$1
case "$opt" in
--pci-blocked | -B | --pci-allowed | -A)
local pcis
if [[ -e /sys/bus/pci/devices ]]; then
pcis=(/sys/bus/pci/devices/*)
pcis=("${pcis[@]##*/}")
fi
COMPREPLY=($(compgen -W '${pcis[*]}' -- "$cur"))
compopt -o filenames
;;
--main-core | -p) # FIXME: Is this meant to be an actual core id or thread id? Assume the latter
local cpus
if [[ -e /sys/devices/system/cpu ]]; then
cpus=(/sys/devices/system/cpu/cpu+([0-9]))
cpus=("${cpus[@]##*cpu}")
fi
COMPREPLY=($(compgen -W '${cpus[*]}' -- "$cur"))
;;
--iova-mode)
COMPREPLY=($(compgen -W 'pa va' -- "$cur"))
;;
--tpoint-group | -e)
COMPREPLY=($(compgen -W '$(_get_tpoint_g_masks)' -- "$cur"))
compopt -o nosort
;;
--logflag)
COMPREPLY=($(compgen -W '$(_get_log_flags)' -- "$cur"))
;;
--huge-dir)
COMPREPLY=($(compgen -W '$(_get_fs_mounts "hugetlbfs")' -- "$cur"))
compopt -o filenames
;;
--iflag | --oflag) # spdk_dd specific
if [[ ${app##*/} == spdk_dd ]]; then
COMPREPLY=($(compgen -W '$(_get_help_pos "${app_help[@]}")' -- "$cur"))
fi
;;
*) return 1 ;;
esac 2> /dev/null
return 0
}
_get_fs_mounts() {
[[ $(< /proc/filesystems) == *"$1"* ]] || return 0
local mount fs mounts
while read -r _ mount fs _; do
[[ $fs == "$1" ]] && mounts+=("$mount")
done < /proc/mounts
if ((${#mounts[@]} > 0)); then
printf '%s\n' "${mounts[@]}"
fi
}
_get_from_spdk_help() {
_get_help "$app" |& grep "$1"
}
_get_tpoint_g_masks() {
local g_masks
g_masks=$(_get_from_spdk_help "tracepoint group mask for spdk trace buffers") || return 0
[[ $g_masks =~ \((.+)\) ]] || return 0
IFS=", " read -ra g_masks <<< "${BASH_REMATCH[1]}"
printf '%s\n' "${g_masks[@]}"
}
_get_log_flags() {
local logflags
logflags=$(_get_from_spdk_help "enable debug log flag") || return 0
[[ $logflags =~ \((.+)\) ]] || return 0
if [[ -n ${BASH_REMATCH[1]} && ${BASH_REMATCH[1]} != "not supported"* ]]; then
IFS=", " read -ra logflags <<< "${BASH_REMATCH[1]}"
printf '%s\n' "${logflags[@]}"
fi
}
_is_app() {
type -P "$1" > /dev/null
}
_rpc() {
local cur prev words
_init_completion || return
_is_app "$1" || return
local rpc=$1 rpc_sock="" method=""
local -A rpc_methods=()
_set_rpc_sock
_get_rpc_methods "$rpc"
if method=$(_method_in_words); then
COMPREPLY=($(compgen -W '$(_get_help_rpc_method "$rpc" "$method")' -- "$cur"))
compopt -o nosort
elif [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W '$(_parse_help "$rpc")' -- "$cur"))
elif [[ $prev == --verbose ]]; then
COMPREPLY=($(compgen -W 'DEBUG INFO ERROR' -- "$cur"))
elif [[ $prev == -s ]]; then
_filedir
else
COMPREPLY=($(compgen -W '${!rpc_methods[*]}' -- "$cur"))
fi 2> /dev/null
}
_spdk_app() {
local cur prev
_init_completion || return
_is_app "$1" || return
local app=$1 app_help
mapfile -t app_help < <(_get_help "$app")
if [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W '$(_get_help_opt "${app_help[@]}")' -- "$cur"))
else
_spdk_opt_to_complete "$prev" || _filedir
fi
}
# Build simple completion for some common spdk apps|tools
_spdk_apps() {
local apps
apps=(
iscsi_tgt
nvmf_tgt
spdk_dd
spdk_tgt
spdk_top
spdk_trace_record
vhost
create_vbox.sh
pkgdep.sh
run-autorun.sh
vm_setup.sh
) # TODO: Add more?
complete -o default -F _spdk_app "${apps[@]}"
complete -o default -F _rpc rpc.py
}
_spdk_apps
# Look for _configure(). If it exists, include default completions for path lookups
if [[ $(type -t _configure) == function ]]; then
complete -o default -F _configure configure
fi