Files
scwrypts/zsh/utils/parse.zsh
T
wrynegade e7484103b9 v5.1.0
=====================================================================

A follow-up to V5 focused on hardening the environment system and
expanding the ZSH logging/caching toolkit. No migration required from
v5.0.x, though note the log-level reorganization below may quiet some
messages at lower verbosities.

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

- persistent cross-runtime cache for ZSH-type scwrypts; extends the
  v5.0 runtime speedup cache to survive between runs with automatic
  hash-based invalidation (toggle via SCWRYPTS__ZSH_CACHE_ENABLED)

- new 'trace' log level (5) and echo.trace, plus '-v VARNAME' state
  injection for echo.debug / echo.trace to surface variable values
  inline

- additional scwrypts output formats: 'raw' and 'logfmt'
  (alongside pretty and json)

- normalize.boolean utility for consistent truthy/falsey handling
  across ZSH-type scwrypts

- utils.fzf.file-select for directory-scoped file selection prompts

- automatic dependency wrappers providing default arguments, GNU
  coreutil resolution, and scwrypts trace on wrapped commands

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

- log levels reorganized; success / status / reminder messages now
  emit at level 3, so lower verbosities will show fewer of these

- environment library restructured around get-user-json as the single
  source of truth (replaces the previous user module and cache-output)

- utility renames for consistency: user.Yn / user.yN (from utils.*)

- utils.fail and utils.abort deprecated in favor of echo.error and
  echo.error.user-abort

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

- CI runs now resolve config lookup-paths (.dotted.path) to their
  environment variable before reading, fixing false "not set" reports
  and invalid-export errors for lookup-path checks in CI

- hardened environment type detection so array-valued configs reprint
  correctly after their first check

- corrected exit-code capture in the cache layer (now reflects the
  cached command, not the downstream output filter)

- scwrypt exit code now survives the logging pipeline

- assorted script fixes (efs unmount file listing, postgres run-sql
  file discovery)
2026-08-14 12:28:08 -06:00

138 lines
4.0 KiB
Bash

#
# when you don't need to check any special negative cases,
# you can simply set up your PARSERS=() array and other local
# variable declarations, then run the following line:
#
# eval "$ZSHPARSEARGS"
#
# This will populate variables, run all validators, and handle
# the special '--help' case, forcing an early 'return 0' after
# parsing the args.
#
ZSHPARSEARGS='
utils.parse $@ || {
local ERROR_CODE=$?
case $ERROR_CODE in
( -1 ) return 0 ;; # -h | --help
( * ) return $ERROR_CODE ;;
esac
}
'
utils.parse() {
#
# Parses all arguments using PARSERS array; return value breaks the typical
# success/failure code paradigm:
#
# returns 0 if all arguments were parsed successfully (success)
# returns >0 a count of every argument which failed to parse successfully (failure)
#
# returns -1 if parent program should "return 0" immediately (success, but signal program end; e.g. --help should print usage and return 0)
#
# other _negative return codes_ can be processed in any custom way
#
#
# Makes argument parsing reusable in zsh. Best-practice argument
# parsing involves looping across the $@ args, processing and 'shift'-ing
# arguments until there are none left, but this can lead to a lot
# of boilerplate. While there _are_ utilities to try and simplify this,
# I've found their API to be quite complex and inconsistent across
# different environments.
#
# By including "parser" functions in the 'PARSERS=()' array, you can
# perform parsing logic (first element is highest priority, last element is
# lowest priority). A sample parser function is defined below.
#
# If variable values are set in the caller function, proper usage requires
# declaration of "local VARIABLE_NAME" in that parent caller _before_
# invoking 'utils.zshparseargs $@'
#
local PARSER VALID_PARSERS=()
local DEFAULT_PARSERS=()
[[ ${DEFAULT_PARSERS[@]-1} =~ ^utils.parse.help$ ]] \
&& local NO_DEFAULT_PARSERS=true # autosetup preloads default parsers
[ ${NO_DEFAULT_PARSERS} ] || {
# automatically includes 'MY_FUNCTION.parse()' as 1st parser when parsing for 'MY_FUNCTION()'
[[ ${funcstack[2]} =~ ^[(]eval[)]$ ]] \
&& PARSERS=(${funcstack[3]}.parse ${PARSERS}) \
|| PARSERS=(${funcstack[2]}.parse ${PARSERS}) \
;
PARSERS+=(utils.parse.args utils.parse.help)
}
for PARSER in ${PARSERS[@]}
do
command -v ${PARSER} &>/dev/null || continue
command -v ${PARSER}.safety &>/dev/null || {
VALID_PARSERS+=(${PARSER})
continue
}
${PARSER}.safety && VALID_PARSERS+=(${PARSER})
done
for PARSER in ${VALID_PARSERS[@]}
do
command -v ${PARSER}.usage &>/dev/null && ${PARSER}.usage &>/dev/null
done
local EARLY_ESCAPE_CODE _S ERRORS=0 POSITIONAL_ARGS=0
while [[ $# -gt 0 ]]
do
_S=0
for PARSER in ${VALID_PARSERS[@]}
do
${PARSER} $@
((_S+=$?))
[ ${EARLY_ESCAPE_CODE} ] && return ${EARLY_ESCAPE_CODE}
[[ ${_S} -gt 0 ]] && break
done
[[ ${_S} -gt 0 ]] \
|| echo.error "unknown argument '$1'" \
|| ((_S+=1))
[[ ${_S} -le $# ]] \
|| echo.error "invalid value(s) for '$1'" \
|| _S=$#
shift ${_S}
done
for PARSER in ${VALID_PARSERS[@]}
do
command -v ${PARSER}.validate &>/dev/null || continue
${PARSER}.validate
done
utils.check-errors
}
#####################################################################
### default parsers #################################################
#####################################################################
# while it is not recommended to leave so many comments on YOUR parser
# functions, these defaults provide verbose comments to provide you
# how-to-write-parser-functions reference
#
# refer to them in-order if you are trying to write a parser for the
# first time
source "${0:a:h}/parse.help.zsh"
source "${0:a:h}/parse.args.zsh"
#####################################################################
### the easy-but-removed way to go ##################################
#####################################################################
source "${0:a:h}/parse.autosetup.zsh"