From 4525f3e55825ef47cec20059d6c3498fe7e7ca71 Mon Sep 17 00:00:00 2001 From: pvincent Date: Tue, 28 Jul 2026 20:10:31 +0400 Subject: [PATCH] on_return --- poc | 98 ++++++++++++++++++++++++++++------------- test/stub/scenario.bash | 24 +++++++--- 2 files changed, 87 insertions(+), 35 deletions(-) diff --git a/poc b/poc index d23c29d..4a91166 100755 --- a/poc +++ b/poc @@ -49,6 +49,18 @@ function is_true { function miaou_debug { is_true "${MIAOU_DEBUG}" && >&4 builtin echo -e "\e[90m <== DEBUG ==> \e[33m$*\e[0m" || true } + +function on_return { + local regex='return ([0-9]+)' + if [[ "$BASH_COMMAND" =~ $regex ]] && [[ "${BASH_REMATCH[1]}" -gt 0 ]]; then + failure_code="${BASH_REMATCH[1]}" + failure_type="RETURN" + failure_payload="${FUNCNAME[0]}" + print_miaou_error "${BASH_SOURCE[1]}" "${BASH_LINENO[0]}" "${failure_code}" "${failure_type}" "${failure_payload}" + miaou_debug "" + fi +} + # overridden function which permits backtracing of the original `exit` statement function exit { error_source=("${BASH_SOURCE[@]}") @@ -89,13 +101,22 @@ function print_miaou_error { } function on_error { + trap - RETURN failure_code="${1:-200}" >&4 printf '\r' # TODO: force carriage return explicitly, is it really useful? if [[ $$ == "$BASHPID" ]]; then - miaou_debug "" - failure_type="COMMAND_ERROR" - print_miaou_error "${BASH_SOURCE[1]}" "${BASH_LINENO[0]}" "${failure_code}" "${failure_type}" '...' + if [[ ! -v failure_type ]]; then + failure_type="COMMAND_ERROR" + failure_payload="${BASH_COMMAND}" + print_miaou_error "${BASH_SOURCE[1]}" "${BASH_LINENO[0]}" "${failure_code}" "${failure_type}" "${failure_payload}" + fi + + if [[ -v failure_payload ]]; then + miaou_debug "" + else + miaou_debug "" + fi error_source=("${BASH_SOURCE[@]}") error_lineno=("${BASH_LINENO[@]}") @@ -116,6 +137,7 @@ function on_error { } function on_pipe { + trap - RETURN local tmp_error regex source lineno error_source=("${BASH_SOURCE[@]}") @@ -198,36 +220,51 @@ function dump_stacktrace { } function on_exit { - local code - code="${1:-0}" + trap - RETURN + local code="${1:-0}" last_error regex mapfile -t tmp_error <"$MIAOU_BASH_ERROR" 2>&3 >&3 dump_stderr - - if [[ $code -gt 0 && ${#tmp_error[@]} -gt 0 ]]; then - local last_error regex + if [[ -v failure_type && "$failure_type" == 'RETURN' ]]; then last_error="${tmp_error[-1]}" - miaou_debug "" - if [[ $code -eq 1 ]]; then - regex='^(.*): line ([0-9]+): (.*): unbound variable$' - if [[ "$last_error" =~ $regex ]]; then - local source line payload - source="${BASH_REMATCH[1]}" - line="${BASH_REMATCH[2]}" - payload="${BASH_REMATCH[3]}" - miaou_debug "" - failure_code=$code - failure_type='UNBOUND_VARIABLE' - failure_payload="${BASH_REMATCH[3]}" - error_source=("${BASH_SOURCE[@]}") - error_lineno=("${BASH_LINENO[@]}") - error_funcname=("${FUNCNAME[@]}") - unset 'error_source[0]' 'error_lineno[0]' 'error_funcname[0]' - unset 'error_source[-1]' 'error_lineno[-1]' 'error_funcname[-1]' - unset 'error_source[-1]' 'error_lineno[-1]' 'error_funcname[-1]' - error_source=("$source" "${error_source[@]}") - error_lineno=("$line" "${error_lineno[@]}") - error_funcname=("${error_funcname[@]}" '
') + regex='^(.*): line ([0-9]+): miaou_error: code=[0-9]+ type=RETURN' + if [[ "$last_error" =~ $regex ]]; then + miaou_debug "" + local source line + source="${BASH_REMATCH[1]}" + line="${BASH_REMATCH[2]}" + error_source=("$source" "${error_source[@]}") + error_lineno=("$line" "${error_lineno[@]}") + error_funcname=("$failure_payload" "${error_funcname[@]}") + else + miaou_debug "" + fi + + else + if [[ $code -gt 0 && ${#tmp_error[@]} -gt 0 ]]; then + last_error="${tmp_error[-1]}" + miaou_debug "" + if [[ $code -eq 1 ]]; then + regex='^(.*): line ([0-9]+): (.*): unbound variable$' + if [[ "$last_error" =~ $regex ]]; then + local source line payload + source="${BASH_REMATCH[1]}" + line="${BASH_REMATCH[2]}" + payload="${BASH_REMATCH[3]}" + miaou_debug "" + failure_code=$code + failure_type='UNBOUND_VARIABLE' + failure_payload="${BASH_REMATCH[3]}" + error_source=("${BASH_SOURCE[@]}") + error_lineno=("${BASH_LINENO[@]}") + error_funcname=("${FUNCNAME[@]}") + unset 'error_source[0]' 'error_lineno[0]' 'error_funcname[0]' + unset 'error_source[-1]' 'error_lineno[-1]' 'error_funcname[-1]' + unset 'error_source[-1]' 'error_lineno[-1]' 'error_funcname[-1]' + error_source=("$source" "${error_source[@]}") + error_lineno=("$line" "${error_lineno[@]}") + error_funcname=("${error_funcname[@]}" '
') + fi fi fi miaou_debug "" @@ -245,7 +282,7 @@ function on_exit { set -euo pipefail set -E # HALT on subshell error -# set -T # DEBUG RETURN +set -T # DEBUG RETURN [[ $# -lt 1 ]] && >&2 echo 'ERROR: script expected!' && builtin exit 1 BASH_ARGV0="$1" && shift # to pretend script runs by itself @@ -253,6 +290,7 @@ BASH_ARGV0="$1" && shift # to pretend script runs by itself trap 'on_error $?' ERR trap 'on_exit $?' EXIT trap 'on_pipe' PIPE +trap 'on_return' RETURN if [[ -e /proc/$$/fd/3 ]]; then exec 4>&3 3>&-; else exec 4>/dev/tty; fi # swap fd 3 4 when fd 3 sent off exec 3>/dev/stderr 2>"$MIAOU_BASH_ERROR" diff --git a/test/stub/scenario.bash b/test/stub/scenario.bash index a9fef6a..119c58c 100755 --- a/test/stub/scenario.bash +++ b/test/stub/scenario.bash @@ -33,11 +33,6 @@ function do_last_false { ! true } -function do_return { - echo START - return 99 -} - function do_command_not_found { echo START command_not_found A B C @@ -50,6 +45,10 @@ function do_exit { echo SHOULD NOT APPEAR } +function do_return { + should_return +} + function do_unbound_associative { declare -A associative associative['A']='Abc' @@ -115,6 +114,10 @@ function call_function_which_will_exit { exit 99 } +function call_function_which_will_return { + return 199 +} + function F2 { echo "stdout A" # echo toto >>/tmp/toto @@ -155,6 +158,17 @@ function main { >&2 echo some trace in stderr2 } +function should_return { + echo A + if call_function_which_will_return; then + echo SUCCESS + else + echo FAILURE + fi + call_function_which_will_return + echo SHOULD NOT APPEAR +} + function F3 { echo F3 return 0