=====================================================================

Excited to bring V5 to life. This includes some BREAKING CHANGES to
several aspects of ZSH-type scwrypts. Please refer to the readme
for upgrade details (specifically docs/upgrade/v4-to-v5.md)

--- New Features -------------------------

- ZSH testing library with basic mock capabilities

- new scwrypts environment file format includes metadata and more
  advanced features like optional parent env overrides, selection
  inheritence, and improved structurual flexibility

- speedup cache for non-CI runs of ZSH-type scwrypts

- ${scwryptsmodule} syntax now allows a consistent unique-naming
  scheme for functions in ZSH-type scwrypts while providing better
  insight into origin of API calls in other modules

- reusable, case-statement-driven argument parsers in ZSH-type scwrypts

--- Changes ------------------------------

- several utility function renames in ZSH-type scwrypts to improve
  consistency

- documentation comments included in ZSH libraries

- ZSH-type scwrypts now allow library modules to live alongside
  executables
  (zsh/lib still supported; autodetection determines default)

--- Bug Fixes ----------------------------

- hardened environment checking for REQUIRED_ENV variables; this removes
  the ability to overwrite variables in local function contexts
This commit is contained in:
2025-05-24 08:10:33 -06:00
committed by Wryn (yage) Wagner
parent 1b4060dd1c
commit 7f14edd039
271 changed files with 11459 additions and 10516 deletions
+222 -179
View File
@@ -1,12 +1,16 @@
#!/bin/zsh
#!/usr/bin/env zsh
export EXECUTION_DIR=$(pwd)
export SCWRYPTS_RUNTIME_ID=$(uuidgen)
source "$(dirname $(readlink -f "$0"))/zsh/lib/import.driver.zsh" || exit 42
source "$(dirname -- $(readlink -f -- "$0"))/zsh/import.driver.zsh" || return 42
use scwrypts/environment
use scwrypts/list-available
use scwrypts/get-runstring
#####################################################################
() {
cd "$SCWRYPTS_ROOT__scwrypts"
GIT_SCWRYPTS() { git -C "$SCWRYPTS_ROOT__scwrypts" $@; }
cd "$(scwrypts.config.group scwrypts root)"
GIT_SCWRYPTS() { git -C "$(scwrypts.config.group scwrypts root)" $@; }
local ERRORS=0
local USAGE='
@@ -39,7 +43,7 @@ source "$(dirname $(readlink -f "$0"))/zsh/lib/import.driver.zsh" || exit 42
--list-envs print out environment list and exit
--list-groups print out configured scwrypts groups and exit
--config "eval"-ed to enable config and "use" import in non-scwrypts environments
--root print out SCWRYPTS_ROOT__scwrypts and exit
--root print out scwrypts.config.group.scwrypts.root and exit
--update update scwrypts library to latest version
--version print out scwrypts version and exit
@@ -55,76 +59,76 @@ source "$(dirname $(readlink -f "$0"))/zsh/lib/import.driver.zsh" || exit 42
### cli argument parsing and global configuration ###################
#####################################################################
local ENV_NAME="$SCWRYPTS_ENV"
local ENV_NAME="${SCWRYPTS_ENV}"
local SEARCH_PATTERNS=()
local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=3
[ ! ${SCWRYPTS_LOG_LEVEL} ] && local SCWRYPTS_LOG_LEVEL=3
local SHIFT_COUNT
while [[ $# -gt 0 ]]
do
SHIFT_COUNT=1
case $1 in
-[a-z][a-z]* )
( -[a-z][a-z]* )
VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
set -- throw-away $(echo " $VARSPLIT ") ${@:2}
set -- throw-away $(echo " ${VARSPLIT} ") ${@:2}
;;
### alternate commands ###################
-h | --help )
USAGE
( -h | --help )
utils.io.usage
return 0
;;
-l | --list )
SCWRYPTS__GET_AVAILABLE_SCWRYPTS
( -l | --list )
scwrypts.list-available
return 0
;;
--list-envs )
SCWRYPTS__GET_ENV_NAMES
( --list-envs )
scwrypts.environment.common.get-env-names
return 0
;;
--list-groups )
( --list-groups )
echo "${SCWRYPTS_GROUPS[@]}" | sed 's/\s\+/\n/g' | sort -u
return 0
;;
--version )
case $SCWRYPTS_INSTALLATION_TYPE in
manual ) echo "scwrypts $(GIT_SCWRYPTS describe --tags) (via GIT)" ;;
* ) echo "scwrypts $(cat "$SCWRYPTS_ROOT__scwrypts/VERSION")" ;;
( --version )
case ${SCWRYPTS_INSTALLATION_TYPE} in
( manual ) echo "scwrypts $(GIT_SCWRYPTS describe --tags) (via GIT)" ;;
( * ) echo "scwrypts $(cat "$(scwrypts.config.group scwrypts root)/VERSION")" ;;
esac
return 0
;;
--root )
echo "$SCWRYPTS_ROOT__scwrypts"
( --root )
scwrypts.config.group scwrypts root
return 0
;;
--config )
echo "source '$SCWRYPTS_ROOT__scwrypts/zsh/lib/import.driver.zsh'"
echo "CHECK_ENVIRONMENT --no-fail --no-usage"
( --config )
echo "source '$(scwrypts.config.group scwrypts root)/zsh/import.driver.zsh'"
echo "utils.check-environment --no-fail --no-usage"
echo "unset __SCWRYPT"
return 0
;;
--update )
case $SCWRYPTS_INSTALLATION_TYPE in
( --update )
case ${SCWRYPTS_INSTALLATION_TYPE} in
aur )
SCWRYPTS_LOG_LEVEL=3 REMINDER "
echo.reminder --force-print "
This installation is built from the AUR. Update through 'makepkg' or use
your preferred AUR package management tool (e.g. 'yay -Syu scwrypts')
"
;;
homebrew )
SCWRYPTS_LOG_LEVEL=3 REMINDER "This installation is managed by homebrew. Update me with 'brew update'"
echo.reminder --force-print "This installation is managed by homebrew. Update me with 'brew update'"
;;
manual )
@@ -135,22 +139,22 @@ source "$(dirname $(readlink -f "$0"))/zsh/lib/import.driver.zsh" || exit 42
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'
[[ ${SYNC_STATUS} -eq 0 ]] && [[ ${DIFF_STATUS} -eq 0 ]] && {
echo.success 'already up-to-date with origin/main'
} || {
GIT_SCWRYPTS rebase --autostash origin/main \
&& SUCCESS 'up-to-date with origin/main' \
&& echo.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 '$SCWRYPTS_ROOT__scwrypts'"
echo.error 'unable to update scwrypts; please try manual upgrade'
echo.reminder "installation in '$(scwrypts.config.group scwrypts root)'"
}
}
;;
* )
SCWRYPTS_LOG_LEVEL=3 REMINDER "
echo.reminder --force-print "
This is a managed installation of scwrypts. Please update through your
system package manager.
"
@@ -161,228 +165,236 @@ source "$(dirname $(readlink -f "$0"))/zsh/lib/import.driver.zsh" || exit 42
### scwrypts filters #####################
-m | --name )
( -m | --name )
((SHIFT_COUNT+=1))
[ $2 ] || { ERROR "missing value for argument $1"; break; }
[ $2 ] || { echo.error "missing value for argument $1"; break; }
SEARCH_NAME=$2
;;
-g | --group )
( -g | --group )
((SHIFT_COUNT+=1))
[ $2 ] || { ERROR "missing value for argument $1"; break; }
[ $2 ] || { echo.error "missing value for argument $1"; break; }
SEARCH_GROUP=$2
GROUP=$2
;;
-t | --type )
( -t | --type )
((SHIFT_COUNT+=1))
[ $2 ] || { ERROR "missing value for argument $1"; break; }
[ $2 ] || { echo.error "missing value for argument $1"; break; }
SEARCH_TYPE=$2
TYPE=$2
;;
### runtime settings #####################
-y | --yes ) export __SCWRYPTS_YES=1 ;;
( -y | --yes ) export __SCWRYPTS_YES=1 ;;
-n ) SCWRYPTS_LOG_LEVEL=0 ;;
( -n ) SCWRYPTS_LOG_LEVEL=0 ;;
-v | --log-level )
( -v | --log-level )
((SHIFT_COUNT+=1))
[[ $2 =~ ^[0-4]$ ]] || ERROR "invalid setting for log-level '$2'"
[[ $2 =~ ^[0-4]$ ]] || echo.error "invalid setting for log-level '$2'"
SCWRYPTS_LOG_LEVEL=$2
;;
-o | --output )
( -o | --output )
((SHIFT_COUNT+=1))
export SCWRYPTS_OUTPUT_FORMAT=$2
case $SCWRYPTS_OUTPUT_FORMAT in
pretty | json ) ;;
* ) ERROR "unsupported format '$SCWRYPTS_OUTPUT_FORMAT'" ;;
case ${SCWRYPTS_OUTPUT_FORMAT} in
( pretty | json ) ;;
* ) echo.error "unsupported format '${SCWRYPTS_OUTPUT_FORMAT}'" ;;
esac
;;
-e | --env )
( -e | --env )
((SHIFT_COUNT+=1))
[ $2 ] || { ERROR "missing value for argument $1"; break; }
[ $2 ] || { echo.error "missing value for argument $1"; break; }
[ $ENV_NAME ] && DEBUG 'overwriting session environment'
[ ${ENV_NAME} ] && echo.debug 'overwriting session environment'
ENV_NAME="$2"
STATUS "using CLI environment '$ENV_NAME'"
echo.status "using CLI environment '${ENV_NAME}'"
;;
##########################################
-- ) shift 1; break ;; # pass arguments after '--' to the scwrypt
--* ) ERROR "unrecognized argument '$1'" ;;
* ) SEARCH_PATTERNS+=($1) ;;
( -- ) shift 1; break ;; # pass arguments after '--' to the scwrypt
( --* ) echo.error "unrecognized argument '$1'" ;;
( * ) SEARCH_PATTERNS+=($1) ;;
esac
shift $SHIFT_COUNT
[[ ${SHIFT_COUNT} -le $# ]] \
&& shift ${SHIFT_COUNT} \
|| echo.error "missing argument for '$1'" \
|| shift $# \
;
done
[ $SCWRYPTS_OUTPUT_FORMAT ] || export SCWRYPTS_OUTPUT_FORMAT=pretty
[ ${SCWRYPTS_OUTPUT_FORMAT} ] || export SCWRYPTS_OUTPUT_FORMAT=pretty
[ $SEARCH_NAME ] && {
[ $SEARCH_TYPE ] || ERROR '--name requires --type argument'
[ $SEARCH_GROUP ] || ERROR '--name requires --group argument'
[ ${SEARCH_NAME} ] && {
[ ${SEARCH_TYPE} ] || echo.error '--name requires --type argument'
[ ${SEARCH_GROUP} ] || echo.error '--name requires --group argument'
}
CHECK_ERRORS
utils.check-errors --fail
#####################################################################
### scwrypts selection / filtering ##################################
#####################################################################
local SCWRYPTS_AVAILABLE
SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS)
local SCWRYPTS_AVAILABLE=$(scwrypts.list-available)
##########################################
[ $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_NAME} ] && SCWRYPTS_AVAILABLE=$({
echo ${SCWRYPTS_AVAILABLE} | head -n1
echo ${SCWRYPTS_AVAILABLE} | utils.colors.remove | grep "^${SEARCH_NAME} *${SEARCH_TYPE} *${SEARCH_GROUP}\$"
}) || {
[ $SEARCH_TYPE ] && {
[ ${SEARCH_TYPE} ] && {
SCWRYPTS_AVAILABLE=$(\
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep ' [^/]*'$SEARCH_TYPE'[^/]* '
echo ${SCWRYPTS_AVAILABLE} | head -n1
echo ${SCWRYPTS_AVAILABLE} | grep ' [^/]*'${SEARCH_TYPE}'[^/]* '
} \
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
| sed 's/ \+$/'$(utils.colors.reset)'/; s/ \+/^/g' \
| column -ts '^'
)
}
[ $SEARCH_GROUP ] && {
[ ${SEARCH_GROUP} ] && {
SCWRYPTS_AVAILABLE=$(
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep "$SEARCH_GROUP"'[^/ ]*$'
echo ${SCWRYPTS_AVAILABLE} | head -n1
echo ${SCWRYPTS_AVAILABLE} | grep "${SEARCH_GROUP}"'[^/ ]*$'
} \
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
| sed 's/ \+$/'$(utils.colors.reset)'/; s/ \+/^/g' \
| column -ts '^'
)
}
[[ ${#SEARCH_PATTERNS[@]} -gt 0 ]] && {
POTENTIAL_ERROR+="\n PATTERNS : $SEARCH_PATTERNS"
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
echo ${SCWRYPTS_AVAILABLE} | head -n1
echo ${SCWRYPTS_AVAILABLE} | grep ${P}
}
)
done
}
}
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -lt 2 ]] && {
FAIL 1 "$(echo "
[[ $(echo ${SCWRYPTS_AVAILABLE} | wc -l) -lt 2 ]] && {
utils.fail 1 "$(echo "
no such scwrypt exists
NAME : '$SEARCH_NAME'
TYPE : '$SEARCH_TYPE'
GROUP : '$SEARCH_GROUP'
PATTERNS : '$SEARCH_PATTERNS'
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) \
[[ $(echo ${SCWRYPTS_AVAILABLE} | wc -l) -eq 2 ]] \
&& SCWRYPT_SELECTION=$(echo ${SCWRYPTS_AVAILABLE} | tail -n1) \
|| SCWRYPT_SELECTION=$(echo ${SCWRYPTS_AVAILABLE} | utils.fzf "select a script to run" --header-lines 1) \
;
[ $SCWRYPT_SELECTION ] || exit 2
[ ${SCWRYPT_SELECTION} ] || utils.abort
##########################################
local NAME TYPE GROUP
SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
() {
set -- $(echo $@ | utils.colors.remove)
export SCWRYPT_NAME=$1
export SCWRYPT_TYPE=$2
export SCWRYPT_GROUP=$3
} ${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 ]] \
&& [ ! ${CI} ] \
&& [[ ! ${SCWRYPT_NAME} =~ scwrypts/logs ]] \
&& [[ ! ${SCWRYPT_NAME} =~ scwrypts/environment ]] \
|| ENV_REQUIRED=false
local REQUIRED_ENVIRONMENT_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$SCWRYPT_GROUP)
local REQUIRED_ENVIRONMENT_REGEX="$(scwrypts.config.group ${SCWRYPT_GROUP} required_environment_regex)"
[ $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)"
[ ${ENV_NAME} ] && [ ${REQUIRED_ENVIRONMENT_REGEX} ] && {
[[ ${ENV_NAME} =~ ${REQUIRED_ENVIRONMENT_REGEX} ]] \
|| utils.fail 5 "group '${SCWRYPT_GROUP}' requires current environment name to match '${REQUIRED_ENVIRONMENT_REGEX}' (currently ${ENV_NAME})"
}
[[ $ENV_REQUIRED =~ true ]] && {
[ ! $ENV_NAME ] && ENV_NAME=$(SCWRYPTS__SELECT_ENV)
[ ! $ENV_NAME ] && ABORT
[[ ${ENV_REQUIRED} =~ true ]] && {
[ ! ${ENV_NAME} ] && {
scwrypts.environment.init \
|| echo.error "failed to initialize scwrypts environments (see above)" \
|| return 1 \
;
export ENV_NAME
export SCWRYPTS_ENV=$ENV_NAME
ENV_NAME=$(scwrypts.environment.select-env)
[ "${ENV_NAME}" ] || user.abort
}
for GROUP in ${SCWRYPTS_GROUPS[@]}
do
local REQUIRED_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$GROUP)
[ $REQUIRED_REGEX ] && {
[[ $ENV_NAME =~ $REQUIRED_REGEX ]] || continue
local REQUIRED_REGEX="$(scwrypts.config.group ${GROUP} required_environment_regex)"
[ ${REQUIRED_REGEX} ] && {
[[ ${ENV_NAME} =~ ${REQUIRED_REGEX} ]] || continue
}
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)
for f in $(find "$(scwrypts.config.group ${GROUP} root)/.config/static" -type f 2>/dev/null)
do
source "$f" || FAIL 5 "invalid static config '$f'"
source "${f}" || utils.fail 5 "invalid static config '${f}'"
done
done
}
[ $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)"
[ ${REQUIRED_ENVIRONMENT_REGEX} ] && {
[[ ${ENV_NAME} =~ ${REQUIRED_ENVIRONMENT_REGEX} ]] \
|| utils.fail 5 "group '${SCWRYPT_GROUP}' requires current environment name to match '${REQUIRED_ENVIRONMENT_REGEX}' (currently ${ENV_NAME})"
}
export SCWRYPTS_ENV=${ENV_NAME}
##########################################
[ ! $SUBSCWRYPT ] && export SUBSCWRYPT=0
[ ! ${SUBSCWRYPT} ] && export SUBSCWRYPT=0
[[ $SCWRYPTS_INSTALLATION_TYPE =~ ^manual$ ]] && {
[[ $SUBSCWRYPT -eq 0 ]] && [[ $ENV_NAME =~ prod ]] && [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] && {
STATUS "on '$ENV_NAME'; checking diff against origin/main"
[[ ${SCWRYPTS_INSTALLATION_TYPE} =~ ^manual$ ]] && {
[[ ${SUBSCWRYPT} -eq 0 ]] && [[ ${SCWRYPTS_ENV} =~ prod ]] && [[ ${SCWRYPTS_LOG_LEVEL} -gt 0 ]] && {
echo.status "on '${SCWRYPTS_ENV}'; checking diff against origin/main"
local WARNING_MESSAGE
[ ! $WARNING_MESSAGE ] && {
[ ! ${WARNING_MESSAGE} ] && {
GIT_SCWRYPTS fetch --quiet origin main \
|| WARNING_MESSAGE='I am unable to verify your scwrypts version'
}
[ ! $WARNING_MESSAGE ] && {
[ ! ${WARNING_MESSAGE} ] && {
GIT_SCWRYPTS diff --exit-code origin/main -- . >/dev/null 2>&1 \
|| WARNING_MESSAGE='your scwrypts is currently out-of-date'
}
[ $WARNING_MESSAGE ] && {
[[ $SCWRYPTS_LOG_LEVEL -lt 3 ]] && {
REMINDER "you are running in ${__BRIGHT_RED}production${__BRIGHT_MAGENTA} and $WARNING_MESSAGE"
[ ${WARNING_MESSAGE} ] && {
[[ ${SCWRYPTS_LOG_LEVEL} -lt 3 ]] && {
echo.reminder "you are running in $(utils.colors.bright-red)production$(utils.colors.bright-magenta) and ${WARNING_MESSAGE}"
} || {
GIT_SCWRYPTS diff --exit-code origin/main -- . >&2
WARNING "you are trying to run in ${__BRIGHT_RED}production${__YELLOW} but $WARNING_MESSAGE (relevant diffs and errors above)"
echo.warning "you are trying to run in $(utils.colors.bright-red)production$(echo.warning.color) but ${WARNING_MESSAGE} (relevant diffs and errors above)"
yN 'continue?' || {
REMINDER "you can use 'scwrypts --update' to quickly update scwrypts to latest"
ABORT
echo.reminder "you can use 'scwrypts --update' to quickly update scwrypts to latest"
user.abort
}
}
}
@@ -391,92 +403,123 @@ source "$(dirname $(readlink -f "$0"))/zsh/lib/import.driver.zsh" || exit 42
##########################################
local RUN_STRING=$(SCWRYPTS__GET_RUNSTRING $SCWRYPT_NAME $SCWRYPT_TYPE $SCWRYPT_GROUP)
[ "$RUN_STRING" ] || return 42
local RUN_STRING=$(scwrypts.get-runstring ${SCWRYPT_NAME} ${SCWRYPT_TYPE} ${SCWRYPT_GROUP})
[ "${RUN_STRING}" ] || return 42
#####################################################################
### logging and pretty header/footer setup ##########################
#####################################################################
local RUN_MODE=normal
[[ ${SCWRYPT_NAME} =~ interactive ]] && RUN_MODE=interactive
local LOGFILE \
&& [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] \
&& [[ $SUBSCWRYPT -eq 0 ]] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
&& [[ ! $SCWRYPT_NAME =~ interactive ]] \
&& LOGFILE="$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log" \
&& [[ ${RUN_MODE} =~ normal ]] \
&& [[ ${SCWRYPTS_LOG_LEVEL} -gt 0 ]] \
&& [[ ${SUBSCWRYPT} -eq 0 ]] \
&& [[ ! ${SCWRYPT_NAME} =~ scwrypts/logs ]] \
&& 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 ]] && {
case $SCWRYPTS_OUTPUT_FORMAT in
pretty )
[[ ${SCWRYPTS_LOG_LEVEL} -ge 2 ]] && {
case ${SCWRYPTS_OUTPUT_FORMAT} in
( raw )
HEADER="--- start scwrypt ${SCWRYPT_GROUP}/${SCWRYPT_TYPE} ${SCWRYPT_NAME} in ${SCWRYPTS_ENV} ---"
FOOTER="--- end scwrypt ---"
;;
( pretty )
HEADER=$(
echo "
=====================================================================
scwrypt : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME
scwrypt : ${SCWRYPT_GROUP} ${SCWRYPT_TYPE} ${SCWRYPT_NAME}
run at : $(date)
config : $ENV_NAME
log level : $SCWRYPTS_LOG_LEVEL
\\033[1;33m--- SCWRYPT BEGIN ---------------------------------------------------\\033[0m
config : ${SCWRYPTS_ENV}
log level : ${SCWRYPTS_LOG_LEVEL}
$(utils.colors.print bright-yellow '--- SCWRYPT BEGIN ---------------------------------------------------')
" | sed 's/^\s\+//; 1d'
)
FOOTER="\\033[1;33m--- SCWRYPT END ---------------------------------------------------\\033[0m"
FOOTER="$(utils.colors.print bright-yellow '--- SCWRYPT END ---------------------------------------------------')"
;;
json )
( json )
HEADER=$(echo '{}' | jq -c ".
| .timestamp = \"$(date +%s)\"
| .runtime = \"$SCWRYPTS_RUNTIME_ID\"
| .scwrypt = \"start of $SCWRYPT_NAME $SCWRYPT_GROUP $SCWRYPT_TYPE\"
| .config = \"$ENV_NAME\"
| .logLevel = \"$SCWRYPTS_LOG_LEVEL\"
| .subscwrypt = $SUBSCWRYPT
| .runtime = \"${SCWRYPTS_RUNTIME_ID}\"
| .scwrypt = \"start of ${SCWRYPT_NAME} ${SCWRYPT_GROUP} ${SCWRYPT_TYPE}\"
| .config = \"${SCWRYPTS_ENV}\"
| .logLevel = \"${SCWRYPTS_LOG_LEVEL}\"
| .subscwrypt = ${SUBSCWRYPT}
")
;;
esac
}
[[ $SUBSCWRYPT -eq 0 ]] || {
case $SCWRYPTS_OUTPUT_FORMAT in
pretty )
HEADER="\\033[0;33m--- ($SUBSCWRYPT) BEGIN $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
FOOTER="\\033[0;33m--- ($SUBSCWRYPT) END $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
[[ ${SUBSCWRYPT} -eq 0 ]] || {
case ${SCWRYPTS_OUTPUT_FORMAT} in
( pretty )
HEADER="$(utils.colors.print yellow "--- (${SUBSCWRYPT}) BEGIN ${SCWRYPT_GROUP} ${SCWRYPT_TYPE} ${SCWRYPT_NAME} ---")"
FOOTER="$(utils.colors.print yellow "--- (${SUBSCWRYPT}) END ${SCWRYPT_GROUP} ${SCWRYPT_TYPE} ${SCWRYPT_NAME} ---")"
;;
esac
}
#####################################################################
### run the scwrypt #################################################
#####################################################################
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'
[[ ${SCWRYPTS_LOG_LEVEL} -ge 2 ]] && __SCWRYPTS_PRINT_EXIT_CODE=true
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && [ ! $SUBSCWRYPT ] \
&& echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
[ ${HEADER} ] && echo ${HEADER} >&2
return $EXIT_CODE
} | tee --append "$LOGFILE"
(
case ${RUN_MODE} in
( normal )
eval "${RUN_STRING} $(printf "%q " "$@")"
;;
( interactive )
eval "${RUN_STRING} $(printf "%q " "$@")" </dev/tty &>/dev/tty
;;
esac
)
EXIT_CODE=$?
[ ${FOOTER} ] && echo ${FOOTER} >&2
[[ ${__SCWRYPTS_PRINT_EXIT_CODE} =~ true ]] && {
EXIT_COLOR=$( [[ ${EXIT_CODE} -eq 0 ]] && utils.colors.bright-green || utils.colors.bright-red )
case ${SCWRYPTS_OUTPUT_FORMAT} in
( raw )
echo "terminated with code ${EXIT_CODE}" >&2
;;
( pretty )
echo "terminated with ${EXIT_COLOR}code ${EXIT_CODE}$(utils.colors.reset)" >&2
;;
( json )
[[ ${EXIT_CODE} =~ 0 ]] \
&& echo.success --force-print "terminated with code ${EXIT_CODE}" \
|| echo.error --force-print "terminated with code ${EXID_CODE}" \
;
;;
esac
}
return ${EXIT_CODE}
} | tee --append "${LOGFILE}"
} $@
EXIT_CODE=$?
[ "${SCWRYPTS_TEMP_PATH}" ] && [ -d "${SCWRYPTS_TEMP_PATH}" ] \
&& {
rm -- $(find "${SCWRYPTS_TEMP_PATH}" -mindepth 1 -maxdepth 1 -type f)
rmdir "${SCWRYPTS_TEMP_PATH}"
} &>/dev/null
return ${EXIT_CODE}