Commit | Line | Data |
---|---|---|
78a1a75c | 1 | #!/bin/bash |
997eb0be IK |
2 | # Copyright 2018 Ian Kelling |
3 | ||
4 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | # you may not use this file except in compliance with the License. | |
6 | # You may obtain a copy of the License at | |
7 | ||
8 | # http://www.apache.org/licenses/LICENSE-2.0 | |
9 | ||
10 | # Unless required by applicable law or agreed to in writing, software | |
11 | # distributed under the License is distributed on an "AS IS" BASIS, | |
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | # See the License for the specific language governing permissions and | |
14 | # limitations under the License. | |
15 | ||
acd03e1e | 16 | |
acd03e1e IK |
17 | # Commentary: Bash stack trace and error handling functions. This file |
18 | # is meant to be sourced. It loads some functions which you may want to | |
19 | # call manually (see the comments at the start of each one), and then | |
20 | # runs err-catch. See the README file for a slightly longer explanation. | |
21 | ||
a5c2ac43 IK |
22 | |
23 | ####################################### | |
24 | # Undoes err-catch. turns off exit and stack trace on error. | |
25 | ####################################### | |
997eb0be | 26 | err-allow() { |
acd03e1e | 27 | set +E +o pipefail; trap ERR |
997eb0be | 28 | } |
364203b2 | 29 | |
acd03e1e | 30 | |
a5c2ac43 IK |
31 | ####################################### |
32 | # Print stack trace | |
33 | # | |
34 | # usage: err-bash-trace [FRAME_START] | |
35 | # | |
36 | # It does not show function args unless you first run: | |
37 | # shopt -s extdebug | |
38 | # which err-catch & err-print does for you. | |
39 | # | |
40 | # FRAME_START The frame to start printing on. default=0. Useful when | |
41 | # printing from an ERR trap function to avoid printing | |
42 | # that function. | |
43 | ####################################### | |
44 | err-bash-trace() { | |
45 | local -i argc_index=0 frame i start=${1:-0} max_indent=8 indent | |
acd03e1e IK |
46 | local source |
47 | local extdebug=false | |
48 | if [[ $(shopt -p extdebug) == *-s* ]]; then | |
49 | extdebug=true | |
50 | fi | |
51 | for ((frame=0; frame < ${#FUNCNAME[@]}-1; frame++)); do | |
52 | argc=${BASH_ARGC[frame]} | |
53 | argc_index+=$argc | |
fb79b8bd | 54 | ((frame < start)) && continue |
acd03e1e IK |
55 | if (( ${#BASH_SOURCE[@]} > 1 )); then |
56 | source="${BASH_SOURCE[frame+1]}:${BASH_LINENO[frame]}:" | |
57 | fi | |
fb79b8bd | 58 | indent=$((frame-start + 1)) |
acd03e1e IK |
59 | indent=$((indent < max_indent ? indent : max_indent)) |
60 | printf "%${indent}s↳%sin \`%s" '' "$source" "${FUNCNAME[frame]}" | |
61 | if $extdebug; then | |
62 | for ((i=argc_index-1; i >= argc_index-argc; i--)); do | |
63 | printf " %s" "${BASH_ARGV[i]}" | |
64 | done | |
78a1a75c | 65 | fi |
acd03e1e IK |
66 | echo \' |
67 | done | |
a5c2ac43 | 68 | return 0 |
78a1a75c | 69 | } |
364203b2 | 70 | |
a5c2ac43 IK |
71 | ####################################### |
72 | # On error print stack trace and exit | |
73 | # | |
74 | # Globals: | |
75 | # ${_errcatch_cleanup[@]} Optional command & args that will run before exiting | |
76 | ####################################### | |
997eb0be | 77 | err-catch() { |
acd03e1e IK |
78 | set -E; shopt -s extdebug |
79 | _err-trap() { | |
80 | err=$? | |
81 | exec >&2 | |
82 | set +x | |
9ce3dca1 IK |
83 | echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err" |
84 | err-bash-trace 2 | |
85 | set -e # err trap does not work within an error trap | |
a0551468 | 86 | "${_errcatch_cleanup[@]:-:}" # note :-: is to be compatible with set -u |
acd03e1e IK |
87 | echo "$0: exiting with code $err" |
88 | exit $err | |
89 | } | |
90 | trap _err-trap ERR | |
91 | set -o pipefail | |
78a1a75c | 92 | } |
364203b2 | 93 | |
a5c2ac43 IK |
94 | ####################################### |
95 | # On error, print stack trace | |
96 | ####################################### | |
9ce3dca1 IK |
97 | err-print() { |
98 | # help: on errors: print stack trace | |
99 | # | |
100 | # This function depends on err-bash-trace. | |
101 | ||
102 | set -E; shopt -s extdebug | |
103 | _err-trap() { | |
104 | err=$? | |
105 | exec >&2 | |
106 | set +x | |
107 | echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err" | |
108 | err-bash-trace 2 | |
109 | } | |
110 | trap _err-trap ERR | |
111 | set -o pipefail | |
112 | } | |
113 | ||
114 | ||
a5c2ac43 IK |
115 | ####################################### |
116 | # On error, print stack trace | |
117 | # | |
118 | # Use this instead of the exit command to be more informative. | |
119 | # | |
120 | # usage: err-exit [EXIT_CODE] [MESSAGE] | |
121 | # | |
122 | # EXIT_CODE Default is 1. | |
123 | # MESSAGE Print MESSAGE to stderr. If only one of EXIT_CODE | |
124 | # and MESSAGE is given, we consider it to be an | |
125 | # exit code if it is a number. | |
126 | ####################################### | |
997eb0be | 127 | err-exit() { |
acd03e1e IK |
128 | exec >&2 |
129 | code=1 | |
41be570a | 130 | if [[ "$*" ]]; then |
acd03e1e IK |
131 | if [[ ${1/[^0-9]/} == "$1" ]]; then |
132 | code=$1 | |
133 | if [[ $2 ]]; then | |
a5c2ac43 | 134 | printf '%s\n' "$2" >&2 |
acd03e1e IK |
135 | fi |
136 | else | |
a5c2ac43 | 137 | printf '%s\n' "$0: $1" >&2 |
78a1a75c | 138 | fi |
acd03e1e IK |
139 | fi |
140 | echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}" | |
141 | err-bash-trace 2 | |
142 | echo "$0: exiting with code $code" | |
143 | exit $err | |
78a1a75c | 144 | } |
364203b2 | 145 | |
a5c2ac43 | 146 | # We want this more often than not, so run it now. |
acd03e1e | 147 | err-catch |