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