fix regression in last commit, ommiting a frame
[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
IK
22
23#######################################
24# Undoes err-catch. turns off exit and stack trace on error.
25#######################################
997eb0be 26err-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#######################################
44err-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 77err-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
97err-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 127err-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 147err-catch