[bitbake-devel,2/3] build: print the originating filename/lineno of failing Bash shell functions
Details
Commit Message
@@ -304,19 +304,46 @@ def exec_func_python(func, d, runfile, cwd=None):
def shell_trap_code():
return '''#!/bin/sh\n
# Emit a useful diagnostic if something fails:
-bb_exit_handler() {
+bb_sh_exit_handler() {
ret=$?
- case $ret in
- 0) ;;
- *) case $BASH_VERSION in
- "") echo "WARNING: exit code $ret from a shell command.";;
- *) echo "WARNING: ${BASH_SOURCE[0]}:${BASH_LINENO[0]} exit $ret from '$BASH_COMMAND'";;
- esac
- exit $ret
- esac
+ if [ "$ret" != 0 ]; then
+ echo "WARNING: exit code $ret from a shell command."
+ fi
+ exit $ret
}
-trap 'bb_exit_handler' 0
-set -e
+
+bb_bash_err_handler() {
+ ret=$?
+ echo "WARNING: ${BASH_SOURCE[0]}:${BASH_LINENO[0]} exit $ret from '$BASH_COMMAND'"
+
+ # Determine the line on which the failing shell function is declared
+ shopt -s extdebug
+ function_line=$(declare -F "${FUNCNAME[1]}" | awk '{print $2}')
+ shopt -u extdebug
+
+ # Grab the special comment that precedes the function declaration - this comment contains the filename and lineno
+ # that BitBake tracked as being the original location for the emitted shell function.
+ prev_line=$((function_line - 1))
+ function_location=$(sed "${prev_line}q;d" "${BASH_SOURCE[0]}")
+ pattern='# line: ([[:digit:]]+), file: (.+)'
+ if [[ $function_location =~ $pattern ]]; then
+ relative_line=$((BASH_LINENO[0] - function_line))
+ # TODO: handle 'autogenerated' (e.g. from _append) by walking up the call chain to the nearest real file?
+ # TODO: actually just fix BitBake to include filename/lineno information when _append is encountered, maybe as
+ # separate varflags.
+ echo "INFO: ${BASH_REMATCH[2]}:$((BASH_REMATCH[1] + relative_line)) is where original shell function '${FUNCNAME[1]}' is declared"
+ fi
+
+ exit $ret
+}
+
+case $BASH_VERSION in
+"") trap 'bb_sh_exit_handler' 0
+ set -e
+ ;;
+*) trap 'bb_bash_err_handler' ERR
+ set -eE
+esac
'''
def create_progress_handler(func, progress, logfile, d):
This patch modifies the shell trap code which is injected into shell tasks. The behavior for 'sh' shells is unchanged. But now when a Bash shell function fails, the following happens: 1. At the line on which an error occurred, the enclosing function name is grabbed. 1. If the shell is 'sh', simply report the return code (just as it did before) Before: | install: cannot stat 'source': No such file or directory | WARNING: /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.95318:1 exit 1 from 'install -m 0644 source dest' After: | install: cannot stat 'source': No such file or directory | WARNING: /home/laplante/repos/oe-core/build/tmp-glibc/work/core2-64-oe-linux/libsolv/0.7.14-r0/temp/run.do_compile.95318:139 exit 1 from 'install -m 0644 source dest' | INFO: /home/laplante/repos/oe-core/meta/recipes-extended/libsolv/libsolv_0.7.14.bb:32 is where original shell function 'my_incorrect_function' is declared Signed-off-by: Chris Laplante <chris.laplante@agilent.com> --- lib/bb/build.py | 49 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-)