mirror of
https://github.com/kvz/bash3boilerplate.git
synced 2025-06-24 16:05:08 +00:00
Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
cc57b8db69 | |||
2019c5146a | |||
d365e8dcea | |||
915f858d5e | |||
cbe70aa80e | |||
ff907092a3 | |||
cdc69d9e03 | |||
56721e9cd5 | |||
df3d535ab1 | |||
894c7fe538 | |||
2196cc4411 | |||
5b4800bad8 | |||
472c9e3b74 | |||
90ad85f419 | |||
d9a0c11e49 | |||
9935335ee8 | |||
e90ad7421f | |||
9d2bcdbfb4 | |||
bfb8d40f6c | |||
dd5950975d | |||
7a9d116d2c | |||
ae074aac0c | |||
30cfd19fd9 | |||
ecd6a9f04b | |||
7a3a07989f | |||
dbedd8f983 | |||
dde3b70596 | |||
bdc8778b2c | |||
63cd89a659 | |||
68219d21d4 | |||
c71b6d14c4 | |||
4c256ed58d | |||
f2e8ff236a | |||
8147ee81b5 | |||
437d384815 | |||
19fcad6851 | |||
df0ad9fe25 | |||
23b68a1bfc | |||
5b8cf352c8 | |||
2f4e089311 | |||
4cef357986 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
npm-debug.log
|
||||
node_modules
|
||||
|
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@ -0,0 +1,7 @@
|
||||
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
|
50
Makefile
50
Makefile
@ -1,16 +1,40 @@
|
||||
SHELL := /usr/bin/env bash
|
||||
# Licensed under MIT.
|
||||
# Copyright (2016) by Kevin van Zonneveld https://twitter.com/kvz
|
||||
#
|
||||
# https://www.npmjs.com/package/fakefile
|
||||
#
|
||||
# This Makefile offers convience shortcuts into any Node.js project that utilizes npm scripts.
|
||||
# It functions as a wrapper around the actual listed in `package.json`
|
||||
# So instead of typing:
|
||||
#
|
||||
# $ npm script build:assets
|
||||
#
|
||||
# you could also type:
|
||||
#
|
||||
# $ make build-assets
|
||||
#
|
||||
# Notice that colons (:) are replaced by dashes for Makefile compatibility.
|
||||
#
|
||||
# The benefits of this wrapper are:
|
||||
#
|
||||
# - You get to keep the the scripts package.json, which is more portable
|
||||
# (Makefiles & Windows are harder to mix)
|
||||
# - Offer a polite way into the project for developers coming from different
|
||||
# languages (npm scripts is obviously very Node centric)
|
||||
# - Profit from better autocomplete (make <TAB><TAB>) than npm currently offers.
|
||||
# OSX users will have to install bash-completion
|
||||
# (http://davidalger.com/development/bash-completion-on-os-x-with-brew/)
|
||||
|
||||
release-major:
|
||||
npm version major -m "Release %s"
|
||||
git push
|
||||
npm publish
|
||||
define npm_script_targets
|
||||
TARGETS := $(shell node -e 'for (var k in require("./package.json").scripts) {console.log(k.replace(/:/g, "-"));}')
|
||||
$$(TARGETS):
|
||||
npm run $(subst -,:,$(MAKECMDGOALS))
|
||||
|
||||
release-minor:
|
||||
npm version minor -m "Release %s"
|
||||
git push
|
||||
npm publish
|
||||
.PHONY: $$(TARGETS)
|
||||
endef
|
||||
|
||||
release-patch:
|
||||
npm version patch -m "Release %s"
|
||||
git push
|
||||
npm publish
|
||||
$(eval $(call npm_script_targets))
|
||||
|
||||
# These npm run scripts are available, without needing to be mentioned in `package.json`
|
||||
install:
|
||||
npm run install
|
||||
|
118
README.md
118
README.md
@ -1,18 +1,10 @@
|
||||
# bash3boilerplate
|
||||
|
||||
<!-- badges/ -->
|
||||
[](http://travis-ci.org/kvz/bash3boilerplate "Check this project's build status on TravisCI")
|
||||
[](https://www.gittip.com/kvz/ "Sponsor the development of bash3boilerplate via Gittip")
|
||||
[](https://flattr.com/submit/auto?user_id=kvz&url=https://github.com/kvz/bash3boilerplate&title=bash3boilerplate&language=&tags=github&category=software "Sponsor the development of bash3boilerplate via Flattr")
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=kevin%40vanzonneveld%2enet&lc=NL&item_name=Open%20source%20donation%20to%20Kevin%20van%20Zonneveld¤cy_code=USD&bn=PP-DonationsBF%3abtn_donate_SM%2egif%3aNonHosted "Sponsor the development of bash3boilerplate via Paypal")
|
||||
[](https://coinbase.com/checkouts/19BtCjLCboRgTAXiaEvnvkdoRyjd843Dg2 "Sponsor the development of bash3boilerplate via BitCoin")
|
||||
<!-- /badges -->
|
||||
[](https://travis-ci.org/kvz/bash3boilerplate)
|
||||
|
||||
When hacking up BASH scripts, I often find there are some
|
||||
higherlevel things like logging, configuration, commandline argument
|
||||
higher level things like logging, configuration, command-line argument
|
||||
parsing that:
|
||||
|
||||
- I need everytime
|
||||
- I need every time
|
||||
- Take quite some effort to get right
|
||||
- Keep you from your actual work
|
||||
|
||||
@ -20,7 +12,34 @@ 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.
|
||||
|
||||
An up to date [intro is found on my blog](http://kvz.io/blog/2013/02/26/introducing-bash3boilerplate/).
|
||||
## 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.
|
||||
|
||||
Aiming for portability, I'm targeting Bash 3 (OSX still ships
|
||||
with 3 for instance). If you're going to ask people to install
|
||||
Bash 4 first, you might as well pick a more advanced language as a
|
||||
dependency.
|
||||
|
||||
## Features
|
||||
|
||||
- Structure
|
||||
- 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)
|
||||
|
||||
## Installation
|
||||
|
||||
There are 3 ways you can install (parts of) 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`
|
||||
|
||||
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.
|
||||
|
||||
## Versioning
|
||||
|
||||
@ -32,13 +51,80 @@ Releases will be numbered with the following format:
|
||||
|
||||
And constructed with the following guidelines:
|
||||
|
||||
* 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
|
||||
|
||||
- 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
|
||||
|
||||
For more information on SemVer, please visit [http://semver.org](http://semver.org).
|
||||
|
||||
## Changelog
|
||||
|
||||
### v1.2.0 (Unreleased)
|
||||
|
||||
- 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)
|
||||
|
||||
### 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
|
||||
|
||||
## 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.
|
||||
|
||||
### Library exports
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
if [ "${BASH_SOURCE[0]}" != ${0} ]; then
|
||||
export -f my_script
|
||||
else
|
||||
my_script "${@}"
|
||||
exit $?
|
||||
fi
|
||||
```
|
||||
|
||||
This allows a user to `source` your script or invoke as a script.
|
||||
|
||||
```bash
|
||||
# Running as a script
|
||||
$ ./my_script.sh some args --blah
|
||||
# Sourcing the script
|
||||
$ source my_script.sh
|
||||
$ my_script some more args --blah
|
||||
```
|
||||
|
||||
(taken from the [bpkg](https://raw.githubusercontent.com/bpkg/bpkg/master/README.md) project)
|
||||
|
||||
## Todo
|
||||
|
||||
- [ ] Make `src` libs adhere to Best practices
|
||||
- [ ] `make build` system for generating custom builds
|
||||
- [ ] tests & releases via Travis
|
||||
|
||||
## Sponsoring
|
||||
|
||||
<!-- 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 -->
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2013 Kevin van Zonneveld, [http://kvz.io](http://kvz.io)
|
||||
|
140
main.sh
140
main.sh
@ -9,10 +9,12 @@
|
||||
# - https://github.com/kvz/bash3boilerplate
|
||||
# - http://kvz.io/blog/2013/02/26/introducing-bash3boilerplate/
|
||||
#
|
||||
# Version 1.0.0
|
||||
# Version 1.2.0
|
||||
#
|
||||
# Authors:
|
||||
# - Kevin van Zonneveld (http://kvz.io)
|
||||
# - Izaak Beekman (https://izaakbeekman.com/)
|
||||
# - Alexander Rathai (Alexander.Rathai@gmail.com)
|
||||
#
|
||||
# Usage:
|
||||
# LOG_LEVEL=7 ./main.sh -f /tmp/x -d
|
||||
@ -24,37 +26,62 @@
|
||||
### 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`
|
||||
set -o errexit
|
||||
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`
|
||||
set -o pipefail
|
||||
# set -o xtrace
|
||||
|
||||
# Environment variables and their defaults
|
||||
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
|
||||
NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected
|
||||
|
||||
# Commandline options. This defines the usage page, and is used to parse cli
|
||||
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
|
||||
read -r -d '' usage <<-'EOF'
|
||||
-f [arg] Filename to process. Required.
|
||||
-t [arg] Location of tempfile. Default="/tmp/bar"
|
||||
-d Enables debug mode
|
||||
-h This page
|
||||
# - 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
|
||||
-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
|
||||
EOF
|
||||
|
||||
# Set magic variables for current FILE & DIR
|
||||
# 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 "${0}")"
|
||||
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
__os="Linux"
|
||||
if [[ "${OSTYPE:-}" == "darwin"* ]]; then
|
||||
__os="OSX"
|
||||
fi
|
||||
|
||||
### Functions
|
||||
#####################################################################
|
||||
|
||||
function _fmt () {
|
||||
local color_ok="\x1b[32m"
|
||||
local color_bad="\x1b[31m"
|
||||
|
||||
local color="${color_bad}"
|
||||
if [ "${1}" = "debug" ] || [ "${1}" = "info" ] || [ "${1}" = "notice" ]; then
|
||||
color="${color_ok}"
|
||||
fi
|
||||
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
|
||||
|
||||
local color="${!colorvar:-$color_error}"
|
||||
local color_reset="\x1b[0m"
|
||||
if [[ "${TERM}" != "xterm"* ]] || [ -t 1 ]; then
|
||||
if [ "${NO_COLOR}" = "true" ] || [[ "${TERM:-}" != "xterm"* ]] || [ -t 1 ]; then
|
||||
# Don't use colors on pipes or non-recognized terminals
|
||||
color=""; color_reset=""
|
||||
fi
|
||||
@ -89,14 +116,27 @@ trap cleanup_before_exit EXIT
|
||||
|
||||
# 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}"
|
||||
opts="${opts:-}${opt}"
|
||||
|
||||
varname="arg_${opt:0:1}"
|
||||
if ! echo "${line}" |egrep '\. Default=' >/dev/null 2>&1; then
|
||||
@ -107,20 +147,40 @@ while read line; do
|
||||
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
|
||||
line="$(echo "${usage}" |grep "\-${opt}")"
|
||||
|
||||
|
||||
[ "${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="${OPTARG:-}"
|
||||
if [ -z "${OPTARG:-}" ] && [ "${default}" = "0" ]; then
|
||||
value="1"
|
||||
fi
|
||||
|
||||
@ -130,10 +190,10 @@ done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
[ "$1" = "--" ] && shift
|
||||
[ "${1:-}" = "--" ] && shift
|
||||
|
||||
|
||||
### Switches (like -d for debugmdoe, -h for showing helppage)
|
||||
### Switches (like -d for debugmode, -h for showing helppage)
|
||||
#####################################################################
|
||||
|
||||
# debug mode
|
||||
@ -142,6 +202,11 @@ if [ "${arg_d}" = "1" ]; then
|
||||
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
|
||||
@ -152,27 +217,24 @@ fi
|
||||
### Validation (decide what's required for running your script and error out)
|
||||
#####################################################################
|
||||
|
||||
[ -z "${arg_f}" ] && help "Setting a filename with -f is required"
|
||||
[ -z "${LOG_LEVEL}" ] && emergency "Cannot continue without LOG_LEVEL. "
|
||||
[ -z "${arg_f:-}" ] && help "Setting a filename with -f or --file is required"
|
||||
[ -z "${LOG_LEVEL:-}" ] && emergency "Cannot continue without LOG_LEVEL. "
|
||||
|
||||
|
||||
### Runtime
|
||||
#####################################################################
|
||||
|
||||
# Exit on error. Append ||true if you expect an error.
|
||||
# set -e is safer than #!/bin/bash -e because that is neutralised if
|
||||
# someone runs your script like `bash yourscript.sh`
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
info "__file: ${__file}"
|
||||
info "__dir: ${__dir}"
|
||||
info "__base: ${__base}"
|
||||
info "__os: ${__os}"
|
||||
|
||||
# Bash will remember & return the highest exitcode in a chain of pipes.
|
||||
# This way you can catch the error in case mysqldump fails in `mysqldump |gzip`
|
||||
set -o pipefail
|
||||
|
||||
if [[ "${OSTYPE}" == "darwin"* ]]; then
|
||||
info "You are on OSX"
|
||||
fi
|
||||
info "arg_f: ${arg_f}"
|
||||
info "arg_d: ${arg_d}"
|
||||
info "arg_v: ${arg_v}"
|
||||
info "arg_h: ${arg_h}"
|
||||
|
||||
# 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."
|
||||
|
17
package.json
17
package.json
@ -1,4 +1,19 @@
|
||||
{
|
||||
"name": "bash3boilerplate",
|
||||
"version": "1.0.3"
|
||||
"description": "Copypastable templates to write better bash scripts",
|
||||
"version": "1.2.0",
|
||||
"scripts": {
|
||||
"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",
|
||||
"save:fixtures": "cross-env SAVE_FIXTURES=true npm run test",
|
||||
"release": "npm version ${SEMANTIC:-patch} -m \"Release %s\" && git push --tags && npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"fakefile": "0.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "1.0.7"
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2014, Transloadit Ltd.
|
||||
#
|
||||
# This file
|
||||
# This file:
|
||||
# - takes a source (template) & destination (config) filepath argument
|
||||
# - and then replaces placeholders with variables found in the environment
|
||||
#
|
||||
# Run as:
|
||||
#
|
||||
# ALLOW_REMAINDERS=1 templater.sh input.cfg output.cfg
|
||||
#
|
||||
# Authors:
|
||||
# - Kevin van Zonneveld <kevin@transloadit.com>
|
||||
|
||||
@ -17,6 +21,8 @@ sed=""
|
||||
[ -n "$(which sed)" ] && sed="$(which sed)"
|
||||
[ -n "$(which gsed)" ] && sed="$(which gsed)"
|
||||
|
||||
ALLOW_REMAINDERS="${ALLOW_REMAINDERS:-0}"
|
||||
|
||||
templateSrc="${1}"
|
||||
templateDst="${2}"
|
||||
|
||||
@ -36,7 +42,7 @@ done
|
||||
|
||||
# cat "${templateDst}"
|
||||
|
||||
if grep '${' ${templateDst}; then
|
||||
if grep '${' ${templateDst} && [ "${ALLOW_REMAINDERS}" == "0" ]; then
|
||||
echo "ERROR: Unable to replace the above template vars"
|
||||
exit 1
|
||||
fi
|
||||
|
166
test/acceptance.sh
Executable file
166
test/acceptance.sh
Executable file
@ -0,0 +1,166 @@
|
||||
#!/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 "${__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}"
|
||||
|
||||
if [[ "${OSTYPE}" == "darwin"* ]]; then
|
||||
cmdSed=gsed
|
||||
else
|
||||
cmdSed=sed
|
||||
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
|
||||
echo "Please install ${cmdSed}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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
|
||||
echo "==> Scenario: ${scenario}"
|
||||
pushd "${__dir}/scenario/${scenario}" > /dev/null
|
||||
|
||||
# Run scenario
|
||||
(${cmdTimeout} bash ./run.sh \
|
||||
> "${__b3bpTmpDir}/${scenario}.stdio" 2>&1; \
|
||||
echo "${?}" > "${__b3bpTmpDir}/${scenario}.exitcode" \
|
||||
) || true
|
||||
|
||||
# Clear out environmental specifics
|
||||
for typ in $(echo stdio exitcode); do
|
||||
curFile="${__b3bpTmpDir}/${scenario}.${typ}"
|
||||
"${cmdSed}" -i \
|
||||
-e "s@${__node}@{node}@g" "${curFile}" \
|
||||
-e "s@${__root}@{root}@g" "${curFile}" \
|
||||
-e "s@${__sysTmpDir}@{tmpdir}@g" "${curFile}" \
|
||||
-e "s@/tmp@{tmpdir}@g" "${curFile}" \
|
||||
-e "s@${HOME:-/home/travis}@{home}@g" "${curFile}" \
|
||||
-e "s@${USER:-travis}@{user}@g" "${curFile}" \
|
||||
-e "s@travis@{user}@g" "${curFile}" \
|
||||
-e "s@kvz@{user}@g" "${curFile}" \
|
||||
-e "s@{root}/node_modules/\.bin/node@{node}@g" "${curFile}" \
|
||||
-e "s@{home}/build/{user}/fre{node}@{node}@g" "${curFile}" \
|
||||
-e "s@${HOSTNAME}@{hostname}@g" "${curFile}" \
|
||||
-e "s@${__os}@{os}@g" "${curFile}" \
|
||||
-e "s@${__arch}@{arch}@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
|
||||
"${cmdSed}" -i \
|
||||
-r 's@[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}@{ip}@g' \
|
||||
"${curFile}"
|
||||
|
||||
# IPs vary in length. Ansible uses padding. {ip} does not vary in length
|
||||
# so kill the padding after it for consistent output
|
||||
"${cmdSed}" -i \
|
||||
-r 's@\{ip\}\s+@{ip} @g' \
|
||||
"${curFile}"
|
||||
fi
|
||||
if [ "$(cat "${curFile}" |grep 'B3BP:STDIO_REPLACE_UUIDS' |wc -l)" -gt 0 ]; 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Save these as new fixtures?
|
||||
if [ "${SAVE_FIXTURES:-}" = "true" ]; then
|
||||
for typ in $(echo stdio exitcode); do
|
||||
curFile="${__b3bpTmpDir}/${scenario}.${typ}"
|
||||
cp -f \
|
||||
"${curFile}" \
|
||||
"${__dir}/fixture/${scenario}.${typ}"
|
||||
done
|
||||
fi
|
||||
|
||||
# Compare
|
||||
for typ in $(echo stdio exitcode); do
|
||||
curFile="${__b3bpTmpDir}/${scenario}.${typ}"
|
||||
|
||||
echo -n " comparing ${typ}.. "
|
||||
|
||||
if [ "${typ}" = "stdio" ]; then
|
||||
if [ "$(cat "${curFile}" |grep 'B3BP:STDIO_SKIP_COMPARE' |wc -l)" -gt 0 ]; 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; \
|
||||
)
|
||||
|
||||
echo "✓"
|
||||
done
|
||||
|
||||
popd > /dev/null
|
||||
done
|
0
test/fixture/.empty
Normal file
0
test/fixture/.empty
Normal file
1
test/fixture/debug.exitcode
Normal file
1
test/fixture/debug.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
19
test/fixture/debug.stdio
Normal file
19
test/fixture/debug.stdio
Normal file
@ -0,0 +1,19 @@
|
||||
B3BP: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 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 [35m[ debug][0m Info useful to developers for debugging the application, not useful during operations.
|
||||
{datetime} UTC [32m[ info][0m Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
|
||||
{datetime} UTC [34m[ notice][0m Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
|
||||
{datetime} UTC [33m[ warning][0m Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. This is a debug message
|
||||
{datetime} UTC [31m[ error][0m Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
|
||||
{datetime} UTC [1;31m[ critical][0m Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.
|
||||
{datetime} UTC [1;33;41m[ alert][0m Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
|
||||
{datetime} UTC [1;4;5;33;41m[emergency][0m A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
|
||||
{datetime} UTC [32m[ info][0m Cleaning up. Done
|
1
test/fixture/help.exitcode
Normal file
1
test/fixture/help.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
11
test/fixture/help.stdio
Normal file
11
test/fixture/help.stdio
Normal file
@ -0,0 +1,11 @@
|
||||
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
|
1
test/fixture/longopt.exitcode
Normal file
1
test/fixture/longopt.exitcode
Normal file
@ -0,0 +1 @@
|
||||
0
|
4
test/fixture/longopt.stdio
Normal file
4
test/fixture/longopt.stdio
Normal file
@ -0,0 +1,4 @@
|
||||
B3BP:STDIO_REPLACE_DATETIMES
|
||||
{datetime} UTC [32m[ info][0m arg_f: {tmpdir}/x
|
||||
{datetime} UTC [32m[ info][0m arg_f: {tmpdir}/x
|
||||
{datetime} UTC [32m[ info][0m arg_f: {tmpdir}/x
|
1
test/fixture/nocolor.exitcode
Normal file
1
test/fixture/nocolor.exitcode
Normal file
@ -0,0 +1 @@
|
||||
1
|
19
test/fixture/nocolor.stdio
Normal file
19
test/fixture/nocolor.stdio
Normal file
@ -0,0 +1,19 @@
|
||||
B3BP: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] arg_f: {tmpdir}/x
|
||||
{datetime} UTC [ info] arg_d: 0
|
||||
{datetime} UTC [ info] arg_v: 0
|
||||
{datetime} UTC [ info] arg_h: 0
|
||||
{datetime} UTC [ debug] Info useful to developers for debugging the application, not useful during operations.
|
||||
{datetime} UTC [ info] Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
|
||||
{datetime} UTC [ notice] Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
|
||||
{datetime} UTC [ warning] Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. This is a debug message
|
||||
{datetime} UTC [ error] Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
|
||||
{datetime} UTC [ critical] Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection.
|
||||
{datetime} UTC [ alert] Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
|
||||
{datetime} UTC [emergency] A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
|
||||
{datetime} UTC [ info] Cleaning up. Done
|
15
test/scenario/debug/run.sh
Normal file
15
test/scenario/debug/run.sh
Normal file
@ -0,0 +1,15 @@
|
||||
#!/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
|
15
test/scenario/help/run.sh
Executable file
15
test/scenario/help/run.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/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
|
17
test/scenario/longopt/run.sh
Normal file
17
test/scenario/longopt/run.sh
Normal file
@ -0,0 +1,17 @@
|
||||
#!/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
|
15
test/scenario/nocolor/run.sh
Normal file
15
test/scenario/nocolor/run.sh
Normal file
@ -0,0 +1,15 @@
|
||||
#!/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
|
Reference in New Issue
Block a user