From a4a779e45d4a8b1037ed49fb5953db94b07e5715 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sat, 14 May 2022 01:24:38 +0900 Subject: [PATCH] complete: work around blocking "_scp_remote_files" and "_dnf" --- ble.pp | 2 +- docs/ChangeLog.md | 1 + lib/core-complete.sh | 20 +++++++++++++++++ note.txt | 34 +++++++++++++++++++++++++++++ src/util.sh | 51 ++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 103 insertions(+), 5 deletions(-) diff --git a/ble.pp b/ble.pp index 5d45f6e8..2cc7ebad 100644 --- a/ble.pp +++ b/ble.pp @@ -813,7 +813,7 @@ function ble/bin/.freeze-utility-path { # POSIX utilities -_ble_init_posix_command_list=(sed date rm mkdir mkfifo sleep stty tty sort awk chmod grep cat wc mv sh od cp) +_ble_init_posix_command_list=(sed date rm mkdir mkfifo sleep stty tty sort awk chmod grep cat wc mv sh od cp ps) function ble/init/check-environment { if ! ble/bin#has "${_ble_init_posix_command_list[@]}"; then local cmd commandMissing= diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index 44d76024..5f11a1f8 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -344,6 +344,7 @@ - global: work around bash-3.0 bug that single quotas remains for `"${v-$''}"` `#D1774` 9b96578 - util: work around old `vte` not supporting `DECSCUSR` yet setting `TERM=xterm` (reported by dongxi8) `#D1785` 70277d0 - progcomp: work around the cobra V2 description hack (reported by SuperSandro2000) `#D1803` 71d0736 +- complete: work around blocking `_scp_remote_files` and `_dnf` (reported by iantra) `#D1807` XXXXXXX ## Internal changes and fixes diff --git a/lib/core-complete.sh b/lib/core-complete.sh index 40de3c48..b2528722 100644 --- a/lib/core-complete.sh +++ b/lib/core-complete.sh @@ -3114,7 +3114,21 @@ function ble/complete/progcomp/.compgen-helper-func { local fDefault= local cmd=${COMP_WORDS[0]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} ble/function#push compopt 'ble/complete/progcomp/compopt "$@"' + + # WA for blocking scp/ssh #D1807 + ble/function#push ssh ' + local IFS=$_ble_term_IFS + if [[ " ${FUNCNAME[*]} " == *" ble/complete/progcomp/.compgen "* ]]; then + local -a args; args=("$@") + ble/util/conditional-sync "exec ssh \"\${args[@]}\"" \ + "! ble/complete/check-cancel <&$_ble_util_fd_stdin" 128 progressive-weight:killall + else + ble/function#push/call-top "$@" + fi' + builtin eval '"$comp_func" "$cmd" "$cur" "$prev"' < /dev/null >&$_ble_util_fd_stdout 2>&$_ble_util_fd_stderr; local ret=$? + + ble/function#pop ssh ble/function#pop compopt [[ $ret == 124 ]] && progcomp_retry=1 @@ -3465,6 +3479,12 @@ function ble/complete/progcomp/.compgen { ble/is-function "$target" && ble/function#advice around "$target" ble/complete/progcomp/.cobraV2.patch fi + + # WA for dnf completion + ble/function#advice around _dnf_commands_helper ' + ble/util/conditional-sync \ + ble/function#advice/do \ + "! ble/complete/check-cancel <&$_ble_util_fd_stdin" 128 progressive-weight:killall' 2>/dev/null fi if [[ $comp_prog ]]; then # aws diff --git a/note.txt b/note.txt index 116b3596..8f9abb9d 100644 --- a/note.txt +++ b/note.txt @@ -6331,6 +6331,40 @@ bash_tips Done (実装ログ) ------------------------------------------------------------------------------- +2022-05-13 + + * complete: scp の補完で固まる (reported by iantra) [#D1807] + https://github.com/akinomyoga/ble.sh/issues/193 + + これは前から気になっていた事である。問題は何処に介入するのかという事である。 + 補完関数全体を subshell で実行する様にしてしまうと 124 を返して再実行した時 + に無限ループになってしまう。他にも変数に対する修正が適用されない等の問題が + 生じる。なので、もっと内側で conditional-sync を実行する必要がある。 + + _scp_remote_files を subshell で実行しようとも思ったがそうすると COMPREPLY + を渡すのが面倒だ。というか scp, ssh 等に介入すれば良い。どうせこれらは他の + プロセスを起動するのだから。実際に _scp_remote_files は ssh を呼び出してい + る: + + https://github.com/scop/bash-completion/blob/6f1bbda3c66814befa8025d49363b4070ef20008/completions/ssh#L435 + + と思って実装したが動かない。どうやら $(...) の中で conditional-sync をした + 場合、$() が結局本体のプロセスが死ぬまでブロックしてしまうのが原因の様だ。 + 本当のプロセスを kill -9 しても駄目の様だ。どうも更に子プロセスが起動してい + るのが原因だ。 + + PGID を確認してみたが command substitution の中で & で呼び出しても固有の + PGID を作成する訳では無い様だ。なので PGID に対して kill を実行すると外側 + も含めて予期しない所まで kill されてしまう。 + + 仕方がないので ps を使ってプロセス一覧を取得して其処から kill を実行する + 事にする。 + + * dnf も遅い。dnf に関しては _dnf_commands_helper に介入すれば良さそうだ。 + 然し、遅延ロードされる関数に確実に介入するには遅延ロードした時に上書きす + る必要がある。うーん。一応 bash-completion に関しては 124 により一旦制御 + を返すので介入はできる気がする。 + 2022-05-01 * 日本語を含むディレクトリに入ると化けてしまう事に気づいた [#D1806] diff --git a/src/util.sh b/src/util.sh index 72c22bd2..700195b4 100644 --- a/src/util.sh +++ b/src/util.sh @@ -3124,8 +3124,11 @@ function ble/function#push/call-top { else while ble/is-function "ble/function#push/$index:$func"; do ((index++)); done fi - ((index)) || return 0 - "ble/function#push/$((index-1)):$func" "$@" + if ((index==0)); then + command "$func" "$@" + else + "ble/function#push/$((index-1)):$func" "$@" + fi } : "${_ble_util_lambda_count:=0}" @@ -4061,6 +4064,46 @@ function ble/util/sleep { #------------------------------------------------------------------------------ # ble/util/conditional-sync +function ble/util/conditional-sync/.collect-descendant-pids { + local pid=$1 awk_script=' + $1 ~ /^[0-9]+$/ && $2 ~ /^[0-9]+$/ { + child[$2,child[$2]++]=$1; + } + function print_recursive(pid, _, n, i) { + if (child[pid]) { + n = child[pid]; + child[pid] = 0; # avoid infinite loop + for (i = 0; i < n; i++) { + print_recursive(child[pid, i]); + } + } + print pid; + } + END { print_recursive(pid); } + ' + ble/util/assign ret 'ble/bin/ps -A -o pid,ppid' + ble/util/assign-array ret 'ble/bin/awk -v pid="$pid" "$awk_script" <<< "$ret"' +} + +## @fn ble/util/conditional-sync/.kill +## @var __pid +## @var __opts +function ble/util/conditional-sync/.kill { + local kill_pids + if [[ :$__opts: == *:killall:* ]]; then + ble/util/conditional-sync/.collect-descendant-pids "$__pid" + kill_pids=("${ret[@]}") + else + kill_pids=("$__pid") + fi + + if [[ :$__opts: == *:SIGKILL:* ]]; then + builtin kill "${kill_pids[@]}" &>/dev/null + else + builtin kill -9 "${kill_pids[@]}" &>/dev/null + fi +} &>/dev/null + ## @fn ble/util/conditional-sync command [condition weight opts] ## @param[in] command ## @param[in,opt] condition @@ -4088,7 +4131,7 @@ function ble/util/conditional-sync { # check timeout if [[ $__timeout ]]; then if ((__timeout<=0)); then - builtin kill "$__pid" &>/dev/null + ble/util/conditional-sync/.kill return 142 fi ((__weight>__timeout)) && __weight=$__timeout @@ -4101,7 +4144,7 @@ function ble/util/conditional-sync { builtin kill -0 "$__pid" &>/dev/null do if ! builtin eval -- "$__continue"; then - builtin kill "$__pid" &>/dev/null + ble/util/conditional-sync/.kill return 148 fi done