mirror of
https://github.com/kvz/bash3boilerplate.git
synced 2025-04-21 05:50:47 +00:00
Compare commits
405 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2e878ec30f | ||
|
726ce78de7 | ||
|
51e7644bb1 | ||
|
985b0046c4 | ||
|
38f269c660 | ||
|
f6b61410c0 | ||
|
42e50f66c8 | ||
|
c5012d0190 | ||
|
14421bd791 | ||
|
7af1f75c5e | ||
|
320609fceb | ||
|
9e70d61133 | ||
|
354c304b19 | ||
|
a6a2d961ae | ||
|
7f9a31f8d8 | ||
|
758fa92f05 | ||
|
555beb1add | ||
|
2d145e24e9 | ||
|
b2140d5ec6 | ||
|
7a022bccf3 | ||
|
55cd329ebd | ||
|
879422d09f | ||
|
1fb7cc4337 | ||
|
f2ccef5b36 | ||
|
2e68b71743 | ||
|
28deb39d86 | ||
|
33a3fd706b | ||
|
ddc6440177 | ||
|
c4585291f3 | ||
|
9a27140e7e | ||
|
cb06f0aa70 | ||
|
e45247d4aa | ||
|
a50ad7007e | ||
|
41172fcc8f | ||
|
9f0c37e2ac | ||
|
0a6e3925dc | ||
|
7d3927b025 | ||
|
49eed4f283 | ||
|
3d47083fcf | ||
|
e516a60169 | ||
|
d1c26b9ac1 | ||
|
85efe41ad9 | ||
|
80ab935cf6 | ||
|
86f20e34b7 | ||
|
d113e87c96 | ||
|
9f06b1a8c6 | ||
|
8a14c0e3d5 | ||
|
c086796573 | ||
|
05cdcdaa12 | ||
|
8ceed901d5 | ||
|
76fbd2104b | ||
|
9cc3bf124c | ||
|
986fec8090 | ||
|
ea15c44c7e | ||
|
febd9e354b | ||
|
13d74bb4f1 | ||
|
ab3857e3bd | ||
|
e5da0aa249 | ||
|
bbb8afea4d | ||
|
e078dd2b91 | ||
|
9fd3f1df64 | ||
|
1005ceeec8 | ||
|
56eab89caa | ||
|
186d9ff6a0 | ||
|
23ce0e6b85 | ||
|
6392674f70 | ||
|
222a95793b | ||
|
269627deec | ||
|
1238b67abe | ||
|
5cc417485a | ||
|
971a83ea3a | ||
|
14dc823cca | ||
|
599faf3830 | ||
|
0d096350b0 | ||
|
24e7ceaaf7 | ||
|
f1ad8a5655 | ||
|
c0f58127bb | ||
|
6689117e5d | ||
|
a28d594d5f | ||
|
bccefb0061 | ||
|
9194295c64 | ||
|
8146667ea1 | ||
|
2019caa899 | ||
|
357ea3778a | ||
|
f377dfb16e | ||
|
f77b400dc9 | ||
|
03662dd404 | ||
|
b8a4aba3c2 | ||
|
685442bbcc | ||
|
16b543114b | ||
|
7791e3ca0f | ||
|
1152cc3cf7 | ||
|
b4048f3f12 | ||
|
11cd18e179 | ||
|
05f35415a6 | ||
|
ec9087f0d2 | ||
|
5a9a68be2b | ||
|
97f9676754 | ||
|
83c77f8df3 | ||
|
04cf154b3e | ||
|
4085bc461e | ||
|
8e548e766e | ||
|
d908e8b362 | ||
|
9250d036dc | ||
|
ea57d157c7 | ||
|
95b9cb1469 | ||
|
ff89a1154b | ||
|
9f31a5e969 | ||
|
664e55ad1e | ||
|
7b7d31a1bf | ||
|
ba0e7150cb | ||
|
2048e4303e | ||
|
327cba75c9 | ||
|
ee869a9584 | ||
|
f57e37eb68 | ||
|
2463cd6cc9 | ||
|
860a7de899 | ||
|
236e3c7eca | ||
|
cf7d25e3d1 | ||
|
d25d6a0106 | ||
|
9b7a9ccd17 | ||
|
38622845a8 | ||
|
0289532f18 | ||
|
2fcd0a765b | ||
|
48848fd17c | ||
|
84685a451b | ||
|
12ea4dd75f | ||
|
63c402912a | ||
|
0c2a580041 | ||
|
eac5ad8022 | ||
|
9f3aa6ead9 | ||
|
c19c08a775 | ||
|
a0e9bb0c05 | ||
|
d134dfd145 | ||
|
f6996a1595 | ||
|
1c672bf8cb | ||
|
87545c8f9a | ||
|
111a00e1f0 | ||
|
6f0cfaddb1 | ||
|
5f815c7f98 | ||
|
c4429de7d5 | ||
|
d35fa94ffc | ||
|
7759cba46f | ||
|
efd984e01d | ||
|
ef66310b27 | ||
|
3e9afe28c3 | ||
|
ef04df597b | ||
|
e7e85ddff3 | ||
|
b2326bf75e | ||
|
9b86dcced8 | ||
|
2bbf6eed2e | ||
|
ff37895ea4 | ||
|
39e0607bcb | ||
|
748fdcfab3 | ||
|
c52a73598e | ||
|
755eb0d02f | ||
|
b1861f9fab | ||
|
b280139595 | ||
|
cb29b2f984 | ||
|
2d5506cb36 | ||
|
986191210a | ||
|
0d1f488365 | ||
|
7eea26c7b4 | ||
|
d879ae1fe0 | ||
|
382217eebf | ||
|
ba2d901cc2 | ||
|
36db2227c7 | ||
|
7cf9ea708d | ||
|
7f9419cda0 | ||
|
47be547cfa | ||
|
21cafb3c34 | ||
|
ea6bbd058f | ||
|
884c55c616 | ||
|
31ee23ba9b | ||
|
f44385ced3 | ||
|
9c3ba0ad77 | ||
|
00acb0383b | ||
|
0c878b7623 | ||
|
d383e8c098 | ||
|
ac7fad3e29 | ||
|
d17152253c | ||
|
8c35bc9e76 | ||
|
bbb589ee0a | ||
|
80f6c82c18 | ||
|
191b8118e0 | ||
|
785e7e9f8b | ||
|
044ef6d1c5 | ||
|
42e9ec669d | ||
|
d0bfc96166 | ||
|
a5c3d1c793 | ||
|
ce755604da | ||
|
f763b47d2b | ||
|
15b1092262 | ||
|
70f7a2905c | ||
|
44c856d41a | ||
|
971096d73b | ||
|
19dfb9cff4 | ||
|
cfbfd527d5 | ||
|
cf85af8c15 | ||
|
02cb82c9e6 | ||
|
9350e0574c | ||
|
2c91db3faa | ||
|
1e69fd5e21 | ||
|
68323978d4 | ||
|
0a1b799e77 | ||
|
c4c0e6ffec | ||
|
d21dd23827 | ||
|
b8bdaf371a | ||
|
290c65d4b9 | ||
|
b38310e915 | ||
|
b14eec4675 | ||
|
8ce2ed44c0 | ||
|
96ce0c8206 | ||
|
f0cb04dec7 | ||
|
046f3ab99a | ||
|
1e9d1548a3 | ||
|
1f13dfae78 | ||
|
9b739b4cf0 | ||
|
bdb501bec0 | ||
|
64dc269217 | ||
|
d556893774 | ||
|
93c9c25c88 | ||
|
f41c05d971 | ||
|
16d699b67b | ||
|
36b9ce280b | ||
|
a178a95c26 | ||
|
fc766c7437 | ||
|
96220cea12 | ||
|
ddd89a787a | ||
|
b4d16f5317 | ||
|
2295da9233 | ||
|
0bed7a3782 | ||
|
5b5d5608b4 | ||
|
c0a2a56cee | ||
|
3c114b9d1d | ||
|
e61028f679 | ||
|
049002a1cc | ||
|
a7665cbf4f | ||
|
74a701a66e | ||
|
57ebf1569d | ||
|
e7a0b2f412 | ||
|
064f30502f | ||
|
539443b3ca | ||
|
0181129aff | ||
|
87530e756e | ||
|
dfd799b4e5 | ||
|
d2195eee3c | ||
|
9928ef16d7 | ||
|
8f06b1a927 | ||
|
e6275924b5 | ||
|
f82bbe59b0 | ||
|
4445c181bb | ||
|
86ab1128ed | ||
|
839df144ca | ||
|
195e84fe09 | ||
|
34e437b23c | ||
|
35b51072b3 | ||
|
8bbba18f7e | ||
|
03a2ec5adf | ||
|
bd49dda4b4 | ||
|
56e02e9306 | ||
|
3f0a7c9166 | ||
|
1f2e1842b3 | ||
|
2b3ee1d195 | ||
|
2d302dd8ac | ||
|
f6a3bb55d4 | ||
|
3d22171ba3 | ||
|
b3c3746948 | ||
|
c8441451bc | ||
|
e4848e360a | ||
|
e0055e5dc1 | ||
|
845a9dfb50 | ||
|
ca8c0a19df | ||
|
1166c878be | ||
|
9dea81377e | ||
|
272dd896d0 | ||
|
bc1b96db71 | ||
|
818d7c81c7 | ||
|
494584b6fd | ||
|
8e9814bc6a | ||
|
dba28c0e8e | ||
|
be3ca43dff | ||
|
28865fc633 | ||
|
0bfba0661c | ||
|
e56e21dc37 | ||
|
09cf71d23c | ||
|
64488e569a | ||
|
e0aadaf50c | ||
|
008face7c8 | ||
|
4926bbc942 | ||
|
83b13e5f55 | ||
|
649b5a0f44 | ||
|
f7fc992b2d | ||
|
efefd5cf2b | ||
|
5ee427eef5 | ||
|
b71ca507ab | ||
|
8bed4a2aaf | ||
|
4c45be4269 | ||
|
156f12f53f | ||
|
16401017e0 | ||
|
2d25f6b0dc | ||
|
400f29b30c | ||
|
95365e6f92 | ||
|
26e282c37f | ||
|
7effd3c9d1 | ||
|
90f52ea19a | ||
|
65338c1660 | ||
|
fe733c1356 | ||
|
ff881d529f | ||
|
ae230acc3b | ||
|
0487f12fff | ||
|
00f84ff8d9 | ||
|
fb8e44864d | ||
|
d0ece6da76 | ||
|
707a14634c | ||
|
18525f72da | ||
|
244e54daa6 | ||
|
12f1013611 | ||
|
d70312e916 | ||
|
fc7802d707 | ||
|
8687e384eb | ||
|
bbd4b7689b | ||
|
300ca2e3ad | ||
|
fcb6d93028 | ||
|
e20bb2900c | ||
|
547825b336 | ||
|
87017c728f | ||
|
0db28b0eec | ||
|
0b79205fb1 | ||
|
9be08bb692 | ||
|
41b9451b20 | ||
|
1fc44d2034 | ||
|
a4326476a3 | ||
|
c1fecf33c3 | ||
|
676989a779 | ||
|
51213e8786 | ||
|
6dc7e1f92a | ||
|
c111725665 | ||
|
abb480c394 | ||
|
fa7f217556 | ||
|
32e061c102 | ||
|
1143670cae | ||
|
a86d8d82b1 | ||
|
db690268ea | ||
|
d43cecf24a | ||
|
0917b75cb9 | ||
|
a6d2a2ad2f | ||
|
366d8c7c9c | ||
|
0001bfe30c | ||
|
2b46168792 | ||
|
1271bf807d | ||
|
583efe734b | ||
|
07ab2a95b4 | ||
|
7fbf9ea8e5 | ||
|
707583a93c | ||
|
e538a2be34 | ||
|
c3f5bcf8c9 | ||
|
180282d97d | ||
|
b404c87999 | ||
|
f2823681d0 | ||
|
67f2eafc81 | ||
|
c8773b999b | ||
|
591642cb38 | ||
|
c3297e4a7a | ||
|
619688bb0f | ||
|
1557e9d66a | ||
|
72cea95865 | ||
|
33887625a7 | ||
|
c4b4f44676 | ||
|
f114dea34d | ||
|
0c4a6c78e5 | ||
|
980a5950d6 | ||
|
cc57b8db69 | ||
|
2019c5146a | ||
|
d365e8dcea | ||
|
915f858d5e | ||
|
cbe70aa80e | ||
|
ff907092a3 | ||
|
cdc69d9e03 | ||
|
56721e9cd5 | ||
|
df3d535ab1 | ||
|
894c7fe538 | ||
|
2196cc4411 | ||
|
5b4800bad8 | ||
|
472c9e3b74 | ||
|
90ad85f419 | ||
|
d9a0c11e49 | ||
|
9935335ee8 | ||
|
e90ad7421f | ||
|
9d2bcdbfb4 | ||
|
bfb8d40f6c | ||
|
dd5950975d | ||
|
7a9d116d2c | ||
|
ae074aac0c | ||
|
30cfd19fd9 | ||
|
ecd6a9f04b | ||
|
7a3a07989f | ||
|
dbedd8f983 | ||
|
dde3b70596 | ||
|
bdc8778b2c | ||
|
63cd89a659 | ||
|
68219d21d4 | ||
|
c71b6d14c4 | ||
|
4c256ed58d | ||
|
f2e8ff236a |
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
Thanks for contributing to b3bp! As part of your PR, have you:
|
||||
|
||||
- [ ] Added an item in [CHANGELOG.md](https://github.com/kvz/bash3boilerplate/blob/HEAD/CHANGELOG.md) with attribution?
|
||||
- [ ] Added your name to the [README.md](https://github.com/kvz/bash3boilerplate/blob/HEAD/README.md#authors)
|
||||
- [ ] Linted your code? (`make test` should do the trick)
|
||||
|
||||
If so, great! Feel free to replace this message with a description of your work and hit submit!
|
5
.github/dependabot.yml
vendored
Normal file
5
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
groups:
|
||||
production-dependencies:
|
||||
dependency-type: 'production'
|
||||
development-dependencies:
|
||||
dependency-type: 'development'
|
30
.github/workflows/ci.yml
vendored
Normal file
30
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: b3bp CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
jobs:
|
||||
ci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 18.x
|
||||
- name: Install
|
||||
run: |
|
||||
corepack yarn
|
||||
- name: Lint
|
||||
env:
|
||||
SHELLCHECK_SEVERITY: warning
|
||||
run: |
|
||||
corepack yarn lint
|
||||
- name: Test
|
||||
run: |
|
||||
corepack yarn test
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1 +1,5 @@
|
||||
.yarn
|
||||
assets/build
|
||||
env.sh
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
3
.shellcheckrc
Normal file
3
.shellcheckrc
Normal file
@ -0,0 +1,3 @@
|
||||
external-sources=true
|
||||
shell=bash
|
||||
color=always
|
8
.vscode/bash3boilerplate.code-workspace
vendored
Normal file
8
.vscode/bash3boilerplate.code-workspace
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": ".."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
1
.yarnrc.yml
Normal file
1
.yarnrc.yml
Normal file
@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
175
CHANGELOG.md
Normal file
175
CHANGELOG.md
Normal file
@ -0,0 +1,175 @@
|
||||
# Changelog
|
||||
|
||||
Here's is a combined todo/done list. You can see what todos are planned for the upcoming release, as well as ideas that may/may not make into a release in `Ideas`.
|
||||
|
||||
## Ideas
|
||||
|
||||
Unplanned.
|
||||
|
||||
- [ ] Better style guide checking (#84)
|
||||
|
||||
## main
|
||||
|
||||
Released: TBA.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/2.7.2...main).
|
||||
|
||||
- [ ]
|
||||
|
||||
## 2.7.2
|
||||
|
||||
Released: 2023-08-29
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.4.1...2.7.2).
|
||||
|
||||
- [x] Upgrade and cleanup node dependencies
|
||||
- [x] Remove lanyon-based website in favor of simple redirect to github for bash3boilerplate.sh
|
||||
- [x] Make tests pass again
|
||||
- [x] Make linting and style checking separate actions
|
||||
- [x] Add feature to edit/update comments in ini file (#132, @rfuehrer)
|
||||
- [x] Upgrade to `lanyon@0.1.16`
|
||||
- [x] Capture correct error_code in err_report (#124, @eval)
|
||||
- [x] Enhanced ini file handling: create new file, create new sections, handle default section, read key from given section (@rfuehrer)
|
||||
|
||||
## v2.4.2
|
||||
|
||||
Released: 2019-11-07.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.4.1...v2.4.2).
|
||||
|
||||
- [x] Upgrade to `lanyon@0.1.16`
|
||||
- [x] Capture correct error_code in err_report (#124, @eval)
|
||||
- [x] Enhanced ini file handling: create new file, create new sections, handle default section, read key from given section (@rfuehrer)
|
||||
|
||||
## v2.4.1
|
||||
|
||||
Released: 2019-11-07.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.3.0...v2.4.1).
|
||||
|
||||
- [x] Upgrade to `lanyon@0.1.7`
|
||||
- [x] Allow counting how many times an argument is used (@genesiscloud)
|
||||
- [x] Fix typos in megamount (thanks @gsaponaro)
|
||||
- [x] Enable color in screen or tmux (#92, @gmasse)
|
||||
- [x] Change `egrep` to `grep -E` in test and lib scripts to comply with ShellCheck (#92, @gmasse)
|
||||
- [x] Fix typo in FAQ (#92, @gmasse)
|
||||
- [x] Fix Travis CI failure on src/templater.sh (@gmasse)
|
||||
- [x] Add magic variable which contains full command invocation
|
||||
- [x] More contrasted alert and emergency colors (#111 @gmeral)
|
||||
- [x] Add support for repeatable arguments (@genesiscloud)
|
||||
- [x] Fix remaining warnings with shellcheck v0.7.0 (#107, @genesiscloud)
|
||||
|
||||
## v2.4.0
|
||||
|
||||
Released: 2016-12-21.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.3.0...v2.4.0).
|
||||
|
||||
- [x] Upgrade to `lanyon@0.0.143`
|
||||
|
||||
## v2.3.0
|
||||
|
||||
Released: 2016-12-21.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.2.0...v2.3.0).
|
||||
|
||||
- [x] Add magic variable `__i_am_main_script` to distinguish if b3bp is being sourced or called directly (#45, @zbeekman)
|
||||
- [x] Add style checks for tab characters and trailing whitespace (@zbeekman)
|
||||
- [x] Add backtracing to help localize errors (#44, @zbeekman)
|
||||
- [x] Additional FAQ entries (#47, suggested by @gdevenyi, implemented by @zbeekman)
|
||||
- [x] Ensure that shifting over `--` doesn't throw an errexit error (#21, @zbeekman)
|
||||
- [x] Add Pull Request template (#83)
|
||||
|
||||
## v2.2.0
|
||||
|
||||
Released: 2016-12-21.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.1.0...v2.2.0).
|
||||
|
||||
- [x] README and FAQ improvements (#66, @mstreuhofer)
|
||||
- [x] Add support for sourcing b3bp (#61, @mstreuhofer)
|
||||
- [x] Upgrade all Node.js dependencies for development (#78)
|
||||
- [x] Switch to http://lanyon.io for static site building, add a new logo
|
||||
- [x] Cleanup environment variables (#58, @mstreuhofer)
|
||||
- [x] Support multi-line logs (#57, @mstreuhofer)
|
||||
- [x] Run shellcheck as part of the acceptance test (#79, @mstreuhofer)
|
||||
- [x] Brace all variables, used `[[` instead of `[` (#33, #76, @mstreuhofer)
|
||||
- [x] Add automatic usage validation for required args (#22, #65, @mstreuhofer)
|
||||
- [x] Remove all usage of eval (@mstreuhofer)
|
||||
- [x] Get rid of awk, sed & egrep usage (#71, @mstreuhofer)
|
||||
- [x] Fix auto-color-off code (#69, #70, @mstreuhofer)
|
||||
- [x] Use shellcheck to find and fix unclean code (#68, #80, @mstreuhofer)
|
||||
- [x] Allow for multiline opt description in `__usage` (#7, @mstreuhofer)
|
||||
- [x] Allow `__usage` and `__helptext` to be defined before sourcing `main.sh` thus makeing b3bp behave like a library (@mstreuhofer)
|
||||
- [x] Add the same License text to each script header (@mstreuhofer)
|
||||
|
||||
## v2.1.0
|
||||
|
||||
Released: 2016-11-08.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v2.0.0...v2.1.0).
|
||||
|
||||
- [x] Cleanup b3bp variables (adds prefixes across the board) (thanks @mstreuhofer)
|
||||
- [x] Add multi-line logging support (thanks @mstreuhofer)
|
||||
- [x] Mangle long-option names to allow dashes (thanks @zbeekman)
|
||||
- [x] Remove OS detection altogether (#38, thx @zbeekman)
|
||||
- [x] Offer the main template for download as http://bash3boilerplate.sh/main.sh
|
||||
- [x] Better OS detection (#38, thx @moviuro)
|
||||
- [x] Improve README copy (#34, thx galaktos)
|
||||
- [x] Fix unquoted variable access within (#34 thx galaktos)
|
||||
- [x] For delete-key-friendliness, bundle the commandline definition block along with its parser
|
||||
- [x] Less verbose header comments
|
||||
- [x] For delete-key-friendliness, don't crash on undeclared help vars
|
||||
- [x] Introduce `errtrace`, which is on by default (BREAKING)
|
||||
- [x] Add a configurable `helptext` that is left alone by the parses and allows you to have a richer help
|
||||
- [x] Add a simple documentation website
|
||||
- [x] Add best practice of using `__double_underscore_prefixed_vars` to indicate global variables that are solely controlled inside your script
|
||||
- [x] Make license more permissive by not requiring distribution of the LICENSE file if the copyright & attribution comments are left intact
|
||||
- [x] Respect `--no-color` by setting the `NO_COLOR` flag in `main.sh` (#25, thx @gdevenyi)
|
||||
- [x] Split out changelog into separate file
|
||||
- [x] Added a [FAQ](./FAQ.md) (#15, #14, thanks @rouson)
|
||||
- [x] Fix Travis OSX testing (before, it would silently pass failures) (#10)
|
||||
- [x] Enable dashes in long, GNU style options, as well as numbers (thanks @zbeekman)
|
||||
|
||||
## v2.0.0
|
||||
|
||||
Released: 2016-02-17.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v1.2.1...v2.0.0).
|
||||
|
||||
- [x] Add tests for `templater` and follow Library export best practices
|
||||
- [x] Add tests for `ini_val` and follow Library export best practices
|
||||
- [x] Add tests for `parse_url` and follow Library export best practices
|
||||
- [x] Add tests for `megamount` and follow Library export best practices
|
||||
- [x] Remove `bump` from `src` (BREAKING)
|
||||
- [x] Remove `semver` from `src` (BREAKING)
|
||||
|
||||
## v1.2.1
|
||||
|
||||
Released: 2016-02-17.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v1.2.0...v1.2.1).
|
||||
|
||||
- [x] Add Travis CI automated testing for OSX (thanks @zbeekman)
|
||||
|
||||
## v1.2.0
|
||||
|
||||
Released: 2016-02-16.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v1.1.0...v1.2.0).
|
||||
|
||||
- [x] Allow disabling colors via `NO_COLOR` environment variable
|
||||
- [x] Enable `errexit`, `nounset` and `pipefail` options at the top of the script already
|
||||
- [x] More refined colors (thanks @arathai)
|
||||
- [x] Add a changelog to the README
|
||||
- [x] Add `__os` magic var (limited to discovering OSX and defaulting to Linux for now)
|
||||
- [x] Add `__base` magic var (`main`, if the source script is `main.sh`)
|
||||
- [x] Enable long, GNU style options (thanks @zbeekman)
|
||||
- [x] Add Travis CI automated testing for Linux
|
||||
|
||||
## v1.1.0
|
||||
|
||||
Released: 2015-06-29.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/v1.0.3...v1.1.0).
|
||||
|
||||
- [x] Add `ALLOW_REMAINDERS` configuration to templater
|
||||
- [x] Fix typo: 'debugmdoe' to 'debugmode' (thanks @jokajak)
|
||||
- [x] Use `${BASH_SOURCE[0]}` for `__file` instead of `${0}`
|
||||
|
||||
## v1.0.3
|
||||
|
||||
Released: 2014-11-02.
|
||||
[Diff](https://github.com/kvz/bash3boilerplate/compare/5db569125319a89b9561b434db84e4d91faefb63...v1.0.3).
|
||||
|
||||
- [x] Add `ini_val`, `megamount`, `parse_url`
|
||||
- [x] Add re-usable libraries in `./src`
|
||||
- [x] Use npm as an additional distribution channel
|
171
FAQ.md
Normal file
171
FAQ.md
Normal file
@ -0,0 +1,171 @@
|
||||
[This document is formatted with GitHub-Flavored Markdown. ]: #
|
||||
[For better viewing, including hyperlinks, read it online at ]: #
|
||||
[https://github.com/kvz/bash3boilerplate/blob/HEAD/FAQ.md ]: #
|
||||
|
||||
## Contents
|
||||
|
||||
- [What is a CLI](#what-is-a-cli)?
|
||||
- [How do I incorporate BASH3 Boilerplate into my own project](#how-do-i-incorporate-bash3-boilerplate-into-my-own-project)?
|
||||
- [How do I add a command-line flag](#how-do-i-add-a-command-line-flag)?
|
||||
- [How do I access the value of a command-line argument](#how-do-i-access-the-value-of-a-command-line-argument)?
|
||||
- [What is a magic variable](#what-is-a-magic-variable)?
|
||||
- [How do I submit an issue report](#how-do-i-submit-an-issue-report)?
|
||||
- [How can I contribute to this project](#how-can-i-contribute-to-this-project)?
|
||||
- [Why are you typing BASH in all caps](#why-are-you-typing-bash-in-all-caps)?
|
||||
- [You are saying you are portable, but why won't b3bp code run in dash / busybox / posh / ksh / mksh / zsh](#you-are-saying-you-are-portable-but-why-wont-b3bp-code-run-in-dash--busybox--posh--ksh--mksh--zsh)?
|
||||
- [How do I do Operating System detection](#how-do-i-do-operating-system-detection)?
|
||||
- [How do I access a potentially unset (environment) variable](#how-do-i-access-a-potentially-unset-environment-variable)?
|
||||
- [How can I detect or trap CTRL-C and other signals](#how-can-i-detect-or-trap-ctrl-c-and-other-signals)?
|
||||
- [How can I get the PID of my running script](how-can-i-get-the-pid-of-my-running-script)?
|
||||
|
||||
<!--more-->
|
||||
|
||||
# Frequently Asked Questions
|
||||
|
||||
## What is a CLI?
|
||||
|
||||
A "CLI" is a [command-line interface](https://en.wikipedia.org/wiki/Command-line_interface).
|
||||
|
||||
## How do I incorporate BASH3 Boilerplate into my own project?
|
||||
|
||||
You can incorporate BASH3 Boilerplate into your project in one of two ways:
|
||||
|
||||
1. Copy the desired portions of [`main.sh`](http://bash3boilerplate.sh/main.sh) into your own script.
|
||||
1. Download [`main.sh`](http://bash3boilerplate.sh/main.sh) and start pressing the delete-key to remove unwanted things
|
||||
|
||||
Once the `main.sh` has been tailor-made for your project, you can either append your own script in the same file, or source it in the following ways:
|
||||
|
||||
1. Copy [`main.sh`](http://bash3boilerplate.sh/main.sh) into the same directory as your script and then edit and embed it into your script using Bash's `source` include feature, e.g.:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source main.sh
|
||||
```
|
||||
|
||||
1. Source [`main.sh`](http://bash3boilerplate.sh/main.sh) in your script or at the command line:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
source main.sh
|
||||
```
|
||||
|
||||
## How do I add a command-line flag?
|
||||
|
||||
1. Copy the line from the `main.sh` [read block](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L109-L115) that most resembles the desired behavior and paste the line into the same block.
|
||||
1. Edit the single-character (e.g., `-d`) and, if present, the multi-character (e.g., `--debug`) versions of the flag in the copied line.
|
||||
1. Omit the `[arg]` text in the copied line, if the desired flag takes no arguments.
|
||||
1. Omit or edit the text after `Default=` to set or not set default values, respectively.
|
||||
1. Omit the `Required.` text, if the flag is optional.
|
||||
|
||||
## How do I access the value of a command-line argument?
|
||||
|
||||
To find out the value of an argument, append the corresponding single-character flag to the text `$arg_`. For example, if the [read block]
|
||||
contains the line
|
||||
|
||||
```bash
|
||||
-t --temp [arg] Location of tempfile. Default="/tmp/bar"
|
||||
```
|
||||
|
||||
then you can evaluate the corresponding argument and assign it to a variable as follows:
|
||||
|
||||
```bash
|
||||
__temp_file_name="${arg_t}"
|
||||
```
|
||||
|
||||
## What is a magic variable?
|
||||
|
||||
The [magic variables](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L26-L28) in `main.sh` are special in that they have a different value, depending on your environment. You can use `${__file}` to get a reference to your current script, and `${__dir}` to get a reference to the directory it lives in. This is not to be confused with the location of the calling script that might be sourcing the `${__file}`, which is accessible via `${0}`, or the current directory of the administrator running the script, accessible via `$(pwd)`.
|
||||
|
||||
## How do I submit an issue report?
|
||||
|
||||
Please visit our [Issues](https://github.com/kvz/bash3boilerplate/issues) page.
|
||||
|
||||
## How can I contribute to this project?
|
||||
|
||||
Please fork this repository. After that, create a branch containing your suggested changes and submit a pull request based on the main branch
|
||||
of <https://github.com/kvz/bash3boilerplate/>. We are always more than happy to accept your contributions!
|
||||
|
||||
## Why are you typing BASH in all caps?
|
||||
|
||||
As an acronym, Bash stands for Bourne-again shell, and is usually written with one uppercase.
|
||||
This project's name, however, is "BASH3 Boilerplate". It is a reference to
|
||||
"[HTML5 Boilerplate](https://html5boilerplate.com/)", which was founded to serve a similar purpose,
|
||||
only for crafting webpages.
|
||||
Somewhat inconsistent – but true to Unix ancestry – the abbreviation for our project is "b3bp".
|
||||
|
||||
## You are saying you are portable, but why won't b3bp code run in dash / busybox / posh / ksh / mksh / zsh?
|
||||
|
||||
When we say _portable_, we mean across Bash versions. Bash is widespread and most systems
|
||||
offer at least version 3 of it. Make sure you have that available and b3bp will work for you.
|
||||
|
||||
We run automated tests to make sure that it will. Here is some proof for the following platforms:
|
||||
|
||||
- [Linux](https://travis-ci.org/kvz/bash3boilerplate/jobs/109804166#L91-L94) `GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)`
|
||||
- [OSX](https://travis-ci.org/kvz/bash3boilerplate/jobs/109804167#L2453-L2455) `GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)`
|
||||
|
||||
This portability, however, does not mean that we try to be compatible with
|
||||
KornShell, Zsh, posh, yash, dash, or other shells. We allow syntax that would explode if
|
||||
you pasted it in anything but Bash 3 and up.
|
||||
|
||||
## How do I do Operating System detection?
|
||||
|
||||
We used to offer a magic `__os` variable, but we quickly [discovered](https://github.com/kvz/bash3boilerplate/issues/38) that it would be hard
|
||||
to create a satisfactory abstraction that is not only correct, but also covers enough use-cases,
|
||||
while still having a relatively small footprint in `main.sh`.
|
||||
|
||||
For simple OS detection, we recommend using the `${OSTYPE}` variable available in Bash as
|
||||
is demoed in [this stackoverflow post](http://stackoverflow.com/a/8597411/151666):
|
||||
|
||||
```bash
|
||||
if [[ "${OSTYPE}" = "linux-gnu" ]]; then
|
||||
echo "GNU Linux"
|
||||
elif [[ "${OSTYPE}" = "darwin"* ]]; then
|
||||
echo "Mac OSX"
|
||||
elif [[ "${OSTYPE}" = "cygwin" ]]; then
|
||||
echo "POSIX compatibility layer and Linux environment emulation for Windows"
|
||||
elif [[ "${OSTYPE}" = "msys" ]]; then
|
||||
echo "Lightweight shell and GNU utilities compiled for Windows (part of MinGW)"
|
||||
elif [[ "${OSTYPE}" = "win32" ]]; then
|
||||
echo "I'm not sure this can happen."
|
||||
elif [[ "${OSTYPE}" = "freebsd"* ]]; then
|
||||
echo "..."
|
||||
else
|
||||
echo "Unknown."
|
||||
fi
|
||||
```
|
||||
|
||||
## How do I access a potentially unset (environment) variable?
|
||||
|
||||
The set -o nounset line in `main.sh` causes error termination when an unset environment variables is detected as unbound. There are multiple ways to avoid this.
|
||||
|
||||
Some code to illustrate:
|
||||
|
||||
```bash
|
||||
# method 1
|
||||
echo ${NAME1:-Damian} # echos Damian, $NAME1 is still unset
|
||||
# method 2
|
||||
echo ${NAME2:=Damian} # echos Damian, $NAME2 is set to Damian
|
||||
# method 3
|
||||
NAME3=${NAME3:-Damian}; echo ${NAME3} # echos Damian, $NAME3 is set to Damian
|
||||
```
|
||||
|
||||
This subject is briefly touched on as well in the [Safety and Portability section under point 5](README.md#safety-and-portability). b3bp currently uses [method 1](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L252) when we want to access a variable that could be undeclared, and [method 3](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L31) when we also want to set a default to an undeclared variable, because we feel it is more readable than method 2. We feel `:=` is easily overlooked, and not very beginner friendly. Method 3 seems more explicit in that regard in our humble opinion.
|
||||
|
||||
## How can I detect or trap Ctrl-C and other signals?
|
||||
|
||||
You can trap [Unix signals](https://en.wikipedia.org/wiki/Unix_signal) like [Ctrl-C](https://en.wikipedia.org/wiki/Control-C) with code similar to:
|
||||
|
||||
```bash
|
||||
# trap ctrl-c and call ctrl_c()
|
||||
trap ctrl_c INT
|
||||
|
||||
function ctrl_c() {
|
||||
echo "** Trapped CTRL-C"
|
||||
}
|
||||
```
|
||||
|
||||
See http://mywiki.wooledge.org/SignalTrap for a list of signals, examples, and an in depth discussion.
|
||||
|
||||
## How can I get the PID of my running script?
|
||||
|
||||
The PID of a running script is contained in the `${$}` variable. This is _not_ the pid of any subshells. With Bash 4 you can get the PID of your subshell with `${BASHPID}`. For a comprehensive list of Bash built in variables see, e.g., http://www.tldp.org/LDP/abs/html/internalvariables.html
|
4
LICENSE
4
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Kevin van Zonneveld
|
||||
Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
|
72
Makefile
72
Makefile
@ -1,19 +1,59 @@
|
||||
SHELL := /usr/bin/env bash
|
||||
# Licensed under MIT.
|
||||
# Copyright (2016) by Kevin van Zonneveld https://twitter.com/kvz
|
||||
#
|
||||
# https://www.npmjs.com/package/fakefile
|
||||
#
|
||||
# Please do not edit this file directly, but propose changed upstream instead:
|
||||
# https://github.com/kvz/fakefile/blob/main/Makefile
|
||||
#
|
||||
# This Makefile offers convience shortcuts into any Node.js project that utilizes npm scripts.
|
||||
# It functions as a wrapper around the actual listed in `package.json`
|
||||
# So instead of typing:
|
||||
#
|
||||
# $ npm script build:assets
|
||||
#
|
||||
# you could also type:
|
||||
#
|
||||
# $ make build-assets
|
||||
#
|
||||
# Notice that colons (:) are replaced by dashes for Makefile compatibility.
|
||||
#
|
||||
# The benefits of this wrapper are:
|
||||
#
|
||||
# - You get to keep the the scripts package.json, which is more portable
|
||||
# (Makefiles & Windows are harder to mix)
|
||||
# - Offer a polite way into the project for developers coming from different
|
||||
# languages (npm scripts is obviously very Node centric)
|
||||
# - Profit from better autocomplete (make <TAB><TAB>) than npm currently offers.
|
||||
# OSX users will have to install bash-completion
|
||||
# (http://davidalger.com/development/bash-completion-on-os-x-with-brew/)
|
||||
|
||||
.PHONY: release-major
|
||||
release-major:
|
||||
npm version major -m "Release %s"
|
||||
git push
|
||||
npm publish
|
||||
ifeq ($(shell test -e ./yarn.lock && echo -n yes),yes)
|
||||
RUNNER=yarn
|
||||
INSTALLER=yarn install
|
||||
else
|
||||
RUNNER=npm run
|
||||
INSTALLER=npm install
|
||||
endif
|
||||
|
||||
.PHONY: release-minor
|
||||
release-minor:
|
||||
npm version minor -m "Release %s"
|
||||
git push
|
||||
npm publish
|
||||
define npm_script_targets
|
||||
TARGETS := $(shell \
|
||||
node -e 'for (var k in require("./package.json").scripts) {console.log(k.replace(/:/g, "-"));}'
|
||||
| grep -v -E "^install$$"
|
||||
)
|
||||
$$(TARGETS):
|
||||
$(RUNNER) $(shell \
|
||||
node -e 'for (var k in require("./package.json").scripts) {console.log(k.replace(/:/g, "-"), k);}'
|
||||
| grep -E "^$(MAKECMDGOALS)\s"
|
||||
| head -n1
|
||||
| awk '{print $$2}'
|
||||
)
|
||||
|
||||
.PHONY: release-patch
|
||||
release-patch:
|
||||
npm version patch -m "Release %s"
|
||||
git push
|
||||
npm publish
|
||||
.PHONY: $$(TARGETS)
|
||||
endef
|
||||
|
||||
$(eval $(call npm_script_targets))
|
||||
|
||||
# These npm run scripts are available, without needing to be mentioned in `package.json`
|
||||
install:
|
||||
$(INSTALLER)
|
||||
|
175
README.md
175
README.md
@ -1,72 +1,109 @@
|
||||
# bash3boilerplate
|
||||
[This document is formatted with GitHub-Flavored Markdown. ]: #
|
||||
[For better viewing, including hyperlinks, read it online at ]: #
|
||||
[https://github.com/kvz/bash3boilerplate/blob/HEAD/README.md]: #
|
||||
|
||||
<!-- badges/ -->
|
||||
[](http://travis-ci.org/kvz/bash3boilerplate "Check this project's build status on TravisCI")
|
||||
[](https://www.gittip.com/kvz/ "Sponsor the development of bash3boilerplate via Gittip")
|
||||
[](https://flattr.com/submit/auto?user_id=kvz&url=https://github.com/kvz/bash3boilerplate&title=bash3boilerplate&language=&tags=github&category=software "Sponsor the development of bash3boilerplate via Flattr")
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=kevin%40vanzonneveld%2enet&lc=NL&item_name=Open%20source%20donation%20to%20Kevin%20van%20Zonneveld¤cy_code=USD&bn=PP-DonationsBF%3abtn_donate_SM%2egif%3aNonHosted "Sponsor the development of bash3boilerplate via Paypal")
|
||||
[](https://coinbase.com/checkouts/19BtCjLCboRgTAXiaEvnvkdoRyjd843Dg2 "Sponsor the development of bash3boilerplate via BitCoin")
|
||||
<!-- /badges -->
|
||||
- [Overview](#overview)
|
||||
- [Goals](#goals)
|
||||
- [Features](#features)
|
||||
- [Installation](#installation)
|
||||
- [Changelog](#changelog)
|
||||
- [Frequently Asked Questions](#frequently-asked-questions)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Who uses b3bp](#who-uses-b3bp)
|
||||
- [Authors](#authors)
|
||||
- [License](#license)
|
||||
|
||||
When hacking up BASH scripts, I often find there are some
|
||||
higherlevel things like logging, configuration, commandline argument
|
||||
parsing that:
|
||||
## Overview
|
||||
|
||||
- I need everytime
|
||||
- Take quite some effort to get right
|
||||
- Keep you from your actual work
|
||||
<!--more-->
|
||||
|
||||
When hacking up Bash scripts, there are often things such as logging or command-line argument parsing that:
|
||||
|
||||
- You need every time
|
||||
- Come with a number of pitfalls you want to avoid
|
||||
- Keep you from your actual work
|
||||
|
||||
Here's an attempt to bundle those things in a generalized way so that
|
||||
they are reusable as-is in most of my (and hopefully your, if not ping
|
||||
me) programs.
|
||||
they are reusable as-is in most scripts.
|
||||
|
||||
An up to date [intro is found on my blog](http://kvz.io/blog/2013/02/26/introducing-bash3boilerplate/).
|
||||
We call it "BASH3 Boilerplate" or b3bp for short.
|
||||
|
||||
## Goals
|
||||
|
||||
Delete-Key-**Friendly**. Instead of introducing packages, includes, compilers, etc., we propose using [`main.sh`](https://bash3boilerplate.sh/main.sh) as a base and removing the parts you don't need.
|
||||
While this may feel a bit archaic at first, it is exactly the strength of Bash scripts that we should want to embrace.
|
||||
|
||||
**Portable**. We are targeting Bash 3 (OSX still ships
|
||||
with 3, for instance). If you are going to ask people to install
|
||||
Bash 4 first, you might as well pick a more advanced language as a
|
||||
dependency.
|
||||
|
||||
## Features
|
||||
|
||||
- Conventions that will make sure that all your scripts follow the same, battle-tested structure
|
||||
- Safe by default (break on error, pipefail, etc.)
|
||||
- Configuration by environment variables
|
||||
- Simple command-line argument parsing that requires no external dependencies. Definitions are parsed from help info, ensuring there will be no duplication
|
||||
- Helpful magic variables like `__file` and `__dir`
|
||||
- Logging that supports colors and is compatible with [Syslog Severity levels](https://en.wikipedia.org/wiki/Syslog#Severity_levels), as well as the [twelve-factor](https://12factor.net/) guidelines
|
||||
|
||||
## Installation
|
||||
|
||||
There are 3 ways you can install (parts of) b3bp:
|
||||
There are three different ways to install b3bp:
|
||||
|
||||
1. Just get the main template: `wget https://raw.githubusercontent.com/kvz/bash3boilerplate/master/main.sh`
|
||||
2. Clone the entire project: `git clone git@github.com:kvz/bash3boilerplate.git`
|
||||
3. As of `v1.0.3`, b3bp can be installed as a `package.json` dependency via: `npm install --save bash3boilerplate`
|
||||
### Option 1: Download the main template
|
||||
|
||||
Although `3` introduces a node.js dependency, this does allow for easy version pinning & distrubtions in environments that already have this prerequisite. But nothing prevents you from just using `curl` and keep your project or build system low on external dependencies.
|
||||
Use curl or wget to download the source and save it as your script. Then you can start deleting the unwanted bits, and adding your own logic.
|
||||
|
||||
## Versioning
|
||||
```bash
|
||||
wget https://bash3boilerplate.sh/main.sh
|
||||
vim main.sh
|
||||
```
|
||||
|
||||
This project implements the Semantic Versioning guidelines.
|
||||
### Option 2: Clone the entire project
|
||||
|
||||
Releases will be numbered with the following format:
|
||||
Besides `main.sh`, this will also get you the entire b3bp repository. This includes a few extra functions that we keep in the `./src` directory.
|
||||
|
||||
`<major>.<minor>.<patch>`
|
||||
```bash
|
||||
git clone git@github.com:kvz/bash3boilerplate.git
|
||||
```
|
||||
|
||||
And constructed with the following guidelines:
|
||||
### Option 3: Require via npm
|
||||
|
||||
* Breaking backward compatibility bumps the major (and resets the minor and patch)
|
||||
* New additions without breaking backward compatibility bumps the minor (and resets the patch)
|
||||
* Bug fixes and misc changes bumps the patch
|
||||
As of `v1.0.3`, b3bp can also be installed as a Node module, meaning you can define it as a dependency in `package.json` via:
|
||||
|
||||
```bash
|
||||
npm init
|
||||
npm install --save --save-exact bash3boilerplate
|
||||
```
|
||||
|
||||
For more information on SemVer, please visit [http://semver.org](http://semver.org).
|
||||
Even though this option introduces a Node.js dependency, it does allow for easy version pinning and distribution in environments that already have this prerequisite. This is, however, entirely optional and nothing prevents you from ignoring this possibility.
|
||||
|
||||
## Changelog
|
||||
|
||||
Please see the [CHANGELOG.md](./CHANGELOG.md) file.
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
Please see the [FAQ.md](./FAQ.md) file.
|
||||
|
||||
## Best practices
|
||||
|
||||
As of `v1.0.3`, b3bp adds some nice re-usable libraries in `./src`. Later on we'll be using snippets inside this directory to build custom packages. In order to make the snippets in `./src` more useful, we recommend these guidelines.
|
||||
As of `v1.0.3`, b3bp offers some nice re-usable libraries in `./src`. In order to make the snippets in `./src` more useful, we recommend the following guidelines.
|
||||
|
||||
### Library exports
|
||||
### Function packaging
|
||||
|
||||
It's nice to have a bash package that can be used in the terminal and also be invoked as a command line function. To achieve this the exporting of your functionality *should* follow this pattern:
|
||||
It is nice to have a Bash package that can not only be used in the terminal, but also invoked as a command line function. In order to achieve this, the exporting of your functionality _should_ follow this pattern:
|
||||
|
||||
```bash
|
||||
if [ "${BASH_SOURCE[0]}" != ${0} ]; then
|
||||
export -f my_script
|
||||
else
|
||||
if [[ "${BASH_SOURCE[0]}" = "${0}" ]]; then
|
||||
my_script "${@}"
|
||||
exit $?
|
||||
fi
|
||||
export -f my_script
|
||||
```
|
||||
|
||||
This allows a user to `source` your script or invoke as a script.
|
||||
This allows a user to `source` your script or invoke it as a script.
|
||||
|
||||
```bash
|
||||
# Running as a script
|
||||
@ -76,15 +113,63 @@ $ source my_script.sh
|
||||
$ my_script some more args --blah
|
||||
```
|
||||
|
||||
(taken from the [bpkg](https://raw.githubusercontent.com/bpkg/bpkg/master/README.md) project)
|
||||
(taken from the [bpkg](https://raw.githubusercontent.com/bpkg/bpkg/HEAD/README.md) project)
|
||||
|
||||
## Todo
|
||||
### Scoping
|
||||
|
||||
- [ ] Make `src` libs adhere to Best practices
|
||||
- [ ] `make build` system for generating custom builds
|
||||
- [ ] tests & releases via Travis
|
||||
1. In functions, use `local` before every variable declaration.
|
||||
1. Use `UPPERCASE_VARS` to indicate environment variables that can be controlled outside your script.
|
||||
1. Use `__double_underscore_prefixed_vars` to indicate global variables that are solely controlled inside your script, with the exception of arguments that are already prefixed with `arg_`, as well as functions, over which b3bp poses no restrictions.
|
||||
|
||||
### Coding style
|
||||
|
||||
1. Use two spaces for tabs, do not use tab characters.
|
||||
1. Do not introduce whitespace at the end of lines or on blank lines as they obfuscate version control diffs.
|
||||
1. Use long options (`logger --priority` vs `logger -p`). If you are on the CLI, abbreviations make sense for efficiency. Nevertheless, when you are writing reusable scripts, a few extra keystrokes will pay off in readability and avoid ventures into man pages in the future, either by you or your collaborators. Similarly, we prefer `set -o nounset` over `set -u`.
|
||||
1. Use a single equal sign when checking `if [[ "${NAME}" = "Kevin" ]]`; double or triple signs are not needed.
|
||||
1. Use the new bash builtin test operator (`[[ ... ]]`) rather than the old single square bracket test operator or explicit call to `test`.
|
||||
|
||||
### Safety and Portability
|
||||
|
||||
1. Use `{}` to enclose your variables. Otherwise, Bash will try to access the `$ENVIRONMENT_app` variable in `/srv/$ENVIRONMENT_app`, whereas you probably intended `/srv/${ENVIRONMENT}_app`. Since it is easy to miss cases like this, we recommend that you make enclosing a habit.
|
||||
1. Use `set`, rather than relying on a shebang like `#!/usr/bin/env bash -e`, since that is neutralized when someone runs your script as `bash yourscript.sh`.
|
||||
1. Use `#!/usr/bin/env bash`, as it is more portable than `#!/bin/bash`.
|
||||
1. Use `${BASH_SOURCE[0]}` if you refer to current file, even if it is sourced by a parent script. In other cases, use `${0}`.
|
||||
1. Use `:-` if you want to test variables that could be undeclared. For instance, with `if [[ "${NAME:-}" = "Kevin" ]]`, `$NAME` will evaluate to `Kevin` if the variable is empty. The variable itself will remain unchanged. The syntax to assign a default value is `${NAME:=Kevin}`.
|
||||
|
||||
## Who uses b3bp?
|
||||
|
||||
- [Transloadit](https://transloadit.com)
|
||||
- [OpenCoarrays](https://www.opencoarrays.org)
|
||||
- [Sourcery Institute](https://www.sourceryinstitute.org)
|
||||
- [Computational Brain Anatomy Laboratory](https://cobralab.ca/)
|
||||
- [Genesis Cloud](https://genesiscloud.com/)
|
||||
|
||||
We are looking for endorsements! Are you also using b3bp? [Let us know](https://github.com/kvz/bash3boilerplate/issues/new?title=I%20use%20b3bp) and get listed.
|
||||
|
||||
## Authors
|
||||
|
||||
- [Kevin van Zonneveld](https://kvz.io)
|
||||
- [Izaak Beekman](https://izaakbeekman.com/)
|
||||
- [Manuel Streuhofer](https://github.com/mstreuhofer)
|
||||
- [Alexander Rathai](mailto:Alexander.Rathai@gmail.com)
|
||||
- [Dr. Damian Rouson](https://www.sourceryinstitute.org/) (documentation, feedback)
|
||||
- [@jokajak](https://github.com/jokajak) (documentation)
|
||||
- [Gabriel A. Devenyi](https://staticwave.ca/) (feedback)
|
||||
- [@bravo-kernel](https://github.com/bravo-kernel) (feedback)
|
||||
- [@skanga](https://github.com/skanga) (feedback)
|
||||
- [galaktos](https://www.reddit.com/user/galaktos) (feedback)
|
||||
- [@moviuro](https://github.com/moviuro) (feedback)
|
||||
- [Giovanni Saponaro](https://github.com/gsaponaro) (feedback)
|
||||
- [Germain Masse](https://github.com/gmasse)
|
||||
- [A. G. Madi](https://github.com/warpengineer)
|
||||
- [Lukas Stockner](mailto:oss@genesiscloud.com)
|
||||
- [Gert Goet](https://github.com/eval)
|
||||
- [@rfuehrer](https://github.com/rfuehrer)
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2013 Kevin van Zonneveld, [http://kvz.io](http://kvz.io)
|
||||
Licensed under MIT: [http://kvz.io/licenses/LICENSE-MIT](http://kvz.io/licenses/LICENSE-MIT)
|
||||
Copyright (c) 2013 Kevin van Zonneveld and [contributors](https://github.com/kvz/bash3boilerplate#authors).
|
||||
Licensed under [MIT](https://raw.githubusercontent.com/kvz/bash3boilerplate/HEAD/LICENSE).
|
||||
You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
as you leave these references intact in the header comments of your source files.
|
||||
|
1
docs/CNAME
Normal file
1
docs/CNAME
Normal file
@ -0,0 +1 @@
|
||||
bash3boilerplate.sh
|
15
docs/index.html
Normal file
15
docs/index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
http-equiv="refresh"
|
||||
content="0;url=https://github.com/kvz/bash3boilerplate"
|
||||
/>
|
||||
<title>Redirecting...</title>
|
||||
</head>
|
||||
<body>
|
||||
If you are not redirected,
|
||||
<a href="https://github.com/kvz/bash3boilerplate">click here</a>.
|
||||
</body>
|
||||
</html>
|
147
example.sh
Executable file
147
example.sh
Executable file
@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env bash
|
||||
# This file:
|
||||
#
|
||||
# - Demos BASH3 Boilerplate (change this for your script)
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# LOG_LEVEL=7 ./example.sh -f /tmp/x -d (change this for your script)
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate v2.3.0
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
|
||||
### BASH3 Boilerplate (b3bp) Header
|
||||
##############################################################################
|
||||
|
||||
# Commandline options. This defines the usage page, and is used to parse cli
|
||||
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
|
||||
# - A short option must be preset for every long option; but every short option
|
||||
# need not have a long option
|
||||
# - `--` is respected as the separator between options and arguments
|
||||
# - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}.
|
||||
# you can use bash variables to work around this (so use ${HOME} instead)
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
-f --file [arg] Filename to process. Required.
|
||||
-t --temp [arg] Location of tempfile. Default="/tmp/bar"
|
||||
-v Enable verbose mode, print script as it is executed
|
||||
-d --debug Enables debug mode
|
||||
-h --help This page
|
||||
-n --no-color Disable color output
|
||||
-1 --one Do just one thing
|
||||
-i --input [arg] File to process. Can be repeated.
|
||||
-x Specify a flag. Can be repeated.
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
EOF
|
||||
|
||||
# shellcheck source=main.sh
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/main.sh"
|
||||
|
||||
|
||||
### Signal trapping and backtracing
|
||||
##############################################################################
|
||||
|
||||
function __b3bp_cleanup_before_exit () {
|
||||
info "Cleaning up. Done"
|
||||
}
|
||||
trap __b3bp_cleanup_before_exit EXIT
|
||||
|
||||
# requires `set -o errtrace`
|
||||
__b3bp_err_report() {
|
||||
local error_code=${?}
|
||||
# shellcheck disable=SC2154
|
||||
error "Error in ${__file} in function ${1} on line ${2}"
|
||||
exit ${error_code}
|
||||
}
|
||||
# Uncomment the following line for always providing an error backtrace
|
||||
# trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
|
||||
|
||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
|
||||
##############################################################################
|
||||
|
||||
# debug mode
|
||||
if [[ "${arg_d:?}" = "1" ]]; then
|
||||
set -o xtrace
|
||||
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||
LOG_LEVEL="7"
|
||||
# Enable error backtracing
|
||||
trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
fi
|
||||
|
||||
# verbose mode
|
||||
if [[ "${arg_v:?}" = "1" ]]; then
|
||||
set -o verbose
|
||||
fi
|
||||
|
||||
# no color mode
|
||||
if [[ "${arg_n:?}" = "1" ]]; then
|
||||
NO_COLOR="true"
|
||||
fi
|
||||
|
||||
# help mode
|
||||
if [[ "${arg_h:?}" = "1" ]]; then
|
||||
# Help exists with code 1
|
||||
help "Help using ${0}"
|
||||
fi
|
||||
|
||||
|
||||
### Validation. Error out if the things required for your script are not present
|
||||
##############################################################################
|
||||
|
||||
[[ "${arg_f:-}" ]] || help "Setting a filename with -f or --file is required"
|
||||
[[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. "
|
||||
|
||||
|
||||
### Runtime
|
||||
##############################################################################
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
info "__i_am_main_script: ${__i_am_main_script}"
|
||||
# shellcheck disable=SC2154
|
||||
info "__file: ${__file}"
|
||||
# shellcheck disable=SC2154
|
||||
info "__dir: ${__dir}"
|
||||
# shellcheck disable=SC2154
|
||||
info "__base: ${__base}"
|
||||
info "OSTYPE: ${OSTYPE}"
|
||||
|
||||
info "arg_f: ${arg_f}"
|
||||
info "arg_d: ${arg_d}"
|
||||
info "arg_v: ${arg_v}"
|
||||
info "arg_h: ${arg_h}"
|
||||
if [[ -n "${arg_i:-}" ]]; then
|
||||
info "arg_i: ${#arg_i[@]}"
|
||||
for input_file in "${arg_i[@]}"; do
|
||||
info " - ${input_file}"
|
||||
done
|
||||
else
|
||||
info "arg_i: 0"
|
||||
fi
|
||||
# shellcheck disable=SC2015
|
||||
[[ -n "${arg_x:-}" ]] && info "arg_x: ${#arg_x[@]}" || info "arg_x: 0"
|
||||
|
||||
info "$(echo -e "multiple lines example - line #1\\nmultiple lines example - line #2\\nimagine logging the output of 'ls -al /path/'")"
|
||||
|
||||
# All of these go to STDERR, so you can use STDOUT for piping machine readable information to other software
|
||||
debug "Info useful to developers for debugging the application, not useful during operations."
|
||||
info "Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required."
|
||||
notice "Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required."
|
||||
warning "Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time."
|
||||
error "Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time."
|
||||
critical "Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection."
|
||||
alert "Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection."
|
||||
emergency "A \"panic\" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call."
|
496
main.sh
496
main.sh
@ -1,182 +1,452 @@
|
||||
#!/usr/bin/env bash
|
||||
# BASH3 Boilerplate
|
||||
#
|
||||
# This file:
|
||||
# - Is a template to write better bash scripts
|
||||
# - Is delete-key friendly, in case you don't need e.g. command line option parsing
|
||||
#
|
||||
# More info:
|
||||
# - https://github.com/kvz/bash3boilerplate
|
||||
# - http://kvz.io/blog/2013/02/26/introducing-bash3boilerplate/
|
||||
#
|
||||
# Version 1.0.0
|
||||
#
|
||||
# Authors:
|
||||
# - Kevin van Zonneveld (http://kvz.io)
|
||||
# - Demos BASH3 Boilerplate (change this for your script)
|
||||
#
|
||||
# Usage:
|
||||
# LOG_LEVEL=7 ./main.sh -f /tmp/x -d
|
||||
#
|
||||
# Licensed under MIT
|
||||
# Copyright (c) 2013 Kevin van Zonneveld (http://kvz.io)
|
||||
# LOG_LEVEL=7 ./main.sh -f /tmp/x -d (change this for your script)
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate vv2.7.2
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
# Exit on error. Append "|| true" if you expect an error.
|
||||
set -o errexit
|
||||
# Exit on error inside any functions or subshells.
|
||||
set -o errtrace
|
||||
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
|
||||
set -o nounset
|
||||
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
|
||||
set -o pipefail
|
||||
# Turn on traces, useful while debugging but commented out by default
|
||||
# set -o xtrace
|
||||
|
||||
### Configuration
|
||||
#####################################################################
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
__i_am_main_script="0" # false
|
||||
|
||||
# Environment variables and their defaults
|
||||
if [[ "${__usage+x}" ]]; then
|
||||
if [[ "${BASH_SOURCE[1]}" = "${0}" ]]; then
|
||||
__i_am_main_script="1" # true
|
||||
fi
|
||||
|
||||
__b3bp_external_usage="true"
|
||||
__b3bp_tmp_source_idx=1
|
||||
fi
|
||||
else
|
||||
__i_am_main_script="1" # true
|
||||
[[ "${__usage+x}" ]] && unset -v __usage
|
||||
[[ "${__helptext+x}" ]] && unset -v __helptext
|
||||
fi
|
||||
|
||||
# Set magic variables for current file, directory, os, etc.
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")"
|
||||
__base="$(basename "${__file}" .sh)"
|
||||
# shellcheck disable=SC2034,SC2015
|
||||
__invocation="$(printf %q "${__file}")$( (($#)) && printf ' %q' "$@" || true)"
|
||||
|
||||
# Define the environment variables (and their defaults) that this script depends on
|
||||
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
|
||||
|
||||
# Commandline options. This defines the usage page, and is used to parse cli
|
||||
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
|
||||
read -r -d '' usage <<-'EOF'
|
||||
-f [arg] Filename to process. Required.
|
||||
-t [arg] Location of tempfile. Default="/tmp/bar"
|
||||
-d Enables debug mode
|
||||
-h This page
|
||||
EOF
|
||||
|
||||
# Set magic variables for current FILE & DIR
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected
|
||||
|
||||
|
||||
### Functions
|
||||
#####################################################################
|
||||
##############################################################################
|
||||
|
||||
function _fmt () {
|
||||
local color_ok="\x1b[32m"
|
||||
local color_bad="\x1b[31m"
|
||||
function __b3bp_log () {
|
||||
local log_level="${1}"
|
||||
shift
|
||||
|
||||
local color="${color_bad}"
|
||||
if [ "${1}" = "debug" ] || [ "${1}" = "info" ] || [ "${1}" = "notice" ]; then
|
||||
color="${color_ok}"
|
||||
# shellcheck disable=SC2034
|
||||
local color_debug="\\x1b[35m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_info="\\x1b[32m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_notice="\\x1b[34m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_warning="\\x1b[33m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_error="\\x1b[31m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_critical="\\x1b[1;31m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_alert="\\x1b[1;37;41m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_emergency="\\x1b[1;4;5;37;41m"
|
||||
|
||||
local colorvar="color_${log_level}"
|
||||
|
||||
local color="${!colorvar:-${color_error}}"
|
||||
local color_reset="\\x1b[0m"
|
||||
|
||||
if [[ "${NO_COLOR:-}" = "true" ]] || { [[ "${TERM:-}" != "xterm"* ]] && [[ "${TERM:-}" != "screen"* ]]; } || [[ ! -t 2 ]]; then
|
||||
if [[ "${NO_COLOR:-}" != "false" ]]; then
|
||||
# Don't use colors on pipes or non-recognized terminals
|
||||
color=""; color_reset=""
|
||||
fi
|
||||
fi
|
||||
|
||||
local color_reset="\x1b[0m"
|
||||
if [[ "${TERM}" != "xterm"* ]] || [ -t 1 ]; then
|
||||
# Don't use colors on pipes or non-recognized terminals
|
||||
color=""; color_reset=""
|
||||
fi
|
||||
echo -e "$(date -u +"%Y-%m-%d %H:%M:%S UTC") ${color}$(printf "[%9s]" ${1})${color_reset}";
|
||||
# all remaining arguments are to be printed
|
||||
local log_line=""
|
||||
|
||||
while IFS=$'\n' read -r log_line; do
|
||||
echo -e "$(date -u +"%Y-%m-%d %H:%M:%S UTC") ${color}$(printf "[%9s]" "${log_level}")${color_reset} ${log_line}" 1>&2
|
||||
done <<< "${@:-}"
|
||||
}
|
||||
function emergency () { echo "$(_fmt emergency) ${@}" 1>&2 || true; exit 1; }
|
||||
function alert () { [ "${LOG_LEVEL}" -ge 1 ] && echo "$(_fmt alert) ${@}" 1>&2 || true; }
|
||||
function critical () { [ "${LOG_LEVEL}" -ge 2 ] && echo "$(_fmt critical) ${@}" 1>&2 || true; }
|
||||
function error () { [ "${LOG_LEVEL}" -ge 3 ] && echo "$(_fmt error) ${@}" 1>&2 || true; }
|
||||
function warning () { [ "${LOG_LEVEL}" -ge 4 ] && echo "$(_fmt warning) ${@}" 1>&2 || true; }
|
||||
function notice () { [ "${LOG_LEVEL}" -ge 5 ] && echo "$(_fmt notice) ${@}" 1>&2 || true; }
|
||||
function info () { [ "${LOG_LEVEL}" -ge 6 ] && echo "$(_fmt info) ${@}" 1>&2 || true; }
|
||||
function debug () { [ "${LOG_LEVEL}" -ge 7 ] && echo "$(_fmt debug) ${@}" 1>&2 || true; }
|
||||
|
||||
function emergency () { __b3bp_log emergency "${@}"; exit 1; }
|
||||
function alert () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && __b3bp_log alert "${@}"; true; }
|
||||
function critical () { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && __b3bp_log critical "${@}"; true; }
|
||||
function error () { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && __b3bp_log error "${@}"; true; }
|
||||
function warning () { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && __b3bp_log warning "${@}"; true; }
|
||||
function notice () { [[ "${LOG_LEVEL:-0}" -ge 5 ]] && __b3bp_log notice "${@}"; true; }
|
||||
function info () { [[ "${LOG_LEVEL:-0}" -ge 6 ]] && __b3bp_log info "${@}"; true; }
|
||||
function debug () { [[ "${LOG_LEVEL:-0}" -ge 7 ]] && __b3bp_log debug "${@}"; true; }
|
||||
|
||||
function help () {
|
||||
echo "" 1>&2
|
||||
echo " ${@}" 1>&2
|
||||
echo " ${*}" 1>&2
|
||||
echo "" 1>&2
|
||||
echo " ${usage}" 1>&2
|
||||
echo " ${__usage:-No usage available}" 1>&2
|
||||
echo "" 1>&2
|
||||
|
||||
if [[ "${__helptext:-}" ]]; then
|
||||
echo " ${__helptext}" 1>&2
|
||||
echo "" 1>&2
|
||||
fi
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
function cleanup_before_exit () {
|
||||
info "Cleaning up. Done"
|
||||
}
|
||||
trap cleanup_before_exit EXIT
|
||||
|
||||
|
||||
### Parse commandline options
|
||||
#####################################################################
|
||||
##############################################################################
|
||||
|
||||
# Commandline options. This defines the usage page, and is used to parse cli
|
||||
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
|
||||
# - A short option must be preset for every long option; but every short option
|
||||
# need not have a long option
|
||||
# - `--` is respected as the separator between options and arguments
|
||||
# - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}.
|
||||
# you can use bash variables to work around this (so use ${HOME} instead)
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
[[ "${__usage+x}" ]] || read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
-f --file [arg] Filename to process. Required.
|
||||
-t --temp [arg] Location of tempfile. Default="/tmp/bar"
|
||||
-v Enable verbose mode, print script as it is executed
|
||||
-d --debug Enables debug mode
|
||||
-h --help This page
|
||||
-n --no-color Disable color output
|
||||
-1 --one Do just one thing
|
||||
-i --input [arg] File to process. Can be repeated.
|
||||
-x Specify a flag. Can be repeated.
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
[[ "${__helptext+x}" ]] || read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
EOF
|
||||
|
||||
# Translate usage string -> getopts arguments, and set $arg_<flag> defaults
|
||||
while read line; do
|
||||
opt="$(echo "${line}" |awk '{print $1}' |sed -e 's#^-##')"
|
||||
if ! echo "${line}" |egrep '\[.*\]' >/dev/null 2>&1; then
|
||||
init="0" # it's a flag. init with 0
|
||||
else
|
||||
opt="${opt}:" # add : if opt has arg
|
||||
init="" # it has an arg. init with ""
|
||||
fi
|
||||
opts="${opts}${opt}"
|
||||
while read -r __b3bp_tmp_line; do
|
||||
if [[ "${__b3bp_tmp_line}" =~ ^- ]]; then
|
||||
# fetch single character version of option string
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_line%% *}"
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt:1}"
|
||||
|
||||
varname="arg_${opt:0:1}"
|
||||
if ! echo "${line}" |egrep '\. Default=' >/dev/null 2>&1; then
|
||||
eval "${varname}=\"${init}\""
|
||||
else
|
||||
match="$(echo "${line}" |sed 's#^.*Default=\(\)#\1#g')"
|
||||
eval "${varname}=\"${match}\""
|
||||
fi
|
||||
done <<< "${usage}"
|
||||
# fetch long version if present
|
||||
__b3bp_tmp_long_opt=""
|
||||
|
||||
# Reset in case getopts has been used previously in the shell.
|
||||
OPTIND=1
|
||||
if [[ "${__b3bp_tmp_line}" = *"--"* ]]; then
|
||||
__b3bp_tmp_long_opt="${__b3bp_tmp_line#*--}"
|
||||
__b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
|
||||
fi
|
||||
|
||||
# Overwrite $arg_<flag> defaults with the actual CLI options
|
||||
while getopts "${opts}" opt; do
|
||||
line="$(echo "${usage}" |grep "\-${opt}")"
|
||||
# map opt long name to+from opt short name
|
||||
printf -v "__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}"
|
||||
printf -v "__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt}" '%s' "${__b3bp_tmp_long_opt//-/_}"
|
||||
|
||||
# check if option takes an argument
|
||||
if [[ "${__b3bp_tmp_line}" =~ \[.*\] ]]; then
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
||||
__b3bp_tmp_init="" # it has an arg. init with ""
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1"
|
||||
elif [[ "${__b3bp_tmp_line}" =~ \{.*\} ]]; then
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
||||
__b3bp_tmp_init="" # it has an arg. init with ""
|
||||
# remember that this option requires an argument
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||
else
|
||||
__b3bp_tmp_init="0" # it's a flag. init with 0
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0"
|
||||
fi
|
||||
__b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}"
|
||||
|
||||
[ "${opt}" = "?" ] && help "Invalid use of script: ${@} "
|
||||
varname="arg_${opt:0:1}"
|
||||
default="${!varname}"
|
||||
|
||||
value="${OPTARG}"
|
||||
if [ -z "${OPTARG}" ] && [ "${default}" = "0" ]; then
|
||||
value="1"
|
||||
if [[ "${__b3bp_tmp_line}" =~ ^Can\ be\ repeated\. ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Can\ be\ repeated\. ]]; then
|
||||
# remember that this option can be repeated
|
||||
printf -v "__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}" '%s' "1"
|
||||
else
|
||||
printf -v "__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}" '%s' "0"
|
||||
fi
|
||||
fi
|
||||
|
||||
eval "${varname}=\"${value}\""
|
||||
debug "cli arg ${varname} = ($default) -> ${!varname}"
|
||||
[[ "${__b3bp_tmp_opt:-}" ]] || continue
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" =~ ^Default= ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Default= ]]; then
|
||||
# ignore default value if option does not have an argument
|
||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}"
|
||||
if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then
|
||||
# take default
|
||||
__b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
|
||||
# strip double quotes from default argument
|
||||
__b3bp_tmp_re='^"(.*)"$'
|
||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
else
|
||||
# strip single quotes from default argument
|
||||
__b3bp_tmp_re="^'(.*)'$"
|
||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" =~ ^Required\. ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Required\. ]]; then
|
||||
# remember that this option requires an argument
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||
fi
|
||||
|
||||
# Init var with value unless it is an array / a repeatable
|
||||
__b3bp_tmp_varname="__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}"
|
||||
[[ "${!__b3bp_tmp_varname}" = "0" ]] && printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}"
|
||||
done <<< "${__usage:-}"
|
||||
|
||||
# run getopts only if options were specified in __usage
|
||||
if [[ "${__b3bp_tmp_opts:-}" ]]; then
|
||||
# Allow long options like --this
|
||||
__b3bp_tmp_opts="${__b3bp_tmp_opts}-:"
|
||||
|
||||
# Reset in case getopts has been used previously in the shell.
|
||||
OPTIND=1
|
||||
|
||||
# start parsing command line
|
||||
set +o nounset # unexpected arguments will cause unbound variables
|
||||
# to be dereferenced
|
||||
# Overwrite $arg_<flag> defaults with the actual CLI options
|
||||
while getopts "${__b3bp_tmp_opts}" __b3bp_tmp_opt; do
|
||||
[[ "${__b3bp_tmp_opt}" = "?" ]] && help "Invalid use of script: ${*} "
|
||||
|
||||
if [[ "${__b3bp_tmp_opt}" = "-" ]]; then
|
||||
# OPTARG is long-option-name or long-option=value
|
||||
if [[ "${OPTARG}" =~ .*=.* ]]; then
|
||||
# --key=value format
|
||||
__b3bp_tmp_long_opt=${OPTARG/=*/}
|
||||
# Set opt to the short option corresponding to the long option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
OPTARG=${OPTARG#*=}
|
||||
else
|
||||
# --key value format
|
||||
# Map long name to short version of option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
# Only assign OPTARG if option takes an argument
|
||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
|
||||
__b3bp_tmp_varvalue="${!__b3bp_tmp_varname}"
|
||||
[[ "${__b3bp_tmp_varvalue}" != "0" ]] && __b3bp_tmp_varvalue="1"
|
||||
printf -v "OPTARG" '%s' "${@:OPTIND:${__b3bp_tmp_varvalue}}"
|
||||
# shift over the argument if argument is expected
|
||||
((OPTIND+=__b3bp_tmp_varvalue))
|
||||
fi
|
||||
# we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
|
||||
fi
|
||||
|
||||
__b3bp_tmp_value="${OPTARG}"
|
||||
|
||||
__b3bp_tmp_varname="__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}"
|
||||
if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then
|
||||
# repeatables
|
||||
# shellcheck disable=SC2016
|
||||
if [[ -z "${OPTARG}" ]]; then
|
||||
# repeatable flags, they increcemnt
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
|
||||
debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
|
||||
# shellcheck disable=SC2004
|
||||
__b3bp_tmp_value=$((${!__b3bp_tmp_varname} + 1))
|
||||
printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
|
||||
else
|
||||
# repeatable args, they get appended to an array
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}[@]"
|
||||
debug "cli arg ${__b3bp_tmp_varname} append ${__b3bp_tmp_value}"
|
||||
declare -a "${__b3bp_tmp_varname}"='("${!__b3bp_tmp_varname}" "${__b3bp_tmp_value}")'
|
||||
fi
|
||||
else
|
||||
# non-repeatables
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
|
||||
__b3bp_tmp_default="${!__b3bp_tmp_varname}"
|
||||
|
||||
if [[ -z "${OPTARG}" ]]; then
|
||||
__b3bp_tmp_value=$((__b3bp_tmp_default + 1))
|
||||
fi
|
||||
|
||||
printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
|
||||
|
||||
debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
|
||||
fi
|
||||
done
|
||||
set -o nounset # no more unbound variable references expected
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [[ "${1:-}" = "--" ]] ; then
|
||||
shift
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
### Automatic validation of required option arguments
|
||||
##############################################################################
|
||||
|
||||
for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do
|
||||
# validate only options which required an argument
|
||||
[[ "${!__b3bp_tmp_varname}" = "2" ]] || continue
|
||||
|
||||
__b3bp_tmp_opt_short="${__b3bp_tmp_varname##*_}"
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt_short}"
|
||||
[[ "${!__b3bp_tmp_varname}" ]] && continue
|
||||
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt_short}"
|
||||
printf -v "__b3bp_tmp_opt_long" '%s' "${!__b3bp_tmp_varname}"
|
||||
[[ "${__b3bp_tmp_opt_long:-}" ]] && __b3bp_tmp_opt_long=" (--${__b3bp_tmp_opt_long//_/-})"
|
||||
|
||||
help "Option -${__b3bp_tmp_opt_short}${__b3bp_tmp_opt_long:-} requires an argument"
|
||||
done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
[ "$1" = "--" ] && shift
|
||||
### Cleanup Environment variables
|
||||
##############################################################################
|
||||
|
||||
for __tmp_varname in ${!__b3bp_tmp_*}; do
|
||||
unset -v "${__tmp_varname}"
|
||||
done
|
||||
|
||||
unset -v __tmp_varname
|
||||
|
||||
|
||||
### Switches (like -d for debugmode, -h for showing helppage)
|
||||
#####################################################################
|
||||
### Externally supplied __usage. Nothing else to do here
|
||||
##############################################################################
|
||||
|
||||
if [[ "${__b3bp_external_usage:-}" = "true" ]]; then
|
||||
unset -v __b3bp_external_usage
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
### Signal trapping and backtracing
|
||||
##############################################################################
|
||||
|
||||
function __b3bp_cleanup_before_exit () {
|
||||
info "Cleaning up. Done"
|
||||
}
|
||||
trap __b3bp_cleanup_before_exit EXIT
|
||||
|
||||
# requires `set -o errtrace`
|
||||
__b3bp_err_report() {
|
||||
local error_code=${?}
|
||||
error "Error in ${__file} in function ${1} on line ${2}"
|
||||
exit ${error_code}
|
||||
}
|
||||
# Uncomment the following line for always providing an error backtrace
|
||||
# trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
|
||||
|
||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
|
||||
##############################################################################
|
||||
|
||||
# debug mode
|
||||
if [ "${arg_d}" = "1" ]; then
|
||||
if [[ "${arg_d:?}" = "1" ]]; then
|
||||
set -o xtrace
|
||||
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||
LOG_LEVEL="7"
|
||||
# Enable error backtracing
|
||||
trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
fi
|
||||
|
||||
# verbose mode
|
||||
if [[ "${arg_v:?}" = "1" ]]; then
|
||||
set -o verbose
|
||||
fi
|
||||
|
||||
# no color mode
|
||||
if [[ "${arg_n:?}" = "1" ]]; then
|
||||
NO_COLOR="true"
|
||||
fi
|
||||
|
||||
# help mode
|
||||
if [ "${arg_h}" = "1" ]; then
|
||||
if [[ "${arg_h:?}" = "1" ]]; then
|
||||
# Help exists with code 1
|
||||
help "Help using ${0}"
|
||||
fi
|
||||
|
||||
|
||||
### Validation (decide what's required for running your script and error out)
|
||||
#####################################################################
|
||||
### Validation. Error out if the things required for your script are not present
|
||||
##############################################################################
|
||||
|
||||
[ -z "${arg_f}" ] && help "Setting a filename with -f is required"
|
||||
[ -z "${LOG_LEVEL}" ] && emergency "Cannot continue without LOG_LEVEL. "
|
||||
[[ "${arg_f:-}" ]] || help "Setting a filename with -f or --file is required"
|
||||
[[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. "
|
||||
|
||||
|
||||
### Runtime
|
||||
#####################################################################
|
||||
##############################################################################
|
||||
|
||||
# Exit on error. Append ||true if you expect an error.
|
||||
# set -e is safer than #!/bin/bash -e because that is neutralised if
|
||||
# someone runs your script like `bash yourscript.sh`
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
info "__i_am_main_script: ${__i_am_main_script}"
|
||||
info "__file: ${__file}"
|
||||
info "__dir: ${__dir}"
|
||||
info "__base: ${__base}"
|
||||
info "OSTYPE: ${OSTYPE}"
|
||||
|
||||
# Bash will remember & return the highest exitcode in a chain of pipes.
|
||||
# This way you can catch the error in case mysqldump fails in `mysqldump |gzip`
|
||||
set -o pipefail
|
||||
info "arg_f: ${arg_f}"
|
||||
info "arg_d: ${arg_d}"
|
||||
info "arg_v: ${arg_v}"
|
||||
info "arg_h: ${arg_h}"
|
||||
|
||||
if [[ "${OSTYPE}" == "darwin"* ]]; then
|
||||
info "You are on OSX"
|
||||
# shellcheck disable=SC2015
|
||||
if [[ -n "${arg_i:-}" ]] && declare -p arg_i 2> /dev/null | grep -q '^declare \-a'; then
|
||||
info "arg_i:"
|
||||
for input_file in "${arg_i[@]}"; do
|
||||
info " - ${input_file}"
|
||||
done
|
||||
elif [[ -n "${arg_i:-}" ]]; then
|
||||
info "arg_i: ${arg_i}"
|
||||
else
|
||||
info "arg_i: 0"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
if [[ -n "${arg_x:-}" ]] && declare -p arg_x 2> /dev/null | grep -q '^declare \-a'; then
|
||||
info "arg_x: ${#arg_x[@]}"
|
||||
elif [[ -n "${arg_x:-}" ]]; then
|
||||
info "arg_x: ${arg_x}"
|
||||
else
|
||||
info "arg_x: 0"
|
||||
fi
|
||||
|
||||
info "$(echo -e "multiple lines example - line #1\\nmultiple lines example - line #2\\nimagine logging the output of 'ls -al /path/'")"
|
||||
|
||||
# All of these go to STDERR, so you can use STDOUT for piping machine readable information to other software
|
||||
debug "Info useful to developers for debugging the application, not useful during operations."
|
||||
info "Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required."
|
||||
notice "Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required."
|
||||
warning "Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. This is a debug message"
|
||||
warning "Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time."
|
||||
error "Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time."
|
||||
critical "Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection."
|
||||
alert "Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection."
|
||||
|
26
package.json
26
package.json
@ -1,5 +1,29 @@
|
||||
{
|
||||
"name": "bash3boilerplate",
|
||||
"description": "Copypastable templates to write better bash scripts",
|
||||
"version": "1.1.0"
|
||||
"version": "2.7.2",
|
||||
"packageManager": "yarn@3.6.0+sha224.19e47520fa56c6146388fdeb438d9dcf6630c3f277a2e1180995c3bb",
|
||||
"engines": {
|
||||
"node": ">= 18",
|
||||
"yarn": "3.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"lint:shellcheck": "shellcheck --severity=${SHELLCHECK_SEVERITY:-info} $(find . -name '*.sh' -maxdepth 2)",
|
||||
"lint:style": "test/style.pl $(find . -name '*.sh' -maxdepth 2)",
|
||||
"lint": "npm-run-all -l 'lint:**'",
|
||||
"release:major": "env SEMANTIC=major yarn release",
|
||||
"release:minor": "env SEMANTIC=minor yarn release",
|
||||
"release:patch": "env SEMANTIC=patch yarn release",
|
||||
"release": "npm version ${SEMANTIC:-patch} -m \"Release %s\" && yarn version:replace && git commit main.sh src/*.sh -m 'Update version' && git push && git push --tags -f && npm publish",
|
||||
"test:debug:main:repeated": "env LOG_LEVEL=7 test/acceptance.sh main-repeated",
|
||||
"test:update": "env SAVE_FIXTURES=true yarn test",
|
||||
"test": "test/acceptance.sh",
|
||||
"version:current": "node -e 'console.log(require(\"./package.json\").version)'",
|
||||
"version:replace": "replace 'v\\d+\\.\\d+\\.\\d+' \"v$(npm run --silent version:current)\" main.sh src/*.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"fakefile": "1.1.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"replace": "1.2.2"
|
||||
}
|
||||
}
|
||||
|
131
src/bump.sh
131
src/bump.sh
@ -1,131 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2014, Transloadit Ltd.
|
||||
#
|
||||
# This file:
|
||||
#
|
||||
# - Bumps a semantic version as specified in first argument
|
||||
# - Or: Bumps a semantic version in a file as specified in first argument
|
||||
# - Returns the version if no levelName is provided in second argument
|
||||
# - Only supports Go files ending in 'var Version = ...'
|
||||
#
|
||||
# Run as:
|
||||
#
|
||||
# ./bump.sh 0.0.1 patch
|
||||
# ./bump.sh ./VERSION patch
|
||||
# ./bump.sh ./VERSION patch
|
||||
# ./bump.sh ./VERSION major 1
|
||||
# ./bump.sh ./version.go patch 2
|
||||
#
|
||||
# Returns:
|
||||
#
|
||||
# v0.0.1
|
||||
#
|
||||
# Requires:
|
||||
#
|
||||
# - gsed on OSX (brew install gnu-sed)
|
||||
#
|
||||
# Authors:
|
||||
#
|
||||
# - Kevin van Zonneveld <kevin@transloadit.com>
|
||||
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
# Set magic variables for current FILE & DIR
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "${__dir}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
|
||||
gsed=""
|
||||
[ -n "$(which sed)" ] && gsed="$(which sed)"
|
||||
[ -n "$(which gsed)" ] && gsed="$(which gsed)"
|
||||
|
||||
|
||||
. ${__dir}/semver.sh
|
||||
|
||||
function readFromFile() {
|
||||
local filepath="${1}"
|
||||
local extension="${filepath##*.}"
|
||||
|
||||
if [ "${extension}" = "go" ]; then
|
||||
curVersion="$(awk -F'"' '/^var Version = / {print $2}' "${filepath}" | tail -n1)" || true
|
||||
else
|
||||
curVersion="$(echo $(cat "${filepath}"))" || true
|
||||
fi
|
||||
|
||||
if [ -z "${curVersion}" ]; then
|
||||
curVersion="v0.0.0"
|
||||
fi
|
||||
|
||||
echo "${curVersion}"
|
||||
}
|
||||
|
||||
function writeToFile() {
|
||||
local filepath="${1}"
|
||||
local newVersion="${2}"
|
||||
local extension="${filepath##*.}"
|
||||
|
||||
if [ "${extension}" = "go" ]; then
|
||||
buf="$(cat "${filepath}" |egrep -v '^var Version = ')" || true
|
||||
echo -e "${buf}\nvar Version = \"${newVersion}\"" > "${filepath}"
|
||||
else
|
||||
echo "${newVersion}" > "${filepath}"
|
||||
fi
|
||||
}
|
||||
|
||||
function bump() {
|
||||
local version="${1}"
|
||||
local levelName="${2}"
|
||||
local bump="${3}"
|
||||
|
||||
local major=0
|
||||
local minor=0
|
||||
local patch=0
|
||||
local special=""
|
||||
|
||||
local newVersion=""
|
||||
|
||||
semverParseInto "${version}" major minor patch special
|
||||
|
||||
if [ "${levelName}" = "major" ]; then
|
||||
let "major = major + ${bump}"
|
||||
minor=0
|
||||
patch=0
|
||||
special=""
|
||||
fi
|
||||
if [ "${levelName}" = "minor" ]; then
|
||||
let "minor = minor + ${bump}"
|
||||
patch=0
|
||||
special=""
|
||||
fi
|
||||
if [ "${levelName}" = "patch" ]; then
|
||||
let "patch = patch + ${bump}"
|
||||
special=""
|
||||
fi
|
||||
if [ "${levelName}" = "special" ]; then
|
||||
special="${bump}"
|
||||
fi
|
||||
|
||||
newVersion="v${major}.${minor}.${patch}"
|
||||
if [ -n "${special}" ]; then
|
||||
newVersion=".${newVersion}"
|
||||
fi
|
||||
echo "${newVersion}"
|
||||
}
|
||||
|
||||
if [ -f "${1}" ]; then
|
||||
filepath="${1}"
|
||||
curVersion="$(readFromFile "${filepath}")"
|
||||
else
|
||||
curVersion="${1}"
|
||||
fi
|
||||
|
||||
newVersion=$(bump "${curVersion}" "${2:-}" "${3:-1}")
|
||||
echo "${newVersion}"
|
||||
|
||||
if [ -n "${filepath:-}" ]; then
|
||||
writeToFile "${filepath}" "${newVersion}"
|
||||
fi
|
123
src/ini_val.sh
123
src/ini_val.sh
@ -1,38 +1,113 @@
|
||||
#!/usr/bin/env bash
|
||||
# BASH3 Boilerplate: ini_val
|
||||
#
|
||||
# This file:
|
||||
#
|
||||
# - Can read and write .ini files using pure bash
|
||||
#
|
||||
# Limitations:
|
||||
#
|
||||
# - All keys inside a section of the .ini file must be unique
|
||||
# - Optional comment parameter for the creation of new entries
|
||||
#
|
||||
# Usage as a function:
|
||||
#
|
||||
# source ini_val.sh
|
||||
# ini_val data.ini connection.host 127.0.0.1 "Host name or IP address"
|
||||
#
|
||||
# Usage as a command:
|
||||
#
|
||||
# ini_val.sh data.ini connection.host 127.0.0.1 "Host name or IP address"
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate vv2.7.2
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
function ini_val() {
|
||||
local file="${1}"
|
||||
local sectionkey="${2}"
|
||||
local val="${3}"
|
||||
local delim=" = "
|
||||
local file="${1:-}"
|
||||
local sectionkey="${2:-}"
|
||||
local val="${3:-}"
|
||||
local comment="${4:-}"
|
||||
local delim="="
|
||||
local comment_delim=";"
|
||||
local section=""
|
||||
local key=""
|
||||
local current=""
|
||||
# add default section
|
||||
local section_default="default"
|
||||
|
||||
# Split on . for section. However, section is optional
|
||||
read section key <<<$(IFS="."; echo ${sectionkey})
|
||||
if [ -z "${key}" ]; then
|
||||
key="${section}"
|
||||
section=""
|
||||
if [[ ! -f "${file}" ]]; then
|
||||
# touch file if not exists
|
||||
touch "${file}"
|
||||
fi
|
||||
|
||||
local current=$(awk -F"${delim}" "/^${key}${delim}/ {for (i=2; i<NF; i++) printf \$i \" \"; print \$NF}" "${file}")
|
||||
if [ -z "${val}" ]; then
|
||||
# Split on . for section. However, section is optional
|
||||
IFS='.' read -r section key <<< "${sectionkey}"
|
||||
if [[ ! "${key}" ]]; then
|
||||
key="${section}"
|
||||
# default section if not given
|
||||
section="${section_default}"
|
||||
fi
|
||||
|
||||
# get current value (if exists)
|
||||
current=$(sed -En "/^\[/{h;d;};G;s/^${key}([[:blank:]]*)${delim}(.*)\n\[${section}\]$/\2/p" "${file}"|awk '{$1=$1};1')
|
||||
# get current comment (if exists)
|
||||
current_comment=$(sed -En "/^\[${section}\]/,/^\[.*\]/ s|^(${comment_delim}\[${key}\])(.*)|\2|p" "${file}"|awk '{$1=$1};1')
|
||||
|
||||
if ! grep -q "\[${section}\]" "${file}"; then
|
||||
# create section if not exists (empty line to seperate new section for better readability)
|
||||
echo >> "${file}"
|
||||
echo "[${section}]" >> "${file}"
|
||||
fi
|
||||
|
||||
if [[ ! "${val}" ]]; then
|
||||
# get a value
|
||||
echo "${current}"
|
||||
else
|
||||
# set a value
|
||||
if [ -z "${current}" ]; then
|
||||
# doesn't exist yet, add
|
||||
|
||||
if [ -z "${section}" ]; then
|
||||
# no section was given, add to bottom of file
|
||||
echo "${key}${delim}${val}" >> "${file}"
|
||||
else
|
||||
# add to section
|
||||
sed "/\[${section}\]/a ${key}${delim}${val}" -i "${file}"
|
||||
fi
|
||||
else
|
||||
# replace existing
|
||||
sed "/^${key}${delim}/s/${delim}.*/${delim}${val}/" -i "${file}"
|
||||
if [[ ! "${section}" ]]; then
|
||||
# if no section is given, propagate the default section
|
||||
section=${section_default}
|
||||
fi
|
||||
|
||||
if [[ ! "${comment}" ]]; then
|
||||
# if no comment given, keep old comment
|
||||
comment="${current_comment}"
|
||||
fi
|
||||
# maintenance area
|
||||
# a) remove comment if new given / respect section
|
||||
sed -i.bak "/^\[${section}\]/,/^\[.*\]/ s|^\(${comment_delim}\[${key}\] \).*$||" "${file}"
|
||||
# b) remove old key / respect section
|
||||
sed -i.bak "/^\[${section}\]/,/^\[.*\]/ s|^\(${key}=\).*$||" "${file}"
|
||||
# c) remove all empty lines in ini file
|
||||
sed -i.bak '/^[[:space:]]*$/d' "${file}"
|
||||
# d) insert line break before every section for better readability
|
||||
sed -i.bak $'s/^\\[/\\\n\\[/g' "${file}"
|
||||
|
||||
# add to section
|
||||
if [[ ! "${comment}" ]]; then
|
||||
# add new key/value _without_ comment
|
||||
RET="/\\[${section}\\]/a\\
|
||||
${key}${delim}${val}"
|
||||
else
|
||||
# add new key/value _with_ preceeding comment
|
||||
RET="/\\[${section}\\]/a\\
|
||||
${comment_delim}[${key}] ${comment}\\
|
||||
${key}${delim}${val}"
|
||||
fi
|
||||
sed -i.bak -e "${RET}" "${file}"
|
||||
# this .bak dance is done for BSD/GNU portability: http://stackoverflow.com/a/22084103/151666
|
||||
rm -f "${file}.bak"
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
export -f ini_val
|
||||
else
|
||||
ini_val "${@}"
|
||||
exit ${?}
|
||||
fi
|
||||
|
@ -1,10 +1,49 @@
|
||||
__dir=$(cd `dirname "${BASH_SOURCE[0]}"` && pwd)
|
||||
#!/usr/bin/env bash
|
||||
# BASH3 Boilerplate: megamount
|
||||
#
|
||||
# This file:
|
||||
#
|
||||
# - Takes a URL (smb, nfs, afs) and tries to mount it at a given target directory
|
||||
# - Forcefully unmounts any active mount at the target directory first
|
||||
# - Displays the mount's contents for verification
|
||||
#
|
||||
# Depends on:
|
||||
#
|
||||
# - ./parse_url.sh
|
||||
#
|
||||
# Usage as a function:
|
||||
#
|
||||
# source megamount.sh
|
||||
# megamount smb://janedoe:abc123@192.168.0.1/documents /mnt/documents
|
||||
#
|
||||
# Usage as a command:
|
||||
#
|
||||
# megamount.sh smb://janedoe:abc123@192.168.0.1/documents /mnt/documents
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate vv2.7.2
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# shellcheck source=src/parse_url.sh
|
||||
source "${__dir}/parse_url.sh"
|
||||
|
||||
function megamount () {
|
||||
local url="${1}"
|
||||
local target="${2}"
|
||||
|
||||
local proto
|
||||
local user
|
||||
local pass
|
||||
local host
|
||||
local port
|
||||
local path
|
||||
|
||||
proto=$(parse_url "${url}" "proto")
|
||||
user=$(parse_url "${url}" "user")
|
||||
pass=$(parse_url "${url}" "pass")
|
||||
@ -12,21 +51,28 @@ function megamount () {
|
||||
port=$(parse_url "${url}" "port")
|
||||
path=$(parse_url "${url}" "path")
|
||||
|
||||
umount -lf "${target}" || true
|
||||
(umount -lf "${target}" || umount -f "${target}") > /dev/null 2>&1 || true
|
||||
mkdir -p "${target}"
|
||||
if [ "${proto}" = "smb://" ]; then
|
||||
if [[ "${proto}" = "smb://" ]]; then
|
||||
mount -t cifs --verbose -o "username=${user},password=${pass},hard" "//${host}/${path}" "${target}"
|
||||
elif [ "${proto}" = "afp://" ]; then
|
||||
elif [[ "${proto}" = "afp://" ]]; then
|
||||
# start syslog-ng
|
||||
# afpfsd || echo "Unable to run afpfsd. Does /dev/log exist?" && exit 1
|
||||
mount_afp "${url}" "${target}"
|
||||
elif [ "${proto}" = "nfs://" ]; then
|
||||
mount -t nfs --verbose -o "vers=3,nolock,soft,intr,rsize=32768,wsize=32768" ${host}:/${path} ${target}
|
||||
elif [[ "${proto}" = "nfs://" ]]; then
|
||||
mount -t nfs --verbose -o "vers=3,nolock,soft,intr,rsize=32768,wsize=32768" "${host}:/${path}" "${target}"
|
||||
else
|
||||
echo "ERR: Unknown protocol ${proto}"
|
||||
echo "ERR: Unknown protocol: '${proto}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# chmod 777 "${target}"
|
||||
ls -al "${target}/"
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
export -f megamount
|
||||
else
|
||||
megamount "${@}"
|
||||
exit ${?}
|
||||
fi
|
||||
|
@ -1,30 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
# BASH3 Boilerplate: parse_url
|
||||
#
|
||||
# This file:
|
||||
#
|
||||
# - Takes a URL and parses protocol, user, pass, host, port, path.
|
||||
#
|
||||
# Based on:
|
||||
#
|
||||
# - http://stackoverflow.com/a/6174447/151666
|
||||
#
|
||||
# Usage as a function:
|
||||
#
|
||||
# source parse_url.sh
|
||||
# parse_url 'http://johndoe:abc123@example.com:8080/index.html' pass
|
||||
#
|
||||
# Usage as a command:
|
||||
#
|
||||
# parse_url.sh 'http://johndoe:abc123@example.com:8080/index.html'
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate vv2.7.2
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
function parse_url() {
|
||||
# Based on http://stackoverflow.com/a/6174447/151666
|
||||
local parse="${1}"
|
||||
local need="${2}"
|
||||
local need="${2:-}"
|
||||
|
||||
local proto="$(echo $parse | grep :// | sed -e's,^\(.*://\).*,\1,g')"
|
||||
local url="$(echo ${parse/$proto/})"
|
||||
local userpass="$(echo $url | grep @ | cut -d@ -f1)"
|
||||
local user="$(echo $userpass | grep : | cut -d: -f1)"
|
||||
local pass="$(echo $userpass | grep : | cut -d: -f2)"
|
||||
local hostport="$(echo ${url/$userpass@/} | cut -d/ -f1)"
|
||||
local host="$(echo $hostport | grep : | cut -d: -f1)"
|
||||
local port="$(echo $hostport | grep : | cut -d: -f2)"
|
||||
local path="$(echo $url | grep / | cut -d/ -f2-)"
|
||||
local proto
|
||||
local url
|
||||
local userpass
|
||||
local user
|
||||
local pass
|
||||
local hostport
|
||||
local host
|
||||
local port
|
||||
local path
|
||||
|
||||
[ -z "${user}" ] && user="${userpass}"
|
||||
[ -z "${host}" ] && host="${hostport}"
|
||||
if [ -z "${port}" ]; then
|
||||
[ "${proto}" = "http://" ] && port="80"
|
||||
[ "${proto}" = "https://" ] && port="443"
|
||||
[ "${proto}" = "mysql://" ] && port="3306"
|
||||
[ "${proto}" = "redis://" ] && port="6379"
|
||||
proto="$(echo "${parse}" | grep :// | sed -e's,^\(.*://\).*,\1,g')"
|
||||
url="${parse/${proto}/}"
|
||||
userpass="$(echo "${url}" | grep @ | cut -d@ -f1)"
|
||||
user="$(echo "${userpass}" | grep : | cut -d: -f1)"
|
||||
pass="$(echo "${userpass}" | grep : | cut -d: -f2)"
|
||||
hostport="$(echo "${url/${userpass}@/}" | cut -d/ -f1)"
|
||||
host="$(echo "${hostport}" | grep : | cut -d: -f1)"
|
||||
port="$(echo "${hostport}" | grep : | cut -d: -f2)"
|
||||
path="$(echo "${url}" | grep / | cut -d/ -f2-)"
|
||||
|
||||
[[ ! "${user}" ]] && user="${userpass}"
|
||||
[[ ! "${host}" ]] && host="${hostport}"
|
||||
if [[ ! "${port}" ]]; then
|
||||
[[ "${proto}" = "http://" ]] && port="80"
|
||||
[[ "${proto}" = "https://" ]] && port="443"
|
||||
[[ "${proto}" = "mysql://" ]] && port="3306"
|
||||
[[ "${proto}" = "redis://" ]] && port="6379"
|
||||
fi
|
||||
|
||||
if [ -n "${need}" ]; then
|
||||
echo ${!need}
|
||||
if [[ "${need}" ]]; then
|
||||
echo "${!need}"
|
||||
else
|
||||
echo ""
|
||||
echo " Use second argument to return just 1 variable."
|
||||
@ -39,3 +75,10 @@ function parse_url() {
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
export -f parse_url
|
||||
else
|
||||
parse_url "${@}"
|
||||
exit ${?}
|
||||
fi
|
||||
|
132
src/semver.sh
132
src/semver.sh
@ -1,132 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
# From: https://github.com/cloudflare/semver_bash
|
||||
# https://raw.githubusercontent.com/cloudflare/semver_bash/master/semver.sh
|
||||
|
||||
function semverParseInto() {
|
||||
local RE='[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)'
|
||||
#MAJOR
|
||||
eval $2=`echo $1 | sed -e "s#$RE#\1#"`
|
||||
#MINOR
|
||||
eval $3=`echo $1 | sed -e "s#$RE#\2#"`
|
||||
#MINOR
|
||||
eval $4=`echo $1 | sed -e "s#$RE#\3#"`
|
||||
#SPECIAL
|
||||
eval $5=`echo $1 | sed -e "s#$RE#\4#"`
|
||||
}
|
||||
|
||||
function semverEQ() {
|
||||
local MAJOR_A=0
|
||||
local MINOR_A=0
|
||||
local PATCH_A=0
|
||||
local SPECIAL_A=0
|
||||
|
||||
local MAJOR_B=0
|
||||
local MINOR_B=0
|
||||
local PATCH_B=0
|
||||
local SPECIAL_B=0
|
||||
|
||||
semverParseInto $1 MAJOR_A MINOR_A PATCH_A SPECIAL_A
|
||||
semverParseInto $2 MAJOR_B MINOR_B PATCH_B SPECIAL_B
|
||||
|
||||
if [ $MAJOR_A -ne $MAJOR_B ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ $MINOR_A -ne $MINOR_B ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ $PATCH_A -ne $PATCH_B ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "_$SPECIAL_A" != "_$SPECIAL_B" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
function semverLT() {
|
||||
local MAJOR_A=0
|
||||
local MINOR_A=0
|
||||
local PATCH_A=0
|
||||
local SPECIAL_A=0
|
||||
|
||||
local MAJOR_B=0
|
||||
local MINOR_B=0
|
||||
local PATCH_B=0
|
||||
local SPECIAL_B=0
|
||||
|
||||
semverParseInto $1 MAJOR_A MINOR_A PATCH_A SPECIAL_A
|
||||
semverParseInto $2 MAJOR_B MINOR_B PATCH_B SPECIAL_B
|
||||
|
||||
if [ $MAJOR_A -lt $MAJOR_B ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ $MAJOR_A -le $MAJOR_B && $MINOR_A -lt $MINOR_B ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ $MAJOR_A -le $MAJOR_B && $MINOR_A -le $MINOR_B && $PATCH_A -lt $PATCH_B ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "_$SPECIAL_A" == "_" ]] && [[ "_$SPECIAL_B" == "_" ]] ; then
|
||||
return 1
|
||||
fi
|
||||
if [[ "_$SPECIAL_A" == "_" ]] && [[ "_$SPECIAL_B" != "_" ]] ; then
|
||||
return 1
|
||||
fi
|
||||
if [[ "_$SPECIAL_A" != "_" ]] && [[ "_$SPECIAL_B" == "_" ]] ; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "_$SPECIAL_A" < "_$SPECIAL_B" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
function semverGT() {
|
||||
semverEQ $1 $2
|
||||
local EQ=$?
|
||||
|
||||
semverLT $1 $2
|
||||
local LT=$?
|
||||
|
||||
if [ $EQ -ne 0 ] && [ $LT -ne 0 ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "___semver.sh" == "___`basename $0`" ]; then
|
||||
|
||||
MAJOR=0
|
||||
MINOR=0
|
||||
PATCH=0
|
||||
SPECIAL=""
|
||||
|
||||
semverParseInto $1 MAJOR MINOR PATCH SPECIAL
|
||||
echo "$1 -> M: $MAJOR m:$MINOR p:$PATCH s:$SPECIAL"
|
||||
|
||||
semverParseInto $2 MAJOR MINOR PATCH SPECIAL
|
||||
echo "$2 -> M: $MAJOR m:$MINOR p:$PATCH s:$SPECIAL"
|
||||
|
||||
semverEQ $1 $2
|
||||
echo "$1 == $2 -> $?."
|
||||
|
||||
semverLT $1 $2
|
||||
echo "$1 < $2 -> $?."
|
||||
|
||||
semverGT $1 $2
|
||||
echo "$1 > $2 -> $?."
|
||||
|
||||
fi
|
@ -1,48 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2014, Transloadit Ltd.
|
||||
# BASH3 Boilerplate: templater
|
||||
#
|
||||
# This file:
|
||||
# - takes a source (template) & destination (config) filepath argument
|
||||
# - and then replaces placeholders with variables found in the environment
|
||||
#
|
||||
# Run as:
|
||||
# - takes a source (template) & destination (config) filepath argument
|
||||
# - then replaces placeholders with variables found in the environment
|
||||
#
|
||||
# Usage as a function:
|
||||
#
|
||||
# source templater.sh
|
||||
# export NAME=kevin
|
||||
# templater input.cfg output.cfg
|
||||
#
|
||||
# Usage as a command:
|
||||
#
|
||||
# ALLOW_REMAINDERS=1 templater.sh input.cfg output.cfg
|
||||
#
|
||||
# Authors:
|
||||
# - Kevin van Zonneveld <kevin@transloadit.com>
|
||||
# Based on a template by BASH3 Boilerplate vv2.7.2
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
# set -o xtrace
|
||||
# set -o nounset
|
||||
function templater() {
|
||||
ALLOW_REMAINDERS="${ALLOW_REMAINDERS:-0}"
|
||||
|
||||
sed=""
|
||||
[ -n "$(which sed)" ] && sed="$(which sed)"
|
||||
[ -n "$(which gsed)" ] && sed="$(which gsed)"
|
||||
templateSrc="${1:-}"
|
||||
templateDst="${2:-}"
|
||||
|
||||
ALLOW_REMAINDERS="${ALLOW_REMAINDERS:-0}"
|
||||
if [[ ! -f "${templateSrc}" ]]; then
|
||||
echo "ERROR: Template source '${templateSrc}' needs to exist"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! "${templateDst}" ]]; then
|
||||
echo "ERROR: Template destination '${templateDst}' needs to be specified"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
templateSrc="${1}"
|
||||
templateDst="${2}"
|
||||
if [[ "$(command -v perl)" ]]; then
|
||||
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1} ? $ENV{$1} : "\${$1}")/eg' < "${templateSrc}" > "${templateDst}"
|
||||
else
|
||||
cp -f "${templateSrc}" "${templateDst}"
|
||||
|
||||
if [ ! -f "${templateSrc}" ]; then
|
||||
echo "ERROR: Template source '${templateSrc}' needs to exist"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -n "${templateDst}" ]; then
|
||||
echo "ERROR: Template destination '${templateDst}' needs to exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp -f "${templateSrc}" "${templateDst}"
|
||||
for var in $(env |awk -F= '{print $1}' |egrep '^[A-Z0-9_]+$'); do
|
||||
${sed} "s#\${${var}}#${!var}#g" -i "${templateDst}"
|
||||
done
|
||||
|
||||
# cat "${templateDst}"
|
||||
|
||||
if grep '${' ${templateDst} && [ "${ALLOW_REMAINDERS}" == "0" ]; then
|
||||
echo "ERROR: Unable to replace the above template vars"
|
||||
exit 1
|
||||
for var in $(env |awk -F= '{print $1}' |grep -E '^(_[A-Z0-9_]+|[A-Z0-9][A-Z0-9_]*)$'); do
|
||||
sed -i.bak -e "s#\${${var}}#${!var//#/\\#/}#g" "${templateDst}"
|
||||
# this .bak dance is done for BSD/GNU portability: http://stackoverflow.com/a/22084103/151666
|
||||
rm -f "${templateDst}.bak"
|
||||
done
|
||||
fi
|
||||
|
||||
# cat "${templateDst}"
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
if grep '${' "${templateDst}" && [[ "${ALLOW_REMAINDERS}" = "0" ]]; then
|
||||
echo "ERROR: Unable to replace the above template vars"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
export -f templater
|
||||
else
|
||||
templater "${@}"
|
||||
exit ${?}
|
||||
fi
|
||||
|
232
test/acceptance.sh
Executable file
232
test/acceptance.sh
Executable file
@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env bash
|
||||
# This file:
|
||||
#
|
||||
# - Executes one (or all) test scenarios
|
||||
# - Replaces dynamic things like hostnames, IPs, dates, etc
|
||||
# - Optionally saves the results as fixtures, that later runs will be compared against
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ./deploy.sh
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate v2.0.0
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
# Exit on error. Append || true if you expect an error.
|
||||
set -o errexit
|
||||
# Exit on error inside any functions or subshells.
|
||||
set -o errtrace
|
||||
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
|
||||
set -o nounset
|
||||
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
|
||||
set -o pipefail
|
||||
# Turn on traces, useful while debugging but commented out by default
|
||||
# set -o xtrace
|
||||
|
||||
# Set magic variables for current file, directory, os, etc.
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename "${__file}" .sh)"
|
||||
__root="$(cd "$(dirname "${__dir}")" && pwd)"
|
||||
|
||||
__sysTmpDir="${TMPDIR:-/tmp}"
|
||||
__sysTmpDir="${__sysTmpDir%/}" # <-- remove trailing slash on macosx
|
||||
__accptstTmpDir=$(mktemp -d "${__sysTmpDir}/${__base}.XXXXXX")
|
||||
|
||||
function cleanup_before_exit () { rm -r "${__accptstTmpDir:?}"; }
|
||||
trap cleanup_before_exit EXIT
|
||||
|
||||
cmdSed="sed"
|
||||
cmdTimeout="timeout"
|
||||
|
||||
if [[ "${OSTYPE}" = "darwin"* ]]; then
|
||||
cmdSed="gsed"
|
||||
cmdTimeout="gtimeout"
|
||||
fi
|
||||
|
||||
if [[ ! "$(command -v ${cmdSed})" ]]; then
|
||||
echo "Please install ${cmdSed}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! "$(command -v ${cmdTimeout})" ]]; then
|
||||
echo "Please install ${cmdTimeout}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
__node="$(command -v node)"
|
||||
__arch="amd64"
|
||||
|
||||
# explicitly setting NO_COLOR to false will make b3bp ignore TERM
|
||||
# not being "xterm*" or "screen*" and STDERR not being connected to a terminal
|
||||
# it's the opposite of NO_COLOR="true" - it forces color, no matter what
|
||||
export NO_COLOR="false"
|
||||
|
||||
# Running prepare before other scenarios is important on Travis,
|
||||
# so that stdio can diverge - and we can enforce stricter
|
||||
# stdio comparison on all other tests.
|
||||
while IFS=$'\n' read -r scenario; do
|
||||
scenario="$(dirname "${scenario}")"
|
||||
scenario="${scenario##${__dir}/scenario/}"
|
||||
|
||||
[[ "${scenario}" = "prepare" ]] && continue
|
||||
[[ "${1:-}" ]] && [[ "${scenario}" != "${1}" ]] && continue
|
||||
|
||||
echo "==> Scenario: ${scenario}"
|
||||
pushd "${__dir}/scenario/${scenario}" > /dev/null
|
||||
|
||||
# Run scenario
|
||||
(${cmdTimeout} --kill-after=6m 5m bash ./run.sh \
|
||||
> "${__accptstTmpDir}/${scenario}.stdio" 2>&1; \
|
||||
echo "${?}" > "${__accptstTmpDir}/${scenario}.exitcode" \
|
||||
) || true
|
||||
|
||||
# Clear out environmental specifics
|
||||
for typ in stdio exitcode; do
|
||||
curFile="${__accptstTmpDir}/${scenario}.${typ}"
|
||||
"${cmdSed}" -i \
|
||||
-e "s@${__node}@{node}@g" "${curFile}" \
|
||||
-e "s@${__root}@{root}@g" "${curFile}" \
|
||||
-e "s@${__sysTmpDir}@{tmpdir}@g" "${curFile}" \
|
||||
-e "s@/tmp@{tmpdir}@g" "${curFile}" \
|
||||
-e "s@${HOME:-/home/travis}@{home}@g" "${curFile}" \
|
||||
-e "s@${USER:-travis}@{user}@g" "${curFile}" \
|
||||
-e "s@travis@{user}@g" "${curFile}" \
|
||||
-e "s@kvz@{user}@g" "${curFile}" \
|
||||
-e "s@{root}/node_modules/\\.bin/node@{node}@g" "${curFile}" \
|
||||
-e "s@{home}/build/{user}/fre{node}@{node}@g" "${curFile}" \
|
||||
-e "s@${HOSTNAME}@{hostname}@g" "${curFile}" \
|
||||
-e "s@${__arch}@{arch}@g" "${curFile}" \
|
||||
-e "s@${OSTYPE}@{OSTYPE}@g" "${curFile}" \
|
||||
-e "s@OSX@{os}@g" "${curFile}" \
|
||||
-e "s@Linux@{os}@g" "${curFile}" \
|
||||
|| false
|
||||
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_IPS' "${curFile}"; then
|
||||
"${cmdSed}" -i \
|
||||
-r 's@[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}@{ip}@g' \
|
||||
"${curFile}"
|
||||
|
||||
# IPs vary in length. Ansible uses padding. {ip} does not vary in length
|
||||
# so kill the padding after it for consistent output
|
||||
"${cmdSed}" -i \
|
||||
-r 's@\{ip\}\s+@{ip} @g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_UUIDS' "${curFile}"; then
|
||||
"${cmdSed}" -i \
|
||||
-r 's@[0-9a-f\-]{32,40}@{uuid}@g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_BIGINTS' "${curFile}"; then
|
||||
# Such as: 3811298194
|
||||
"${cmdSed}" -i \
|
||||
-r 's@[0-9]{7,64}@{bigint}@g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_DATETIMES' "${curFile}"; then
|
||||
# Such as: 2016-02-10 15:38:44.420094
|
||||
"${cmdSed}" -i \
|
||||
-r 's@[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}@{datetime}@g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_LONGTIMES' "${curFile}"; then
|
||||
# Such as: 2016-02-10 15:38:44.420094
|
||||
"${cmdSed}" -i \
|
||||
-r 's@[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{6}@{longtime}@g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_DURATIONS' "${curFile}"; then
|
||||
# Such as: 0:00:00.001991
|
||||
"${cmdSed}" -i \
|
||||
-r 's@[0-9]{1,2}:[0-9]{2}:[0-9]{2}.[0-9]{6}@{duration}@g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_REMOTE_EXEC' "${curFile}"; then
|
||||
grep -Ev 'remote-exec\): [ a-zA-Z]' "${curFile}" > "${__sysTmpDir}/accptst-filtered.txt"
|
||||
mv "${__sysTmpDir}/accptst-filtered.txt" "${curFile}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Save these as new fixtures?
|
||||
if [[ "${SAVE_FIXTURES:-}" = "true" ]]; then
|
||||
for typ in stdio exitcode; do
|
||||
curFile="${__accptstTmpDir}/${scenario}.${typ}"
|
||||
cp -f \
|
||||
"${curFile}" \
|
||||
"${__dir}/fixture/${scenario}.${typ}"
|
||||
done
|
||||
fi
|
||||
|
||||
# Compare
|
||||
for typ in stdio exitcode; do
|
||||
curFile="${__accptstTmpDir}/${scenario}.${typ}"
|
||||
|
||||
echo -n " comparing ${typ}.. "
|
||||
|
||||
if [[ "${typ}" = "stdio" ]]; then
|
||||
if grep -q 'ACCPTST:STDIO_SKIP_COMPARE' "${curFile}"; then
|
||||
echo "skip"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! diff --strip-trailing-cr "${__dir}/fixture/${scenario}.${typ}" "${curFile}"; then
|
||||
echo -e "\\n\\n==> MISMATCH OF: ${scenario}.${typ} ---^"
|
||||
echo -e "\\n\\n==> EXPECTED STDIO: "
|
||||
cat "${__dir}/fixture/${scenario}.stdio" || true
|
||||
echo -e "\\n\\n==> ACTUAL STDIO: "
|
||||
cat "${__accptstTmpDir}/${scenario}.stdio" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓"
|
||||
done
|
||||
|
||||
popd > /dev/null
|
||||
done <<< "$(find "${__dir}/scenario" -type f -iname 'run.sh')"
|
||||
|
||||
[[ "${1:-}" ]] && exit 0
|
||||
|
||||
# Ensure correct syntax with all available bashes
|
||||
|
||||
# shellcheck disable=SC2230
|
||||
# "command -v" is not a substitute for "which -a"
|
||||
while IFS=$'\n' read -r bash; do
|
||||
if [[ "${bash:-}" = "" ]]; then
|
||||
continue
|
||||
fi
|
||||
# shellcheck disable=SC2016
|
||||
echo "==> ${bash} -n $(${bash} -c 'echo "(${BASH_VERSION})"')"
|
||||
pushd "${__root}" > /dev/null
|
||||
|
||||
failed="false"
|
||||
|
||||
while IFS=$'\n' read -r file; do
|
||||
[[ "${file}" =~ ^\./node_modules/ ]] && continue
|
||||
|
||||
echo -n " ${file}.. "
|
||||
|
||||
if ! "${bash}" -n "${file}" 2>> "${__accptstTmpDir}/${bash//\//.}.err"; then
|
||||
echo "✗"
|
||||
failed="true"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "✓"
|
||||
done <<< "$(find . -type f -iname '*.sh')"
|
||||
|
||||
popd > /dev/null
|
||||
|
||||
if [[ "${failed}" = "true" ]]; then
|
||||
cat "${__accptstTmpDir}/${bash//\//.}.err"
|
||||
exit 1
|
||||
fi
|
||||
done <<< "$(which -a bash 2>/dev/null)"
|
||||
|
||||
exit 0
|
0
test/fixture/.empty
Normal file
0
test/fixture/.empty
Normal file
1
test/fixture/double-source.exitcode
Normal file
1
test/fixture/double-source.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
25
test/fixture/double-source.stdio
Normal file
25
test/fixture/double-source.stdio
Normal file
@ -0,0 +1,25 @@
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [35m[ debug][0m cli arg arg_f = () -> {tmpdir}/x
|
||||
{datetime} UTC [32m[ info][0m __i_am_main_script: 0
|
||||
{datetime} UTC [32m[ info][0m __file: {root}/example.sh
|
||||
{datetime} UTC [32m[ info][0m __dir: {root}
|
||||
{datetime} UTC [32m[ info][0m __base: example
|
||||
{datetime} UTC [32m[ info][0m OSTYPE: {OSTYPE}
|
||||
{datetime} UTC [32m[ info][0m arg_f: {tmpdir}/x
|
||||
{datetime} UTC [32m[ info][0m arg_d: 0
|
||||
{datetime} UTC [32m[ info][0m arg_v: 0
|
||||
{datetime} UTC [32m[ info][0m arg_h: 0
|
||||
{datetime} UTC [32m[ info][0m arg_i: 0
|
||||
{datetime} UTC [32m[ info][0m arg_x: 0
|
||||
{datetime} UTC [32m[ info][0m multiple lines example - line #1
|
||||
{datetime} UTC [32m[ info][0m multiple lines example - line #2
|
||||
{datetime} UTC [32m[ info][0m imagine logging the output of 'ls -al /path/'
|
||||
{datetime} UTC [35m[ debug][0m Info useful to developers for debugging the application, not useful during operations.
|
||||
{datetime} UTC [32m[ info][0m Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
|
||||
{datetime} UTC [34m[ notice][0m Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
|
||||
{datetime} UTC [33m[ warning][0m Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time.
|
||||
{datetime} UTC [31m[ error][0m Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
|
||||
{datetime} UTC [1;31m[ critical][0m Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.
|
||||
{datetime} UTC [1;37;41m[ alert][0m Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
|
||||
{datetime} UTC [1;4;5;37;41m[emergency][0m A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
|
||||
{datetime} UTC [32m[ info][0m Cleaning up. Done
|
1
test/fixture/ini_val.exitcode
Normal file
1
test/fixture/ini_val.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
42
test/fixture/ini_val.stdio
Normal file
42
test/fixture/ini_val.stdio
Normal file
@ -0,0 +1,42 @@
|
||||
--> command: Read 3 values
|
||||
exists
|
||||
127.0.0.1
|
||||
nginx, nodejs
|
||||
|
||||
--> command: Replace three values in-place and show result
|
||||
|
||||
[default]
|
||||
orphan=no more
|
||||
|
||||
[connection]
|
||||
host=192.168.0.1
|
||||
|
||||
[software]
|
||||
packages=vim
|
||||
|
||||
[comment]
|
||||
;[command] got this new comment
|
||||
command=works like a chame
|
||||
;[new_command] last addition will be moved downwards again after next command
|
||||
new_command=commented too
|
||||
--> function: Read 3 values
|
||||
exists
|
||||
127.0.0.1
|
||||
nginx, nodejs
|
||||
|
||||
--> function: Replace three values in-place and show result
|
||||
|
||||
[default]
|
||||
orphan=no more
|
||||
|
||||
[connection]
|
||||
host=192.168.0.1
|
||||
|
||||
[software]
|
||||
packages=vim
|
||||
|
||||
[comment]
|
||||
;[command] got this new comment
|
||||
command=works like a chame
|
||||
;[new_command] last addition will be moved downwards again after next command
|
||||
new_command=commented too
|
1
test/fixture/main-debug.exitcode
Normal file
1
test/fixture/main-debug.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
25
test/fixture/main-debug.stdio
Normal file
25
test/fixture/main-debug.stdio
Normal file
@ -0,0 +1,25 @@
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [35m[ debug][0m cli arg arg_f = () -> {tmpdir}/x
|
||||
{datetime} UTC [32m[ info][0m __i_am_main_script: 1
|
||||
{datetime} UTC [32m[ info][0m __file: {root}/main.sh
|
||||
{datetime} UTC [32m[ info][0m __dir: {root}
|
||||
{datetime} UTC [32m[ info][0m __base: main
|
||||
{datetime} UTC [32m[ info][0m OSTYPE: {OSTYPE}
|
||||
{datetime} UTC [32m[ info][0m arg_f: {tmpdir}/x
|
||||
{datetime} UTC [32m[ info][0m arg_d: 0
|
||||
{datetime} UTC [32m[ info][0m arg_v: 0
|
||||
{datetime} UTC [32m[ info][0m arg_h: 0
|
||||
{datetime} UTC [32m[ info][0m arg_i: 0
|
||||
{datetime} UTC [32m[ info][0m arg_x: 0
|
||||
{datetime} UTC [32m[ info][0m multiple lines example - line #1
|
||||
{datetime} UTC [32m[ info][0m multiple lines example - line #2
|
||||
{datetime} UTC [32m[ info][0m imagine logging the output of 'ls -al /path/'
|
||||
{datetime} UTC [35m[ debug][0m Info useful to developers for debugging the application, not useful during operations.
|
||||
{datetime} UTC [32m[ info][0m Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
|
||||
{datetime} UTC [34m[ notice][0m Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
|
||||
{datetime} UTC [33m[ warning][0m Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time.
|
||||
{datetime} UTC [31m[ error][0m Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
|
||||
{datetime} UTC [1;31m[ critical][0m Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.
|
||||
{datetime} UTC [1;37;41m[ alert][0m Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
|
||||
{datetime} UTC [1;4;5;37;41m[emergency][0m A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
|
||||
{datetime} UTC [32m[ info][0m Cleaning up. Done
|
1
test/fixture/main-help.exitcode
Normal file
1
test/fixture/main-help.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
19
test/fixture/main-help.stdio
Normal file
19
test/fixture/main-help.stdio
Normal file
@ -0,0 +1,19 @@
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
|
||||
Help using {root}/main.sh
|
||||
|
||||
-f --file [arg] Filename to process. Required.
|
||||
-t --temp [arg] Location of tempfile. Default="{tmpdir}/bar"
|
||||
-v Enable verbose mode, print script as it is executed
|
||||
-d --debug Enables debug mode
|
||||
-h --help This page
|
||||
-n --no-color Disable color output
|
||||
-1 --one Do just one thing
|
||||
-i --input [arg] File to process. Can be repeated.
|
||||
-x Specify a flag. Can be repeated.
|
||||
|
||||
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
|
||||
{datetime} UTC [32m[ info][0m Cleaning up. Done
|
1
test/fixture/main-longopt.exitcode
Normal file
1
test/fixture/main-longopt.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
4
test/fixture/main-longopt.stdio
Normal file
4
test/fixture/main-longopt.stdio
Normal file
@ -0,0 +1,4 @@
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [32m[ info][0m arg_f: {tmpdir}/x
|
||||
{datetime} UTC [32m[ info][0m arg_f: {tmpdir}/x
|
||||
{datetime} UTC [32m[ info][0m arg_f: {tmpdir}/x
|
1
test/fixture/main-nocolor.exitcode
Normal file
1
test/fixture/main-nocolor.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
25
test/fixture/main-nocolor.stdio
Normal file
25
test/fixture/main-nocolor.stdio
Normal file
@ -0,0 +1,25 @@
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [ debug] cli arg arg_f = () -> {tmpdir}/x
|
||||
{datetime} UTC [ info] __i_am_main_script: 1
|
||||
{datetime} UTC [ info] __file: {root}/main.sh
|
||||
{datetime} UTC [ info] __dir: {root}
|
||||
{datetime} UTC [ info] __base: main
|
||||
{datetime} UTC [ info] OSTYPE: {OSTYPE}
|
||||
{datetime} UTC [ info] arg_f: {tmpdir}/x
|
||||
{datetime} UTC [ info] arg_d: 0
|
||||
{datetime} UTC [ info] arg_v: 0
|
||||
{datetime} UTC [ info] arg_h: 0
|
||||
{datetime} UTC [ info] arg_i: 0
|
||||
{datetime} UTC [ info] arg_x: 0
|
||||
{datetime} UTC [ info] multiple lines example - line #1
|
||||
{datetime} UTC [ info] multiple lines example - line #2
|
||||
{datetime} UTC [ info] imagine logging the output of 'ls -al /path/'
|
||||
{datetime} UTC [ debug] Info useful to developers for debugging the application, not useful during operations.
|
||||
{datetime} UTC [ info] Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
|
||||
{datetime} UTC [ notice] Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
|
||||
{datetime} UTC [ warning] Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time.
|
||||
{datetime} UTC [ error] Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
|
||||
{datetime} UTC [ critical] Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.
|
||||
{datetime} UTC [ alert] Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
|
||||
{datetime} UTC [emergency] A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
|
||||
{datetime} UTC [ info] Cleaning up. Done
|
1
test/fixture/main-repeated.exitcode
Normal file
1
test/fixture/main-repeated.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
9
test/fixture/main-repeated.stdio
Normal file
9
test/fixture/main-repeated.stdio
Normal file
@ -0,0 +1,9 @@
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [32m[ info][0m arg_i:
|
||||
{datetime} UTC [32m[ info][0m - simple_input
|
||||
{datetime} UTC [32m[ info][0m - input_in_quotes
|
||||
{datetime} UTC [32m[ info][0m - input with spaces
|
||||
{datetime} UTC [32m[ info][0m - input with "quotes"
|
||||
{datetime} UTC [32m[ info][0m - last_input
|
||||
{datetime} UTC [32m[ info][0m arg_x: 3
|
||||
{datetime} UTC [32m[ info][0m arg_x: 4
|
1
test/fixture/main-usage-defaults.exitcode
Normal file
1
test/fixture/main-usage-defaults.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
7
test/fixture/main-usage-defaults.stdio
Normal file
7
test/fixture/main-usage-defaults.stdio
Normal file
@ -0,0 +1,7 @@
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [32m[ info][0m arg_1: 0
|
||||
{datetime} UTC [32m[ info][0m arg_2: 0
|
||||
{datetime} UTC [32m[ info][0m arg_3: 'THREE'
|
||||
{datetime} UTC [32m[ info][0m arg_4: "FOUR"
|
||||
{datetime} UTC [32m[ info][0m arg_5: OOOPS
|
||||
{datetime} UTC [32m[ info][0m arg_6:
|
1
test/fixture/main-usage-validation.exitcode
Normal file
1
test/fixture/main-usage-validation.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
169
test/fixture/main-usage-validation.stdio
Normal file
169
test/fixture/main-usage-validation.stdio
Normal file
@ -0,0 +1,169 @@
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
# complain about -3
|
||||
|
||||
Option -3 (--three) requires an argument
|
||||
|
||||
-0 --zero Do nothing.
|
||||
-1 --one Do one thing. Required.
|
||||
More description.
|
||||
-2 --two Do two things.
|
||||
More. Required. Description.
|
||||
-3 --three [arg] Do three things.
|
||||
Required.
|
||||
-4 --four {arg} Do four things.
|
||||
-5 --five {arg} Do five things. Required. Maybe.
|
||||
-6 --six [arg] Do six things. Not Required.
|
||||
Required, it is not.
|
||||
-7 --seven [arg] Required. Or bust.
|
||||
-8 --eight [arg] Do eight things.
|
||||
More.Required.Description.
|
||||
-a [arg] Do A. Required.
|
||||
Default="do-a"
|
||||
-b {arg} Do B.Default="do-b"
|
||||
-c [arg] Required. Default="do-c"
|
||||
-d {arg} Default="do-d"
|
||||
|
||||
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
|
||||
# complain about -4
|
||||
|
||||
Option -4 (--four) requires an argument
|
||||
|
||||
-0 --zero Do nothing.
|
||||
-1 --one Do one thing. Required.
|
||||
More description.
|
||||
-2 --two Do two things.
|
||||
More. Required. Description.
|
||||
-3 --three [arg] Do three things.
|
||||
Required.
|
||||
-4 --four {arg} Do four things.
|
||||
-5 --five {arg} Do five things. Required. Maybe.
|
||||
-6 --six [arg] Do six things. Not Required.
|
||||
Required, it is not.
|
||||
-7 --seven [arg] Required. Or bust.
|
||||
-8 --eight [arg] Do eight things.
|
||||
More.Required.Description.
|
||||
-a [arg] Do A. Required.
|
||||
Default="do-a"
|
||||
-b {arg} Do B.Default="do-b"
|
||||
-c [arg] Required. Default="do-c"
|
||||
-d {arg} Default="do-d"
|
||||
|
||||
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
|
||||
# complain about -5
|
||||
|
||||
Option -5 (--five) requires an argument
|
||||
|
||||
-0 --zero Do nothing.
|
||||
-1 --one Do one thing. Required.
|
||||
More description.
|
||||
-2 --two Do two things.
|
||||
More. Required. Description.
|
||||
-3 --three [arg] Do three things.
|
||||
Required.
|
||||
-4 --four {arg} Do four things.
|
||||
-5 --five {arg} Do five things. Required. Maybe.
|
||||
-6 --six [arg] Do six things. Not Required.
|
||||
Required, it is not.
|
||||
-7 --seven [arg] Required. Or bust.
|
||||
-8 --eight [arg] Do eight things.
|
||||
More.Required.Description.
|
||||
-a [arg] Do A. Required.
|
||||
Default="do-a"
|
||||
-b {arg} Do B.Default="do-b"
|
||||
-c [arg] Required. Default="do-c"
|
||||
-d {arg} Default="do-d"
|
||||
|
||||
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
|
||||
# complain about -8 (because -7 syntax is not supported)
|
||||
|
||||
Option -8 (--eight) requires an argument
|
||||
|
||||
-0 --zero Do nothing.
|
||||
-1 --one Do one thing. Required.
|
||||
More description.
|
||||
-2 --two Do two things.
|
||||
More. Required. Description.
|
||||
-3 --three [arg] Do three things.
|
||||
Required.
|
||||
-4 --four {arg} Do four things.
|
||||
-5 --five {arg} Do five things. Required. Maybe.
|
||||
-6 --six [arg] Do six things. Not Required.
|
||||
Required, it is not.
|
||||
-7 --seven [arg] Required. Or bust.
|
||||
-8 --eight [arg] Do eight things.
|
||||
More.Required.Description.
|
||||
-a [arg] Do A. Required.
|
||||
Default="do-a"
|
||||
-b {arg} Do B.Default="do-b"
|
||||
-c [arg] Required. Default="do-c"
|
||||
-d {arg} Default="do-d"
|
||||
|
||||
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
|
||||
# complain about -d (because -d syntax is not supported)
|
||||
|
||||
Option -d requires an argument
|
||||
|
||||
-0 --zero Do nothing.
|
||||
-1 --one Do one thing. Required.
|
||||
More description.
|
||||
-2 --two Do two things.
|
||||
More. Required. Description.
|
||||
-3 --three [arg] Do three things.
|
||||
Required.
|
||||
-4 --four {arg} Do four things.
|
||||
-5 --five {arg} Do five things. Required. Maybe.
|
||||
-6 --six [arg] Do six things. Not Required.
|
||||
Required, it is not.
|
||||
-7 --seven [arg] Required. Or bust.
|
||||
-8 --eight [arg] Do eight things.
|
||||
More.Required.Description.
|
||||
-a [arg] Do A. Required.
|
||||
Default="do-a"
|
||||
-b {arg} Do B.Default="do-b"
|
||||
-c [arg] Required. Default="do-c"
|
||||
-d {arg} Default="do-d"
|
||||
|
||||
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
|
||||
# complain about nothing
|
||||
{datetime} UTC [ info] arg_0: 0
|
||||
{datetime} UTC [ info] arg_1: 0
|
||||
{datetime} UTC [ info] arg_2: 0
|
||||
{datetime} UTC [ info] arg_3: arg3
|
||||
{datetime} UTC [ info] arg_4: arg4
|
||||
{datetime} UTC [ info] arg_5: arg5
|
||||
{datetime} UTC [ info] arg_6:
|
||||
{datetime} UTC [ info] arg_7:
|
||||
{datetime} UTC [ info] arg_8: arg8
|
||||
{datetime} UTC [ info] arg_a: do-a
|
||||
{datetime} UTC [ info] arg_b: do-b
|
||||
{datetime} UTC [ info] arg_c: do-c
|
||||
{datetime} UTC [ info] arg_d: argd
|
||||
# test for issue #108
|
||||
{datetime} UTC [ info] arg_0: 1
|
||||
{datetime} UTC [ info] arg_1: 0
|
||||
{datetime} UTC [ info] arg_2: 0
|
||||
{datetime} UTC [ info] arg_3: arg3
|
||||
{datetime} UTC [ info] arg_4: value
|
||||
{datetime} UTC [ info] arg_5: arg5
|
||||
{datetime} UTC [ info] arg_6:
|
||||
{datetime} UTC [ info] arg_7:
|
||||
{datetime} UTC [ info] arg_8: arg8
|
||||
{datetime} UTC [ info] arg_a: do-a
|
||||
{datetime} UTC [ info] arg_b: do-b
|
||||
{datetime} UTC [ info] arg_c: do-c
|
||||
{datetime} UTC [ info] arg_d: argd
|
1
test/fixture/megamount.exitcode
Normal file
1
test/fixture/megamount.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
2
test/fixture/megamount.stdio
Normal file
2
test/fixture/megamount.stdio
Normal file
@ -0,0 +1,2 @@
|
||||
ERR: Unknown protocol: 'foobarfs://'
|
||||
ERR: Unknown protocol: 'foobarfs://'
|
1
test/fixture/parse_url.exitcode
Normal file
1
test/fixture/parse_url.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
24
test/fixture/parse_url.stdio
Normal file
24
test/fixture/parse_url.stdio
Normal file
@ -0,0 +1,24 @@
|
||||
abc123
|
||||
|
||||
Use second argument to return just 1 variable.
|
||||
parse_url() demo:
|
||||
|
||||
proto: http://
|
||||
user: johndoe
|
||||
pass: abc123
|
||||
host: example.com
|
||||
port: 8080
|
||||
path: index.html
|
||||
|
||||
abc123
|
||||
|
||||
Use second argument to return just 1 variable.
|
||||
parse_url() demo:
|
||||
|
||||
proto: http://
|
||||
user: johndoe
|
||||
pass: abc123
|
||||
host: example.com
|
||||
port: 8080
|
||||
path: index.html
|
||||
|
1
test/fixture/templater.exitcode
Normal file
1
test/fixture/templater.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
14
test/fixture/templater.stdio
Normal file
14
test/fixture/templater.stdio
Normal file
@ -0,0 +1,14 @@
|
||||
--
|
||||
[connection]
|
||||
host = 127.0.0.1
|
||||
--
|
||||
[connection]
|
||||
host = 127.0.0.1
|
||||
--
|
||||
port = ${I_DONT_EXIST}
|
||||
[connection]
|
||||
host = 127.0.0.1
|
||||
port = ${I_DONT_EXIST}
|
||||
--
|
||||
port = ${I_DONT_EXIST}
|
||||
ERROR: Unable to replace the above template vars
|
15
test/scenario/double-source/run.sh
Normal file
15
test/scenario/double-source/run.sh
Normal file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
export LOG_LEVEL=7
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
# shellcheck source=example.sh
|
||||
source "${__root}/example.sh" -f /tmp/x
|
8
test/scenario/ini_val/data.ini
Normal file
8
test/scenario/ini_val/data.ini
Normal file
@ -0,0 +1,8 @@
|
||||
[default]
|
||||
orphan=exists
|
||||
|
||||
[connection]
|
||||
host=127.0.0.1
|
||||
|
||||
[software]
|
||||
packages=nginx, nodejs
|
54
test/scenario/ini_val/run.sh
Executable file
54
test/scenario/ini_val/run.sh
Executable file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
# Set magic variables for current FILE & DIR
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
# echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
|
||||
# Use as standalone:
|
||||
cp -f data.ini dummy.ini
|
||||
echo "--> command: Read 3 values"
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini orphan
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini connection.host
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini software.packages
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini comment.command
|
||||
|
||||
echo "--> command: Replace three values in-place and show result"
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini orphan "no more"
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini connection.host "192.168.0.1"
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini software.packages "vim"
|
||||
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini comment.command "commented" "this key is commented"
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini comment.new_command "commented too" "last addition will be moved downwards again after next command"
|
||||
bash "${__root}/src/ini_val.sh" ./dummy.ini comment.command "works like a chame" "got this new comment"
|
||||
cat dummy.ini
|
||||
rm -f dummy.ini
|
||||
|
||||
# Use as include:
|
||||
cp -f data.ini dummy.ini
|
||||
|
||||
# shellcheck source=main.sh
|
||||
source "${__root}/src/ini_val.sh"
|
||||
|
||||
echo "--> function: Read 3 values"
|
||||
ini_val ./dummy.ini orphan
|
||||
ini_val ./dummy.ini connection.host
|
||||
ini_val ./dummy.ini software.packages
|
||||
ini_val ./dummy.ini comment.command
|
||||
|
||||
echo "--> function: Replace three values in-place and show result"
|
||||
ini_val ./dummy.ini orphan "no more"
|
||||
ini_val ./dummy.ini connection.host "192.168.0.1"
|
||||
ini_val ./dummy.ini software.packages "vim"
|
||||
|
||||
ini_val ./dummy.ini comment.command "commented" "this key is commited"
|
||||
ini_val ./dummy.ini comment.new_command "commented too" "last addition will be moved downwards again after next command"
|
||||
ini_val ./dummy.ini comment.command "works like a chame" "got this new comment"
|
||||
cat dummy.ini
|
||||
rm -f dummy.ini
|
12
test/scenario/main-debug/run.sh
Normal file
12
test/scenario/main-debug/run.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
env LOG_LEVEL=7 bash "${__root}/main.sh" -f /tmp/x
|
12
test/scenario/main-help/run.sh
Executable file
12
test/scenario/main-help/run.sh
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
bash "${__root}/main.sh" -f /tmp/x -h
|
16
test/scenario/main-longopt/run.sh
Normal file
16
test/scenario/main-longopt/run.sh
Normal file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
# set -o pipefail
|
||||
# set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
(
|
||||
env LOG_LEVEL=6 bash "${__root}/main.sh" --file /tmp/x;
|
||||
env LOG_LEVEL=6 bash "${__root}/main.sh" --file=/tmp/x;
|
||||
env LOG_LEVEL=6 bash "${__root}/main.sh" -f /tmp/x
|
||||
) 2>&1 |grep arg_f
|
12
test/scenario/main-nocolor/run.sh
Normal file
12
test/scenario/main-nocolor/run.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
env LOG_LEVEL=7 NO_COLOR=true bash "${__root}/main.sh" -f /tmp/x
|
19
test/scenario/main-repeated/run.sh
Normal file
19
test/scenario/main-repeated/run.sh
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# set -o pipefail
|
||||
# set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
(
|
||||
env LOG_LEVEL="${LOG_LEVEL:-6}" bash "${__root}/main.sh" -f dummy -i simple_input -i "input_in_quotes" -i "input with spaces" -i "input with \"quotes\"" -i last_input
|
||||
) 2>&1 |grep arg_i -A 5
|
||||
|
||||
(
|
||||
env LOG_LEVEL="${LOG_LEVEL:-6}" bash "${__root}/main.sh" -x -f dummy -x -x
|
||||
env LOG_LEVEL="${LOG_LEVEL:-6}" bash "${__root}/main.sh" -f dummy -xxxx
|
||||
) 2>&1 |grep arg_x
|
32
test/scenario/main-usage-defaults/run.sh
Executable file
32
test/scenario/main-usage-defaults/run.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
-1 --one Do one thing. Default="ONE"
|
||||
More description.
|
||||
-2 --two Do two things.
|
||||
More description. Default="TWO"
|
||||
-3 --three [arg] Do three things. Default="'THREE'"
|
||||
More description.
|
||||
-4 --four [arg] Do four things.
|
||||
More description. Default='"FOUR"'
|
||||
-5 --five [arg] Do five things. Default="FIVE"
|
||||
More description. Default='OOOPS'
|
||||
-6 --six [arg] Do six things.
|
||||
More description.
|
||||
EOF
|
||||
|
||||
export __usage
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
# shellcheck source=main.sh
|
||||
source "${__root}/main.sh"
|
||||
|
||||
for argument in ${!arg_*}; do info "${argument}: ${!argument}"; done
|
64
test/scenario/main-usage-validation/run.sh
Executable file
64
test/scenario/main-usage-validation/run.sh
Executable file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck source=main.sh
|
||||
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
-0 --zero Do nothing.
|
||||
-1 --one Do one thing. Required.
|
||||
More description.
|
||||
-2 --two Do two things.
|
||||
More. Required. Description.
|
||||
-3 --three [arg] Do three things.
|
||||
Required.
|
||||
-4 --four {arg} Do four things.
|
||||
-5 --five {arg} Do five things. Required. Maybe.
|
||||
-6 --six [arg] Do six things. Not Required.
|
||||
Required, it is not.
|
||||
-7 --seven [arg] Required. Or bust.
|
||||
-8 --eight [arg] Do eight things.
|
||||
More.Required.Description.
|
||||
-a [arg] Do A. Required.
|
||||
Default="do-a"
|
||||
-b {arg} Do B.Default="do-b"
|
||||
-c [arg] Required. Default="do-c"
|
||||
-d {arg} Default="do-d"
|
||||
EOF
|
||||
|
||||
export __usage
|
||||
export NO_COLOR="true"
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
echo "# complain about -3"
|
||||
(source "${__root}/main.sh") || true
|
||||
|
||||
echo "# complain about -4"
|
||||
(source "${__root}/main.sh" -3 arg3) || true
|
||||
|
||||
echo "# complain about -5"
|
||||
(source "${__root}/main.sh" -3 arg3 -4 arg4) || true
|
||||
|
||||
echo "# complain about -8 (because -7 syntax is not supported)"
|
||||
(source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5) || true
|
||||
|
||||
echo "# complain about -d (because -d syntax is not supported)"
|
||||
(source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5 -8 arg8) || true
|
||||
|
||||
echo "# complain about nothing"
|
||||
(
|
||||
source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5 -8 arg8 -d argd
|
||||
for argument in ${!arg_*}; do info "${argument}: ${!argument}"; done
|
||||
)
|
||||
|
||||
echo "# test for issue #108"
|
||||
(
|
||||
source "${__root}/main.sh" -3 arg3 -5 arg5 -8 arg8 -d argd --four value --zero
|
||||
for argument in ${!arg_*}; do info "${argument}: ${!argument}"; done
|
||||
)
|
21
test/scenario/megamount/run.sh
Normal file
21
test/scenario/megamount/run.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
__sysTmpDir="${TMPDIR:-/tmp}"
|
||||
__sysTmpDir="${__sysTmpDir%/}" # <-- remove trailing slash on macosx
|
||||
|
||||
# Currently I only know how to test a failing condition here since
|
||||
# it's too invasive to create actual mounts to play with on a system
|
||||
|
||||
bash "${__root}/src/megamount.sh" 'foobarfs://janedoe:abc123@192.168.0.1/documents' "${__sysTmpDir}/mnt/documents" || true
|
||||
|
||||
# shellcheck source=src/megamount.sh
|
||||
source "${__root}/src/megamount.sh"
|
||||
|
||||
megamount 'foobarfs://janedoe:abc123@192.168.0.1/documents' "${__sysTmpDir}/mnt/documents"
|
17
test/scenario/parse_url/run.sh
Normal file
17
test/scenario/parse_url/run.sh
Normal file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
bash "${__root}/src/parse_url.sh" 'http://johndoe:abc123@example.com:8080/index.html' pass
|
||||
bash "${__root}/src/parse_url.sh" 'http://johndoe:abc123@example.com:8080/index.html'
|
||||
|
||||
# shellcheck source=src/parse_url.sh
|
||||
source "${__root}/src/parse_url.sh"
|
||||
|
||||
parse_url 'http://johndoe:abc123@example.com:8080/index.html' pass
|
||||
parse_url 'http://johndoe:abc123@example.com:8080/index.html'
|
2
test/scenario/templater/app.template.cfg
Normal file
2
test/scenario/templater/app.template.cfg
Normal file
@ -0,0 +1,2 @@
|
||||
[connection]
|
||||
host = ${TARGET_HOST}
|
3
test/scenario/templater/break.template.cfg
Normal file
3
test/scenario/templater/break.template.cfg
Normal file
@ -0,0 +1,3 @@
|
||||
[connection]
|
||||
host = ${TARGET_HOST}
|
||||
port = ${I_DONT_EXIST}
|
36
test/scenario/templater/run.sh
Normal file
36
test/scenario/templater/run.sh
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o pipefail
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename "${__file}" .sh)"
|
||||
|
||||
__root="$(cd "$(dirname "$(dirname "$(dirname "${__dir}")")")" && pwd)"
|
||||
|
||||
__templaterTmpFile=$(mktemp "${TMPDIR:-/tmp}/${__base}.XXXXXX")
|
||||
function cleanup_before_exit () { rm "${__templaterTmpFile:?}"; }
|
||||
trap cleanup_before_exit EXIT
|
||||
|
||||
echo "--"
|
||||
env TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./app.template.cfg "${__templaterTmpFile}"
|
||||
cat "${__templaterTmpFile}"
|
||||
|
||||
echo "--"
|
||||
export TARGET_HOST="127.0.0.1"
|
||||
|
||||
# shellcheck source=src/templater.sh
|
||||
source "${__root}/src/templater.sh"
|
||||
|
||||
templater ./app.template.cfg "${__templaterTmpFile}"
|
||||
cat "${__templaterTmpFile}"
|
||||
|
||||
echo "--"
|
||||
env ALLOW_REMAINDERS="1" TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./break.template.cfg "${__templaterTmpFile}"
|
||||
cat "${__templaterTmpFile}"
|
||||
|
||||
echo "--"
|
||||
env TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./break.template.cfg "${__templaterTmpFile}"
|
||||
cat "${__templaterTmpFile}"
|
45
test/style.pl
Executable file
45
test/style.pl
Executable file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
die "usage: $0 <file>\n" if (not @ARGV);
|
||||
|
||||
my $rc = 0;
|
||||
my $file = shift;
|
||||
|
||||
open(my $fh, '<', $file) or die "Cannot open \`$file' for read: $!\n";
|
||||
while (<$fh>) {
|
||||
next if (/^\s*#/);
|
||||
|
||||
my $errors = 0;
|
||||
|
||||
# remove everything between single quotes
|
||||
# this will remove too much in case of: echo "var='$var'"
|
||||
# and thus miss an opportunity to complain later on
|
||||
# also it mangles the input line irreversible
|
||||
s/'[^']+'/'___'/g;
|
||||
|
||||
# highlight unbraced variables--
|
||||
# unless properly backslash'ed
|
||||
$errors += s/((?:^|[^\\]))(((\\\\)+)?\$\w)/$1\033[31m$2\033[0m/g;
|
||||
|
||||
# highlight single square brackets
|
||||
$errors += s/((?:^|\s+))\[([^\[].+[^\]])\](\s*(;|&&|\|\|))/$1\033[31m\[\033[0m$2\033[31m\]\033[0m$3/g;
|
||||
|
||||
# highlight double equal sign
|
||||
$errors += s/(\[\[.*)(==)(.*\]\])/$1\033[31m$2\033[0m$3/g;
|
||||
|
||||
# highlight tabs mixed with whitespace at beginning of lines
|
||||
$errors += s/^( *)(\t+ *)/\033[31m\[$2\]\033[0m/;
|
||||
|
||||
# highlight trailing whitespace
|
||||
$errors += s/([ \t]+)$/\033[31m\[$1\]\033[0m/;
|
||||
|
||||
next if (not $errors);
|
||||
print "${file}[$.]: $_";
|
||||
$rc = 1;
|
||||
}
|
||||
close($fh);
|
||||
|
||||
exit $rc;
|
Loading…
x
Reference in New Issue
Block a user