2022-08-01 21:53:40 +00:00
#!/bin/zsh
2022-08-09 23:42:31 +00:00
export EXECUTION_DIR=$(pwd)
2023-02-22 01:44:27 +00:00
source "${0:a:h}/zsh/lib/import.driver.zsh" || exit 42
2022-08-01 21:53:40 +00:00
#####################################################################
2024-02-06 21:06:44 +00:00
() {
cd "$SCWRYPTS_ROOT__scwrypts"
GIT_SCWRYPTS() { git -C "$SCWRYPTS_ROOT__scwrypts" $@; }
local ERRORS=0
2022-08-01 21:53:40 +00:00
local USAGE='
2024-02-06 21:06:44 +00:00
usage: scwrypts [...options...] [...patterns...] -- [...script options...]
2023-12-12 00:07:09 +00:00
options:
selection
-m, --name <scwrypt-name> only run the script if there is an exact match
(requires type and group)
-g, --group <group-name> only use scripts from the indicated group
-t, --type <type-name> only use scripts of the indicated type
runtime
-y, --yes auto-accept all [yn] prompts through current scwrypt
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
2024-02-06 21:06:44 +00:00
-n shorthand for "--log-level 0"
-v, --log-level [0-4] set scwrypts log level to one of the following:
0 : only command output and critical failures; skips logfile
1 : add success / failure messages
2 : (default) include status update messages
3 : (CI default) include warning messages
4 : include debug messages
2023-12-12 00:07:09 +00:00
alternate commands
-h, --help display this message and exit
-l, --list print out command list and exit
--list-envs print out environment list and exit
--update update scwrypts library to latest version
--version print out scwrypts version and exit
2024-02-06 21:06:44 +00:00
2023-12-12 00:07:09 +00:00
patterns:
- a list of glob patterns to loose-match a scwrypt by name
script options:
- everything after "--" is forwarded to the scwrypt you run
2024-02-06 21:06:44 +00:00
("-- --help" will provide more information)
2022-08-16 00:30:37 +00:00
'
2024-02-06 21:06:44 +00:00
#####################################################################
### cli argument parsing and global configuration ###################
#####################################################################
2022-08-01 21:53:40 +00:00
local ENV_NAME="$SCWRYPTS_ENV"
local SEARCH_PATTERNS=()
2023-02-22 01:44:27 +00:00
local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME
2024-02-06 21:06:44 +00:00
[ ! $SCWRYPTS_LOG_LEVEL ] && {
local SCWRYPTS_LOG_LEVEL
[ $CI ] && SCWRYPTS_LOG_LEVEL=3 || SCWRYPTS_LOG_LEVEL=2
}
2022-08-01 21:53:40 +00:00
while [[ $# -gt 0 ]]
do
case $1 in
2023-02-22 01:44:27 +00:00
-[a-z][a-z]* )
VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
set -- $(echo " $VARSPLIT ") ${@:2}
;;
2023-11-22 22:54:16 +00:00
2024-02-06 21:06:44 +00:00
### alternate commands ###################
-h | --help )
USAGE
return 0
;;
-l | --list )
SCWRYPTS__GET_AVAILABLE_SCWRYPTS
return 0
;;
--list-envs )
SCWRYPTS__GET_ENV_NAMES
return 0
;;
2023-12-12 00:07:09 +00:00
--version )
2024-02-06 21:06:44 +00:00
echo scwrypts $(GIT_SCWRYPTS describe --tags)
2022-08-01 21:53:40 +00:00
return 0
;;
2023-11-22 22:54:16 +00:00
2023-02-22 01:44:27 +00:00
--update )
2024-02-06 21:06:44 +00:00
GIT_SCWRYPTS fetch --quiet origin main
GIT_SCWRYPTS fetch --quiet origin main --tags
2023-02-22 01:44:27 +00:00
local SYNC_STATUS=$?
2024-02-06 21:06:44 +00:00
GIT_SCWRYPTS diff --exit-code origin/main -- . >/dev/null 2>&1
2023-02-22 01:44:27 +00:00
local DIFF_STATUS=$?
[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
SUCCESS 'already up-to-date with origin/main'
} || {
2024-02-06 21:06:44 +00:00
GIT_SCWRYPTS rebase --autostash origin/main \
2023-02-22 01:44:27 +00:00
&& SUCCESS 'up-to-date with origin/main' \
2024-02-06 21:06:44 +00:00
&& GIT_SCWRYPTS log -n1 \
2023-02-22 01:44:27 +00:00
|| {
2024-02-06 21:06:44 +00:00
GIT_SCWRYPTS rebase --abort
2023-02-22 01:44:27 +00:00
ERROR 'unable to update scwrypts; please try manual upgrade'
REMINDER "installation in '$(pwd)'"
}
}
2022-08-01 21:53:40 +00:00
return 0
;;
2023-12-12 00:07:09 +00:00
2024-02-06 21:06:44 +00:00
### scwrypts filters #####################
2023-12-12 00:07:09 +00:00
-m | --name )
2024-02-06 21:06:44 +00:00
[ $2 ] || { ERROR "missing value for argument $1"; break; }
2023-12-12 00:07:09 +00:00
SEARCH_NAME=$2
2022-08-01 21:53:40 +00:00
shift 1
;;
2023-12-12 00:07:09 +00:00
-g | --group )
2024-02-06 21:06:44 +00:00
[ $2 ] || { ERROR "missing value for argument $1"; break; }
2023-12-12 00:07:09 +00:00
SEARCH_GROUP=$2
2022-08-01 21:53:40 +00:00
shift 1
;;
2023-12-12 00:07:09 +00:00
-t | --type )
2024-02-06 21:06:44 +00:00
[ $2 ] || { ERROR "missing value for argument $1"; break; }
2023-12-12 00:07:09 +00:00
SEARCH_TYPE=$2
2022-08-01 21:53:40 +00:00
shift 1
;;
2023-12-12 00:07:09 +00:00
2024-02-06 21:06:44 +00:00
### runtime settings #####################
-y | --yes ) export __SCWRYPTS_YES=1 ;;
-n | --no-log )
SCWRYPTS_LOG_LEVEL=0
[[ $1 =~ ^--no-log$ ]] && WARNING 'the --no-log flag is deprecated and will be removed in scwrypts v4.2'
;;
-v | --log-level )
[[ $2 =~ ^[0-4]$ ]] || ERROR "invalid setting for log-level '$2'"
SCWRYPTS_LOG_LEVEL=$2
shift 1
;;
2023-12-12 00:07:09 +00:00
-e | --env )
2024-02-06 21:06:44 +00:00
[ $2 ] || { ERROR "missing value for argument $1"; break; }
[ $ENV_NAME ] && DEBUG 'overwriting session environment'
2023-12-12 00:07:09 +00:00
ENV_NAME="$2"
STATUS "using CLI environment '$ENV_NAME'"
shift 1
;;
2024-02-06 21:06:44 +00:00
##########################################
2023-12-12 00:07:09 +00:00
-- ) shift 1; break ;; # pass arguments after '--' to the scwrypt
--* ) ERROR "unrecognized argument '$1'" ;;
* ) SEARCH_PATTERNS+=($1) ;;
2022-08-01 21:53:40 +00:00
esac
2023-12-12 00:07:09 +00:00
shift 1
2022-08-01 21:53:40 +00:00
done
2023-02-22 01:44:27 +00:00
[ $SEARCH_NAME ] && {
2023-12-12 00:07:09 +00:00
[ $SEARCH_TYPE ] || ERROR '--name requires --type argument'
[ $SEARCH_GROUP ] || ERROR '--name requires --group argument'
2023-02-22 01:44:27 +00:00
}
CHECK_ERRORS
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
#####################################################################
### scwrypts selection / filtering ##################################
#####################################################################
2022-08-01 21:53:40 +00:00
2023-02-22 01:44:27 +00:00
local SCWRYPTS_AVAILABLE
SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS)
2024-02-06 21:06:44 +00:00
##########################################
2023-02-22 01:44:27 +00:00
2024-02-06 21:06:44 +00:00
[ $SEARCH_NAME ] && SCWRYPTS_AVAILABLE=$({
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | sed -e 's/\x1b\[[0-9;]*m//g' | grep "^$SEARCH_NAME *$SEARCH_TYPE *$SEARCH_GROUP\$"
}) || {
2023-02-22 01:44:27 +00:00
[ $SEARCH_TYPE ] && {
SCWRYPTS_AVAILABLE=$(\
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep ' [^/]*'$SEARCH_TYPE'[^/]* '
} \
| awk '{$2=""; print $0;}' \
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
| column -ts '^'
)
}
[ $SEARCH_GROUP ] && {
SCWRYPTS_AVAILABLE=$(
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep "$SEARCH_GROUP"'[^/]*$'
} \
| awk '{$NF=""; print $0;}' \
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
| column -ts '^'
)
}
[[ ${#SEARCH_PATTERNS[@]} -gt 0 ]] && {
POTENTIAL_ERROR+="\n PATTERNS : $SEARCH_PATTERNS"
local P
for P in ${SEARCH_PATTERNS[@]}
do
SCWRYPTS_AVAILABLE=$(
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep $P
}
)
done
}
}
2024-02-06 21:06:44 +00:00
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -lt 2 ]] && {
FAIL 1 "$(echo "
no such scwrypt exists
NAME : '$SEARCH_NAME'
TYPE : '$SEARCH_TYPE'
GROUP : '$SEARCH_GROUP'
PATTERNS : '$SEARCH_PATTERNS'
" | sed "1d; \$d; /''$/d")"
}
2023-02-22 01:44:27 +00:00
##########################################
2024-02-06 21:06:44 +00:00
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -eq 2 ]] \
&& SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | tail -n1) \
|| SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | FZF "select a script to run" --header-lines 1) \
;
2023-02-22 01:44:27 +00:00
[ $SCWRYPT_SELECTION ] || exit 2
2024-02-06 21:06:44 +00:00
##########################################
local NAME TYPE GROUP
2023-02-22 01:44:27 +00:00
SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
export SCWRYPT_NAME=$NAME
export SCWRYPT_TYPE=$TYPE
export SCWRYPT_GROUP=$GROUP
2024-02-06 21:06:44 +00:00
#####################################################################
### environment variables and configuration validation ##############
#####################################################################
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
local ENV_REQUIRED=true \
&& [ ! $CI ] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/environment ]] \
|| ENV_REQUIRED=false
2023-08-22 20:20:03 +00:00
2024-02-06 21:06:44 +00:00
local REQUIRED_ENVIRONMENT_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$SCWRYPT_GROUP)
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
[[ $ENV_REQUIRED =~ true ]] && {
2023-02-22 01:44:27 +00:00
[ ! $ENV_NAME ] && ENV_NAME=$(SCWRYPTS__SELECT_ENV)
2023-11-13 19:20:08 +00:00
2023-06-27 11:00:06 +00:00
for GROUP in ${SCWRYPTS_GROUPS[@]}
do
local ENV_FILE=$(SCWRYPTS__GET_ENV_FILE "$ENV_NAME" "$GROUP")
source "$ENV_FILE" || FAIL 5 "missing or invalid environment '$GROUP/$ENV_NAME'"
2023-08-18 18:40:14 +00:00
for f in $(eval 'echo $SCWRYPTS_STATIC_CONFIG__'$GROUP)
do
source "$f" || FAIL 5 "invalid static config '$f'"
done
2023-06-27 11:00:06 +00:00
done
2022-08-01 21:53:40 +00:00
export ENV_NAME
}
2024-02-06 21:06:44 +00:00
##########################################
2023-08-22 20:20:03 +00:00
[ $REQUIRED_ENVIRONMENT_REGEX ] && {
[[ $ENV_NAME =~ $REQUIRED_ENVIRONMENT_REGEX ]] \
2024-02-06 21:06:44 +00:00
|| FAIL 5 "group '$SCWRYPT_GROUP' requires current environment name to match '$REQUIRED_ENVIRONMENT_REGEX' (currently $ENV_NAME)"
2023-08-22 20:20:03 +00:00
}
2023-06-22 21:48:57 +00:00
2023-02-22 01:44:27 +00:00
##########################################
2024-02-06 21:06:44 +00:00
[ ! $SUBSCWRYPT ] && [[ $ENV_NAME =~ prod ]] && {
STATUS "on '$ENV_NAME'; checking diff against origin/main"
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
GIT_SCWRYPTS fetch --quiet origin main
local SYNC_STATUS=$?
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
GIT_SCWRYPTS diff --exit-code origin/main -- . >&2
local DIFF_STATUS=$?
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
SUCCESS 'up-to-date with origin/main'
2022-08-01 21:53:40 +00:00
} || {
2024-02-06 21:06:44 +00:00
SCWRYPTS_LOG_LEVEL=3 WARNING "you are trying to run in ${__BRIGHT_RED}production${__YELLOW} but $([[ $SYNC_STATUS -ne 0 ]] && echo 'I am unable to verify your scwrypts version')$([[ $DIFF_STATUS -ne 0 ]] && echo 'your scwrypts is out-of-date (diff listed above)')"
yN 'continue?' || {
REMINDER "you can use 'scwrypts --update' to quickly update scwrypts to latest"
ABORT
}
2022-08-01 21:53:40 +00:00
}
}
2024-02-06 21:06:44 +00:00
##########################################
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
local RUN_STRING=$(SCWRYPTS__GET_RUNSTRING $SCWRYPT_NAME $SCWRYPT_TYPE $SCWRYPT_GROUP)
[ "$RUN_STRING" ] || return 42
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
#####################################################################
### logging and pretty header/footer setup ##########################
#####################################################################
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
local LOGFILE \
&& [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] \
&& [ ! $SUBSCWRYPT ] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
&& [[ ! $SCWRYPT_NAME =~ interactive ]] \
&& LOGFILE="$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log" \
|| LOGFILE='/dev/null' \
;
local RUN_MODE=normal
[[ $LOGFILE =~ ^/dev/null$ ]] && RUN_MODE=no-logfile
[[ $SCWRYPT_NAME =~ interactive ]] && RUN_MODE=interactive
local HEADER FOOTER
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && {
HEADER=$(
echo "
=====================================================================
script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME
run at : $(date)
config : $ENV_NAME
log level : $SCWRYPTS_LOG_LEVEL
\\033[1;33m--- SCWRYPT BEGIN ---------------------------------------------------\\033[0m
" | sed 's/^\s\+//; 1d'
)
FOOTER="\\033[1;33m--- SCWRYPT END ---------------------------------------------------\\033[0m"
}
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
[ $SUBSCWRYPT ] && {
HEADER="\\033[0;33m--- ($SUBSCWRYPT) BEGIN $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
FOOTER="\\033[0;33m--- ($SUBSCWRYPT) END $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
}
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
#####################################################################
### run the scwrypt #################################################
#####################################################################
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
[ ! $SUBSCWRYPT ] && export SUBSCWRYPT=0
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
set -o pipefail
{
[ $HEADER ] && echo $HEADER
case $RUN_MODE in
normal )
(eval "$RUN_STRING $(printf "%q " "$@")")
EXIT_CODE=$?
;;
no-logfile )
eval "$RUN_STRING $(printf "%q " "$@")"
EXIT_CODE=$?
;;
interactive )
eval "$RUN_STRING $(printf "%q " "$@")" </dev/tty >/dev/tty 2>&1
EXIT_CODE=$?
;;
esac
[ $FOOTER ] && echo $FOOTER
[[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m'
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && [ ! $SUBSCWRYPT ] \
&& echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
return $EXIT_CODE
} 2>&1 | tee --append "$LOGFILE"
2022-08-01 21:53:40 +00:00
2024-02-06 21:06:44 +00:00
} $@