===================================================================== --- Bug fixes ---------------------------- - Some exit error cases were not handled properly by the default eval string due to early exit failing within the primary subshell of the scwrypt; moving the runstring one subshell deeper allows the capture of exit cases
		
			
				
	
	
		
			336 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/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 <group-name>    only use scripts from the indicated group
 | |
| 		  -t, --type <type-name>      only use scripts of the indicated type
 | |
| 		  -m, --name <scwrypt-name>   only run the script if there is an exact match 
 | |
| 		                                (requires type and group)
 | |
| 
 | |
| 		  -e, --env <env-name>   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
 | |
| 				git fetch --quiet origin main --tags
 | |
| 				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 >/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 $@
 |