[PATCH 1 of 1] scripts: add option to start an interactive debug shell

Yann E. MORIN yann.morin.1998@free.fr
Mon Oct 15 19:56:00 GMT 2012


# HG changeset patch
# User "Yann E. MORIN" <yann.morin.1998@free.fr>
# Date 1349560087 -7200
# Node ID 82c19a72f25a7b399f6be4e2c8c1cecc45d8c171
# Parent  2a616dab6531ad82876c3252cd2e1cb873375c3f
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, continue, or aborts
    at user's whim.

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: "Yann E. MORIN" <yann.morin.1998@free.fr>
Cc: Johannes Stezenbach <js@sig21.net>

diff --git a/config/global/ct-behave.in b/config/global/ct-behave.in
--- a/config/global/ct-behave.in
+++ b/config/global/ct-behave.in
@@ -87,4 +87,22 @@
       
       Say N, please.
 
+config DEBUG_INTERACTIVE
+    bool
+    prompt "Interactive shell on failed commands"
+    depends on EXPERIMENTAL
+    help
+      If you say 'y' here, then an interactive shell will be spawned for
+      each failed command run via CT_DoExecLog.
+      
+      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
+
 endif
diff --git a/scripts/functions b/scripts/functions
--- a/scripts/functions
+++ b/scripts/functions
@@ -5,10 +5,45 @@
 # Prepare the fault handler
 CT_OnError() {
     local ret=$?
+    local old_trap result
     local intro
     local file line func
     local step step_depth
 
+    # 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
+        old_trap="$(trap -p ERR)"
+        trap ERR
+        (
+            exec >&6
+            printf "Current command\n  %s\n" "${cur_cmd}"
+            printf "exited with error code: %d\n" ${ret}
+            printf "Please fix it up and finish by exiting the shell.\n"
+            while true; do
+                bash --rcfile <(echo "PS1='ct-ng:\w> '") -i
+                result=$?
+                case $result in
+                    1)  break;;
+                    2)  break;;
+                    3)  break;;
+                    *)  echo "please exit with one of these values:"
+                        echo "1  fixed, continue with next build command"
+                        echo "2  repeat this build command"
+                        echo "3  abort build"
+                        ;;
+                esac
+            done
+            exit $result
+        )
+        result=$?
+        case "${result}" in
+            1)  return;;
+            2)  touch "${CT_BUILD_DIR}/repeat"; return;;
+            # 3 is an abort, continue...
+        esac
+    fi
+
     # To avoid printing the backtace for each sub-shell
     # up to the top-level, just remember we've dumped it
     if [ ! -f "${CT_BUILD_DIR}/backtrace" ]; then
@@ -157,10 +192,11 @@
 # 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 +204,39 @@
             *)      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 ]

--
For unsubscribe information see http://sourceware.org/lists.html#faq



More information about the crossgcc mailing list