Compare commits
199 Commits
Author | SHA1 | Date | |
---|---|---|---|
884c55c616 | |||
31ee23ba9b | |||
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 |
23
.gitignore
vendored
@ -1,2 +1,25 @@
|
||||
npm-debug.log
|
||||
node_modules
|
||||
|
||||
test/scenario/templater/break.cfg
|
||||
|
||||
website/index.md
|
||||
website/_site/
|
||||
website/_vendor/
|
||||
|
||||
website/changelog.md
|
||||
|
||||
website/faq.md
|
||||
|
||||
website/.jekyll-metadata
|
||||
|
||||
env.sh
|
||||
|
||||
website/main.sh
|
||||
website/assets/build
|
||||
website/.lanyon
|
||||
website/.lanyon/vendor/bin
|
||||
website/.lanyon/bin
|
||||
assets/build
|
||||
.lanyon
|
||||
.lanyon/bin
|
||||
|
49
.travis.yml
@ -1,7 +1,42 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "4.2.1"
|
||||
script: npm run test
|
||||
# For some reason, `sudo: false` broke nvm. Tried this build two times:
|
||||
# https://s3.amazonaws.com/archive.travis-ci.org/jobs/109619626/log.txt
|
||||
sudo: false
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js: 6
|
||||
- os: osx
|
||||
language: node_js
|
||||
node_js: 6
|
||||
env:
|
||||
global:
|
||||
- secure: BeM6mpPEATdeFcAr/222QBZ9vRkZtU2WOi9QQy3mxsuDbWfM8RxYESIEJLipyhW9kXGoe6HGMqm4Kz9B/c4jrzeSXPpKnW7mIfnyqN+hhq1ctW9qPSqodu+fYNhdDxXh5wylml7hnIJzU70vFGrFknZRE2FYk5XvyHg2ImIKDJw=
|
||||
- secure: RJ5UpdXms9QkraylZ11OBfmcRrmKnb254Yj0yCDAvZmg+n+3jSTwMgGvPY8Ih8X/R1JeW3VTtFDkJXXPnjjfpNg1M91u4CAEUOMPciCudYcoF6GKb8psnOzneTTX5M7zuJSzknGdpv/foldxiPYxiY5Hn5bfjmikhAEl+QX/R0Y=
|
||||
- secure: BXf2buPt/DA09M5ZUdp/LpOWtUuz1mfCBopLyxvHv3Sl3ln+Az57wWsM2+Re+77lUOgihR2f6lXYfNUmQuSUo157rZPunQCqM/DJhK69KhREEB6SJDaJF3FVlnGla+Cwwb1IQUtMopqX9pBYD7w/zyWQFJCi20O57JEVIdfZZS8=
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- debian-sid
|
||||
packages:
|
||||
- shellcheck
|
||||
install: npm install # <-- yarn still messes up nested bins: https://github.com/yarnpkg/yarn/issues/760
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then which gsed || brew install gnu-sed; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then which gtimeout || brew install coreutils;
|
||||
fi
|
||||
- bash --version
|
||||
- awk --version
|
||||
before_cache:
|
||||
- rm -f ./node_modules/.bin/which # <-- workaround for https://github.com/travis-ci/travis-ci/issues/5092
|
||||
cache:
|
||||
apt: true
|
||||
directories:
|
||||
- .lanyon
|
||||
script: test/acceptance.sh
|
||||
deploy:
|
||||
skip_cleanup: true
|
||||
provider: script
|
||||
script: website/.lanyon/bin/deploy
|
||||
on:
|
||||
branch: master
|
||||
condition: $TRAVIS_OS_NAME = linux
|
||||
|
98
CHANGELOG.md
Normal file
@ -0,0 +1,98 @@
|
||||
# Changelog
|
||||
|
||||
## master
|
||||
|
||||
Released: Unreleased. [Commit log](https://github.com/kvz/bash3boilerplate/compare/v2.2.0...master)
|
||||
|
||||
## v2.2.0
|
||||
|
||||
Released: 2016-12-21. [Commit log](https://github.com/kvz/bash3boilerplate/compare/v2.1.0...v2.2.0)
|
||||
|
||||
- README and FAQ improvements (#66, @mstreuhofer)
|
||||
- Add support for sourcing b3bp (#61, @mstreuhofer)
|
||||
- Upgrade all Node.js dependencies for development (#78)
|
||||
- Switch to http://lanyon.io for static site building, add a new logo
|
||||
- Cleanup environment variables (#58, @mstreuhofer)
|
||||
- Support multi-line logs (#57, @mstreuhofer)
|
||||
- Run shellcheck as part of the acceptance test (#79, @mstreuhofer)
|
||||
- Brace all variables, used `[[` instead of `[` (#33, #76, @mstreuhofer)
|
||||
- Add automatic usage validation for required args (#22, #65, @mstreuhofer)
|
||||
- Remove all usage of eval (@mstreuhofer)
|
||||
- Get rid of awk, sed & egrep usage (#71, @mstreuhofer)
|
||||
- Fix auto-color-off code (#69, #70, @mstreuhofer)
|
||||
- Use shellcheck to find and fix unclean code (#68, #80, @mstreuhofer)
|
||||
- Allow for multiline opt description in `__usage` (#7, @mstreuhofer)
|
||||
- Allow `__usage` and `__helptext` to be defined before sourcing `main.sh` thus makeing b3bp behave like a library (@mstreuhofer)
|
||||
- Add the same License text to each script header (@mstreuhofer)
|
||||
|
||||
## v2.1.0
|
||||
|
||||
Released: 2016-11-08. [Commit log](https://github.com/kvz/bash3boilerplate/compare/v2.0.0...v2.1.0)
|
||||
|
||||
- Cleanup b3bp variables (adds prefixes across the board) (thanks @mstreuhofer)
|
||||
- Add multi-line logging support (thanks @mstreuhofer)
|
||||
- Mangle long-option names to allow dashes (thanks @zbeekman)
|
||||
- Remove OS detection altogether (#38, thx @zbeekman)
|
||||
- Offer the main template for download as http://bash3boilerplate.sh/main.sh
|
||||
- Better OS detection (#38, thx @moviuro)
|
||||
- Improve README copy (#34, thx galaktos)
|
||||
- Fix unquoted variable access within (#34 thx galaktos)
|
||||
- For delete-key-friendliness, bundle the commandline definition block along with its parser
|
||||
- Less verbose header comments
|
||||
- For delete-key-friendliness, don't crash on undeclared help vars
|
||||
- Introduce `errtrace`, which is on by default (BREAKING)
|
||||
- Add a configurable `helptext` that is left alone by the parses and allows you to have a richer help
|
||||
- Add a simple documentation website
|
||||
- Add best practice of using `__double_underscore_prefixed_vars` to indicate global variables that are solely controlled inside your script
|
||||
- Make license more permissive by not requiring distribution of the LICENSE file if the copyright & attribution comments are left intact
|
||||
- Respect `--no-color` by setting the `NO_COLOR` flag in `main.sh` (#25, thx @gdevenyi)
|
||||
- Split out changelog into separate file
|
||||
- Added a [FAQ](./FAQ.md) (#15, #14, thanks @rouson)
|
||||
- Fix Travis OSX testing (before, it would silently pass failures) (#10)
|
||||
- Enable dashes in long, GNU style options, as well as numbers (thanks @zbeekman)
|
||||
|
||||
## v2.0.0
|
||||
|
||||
Released: 2016-02-17. [Commit log](https://github.com/kvz/bash3boilerplate/compare/v1.2.1...v2.0.0)
|
||||
|
||||
- Add tests for `templater` and follow Library export best practices
|
||||
- Add tests for `ini_val` and follow Library export best practices
|
||||
- Add tests for `parse_url` and follow Library export best practices
|
||||
- Add tests for `megamount` and follow Library export best practices
|
||||
- Remove `bump` from `src` (BREAKING)
|
||||
- Remove `semver` from `src` (BREAKING)
|
||||
|
||||
## v1.2.1
|
||||
|
||||
Released: 2016-02-17. [Commit log](https://github.com/kvz/bash3boilerplate/compare/v1.2.0...v1.2.1)
|
||||
|
||||
- Add Travis CI automated testing for OSX (thanks @zbeekman)
|
||||
|
||||
## v1.2.0
|
||||
|
||||
Released: 2016-02-16. [Commit log](https://github.com/kvz/bash3boilerplate/compare/v1.1.0...v1.2.0)
|
||||
|
||||
- Allow disabling colors via `NO_COLOR` environment variable
|
||||
- Enable `errexit`, `nounset` and `pipefail` options at the top of the script already
|
||||
- More refined colors (thanks @arathai)
|
||||
- Add a changelog to the README
|
||||
- Add `__os` magic var (limited to discovering OSX and defaulting to Linux for now)
|
||||
- Add `__base` magic var (`main`, if the source script is `main.sh`)
|
||||
- Enable long, GNU style options (thanks @zbeekman)
|
||||
- Add Travis CI automated testing for Linux
|
||||
|
||||
## v1.1.0
|
||||
|
||||
Released: 2015-06-29. [Commit log](https://github.com/kvz/bash3boilerplate/compare/v1.0.3...v1.1.0)
|
||||
|
||||
- Add `ALLOW_REMAINDERS` configuration to templater
|
||||
- Fix typo: 'debugmdoe' to 'debugmode' (thanks @jokajak)
|
||||
- Use `${BASH_SOURCE[0]}` for `__file` instead of `${0}`
|
||||
|
||||
## v1.0.3
|
||||
|
||||
Released: 2014-11-02. [Commit log](https://github.com/kvz/bash3boilerplate/compare/5db569125319a89b9561b434db84e4d91faefb63...v1.0.3)
|
||||
|
||||
- Add `ini_val`, `megamount`, `parse_url`
|
||||
- Add re-usable libraries in `./src`
|
||||
- Use npm as an additional distribution channel
|
174
FAQ.md
Normal file
@ -0,0 +1,174 @@
|
||||
[This document is formatted with GitHub-Flavored Markdown. ]:#
|
||||
[For better viewing, including hyperlinks, read it online at ]:#
|
||||
[https://github.com/kvz/bash3boilerplate/blob/master/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)?
|
||||
* [How can I locally develop and preview the b3bp website](#how-can-i-locally-develop-and-preview-the-b3bp-website)?
|
||||
* [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)?
|
||||
|
||||
<!--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 master 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".
|
||||
|
||||
## How can I locally develop and preview the b3bp website?
|
||||
|
||||
You should have a working Node.js >=10 and Ruby >=2 install on your workstation. When that is the case, you can run:
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
```
|
||||
|
||||
This will install and start all required services and automatically open a webbrowser that reloads as soon as you make any changes to the source.
|
||||
|
||||
The source mainly consists of:
|
||||
|
||||
- `./README.md` (Front page)
|
||||
- `./FAQ.md` (FAQ page)
|
||||
- `./CHANGELOG.md` (changelog page)
|
||||
- `./website/_layouts/default.html` (the design in which all pages are rendered)
|
||||
- `./website/assets/app.js` (main JS file)
|
||||
- `./website/assets/style.css` (main CSS file)
|
||||
|
||||
The rest is dark magic from which you should probably steer clear. : )
|
||||
|
||||
Any changes should be proposed as PRs. Anything added to `master` is automatically deployed using a combination of Travis CI and GitHub Pages.
|
||||
|
||||
## 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.
|
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.
|
||||
|
174
README.md
@ -1,96 +1,104 @@
|
||||
[](https://travis-ci.org/kvz/bash3boilerplate)
|
||||
|
||||
When hacking up BASH scripts, I often find there are some
|
||||
higher level things like logging, configuration, command-line argument
|
||||
parsing that:
|
||||
[This document is formatted with GitHub-Flavored Markdown. ]:#
|
||||
[For better viewing, including hyperlinks, read it online at ]:#
|
||||
[https://github.com/kvz/bash3boilerplate/blob/master/README.md]:#
|
||||
|
||||
- I need every time
|
||||
- Take quite some effort to get right
|
||||
* [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)
|
||||
|
||||
## Overview
|
||||
|
||||
<!--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.
|
||||
|
||||
We call it "BASH3 Boilerplate" or b3bp for short.
|
||||
|
||||
## Goals
|
||||
|
||||
Delete-key-friendly. I propose people use `main.sh` as a base and remove the
|
||||
parts they don't need, rather than introducing a ton of packages, includes, compilers, etc.
|
||||
Delete-Key-**Friendly**. Instead of introducing packages, includes, compilers, etc., we propose using [`main.sh`](http://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.
|
||||
|
||||
Aiming for portability, I'm targeting Bash 3 (OSX still ships
|
||||
with 3 for instance). If you're going to ask people to install
|
||||
**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
|
||||
|
||||
- Structure
|
||||
- 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
|
||||
- Configuration by command-line arguments (definitions parsed from help info,
|
||||
so no duplication needed)
|
||||
- Magic variables like `__file` and `__dir`
|
||||
- Logging that supports colors and is compatible with [Syslog Severity levels](http://en.wikipedia.org/wiki/Syslog#Severity_levels)
|
||||
- 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](http://en.wikipedia.org/wiki/Syslog#Severity_levels), as well as the [twelve-factor](http://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 http://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:
|
||||
|
||||
For more information on SemVer, please visit [http://semver.org](http://semver.org).
|
||||
```bash
|
||||
npm init
|
||||
npm install --save --save-exact bash3boilerplate
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
### v1.2.0 (Unreleased)
|
||||
Please see the [CHANGELOG.md](./CHANGELOG.md) file.
|
||||
|
||||
- Allow disabling colors via `NO_COLOR` environment variable
|
||||
- Enable errexit, nounset and pipefail at the top
|
||||
- More refined colors (thanks @arathai)
|
||||
- Add Changelog
|
||||
- Add `__os` magic var
|
||||
- Add `__base` magic var
|
||||
- Enable long, GNU style options (thanks @zbeekman)
|
||||
## Frequently Asked Questions
|
||||
|
||||
### v1.1.0 (2015-06-29)
|
||||
|
||||
- Add `ALLOW_REMAINDERS` configuration to templater
|
||||
- Fix typo: 'debugmdoe' to 'debugmode' (thanks @jokajak)
|
||||
- Use `${BASH_SOURCE[0]}` for `__file` instead of `${0}`
|
||||
|
||||
### v1.0.3 (2014-11-02)
|
||||
|
||||
- Add `ini_val`, `megamount`, `parse_url`
|
||||
- Add re-usable libraries in `./src`
|
||||
- Use npm for distribution
|
||||
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
|
||||
if [ "${BASH_SOURCE[0]}" != "${0}" ]; then
|
||||
export -f my_script
|
||||
else
|
||||
my_script "${@}"
|
||||
@ -98,7 +106,7 @@ else
|
||||
fi
|
||||
```
|
||||
|
||||
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
|
||||
@ -110,22 +118,52 @@ $ my_script some more args --blah
|
||||
|
||||
(taken from the [bpkg](https://raw.githubusercontent.com/bpkg/bpkg/master/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.
|
||||
|
||||
## Sponsoring
|
||||
### Coding style
|
||||
|
||||
<!-- badges/ -->
|
||||
[](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 -->
|
||||
1. Use two spaces for tabs.
|
||||
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.
|
||||
|
||||
### 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](http://www.opencoarrays.org)
|
||||
- [Sourcery Institute](http://www.sourceryinstitute.org)
|
||||
- [Computational Brain Anatomy Laboratory](http://cobralab.ca/)
|
||||
|
||||
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](http://kvz.io)
|
||||
- [Izaak Beekman](https://izaakbeekman.com/)
|
||||
- [Manuel Streuhofer](https://github.com/mstreuhofer)
|
||||
- [Alexander Rathai](mailto:Alexander.Rathai@gmail.com)
|
||||
- [Dr. Damian Rouson](http://www.sourceryinstitute.org/) (documentation, feedback)
|
||||
- [@jokajak](https://github.com/jokajak) (documentation)
|
||||
- [Gabriel A. Devenyi](http://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)
|
||||
|
||||
## 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/master/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.
|
||||
|
111
example.sh
Executable file
@ -0,0 +1,111 @@
|
||||
#!/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.2.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)
|
||||
|
||||
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
|
||||
EOF
|
||||
|
||||
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"
|
||||
|
||||
|
||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
|
||||
##############################################################################
|
||||
|
||||
# debug mode
|
||||
if [[ "${arg_d:?}" = "1" ]]; then
|
||||
set -o xtrace
|
||||
LOG_LEVEL="7"
|
||||
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
|
||||
##############################################################################
|
||||
|
||||
function cleanup_before_exit () {
|
||||
info "Cleaning up. Done"
|
||||
}
|
||||
trap cleanup_before_exit EXIT
|
||||
|
||||
info "__file: ${__file}"
|
||||
info "__dir: ${__dir}"
|
||||
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}"
|
||||
|
||||
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"
|
||||
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."
|
499
main.sh
@ -1,239 +1,360 @@
|
||||
#!/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.2.0
|
||||
#
|
||||
# Authors:
|
||||
# - Kevin van Zonneveld (http://kvz.io)
|
||||
# - Izaak Beekman (https://izaakbeekman.com/)
|
||||
# - Alexander Rathai (Alexander.Rathai@gmail.com)
|
||||
# - 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 v2.2.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.
|
||||
|
||||
|
||||
### Configuration
|
||||
#####################################################################
|
||||
|
||||
# Exit on error. Append ||true if you expect an error.
|
||||
# `set` is safer than relying on a shebang like `#!/bin/bash -e` because that is neutralized
|
||||
# when someone runs your script as `bash yourscript.sh`
|
||||
# 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
|
||||
|
||||
# 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`
|
||||
# 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
|
||||
|
||||
# Environment variables and their defaults
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
if [[ "${__usage+x}" ]]; then
|
||||
__b3bp_external_usage="true"
|
||||
__b3bp_tmp_source_idx=1
|
||||
fi
|
||||
else
|
||||
[[ "${__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)"
|
||||
|
||||
# Define the environment variables (and their defaults) that this script depends on
|
||||
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
|
||||
NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected
|
||||
|
||||
|
||||
### Functions
|
||||
##############################################################################
|
||||
|
||||
function __b3bp_log () {
|
||||
local log_level="${1}"
|
||||
shift
|
||||
|
||||
# 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;33;41m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_emergency="\x1b[1;4;5;33;41m"
|
||||
|
||||
local colorvar="color_${log_level}"
|
||||
|
||||
local color="${!colorvar:-${color_error}}"
|
||||
local color_reset="\x1b[0m"
|
||||
|
||||
if [[ "${NO_COLOR:-}" = "true" ]] || [[ "${TERM:-}" != "xterm"* ]] || [[ ! -t 2 ]]; then
|
||||
if [[ "${NO_COLOR:-}" != "false" ]]; then
|
||||
# Don't use colors on pipes or non-recognized terminals
|
||||
color=""; color_reset=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# 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 () { __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 " ${__usage:-No usage available}" 1>&2
|
||||
echo "" 1>&2
|
||||
|
||||
if [[ "${__helptext:-}" ]]; then
|
||||
echo " ${__helptext}" 1>&2
|
||||
echo "" 1>&2
|
||||
fi
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
### 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
|
||||
read -r -d '' usage <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
# - 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
|
||||
EOF
|
||||
|
||||
# Set magic variables for current file and its directory.
|
||||
# BASH_SOURCE[0] is used so we can display the current file even if it is sourced by a parent script.
|
||||
# If you need the script that was executed, consider using $0 instead.
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
__os="Linux"
|
||||
if [[ "${OSTYPE:-}" == "darwin"* ]]; then
|
||||
__os="OSX"
|
||||
# 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 -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}"
|
||||
|
||||
# fetch long version if present
|
||||
__b3bp_tmp_long_opt=""
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" = *"--"* ]]; then
|
||||
__b3bp_tmp_long_opt="${__b3bp_tmp_line#*--}"
|
||||
__b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
|
||||
fi
|
||||
|
||||
# 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}"
|
||||
fi
|
||||
|
||||
[[ "${__b3bp_tmp_opt:-}" ]] || continue
|
||||
|
||||
if [[ "${__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
|
||||
__b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
|
||||
__b3bp_tmp_re='^"(.*)"$'
|
||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
else
|
||||
__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\. ]]; then
|
||||
# remember that this option requires an argument
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||
fi
|
||||
|
||||
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}"
|
||||
printf -v "OPTARG" '%s' "${@:OPTIND:${!__b3bp_tmp_varname}}"
|
||||
# shift over the argument if argument is expected
|
||||
((OPTIND+=__b3bp_tmp_has_arg_${__b3bp_tmp_opt}))
|
||||
fi
|
||||
# we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
|
||||
fi
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
|
||||
__b3bp_tmp_default="${!__b3bp_tmp_varname}"
|
||||
|
||||
__b3bp_tmp_value="${OPTARG}"
|
||||
if [[ -z "${OPTARG}" ]] && [[ "${__b3bp_tmp_default}" = "0" ]]; then
|
||||
__b3bp_tmp_value="1"
|
||||
fi
|
||||
|
||||
printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
|
||||
debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
|
||||
done
|
||||
set -o nounset # no more unbound variable references expected
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
[[ "${1:-}" = "--" ]] && shift
|
||||
fi
|
||||
|
||||
### Functions
|
||||
#####################################################################
|
||||
|
||||
function _fmt () {
|
||||
local color_debug="\x1b[35m"
|
||||
local color_info="\x1b[32m"
|
||||
local color_notice="\x1b[34m"
|
||||
local color_warning="\x1b[33m"
|
||||
local color_error="\x1b[31m"
|
||||
local color_critical="\x1b[1;31m"
|
||||
local color_alert="\x1b[1;33;41m"
|
||||
local color_emergency="\x1b[1;4;5;33;41m"
|
||||
local colorvar=color_$1
|
||||
### Automatic validation of required option arguments
|
||||
##############################################################################
|
||||
|
||||
local color="${!colorvar:-$color_error}"
|
||||
local color_reset="\x1b[0m"
|
||||
if [ "${NO_COLOR}" = "true" ] || [[ "${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}";
|
||||
}
|
||||
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; }
|
||||
for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do
|
||||
# validate only options which required an argument
|
||||
[[ "${!__b3bp_tmp_varname}" = "2" ]] || continue
|
||||
|
||||
function help () {
|
||||
echo "" 1>&2
|
||||
echo " ${@}" 1>&2
|
||||
echo "" 1>&2
|
||||
echo " ${usage}" 1>&2
|
||||
echo "" 1>&2
|
||||
exit 1
|
||||
}
|
||||
__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
|
||||
|
||||
|
||||
### Cleanup Environment variables
|
||||
##############################################################################
|
||||
|
||||
for __tmp_varname in ${!__b3bp_tmp_*}; do
|
||||
unset -v "${__tmp_varname}"
|
||||
done
|
||||
|
||||
unset -v __tmp_varname
|
||||
|
||||
|
||||
### Externally supplied __usage. Nothing else to do here
|
||||
##############################################################################
|
||||
|
||||
if [[ "${__b3bp_external_usage:-}" = "true" ]]; then
|
||||
unset -v __b3bp_external_usage
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
|
||||
##############################################################################
|
||||
|
||||
# debug mode
|
||||
if [[ "${arg_d:?}" = "1" ]]; then
|
||||
set -o xtrace
|
||||
LOG_LEVEL="7"
|
||||
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
|
||||
##############################################################################
|
||||
|
||||
function cleanup_before_exit () {
|
||||
info "Cleaning up. Done"
|
||||
}
|
||||
trap cleanup_before_exit EXIT
|
||||
|
||||
|
||||
### Parse commandline options
|
||||
#####################################################################
|
||||
|
||||
# Translate usage string -> getopts arguments, and set $arg_<flag> defaults
|
||||
while read line; do
|
||||
# fetch single character version of option sting
|
||||
opt="$(echo "${line}" |awk '{print $1}' |sed -e 's#^-##')"
|
||||
|
||||
# fetch long version if present
|
||||
long_opt="$(echo "${line}" |awk '/\-\-/ {print $2}' |sed -e 's#^--##')"
|
||||
|
||||
# map long name back to short name
|
||||
varname="short_opt_${long_opt}"
|
||||
eval "${varname}=\"${opt}\""
|
||||
|
||||
# check if option takes an argument
|
||||
varname="has_arg_${opt}"
|
||||
if ! echo "${line}" |egrep '\[.*\]' >/dev/null 2>&1; then
|
||||
init="0" # it's a flag. init with 0
|
||||
eval "${varname}=0"
|
||||
else
|
||||
opt="${opt}:" # add : if opt has arg
|
||||
init="" # it has an arg. init with ""
|
||||
eval "${varname}=1"
|
||||
fi
|
||||
opts="${opts:-}${opt}"
|
||||
|
||||
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}"
|
||||
|
||||
# Allow long options like --this
|
||||
opts="${opts}-:"
|
||||
|
||||
# Reset in case getopts has been used previously in the shell.
|
||||
OPTIND=1
|
||||
|
||||
# Overwrite $arg_<flag> defaults with the actual CLI options
|
||||
while getopts "${opts}" opt; do
|
||||
[ "${opt}" = "?" ] && help "Invalid use of script: ${@} "
|
||||
|
||||
if [ "${opt}" = "-" ]; then
|
||||
# OPTARG is long-option-name or long-option=value
|
||||
if [[ "${OPTARG}" =~ .*=.* ]]; then
|
||||
# --key=value format
|
||||
long=${OPTARG/=*/}
|
||||
# Set opt to the short option corresponding to the long option
|
||||
eval "opt=\"\${short_opt_${long}}\""
|
||||
OPTARG=${OPTARG#*=}
|
||||
else
|
||||
# --key value format
|
||||
# Map long name to short version of option
|
||||
eval "opt=\"\${short_opt_${OPTARG}}\""
|
||||
# Only assign OPTARG if option takes an argument
|
||||
eval "OPTARG=\"\${@:OPTIND:\${has_arg_${opt}}}\""
|
||||
# shift over the argument if argument is expected
|
||||
((OPTIND+=has_arg_${opt}))
|
||||
fi
|
||||
# we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
|
||||
fi
|
||||
varname="arg_${opt:0:1}"
|
||||
default="${!varname}"
|
||||
|
||||
value="${OPTARG:-}"
|
||||
if [ -z "${OPTARG:-}" ] && [ "${default}" = "0" ]; then
|
||||
value="1"
|
||||
fi
|
||||
|
||||
eval "${varname}=\"${value}\""
|
||||
debug "cli arg ${varname} = ($default) -> ${!varname}"
|
||||
done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
[ "${1:-}" = "--" ] && shift
|
||||
|
||||
|
||||
### Switches (like -d for debugmode, -h for showing helppage)
|
||||
#####################################################################
|
||||
|
||||
# debug mode
|
||||
if [ "${arg_d}" = "1" ]; then
|
||||
set -o xtrace
|
||||
LOG_LEVEL="7"
|
||||
fi
|
||||
|
||||
# verbose mode
|
||||
if [ "${arg_v}" = "1" ]; then
|
||||
set -o verbose
|
||||
fi
|
||||
|
||||
# help mode
|
||||
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)
|
||||
#####################################################################
|
||||
|
||||
[ -z "${arg_f:-}" ] && help "Setting a filename with -f or --file is required"
|
||||
[ -z "${LOG_LEVEL:-}" ] && emergency "Cannot continue without LOG_LEVEL. "
|
||||
|
||||
|
||||
### Runtime
|
||||
#####################################################################
|
||||
|
||||
info "__file: ${__file}"
|
||||
info "__dir: ${__dir}"
|
||||
info "__base: ${__base}"
|
||||
info "__os: ${__os}"
|
||||
info "OSTYPE: ${OSTYPE}"
|
||||
|
||||
info "arg_f: ${arg_f}"
|
||||
info "arg_d: ${arg_d}"
|
||||
info "arg_v: ${arg_v}"
|
||||
info "arg_h: ${arg_h}"
|
||||
|
||||
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."
|
||||
|
40
package.json
@ -1,19 +1,47 @@
|
||||
{
|
||||
"name": "bash3boilerplate",
|
||||
"description": "Copypastable templates to write better bash scripts",
|
||||
"version": "1.2.0",
|
||||
"version": "2.2.0",
|
||||
"scripts": {
|
||||
"build:production": "LANYON_ENV=production lanyon build",
|
||||
"build": "lanyon build",
|
||||
"deploy": "lanyon deploy",
|
||||
"encrypt": "lanyon encrypt",
|
||||
"install": "lanyon postinstall",
|
||||
"lint": "shellcheck --shell=bash $(find . -name '*.sh' -maxdepth 2)",
|
||||
"release:major": "env SEMANTIC=major npm run release",
|
||||
"release:minor": "env SEMANTIC=minor npm run release",
|
||||
"release:patch": "env SEMANTIC=patch npm run release",
|
||||
"test": "test/acceptance.sh",
|
||||
"release": "npm version ${SEMANTIC:-patch} -m \"Release %s\" && npm run version:replace && git commit main.sh src/*.sh -m 'Update version' && git push && git push --tags && npm publish",
|
||||
"save:fixtures": "cross-env SAVE_FIXTURES=true npm run test",
|
||||
"release": "npm version ${SEMANTIC:-patch} -m \"Release %s\" && git push --tags && npm publish"
|
||||
"serve:production": "LANYON_ENV=production lanyon serve",
|
||||
"start:production": "npm-run-all build:production serve:production",
|
||||
"start": "lanyon start",
|
||||
"test": "test/acceptance.sh",
|
||||
"upgrade:modules": "next-update --keep true --tldr",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"fakefile": "0.0.6"
|
||||
"lanyon": {
|
||||
"projectDir": "website",
|
||||
"prebuild": "./_scripts/inject.sh",
|
||||
"contentScandir": "../",
|
||||
"contentIgnore": [
|
||||
"website/*.md",
|
||||
"website/main.sh"
|
||||
]
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "*"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"cross-env": "1.0.7"
|
||||
"browser-sync": "2.18.5",
|
||||
"cross-env": "3.1.3",
|
||||
"fakefile": "0.0.8",
|
||||
"lanyon": "0.0.47",
|
||||
"next-update": "1.5.1",
|
||||
"npm-run-all": "3.1.2",
|
||||
"replace": "^0.3.0"
|
||||
}
|
||||
}
|
||||
|
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
|
@ -1,20 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# BASH3 Boilerplate: ini_val
|
||||
#
|
||||
# This file:
|
||||
#
|
||||
# - Can read and write .ini files using pure bash
|
||||
#
|
||||
# Limitations:
|
||||
#
|
||||
# - All keys inside the .ini file must be unique, regardless of the use of sections
|
||||
#
|
||||
# Usage as a function:
|
||||
#
|
||||
# source ini_val.sh
|
||||
# ini_val data.ini connection.host 127.0.0.1
|
||||
#
|
||||
# Usage as a command:
|
||||
#
|
||||
# ini_val.sh data.ini connection.host 127.0.0.1
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate v2.1.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.
|
||||
|
||||
function ini_val() {
|
||||
local file="${1}"
|
||||
local sectionkey="${2}"
|
||||
local val="${3}"
|
||||
local file="${1:-}"
|
||||
local sectionkey="${2:-}"
|
||||
local val="${3:-}"
|
||||
local delim=" = "
|
||||
local section=""
|
||||
local key=""
|
||||
|
||||
# Split on . for section. However, section is optional
|
||||
read section key <<<$(IFS="."; echo ${sectionkey})
|
||||
IFS='.' read -r section key <<< "${sectionkey}"
|
||||
if [ -z "${key}" ]; then
|
||||
key="${section}"
|
||||
section=""
|
||||
fi
|
||||
|
||||
local current=$(awk -F"${delim}" "/^${key}${delim}/ {for (i=2; i<NF; i++) printf \$i \" \"; print \$NF}" "${file}")
|
||||
local current
|
||||
current=$(awk -F "${delim}" "/^${key}${delim}/ {for (i=2; i<NF; i++) printf \$i \" \"; print \$NF}" "${file}")
|
||||
|
||||
if [ -z "${val}" ]; then
|
||||
# get a value
|
||||
echo "${current}"
|
||||
@ -28,11 +57,22 @@ function ini_val() {
|
||||
echo "${key}${delim}${val}" >> "${file}"
|
||||
else
|
||||
# add to section
|
||||
sed "/\[${section}\]/a ${key}${delim}${val}" -i "${file}"
|
||||
sed -i.bak -e "/\[${section}\]/a ${key}${delim}${val}" "${file}"
|
||||
# this .bak dance is done for BSD/GNU portability: http://stackoverflow.com/a/22084103/151666
|
||||
rm -f "${file}.bak"
|
||||
fi
|
||||
else
|
||||
# replace existing
|
||||
sed "/^${key}${delim}/s/${delim}.*/${delim}${val}/" -i "${file}"
|
||||
sed -i.bak -e "/^${key}${delim}/s/${delim}.*/${delim}${val}/" "${file}"
|
||||
# this .bak dance is done for BSD/GNU portability: http://stackoverflow.com/a/22084103/151666
|
||||
rm -f "${file}.bak"
|
||||
fi
|
||||
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
|
||||
# - Forceully unmounts any active mount at the target directory first
|
||||
# - Displays the mounts 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 v2.1.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.
|
||||
|
||||
__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,7 +51,7 @@ 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
|
||||
mount -t cifs --verbose -o "username=${user},password=${pass},hard" "//${host}/${path}" "${target}"
|
||||
@ -21,12 +60,19 @@ function megamount () {
|
||||
# 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}
|
||||
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,18 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
function parse_url() {
|
||||
# Based on http://stackoverflow.com/a/6174447/151666
|
||||
local parse="${1}"
|
||||
local need="${2}"
|
||||
# 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 v2.1.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.
|
||||
|
||||
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-)"
|
||||
function parse_url() {
|
||||
local parse="${1}"
|
||||
local need="${2:-}"
|
||||
|
||||
local proto
|
||||
local url
|
||||
local userpass
|
||||
local user
|
||||
local pass
|
||||
local hostport
|
||||
local host
|
||||
local port
|
||||
local path
|
||||
|
||||
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-)"
|
||||
|
||||
[ -z "${user}" ] && user="${userpass}"
|
||||
[ -z "${host}" ] && host="${hostport}"
|
||||
@ -24,7 +60,7 @@ function parse_url() {
|
||||
fi
|
||||
|
||||
if [ -n "${need}" ]; then
|
||||
echo ${!need}
|
||||
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
@ -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,63 @@
|
||||
#!/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 v2.1.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.
|
||||
|
||||
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 [ ! -n "${templateDst}" ]; then
|
||||
echo "ERROR: Template destination '${templateDst}' needs to be specified"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
templateSrc="${1}"
|
||||
templateDst="${2}"
|
||||
cp -f "${templateSrc}" "${templateDst}"
|
||||
for var in $(env |awk -F= '{print $1}' |egrep '^[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
|
||||
|
||||
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
|
||||
# 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
|
||||
|
@ -1,65 +1,94 @@
|
||||
#!/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.
|
||||
|
||||
set -o pipefail
|
||||
# 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 & DIR
|
||||
# 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)"
|
||||
__base="$(basename "${__file}" .sh)"
|
||||
__root="$(cd "$(dirname "${__dir}")" && pwd)"
|
||||
|
||||
scenarios="${1:-$(ls ${__dir}/scenario/|egrep -v ^prepare$)}"
|
||||
|
||||
__sysTmpDir="${TMPDIR:-/tmp}"
|
||||
__sysTmpDir="${__sysTmpDir%/}" # <-- remove trailing slash on macosx
|
||||
__b3bpTmpDir="${__sysTmpDir}/b3bp"
|
||||
mkdir -p "${__b3bpTmpDir}"
|
||||
__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
|
||||
else
|
||||
cmdSed=sed
|
||||
cmdTimeout=gtimeout
|
||||
fi
|
||||
|
||||
if [[ "${OSTYPE}" == "darwin"* ]]; then
|
||||
cmdTimeout="gtimeout --kill-after=6m 5m"
|
||||
else
|
||||
cmdTimeout="timeout --kill-after=6m 5m"
|
||||
fi
|
||||
|
||||
__node="$(which node)"
|
||||
|
||||
__os="linux"
|
||||
if [[ "${OSTYPE}" == "darwin"* ]]; then
|
||||
__os="darwin"
|
||||
fi
|
||||
__arch="amd64"
|
||||
|
||||
|
||||
if ! which "${cmdSed}" > /dev/null; then
|
||||
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="$(which node)"
|
||||
__arch="amd64"
|
||||
|
||||
# explicitly setting NO_COLOR to false will make b3bp ignore TERM
|
||||
# not being "xterm*" 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.
|
||||
for scenario in $(echo ${scenarios}); do
|
||||
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} bash ./run.sh \
|
||||
> "${__b3bpTmpDir}/${scenario}.stdio" 2>&1; \
|
||||
echo "${?}" > "${__b3bpTmpDir}/${scenario}.exitcode" \
|
||||
(${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 $(echo stdio exitcode); do
|
||||
curFile="${__b3bpTmpDir}/${scenario}.${typ}"
|
||||
for typ in stdio exitcode; do
|
||||
curFile="${__accptstTmpDir}/${scenario}.${typ}"
|
||||
"${cmdSed}" -i \
|
||||
-e "s@${__node}@{node}@g" "${curFile}" \
|
||||
-e "s@${__root}@{root}@g" "${curFile}" \
|
||||
@ -72,13 +101,13 @@ for scenario in $(echo ${scenarios}); do
|
||||
-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@${__os}@{os}@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 [ "$(cat "${curFile}" |grep 'B3BP:STDIO_REPLACE_IPS' |wc -l)" -gt 0 ]; then
|
||||
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}"
|
||||
@ -89,45 +118,45 @@ for scenario in $(echo ${scenarios}); do
|
||||
-r 's@\{ip\}\s+@{ip} @g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if [ "$(cat "${curFile}" |grep 'B3BP:STDIO_REPLACE_UUIDS' |wc -l)" -gt 0 ]; then
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_UUIDS' "${curFile}"; then
|
||||
"${cmdSed}" -i \
|
||||
-r 's@[0-9a-f\-]{32,40}@{uuid}@g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if [ "$(cat "${curFile}" |grep 'B3BP:STDIO_REPLACE_BIGINTS' |wc -l)" -gt 0 ]; then
|
||||
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 [ "$(cat "${curFile}" |grep 'B3BP:STDIO_REPLACE_DATETIMES' |wc -l)" -gt 0 ]; then
|
||||
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 [ "$(cat "${curFile}" |grep 'B3BP:STDIO_REPLACE_LONGTIMES' |wc -l)" -gt 0 ]; then
|
||||
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 [ "$(cat "${curFile}" |grep 'B3BP:STDIO_REPLACE_DURATIONS' |wc -l)" -gt 0 ]; then
|
||||
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 [ "$(cat "${curFile}" |grep 'B3BP:STDIO_REPLACE_REMOTE_EXEC' |wc -l)" -gt 0 ]; then
|
||||
egrep -v 'remote-exec\): [ a-zA-Z]' "${curFile}" > "${__sysTmpDir}/b3bp-filtered.txt"
|
||||
mv "${__sysTmpDir}/b3bp-filtered.txt" "${curFile}"
|
||||
if grep -q 'ACCPTST:STDIO_REPLACE_REMOTE_EXEC' "${curFile}"; then
|
||||
egrep -v '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 $(echo stdio exitcode); do
|
||||
curFile="${__b3bpTmpDir}/${scenario}.${typ}"
|
||||
if [[ "${SAVE_FIXTURES:-}" = "true" ]]; then
|
||||
for typ in stdio exitcode; do
|
||||
curFile="${__accptstTmpDir}/${scenario}.${typ}"
|
||||
cp -f \
|
||||
"${curFile}" \
|
||||
"${__dir}/fixture/${scenario}.${typ}"
|
||||
@ -135,32 +164,63 @@ for scenario in $(echo ${scenarios}); do
|
||||
fi
|
||||
|
||||
# Compare
|
||||
for typ in $(echo stdio exitcode); do
|
||||
curFile="${__b3bpTmpDir}/${scenario}.${typ}"
|
||||
for typ in stdio exitcode; do
|
||||
curFile="${__accptstTmpDir}/${scenario}.${typ}"
|
||||
|
||||
echo -n " comparing ${typ}.. "
|
||||
|
||||
if [ "${typ}" = "stdio" ]; then
|
||||
if [ "$(cat "${curFile}" |grep 'B3BP:STDIO_SKIP_COMPARE' |wc -l)" -gt 0 ]; then
|
||||
if [[ "${typ}" = "stdio" ]]; then
|
||||
if grep -q 'ACCPTST:STDIO_SKIP_COMPARE' "${curFile}"; then
|
||||
echo "skip"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
diff \
|
||||
--strip-trailing-cr \
|
||||
"${__dir}/fixture/${scenario}.${typ}" \
|
||||
"${curFile}" || ( \
|
||||
echo -e "\n\n==> MISMATCH OF: ${typ}";
|
||||
echo -e "\n\n==> EXPECTED STDIO: ";
|
||||
cat "${__dir}/fixture/${scenario}.stdio";
|
||||
echo -e "\n\n==> ACTUAL STDIO: ";
|
||||
cat "${__b3bpTmpDir}/${scenario}.stdio";
|
||||
exit 1; \
|
||||
)
|
||||
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
|
||||
done <<< "$(find "${__dir}/scenario" -type f -iname 'run.sh')"
|
||||
|
||||
[[ "${1:-}" ]] && exit 0
|
||||
|
||||
# finally do some shellcheck linting
|
||||
if [[ "$(command -v shellcheck)" ]]; then
|
||||
echo "==> Shellcheck"
|
||||
pushd "${__root}" > /dev/null
|
||||
|
||||
failed="false"
|
||||
|
||||
while IFS=$'\n' read -r file; do
|
||||
[[ "${file}" =~ ^\./node_modules/ ]] && continue
|
||||
[[ "${file}" =~ ^\./website/\.lanyon/ ]] && continue
|
||||
|
||||
echo -n " ${file}.. "
|
||||
|
||||
if ! shellcheck --shell=bash --external-sources "${file}" >> "${__accptstTmpDir}/shellcheck.err"; then
|
||||
echo "✗"
|
||||
failed="true"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "✓"
|
||||
done <<< "$(find . -type f -iname '*.sh')"
|
||||
|
||||
popd > /dev/null
|
||||
|
||||
if [[ "${failed}" = "true" ]]; then
|
||||
cat "${__accptstTmpDir}/shellcheck.err"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
@ -1,11 +0,0 @@
|
||||
B3BP: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
|
||||
|
||||
{datetime} UTC [32m[ info][0m Cleaning up. Done
|
24
test/fixture/ini_val.stdio
Normal file
@ -0,0 +1,24 @@
|
||||
--> command: Read 3 values
|
||||
exists
|
||||
127.0.0.1
|
||||
nginx, nodejs
|
||||
--> command: Replace three values in-place and show result
|
||||
orphan = no more
|
||||
|
||||
[connection]
|
||||
host = 192.168.0.1
|
||||
|
||||
[software]
|
||||
packages = vim
|
||||
--> function: Read 3 values
|
||||
exists
|
||||
127.0.0.1
|
||||
nginx, nodejs
|
||||
--> function: Replace three values in-place and show result
|
||||
orphan = no more
|
||||
|
||||
[connection]
|
||||
host = 192.168.0.1
|
||||
|
||||
[software]
|
||||
packages = vim
|
@ -1,13 +1,16 @@
|
||||
B3BP:STDIO_REPLACE_DATETIMES
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [35m[ debug][0m cli arg arg_f = () -> {tmpdir}/x
|
||||
{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 __os: {os}
|
||||
{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 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.
|
16
test/fixture/main-help.stdio
Normal file
@ -0,0 +1,16 @@
|
||||
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
|
||||
|
||||
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.
|
||||
|
1
test/fixture/main-longopt.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
@ -1,4 +1,4 @@
|
||||
B3BP:STDIO_REPLACE_DATETIMES
|
||||
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,13 +1,16 @@
|
||||
B3BP:STDIO_REPLACE_DATETIMES
|
||||
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [ debug] cli arg arg_f = () -> {tmpdir}/x
|
||||
{datetime} UTC [ info] __file: {root}/main.sh
|
||||
{datetime} UTC [ info] __dir: {root}
|
||||
{datetime} UTC [ info] __base: main
|
||||
{datetime} UTC [ info] __os: {os}
|
||||
{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] 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.
|
1
test/fixture/main-usage-defaults.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
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
@ -0,0 +1 @@
|
||||
0
|
155
test/fixture/main-usage-validation.stdio
Normal file
@ -0,0 +1,155 @@
|
||||
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
|
1
test/fixture/megamount.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
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
@ -0,0 +1 @@
|
||||
0
|
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
@ -0,0 +1 @@
|
||||
1
|
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
|
@ -1,15 +0,0 @@
|
||||
#!/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)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
__root="$(cd "$(dirname $(dirname $(dirname "${__dir}")))" && pwd)"
|
||||
|
||||
echo "B3BP:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
env LOG_LEVEL=8 bash "${__root}/main.sh" -f /tmp/x
|
@ -1,15 +0,0 @@
|
||||
#!/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)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
__root="$(cd "$(dirname $(dirname $(dirname "${__dir}")))" && pwd)"
|
||||
|
||||
echo "B3BP:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
bash "${__root}/main.sh" -h
|
7
test/scenario/ini_val/data.ini
Normal file
@ -0,0 +1,7 @@
|
||||
orphan = exists
|
||||
|
||||
[connection]
|
||||
host = 127.0.0.1
|
||||
|
||||
[software]
|
||||
packages = nginx, nodejs
|
46
test/scenario/ini_val/run.sh
Normal file
@ -0,0 +1,46 @@
|
||||
#!/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)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename "${__file}" .sh)"
|
||||
__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
|
||||
|
||||
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"
|
||||
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
|
||||
|
||||
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"
|
||||
cat dummy.ini
|
||||
rm -f dummy.ini
|
@ -1,17 +0,0 @@
|
||||
#!/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)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
__root="$(cd "$(dirname $(dirname $(dirname "${__dir}")))" && pwd)"
|
||||
|
||||
echo "B3BP: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-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=8 bash "${__root}/main.sh" -f /tmp/x
|
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
@ -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
@ -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=8 NO_COLOR=true bash "${__root}/main.sh" -f /tmp/x
|
30
test/scenario/main-usage-defaults/run.sh
Executable file
@ -0,0 +1,30 @@
|
||||
#!/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
|
||||
|
||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
# shellcheck source=main.sh
|
||||
source "${__root}/main.sh"
|
||||
|
||||
for argument in ${!arg_*}; do info "${argument}: ${!argument}"; done
|
58
test/scenario/main-usage-validation/run.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/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
|
||||
)
|
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"
|
@ -1,15 +0,0 @@
|
||||
#!/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)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
__root="$(cd "$(dirname $(dirname $(dirname "${__dir}")))" && pwd)"
|
||||
|
||||
echo "B3BP:STDIO_REPLACE_DATETIMES"
|
||||
|
||||
env LOG_LEVEL=8 NO_COLOR=true bash "${__root}/main.sh" -f /tmp/x
|
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
@ -0,0 +1,2 @@
|
||||
[connection]
|
||||
host = ${TARGET_HOST}
|
3
test/scenario/templater/break.template.cfg
Normal file
@ -0,0 +1,3 @@
|
||||
[connection]
|
||||
host = ${TARGET_HOST}
|
||||
port = ${I_DONT_EXIST}
|
33
test/scenario/templater/run.sh
Normal file
@ -0,0 +1,33 @@
|
||||
#!/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 "--"
|
||||
env TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./app.template.cfg ./app.cfg
|
||||
cat app.cfg
|
||||
rm -f app.cfg
|
||||
|
||||
echo "--"
|
||||
export TARGET_HOST="127.0.0.1"
|
||||
|
||||
# shellcheck source=src/templater.sh
|
||||
source "${__root}/src/templater.sh"
|
||||
|
||||
templater ./app.template.cfg ./app.cfg
|
||||
cat app.cfg
|
||||
rm -f app.cfg
|
||||
|
||||
echo "--"
|
||||
env ALLOW_REMAINDERS="1" TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./break.template.cfg ./break.cfg
|
||||
cat break.cfg
|
||||
rm -f break.cfg
|
||||
|
||||
echo "--"
|
||||
env TARGET_HOST="127.0.0.1" bash "${__root}/src/templater.sh" ./break.template.cfg ./break.cfg
|
||||
cat break.cfg
|
||||
rm -f break.cfg
|
1
website/.stylelintrc
Normal file
@ -0,0 +1 @@
|
||||
{rules: {}}
|
1
website/CNAME
Normal file
@ -0,0 +1 @@
|
||||
bash3boilerplate.sh
|
4
website/_config.yml
Normal file
@ -0,0 +1,4 @@
|
||||
title: BASH3 Boilerplate
|
||||
|
||||
gems:
|
||||
- jekyll-redirect-from
|
84
website/_layouts/default.html
Normal file
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
{% if page.url == "/" %}
|
||||
<title>{{page.title}}</title>
|
||||
{% else %}
|
||||
<title>{{page.title}} | {{site.title}}</title>
|
||||
{% endif %}
|
||||
|
||||
<meta name="keywords" content="bash, template, scripting, command-line">
|
||||
<meta name="description" content="BASH3 Boilerplate">
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700' rel='stylesheet' type='text/css'>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{site.lanyon_assets.app.css}}" media="screen" charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div id="header-overlay"></div>
|
||||
<a href="/">
|
||||
<span id="logo"></span>
|
||||
</a>
|
||||
<div id="menu">
|
||||
<i class="material-icons">menu</i>
|
||||
<ul id="menu-items">
|
||||
</ul>
|
||||
</div>
|
||||
<span id="more">
|
||||
<i class="material-icons">expand_more</i>
|
||||
</span>
|
||||
</header>
|
||||
<section id="content">
|
||||
{% if page.url == "/" %}
|
||||
<div class="Social">
|
||||
<iframe src="http://ghbtns.com/github-btn.html?user=kvz&repo=bash3boilerplate&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="100" height="20"></iframe>
|
||||
<a href="https://travis-ci.org/kvz/bash3boilerplate"><img src="https://travis-ci.org/kvz/bash3boilerplate.svg" alt="Build Status"></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{{content}}
|
||||
|
||||
{% if page.url == "/" %}
|
||||
<h2 id="activity-feed">On GitHub</h2>
|
||||
<p>
|
||||
BASH3 Boilerplate is a friendly group of folks further developing our
|
||||
re-usable templates as we go.
|
||||
We'd love to hear what you think <a href="https://github.com/kvz/bash3boilerplate">on GitHub</a>.
|
||||
Here's what's been going on recently.
|
||||
</p>
|
||||
<div class="on-the-githubs" data-event-source="repos/kvz/bash3boilerplate">Loading...</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script src="//kvz.github.io/on-the-githubs/js/jquery.on-the-githubs.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$('.on-the-githubs').onthegithubs();
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<div class="Social">
|
||||
<iframe src="http://ghbtns.com/github-btn.html?user=kvz&repo=bash3boilerplate&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="100" height="20"></iframe>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<small>
|
||||
<hr />
|
||||
Website design based on
|
||||
the wonderful <a href="http://apex.run">apex.run</a>
|
||||
with <a href="https://twitter.com/tjholowaychuk/status/744909762865696769">the author's consent</a>.
|
||||
</small>
|
||||
</p>
|
||||
</section>
|
||||
</body>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/highlight.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.1.0/languages/bash.min.js"></script>
|
||||
<script async src="{{site.lanyon_assets.app.js}}"></script>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-63083-13', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</html>
|
76
website/_scripts/inject.sh
Executable file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# This file:
|
||||
#
|
||||
# - Injects markdown files into the ./website directory
|
||||
# - Changes them a little to make them more suitable for Jekyll building
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ./inject.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 "$(dirname "${__dir}")")" && pwd)"
|
||||
|
||||
pushd "${__root}"
|
||||
# Offer the main template for download as http://bash3boilerplate.sh/main.sh
|
||||
cp -v main.sh website/
|
||||
|
||||
for doc in "README" "FAQ" "CHANGELOG"; do
|
||||
targetName="$(echo "${doc}" | awk '{print tolower($0)}')"
|
||||
permalink="/${targetName}/"
|
||||
subtitle="$(tr '[:lower:]' '[:upper:]' <<< "${targetName:0:1}")${targetName:1} | "
|
||||
redirectFrom="/${doc}.md/"
|
||||
backLink="\n\n<a href=\"/\">« Home</a>"
|
||||
if [[ "${doc}" = "README" ]]; then
|
||||
targetName="index"
|
||||
permalink="/"
|
||||
subtitle=""
|
||||
redirectFrom="nothing"
|
||||
backLink=""
|
||||
fi
|
||||
|
||||
cat <<EOF > "website/${targetName}.md"
|
||||
---
|
||||
layout: default
|
||||
permalink: ${permalink}
|
||||
redirect_from: ${redirectFrom}
|
||||
title: ${subtitle}BASH3 Boilerplate – Template for writing better Bash scripts
|
||||
warning: This page is generated by ${__base}.sh based on ${doc}.md, please don't edit ${targetName}.md directly.
|
||||
---
|
||||
EOF
|
||||
# If '<!--more-->' exists, only inject what comes after it, so you can have e.g. a ToC or buildbuttons
|
||||
# on GitHub, without that also rendering in the site (site may have its own ToC rendering for instance)
|
||||
if grep '<!--more-->' "${doc}.md"; then
|
||||
sed -n -e '/<!--more-->/,$p' "${doc}.md" | tail -n +2 >> "website/${targetName}.md"
|
||||
else
|
||||
cat "${doc}.md" >> "website/${targetName}.md"
|
||||
fi
|
||||
|
||||
# Add a "<- Back Home" link, if any
|
||||
echo -e $backLink >> "website/${targetName}.md"
|
||||
|
||||
echo "--> written website/${targetName}.md"
|
||||
done
|
||||
popd
|
13
website/assets/app.js
Normal file
@ -0,0 +1,13 @@
|
||||
require('./main.js')
|
||||
require('./style.css')
|
||||
require('./syntax.css')
|
||||
|
||||
// check if HMR is enabled
|
||||
if (module.hot) {
|
||||
module.hot.accept('./main.js', function () {
|
||||
require('./main.js');
|
||||
});
|
||||
module.hot.accept('./style.css', function () {
|
||||
require('./style.css');
|
||||
});
|
||||
}
|
BIN
website/assets/images/1.jpg
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
website/assets/images/b3bp-logo.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
website/assets/images/logo.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
website/assets/images/logo.pxm
Normal file
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 563 KiB |
After Width: | Height: | Size: 349 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 543 KiB |
After Width: | Height: | Size: 345 KiB |
55
website/assets/main.js
Normal file
@ -0,0 +1,55 @@
|
||||
// Backgrounds.
|
||||
// var backgrounds = [1,2,3,4,5,6]
|
||||
var backgrounds = [1]
|
||||
|
||||
// Highlighting.
|
||||
hljs.initHighlighting()
|
||||
|
||||
// Storage.
|
||||
var store = window.sessionStorage
|
||||
|
||||
// Background.
|
||||
var background = store.getItem('background')
|
||||
|
||||
if (!background) {
|
||||
var i = Math.random() * backgrounds.length | 0
|
||||
background = backgrounds[i]
|
||||
console.log('setting background to %s', background)
|
||||
store.setItem('background', background)
|
||||
}
|
||||
|
||||
// Body class for background.
|
||||
var el = document.getElementById('header-overlay')
|
||||
el.style.backgroundImage = 'url(/assets/images/' + background + '.jpg)'
|
||||
|
||||
// Attach class to #menu element depending on page offset.
|
||||
document.addEventListener('DOMContentLoaded', chooseMenuColor)
|
||||
window.onscroll = chooseMenuColor
|
||||
|
||||
function chooseMenuColor() {
|
||||
var menuElement = document.getElementById('menu')
|
||||
var menuTopOffset = 45
|
||||
Math.floor(window.innerHeight * .20) < window.pageYOffset + menuTopOffset ?
|
||||
menuElement.classList.remove('over-header') :
|
||||
menuElement.classList.add('over-header')
|
||||
}
|
||||
|
||||
|
||||
function $get(selector) { return document.querySelector(selector) }
|
||||
function $all(selector) {
|
||||
return Array.prototype.slice.call(document.querySelectorAll(selector))
|
||||
}
|
||||
|
||||
var container = $get('#menu-items')
|
||||
|
||||
// if (location.pathname !== '/') {
|
||||
// var li = document.createElement('li');
|
||||
// li.innerHTML = '<a href="/">« Home</a>';
|
||||
// container.appendChild(li);
|
||||
// }
|
||||
|
||||
$all('#content h2').forEach(function(el) {
|
||||
var li = document.createElement('li');
|
||||
li.innerHTML = '<a href="#' + el.id + '">' + el.innerHTML + '</a>';
|
||||
container.appendChild(li);
|
||||
})
|
345
website/assets/style.css
Normal file
@ -0,0 +1,345 @@
|
||||
|
||||
body {
|
||||
font: 16px/1.625 "Open Sans", "Helvetica Neue", "Helvetica", Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
color: #656a71;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#header-overlay {
|
||||
background: #131313 50% 100% no-repeat;
|
||||
background-size: cover;
|
||||
height: 20vh;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
-webkit-animation-name: overlay;
|
||||
animation-name: overlay;
|
||||
-webkit-animation-duration: 5s;
|
||||
animation-duration: 5s;
|
||||
-webkit-animation-delay: 1s;
|
||||
animation-delay: 1s;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@-webkit-keyframes overlay {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: .25;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes overlay {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: .25;
|
||||
}
|
||||
}
|
||||
|
||||
body.background-1 #header-overlay {
|
||||
background-image: url(images/1.jpg);
|
||||
}
|
||||
|
||||
body.background-4 #header-overlay {
|
||||
background-image: url(images/1.jpg);
|
||||
}
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
background: url(images/b3bp-logo.png) center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
width: 180px;
|
||||
height: 120px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -100px;
|
||||
margin-top: -60px;
|
||||
-webkit-animation-name: logo;
|
||||
animation-name: logo;
|
||||
-webkit-animation-duration: 2s;
|
||||
animation-duration: 2s;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@-webkit-keyframes logo {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes logo {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#more {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
color: white;
|
||||
opacity: 0;
|
||||
-webkit-animation-name: move;
|
||||
animation-name: move;
|
||||
-webkit-animation-duration: 3s;
|
||||
animation-duration: 3s;
|
||||
-webkit-animation-delay: 3s;
|
||||
animation-delay: 3s;
|
||||
-webkit-animation-fill-mode: forwards;
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.86, 0, 0.07, 1);
|
||||
animation-timing-function: cubic-bezier(0.86, 0, 0.07, 1);
|
||||
}
|
||||
|
||||
@-webkit-keyframes move {
|
||||
0% {
|
||||
opacity: 0;
|
||||
bottom: 300px;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
90% {
|
||||
opacity: 1;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
bottom: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
0% {
|
||||
opacity: 0;
|
||||
bottom: 300px;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
90% {
|
||||
opacity: 1;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
bottom: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: 100px 0;
|
||||
max-width: 650px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#menu {
|
||||
position: fixed;
|
||||
top: 35px;
|
||||
right: 35px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
color: black;
|
||||
padding: 7px;
|
||||
border-radius: 1px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
#menu.over-header {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#menu i {
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
#menu:hover #menu-items {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#menu-items {
|
||||
line-height: 1.7;
|
||||
opacity: 0;
|
||||
position: fixed;
|
||||
visibility: hidden;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
font-size: 12px;
|
||||
background: white;
|
||||
color: #121212;
|
||||
top: 67px;
|
||||
right: 35px;
|
||||
border-radius: 1px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#menu-items li a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#menu-items li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#menu-items li a {
|
||||
color: #4C4C4C;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0px;
|
||||
color: #3b444f;
|
||||
}
|
||||
|
||||
h1 { font-size: 2em; /* 2*16 = 32 */ }
|
||||
h2 { font-size: 1.5em; /* 1.5*16 = 24 */ }
|
||||
h3 { font-size: 1.17em; /* 1.17*16 = 18.72 */ }
|
||||
h4 { font-size: 1em; /* 1*16 = 16 */ }
|
||||
h5 { font-size: 0.83em; /* 0.83*16 = 13.28 */ }
|
||||
h6 { font-size: 0.75em; /* 0.75*16 = 12 */ }
|
||||
|
||||
h1 {
|
||||
/*margin-top: 75px;*/
|
||||
}
|
||||
|
||||
h1::before {
|
||||
/*display: block;
|
||||
content: ' ';
|
||||
border-top: 1px dotted #eee;
|
||||
width: 35%;
|
||||
margin: 0 auto 75px auto;*/
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
p > code,
|
||||
li > code {
|
||||
border: 1px solid #eee;
|
||||
padding: 2px 10px;
|
||||
border-radius: 3px;
|
||||
font-size: .75rem;
|
||||
color: #555;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
header {
|
||||
background: #131313;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #55A1E1;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1px;
|
||||
border: none;
|
||||
height: 1px;
|
||||
/* Set the hr color */
|
||||
color: gainsboro; /* old IE */
|
||||
background-color: gainsboro; /* Modern Browsers */
|
||||
}
|
||||
|
||||
.Social {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
.Social > * {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.on-the-githubs {
|
||||
-webkit-margin-before: 1em;
|
||||
-webkit-margin-after: 1em;
|
||||
}
|
||||
.on-the-githubs:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
.on-the-githubs > li {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
/*height: 26px;*/
|
||||
position: relative;
|
||||
border-bottom: 1px solid rgba(gainsboro, 0.3);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.on-the-githubs > li:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.on-the-githubs > li p {
|
||||
font-size: 15px;
|
||||
line-height: 16px;
|
||||
margin: 0 2px;
|
||||
padding: 0;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
max-width: 80%;
|
||||
}
|
||||
.on-the-githubs > li abbr {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
float: left;
|
||||
text-align: right;
|
||||
/*display: none*/
|
||||
}
|
||||
.on-the-githubs > li a {
|
||||
font-weight: normal;
|
||||
/*text-decoration: underline;*/
|
||||
}
|
||||
.on-the-githubs > li img {
|
||||
float: left;
|
||||
margin: 0 2px 0 0;
|
||||
border-radius: 10px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
104
website/assets/syntax.css
Normal file
@ -0,0 +1,104 @@
|
||||
|
||||
pre {
|
||||
border-top-color: #ddd;
|
||||
border-radius: 3px;
|
||||
font-size: .75rem;
|
||||
overflow-x: auto;
|
||||
line-height: 1.3;
|
||||
padding: 1.5rem;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
overflow-x: auto;
|
||||
border: 1px solid #eee;
|
||||
border-bottom-color: #ddd;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
XCode style (c) Angel Garcia <angelgarcia.mail@gmail.com>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #006a00;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-literal {
|
||||
color: #aa0d91;
|
||||
}
|
||||
|
||||
.hljs-name {
|
||||
color: #008;
|
||||
}
|
||||
|
||||
.hljs-variable,
|
||||
.hljs-template-variable {
|
||||
color: #660;
|
||||
}
|
||||
|
||||
.hljs-string {
|
||||
color: #c41a16;
|
||||
}
|
||||
|
||||
.hljs-regexp,
|
||||
.hljs-link {
|
||||
color: #080;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-tag,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-number,
|
||||
.hljs-meta {
|
||||
color: #1c00cf;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-class .hljs-title,
|
||||
.hljs-type,
|
||||
.hljs-attr,
|
||||
.hljs-built_in,
|
||||
.hljs-builtin-name,
|
||||
.hljs-params {
|
||||
color: #5c2699;
|
||||
}
|
||||
|
||||
.hljs-attribute,
|
||||
.hljs-subst {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.hljs-formula {
|
||||
background-color: #eee;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
background-color: #baeeba;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
background-color: #ffc8bd;
|
||||
}
|
||||
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class {
|
||||
color: #9b703f;
|
||||
}
|
||||
|
||||
.hljs-doctag,
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|