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 | ||
997eb0be | 22 | err-allow() { |
acd03e1e IK |
23 | # help: turn off exit and stack trace on error. undoes err-catch |
24 | set +E +o pipefail; trap ERR | |
997eb0be | 25 | } |
364203b2 | 26 | |
997eb0be | 27 | err-bash-trace() { |
acd03e1e IK |
28 | # help: print stack trace |
29 | # | |
30 | # Note: It does not show function args unless you first run: | |
31 | # shopt -s extdebug | |
9ce3dca1 IK |
32 | # which err-catch & err-print does for you. |
33 | # | |
34 | # $1 is the frame to start printing on. default -1. Useful when | |
35 | # printing from an ERR trap function. | |
acd03e1e IK |
36 | |
37 | local -i argc_index=0 frame i start=${1:-1} max_indent=8 indent | |
38 | local source | |
39 | local extdebug=false | |
40 | if [[ $(shopt -p extdebug) == *-s* ]]; then | |
41 | extdebug=true | |
42 | fi | |
43 | for ((frame=0; frame < ${#FUNCNAME[@]}-1; frame++)); do | |
44 | argc=${BASH_ARGC[frame]} | |
45 | argc_index+=$argc | |
46 | ((frame < start)) && continue | |
47 | if (( ${#BASH_SOURCE[@]} > 1 )); then | |
48 | source="${BASH_SOURCE[frame+1]}:${BASH_LINENO[frame]}:" | |
49 | fi | |
50 | indent=$((frame-start+1)) | |
51 | indent=$((indent < max_indent ? indent : max_indent)) | |
52 | printf "%${indent}s↳%sin \`%s" '' "$source" "${FUNCNAME[frame]}" | |
53 | if $extdebug; then | |
54 | for ((i=argc_index-1; i >= argc_index-argc; i--)); do | |
55 | printf " %s" "${BASH_ARGV[i]}" | |
56 | done | |
78a1a75c | 57 | fi |
acd03e1e IK |
58 | echo \' |
59 | done | |
78a1a75c | 60 | } |
364203b2 | 61 | |
997eb0be | 62 | err-catch() { |
364203b2 | 63 | # help: on errors: print stack trace and exit |
acd03e1e | 64 | # |
364203b2 | 65 | # You can set "${_errcatch_cleanup[@]}" to a command and it will run before exiting. |
acd03e1e IK |
66 | # This function depends on err-bash-trace. |
67 | ||
68 | set -E; shopt -s extdebug | |
69 | _err-trap() { | |
70 | err=$? | |
71 | exec >&2 | |
72 | set +x | |
9ce3dca1 IK |
73 | echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err" |
74 | err-bash-trace 2 | |
75 | set -e # err trap does not work within an error trap | |
a0551468 | 76 | "${_errcatch_cleanup[@]:-:}" # note :-: is to be compatible with set -u |
acd03e1e IK |
77 | echo "$0: exiting with code $err" |
78 | exit $err | |
79 | } | |
80 | trap _err-trap ERR | |
81 | set -o pipefail | |
78a1a75c | 82 | } |
364203b2 | 83 | |
9ce3dca1 IK |
84 | err-print() { |
85 | # help: on errors: print stack trace | |
86 | # | |
87 | # This function depends on err-bash-trace. | |
88 | ||
89 | set -E; shopt -s extdebug | |
90 | _err-trap() { | |
91 | err=$? | |
92 | exec >&2 | |
93 | set +x | |
94 | echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err" | |
95 | err-bash-trace 2 | |
96 | } | |
97 | trap _err-trap ERR | |
98 | set -o pipefail | |
99 | } | |
100 | ||
101 | ||
997eb0be | 102 | err-exit() { |
acd03e1e IK |
103 | # usage: err-exit [EXIT_CODE] [MESSAGE] |
104 | # help: exit and print stack trace. | |
105 | # | |
106 | # Use this instead of the exit command to be more informative. default | |
107 | # EXIT_CODE is 1. If only one of EXIT_CODE and MESSAGE is given, | |
108 | # we consider it to be an exit code if it is a number. | |
109 | # This function depends on err-bash-trace. | |
110 | ||
111 | exec >&2 | |
112 | code=1 | |
41be570a | 113 | if [[ "$*" ]]; then |
acd03e1e IK |
114 | if [[ ${1/[^0-9]/} == "$1" ]]; then |
115 | code=$1 | |
116 | if [[ $2 ]]; then | |
41be570a | 117 | printf '%s\n' "$2" |
acd03e1e IK |
118 | fi |
119 | else | |
41be570a | 120 | printf '%s\n' "$0: $1" |
78a1a75c | 121 | fi |
acd03e1e IK |
122 | fi |
123 | echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}" | |
124 | err-bash-trace 2 | |
125 | echo "$0: exiting with code $code" | |
126 | exit $err | |
78a1a75c | 127 | } |
364203b2 | 128 | |
acd03e1e | 129 | err-catch |