Skip to content

Commit 21a3f44

Browse files
authored
Merge pull request #635 from DannyBen/add/stacktrace-library
Add `stacktrace` standard library
2 parents 340dd18 + ed3da9d commit 21a3f44

File tree

13 files changed

+301
-1
lines changed

13 files changed

+301
-1
lines changed

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Each of these examples demonstrates one aspect or feature of bashly.
6767
- [completions](completions#readme) - adding bash completion functionality
6868
- [validations](validations#readme) - adding validation functions for arguments, flags or environment variables
6969
- [hooks](hooks#readme) - adding before/after hooks
70+
- [stacktrace](stacktrace#readme) - adding stacktrace on error
7071

7172
## Real-world-like examples
7273

examples/stacktrace/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
download

examples/stacktrace/README.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Stack Trace Example
2+
3+
Demonstrates how to show stack trace on error.
4+
5+
This example was generated with:
6+
7+
```bash
8+
$ bashly init --minimal
9+
$ bashly add stacktrace
10+
$ bashly generate
11+
# ... now create and edit src/initialize.sh to match the example ...
12+
# ... now edit src/root_command.sh to match the example ...
13+
$ bashly generate
14+
```
15+
16+
<!-- include: src/initialize.sh src/root_command.sh -->
17+
18+
-----
19+
20+
## `bashly.yml`
21+
22+
````yaml
23+
name: download
24+
help: Sample minimal application without commands
25+
version: 0.1.0
26+
27+
args:
28+
- name: source
29+
required: true
30+
help: URL to download from
31+
- name: target
32+
help: "Target filename (default: same as source)"
33+
34+
flags:
35+
- long: --force
36+
short: -f
37+
help: Overwrite existing files
38+
39+
examples:
40+
- download example.com
41+
- download example.com ./output -f
42+
````
43+
44+
## `src/initialize.sh`
45+
46+
````bash
47+
## initialize hook
48+
##
49+
## Any code here will be placed inside the `initialize()` function and called
50+
## before running anything else.
51+
##
52+
## You can safely delete this file if you do not need it.
53+
trap 'stacktrace' ERR
54+
set -o errtrace
55+
56+
````
57+
58+
## `src/root_command.sh`
59+
60+
````bash
61+
## trigger an error by calling a function that does not exist
62+
no_such_command
63+
64+
````
65+
66+
67+
## Output
68+
69+
### `$ ./download`
70+
71+
````shell
72+
missing required argument: SOURCE
73+
usage: download SOURCE [TARGET] [OPTIONS]
74+
75+
76+
````
77+
78+
### `$ ./download --help`
79+
80+
````shell
81+
download - Sample minimal application without commands
82+
83+
Usage:
84+
download SOURCE [TARGET] [OPTIONS]
85+
download --help | -h
86+
download --version | -v
87+
88+
Options:
89+
--force, -f
90+
Overwrite existing files
91+
92+
--help, -h
93+
Show this help
94+
95+
--version, -v
96+
Show version number
97+
98+
Arguments:
99+
SOURCE
100+
URL to download from
101+
102+
TARGET
103+
Target filename (default: same as source)
104+
105+
Examples:
106+
download example.com
107+
download example.com ./output -f
108+
109+
110+
111+
````
112+
113+
### `$ ./download something`
114+
115+
````shell
116+
./download: line 15: no_such_command: command not found
117+
./download:15 in `root_command`: no_such_command
118+
119+
Stack trace:
120+
from ./download:15 in `root_command`
121+
from ./download:254 in `run`
122+
from ./download:260 in `main`
123+
124+
125+
````
126+
127+
128+

examples/stacktrace/src/bashly.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: download
2+
help: Sample minimal application without commands
3+
version: 0.1.0
4+
5+
args:
6+
- name: source
7+
required: true
8+
help: URL to download from
9+
- name: target
10+
help: "Target filename (default: same as source)"
11+
12+
flags:
13+
- long: --force
14+
short: -f
15+
help: Overwrite existing files
16+
17+
examples:
18+
- download example.com
19+
- download example.com ./output -f

examples/stacktrace/src/initialize.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## initialize hook
2+
##
3+
## Any code here will be placed inside the `initialize()` function and called
4+
## before running anything else.
5+
##
6+
## You can safely delete this file if you do not need it.
7+
trap 'stacktrace' ERR
8+
set -o errtrace
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## Stack trace functions [@bashly-upgrade stacktrace]
2+
## This file is a part of Bashly standard library
3+
##
4+
## Usage:
5+
## This function is designed to be called on error.
6+
##
7+
## To enable this functionality, add these lines to your `src/initialize.sh`
8+
## file (Run `bashly add hooks` to add this file):
9+
##
10+
## trap 'stacktrace' ERR
11+
## set -o errtrace
12+
##
13+
## Note that this functionality also requires `set -e`, which is enabled by
14+
## default in bashly generated scripts.
15+
##
16+
stacktrace() {
17+
local exit_status="$?"
18+
local i=0
19+
local caller_output line func file
20+
21+
printf "%s:%s in \`%s\`: %s\n" "${BASH_SOURCE[0]}" "${BASH_LINENO[0]}" "${FUNCNAME[1]}" "$BASH_COMMAND"
22+
printf "\nStack trace:\n"
23+
while caller_output="$(caller $i)"; do
24+
read -r line func file <<<"$caller_output"
25+
printf "\tfrom %s:%s in \`%s\`\n" "$file" "$line" "$func"
26+
i=$((i + 1))
27+
done
28+
exit "$exit_status"
29+
} >&2
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
## trigger an error by calling a function that does not exist
2+
no_such_command

examples/stacktrace/test.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env bash
2+
3+
set -x
4+
5+
bashly add stacktrace --force
6+
bashly generate
7+
8+
### Try Me ###
9+
10+
./download
11+
./download --help
12+
./download something

lib/bashly/libraries/libraries.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,19 @@ settings:
102102
- source: "settings/settings.yml"
103103
target: "settings.yml"
104104

105+
stacktrace:
106+
help: Add a function that shows stacktrace on error.
107+
files:
108+
- source: "stacktrace/stacktrace.sh"
109+
target: "%{user_lib_dir}/stacktrace.%{user_ext}"
110+
post_install_message: |
111+
The stacktrace function is designed to be called automatically on error.
112+
113+
To enable this functionality, add these lines to your `initialize.sh`:
114+
115+
g`trap 'stacktrace' ERR`
116+
g`set -o errtrace`
117+
105118
strings:
106119
help: Copy an additional configuration file to your project, allowing you to customize all the tips and error strings.
107120
files:
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## Stack trace functions [@bashly-upgrade stacktrace]
2+
## This file is a part of Bashly standard library
3+
##
4+
## Usage:
5+
## This function is designed to be called on error.
6+
##
7+
## To enable this functionality, add these lines to your `src/initialize.sh`
8+
## file (Run `bashly add hooks` to add this file):
9+
##
10+
## trap 'stacktrace' ERR
11+
## set -o errtrace
12+
##
13+
## Note that this functionality also requires `set -e`, which is enabled by
14+
## default in bashly generated scripts.
15+
##
16+
stacktrace() {
17+
local exit_status="$?"
18+
local i=0
19+
local caller_output line func file
20+
21+
printf "%s:%s in \`%s\`: %s\n" "${BASH_SOURCE[0]}" "${BASH_LINENO[0]}" "${FUNCNAME[1]}" "$BASH_COMMAND"
22+
printf "\nStack trace:\n"
23+
while caller_output="$(caller $i)"; do
24+
read -r line func file <<<"$caller_output"
25+
printf "\tfrom %s:%s in \`%s\`\n" "$file" "$line" "$func"
26+
i=$((i + 1))
27+
done
28+
exit "$exit_status"
29+
} >&2

0 commit comments

Comments
 (0)