1.1 --- a/scripts/functions Sun Oct 14 23:46:15 2012 +0000
1.2 +++ b/scripts/functions Sat Oct 06 23:48:07 2012 +0200
1.3 @@ -5,6 +5,8 @@
1.4 # Prepare the fault handler
1.5 CT_OnError() {
1.6 local ret=$?
1.7 + local result
1.8 + local old_trap
1.9 local intro
1.10 local file line func
1.11 local step step_depth
1.12 @@ -35,6 +37,62 @@
1.13 CT_DoLog ERROR ">> ${intro}: ${func}[${file}${line}]"
1.14 intro=" called from"
1.15 done
1.16 +
1.17 + # If the user asked for interactive debugging, dump him/her to a shell
1.18 + if [ "${CT_DEBUG_INTERACTIVE}" = "y" ]; then
1.19 + # We do not want this sub-shell exit status to be caught, because
1.20 + # it is absolutely legit that it exits with non-zero.
1.21 + # Save the trap handler to restore it after our debug-shell
1.22 + old_trap="$(trap -p ERR)"
1.23 + trap -- ERR
1.24 + (
1.25 + exec >&6
1.26 + printf "\r \n\nCurrent command"
1.27 + if [ -n "${cur_cmd}" ]; then
1.28 + printf ":\n %s\n" "${cur_cmd}"
1.29 + else
1.30 + printf " (unknown), "
1.31 + fi
1.32 + printf "exited with error code: %d\n" ${ret}
1.33 + printf "Please fix it up and finish by exiting the shell with one of these values:\n"
1.34 + printf " 1 fixed, continue with next build command\n"
1.35 + if [ -n "${cur_cmd}" ]; then
1.36 + printf " 2 repeat this build command\n"
1.37 + fi
1.38 + printf " 3 abort build\n\n"
1.39 + while true; do
1.40 + ${bash} --rcfile <(printf "PS1='ct-ng:\w> '\nPROMPT_COMMAND=''\n") -i
1.41 + result=$?
1.42 + case $result in
1.43 + 1) printf "\nContinuing past the failed command.\n\n"
1.44 + break
1.45 + ;;
1.46 + 2) if [ -n "${cur_cmd}" ]; then
1.47 + printf "\nRe-trying last command.\n\n"
1.48 + break
1.49 + fi
1.50 + ;;&
1.51 + 3) break;;
1.52 + *) printf "\nPlease exit with one of these values:\n"
1.53 + printf " 1 fixed, continue with next build command\n"
1.54 + if [ -n "${cur_cmd}" ]; then
1.55 + printf " 2 repeat this build command\n"
1.56 + fi
1.57 + printf " 3 abort build\n"
1.58 + ;;
1.59 + esac
1.60 + done
1.61 + exit $result
1.62 + )
1.63 + result=$?
1.64 + # Restore the trap handler
1.65 + eval "${old_trap}"
1.66 + case "${result}" in
1.67 + 1) rm -f "${CT_WORK_DIR}/backtrace"; return;;
1.68 + 2) rm -f "${CT_WORK_DIR}/backtrace"; touch "${CT_BUILD_DIR}/repeat"; return;;
1.69 + # 3 is an abort, continue...
1.70 + esac
1.71 + fi
1.72 fi
1.73
1.74 # And finally, in top-level shell, print some hints
1.75 @@ -157,10 +215,11 @@
1.76 # Usage: CT_DoExecLog <level> [VAR=val...] <command> [parameters...]
1.77 CT_DoExecLog() {
1.78 local level="$1"
1.79 + local cur_cmd
1.80 shift
1.81 (
1.82 for i in "$@"; do
1.83 - tmp_log+="'${i}' "
1.84 + cur_cmd+="'${i}' "
1.85 done
1.86 while true; do
1.87 case "${1}" in
1.88 @@ -168,8 +227,39 @@
1.89 *) break;;
1.90 esac
1.91 done
1.92 - CT_DoLog DEBUG "==> Executing: ${tmp_log}"
1.93 - "${@}" 2>&1 |CT_DoLog "${level}"
1.94 + # This while-loop goes hand-in-hand with the ERR trap handler:
1.95 + # - if the command terminates successfully, then we hit the break
1.96 + # statement, and we exit the loop
1.97 + # - if the command terminates in error, then the ERR handler kicks
1.98 + # in, then:
1.99 + # - if the user did *not* ask for interactive debugging, the ERR
1.100 + # handler exits, and we hit the end of the sub-shell
1.101 + # - if the user did ask for interactive debugging, the ERR handler
1.102 + # spawns a shell. Upon termination of this shell, the ERR handler
1.103 + # examines the exit status of the shell:
1.104 + # - if 1, the ERR handler returns; then we hit the else statement,
1.105 + # then the break, and we exit the 'while' loop, to continue the
1.106 + # build;
1.107 + # - if 2, the ERR handler touches the repeat file, and returns;
1.108 + # then we hit the if statement, and we loop for one more
1.109 + # iteration;
1.110 + # - if 3, the ERR handler exits with the command's exit status,
1.111 + # and we're dead;
1.112 + # - for any other exit status of the shell, the ERR handler
1.113 + # prints an informational message, and respawns the shell
1.114 + #
1.115 + # This allows a user to get an interactive shell that has the same
1.116 + # environment (PATH and so on) that the failed command was ran with.
1.117 + while true; do
1.118 + rm -f "${CT_BUILD_DIR}/repeat"
1.119 + CT_DoLog DEBUG "==> Executing: ${cur_cmd}"
1.120 + "${@}" 2>&1 |CT_DoLog "${level}"
1.121 + if [ -f "${CT_BUILD_DIR}/repeat" ]; then
1.122 + continue
1.123 + else
1.124 + break
1.125 + fi
1.126 + done
1.127 )
1.128 # Catch failure of the sub-shell
1.129 [ $? -eq 0 ]