From 963ca087521a01090db26e993af99b15000363c8 Mon Sep 17 00:00:00 2001 From: Benjamin Lupton Date: Wed, 25 Oct 2023 16:26:05 +0800 Subject: [PATCH] ensure that bash v3 tests run with bash v3 this fixes our ability to catch the error from 3b85eb173090da873241cec86526428b9f0343ce this is necessary as the movement from sourcing to commands causes `env` to be used, which will reset to the preferred bash rather than the active bash. other changes: - confirm: tests no longer hang indefinitely on macos sonoma - read-key: fix timeouts for bash v3 --- commands/confirm | 6 ++++-- commands/debug-bash | 29 +++++++++++++++++++++++++---- commands/dorothy | 10 +++++----- commands/eval-tester | 32 ++++++++++++++++++++++++-------- commands/read-key | 33 ++++++++++++++++++++++----------- 5 files changed, 80 insertions(+), 30 deletions(-) diff --git a/commands/confirm b/commands/confirm index c20e71dbb..db20b9324 100755 --- a/commands/confirm +++ b/commands/confirm @@ -259,9 +259,11 @@ function confirm_() ( print_string "$prompt " >"$tty_target" # send an ansi query to fetch the cursor row and column, returns [^[[24;80R] where 24 is row, 80 is column # use _ to discard, the first read var is garbage, the second read var is the column, the final read var is the column - # don't use a timeout, as we already in a TTY so can guarantee an answer, and the read will complete immediately upon a response thanks to [-d R] which completes reading when the R is read, which is the final character of the response query + # use a 2 second timeout, as otherwise [confirm --test] on macos sonoma will wait forever + # shorter timeouts aren't suitable as slower machines take a while for the response + # we are already in a TTY, so can usually guarantee an answer, and the read will complete immediately upon a response thanks to [-d R] which completes reading when the R is read, which is the final character of the response query local _ - IFS='[;' read -srd R -p $'\e[6n' _ _ CURSOR_COLUMN <"$tty_target" || : + IFS='[;' read -t 2 -srd R -p $'\e[6n' _ _ CURSOR_COLUMN <"$tty_target" || : # output the body if it exists if test -n "$body"; then diff --git a/commands/debug-bash b/commands/debug-bash index fe2f32685..148ca78a5 100755 --- a/commands/debug-bash +++ b/commands/debug-bash @@ -15,6 +15,9 @@ function debug_bash() ( debug-bash [...options] -- [...args] OPTIONS: + --bash= + If you want to invoke the command through a custom bash binary, then provide it here. + -v Pass the -v flag to bash: Print shell input lines as they are read. EOF @@ -22,13 +25,14 @@ function debug_bash() ( } # process - local item cmd=() args=('-x') + local item option_bash='' bash_args=('-x') cmd=() while test "$#" -ne 0; do item="$1" shift case "$item" in '--help' | '-h') help ;; - '-v') args+=('-v') ;; + '--bash='*) option_bash="${item#*--bash=}" ;; + '-v') bash_args+=('-v') ;; '--') cmd+=("$@") shift "$#" @@ -46,11 +50,28 @@ function debug_bash() ( help 'No was provided.' fi + # fallback + if test -z "$option_bash"; then + option_bash="$(type -P bash)" + fi + # ===================================== # Act - bash "${args[@]}" "$(type -P "${cmd[0]}")" "${cmd[@]:1}" - return + # invoke the command or function + local cmd_path + cmd_path="$(type -P "${cmd[0]}" 2>/dev/null || :)" + if test -n "$cmd_path" && [[ $cmd_path == "$DOROTHY"* ]]; then + # command + cmd[0]="$cmd_path" + "$option_bash" "${bash_args[@]}" "${cmd[@]}" + return + else + # function/builtin + set "${bash_args[@]}" + "${cmd[@]}" + return + fi ) # fire if invoked standalone diff --git a/commands/dorothy b/commands/dorothy index d1d923bbb..4d5b7031e 100755 --- a/commands/dorothy +++ b/commands/dorothy @@ -1725,10 +1725,10 @@ function dorothy() ( source "$DOROTHY/sources/ripgrep.bash" # able to test on bash v3? - local bash bashv3='' + local bash has_macos_bashv3='no' bash="$(type -P bash)" if is_mac && test "$bash" != '/bin/bash' && [[ "$(/bin/bash --version || :)" == 'GNU bash, version 3.'* ]]; then - bashv3='/bin/bash' + has_macos_bashv3=yes fi # prepre scan paths @@ -1759,9 +1759,9 @@ function dorothy() ( fi # run the bash v3 test - if test -n "$bashv3"; then - eval-helper --no-quiet --wrap -- "$bashv3" "$filepath" --test || { - failures+=("$bashv3 $filepath --test") + if test "$has_macos_bashv3" = 'yes'; then + eval-helper --no-quiet --wrap -- env EVAL_TESTER_BASH=/bin/bash PATH="/bin:$PATH" /bin/bash "$filepath" --test || { + failures+=("env EVAL_TESTER_BASH=/bin/bash PATH='/bin:$PATH' /bin/bash '$filepath' --test") } fi done diff --git a/commands/eval-tester b/commands/eval-tester index 8cd468f45..aacf343ce 100755 --- a/commands/eval-tester +++ b/commands/eval-tester @@ -21,6 +21,8 @@ function eval_tester() ( --stderr= (defaults to empty) --ignore-stderr --debug (implies --ignore-stderr) + --bash= + Used to ensure that the command is invoked through a specific bash binary. Defaults to the env var EVAL_TESTER_BASH. EOF if test "$#" -ne 0; then echo-error "$@" @@ -29,13 +31,14 @@ function eval_tester() ( } # process - local item cmd=() ignore_option=$'\e' option_name='' option_status='0' option_stdout='' option_stderr='' option_debug='no' + local item cmd=() ignore_option=$'\e' option_name='' option_status='0' option_stdout='' option_stderr='' option_debug='no' option_bash="${EVAL_TESTER_BASH-}" while test "$#" -ne 0; do item="$1" shift case "$item" in '--help' | '-h') help ;; '--name='*) option_name="${item#*--name=}" ;; + '--bash='*) option_bash="${item#*--bash=}" ;; '--ignore-status') option_status="$ignore_option" ;; '--ignore-stdout') option_stdout="$ignore_option" ;; '--ignore-stderr') option_stderr="$ignore_option" ;; @@ -55,13 +58,26 @@ function eval_tester() ( esac done - # overrides - if test "$option_debug" = 'yes'; then - cmd=( - 'debug-bash' - '--' - "${cmd[@]}" - ) + # if invoking a dorothy command (not a function, nor things like cat), then support debug and custom bash + # otherwise, custom bash not necessary as already inherited + # and debug-bash not possible + local cmd_path + cmd_path="$(type -P "${cmd[0]}" 2>/dev/null || :)" + if test -n "$cmd_path" && [[ $cmd_path == "$DOROTHY"* ]]; then + cmd[0]="$cmd_path" + if test "$option_debug" = 'yes'; then + cmd=( + 'debug-bash' + "--bash=$option_bash" + '--' + "${cmd[@]}" + ) + elif test -n "$option_bash"; then + cmd=( + "$option_bash" + "${cmd[@]}" + ) + fi fi # ===================================== diff --git a/commands/read-key b/commands/read-key index 213fb3f72..8737d74ff 100755 --- a/commands/read-key +++ b/commands/read-key @@ -10,6 +10,8 @@ function read_key_test() ( # do a test without any capturing local book status + printf '%s\n' "read-key bash version [$BASH_VERSION] [$BASH_VERSION_MAJOR] " + status=0 read -t 0 || status=$? printf '%s\n' "read-key check status [$status] " @@ -26,11 +28,13 @@ function read_key_test() ( read -t 0 < <(printf '%s\n' 'abc') || status=$? printf '%s\n' "read-key < <(...) check status [$status] " - status=0 - date - read -sN1 -t 5 book || status=$? - date - printf '%s\n' "read-key v4 status [$status] and read [$book]" + if test "$BASH_VERSION_MAJOR" -ge '4'; then + status=0 + date + read -sN1 -t 5 book || status=$? + date + printf '%s\n' "read-key v4 status [$status] and read [$book]" + fi status=0 date @@ -38,9 +42,11 @@ function read_key_test() ( date printf '%s\n' "read-key v3 status [$status] and read [$book]" - status=0 - printf '%s\n' 'abc' | read -sN1 -t 5 book || status=$? - printf '%s\n' "read-key v4 status [$status] and read [$book]" + if test "$BASH_VERSION_MAJOR" -ge '4'; then + status=0 + printf '%s\n' 'abc' | read -sN1 -t 5 book || status=$? + printf '%s\n' "read-key v4 status [$status] and read [$book]" + fi status=0 printf '%s\n' 'def' | IFS= read -sn1 -t 5 book || status=$? @@ -190,9 +196,14 @@ function read_key() ( fi } - # expand - local key - key="$(read_key_bash_compat)" + # read the key with bash v3 compat, as key="$(...)" creates a subshell so return status is ignored + local key key_status + eval_capture --statusvar=key_status --stdoutvar=key -- read_key_bash_compat + if test "$key_status" -ne 0; then + return "$key_status" + fi + + # expand the key case "$key" in # vt100 $'\eOB') print_line 'down' ;;