#!/bin/zsh export EXECUTION_DIR=$(pwd) source "${0:a:h}/zsh/lib/import.driver.zsh" || exit 42 ##################################################################### __RUN() { local USAGE=' usage: scwrypts [OPTIONS ...] SCRIPT -- [SCRIPT OPTIONS ...] OPTIONS -g, --group only use scripts from the indicated group -t, --type only use scripts of the indicated type -m, --name only run the script if there is an exact match (requires type and group) -e, --env set environment; overwrites SCWRYPTS_ENV -n, --no-log skip logging and run in quiet mode --update update scwrypts library to latest version -v, --version print out scwrypts version and exit -l, --list print out command list and exit -h, --help display this message and exit ' cd "$SCWRYPTS_ROOT" local ENV_NAME="$SCWRYPTS_ENV" local SEARCH_PATTERNS=() local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME local ERROR=0 while [[ $# -gt 0 ]] do case $1 in -t | --type ) [ ! $2 ] && ERROR "missing value for argument $1" && break SEARCH_TYPE=$2 shift 2 ;; -g | --group ) [ ! $2 ] && ERROR "missing value for argument $1" && break SEARCH_GROUP=$2 shift 2 ;; -m | --name ) [ ! $2 ] && ERROR "missing value for argument $1" && break SEARCH_NAME=$2 shift 2 ;; -[a-z][a-z]* ) VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/') set -- $(echo " $VARSPLIT ") ${@:2} ;; -h | --help ) USAGE return 0 ;; -n | --no-log ) [ ! $SUBSCWRYPT ] && SUBSCWRYPT=0 shift 1 ;; -e | --env ) [ ! $2 ] && ERROR "missing value for argument $1" && break [ ! $SUBSCWRYPTS ] \ && [ $ENV_NAME ] \ && WARNING 'overwriting session environment' \ ; ENV_NAME="$2" STATUS "using CLI environment '$ENV_NAME'" shift 2 ;; -l | --list ) SCWRYPTS__GET_AVAILABLE_SCWRYPTS return 0 ;; -v | --version ) echo scwrypts $(cd "$SCWRYPTS__ROOT__scwrypts"; git describe --tags) return 0 ;; --update ) cd "$SCWRYPTS__ROOT__scwrypts" git fetch --quiet origin main local SYNC_STATUS=$? git diff --exit-code origin/main -- . >&2 local DIFF_STATUS=$? [[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && { SUCCESS 'already up-to-date with origin/main' } || { git rebase --autostash origin/main \ && SUCCESS 'up-to-date with origin/main' \ || { git rebase --abort ERROR 'unable to update scwrypts; please try manual upgrade' REMINDER "installation in '$(pwd)'" } } return 0 ;; -- ) shift 1 break # pass arguments after '--' to the scwrypt ;; --* ) ERROR "unrecognized argument '$1'" shift 1 ;; * ) SEARCH_PATTERNS+=($1) shift 1 ;; esac done [ $SEARCH_NAME ] && { [ ! $SEARCH_TYPE ] && ERROR '--name requires --type argument' [ ! $SEARCH_GROUP ] && ERROR '--name requires --group argument' } CHECK_ERRORS ########################################## local SCWRYPTS_AVAILABLE local POTENTIAL_ERROR="no such scwrypt exists:" SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS) [ $SEARCH_NAME ] && { POTENTIAL_ERROR+="\n NAME : '$SEARCH_NAME'" POTENTIAL_ERROR+="\n TYPE : '$SEARCH_TYPE'" POTENTIAL_ERROR+="\n GROUP : '$SEARCH_GROUP'" 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\$" }) } [ ! $SEARCH_NAME ] && { [ $SEARCH_TYPE ] && { POTENTIAL_ERROR+="\n TYPE : '$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 ] && { POTENTIAL_ERROR+="\n GROUP : '$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 } } [[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -lt 2 ]] && ERROR "$POTENTIAL_ERROR" CHECK_ERRORS ########################################## local NAME="$SEARCH_NAME" local TYPE="$SEARCH_TYPE" local GROUP="$SEARCH_GROUP" [[ $(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) [ $SCWRYPT_SELECTION ] || exit 2 SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION export SCWRYPT_NAME=$NAME export SCWRYPT_TYPE=$TYPE export SCWRYPT_GROUP=$GROUP ########################################## local ENV_REQUIRED=$(__CHECK_ENV_REQUIRED && echo 1 || echo 0) local REQUIRED_ENVIRONMENT_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$SCWRYPT_GROUP) [ $REQUIRED_ENVIRONMENT_REGEX ] && { [[ $ENV_NAME =~ $REQUIRED_ENVIRONMENT_REGEX ]] \ || FAIL 5 "group '$SCWRYPT_GROUP' requires current environment to match '$REQUIRED_ENVIRONMENT_REGEX' (currently $ENV_NAME)" } [[ $ENV_REQUIRED -eq 1 ]] && { [ ! $ENV_NAME ] && ENV_NAME=$(SCWRYPTS__SELECT_ENV) 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'" for f in $(eval 'echo $SCWRYPTS_STATIC_CONFIG__'$GROUP) do source "$f" || FAIL 5 "invalid static config '$f'" done done export ENV_NAME } [ $REQUIRED_ENVIRONMENT_REGEX ] && { [[ $ENV_NAME =~ $REQUIRED_ENVIRONMENT_REGEX ]] \ || FAIL 5 "group '$SCWRYPT_GROUP' requires current environment to match '$REQUIRED_ENVIRONMENT_REGEX' (currently $ENV_NAME)" } ########################################## [ ! $SUBSCWRYPT ] \ && [[ $ENV_NAME =~ prod ]] \ && { __VALIDATE_UPSTREAM_TIMELINE || ABORT; } ########################################## local RUN_STRING=$(SCWRYPTS__GET_RUNSTRING $SCWRYPT_NAME $SCWRYPT_TYPE $SCWRYPT_GROUP) [ ! $RUN_STRING ] && exit 3 ########################################## local LOGFILE=$(__GET_LOGFILE) local HEADER=$( [ $SUBSCWRYPT ] && return 0 echo '=====================================================================' echo "script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME" echo "run at : $(date)" echo "config : $ENV_NAME" [ ! $LOGFILE ] && echo '\033[1;33m------------------------------------------\033[0m' ) [ ! $LOGFILE ] && { [ $HEADER ] && echo $HEADER [ $SUBSCWRYPT ] && { eval "$RUN_STRING $(printf "%q " "$@")" exit $? } || { eval "$RUN_STRING $(printf "%q " "$@")" /dev/tty 2>&1 exit $? } } { [ $HEADER ] && echo $HEADER echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m' eval "$RUN_STRING $(printf "%q " "$@")" EXIT_CODE=$? echo '\033[1;33m--- END OUTPUT ---------------------------\033[0m' [[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m' echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m" } 2>&1 | tee --append "$LOGFILE" exit $(\ sed -n 's/^terminated with.*code \([0-9]*\).*$/\1/p' $LOGFILE \ | tail -n1 ) } ##################################################################### __CHECK_ENV_REQUIRED() { [ $CI ] && return 1 echo $SCWRYPT_NAME | grep -q 'scwrypts/logs/' && return 1 echo $SCWRYPT_NAME | grep -q 'scwrypts/environment/' && return 1 return 0 } __VALIDATE_UPSTREAM_TIMELINE() { STATUS "on '$ENV_NAME'; checking diff against origin/main" git fetch --quiet origin main local SYNC_STATUS=$? git diff --exit-code origin/main -- . >&2 local DIFF_STATUS=$? [[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && { SUCCESS 'up-to-date with origin/main' } || { WARNING [[ $SYNC_STATUS -ne 0 ]] && WARNING 'unable to synchronize with origin/main' [[ $DIFF_STATUS -ne 0 ]] && WARNING 'your branch differs from origin/main (diff listed above)' WARNING yN 'continue?' || return 1 } } __GET_LOGFILE() { [ $SUBSCWRYPT ] \ || [[ $SCWRYPT_NAME =~ scwrypts/logs ]] \ || [[ $SCWRYPT_NAME =~ interactive ]] \ && return 0 echo "$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log" } ##################################################################### __RUN $@