Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Avoid confusion with preloaded bash function for perf bash completion

Since some functions (e.g. '_get_comp_words_by_ref()') in perf bash
completion script are originally taken from git bash completion script,
these functions may be preloaded before perf bash completion script
runs.

In order to avoid repeating loading the same function twice, some test
constraints are used before these function definitions in the perf bash
completion script (e.g. 'type _get_comp_words_by_ref &>/dev/null ||').

The problem is that, if these functions in perf bash completion script
are changed for some reason, perf will still use the preloaded bash
functions rather than the customized functions of its own.

As a result, the perf bash completion will behave incorrectly. To get
rid of this problem, a flag can be defined to determine the proper
situation.

And to avoid overwriting the preloaded functions, the names of these
functions in perf bash completion script should be renamed to the
perf-customized ones.

Example:

Before this patch:

$ type _get_comp_words_by_ref
_get_comp_words_by_ref is a function
_get_comp_words_by_ref ()
{
local exclude flag i OPTIND=1;
local cur cword words=();
local upargs=() upvars=() vcur vcword vprev vwords;
while getopts "c:i:n:p:w:" flag "$@"; do
case $flag in
c)
vcur=$OPTARG
;;
i)
vcword=$OPTARG
;;
n)
exclude=$OPTARG
;;
p)
vprev=$OPTARG
;;
w)
vwords=$OPTARG
;;
esac;
done;
while [[ $# -ge $OPTIND ]]; do
case ${!OPTIND} in
cur)
vcur=cur
;;
prev)
vprev=prev
;;
cword)
vcword=cword
;;
words)
vwords=words
;;
*)
echo "bash: $FUNCNAME(): \`${!OPTIND}': unknown argument" 1>&2;
return 1
;;
esac;
let "OPTIND += 1";
done;
__get_cword_at_cursor_by_ref "$exclude" words cword cur;
[[ -n $vcur ]] && {
upvars+=("$vcur");
upargs+=(-v $vcur "$cur")
};
[[ -n $vcword ]] && {
upvars+=("$vcword");
upargs+=(-v $vcword "$cword")
};
[[ -n $vprev && $cword -ge 1 ]] && {
upvars+=("$vprev");
upargs+=(-v $vprev "${words[cword - 1]}")
};
[[ -n $vwords ]] && {
upvars+=("$vwords");
upargs+=(-a${#words[@]} $vwords "${words[@]}")
};
(( ${#upvars[@]} )) && local "${upvars[@]}" && _upvars "${upargs[@]}"
}

As shown above, the _get_comp_words_by_ref is the preloaded function in
fact, rather than the function defined in perf-completion.sh. So if we
happen to change the function for some reason, the result will behave in
a wrong state.

After this patch:

We can set preload_get_comp_words_by_ref="false" to not use the preloaded
function. Instead, it will use the function defined in perf-completion.sh,
which is renamed as __perf_get_comp_words_by_ref to avoid overwriting
the preloaded function _get_comp_words_by_ref.

$ type __perf_get_comp_words_by_ref
__perf_get_comp_words_by_ref is a function
__perf_get_comp_words_by_ref ()
{
local exclude cur_ words_ cword_;
if [ "$1" = "-n" ]; then
exclude=$2;
shift 2;
fi;
__my_reassemble_comp_words_by_ref "$exclude";
cur_=${words_[cword_]};
while [ $# -gt 0 ]; do
case "$1" in
cur)
cur=$cur_
;;
prev)
prev=${words_[$cword_-1]}
;;
words)
words=("${words_[@]}")
;;
cword)
cword=$cword_
;;
esac;
shift;
done
}

As shown above, the function __perf_get_comp_words_by_ref is loaded and
can work this time.

Note that we do not change the original behavior when those functions are
not preloaded before perf bash completion script runs. In this case,
although the flag is set to "true", the code will still change it to
"false" to use the function defined in perf-completion.sh.

Signed-off-by: Yunlong Song <yunlong.song@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1426685758-25488-14-git-send-email-yunlong.song@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Yunlong Song and committed by
Arnaldo Carvalho de Melo
1312c8a8 6fdd9cb7

+30 -6
+30 -6
tools/perf/perf-completion.sh
··· 47 47 done 48 48 } 49 49 50 - type _get_comp_words_by_ref &>/dev/null || 51 - _get_comp_words_by_ref() 50 + # Define preload_get_comp_words_by_ref="false", if the function 51 + # __perf_get_comp_words_by_ref() is required instead. 52 + preload_get_comp_words_by_ref="true" 53 + 54 + if [ $preload_get_comp_words_by_ref = "true" ]; then 55 + type _get_comp_words_by_ref &>/dev/null || 56 + preload_get_comp_words_by_ref="false" 57 + fi 58 + [ $preload_get_comp_words_by_ref = "true" ] || 59 + __perf_get_comp_words_by_ref() 52 60 { 53 61 local exclude cur_ words_ cword_ 54 62 if [ "$1" = "-n" ]; then ··· 84 76 done 85 77 } 86 78 87 - type __ltrim_colon_completions &>/dev/null || 88 - __ltrim_colon_completions() 79 + # Define preload__ltrim_colon_completions="false", if the function 80 + # __perf__ltrim_colon_completions() is required instead. 81 + preload__ltrim_colon_completions="true" 82 + 83 + if [ $preload__ltrim_colon_completions = "true" ]; then 84 + type __ltrim_colon_completions &>/dev/null || 85 + preload__ltrim_colon_completions="false" 86 + fi 87 + [ $preload__ltrim_colon_completions = "true" ] || 88 + __perf__ltrim_colon_completions() 89 89 { 90 90 if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then 91 91 # Remove colon-word prefix from COMPREPLY items ··· 113 97 __perfcomp_colon () 114 98 { 115 99 __perfcomp "$1" "$2" 116 - __ltrim_colon_completions $cur 100 + if [ $preload__ltrim_colon_completions = "true" ]; then 101 + __ltrim_colon_completions $cur 102 + else 103 + __perf__ltrim_colon_completions $cur 104 + fi 117 105 } 118 106 119 107 __perf_prev_skip_opts () ··· 246 226 _perf() 247 227 { 248 228 local cur words cword prev 249 - _get_comp_words_by_ref -n =: cur words cword prev 229 + if [ $preload_get_comp_words_by_ref = "true" ]; then 230 + _get_comp_words_by_ref -n =: cur words cword prev 231 + else 232 + __perf_get_comp_words_by_ref -n =: cur words cword prev 233 + fi 250 234 __perf_main 251 235 } && 252 236