You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

98 lines
2.3 KiB

#!/usr/bin/env bash
# CONSTANTS
DEBUG=true
TMP_ERROR=$(mktemp -t "$(basename $0).XXXXXXXX" --tmpdir=/run/user/$(id -u))
SCRIPT=$1
# FUNCTIONS
# overridden function which permits stacktracing of original `return` statement
function return {
code=${1:-0}
[[ $code -gt 0 ]] && >&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: return $@"
builtin return $code
}
# overridden function which permits stacktracing of original `return` statement
function exit {
code=${1:-0}
>&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: exit $@"
builtin exit $code
}
function on_exit {
code=${1:-0}
>&4 dump_stderr
stack_lines=("${BASH_LINENO[@]}")
stack_functions=("${FUNCNAME[@]}")
stack_sources=("${BASH_SOURCE[@]}")
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]
stack_lines=("${stack_lines[@]}")
stack_functions=("${stack_functions[@]}")
stack_sources=("${stack_sources[@]}")
if [[ $code -gt 0 ]]; then
$DEBUG && >/dev/tty echo '---stacktrace---'
last_error=$(tail -n1 $TMP_ERROR)
last_source=${stack_sources[0]}
last_source=${last_source//./"\."} # replace . by \.
regex="^$last_source: line ([0-9]+): (.*)$"
if [[ "$last_error" =~ $regex ]]; then
line=${BASH_REMATCH[1]}
message=${BASH_REMATCH[2]}
regex=': unbound variable$'
[[ $code == 1 ]] && [[ "$message" =~ $regex ]] && stack_lines[0]=$line
>&4 echo -e "ERROR $code: [$message]"
else
>&4 echo "ERROR $code: <undefined>"
fi
for i in "${!stack_functions[@]}"; do
>&4 printf "\t%30s\t%s\n" "${stack_sources[$i]}:${stack_lines[$i]}" "${stack_functions[$i]}"
done
fi
# echo "${stack_lines[@]}"
# echo "${stack_functions[@]}"
# echo "${stack_sources[@]}"
cleanup
builtin exit $code
}
function dump_stderr {
if [[ -s $TMP_ERROR ]]; then
$DEBUG && >/dev/tty echo '---stderr---'
cat $TMP_ERROR
fi
}
function success {
>&2 dump_stderr
cleanup
}
function cleanup {
trap - ERR TERM INT EXIT
exec 3>&- 4>&-
rm $TMP_ERROR
}
# MAIN
set -TEue -o pipefail
trap 'on_exit $?' ERR TERM INT EXIT
# magic FD
exec 3>$TMP_ERROR 4>/dev/stderr
$DEBUG && >/dev/tty echo '---stdout---'
source $SCRIPT 2>&3
success