378 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			378 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/bin/zsh
 | 
						|
export EXECUTION_DIR=$(pwd)
 | 
						|
source "${0:a:h}/zsh/lib/import.driver.zsh" || exit 42
 | 
						|
#####################################################################
 | 
						|
() {
 | 
						|
	cd "$SCWRYPTS_ROOT__scwrypts"
 | 
						|
	GIT_SCWRYPTS() { git -C "$SCWRYPTS_ROOT__scwrypts" $@; }
 | 
						|
	local ERRORS=0
 | 
						|
	local USAGE='
 | 
						|
		usage: scwrypts [...options...] [...patterns...] -- [...script options...]
 | 
						|
 | 
						|
		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
 | 
						|
		    -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
 | 
						|
 | 
						|
		  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
 | 
						|
 | 
						|
		patterns:
 | 
						|
		  - a list of glob patterns to loose-match a scwrypt by name
 | 
						|
 | 
						|
		script options:
 | 
						|
		  - everything after "--" is forwarded to the scwrypt you run
 | 
						|
		    ("-- --help" will provide more information)
 | 
						|
	'
 | 
						|
 | 
						|
	#####################################################################
 | 
						|
	### cli argument parsing and global configuration ###################
 | 
						|
	#####################################################################
 | 
						|
 | 
						|
	local ENV_NAME="$SCWRYPTS_ENV"
 | 
						|
	local SEARCH_PATTERNS=()
 | 
						|
 | 
						|
	local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME
 | 
						|
 | 
						|
	[ ! $SCWRYPTS_LOG_LEVEL ] && {
 | 
						|
		local SCWRYPTS_LOG_LEVEL
 | 
						|
		[ $CI ] && SCWRYPTS_LOG_LEVEL=3 || SCWRYPTS_LOG_LEVEL=2
 | 
						|
	}
 | 
						|
 | 
						|
	while [[ $# -gt 0 ]]
 | 
						|
	do
 | 
						|
		case $1 in
 | 
						|
			-[a-z][a-z]* )
 | 
						|
				VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
 | 
						|
				set -- $(echo " $VARSPLIT ") ${@:2}
 | 
						|
				;;
 | 
						|
 | 
						|
			### alternate commands ###################
 | 
						|
 | 
						|
			-h | --help )
 | 
						|
				USAGE
 | 
						|
				return 0
 | 
						|
				;;
 | 
						|
 | 
						|
			-l | --list )
 | 
						|
				SCWRYPTS__GET_AVAILABLE_SCWRYPTS
 | 
						|
				return 0
 | 
						|
				;;
 | 
						|
 | 
						|
			--list-envs )
 | 
						|
				SCWRYPTS__GET_ENV_NAMES
 | 
						|
				return 0
 | 
						|
				;;
 | 
						|
 | 
						|
			--version )
 | 
						|
				echo scwrypts $(GIT_SCWRYPTS describe --tags)
 | 
						|
				return 0
 | 
						|
				;;
 | 
						|
 | 
						|
			--update )
 | 
						|
				GIT_SCWRYPTS fetch --quiet origin main
 | 
						|
				GIT_SCWRYPTS fetch --quiet origin main --tags
 | 
						|
				local SYNC_STATUS=$?
 | 
						|
 | 
						|
				GIT_SCWRYPTS diff --exit-code origin/main -- . >/dev/null 2>&1
 | 
						|
				local DIFF_STATUS=$?
 | 
						|
 | 
						|
				[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
 | 
						|
					SUCCESS 'already up-to-date with origin/main'
 | 
						|
				} || {
 | 
						|
					GIT_SCWRYPTS rebase --autostash origin/main \
 | 
						|
						&& SUCCESS 'up-to-date with origin/main' \
 | 
						|
						&& GIT_SCWRYPTS log -n1 \
 | 
						|
						|| {
 | 
						|
							GIT_SCWRYPTS rebase --abort
 | 
						|
							ERROR 'unable to update scwrypts; please try manual upgrade'
 | 
						|
							REMINDER "installation in '$(pwd)'"
 | 
						|
						}
 | 
						|
				}
 | 
						|
				return 0
 | 
						|
				;;
 | 
						|
 | 
						|
			### scwrypts filters #####################
 | 
						|
 | 
						|
			-m | --name )
 | 
						|
				[ $2 ] || { ERROR "missing value for argument $1"; break; }
 | 
						|
				SEARCH_NAME=$2
 | 
						|
				shift 1
 | 
						|
				;;
 | 
						|
 | 
						|
			-g | --group )
 | 
						|
				[ $2 ] || { ERROR "missing value for argument $1"; break; }
 | 
						|
				SEARCH_GROUP=$2
 | 
						|
				shift 1
 | 
						|
				;;
 | 
						|
 | 
						|
			-t | --type )
 | 
						|
				[ $2 ] || { ERROR "missing value for argument $1"; break; }
 | 
						|
				SEARCH_TYPE=$2
 | 
						|
				shift 1
 | 
						|
				;;
 | 
						|
 | 
						|
			### 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
 | 
						|
				;;
 | 
						|
 | 
						|
			-e | --env )
 | 
						|
				[ $2 ] || { ERROR "missing value for argument $1"; break; }
 | 
						|
 | 
						|
				[ $ENV_NAME ] && DEBUG 'overwriting session environment'
 | 
						|
 | 
						|
				ENV_NAME="$2"
 | 
						|
				STATUS "using CLI environment '$ENV_NAME'"
 | 
						|
				shift 1
 | 
						|
				;;
 | 
						|
 | 
						|
			##########################################
 | 
						|
 | 
						|
			--  ) shift 1; break ;; # pass arguments after '--' to the scwrypt
 | 
						|
			--* ) ERROR "unrecognized argument '$1'" ;;
 | 
						|
			*   ) SEARCH_PATTERNS+=($1) ;;
 | 
						|
		esac
 | 
						|
		shift 1
 | 
						|
	done
 | 
						|
 | 
						|
	[ $SEARCH_NAME ] && {
 | 
						|
		[ $SEARCH_TYPE  ] || ERROR '--name requires --type argument'
 | 
						|
		[ $SEARCH_GROUP ] || ERROR '--name requires --group argument'
 | 
						|
	}
 | 
						|
 | 
						|
	CHECK_ERRORS
 | 
						|
 | 
						|
	#####################################################################
 | 
						|
	### scwrypts selection / filtering ##################################
 | 
						|
	#####################################################################
 | 
						|
 | 
						|
	local SCWRYPTS_AVAILABLE
 | 
						|
	SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS)
 | 
						|
 | 
						|
	##########################################
 | 
						|
 | 
						|
	[ $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\$"
 | 
						|
	}) || {
 | 
						|
		[ $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
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	[[ $(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")"
 | 
						|
	}
 | 
						|
 | 
						|
	##########################################
 | 
						|
 | 
						|
	[[ $(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
 | 
						|
 | 
						|
	##########################################
 | 
						|
 | 
						|
	local NAME TYPE GROUP
 | 
						|
	SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
 | 
						|
 | 
						|
	export SCWRYPT_NAME=$NAME
 | 
						|
	export SCWRYPT_TYPE=$TYPE
 | 
						|
	export SCWRYPT_GROUP=$GROUP
 | 
						|
 | 
						|
	#####################################################################
 | 
						|
	### environment variables and configuration validation ##############
 | 
						|
	#####################################################################
 | 
						|
 | 
						|
	local ENV_REQUIRED=true \
 | 
						|
		&& [ ! $CI ] \
 | 
						|
		&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
 | 
						|
		&& [[ ! $SCWRYPT_NAME =~ scwrypts/environment ]] \
 | 
						|
		|| ENV_REQUIRED=false
 | 
						|
 | 
						|
	local REQUIRED_ENVIRONMENT_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$SCWRYPT_GROUP)
 | 
						|
 | 
						|
	[[ $ENV_REQUIRED =~ true ]] && {
 | 
						|
		[ ! $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 name to match '$REQUIRED_ENVIRONMENT_REGEX' (currently $ENV_NAME)"
 | 
						|
	}
 | 
						|
 | 
						|
	##########################################
 | 
						|
 | 
						|
	[ ! $SUBSCWRYPT ] && [[ $ENV_NAME =~ prod ]] && {
 | 
						|
		STATUS "on '$ENV_NAME'; checking diff against origin/main"
 | 
						|
 | 
						|
		GIT_SCWRYPTS fetch --quiet origin main
 | 
						|
		local SYNC_STATUS=$?
 | 
						|
 | 
						|
		GIT_SCWRYPTS diff --exit-code origin/main -- . >&2
 | 
						|
		local DIFF_STATUS=$?
 | 
						|
 | 
						|
		[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
 | 
						|
			SUCCESS 'up-to-date with origin/main'
 | 
						|
		} || {
 | 
						|
			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
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	##########################################
 | 
						|
 | 
						|
	local RUN_STRING=$(SCWRYPTS__GET_RUNSTRING $SCWRYPT_NAME $SCWRYPT_TYPE $SCWRYPT_GROUP)
 | 
						|
	[ "$RUN_STRING" ] || return 42
 | 
						|
 | 
						|
	#####################################################################
 | 
						|
	### logging and pretty header/footer setup ##########################
 | 
						|
	#####################################################################
 | 
						|
 | 
						|
	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 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"
 | 
						|
	}
 | 
						|
 | 
						|
	[ $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 ---"
 | 
						|
	}
 | 
						|
 | 
						|
	#####################################################################
 | 
						|
	### run the scwrypt #################################################
 | 
						|
	#####################################################################
 | 
						|
 | 
						|
	[ ! $SUBSCWRYPT ] && export SUBSCWRYPT=0
 | 
						|
 | 
						|
	set -o pipefail
 | 
						|
	{
 | 
						|
		[ $HEADER ] && echo $HEADER
 | 
						|
		[[ $LOGFILE =~ ^/dev/null$ ]] && {
 | 
						|
			eval "$RUN_STRING $(printf "%q " "$@")" </dev/tty >/dev/tty 2>&1
 | 
						|
			EXIT_CODE=$?
 | 
						|
		} || {
 | 
						|
			(eval "$RUN_STRING $(printf "%q " "$@")")
 | 
						|
			EXIT_CODE=$?
 | 
						|
		}
 | 
						|
		[ $FOOTER ] && echo $FOOTER
 | 
						|
		[[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m'
 | 
						|
 | 
						|
		[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && [ ! $SUBSCWRYPT ] \
 | 
						|
			&& echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
 | 
						|
 | 
						|
		return $EXIT_CODE
 | 
						|
	} 2>&1 | tee --append "$LOGFILE"
 | 
						|
 | 
						|
} $@
 |