scripts/functions
changeset 3083 3a7b2eee9dcd
parent 3082 39ec9e913d79
child 3084 95df9d32afd2
     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 ]