Created
January 10, 2020 17:27
-
-
Save brodygov/5a77db9474ecdbc633eac65d47e1f3e4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Common shell functions. | |
# Having a library like this is a surefire sign that you are using too much | |
# shell and should switch to something like Ruby. But our scripts currently | |
# pass around a ton of stuff with shell environment variables, so this will | |
# have to do for the time being. | |
run() { | |
echo >&2 "+ $*" | |
"$@" | |
} | |
# Prompt the user for a yes/no response. | |
# Exit codes: | |
# 0: user entered yes | |
# 2: STDIN is not a TTY | |
# 10: user entered no | |
# | |
prompt_yn() { | |
local prompt ans | |
if [ $# -ge 1 ]; then | |
prompt="$1" | |
else | |
prompt="Continue?" | |
fi | |
if [ ! -t 0 ]; then | |
echo >&2 "$prompt [y/n]" | |
echo >&2 "prompt_yn: error: stdin is not a TTY!" | |
return 2 | |
fi | |
while true; do | |
read -r -p "$prompt [y/n] " ans | |
case "$ans" in | |
Y|y|yes|YES|Yes) | |
return | |
;; | |
N|n|no|NO|No) | |
return 10 | |
;; | |
esac | |
done | |
} | |
# usage: backup_if_exists FILE/DIR MODE | |
# | |
# If FILE/DIR exists, prompt to back it up. | |
# MODE can be --overwrite or --abort. This is used to hint the user for what | |
# will happen upon a "no" answer. | |
# | |
# Upon yes, move it to a timestamped backup name. | |
# Upon no, return 1 if --abort is given, 0 if --abort is given. | |
# | |
backup_if_exists() { | |
local target backup_name overwrite | |
target="$1" | |
mode="$2" | |
case "$mode" in | |
--overwrite) | |
overwrite=1 | |
prompt="Would you like to back it up? Y=backup N=overwrite" | |
;; | |
--abort) | |
overwrite= | |
prompt="Would you like to back it up? Y=backup N=abort" | |
;; | |
*) | |
echo_red >&2 "Unexpected backup mode $mode" | |
return 2 | |
;; | |
esac | |
if [ -e "$target" ]; then | |
echo_yellow >&2 "warning: '$target' already exists" | |
prompt_yn "$prompt" && ret=$? || ret=$? | |
case "$ret" in | |
0) | |
backup_name="$target.backup~$(date "+%F.%H-%M-%S")" | |
run mv -iv "$target" "$backup_name" | |
;; | |
10) | |
if [ -n "$overwrite" ]; then | |
echo_yellow >&2 "OK, not backing up" | |
return | |
else | |
echo_yellow >&2 "OK, returning error $ret" | |
return "$ret" | |
fi | |
;; | |
*) | |
echo_red >&2 "Unexpected return value $ret from prompt_yn" | |
return "$ret" | |
;; | |
esac | |
fi | |
} | |
echo_color() { | |
local color code | |
color="$1" | |
shift | |
case "$color" in | |
red) code=31 ;; | |
green) code=32 ;; | |
yellow) code=33 ;; | |
blue) code=34 ;; | |
purple) code=35 ;; | |
cyan) code=36 ;; | |
*) | |
echo >&2 "echo_color: unknown color $color" | |
return 1 | |
;; | |
esac | |
if [ -t 1 ]; then | |
echo -ne "\\033[1;${code}m" | |
fi | |
echo -n "$*" | |
if [ -t 1 ]; then | |
echo -ne '\033[m' | |
fi | |
echo | |
} | |
echo_blue() { | |
echo_color blue "$@" | |
} | |
echo_green() { | |
echo_color green "$@" | |
} | |
echo_red() { | |
echo_color red "$@" | |
} | |
echo_yellow() { | |
echo_color yellow "$@" | |
} | |
# Print underscores as wide as the terminal screen | |
echo_color_horizontal_rule() { | |
declare -i width # local integer | |
width="${COLUMNS-80}" | |
local color | |
case $# in | |
0) color=blue ;; | |
1) color="$1" ;; | |
*) | |
echo >&2 "usage: echo_color_horizontal_rule [COLOR]" | |
return 1 | |
;; | |
esac | |
echo_color "$color" "$(printf "%0.s_" $(seq 1 "$width"))" | |
} | |
log() { | |
local color= | |
if [ "${1-}" = "--blue" ]; then | |
color=34 | |
shift | |
fi | |
# print our caller if possible as the basename | |
if [ "${#BASH_SOURCE[@]}" -ge 2 ]; then | |
local basename | |
basename="${BASH_SOURCE[1]}" | |
if [[ $basename = */* ]]; then | |
basename="$(basename "$basename")" | |
fi | |
if [ -n "$color" ] && [ -t 2 ]; then | |
echo >&2 -ne "\\033[1;${color}m" | |
fi | |
echo >&2 -n "$basename: " | |
fi | |
echo >&2 -n "$*" | |
if [ -n "$color" ] && [ -t 2 ]; then | |
echo >&2 -ne '\033[m' | |
fi | |
echo >&2 | |
} | |
get_terraform_version() { | |
local output | |
# checkpoint is the hashicorp thing that phones home to check versions | |
output="$(CHECKPOINT_DISABLE=1 run terraform --version)" || return $? | |
# we do this in two phases to avoid sending SIGPIPE to terraform, which | |
# would cause it to exit with status 141 | |
echo "$output" | head -1 | cut -d' ' -f2 | |
} | |
assert_file_not_exists() { | |
if [ -e "$1" ]; then | |
echo_red >&2 "error: \`$1' already exists!" | |
return 1 | |
fi | |
} | |
assert_file_exists() { | |
if [ ! -e "$1" ]; then | |
echo_red >&2 "error: \`$1' does not exist!" | |
return 1 | |
fi | |
} | |
# usage: check_terraform_version SUPPORTED_VERSION... | |
# | |
# e.g. check_terraform_version v0.8.* v0.9.* | |
# | |
# Check whether the current version of terraform (as reported by terraform | |
# --version) is in the allowed list passed as arguments. Return 0 if so, | |
# otherwise return 1. | |
check_terraform_version() { | |
current_tf_version="$(get_terraform_version)" | |
if [ $# -eq 0 ]; then | |
echo_red >&2 \ | |
"error: no supported versions passed to check_terraform_version" | |
return 2 | |
fi | |
for version in "$@"; do | |
# version is expected to be a pattern | |
# shellcheck disable=SC2053 | |
if [[ $current_tf_version == $version ]]; then | |
echo "Terraform version $current_tf_version is supported" | |
return | |
fi | |
done | |
echo_red >&2 "Terraform version $current_tf_version is not supported" | |
echo_red >&2 "Expected versions: $*" | |
echo >&2 "Try using \`bin/terraform-switch.sh\` to install / switch" | |
echo >&2 "to a target installed version of terraform with homebrew." | |
return 1 | |
} | |
# Similar to Ruby's Array#join | |
# usage: join_by DELIMITER ELEM... | |
join_by() { | |
local delimiter="$1" | |
shift | |
if [ $# -eq 0 ]; then | |
echo | |
return | |
fi | |
# print first elem with no delimiter | |
echo -n "$1" | |
shift | |
for elem in "$@"; do | |
echo -n "$delimiter$elem" | |
done | |
echo | |
} | |
# Output shell array as a terraform-compatible string | |
# (1 2 3) => '["1", "2", "3"]' | |
array_to_string() { | |
echo "[\"$(join_by '", "' "$@")\"]" | |
} | |
# Usage: verify_repo_root_unchanged REPO_ROOT_BEFORE_CD BASENAME | |
# | |
# Double check that the repo root has not changed after executing a cd. This is | |
# useful in case you are running a script like tf-deploy or diff-deploy on your | |
# PATH, since the script will cd to the script's own parent directory.. | |
# | |
# If your prior cwd repo root was not the same as the new repo root, this means | |
# that you are probably executing a different script from the one you expected. | |
# Prompt to confirm, since this is probably not what the user intended. | |
# | |
verify_repo_root_unchanged() { | |
local repo_root_before_cd repo_root_after_cd BASENAME | |
repo_root_before_cd="$1" | |
BASENAME="$2" | |
repo_root_after_cd="$(git rev-parse --show-toplevel)" | |
if [ -n "$repo_root_before_cd" ] \ | |
&& [ -e "$repo_root_before_cd/bin/$BASENAME" ] \ | |
&& [ "$repo_root_before_cd" != "$repo_root_after_cd" ] | |
then | |
echo_yellow >&2 "WARNING: your cwd is in a different directory than $BASENAME. | |
Are you sure you didn't mean to run ./bin/$BASENAME instead? | |
Repo root from your cwd: $repo_root_before_cd | |
Repo root for $BASENAME: $repo_root_after_cd" | |
prompt_yn | |
fi | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment