#!/usr/bin/env bash # constants MIAOU_BASH_ERROR=$(mktemp -t "$(basename "$0").XXXXXXXX" --tmpdir="/run/user/$(id -u)") MIAOU_DEBUG=${MIAOU_DEBUG:-false} readonly MIAOU_BASH_ERROR MIAOU_DEBUG ## functions function is_true { [[ "${1:-}" == 'true' ]] } # FIXME: define an alias to bypass ARG evaluation when unnecessary! # example: # alias toto="bash -c \"[[ \\\$MIAOU_DEBUG == 'true' ]] && echo yes \\\$* || echo nope\"" function miaou_debug { is_true "${MIAOU_DEBUG}" && >/dev/tty builtin echo -e "\r\e[90mDEBUG <==> \e[95m$*\e[0m" || true } function on_error { code="${1:-100}" miaou_debug "on_error: $code ($$ -- $BASHPID)" if [[ $$ == "$BASHPID" ]]; then >&2 echo "${BASH_SOURCE[1]}: line ${BASH_LINENO[0]}: command_error: ${code}" failure_type="COMMAND_ERROR" exit "$code" else >&2 echo "${BASH_SOURCE[1]}: line ${BASH_LINENO[0]}: subshell_error: ${code}" kill -PIPE $$ fi } function dump_stderr { >&2 printf '' # force flush miaou_debug --stderr-- mapfile -t tmp_error <"$MIAOU_BASH_ERROR" for i in "${tmp_error[@]}"; do >&4 echo -e "$i"; done miaou_debug --end of stderr-- } function on_exit { code="${1:-0}" failure_type="${failure_type:-UNDEFINED}" dump_stderr miaou_debug "on_exit $code $failure_type" } function on_pipe { local code=141 # default code error for pipe local tmp_error regex mapfile -t tmp_error <"$MIAOU_BASH_ERROR" last_error="${tmp_error[-1]}" regex='.*: line [0-9]+: subshell_error: ([0-9]+)' [[ $last_error =~ $regex ]] && code=${BASH_REMATCH[1]} && failure_type="SUBSHELL_ERROR" miaou_debug on_pipe: "${code}" exit "$code" } ## main set -euo pipefail set -E # HALT on subshell error # set -T # DEBUG RETURN trap 'on_error $?' ERR trap 'on_exit $?' EXIT trap 'on_pipe' PIPE echo "--SOURCE scenario ${BASHPID}" exec 3> >(tee "$MIAOU_BASH_ERROR" >/dev/null) 4>/dev/stderr source ./test/stub/scenario.bash subshell_term 2>&3 echo "--SUCCESS scenario"