introduce --verbosity flag rather than mixed logging settings; correct color misnaming to ANSI convention; added sanity-check; simplified hello-world; created FZF_USER_INPUT to replace the confusing FZF_HEAD and FZF_TAIL

This commit is contained in:
Wryn (yage) Wagner 2024-02-07 15:14:36 -07:00
parent fcf492c661
commit 261bbee1a4
11 changed files with 419 additions and 226 deletions

45
run
View File

@ -18,9 +18,13 @@ __RUN() {
runtime runtime
-y, --yes auto-accept all [yn] prompts through current scwrypt -y, --yes auto-accept all [yn] prompts through current scwrypt
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV -e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
-q, --quiet run in quiet mode -n shorthand for "--verbosity 0"
-n, --no-log skip the log file and run in quiet mode -v, --verbosity [0-4] set scwrypts log level to one of the following:
-v, --verbose override quiet mode settings and print all debug dialogue 0 : only command output and critical failures; skips logfile
1 : add success / failure messages
2 : (default) include status update messages
3 : include warning messages
4 : include debug messages
alternate commands alternate commands
-h, --help display this message and exit -h, --help display this message and exit
@ -44,9 +48,9 @@ __RUN() {
local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME
local ALLOW_LOGFILE=1 local ALLOW_LOGFILE=1
local VERBOSE=1 local SCWRYPTS_LOG_LEVEL=2
[ $CI ] && [ ! $SCWRYPTS_CI_FORCE_NON_VERBOSE ] && VERBOSE=2 [ $CI ] && [ ! $SCWRYPTS_CI_FORCE_NON_VERBOSE ] && SCWRYPTS_LOG_LEVEL=3
local ERROR=0 local ERROR=0
@ -108,9 +112,8 @@ __RUN() {
;; ;;
-y | --yes ) export __SCWRYPTS_YES=1 ;; -y | --yes ) export __SCWRYPTS_YES=1 ;;
-q | --quiet ) VERBOSE=0 ;; -n | --no-log ) SCWRYPTS_LOG_LEVEL=0 ;;
-n | --no-log ) VERBOSE=0 ; [ ! $SUBSCWRYPT ] && SUBSCWRYPT=0 ;; -v | --verbosity ) SCWRYPTS_LOG_LEVEL=$2 ;;
-v | --verbose ) VERBOSE=2 ;;
-e | --env ) -e | --env )
[ ! $2 ] && ERROR "missing value for argument $1" && break [ ! $2 ] && ERROR "missing value for argument $1" && break
@ -210,7 +213,6 @@ __RUN() {
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -eq 2 ]] && { [[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -eq 2 ]] && {
SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | tail -n1) SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | tail -n1)
[[ $VERBOSE -eq 2 ]] || VERBOSE=0
} || { } || {
SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | FZF "select a script to run" --header-lines 1) SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | FZF "select a script to run" --header-lines 1)
} }
@ -271,12 +273,13 @@ __RUN() {
local LOGFILE=$(__GET_LOGFILE) local LOGFILE=$(__GET_LOGFILE)
local HEADER=$( local HEADER=$(
[[ $VERBOSE -gt 0 ]] || return 0 [[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] || return 0
[ $SUBSCWRYPT ] && return 0 [ $SUBSCWRYPT ] && return 0
echo '=====================================================================' echo '====================================================================='
echo "script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME" echo "script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME"
echo "run at : $(date)" echo "run at : $(date)"
echo "config : $ENV_NAME" echo "config : $ENV_NAME"
echo "verbosity : $SCWRYPTS_LOG_LEVEL"
[ ! $LOGFILE ] && echo '\033[1;33m------------------------------------------\033[0m' [ ! $LOGFILE ] && echo '\033[1;33m------------------------------------------\033[0m'
) )
@ -291,22 +294,19 @@ __RUN() {
} }
} }
set -o pipefail
{ {
[ $HEADER ] && echo $HEADER [ $HEADER ] && echo $HEADER
[[ $VERBOSE -gt 0 ]] && echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m' [[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m'
(eval "$RUN_STRING $(printf "%q " "$@")") (eval "$RUN_STRING $(printf "%q " "$@")")
EXIT_CODE=$? export EXIT_CODE=$?
[[ $VERBOSE -gt 0 ]] && echo '\033[1;33m--- END OUTPUT ---------------------------\033[0m' [[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && echo '\033[1;33m--- END OUTPUT ---------------------------\033[0m'
[[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m' [[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m'
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
[[ $VERBOSE -gt 0 ]] && echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m" return $EXIT_CODE
} 2>&1 | tee --append "$LOGFILE" } 2>&1 | tee --append "$LOGFILE"
exit $(\
sed -n 's/^terminated with.*code \([0-9]*\).*$/\1/p' $LOGFILE \
| tail -n1
)
} }
##################################################################### #####################################################################
@ -343,6 +343,7 @@ __VALIDATE_UPSTREAM_TIMELINE() {
__GET_LOGFILE() { __GET_LOGFILE() {
[ $SUBSCWRYPT ] && return 0 [ $SUBSCWRYPT ] && return 0
[[ $SCWRYPTS_LOG_LEVEL -eq 0 ]] && return 0
[[ $SCWRYPT_NAME =~ scwrypts/logs ]] && return 0 [[ $SCWRYPT_NAME =~ scwrypts/logs ]] && return 0
[[ $SCWRYPT_NAME =~ interactive ]] && return 0 [[ $SCWRYPT_NAME =~ interactive ]] && return 0

View File

@ -1,4 +1,6 @@
#!/bin/zsh #!/bin/zsh
#####################################################################
MAIN() { MAIN() {
SUCCESS 'hello world!' SUCCESS 'Hello, World!'
} }

View File

@ -119,12 +119,51 @@ SCWRYPTS__GET_RUNSTRING__zsh() {
|| SCWRYPT_FILENAME="$GROUP_PATH/$SCWRYPT_TYPE/$SCWRYPT_NAME" \ || SCWRYPT_FILENAME="$GROUP_PATH/$SCWRYPT_TYPE/$SCWRYPT_NAME" \
; ;
echo "source '$SCWRYPT_FILENAME'; CHECK_ENVIRONMENT; MAIN" printf "
source '$SCWRYPT_FILENAME'
CHECK_ENVIRONMENT
ERRORS=0
export USAGE=\"
usage: -
args: -
options: -
-h, --help display this message and exit
-v, --verbose output debugging information
description: -
\"
[ ! \$USAGE__usage ] && export USAGE__usage='[...options...]'
() {
local MAIN_ARGS=()
local VARSPLIT
while [[ \$# -gt 0 ]]
do
case \$1 in
-[a-z][a-z]* )
VARSPLIT=\$(echo \"\$1 \" | sed 's/^\\\\(-.\\\\)\\\\(.*\\\\) /\\\\1 -\\\\2/')
set -- throw-away \$(echo \" \$VARSPLIT \") \${@:2}
;;
-h | --help ) USAGE; exit 0 ;;
-v | --verbose ) INFO \"setting SCWRYPTS_LOG_LEVEL to 'debug'\"; export SCWRYPTS_LOG_LEVEL=debug ;;
* ) MAIN_ARGS+=(\$1) ;;
esac
shift 1
done
MAIN \${MAIN_ARGS[@]}
} "
return 0 return 0
} }
SCWRYPTS__GET_RUNSTRING__zsh_v3_compatibility() { SCWRYPTS__GET_RUNSTRING__zsh_v3() {
WARNING "scwrypts zsh/v3 runstrings are now deprecated; please update to scwrypts v4 format"
__CHECK_DEPENDENCY zsh || return 1 __CHECK_DEPENDENCY zsh || return 1
[ $(eval echo '$SCWRYPTS_TYPE__'$SCWRYPT_GROUP) ] \ [ $(eval echo '$SCWRYPTS_TYPE__'$SCWRYPT_GROUP) ] \
@ -132,8 +171,6 @@ SCWRYPTS__GET_RUNSTRING__zsh_v3_compatibility() {
|| echo "source $GROUP_PATH/$SCWRYPT_TYPE/$SCWRYPT_NAME" \ || echo "source $GROUP_PATH/$SCWRYPT_TYPE/$SCWRYPT_NAME" \
; ;
WARNING "scwrypts zsh/v3 runstrings are now deprecated; please update to scwrypts v4 format"
return 0 return 0
} }

View File

@ -2,22 +2,22 @@ __BLACK='\033[0;30m'
__DARK_GRAY='\033[1;30m' __DARK_GRAY='\033[1;30m'
__RED='\033[0;31m' __RED='\033[0;31m'
__LIGHT_RED='\033[1;31m' __BRIGHT_RED='\033[1;31m'
__GREEN='\033[0;32m' __GREEN='\033[0;32m'
__LIGHT_GREEN='\033[1;32m' __BRIGHT_GREEN='\033[1;32m'
__ORANGE='\033[0;33m' __YELLOW='\033[0;33m'
__YELLOW='\033[1;33m' __BRIGHT_YELLOW='\033[1;33m'
__BLUE='\033[1;34m' __BLUE='\033[0;34m'
__DARK_BLUE='\033[0;34m' __BRIGHT_BLUE='\033[1;34m'
__PURPLE='\033[1;35m' __MAGENTA='\033[0;35m'
__DARK_PURPLE='\033[0;35m' __BRIGHT_MAGENTA='\033[1;35m'
__CYAN='\033[1;36m' __CYAN='\033[0;36m'
__DARK_CYAN='\033[0;36m' __BRIGHT_CYAN='\033[1;36m'
__WHITE='\033[1;37m' __WHITE='\033[1;37m'
__LIGHT_GRAY='\033[0;37m' __LIGHT_GRAY='\033[0;37m'
@ -27,17 +27,17 @@ __COLOR_RESET='\033[0m'
__GET_RANDOM_COLOR() { __GET_RANDOM_COLOR() {
local COLORS=( local COLORS=(
$__RED $__RED
$__LIGHT_RED $__BRIGHT_RED
$__GREEN $__GREEN
$__LIGHT_GREEN $__BRIGHT_GREEN
$__ORANGE
$__YELLOW $__YELLOW
$__BRIGHT_YELLOW
$__BLUE $__BLUE
$__DARK_BLUE $__BRIGHT_BLUE
$__PURPLE $__MAGENTA
$__DARK_PURPLE $__BRIGHT_MAGENTA
$__CYAN $__CYAN
$__DARK_CYAN $__BRIGHT_CYAN
$__WHITE $__WHITE
) )
print "$__COLOR_RESET${COLORS[$(shuf -i 1-${#COLORS[@]} -n 1)]}" print "$__COLOR_RESET${COLORS[$(shuf -i 1-${#COLORS[@]} -n 1)]}"

View File

@ -1,13 +1,14 @@
__CHECK_DEPENDENCIES() { __CHECK_DEPENDENCIES() {
local DEP ERROR=0 local DEP ERRORS=0
local SCWRYPTS_LOG_LEVEL=1
[ ! $E ] && E=ERROR [ ! $E ] && E=ERROR
DEPENDENCIES=($(echo $DEPENDENCIES | sed 's/ \+/\n/g' | sort -u)) DEPENDENCIES=($(echo $DEPENDENCIES | sed 's/ \+/\n/g' | sort -u))
for DEP in ${DEPENDENCIES[@]}; do __CHECK_DEPENDENCY $DEP || ((ERROR+=1)); done for DEP in ${DEPENDENCIES[@]}; do __CHECK_DEPENDENCY $DEP || ((ERRORS+=1)); done
__CHECK_COREUTILS || ((ERROR+=$?)) __CHECK_COREUTILS || ((ERRORS+=$?))
return $ERROR return $ERRORS
} }
__CHECK_DEPENDENCY() { __CHECK_DEPENDENCY() {

View File

@ -1,4 +1,5 @@
__CHECK_REQUIRED_ENV() { __CHECK_REQUIRED_ENV() {
local SCWRYPTS_LOG_LEVEL=1
local VAR ERROR=0 local VAR ERROR=0
REQUIRED_ENV=($(echo $REQUIRED_ENV | sed 's/\s\+/\n/g' | sort -u)) REQUIRED_ENV=($(echo $REQUIRED_ENV | sed 's/\s\+/\n/g' | sort -u))
for VAR in ${REQUIRED_ENV[@]}; do __CHECK_ENV_VAR $VAR || ((ERROR+=1)); done for VAR in ${REQUIRED_ENV[@]}; do __CHECK_ENV_VAR $VAR || ((ERROR+=1)); done

57
zsh/lib/utils/io.fzf.zsh Normal file
View File

@ -0,0 +1,57 @@
FZF() {
[ $CI ] && FAIL 1 'currently in CI, but FZF requires user input'
local FZF_ARGS=()
FZF_ARGS+=(-i)
FZF_ARGS+=(--ansi)
FZF_ARGS+=(--bind=ctrl-c:cancel)
FZF_ARGS+=(--height=50%)
FZF_ARGS+=(--layout=reverse)
local SELECTION=$(fzf ${FZF_ARGS[@]} --prompt "$1 : " ${@:2})
PROMPT "$1"
[ $BE_QUIET ] || {
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] && echo $SELECTION >&2
}
echo $SELECTION
[ $SELECTION ]
}
FZF_USER_INPUT() { # allow user to type custom answers; reconfirm if ambiguous with select
local FZF_OUTPUT=$(BE_QUIET=1 FZF $@ --print-query | sed '/^$/d' | sort -u)
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] && echo $FZF_OUTPUT | head -n1 >&2
[ ! $FZF_OUTPUT ] && return 1
[[ $(echo "$FZF_OUTPUT" | wc -l) -eq 1 ]] \
&& { echo "$FZF_OUTPUT"; return 0; }
local FZF_OUTPUT=$(
echo "$FZF_OUTPUT" \
| sed "1s/\$/^$(printf "$__LIGHT_GRAY\\033[3m")<- what you typed$(printf $__COLOR_RESET)/" \
| sed "2s/\$/^$(printf "$__LIGHT_GRAY\\033[3m")<- what you selected$(printf $__COLOR_RESET)/" \
| column -ts '^' \
| BE_QUIET=1 FZF "$@ (clarify)" \
)
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] && echo $FZF_OUTPUT >&2
FZF_OUTPUT=$(echo $FZF_OUTPUT | sed 's/\s\+<- what you .*$//')
echo $FZF_OUTPUT
[ $FZF_OUTPUT ]
}
#####################################################################
### vvv DEPRECATED vvv ##############################################
#####################################################################
FZF_HEAD() { # prefer user input over selected
WARNING 'FZF_HEAD is deprecated; please switch to FZF_USER_INPUT (drop-in fix!)'
FZF $@ --print-query | sed '/^$/d' | head -n1;
}
FZF_TAIL() { # prefer selected over user input
WARNING 'FZF_TAIL is deprecated; please switch to FZF_USER_INPUT (drop-in fix!)'
FZF $@ --print-query | sed '/^$/d' | tail -n1;
}
#####################################################################

View File

@ -0,0 +1,38 @@
PRINT() {
local MESSAGE
local LAST_LINE_END='\n'
local STDERR=1
local STDOUT=0
local LTRIM=1
while [[ $# -gt 0 ]]
do
case $1 in
-n | --no-trim-tabs ) LTRIM=0 ;;
-x | --no-line-end ) LAST_LINE_END='' ;;
-o | --use-stdout ) STDOUT=1; STDERR=0 ;;
* ) MESSAGE+="$(echo $1) " ;;
esac
shift 1
done
MESSAGE="$(echo "$MESSAGE" | sed 's/%/%%/g')"
local STYLED_MESSAGE="$({
printf "${COLOR}"
while IFS='' read line
do
[[ $PREFIX =~ ^[[:space:]]\+$ ]] && printf '\n'
printf "${PREFIX} : $(echo "$line" | sed 's/^ \+//; s/ \+$//')"
PREFIX=$(echo $PREFIX | sed 's/./ /g')
done <<< $MESSAGE
})"
STYLED_MESSAGE="${COLOR}$(echo "$STYLED_MESSAGE" | sed 's/%/%%/g')${__COLOR_RESET}${LAST_LINE_END}"
[[ $STDERR -eq 1 ]] && printf $STYLED_MESSAGE >&2
[[ $STDOUT -eq 1 ]] && printf $STYLED_MESSAGE
return 0
}

View File

@ -0,0 +1,65 @@
USAGE() { # formatter for USAGE variable
[ ! $USAGE ] && return 0
local USAGE_LINE=$(echo $USAGE | grep -i '^[ ]*usage *:' | sed 's/^[ ]*//')
[ $USAGE__usage ] && echo $USAGE_LINE | grep -q 'usage: -' \
&& USAGE_LINE=$(echo $USAGE_LINE | sed "s/usage: -/usage: $USAGE__usage/")
[ $__SCWRYPT ] \
&& USAGE_LINE=$(
echo $USAGE_LINE \
| sed "s;^[^:]*:;& scwrypts $SCWRYPT_NAME --;" \
| sed 's/ \{2,\}/ /g; s/scwrypts -- scwrypts/scwrypts/' \
)
local THE_REST=$(echo $USAGE | grep -vi '^[ ]*usage *:' )
local DYNAMIC_USAGE_ELEMENT
#
# create dynamic usage elements (like 'args') by defining USAGE__<element>
# then using the syntax "<element>: -" in your USAGE variable
#
# e.g.
#
# USAGE__args="
# subcommand arg 1 arg 1 description
# subcommand arg 2 some other description
# "
#
# USAGE="
# usage: some-command [...args...]
#
# args: -
# -h, --help some arguments are applicable everywhere
# "
#
for DYNAMIC_USAGE_ELEMENT in $(echo $THE_REST | sed -n 's/^\([^:]*\): -$/\1/p')
do
DYNAMIC_USAGE_ELEMENT_TEXT=$(eval echo '$USAGE__'$DYNAMIC_USAGE_ELEMENT)
#[ $DYNAMIC_USAGE_ELEMENT_TEXT ] || continue
case $DYNAMIC_USAGE_ELEMENT in
description )
DYNAMIC_USAGE_ELEMENT_TEXT=$(echo "$DYNAMIC_USAGE_ELEMENT_TEXT" | perl -p0e 's/^[\n\s]+//')
DYNAMIC_USAGE_ELEMENT_TEXT="$__YELLOW\\033[03m$DYNAMIC_USAGE_ELEMENT_TEXT\\033[0m"
;;
* )
DYNAMIC_USAGE_ELEMENT_TEXT=$(echo $DYNAMIC_USAGE_ELEMENT_TEXT | sed 's/[^ ]/ &/')
;;
esac
THE_REST=$(echo $THE_REST | perl -pe "s$DYNAMIC_USAGE_ELEMENT: -$DYNAMIC_USAGE_ELEMENT:\n$DYNAMIC_USAGE_ELEMENT_TEXT\n\n")
done
# allow for dynamic 'description: -' but delete the 'description:' header line
THE_REST=$(echo $THE_REST | sed '/^[ ]*description:$/d')
echo "$__BLUE$USAGE_LINE$__COLOR_RESET\n\n$THE_REST" \
| sed "s/^\t\+//; s/\s\+$//; s/^\\s*$//;" \
| sed '/./,$!d; :a; /^\n*$/{$d;N;ba;};' \
| perl -p0e 's/\n{2,}/\n\n/g' \
| perl -p0e 's/:\n{2,}/:\n/g' \
| perl -p0e 's/([a-z]+:)\n([a-z]+:)/\2/g' \
>&2
}

View File

@ -1,216 +1,115 @@
PRINT() { #####################################################################
local MESSAGE ### basic colorized print messages ##################################
local LAST_LINE_END='\n' #####################################################################
local STDERR=1
local STDOUT=0
local LTRIM=1
while [[ $# -gt 0 ]]
do
case $1 in
-n | --no-trim-tabs ) LTRIM=0 ;;
-x | --no-line-end ) LAST_LINE_END='' ;;
-o | --use-stdout ) STDOUT=1; STDERR=0 ;;
* ) MESSAGE+="$(echo $1) " ;;
esac
shift 1
done
MESSAGE="$(echo "$MESSAGE" | sed 's/%/%%/g')"
local STYLED_MESSAGE="$({
printf "${COLOR}"
while IFS='' read line
do
[[ $PREFIX =~ ^[[:space:]]\+$ ]] && printf '\n'
printf "${PREFIX} : $(echo "$line" | sed 's/^ \+//; s/ \+$//')"
PREFIX=$(echo $PREFIX | sed 's/./ /g')
done <<< $MESSAGE
})"
STYLED_MESSAGE="${COLOR}$(echo "$STYLED_MESSAGE" | sed 's/%/%%/g')${__COLOR_RESET}${LAST_LINE_END}"
[[ $STDERR -eq 1 ]] && printf $STYLED_MESSAGE >&2
[[ $STDOUT -eq 1 ]] && printf $STYLED_MESSAGE
return 0
}
source "${0:a:h}/io.print.zsh"
[ ! $ERRORS ] && ERRORS=0 [ ! $ERRORS ] && ERRORS=0
ERROR() { PREFIX="ERROR ✖" COLOR=$__RED PRINT "$@"; ((ERRORS+=1)); }
SUCCESS() { PREFIX="SUCCESS ✔" COLOR=$__GREEN PRINT "$@"; }
WARNING() { PREFIX="WARNING " COLOR=$__ORANGE PRINT "$@"; }
STATUS() { PREFIX="STATUS " COLOR=$__BLUE PRINT "$@"; }
REMINDER() { PREFIX="REMINDER " COLOR=$__PURPLE PRINT "$@"; }
INFO() { PREFIX="INFO " COLOR=$__WHITE PRINT "$@"; }
PROMPT() {
PREFIX="PROMPT " COLOR=$__CYAN PRINT "$@"
PREFIX="USER ⌨" COLOR=$__CYAN PRINT '' --no-line-end
}
FAIL() { ERROR "${@:2}"; exit $1; }
ABORT() { FAIL 69 'user abort'; }
CHECK_ERRORS() {
local FAIL_OUT=1
local DISPLAY_USAGE=1
while [[ $# -gt 0 ]]
do
case $1 in
--no-fail ) FAIL_OUT=0 ;;
--no-usage ) DISPLAY_USAGE=0 ;;
esac
shift 1
done
[ ! $ERRORS ] && ERRORS=0
[[ $ERRORS -eq 0 ]] && return 0
[[ $DISPLAY_USAGE -eq 1 ]] && USAGE
[[ $FAIL_OUT -eq 1 ]] && exit $ERRORS
ERROR() { # command encountered an error
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="ERROR ✖" COLOR=$__RED PRINT "$@"
((ERRORS+=1))
return $ERRORS return $ERRORS
} }
USAGE() { # formatter for USAGE variable SUCCESS() { # command completed successfully
[ ! $USAGE ] && return 0 [[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
local USAGE_LINE=$(echo $USAGE | grep -i '^[ ]*usage *:' | sed 's/^[ ]*//') && PREFIX="SUCCESS ✔" COLOR=$__GREEN PRINT "$@"
}
[ $USAGE__usage ] && echo $USAGE_LINE | grep -q 'usage: -' \ REMINDER() { # include sysadmin reminder or other important notice to users
&& USAGE_LINE=$(echo $USAGE_LINE | sed "s/usage: -/usage: $USAGE__usage/") [[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="REMINDER " COLOR=$__BRIGHT_MAGENTA PRINT "$@"
}
[ $__SCWRYPT ] \ STATUS() { # general status updates (prefer this to generic 'echo')
&& USAGE_LINE=$( [[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] \
echo $USAGE_LINE \ && PREFIX="STATUS " COLOR=$__BLUE PRINT "$@"
| sed "s;^[^:]*:;& scwrypts $SCWRYPT_NAME --;" \ }
| sed 's/ \{2,\}/ /g; s/scwrypts -- scwrypts/scwrypts/' \
)
local THE_REST=$(echo $USAGE | grep -vi '^[ ]*usage *:' ) WARNING() { # warning-level messages; not errors
[[ $SCWRYPTS_LOG_LEVEL -ge 3 ]] \
&& PREFIX="WARNING " COLOR=$__YELLOW PRINT "$@"
}
local DYNAMIC_USAGE_ELEMENT DEBUG() { # helpful during development or (sparingly) to help others' development
# [[ $SCWRYPTS_LOG_LEVEL -gt 4 ]] \
# create dynamic usage elements (like 'args') by defining USAGE__<element> && PREFIX="DEBUG " COLOR=$__WHITE PRINT "$@"
# then using the syntax "<element>: -" in your USAGE variable }
#
# e.g. PROMPT() { # you probably want to use yN or INPUT from below
# [[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
# USAGE__args=" && PREFIX="PROMPT " COLOR=$__CYAN PRINT "$@" \
# subcommand arg 1 arg 1 description && PREFIX="USER ⌨" COLOR=$__BRIGHT_CYAN PRINT '' --no-line-end \
# subcommand arg 2 some other description ;
# " }
#
# USAGE=" FAIL() { SCWRYPTS_LOG_LEVEL=1 ERROR "${@:2}"; exit $1; }
# usage: some-command [...args...] ABORT() { FAIL 69 'user abort'; }
#
# args: - #####################################################################
# -h, --help some arguments are applicable everywhere ### check for reported errors and format USAGE contents #############
# " #####################################################################
#
for DYNAMIC_USAGE_ELEMENT in $(echo $THE_REST | sed -n 's/^\([^:]*\): -$/\1/p') CHECK_ERRORS() {
local FAIL_OUT=true
local DISPLAY_USAGE=true
[ ! $ERRORS ] && ERRORS=0
while [[ $# -gt 0 ]]
do do
DYNAMIC_USAGE_ELEMENT_TEXT=$(eval echo '$USAGE__'$DYNAMIC_USAGE_ELEMENT) case $1 in
--fail ) FAIL_OUT=true ;;
--no-fail ) FAIL_OUT=false ;;
[[ ! $DYNAMIC_USAGE_ELEMENT =~ ^description$ ]] \ --usage ) DISPLAY_USAGE=true ;;
&& DYNAMIC_USAGE_ELEMENT_TEXT=$(echo $DYNAMIC_USAGE_ELEMENT_TEXT | sed 's/[^ ]/ &/') --no-usage ) DISPLAY_USAGE=false ;;
esac
THE_REST=$(echo $THE_REST | perl -pe "s/$DYNAMIC_USAGE_ELEMENT: -/$DYNAMIC_USAGE_ELEMENT:\n$DYNAMIC_USAGE_ELEMENT_TEXT\n\n/") shift 1
done done
# allow for dynamic 'description: -' but delete the 'description:' header line [[ $ERRORS -eq 0 ]] && return 0
THE_REST=$(echo $THE_REST | sed '/^[ ]*description:$/d')
echo "$__DARK_BLUE$USAGE_LINE$__COLOR_RESET\n\n$THE_REST" \ [[ $DISPLAY_USAGE =~ true ]] && USAGE
| sed "s/^\t\+//; s/\s\+$//; s/^\\s*$//;" \
| sed '/./,$!d; :a; /^\n*$/{$d;N;ba;};' \ [[ $FAIL_OUT =~ true ]] && exit $ERRORS || return $ERRORS
| perl -p0e 's/\n{2,}/\n\n/g' \
| perl -p0e 's/:\n{2,}/:\n/g' \
>&2
} }
INPUT() { source "${0:a:h}/io.usage.zsh"
PROMPT "${@:2}"
READ $1
local VALUE=$(eval echo '$'$1)
[ $VALUE ]
}
Yn() { #####################################################################
### facilitate user prompt and input ################################
#####################################################################
Yn() { # ask a yes-or-no question (default yes)
PROMPT "$@ [Yn]" PROMPT "$@ [Yn]"
[ $CI ] && { echo y; return 0; } [ $CI ] && { echo y >&2; return 0; }
[ $__SCWRYPTS_YES ] && [[ $__SCWRYPTS_YES -eq 1 ]] && { echo y; return 0; } [ $__SCWRYPTS_YES ] && [[ $__SCWRYPTS_YES -eq 1 ]] && { echo y; return 0; }
local Yn; READ -k Yn; echo >&2 local Yn; READ -k Yn; echo >&2
[[ $Yn =~ [nN] ]] && return 1 || return 0 [[ $Yn =~ [nN] ]] && return 1 || return 0
} }
yN() { yN() { # ask a yes-or-no question (default no)
PROMPT "$@ [yN]" PROMPT "$@ [yN]"
[ $CI ] && { echo y; return 0; } [ $CI ] && { echo y >&2; return 0; }
[ $__SCWRYPTS_YES ] && [[ $__SCWRYPTS_YES -eq 1 ]] && { echo y; return 0; } [ $__SCWRYPTS_YES ] && [[ $__SCWRYPTS_YES -eq 1 ]] && { echo y; return 0; }
local yN; READ -k yN; echo >&2 local yN; READ -k yN; echo >&2
[[ $yN =~ [yY] ]] && return 0 || return 1 [[ $yN =~ [yY] ]] && return 0 || return 1
} }
CAPTURE() { INPUT() { # read a single line of user input
[ ! $USAGE ] && USAGE=" PROMPT "${@:2}"
usage: stdout-varname stderr-varname [...cmd and args...] READ $1
local VALUE=$(eval echo '$'$1)
captures stdout and stderr on separate variables for a command [ $VALUE ]
"
{
IFS=$'\n' read -r -d '' $2;
IFS=$'\n' read -r -d '' $1;
} < <((printf '\0%s\0' "$(${@:3})" 1>&2) 2>&1)
} }
##################################################################### source "${0:a:h}/io.fzf.zsh" # allow user to select from a list of inputs
GETSUDO() { EDIT() { # edit a file in user's preferred editor
echo "\\033[1;36mPROMPT  : checking sudo password...\\033[0m" >&2
sudo echo hi >/dev/null 2>&1 </dev/tty \
&& SUCCESS '...authenticated!' \
|| { ERROR 'failed :c'; return 1; }
}
LESS() { less -R $@ </dev/tty >/dev/tty; }
FZF() {
[ $CI ] && {
ERROR 'currently in CI, but FZF requires user input'
exit 1
}
local FZF_ARGS=()
FZF_ARGS+=(-i)
FZF_ARGS+=(--ansi)
FZF_ARGS+=(--bind=ctrl-c:cancel)
FZF_ARGS+=(--height=50%)
FZF_ARGS+=(--layout=reverse)
local SELECTION=$(fzf ${FZF_ARGS[@]} --layout=reverse --prompt "$1 : " ${@:2})
PROMPT "$1"
echo $SELECTION >&2
echo $SELECTION
}
FZF_HEAD() { FZF $@ --print-query | sed '/^$/d' | head -n1; } # prefer user input over selected
FZF_TAIL() { FZF $@ --print-query | sed '/^$/d' | tail -n1; } # prefer selected over user input
READ() {
[ $CI ] && {
INFO 'currently in CI, skipping READ'
return 0
}
read $@ </dev/tty
}
EDIT() {
[ $CI ] && { [ $CI ] && {
INFO 'currently in CI, skipping EDIT' INFO 'currently in CI, skipping EDIT'
return 0 return 0
@ -221,6 +120,12 @@ EDIT() {
SUCCESS "finished editing '$1'!" SUCCESS "finished editing '$1'!"
} }
#####################################################################
### basic commands with tricky states or default requirements #######
#####################################################################
LESS() { less -R $@ </dev/tty >/dev/tty; }
YQ() { YQ() {
yq --version | grep -q mikefarah || { yq --version | grep -q mikefarah || {
yq $@ yq $@
@ -229,3 +134,37 @@ YQ() {
yq eval '... comments=""' | yq $@ yq eval '... comments=""' | yq $@
} }
#####################################################################
### other i/o utilities #############################################
#####################################################################
CAPTURE() {
[ ! $USAGE ] && USAGE="
usage: stdout-varname stderr-varname [...cmd and args...]
captures stdout and stderr on separate variables for a command
"
{
IFS=$'\n' read -r -d '' $2;
IFS=$'\n' read -r -d '' $1;
} < <((printf '\0%s\0' "$(${@:3})" 1>&2) 2>&1)
}
GETSUDO() {
echo "\\033[1;36mPROMPT  : checking sudo password...\\033[0m" >&2
sudo echo hi >/dev/null 2>&1 </dev/tty \
&& SUCCESS '...authenticated!' \
|| { ERROR 'failed :c'; return 1; }
}
READ() {
[ $CI ] && {
INFO 'currently in CI, skipping READ'
return 0
}
read $@ </dev/tty
}

52
zsh/sanity-check Executable file
View File

@ -0,0 +1,52 @@
#!/bin/zsh
#####################################################################
USAGE__options='
-e, --exit-code desired exit code of the function (default "0")
-f, --output-function one of the zsh/utils output functions (default "SUCCESS")
-m, --message a message to display (default "Hello, World!")
'
USAGE__description='
a simple hello-world-style script which allows specific scwrypts
conditions to be quickly emulated
'
#####################################################################
MAIN() {
local OUTPUT_FUNCTION=SUCCESS
local EXIT_CODE=0
local MESSAGE='Hello, world!'
ARGUMENT_REQUIRED() { ERROR "'$1' requires an argument"; }
while [[ $# -gt 0 ]]
do
case $1 in
-e | --exit-code )
EXIT_CODE="$2"
[ $2 ] && shift 1 || ARGUMENT_REQUIRED
;;
-f | --output-function )
OUTPUT_FUNCTION="$2"
[ $2 ] && shift 1 || ARGUMENT_REQUIRED
;;
-m | --message )
MESSAGE="$2"
[ $2 ] && shift 1 || ARGUMENT_REQUIRED
;;
* ) ERROR "unknown argument '$1'" ;;
esac
shift 1
done
CHECK_ERRORS
##########################################
[[ $OUTPUT_FUNCTION =~ ^FAIL$ ]] && FAIL $EXIT_CODE "$MESSAGE"
$OUTPUT_FUNCTION "$MESSAGE"
return $EXIT_CODE
}