summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann E. MORIN" <yann.morin.1998@free.fr>2012-10-06 21:48:07 (GMT)
committerYann E. MORIN" <yann.morin.1998@free.fr>2012-10-06 21:48:07 (GMT)
commitdd98145bc182af39645ba6bea0e5441afd84a1d3 (patch)
tree757098117f03c960017353fbcbb20a08c077d2f6
parentdf3be9eef3cc4e0b111d25d75b12fa5ed69a3c1d (diff)
scripts: add option to start an interactive debug shell
Add an option that, when a command fails: - starts an interactive shell with the failed command's environment - attempts re-execution of the failed command, continues, or aborts at user's whim. Before starting the debug-shell, the backtrace is printed. When exiting for an abort, the standard error message is printed. Based on an idea and a patch from: Johannes Stezenbach <js@sig21.net> http://sourceware.org/ml/crossgcc/2012-09/msg00144.html Signed-off-by: Johannes Stezenbach <js@sig21.net> [yann.morin.1998@free.fr: integrate in the fault handler] Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr> Acked-by: Johannes Stezenbach <js@sig21.net> Patchwork-Id: 191571 Patchwork-Id: 191668
-rw-r--r--config/global/ct-behave.in19
-rw-r--r--scripts/crosstool-NG.sh.in8
-rw-r--r--scripts/functions96
3 files changed, 120 insertions, 3 deletions
diff --git a/config/global/ct-behave.in b/config/global/ct-behave.in
index bbe4324..6256a34 100644
--- a/config/global/ct-behave.in
+++ b/config/global/ct-behave.in
@@ -87,4 +87,23 @@ config NO_OVERIDE_LC_MESSAGES
Say N, please.
+config DEBUG_INTERACTIVE
+ bool
+ prompt "Interactive shell on failed commands"
+ help
+ If you say 'y' here, then an interactive shell will be spawned for
+ each failed command.
+
+ This shell will have the same environment that the failed command
+ was run with, and the working directory will be set to the directory
+ the failed command was run in.
+
+ After you fix the issue, you can exit the interactive shell with any
+ of these exit codes:
+ 1 the issue was fixed, continue the build with the next command
+ 2 the issue was fixed, re-run the failed command
+ 3 abort the build
+
+ Note: '2' is only possible for commands run via CT_DoExecLog, though.
+
endif
diff --git a/scripts/crosstool-NG.sh.in b/scripts/crosstool-NG.sh.in
index 1f1ffdb..a7a8015 100644
--- a/scripts/crosstool-NG.sh.in
+++ b/scripts/crosstool-NG.sh.in
@@ -25,6 +25,14 @@
. .config.2
# Yes! We can do full logging from now on!
+# If we want an interactive debug-shell, we must ensure these FDs
+# are indeed connected to a terminal (and not redirected in any way).
+if [ "${CT_DEBUG_INTERACTIVE}" = "y" -a ! \( -t 0 -a -t 6 -a -t 2 \) ]; then
+ CT_DoLog ERROR "Can't spawn interactive debug-shell,"
+ CT_DoLog ERROR "because stdout/stderr has been redirected."
+ exit 1
+fi
+
# Override the locale early, in case we ever translate crosstool-NG messages
if [ -z "${CT_NO_OVERIDE_LC_MESSAGES}" ]; then
export LC_ALL=C
diff --git a/scripts/functions b/scripts/functions
index 5180726..7bb58ab 100644
--- a/scripts/functions
+++ b/scripts/functions
@@ -5,6 +5,8 @@
# Prepare the fault handler
CT_OnError() {
local ret=$?
+ local result
+ local old_trap
local intro
local file line func
local step step_depth
@@ -35,6 +37,62 @@ CT_OnError() {
CT_DoLog ERROR ">> ${intro}: ${func}[${file}${line}]"
intro=" called from"
done
+
+ # If the user asked for interactive debugging, dump him/her to a shell
+ if [ "${CT_DEBUG_INTERACTIVE}" = "y" ]; then
+ # We do not want this sub-shell exit status to be caught, because
+ # it is absolutely legit that it exits with non-zero.
+ # Save the trap handler to restore it after our debug-shell
+ old_trap="$(trap -p ERR)"
+ trap -- ERR
+ (
+ exec >&6
+ printf "\r \n\nCurrent command"
+ if [ -n "${cur_cmd}" ]; then
+ printf ":\n %s\n" "${cur_cmd}"
+ else
+ printf " (unknown), "
+ fi
+ printf "exited with error code: %d\n" ${ret}
+ printf "Please fix it up and finish by exiting the shell with one of these values:\n"
+ printf " 1 fixed, continue with next build command\n"
+ if [ -n "${cur_cmd}" ]; then
+ printf " 2 repeat this build command\n"
+ fi
+ printf " 3 abort build\n\n"
+ while true; do
+ ${bash} --rcfile <(printf "PS1='ct-ng:\w> '\nPROMPT_COMMAND=''\n") -i
+ result=$?
+ case $result in
+ 1) printf "\nContinuing past the failed command.\n\n"
+ break
+ ;;
+ 2) if [ -n "${cur_cmd}" ]; then
+ printf "\nRe-trying last command.\n\n"
+ break
+ fi
+ ;;&
+ 3) break;;
+ *) printf "\nPlease exit with one of these values:\n"
+ printf " 1 fixed, continue with next build command\n"
+ if [ -n "${cur_cmd}" ]; then
+ printf " 2 repeat this build command\n"
+ fi
+ printf " 3 abort build\n"
+ ;;
+ esac
+ done
+ exit $result
+ )
+ result=$?
+ # Restore the trap handler
+ eval "${old_trap}"
+ case "${result}" in
+ 1) rm -f "${CT_WORK_DIR}/backtrace"; return;;
+ 2) rm -f "${CT_WORK_DIR}/backtrace"; touch "${CT_BUILD_DIR}/repeat"; return;;
+ # 3 is an abort, continue...
+ esac
+ fi
fi
# And finally, in top-level shell, print some hints
@@ -157,10 +215,11 @@ CT_DoLog() {
# Usage: CT_DoExecLog <level> [VAR=val...] <command> [parameters...]
CT_DoExecLog() {
local level="$1"
+ local cur_cmd
shift
(
for i in "$@"; do
- tmp_log+="'${i}' "
+ cur_cmd+="'${i}' "
done
while true; do
case "${1}" in
@@ -168,8 +227,39 @@ CT_DoExecLog() {
*) break;;
esac
done
- CT_DoLog DEBUG "==> Executing: ${tmp_log}"
- "${@}" 2>&1 |CT_DoLog "${level}"
+ # This while-loop goes hand-in-hand with the ERR trap handler:
+ # - if the command terminates successfully, then we hit the break
+ # statement, and we exit the loop
+ # - if the command terminates in error, then the ERR handler kicks
+ # in, then:
+ # - if the user did *not* ask for interactive debugging, the ERR
+ # handler exits, and we hit the end of the sub-shell
+ # - if the user did ask for interactive debugging, the ERR handler
+ # spawns a shell. Upon termination of this shell, the ERR handler
+ # examines the exit status of the shell:
+ # - if 1, the ERR handler returns; then we hit the else statement,
+ # then the break, and we exit the 'while' loop, to continue the
+ # build;
+ # - if 2, the ERR handler touches the repeat file, and returns;
+ # then we hit the if statement, and we loop for one more
+ # iteration;
+ # - if 3, the ERR handler exits with the command's exit status,
+ # and we're dead;
+ # - for any other exit status of the shell, the ERR handler
+ # prints an informational message, and respawns the shell
+ #
+ # This allows a user to get an interactive shell that has the same
+ # environment (PATH and so on) that the failed command was ran with.
+ while true; do
+ rm -f "${CT_BUILD_DIR}/repeat"
+ CT_DoLog DEBUG "==> Executing: ${cur_cmd}"
+ "${@}" 2>&1 |CT_DoLog "${level}"
+ if [ -f "${CT_BUILD_DIR}/repeat" ]; then
+ continue
+ else
+ break
+ fi
+ done
)
# Catch failure of the sub-shell
[ $? -eq 0 ]