|
|
|
@ -1,14 +1,17 @@ |
|
|
|
#!/usr/bin/env bash |
|
|
|
|
|
|
|
# CONSTANTS |
|
|
|
BASH_BACK_ERROR=$(mktemp -t "$(basename $0).XXXXXXXX" --tmpdir=/run/user/$(id -u)) |
|
|
|
|
|
|
|
BASH_BACK_NAME=$(basename "${0}") |
|
|
|
BASH_BACK_ERROR=$(mktemp -t "${BASH_BACK_NAME}.XXXXXXXX" --tmpdir="/run/user/$(id -u)") |
|
|
|
BASH_BACK_DEBUG=${BASH_BACK_DEBUG:-false} |
|
|
|
readonly BASH_BACK_NAME BASH_BACK_ERROR BASH_BACK_DEBUG |
|
|
|
|
|
|
|
# FUNCTIONS |
|
|
|
|
|
|
|
function on_return { |
|
|
|
if [[ "${BASH_COMMAND}" == 'return '* ]]; then |
|
|
|
code=$(echo "${BASH_COMMAND}" | cut -d' ' -f2) # regex does not work here unfortunately! thus use of basic cut |
|
|
|
code=$(echo "${BASH_COMMAND}" | cut -d' ' -f2) # regex does not work here unfortunately! |
|
|
|
if [[ -n "$code" ]] && [[ "$code" -ne 0 ]]; then |
|
|
|
trap - DEBUG |
|
|
|
>&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: return $code from ${FUNCNAME[1]}" |
|
|
|
@ -16,12 +19,12 @@ function on_return { |
|
|
|
fi |
|
|
|
} |
|
|
|
|
|
|
|
# overridden function which permits stacktracing of original `return` statement |
|
|
|
# overridden function which permits backtracing of original `return` statement |
|
|
|
function exit { |
|
|
|
code=${1:-0} |
|
|
|
>&2 echo "${BASH_SOURCE[2]}:${BASH_LINENO[0]} exit $@" |
|
|
|
# >&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: exit $@" |
|
|
|
builtin exit $code |
|
|
|
>&2 echo "${BASH_SOURCE[2]}:${BASH_LINENO[0]} exit $code" |
|
|
|
builtin exit "$code" |
|
|
|
} |
|
|
|
|
|
|
|
function on_exit { |
|
|
|
@ -31,19 +34,19 @@ function on_exit { |
|
|
|
stack_functions=("${FUNCNAME[@]}") |
|
|
|
stack_sources=("${BASH_SOURCE[@]}") |
|
|
|
|
|
|
|
unset stack_lines[-1] |
|
|
|
unset stack_lines[-1] |
|
|
|
unset stack_functions[0] |
|
|
|
unset stack_functions[-1] |
|
|
|
unset 'stack_lines[-1]' |
|
|
|
unset 'stack_lines[-1]' |
|
|
|
unset 'stack_functions[0]' |
|
|
|
unset 'stack_functions[-1]' |
|
|
|
stack_functions[-1]='<main>' |
|
|
|
unset stack_sources[0] |
|
|
|
unset stack_sources[-1] |
|
|
|
unset 'stack_sources[0]' |
|
|
|
unset 'stack_sources[-1]' |
|
|
|
|
|
|
|
if [[ "${stack_functions[1]}" == exit && "${stack_sources[1]}" == "${BASH_SOURCE[0]}" ]]; then |
|
|
|
# the exit case scenario |
|
|
|
unset stack_functions[1] |
|
|
|
unset stack_sources[1] |
|
|
|
unset stack_lines[0] |
|
|
|
unset 'stack_functions[1]' |
|
|
|
unset 'stack_sources[1]' |
|
|
|
unset 'stack_lines[0]' |
|
|
|
fi |
|
|
|
|
|
|
|
stack_lines=("${stack_lines[@]}") |
|
|
|
@ -53,9 +56,9 @@ function on_exit { |
|
|
|
stack_summary=() |
|
|
|
|
|
|
|
if [[ $code -gt 0 ]]; then |
|
|
|
last_error=$(tail -n1 $BASH_BACK_ERROR) |
|
|
|
last_error=$(tail -n1 "$BASH_BACK_ERROR") |
|
|
|
last_source=${stack_sources[0]} |
|
|
|
last_source=${last_source//./"\."} # replace . by \. |
|
|
|
last_source=${last_source//./"\."} # replace '.' with '\.' |
|
|
|
regex1="^$last_source: line ([0-9]+): (.*)\$" |
|
|
|
regex2="^$last_source:([0-9]+) (.*)\$" |
|
|
|
if [[ "$last_error" =~ $regex1 || "$last_error" =~ $regex2 ]]; then |
|
|
|
@ -92,7 +95,7 @@ function on_exit { |
|
|
|
fi |
|
|
|
|
|
|
|
cleanup |
|
|
|
builtin exit $code |
|
|
|
builtin exit "$code" |
|
|
|
} |
|
|
|
|
|
|
|
function dump_summary { |
|
|
|
@ -104,8 +107,8 @@ function dump_summary { |
|
|
|
|
|
|
|
function dump_stderr { |
|
|
|
last_trim=${1:-false} |
|
|
|
mapfile -t tmp_error <$BASH_BACK_ERROR |
|
|
|
$last_trim && unset tmp_error[-1] && tmp_error=("${tmp_error[@]}") |
|
|
|
mapfile -t tmp_error <"$BASH_BACK_ERROR" |
|
|
|
$last_trim && unset 'tmp_error[-1]' && tmp_error=("${tmp_error[@]}") |
|
|
|
if [[ "${#tmp_error[@]}" -gt 0 ]]; then |
|
|
|
$BASH_BACK_DEBUG && >/dev/tty echo '---stderr---' |
|
|
|
for i in "${tmp_error[@]}"; do |
|
|
|
@ -122,7 +125,7 @@ function success { |
|
|
|
function cleanup { |
|
|
|
trap - ERR TERM INT EXIT |
|
|
|
exec 3>&- 4>&- |
|
|
|
rm $BASH_BACK_ERROR |
|
|
|
rm "$BASH_BACK_ERROR" |
|
|
|
} |
|
|
|
|
|
|
|
# MAIN |
|
|
|
@ -133,9 +136,13 @@ set -TEue -o pipefail |
|
|
|
trap 'on_exit $?' ERR TERM INT EXIT |
|
|
|
trap 'on_return' DEBUG |
|
|
|
|
|
|
|
# magic FD |
|
|
|
exec 3> >(tee $BASH_BACK_ERROR >/dev/null) 4>/dev/stderr |
|
|
|
# magic FD + delayed tee |
|
|
|
exec 3> >(tee "$BASH_BACK_ERROR" >/dev/null) 4>/dev/stderr |
|
|
|
|
|
|
|
# magic $0 |
|
|
|
BASH_ARGV0="$1" # to pretend script runs by itself |
|
|
|
|
|
|
|
$BASH_BACK_DEBUG && >/dev/tty echo '---stdout---' |
|
|
|
source $1 2>&3 |
|
|
|
# shellcheck source=/dev/null |
|
|
|
source "$1" 2>&3 |
|
|
|
success |