From 7803305f1afd9476e372c0d9c5c4357153bd3a73 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sun, 12 Mar 2023 20:10:03 +0900 Subject: [PATCH] lib: add "util.bgproc" for "ble/util/bgproc" --- GNUmakefile | 1 + contrib | 2 +- docs/ChangeLog.md | 4 +- lib/util.bgproc.sh | 460 +++++++++++++++++++++++++++++++++++++++++++++ make_command.sh | 1 + note.txt | 98 ++++++++++ src/util.sh | 14 +- 7 files changed, 575 insertions(+), 5 deletions(-) create mode 100644 lib/util.bgproc.sh diff --git a/GNUmakefile b/GNUmakefile index beccf5e0..790ab87f 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -98,6 +98,7 @@ outfiles += $(OUTDIR)/lib/test-decode.sh outfiles += $(OUTDIR)/lib/test-edit.sh outfiles += $(OUTDIR)/lib/test-syntax.sh outfiles += $(OUTDIR)/lib/test-complete.sh +outfiles += $(OUTDIR)/lib/util.bgproc.sh $(OUTDIR)/lib/%.sh: lib/%.sh | $(OUTDIR)/lib cp -p $< $@ $(OUTDIR)/lib/%.txt: lib/%.txt | $(OUTDIR)/lib diff --git a/contrib b/contrib index b4978f81..bfc1670e 160000 --- a/contrib +++ b/contrib @@ -1 +1 @@ -Subproject commit b4978f8126bcd478e5fb5657be7806e2a672b217 +Subproject commit bfc1670e9ca473af6db1eb7b5ccabda44dd896e5 diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index 3a9e3731..d77b4ada 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -138,7 +138,8 @@ - decode: accept isolated ESC \ (requested by mozirilla213) `#D2004` d7210494 - sabbrev: add widget `magic-slash` to approximate Zsh named directories (motivated by mozirilla213) `#D2008` e6b9581c - sabbrev: support inline and linewise sabbre with `ble-sabbrev -il` `#D2012` 56208534 -- complete: add `bleopt complete_source_sabbrev_{opts,ignore}` (motivated by mozirilla213) `#D2013` f95eb0cc `#D2016` xxxxxxxx +- complete: add `bleopt complete_source_sabbrev_{opts,ignore}` (motivated by mozirilla213) `#D2013` f95eb0cc `#D2016` 45c76746 +- util.bgproc: separate `ble/util/bgproc` from `histdb` (motivated by bkerin) `#D2017` xxxxxxxx ## Changes @@ -615,6 +616,7 @@ - histdb: fix `.timeout` not set for background `sqlite3` `#D1982` 20b42fa - histdb: suppress color codes in the default `histdb_remarks` `#D1968` 20b42fa - histdb: disable timeout of background processes in Bash 3.2 `#D1992` 20b42fa + - histdb: rewrite to use `ble/util/bgproc` `#D2017` xxxxxxxx - integration: move `fzf` and `bash-preexec` integrations to subdir `#D1939` 86d9467 diff --git a/lib/util.bgproc.sh b/lib/util.bgproc.sh new file mode 100644 index 00000000..24f97d81 --- /dev/null +++ b/lib/util.bgproc.sh @@ -0,0 +1,460 @@ +# -*- mode: sh; mode: sh-bash -*- + +## @fn ble/util/bgproc#open prefix command [opts] +## Start a session for a background process. The session can be closed by +## calling "ble/util/bgproc#close PREFIX". The background process is usually +## started on the start of the session and terminated on closing the session. +## In addition, if requested, the background process can be stopped and +## started any time in the session. If the background process is stopped +## when it is needed, it is automatically restarted. If "timeout=TIMEOUT" is +## specified in OPTS, the background process is automatically stopped where +## there is no access for the time duration specified by TIMEOUT. +## +## @param[in] prefix +## This names the identifier of the bgproc. This is actually used as the +## prefix of the array names used to store the information of the created +## bgproc, so the value needs to be a valid variable name. +## +## When the bgproc is successfully created, the following array elements +## are set, (where PREFIX in the variable name is replaced by the value of +## prefix). +## +## @var PREFIX_bgproc[0] ... fd_response +## @var PREFIX_bgproc[1] ... fd_request +## @var PREFIX_bgproc[2] ... command +## @var PREFIX_bgproc[3] ... opts +## @var PREFIX_bgproc[4] ... bgpid +## @var PREFIX_bgproc_fname[0] ... fname_response +## @var PREFIX_bgproc_fname[1] ... fname_request +## @var PREFIX_bgproc_fname[2] ... fname_run_pid +## +## To send strings to stdin of the background process, one can write to the +## file descriptor ${PREFIX_bgproc[1]}. To read strings coming from stdout +## of the background process, one can read from the file descriptor +## ${PREFIX_bgproc[0]}. +## +## When any of "timeout=TIMEOUT", "deferred", and "restart" are specified +## to OPTS, one should call "ble/util/bgproc#use PREFIX" just before +## directly accesssing the file descriptors ${PREFIX_bgproc[0]} and +## ${PREFIX_bgproc[1]} to ensure that the background process is running. +## Or, one can use a shorthand "ble/util/bgproc#post PREFIX STRING" to +## ensure the background process and write STRING to it. Immediately after +## "ble/util/bgproc#post PREFIX STRING", one do not need to call +## "ble/util/bgproc#use PREFIX" to read from ${PREFIX_bgproc[0]}. +## +## @param[in] command +## The command to execute. +## +## Note: If the command wants to access the variable names "bgproc" and +## "bgproc_fname" defined outside the command, please save the values in +## other names of variables before calling "ble/util/bgproc#open" and +## access those alternative variables from inside the command. The +## variable names "bgproc" and "bgproc_fname" are hidden by the local +## variables used by ble/util/bgproc itself. +## +## @param[in,opt] opts +## A colon-separated list of options. The following options can be +## specified. +## +## deferred +## When this option is specified, the background process is initially not +## started. It will be started when it is first required. +## +## restart +## When this option is specified, if the background process died +## unexpectedly, the background process will be restarted when it becomes +## necessary. +## +## Note: Even if this option is unspecified, the background process that +## was intensiontally stopped will be always restarted when it becomes +## necessary. This option only affects the case that the background +## process exited or died outside the management of bgproc. +## +## timeout=TIMEOUT +## When this option is specified, the background process is stopped when +## there are no access to the background process for the time duration +## specified by TIMEOUT. The unit of TIMEOUT is millisecond. +## +## owner-close-on-unload +## This option suppresses the automatic call of "ble/util/bgproc#close" +## from the "unload" blehook. This option is useful when another +## "unload" blehook needs to access to this bgproc. When this option is +## specified, another "unload" blehook needs to manually call +## "ble/util/bgproc#close" for this bgproc. If "ble/util/bgproc#close" +## is not called, the background process may be forcibly terminated by +## the final cleaup stage of ble.sh session. +## +## no-close-on-unload +## This option suppresses the automatic call of "ble/util/bgproc#close" +## and any cleanups of the background process, so that the background +## process survives after Bash terminates or ble.sh has been unloaded. +## +## Note: Nevertheless, file descriptors at the side of the parent shell +## will be closed on the termination of the parent shell, which can cause +## SIGPIPE write error or EOF read error in the background process. +## +## kill-timeout=TIMEOUT +## This option specifies the timeout after the attempt of stopping the +## background process in unit of millisecond. The default is 10000 (10 +## seconds). If the background process does not terminate within the +## timeout after closing the file descriptors at the side of the parent +## shell, the background process will receive SIGTERM. If it does not +## terminate even after sending SIGTERM, it will then receive SIGKILL +## after additional 10 seconds. +## +## @exit 0 if the background process is successfully started or "deferred" is +## specified to OPTS. 2 if an invalid prefix value is specified. 3 if the +## system does not support named pipes. 1 if the background process failed +## to be started. +## +## @fn ble/util/bgproc/onstart:PREFIX +## When this function is defined, this function is called after the new +## background process is created. +## +## @fn ble/util/bgproc/onstop:PREFIX +## When this function is defined, this function is called before the +## background process is stopped. +## +## The application can send an intruction to terminate the background process +## in this hook (in case that the background process does not automatically +## end on the close of the file descriptors, or the file descriptors can be +## shared with other background subshells). Note that the background process +## will receive SIGTERM or SIGKILL if it does not terminate within the +## timeout specified by kill-timeout=TIMEOUT. +## +## @fn ble/util/bgproc/onclose:PREFIX +## When this function is defined, this function is called before the bgproc +## session is closed. +## +## @fn ble/util/bgproc/ontimeout:PREFIX +## When this function is defined, this function is called before the timeout +## specified by "timeout=TIMEOUT" in OPTS. If this function exits with +## non-zero status, the timeout is canceled. +## +function ble/util/bgproc#open { + if ! ble/string#match "$1" '^[_a-zA-Z][_a-zA-Z0-9]*$'; then + ble/util/print "$FUNCNAME: $1: invalid prefix value." >&2 + return 2 + fi + + # If there is an existing bgproc on the same prefix, close it first. + ble/util/bgproc#close "$1" + + local -a bgproc=() + bgproc[0]= + bgproc[1]= + bgproc[2]=$2 + bgproc[3]=${3-} + + local -a bgproc_fname=() + bgproc_fname[0]=$_ble_base_run/$$.util.bgproc.$1.response.pipe + bgproc_fname[1]=$_ble_base_run/$$.util.bgproc.$1.request.pipe + bgproc_fname[2]=$_ble_base_run/$$.util.bgproc.$1.pid + + ble/util/save-vars "${1}_" bgproc bgproc_fname + + [[ :${bgproc[3]}: == *:deferred:* ]] || ble/util/bgproc#start "$1"; local ext=$? + if ((ext!=0)); then + builtin eval -- "${1}_bgproc=() ${1}_bgproc_fname=()" + fi + return "$ext" +} + +## @fn ble/util/bgproc#alive prefix +## Test if the bgproc session is active. +## +## @param[in] prefix +## The name to identify the bgproc. +## +function ble/util/bgproc#opened { + local bgpid_ref=${1}_bgproc[0] + [[ ${!bgpid_ref+set} ]] || return 2 +} + +## @fn ble/util/bgproc/.alive +## @var[in] bgproc +function ble/util/bgproc/.alive { + [[ ${bgproc[4]-} ]] && kill -0 "${bgproc[4]}" 2>/dev/null +} + +## @fn ble/util/bgproc/.exec +## @var[in] bgproc +function ble/util/bgproc/.exec { + # Note: We need to specify the redirections for ${bgproc[0]} and ${bgproc[1]} + # on "builtin eval" because of a bash-3.0 bug. In Bash 3.0, the redirections + # are not properly set up if one uses a function definition of the form + # "function fname { } redirections". + builtin eval -- "${bgproc[2]}" <&"${bgproc[1]}" >&"${bgproc[0]}" +} + +## @fn ble/util/bgproc/.mkfifo +## @var[in] bgproc_fname +function ble/util/bgproc/.mkfifo { + local -a pipe_remove=() pipe_create=() + local i + for i in 0 1; do + [[ -p ${bgproc_fname[i]} ]] && continue + ble/array#push pipe_create "${bgproc_fname[i]}" + if [[ -e ${bgproc_fname[i]} || -h ${bgproc_fname[i]} ]]; then + ble/array#push pipe_remove "${bgproc_fname[i]}" + fi + done + ((${#pipe_remove[@]}==0)) || ble/bin/rm -f "${pipe_remove[@]}" 2>/dev/null + ((${#pipe_create[@]}==0)) || ble/bin/mkfifo "${pipe_create[@]}" 2>/dev/null +} + +## @fn ble/util/bgproc#start prefix +## Start the background process. This runs the command specified to +## "ble/util/bgproc#open". +## +## @param[in] prefix +## The name to identify the bgproc. +## +## @exit 0 if the background process is successfully started or was already +## running. 2 if the PREFIX does not corresponds to an existing bgproc. 3 +## if the system does not support the named pipes. 1 if the background +## process failed to be started. +## +function ble/util/bgproc#start { + local bgproc bgproc_fname + ble/util/restore-vars "${1}_" bgproc bgproc_fname + if ((!${#bgproc[@]})); then + ble/util/print "$FUNCNAME: $1: not an existing bgproc name." >&2 + return 2 + fi + + if ble/util/bgproc/.alive; then + # The background process is already running + return 0 + fi + [[ ! ${bgproc[0]-} ]] || ble/fd#close 'bgproc[0]' + [[ ! ${bgproc[1]-} ]] || ble/fd#close 'bgproc[1]' + + # Note: mkfifo may fail in MSYS-1 + local _ble_local_ext=0 + if ble/util/bgproc/.mkfifo && + ble/fd#alloc 'bgproc[0]' '<> "${bgproc_fname[0]}"' && + ble/fd#alloc 'bgproc[1]' '<> "${bgproc_fname[1]}"' + then + # Note: We want to assign a new process group to the background process + # without affecting the job table of the main shell so use the subshell + # `(...)'. The process group is later used to kill the process tree in + # stopping the background process. Note that the command substitutions + # $(...) do not create a new process group even if we specify `set -m' so + # cannot be used for the present purpose. + ble/util/assign 'bgproc[4]' '(set -m; ble/util/bgproc/.exec __ble_suppress_joblist__ >/dev/null & ble/util/print "$!")' + + if ble/util/bgproc/.alive; then + [[ :${bgproc[3]}: == *:no-close-on-unload:* ]] || + ble/util/print "-${bgproc[4]}" >| "${bgproc_fname[2]}" + [[ :${bgproc[3]}: == *:no-close-on-unload:* || :${bgproc[3]}: == *:owner-close-on-unload:* ]] || + blehook unload!="ble/util/bgproc#close $1" + ble/util/bgproc#keepalive "$1" + else + builtin unset -v 'bgproc[4]' + _ble_local_ext=1 + fi + else + _ble_local_ext=3 + fi + + if ((_ble_local_ext!=0)); then + [[ ! ${bgproc[0]-} ]] || ble/fd#close 'bgproc[0]' + [[ ! ${bgproc[1]-} ]] || ble/fd#close 'bgproc[1]' + bgproc[0]= + bgproc[1]= + builtin unset -v 'bgproc[4]' + fi + + ble/util/save-vars "${1}_" bgproc bgproc_fname + + if ((_ble_local_ext==0)); then + ble/function#try ble/util/bgproc/onstart:"$1" + fi + return "$_ble_local_ext" +} + +function ble/util/bgproc#stop/.wait { + local pid=$1 msec=$2 + while + kill -0 "$pid" 2>/dev/null || return 0 + ((msec>0)) + do + ble/util/msleep "$((msec>1000?1000:msec))" + ((msec-=1000)) + done + return 1 +} +function ble/util/bgproc#stop/.kill { + local pid=$1 i close_timeout=$2 + ble/util/bgproc#stop/.wait "$pid" "$close_timeout" && return 0 + kill -- "$pid" + ble/util/bgproc#stop/.wait "$pid" 10000 && return 0 + kill -9 "$pid" +} + +## @fn ble/util/bgproc#stop prefix +## Stop the background process. +## +## @param[in] prefix +## The name to identify the bgproc. +## +function ble/util/bgproc#stop { + local prefix=$1 + ble/util/idle.cancel "ble/util/bgproc#keepalive/.timeout $prefix" + + local bgproc bgproc_fname + ble/util/restore-vars "${prefix}_" bgproc bgproc_fname + if ((!${#bgproc[@]})); then + ble/util/print "$FUNCNAME: $prefix: not an existing bgproc name." >&2 + return 2 + fi + + [[ ${bgproc[4]-} ]] || return 1 + + if ble/is-function ble/util/bgproc/onstop:"$prefix" && ble/util/bgproc/.alive; then + ble/util/bgproc/onstop:"$prefix" + fi + + ble/fd#close 'bgproc[0]' + ble/fd#close 'bgproc[1]' + >| "${bgproc_fname[2]}" + + # When the background process is active, kill the process after waiting for + # the time specified by kill-timeout. + if ble/util/bgproc/.alive; then + local ret close_timeout=10000 + if ble/opts#extract-last-optarg "${bgproc[3]}" kill-timeout; then + close_timeout=$ret + fi + (ble/util/bgproc#stop/.kill "-${bgproc[4]}" "$close_timeout" /dev/null & disown) + fi + + builtin eval -- "${prefix}_bgproc[0]=" + builtin eval -- "${prefix}_bgproc[1]=" + builtin unset -v "${prefix}_bgproc[4]" + return 0 +} + +## @fn ble/util/bgproc#alive prefix +## Test if the background process is currently running. +## +## @param[in] prefix +## The name to identify the bgproc. +## +function ble/util/bgproc#alive { + local bgpid_ref=${1}_bgproc[4] + [[ ${!bgpid_ref-} ]] || return 2 + kill -0 "${!bgpid_ref}" 2>/dev/null +} + +function ble/util/bgproc#keepalive/.timeout { + local prefix=$1 + + # Call ble/util/bgproc/ontimeout:PREFIX if any + if ble/is-function ble/util/bgproc/ontimeout:"$prefix"; then + if ! ble/util/bgproc/ontimeout:"$prefix"; then + ble/util/bgproc#keepalive "$prefix" + return 0 + fi + fi + + ble/util/bgproc#stop "$prefix" +} + +## @fn ble/util/bgproc#keepalive prefix +## Rest the timeout to stop the background process. +## +## @param[in] prefix +## The name to identify the bgproc. +## +function ble/util/bgproc#keepalive { + local prefix=$1 bgproc + ble/util/restore-vars "${prefix}_" bgproc + ((${#bgproc[@]})) || return 2 + ble/util/bgproc/.alive || return 1 + + local timeout_proc="ble/util/bgproc#keepalive/.timeout $1" + ble/util/idle.cancel "$timeout_proc" + ble/opts#extract-last-optarg "${bgproc[3]}" timeout || return 0; local bgproc_timeout=$ret + if ((bgproc_timeout>0)); then + ble/util/idle.push --sleep="$bgproc_timeout" "$timeout_proc" + fi + return 0 +} + +_ble_util_bgproc_onclose_processing= +## @fn ble/util/bgproc#close prefix +## Close the bgproc session. +## +## @param[in] prefix +## The name to identify the bgproc. +## +function ble/util/bgproc#close { + # If the bgproc does not exist, do nothing. + ble/util/bgproc#opened "$1" || return 2 + + local prefix=${1} + blehook unload-="ble/util/bgproc#close $prefix" + ble/util/idle.cancel "ble/util/bgproc#keepalive/.timeout $prefix" + + # When the callback function "ble/util/bgproc/onclose:PREFIX" is defined, we + # call the function before starting the closing process. However, we skip + # this if the present call of "ble/util/bgproc#close" is already from inside + # the callback, we skip it to avoid the infinite recursion. + if ble/is-function ble/util/bgproc/onclose:"$prefix"; then + if [[ :${_ble_util_bgproc_onclose_processing-}: != *:"$prefix":* ]]; then + local _ble_util_bgproc_onclose_processing=${_ble_util_bgproc_onclose_processing-}:$prefix + ble/util/bgproc/onclose:"$prefix" + fi + fi + + ble/util/bgproc#stop "$prefix" + builtin eval -- "${prefix}_bgproc=() ${prefix}_bgproc_fname=()" +} + +## @fn ble/util/bgproc#use prefix +## Ensure the file descriptors to be ready for uses. When the background +## process is temporarily stopped, this will restart the background process. +## When the background process was terminated unexpectedly and "restart" is +## specified to the bgproc's OPTS, this will also restart the background +## process. +## +## @param[in] prefix +## The name to identify the bgproc. +## +## @exit 0 if the background process is ready. 2 if the specified PREFIX +## does not correspond to an existing bgproc. 3 if the system does not seem +## to support named pipes. 1 if the background process was stopped and +## failed to restart it. +## +function ble/util/bgproc#use { + local bgproc + ble/util/restore-vars "${1}_" bgproc + if ((!${#bgproc[@]})); then + ble/util/print "$FUNCNAME: $1: not an existing bgproc name." >&2 + return 2 + fi + + if [[ ! ${bgproc[4]-} ]]; then + # The background process has been stopped intenstionally. We automatically + # restart the background process in this case. + ble/util/bgproc#start "$1" || return "$?" + elif ! kill -0 "${bgproc[4]-}"; then + # The background process died unexpectedly + if [[ :${bgproc[3]-}: == *:restart:* ]]; then + ble/util/bgproc#start "$1" || return "$?" + else + return 1 + fi + else + ble/util/bgproc#keepalive "$1" + return 0 + fi +} + +function ble/util/bgproc#post { + ble/util/bgproc#use "$1" || return "$?" + local fd1_ref=${1}_bgproc[1] + ble/util/print "$2" >&"${!fd1_ref}" +} diff --git a/make_command.sh b/make_command.sh index d32e4379..041d03b8 100755 --- a/make_command.sh +++ b/make_command.sh @@ -1132,6 +1132,7 @@ function sub:scan/a.txt { grc --color --exclude={test,ext,./lib/test-\*.sh,./make_command.sh,\*.md} --exclude=check-mem.sh '[/[:space:]<>"'\''][a-z]\.txt|/dev/(pts/|pty)[0-9]*|/dev/tty' | sed -E 'h;s/'"$_make_rex_escseq"'//g \Z^\./memo/Zd + \Zgithub302-perlre-server\.bashZd s/^[^:]*:[0-9]+:[[:space:]]*// \Z^[[:space:]]*#Zd \ZDEBUG_LEAKVARZd diff --git a/note.txt b/note.txt index f85cea74..01ed2c12 100644 --- a/note.txt +++ b/note.txt @@ -623,6 +623,11 @@ bashbug 算術式周りのバグと注意点 $ bash-3.1 -c '((a?(b=123):c?(d=321):1))' bash-3.1: ((: a?(b=123):c?(d=321):1: syntax error in expression (error token is "?(d=321):1") + * bash-3.0 + + D1956: 関数定義の一番外側でリダイレクトしてもリダイレクトされない。例えば、 + function func { ls -l /proc/$BASHPID/fd/{0..2}; } <&"$fd0" >&"$fd1" + bash 配列の宣言に関する仕様・バグと注意点 * arr=(1 2 3) func の形式で配列をシェル関数に渡そうとすると、 @@ -1237,6 +1242,10 @@ bash_tips 6 ble-update で更新の必要がなかった時に内部的に使用 (由来: ACK = 6) + 2 コマンドの使い方が異なる + + 3 ble/util/bgproc は named pipes がシステムでサポートされていない時に 3 を返す。 + 2017-10-18 * ble-decode: widget に関して [#M0007] @@ -6624,6 +6633,95 @@ bash_tips Done (実装ログ) ------------------------------------------------------------------------------- +2023-03-12 + + * bgproc: histdb から切り離して再利用可能にする (motivated by bkerin) [#D2017] + https://lists.gnu.org/archive/html/help-bash/2023-03/msg00068.html + https://github.com/akinomyoga/ble.sh/issues/302#issuecomment-1462977627 + + * done: ble/opts#has バグ修正。影響は cmdspec_opts の plus-options だけの様だ。 + 全然判定できていなかった。常にほぼ false になっていたと思われる。 + + * done: ble/util/bgproc 既に開いている prefix を指定した場合は以前のものは + 削除する。 + + * done: 複数のプロセスが走っている場合に対応できる様にプロセスグループを作 + らせる事にする。set -m を実行すれば良い。 + + * done: 実は負の引数を kill -0 に渡すことでプロセスグループの何れかのプロ + セスが残っているかどうかを判定することができると分かった → これを利用 + して改めて kill 部分の処理を作り直した。 + + * done: どうやらコマンド置換の中でやるとプロセスグループが作られない様だ。 + なので bgpid=$(set -m; bgproc & echo "$!") ではなくて ble/util/assign + bgpid '(set -m; ...)' とする必要がある。 + + 一方で、そもそもコマンド置換にしていた理由はあったのだったか。もし別の + 理由があったのであればそれについても () で壊れないか確認する必要がある。 + 調べてみるとコマンド置換を使っていたのは最初からで (#D1925) 特に考察は + していない様に見える。取り敢えず普通のプロセス置換にしても大丈夫。 + + 修正した。 + + * done: EXIT (もしくは internal_EXIT) に自動で登録する? + + →と思ったが単なる close ではなくて EXIT の時に特別の処理をしたい時に + EXIT もしくは internal_EXIT を設定していると、期せずして先に bgproc#close + されてしまって後処理ができなくなってしまう。 + + a うーん。後処理を行いたい場合の為に internal_EXIT に登録しない設定を作る? + + 特に指定しない場合に自動で終了処理を追加するとしても、internal_EXIT で + 呼び出して良いのだろうか。他の EXIT 処理が bgproc を利用したいという場 + 合に問題が起こる可能性がある。という事を考えると、EXIT の方に登録するべ + き? 然し EXIT の方に登録したとしても呼び出しの順序によって変なことが起 + こる可能性がある。 + + b reject: bgproc/onclose:prefix の中で EXIT 処理を実装してもらう + + 別の方法として bgproc#close の中で終了処理としての close なのか一時的な + close なのかを判定して各自処理を切り替える方針で実装してもらう? しかし + これだと bgproc が生きていても死んでいても実行するべき処理の場合に困る。 + 単に bgproc#close からの呼び出しを期待していると bgproc が走っていない + 場合にその処理が呼び出されなくなってしまう。それに分かりにくい。 + + 取り敢えず owner-close-on-exit と no-close-on-exit を opts として指定可能 + にすることにした。 + + * fixed: unload の時にも同様に呼び出すべきなのではないか? というか寧ろ今ま + で EXIT でやっていたのは unload でやるべきだったのではないか。 + + →histdb と bgproc の両方を EXIT ではなく unload を使う様に変更した。 + + * done: close-callback は関数に置き換えるべきなのでは? 結局 bgproc#close を + 呼び出す必要があるのであれば、opts の中に直接コマンドを記述するよりはちゃ + んとした関数を定義して関数名を close-callback に指定することになるが、そ + うであるのならば最初から関数名を ble/util/bgproc/close:_ble_histdb 等に固 + 定してそれを直接呼び出す様にした方がわかりやすい。 + + また callback の中で ble/util/bgproc#close を呼び出すのも一見して無限ルー + プになるのでインターフェイスとして分かりにくい。それよりは単に close 直前 + の終端処理として呼び出す様にするのが良い気がする。それでも + ble/util/bgproc#close を入れ子で呼び出した時の対策は今のまま残しておく事 + にする。 + + * done: request を送る機能 & 死んでいたら再始動する機能 + + timeout でデータを削除してしまうと restart 時に問題なのでは? なので + timeout 時には [4] だけ消す事にする? timeout で終了した場合と期せず終了し + てしまった場合は区別するべき。 + + 適当にいい加減な bgproc を作って動作確認した。取り敢えず簡単な使い道の範 + 囲ではちゃんと動いている様である。 + + また help-bash で提供されていた例に関しても cotnrib/config/github302 に実 + 装してみて動作確認した。動いている気がする。 + + 面倒なので取り敢えずこれで push する事にする。何れにしても histdb は未だ実 + 験中でドキュメントにも記していないし、また例として実装した perlre-server も + help-bash / GitHub #302 の為の例に過ぎないので寧ろテストしてもらうぐらいで + 良い。 + 2023-03-10 * complete: complete_source_sabbrev_ignore が動いていない [#D2016] diff --git a/src/util.sh b/src/util.sh index f957337a..92030173 100644 --- a/src/util.sh +++ b/src/util.sh @@ -417,9 +417,11 @@ function ble/util/restore-vars { local __ble_name __ble_prefix=$1; shift for __ble_name; do if ble/is-array "$__ble_prefix$__ble_name"; then - builtin eval "$__ble_name=(\"\${$__ble_prefix$__ble_name[@]}\")" + # Note: bash-4.2 以下では set -u で空配列に対する "${arr[@]}" が失敗す + # るので ${arr[@]+"${arr[@]}"} とする。 + builtin eval "$__ble_name=(\${$__ble_prefix$__ble_name[@]+\"\${$__ble_prefix$__ble_name[@]}\"})" else - builtin eval "$__ble_name=\"\$$__ble_prefix$__ble_name\"" + builtin eval "$__ble_name=\"\${$__ble_prefix$__ble_name-}\"" fi done } @@ -1378,7 +1380,7 @@ function ble/path#contains { ## @fn ble/opts#has opts key function ble/opts#has { - local rex=':'$2'[=[]' + local rex=':'$2'[=:]' [[ :$1: =~ $rex ]] } ## @fn ble/opts#remove opts value @@ -2195,6 +2197,12 @@ function ble/util/assign/.rmtmp { } if ((_ble_bash>=40000)); then # mapfile の方が read より高速 + # + # @remarks 将来的に ${ ...; } に切り替えることになった時に set -m でプロセス + # グループが作られるかどうかについて確認が必要。util.broc.sh では « + # ble/util/assign bgpid '(set -m; command & echo "$!")' » でプロセスグルー + # プが作られる事を想定している。例えば $(...) はプロセスグループが作られな + # いので使えない。 function ble/util/assign { local _ble_local_tmpfile; ble/util/assign/.mktmp builtin eval -- "$2" >| "$_ble_local_tmpfile"