diff --git a/argsh.min.sh b/argsh.min.sh index c7c3440..927cb08 100755 --- a/argsh.min.sh +++ b/argsh.min.sh @@ -1,13 +1,12 @@ #!/usr/bin/env bash # shellcheck disable=SC2178 disable=SC2120 disable=SC1090 disable=SC2046 disable=SC2155 -set -euo pipefail; ARGSH_COMMIT_SHA="794e18b84ef32266f3afd0cd88a46905a8e7b68a"; ARGSH_VERSION="v0.0.5" -: "${ARGSH_VERSION:=unknown}";: "${ARGSH_COMMIT_SHA:=unknown}";: "${ARGSH_FIELD_WIDTH:=24}";COMMANDNAME=("$(s="${ARGSH_SOURCE:-"${0}"}"; echo "${s##*/}")");:usage() { local a24="${1}"; shift;declare -p usage &>/dev/null || local -a usage=();declare -p args &>/dev/null || local -a args=();[[ $(( ${#usage[@]} % 2 )) -eq 0 ]] || :args::_error "usage must be an associative array";[[ $(( ${#usage[@]} % 2 )) -eq 0 ]] || :args::_error "usage must be an associative array";if [[ -z ${1:-} || ${1} == "-h" || ${1} == "--help" ]]; then :usage::text "${a24}";exit 0;fi;if ! (( ${#COMMANDNAME[@]} )) && [[ ${1:-} == "--argsh" ]]; then echo "https://arg.sh ${ARGSH_COMMIT_SHA:-} ${ARGSH_VERSION:-}";exit 0;fi;local -A a18=();local -a a51=("${@}");local a54 a32="";while (( ${#a51[@]} )); do if [[ ${a51[0]:0:1} != "-" ]]; then [[ -z "${a54:-}" ]] || break;a54="${a51[0]}";a51=("${a51[@]:1}");continue;fi;:args::parse_flag || break;a18["${a32}"]=1;done;:args::check_required_flags;local a41;for (( a63=0; a63 < ${#usage[@]}; a63+=2 )); do for a21 in $(echo "${usage[a63]/:*}" | tr '|' "\n"); do a21="${a21#\#}";[[ "${a54}" == "${a21}" ]] || continue;a32="${usage[a63]#\#}";a41="${usage[a63]/*:-}";a41="${a41#\#}";[[ "${a41}" == "${usage[a63]}" ]] || break 2;a41="${a41/|*}";break 2;done;done;[[ -n "${a41:-}" ]] || :args::error_usage "Invalid command: ${a54}";COMMANDNAME+=("${a32/[|:]*}");usage=("${a41}" "${a51[@]}");};:usage::text() { local a24="${1:-}";string::indent "${a24}";echo;echo "Usage: ${COMMANDNAME[*]} [args]";[[ ${usage[0]:-} == '-' ]] || echo -e "\nAvailable Commands:";for (( a63=0; a63 < ${#usage[@]}; a63+=2 )); do [[ "${usage[a63]:0:1}" != "#" ]] || continue;[[ "${usage[a63]}" != "-" ]] || { echo;echo "${usage[a63+1]}";continue;};printf " %-${ARGSH_FIELD_WIDTH}s %s\n" "${usage[a63]/[:|]*}" "${usage[a63+1]}";done;:args::text_flags;echo;echo "Use \"${COMMANDNAME[*]} --help\" for more information about a command.";};:args() { local a24="${1}"; shift;declare -p args &>/dev/null || local -a args=();[[ $(( ${#args[@]} % 2 )) -eq 0 ]] || :args::_error "args must be an associative array";if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then :args::text;exit 0;fi;local a32="" a63 a0=1;local -A a18=();local -a a51=("${@}");while (( ${#a51[@]} )); do if [[ ${a51[0]:0:1} != "-" ]]; then a63="$(:args::field_positional "${a0}")" || :args::error_usage "too many arguments: ${a51[0]}";a32="${args[a63]}";local -n a59="$(args::field_name "${a32}")";a59="$(:args::field_value "${a51[0]}")" || exit "${?}";a51=("${a51[@]:1}");(( ++a0 ));continue;fi;:args::parse_flag || :args::error_usage "unknown a47: ${a51[0]}";a18["${a32}"]=1;done;if a63="$(:args::field_positional "${a0}")"; then a32="$(args::field_name "${args[a63]}")";if is::uninitialized "${a32}" && ! is::array "${a32}"; then :args::error_usage "missing required argument: ${a32}";fi;fi;:args::check_required_flags;[[ ${#a51[@]} -eq 0 ]] || :args::error_usage "too many arguments: ${a51[*]}";};:args::text() { declare -p args &>/dev/null || return 0;local -a a2=() a8=();:args::positional -string::indent "${a24}";echo;echo "Usage:";echo " ${COMMANDNAME[*]} ${a8[*]}";(( ${#a2[@]} == 0 )) || { echo;echo "Arguments:";for a63 in "${a2[@]}"; do [[ ${args[a63]} != "-" ]] || continue;a45="$(printf " %-${ARGSH_FIELD_WIDTH}s%s" " " "${args[a63+1]}" | fmt::tty;)";printf " %-${ARGSH_FIELD_WIDTH}s%s\n" "$(:args::fieldf "${args[a63]}")" "$(string::trim-left "${a45}")";done;};:args::text_flags;echo;};:args::text_flags() { local -a args=("${args[@]}");local -a a31=();array::contains 'help|h:+' "${args[@]}" || args+=('help|h:+' "Show this help message");:args::flags;(( ${#a31[@]} )) || return 0;[[ "${args[${a31[0]}]}" == "-" ]] || echo -e "\nOptions:";for a63 in "${a31[@]}"; do [[ "${args[a63]:0:1}" != "#" ]] || continue;[[ "${args[a63]}" != "-" ]] || { echo;echo "${args[a63+1]}";continue;};:args::fieldf "${args[a63]}";{ echo -n " ";echo -e "${args[a63+1]}\n";} | fmt::tty;done;};:args::flags() { declare -p args &>/dev/null || local -a args;declare -p a31 &>/dev/null || local -a a31;for (( a63=0; a63 < "${#args[@]}"; a63+=2 )); do if [[ ${args[a63]} == *"|"* || ${args[a63]} == '-' ]]; then a31+=("${a63}");fi;done;};:args::positional() { declare -p args &>/dev/null || local -a args;declare -p a2 &>/dev/null || local -a a2;declare -p a8 &>/dev/null || local -a a8;local a59;for (( a63=0; a63 < "${#args[@]}"; a63+=2 )); do [[ ${args[a63]} != *"|"* && ${args[a63]} != '-' ]] || continue;a59="$(args::field_name "${args[a63]}")";a2+=("${a63}");if is::array "${a59}"; then a8+=("...${a59}");continue;fi;if ! is::uninitialized "${a59}"; then a8+=("[${a59}]");continue;fi;a8+=("<${a59}>");done;};:args::parse_flag() { declare -p a51 a32 &>/dev/null || return 1;local a47="${a51[0]/=*}";if [[ ${a47:0:2} == "--" ]]; then a32="$(:args::field_lookup "${a47:2}")" || return "${?}";elif [[ ${a47:0:1} == "-" ]]; then a47="${a47:0:2}";a32="$(:args::field_lookup "${a47:1}")" || return "${?}";fi;:args::field_set_flag "${a32}";};:args::check_required_flags() { declare -p a18 args &>/dev/null || return 1;local a32;local -a a22;for (( a63=0; a63 < ${#args[@]}; a63+=2 )); do a32="${args[a63]}";:args::field_attrs "${a32}";if (( a22[2] )) && ! (( a22[4] )); then local -n a59="${a22[0]}";a59=0;fi;if (( a22[6] )) && [[ -z ${a18[${args[a63]}]:-} ]]; then :args::error_usage "missing required a47: ${args[a63]/|*}";fi;done;};:args::field_set_flag() { local a32="${1}";declare -p a51 a47 &>/dev/null || return 1;local -a a22;:args::field_attrs "${a32}";local -n a59="${a22[0]}";local a4 a3;if (( a22[2] )); then a4=1;if [[ ${a47:0:2} == "--" ]]; then a51=("${a51[@]:1}");else a51[0]="-${a51[0]:2}";[[ ${a51[0]} != "-" ]] || a51=("${a51[@]:1}");fi;fi;[[ -n ${a4:-} ]] || { a3="${a51[0]/${a47}}";if [[ ${a3} == "" ]]; then (( ${#a51[@]} )) || :args::error "missing value for a47: ${a22[0]}";a4="${a51[1]}";a51=("${a51[@]:1}");else [[ "${a3:0:1}" != "=" ]] || a3="${a3:1}";a4="${a3}";fi;a4="$(:args::field_value "${a4}")" || exit "${?}";a51=("${a51[@]:1}");};if (( a22[5] )); then a59+=("${a4}");else a59="${a4}";fi;};:args::field_value() { local a25="${1}";declare -p a32 &>/dev/null || return 1;declare -p a22 &>/dev/null || { local -a a22;:args::field_attrs "${a32}";};declare -f "to::${a22[3]}" &>/dev/null || :args::_error "unknown type: ${a22[3]}";"to::${a22[3]}" "${a25}" "${a22[0]}" || :args::error_usage "invalid type (${a22[3]}): ${a25}";};:args::field_lookup() { local a32="${1}";declare -p args &>/dev/null || return 1;for (( a63=0; a63 < ${#args[@]}; a63+=2 )); do if [[ ${args[a63]} =~ (^${a32}\||\|${a32}:|\|${a32}$) ]]; then echo "${args[a63]}";return 0;fi;done;return 1;};:args::field_positional() { local a6="${1:-1}";declare -p args &>/dev/null || return 1;for (( a63=0; a63 < ${#args[@]}; a63+=2 )); do if [[ ${args[a63]} != *"|"* && ${args[a63]} != '-' ]]; then if is::array "$(args::field_name "${args[a63]}")" || (( --a6 == 0 )); then echo "${a63}";return 0;fi;fi;done;return 1;};args::field_name() { local a32="${1}";local a27="${2:-1}";a32="${a32/[|:]*}";a32="${a32#\#}";if (( a27 )); then a32="${a32//-/_}";fi;echo "${a32}";};:args::field_attrs() { local a32="${1}";declare -p a22 &>/dev/null || local -a a22;a22=("" "" 0 "" 0 0 0 0 "" );local a36="+~!";local a33="${a32#*[:]}";[ "${a33}" != "${a32}" ] || a33="";a22[0]="$(args::field_name "${a32}")";a22[8]="$(args::field_name "${a32}" 0)";[[ ${a22[0]:0:1} != "#" ]] || { a22[7]=1;};local -n a59="${a22[0]}";local -a a31;mapfile -t a31 < <(echo "${a32/[:]*}" | tr '|' '\n');[[ ${#a31[@]} -eq 1 ]] || { a22[1]="${a31[1]}";};if is::array "${a22[0]}"; then a22[5]=1;! is::uninitialized "${a22[0]}" || a59=();! (( ${#a59[@]} )) || a22[4]=1;elif ! is::uninitialized "${a22[0]}"; then a22[4]=1;fi;while (( ${#a33} > 0 )); do if [[ ${a33:0:1} == "+" ]]; then [[ -z ${a22[3]} ]] || :args::_error "cannot have multiple types: ${a22[3]} and boolean";a22[2]=1;a33="${a33:1}";continue;fi;if [[ ${a33:0:1} == "~" ]]; then ! (( a22[2] )) || :args::_error "already flagged as boolean";a33="${a33:1}";a22[3]="${a33/[$a36]*}";a33="${a33:${#a22[3]}}";continue;fi;if [[ ${a33:0:1} == "!" ]]; then ! (( a22[6] )) || :args::_error "field already flagged as required";a22[6]=1;a33="${a33:1}";continue;fi;echo ":args error: unknown modifier: ${a33:0:1}" >&2;exit 2;done;if [[ -z ${a22[3]} && ${a22[2]} -eq 0 ]]; then a22[3]="string";fi;};:args::fieldf() { local a32="${1}";declare -p a22 &>/dev/null || { local -a a22;:args::field_attrs "${a32}";};[[ ${a32} == *"|"* ]] || { echo "${a22[8]} ${a22[3]}";return 0;};local -n a59="${a22[0]}";a14=" ";! (( a22[6] )) || a14=" ! ";if [[ -n ${a22[1]} ]]; then a14+="-${a22[1]}, --${a22[8]}";else a14+=" --${a22[8]}";fi;a14+=" ";! (( a22[5] )) || a14+="...";a14+="${a22[3]}";if (( a22[4] )) && ! (( a22[2] )); then a14+=" (default: ${a59[*]})";fi;echo "${a14}";};args::run() { local a60="${1}"; shift;for (( a63=0; a63<${#}; a63++ )); do local a53="${1}"; shift;local a41="${1}"; shift;if ! (( a60 )) || (( a53 )); then "${a41}";fi;done;};array::contains() { local -r a10="${1}"; shift;for a7 in "${@}"; do [[ "${a7}" != "${a10}" ]] || return 0;done;return 1;};array::join() { local -r a5="${1}"; shift;local a13;printf -v a13 "${a5}%s" "${@}";echo "${a13:${#a5}}";};array::nth() { local -n a57="${1}";local -r a52="${2}";shift 2;for (( a63=1; a63<=${#}; a63++ )); do (( a63 % a52 )) || a57+=("${!a63}");done;};bash::version() { local a29="${1:-4}";local a19="${2:-3}";local a20="${3:-0}";if [[ "${BASH_VERSINFO[0]}" -lt "${a29}" ]]; then return 1;elif [[ "${BASH_VERSINFO[0]}" -gt "${a29}" ]]; then return 0;fi;if [[ "${BASH_VERSINFO[1]}" -lt "${a19}" ]]; then return 1;elif [[ "${BASH_VERSINFO[1]}" -gt "${a19}" ]]; then return 0;fi;if [[ "${BASH_VERSINFO[2]}" -lt "${a20}" ]]; then return 1;fi;return 0;};binary::exists() { local a16="${1}";command -v "${a16}" &> /dev/null || { echo "${a16} is required to run this script" >&2;return 1;};};binary::github() { local a46="${1}";local -r a16="$(basename "${a46}")";local a37="${2}";local a39="${3}";local a58="${4:-}";curl -Lso /dev/stdout "https://github.com/${a37}/releases/download/${a39}" | { if [[ -n "${a58}" ]]; then tar -xz -C "$(dirname "${a46}")" "${a58}";else tee "${a46}" &> /dev/null;fi;chmod +x "${a46}";};};binary::arch() { local a28="${1}";local -r a38="$(uname -m)";case "${a38}" in -x86_64|amd64) if (( a28 )); then echo "64-bit"; else echo "amd64"; fi ;; -armv7l) echo "arm" ;; -aarch64) echo "arm64" ;; -*) echo "${a38}" ;; -esac;};binary::jq() { binary::exists "jq" 2>/dev/null || { local -r a12="$(github::latest "stedolan/jq")" system="$(uname -s)";binary::github "${PATH_BIN?}/jq" "stedolan/jq" "${a12}/jq-${system,,}-$(binary::arch)";};};binary::vale() { binary::exists "vale" 2>/dev/null || { local -r a12="$(github::latest "errata-ai/vale")" system="$(uname -s)";binary::github "${PATH_BIN?}/vale" "errata-ai/vale" "${a12}/vale_${a12:1}_$(uname -s)_$(binary::arch 1).tar.gz" "vale";};};docker::user() { local a61="${1:-"$(id -u)"}";local a49="${2:-"$(id -g)"}";local a43="${3:-"$(whoami)"}";local a34="${4:-"/workspace"}";local a30="${5:-"/bin/sh"}";local a40;a40="$(pwd)";a40="${a40#"${PATH_BASE:-}"}";if [[ "${a40}" == "$(pwd)" ]]; then a40="${a34}";else a40="${a34}${a40}";fi;echo "${a43}:x:${a61}:${a49}::${a34}:${a30}" > /tmp/docker_passwd;echo "${a43}:x:${a49}:" > /tmp/docker_group;echo "-v /tmp/docker_passwd:/etc/passwd -v /tmp/docker_group:/etc/group";echo "-u ${a61}:${a49}";echo "-v ${PATH_BASE:-"$(pwd)"}:${a34}";echo "-w ${a40}";};error::stacktrace() { local -r a42="${1:-${?}}";if (( a42 )); then echo -e "\n\033[38;5;196m■■ Stacktrace(${a42}): \e[1m${BASH_COMMAND}\e[22m";for a63 in $(seq 1 $((${#FUNCNAME[@]} - 2))); do echo -e "${a63}. ${BASH_SOURCE[a63]}:${BASH_LINENO[a63-1]} ➜ ${FUNCNAME[a63]}()";done;echo -e "\033[0m";return "${a42}";fi;};:args::_error() { declare -p a32 &>/dev/null || local a32="???";echo ":args error [${a32}] ➜ ${1}" >&2;exit 2;};:args::error() { declare -p a32 &>/dev/null || local a32="???";echo -e "[ ${a32/[:|]*} ] invalid argument\n➜ ${1}\n" >&2;exit 2;};:args::error_usage() { declare -p a32 &>/dev/null || local a32="???";echo -e "[ ${a32/[:|]*} ] invalid usage\n➜ ${1}\n" >&2;echo -e "Use \"${0##*/} -h\" for more information" >&2;exit 2;};fmt::tty() { local a50="${1:-"$(cat)"}";if ! command -v fmt &>/dev/null || [[ ! -t 1 ]]; then echo "${a50}";return 0;fi;local a35;a35="$(tput cols)";echo "${a50}" | fmt -w "${a35}";};github::latest() { local a37="${1}";curl -fsSLI -o /dev/null -w "%{url_effective}" "https://github.com/${a37}/releases/latest" | rev | cut -d'/' -f1 | rev;};declare -gA a1=();import() { local a55="${1}";(( ${a1["${a55}"]:-} )) || { a1["${a55}"]=1;if [[ ${a55:0:1} == "@" ]]; then a55="${PATH_BASE:?"PATH_BASE missing"}/${a55:1}";elif [[ ${a55:0:1} == "~" ]]; then local _s="${ARGSH_SOURCE:-${BASH_SOURCE[-1]}}";a55="${_s%/*}/${a55:1}";else a55="${BASH_SOURCE[0]%/*}/${a55}";fi;import::source "${a55}" || exit 1;};};import::source() { local a55="${1}";for a56 in "" ".sh" ".bash"; do if [[ -f "${a55}${a56}" ]]; then . "${a55}${a56}";return;fi;done;echo "Library not found ${a55}" >&2;return 1;};import::clear() { a1=();};is::tty() { [[ -t 1 ]];};is::array() { declare -p "${1}" &>/dev/null && [[ $(declare -p "${1}") == "declare -a"* ]];};is::uninitialized() { local a48="${1}";if is::array "${a48}"; then [[ $(declare -p "${a48}") == "declare -a ${a48}" ]];else [[ ! ${!a48+x} ]];fi;};is::set() { ! is::uninitialized "${1}";};argsh::shebang() { local -r a39="${1}";: "${ARGSH_SOURCE="${a39}"}";export ARGSH_SOURCE;[[ "${BASH_SOURCE[-1]}" != "${a39}" && -f "${a39}" ]] || { binary::exists docker || { echo "This script requires Docker to be installed";return 1;} >&2;local a62="";! tty -s || a62="-it";docker run --rm ${a62} $(docker::user) -e "BATS_LOAD" -e "ARGSH_SOURCE" -e "GIT_COMMIT_SHA=$(git rev-parse HEAD 2>/dev/null || :)" -e "GIT_VERSION=$(git describe --tags --dirty 2>/dev/null || :)" ghcr.io/arg-sh/argsh:latest "${@}" ;return 0;};bash::version 4 3 0 || { echo "This script requires bash 4.3.0 or later";return 1;} >&2;shift;. "${a39}";};string::drop-index() { local a9="${1}";local a17="${2}";local a11="${3:-1}";echo "${a9:0:a17}${a9:a17+a11}";};string::random() { local a11="${1:-42}";local a23="${2:-"a-zA-Z0-9"}";local a50;until [[ "${a50:-}" =~ ^[:alpha:] ]]; do a50=$(tr -dc "${a23}" < /dev/urandom | fold -w "${a11}" | head -n 1 || :);done;echo "${a50}";};string::indent() { local a9="${1:-'-'}";local a15="${2:-0}";local a44 a26;[[ ${a9} != '-' ]] || a9="$(cat)";mapfile -t a26 < <(echo "${a9}");for a44 in "${a26[@]}"; do a44="$(string::trim-left "${a44}")";(( a15 == 0 )) || printf "%${a15}s" " " ;echo "${a44}";done;};string::trim-left() { local a9="${1}";local a23="${2:-" "$'\n'$'\t'}";[[ -n ${a9:-} ]] || return 0;[[ ${a9} != '-' ]] || a9="$(cat)" ;while [[ -n "${a9}" ]]; do [[ ${a23} == *${a9:0:1}* ]] || break;a9="${a9:1}";done;echo "${a9}";};string::trim-right() { local a9="${1:-'-'}";local a23="${2:-" "$'\n'$'\t'}";[[ ${a9} != '-' ]] || a9="$(cat)";while [[ -n "${a9}" ]]; do [[ ${a23} == *${a9: -1}* ]] || break;a9="${a9:0: -1}";done;echo "${a9}";};string::trim() { local a9="${1:-'-'}";local a23="${2:-" "$'\n'$'\t'}";[[ ${a9} != '-' ]] || a9="$(cat)" ;echo "${a9}" | string::trim-left - "${a23}" | string::trim-right - "${a23}";};to::string() { local a25="${1}";echo "${a25}";};to::boolean() { local a25="${1}";case "${a25}" in -""|"false"|"0") a25="0" ;; -*) a25="1" ;; -esac;echo "${a25}";};to::int() { local a25="${1}";[[ ${a25} =~ ^-?[0-9]+$ ]] || return 1;echo "${a25}";};to::float() { local a25="${1}";[[ ${a25} =~ ^-?[0-9]+(\.[0-9]+)?$ ]] || return 1;echo "${a25}";};to::stdin() { local a25="${1}";[[ ${a25} != "-" ]] || a25="$(cat)";echo "${a25}";};to::file() { local a25="${1}";[[ -f "${a25}" ]] || return 1;echo "${a25}";};[[ "${BASH_SOURCE[0]}" != "${0}" ]] || argsh::shebang "${@}" +set -euo pipefail; ARGSH_COMMIT_SHA="45a1e687d254c7b0d2b312076bbed489baff949f"; ARGSH_VERSION="v0.1.0" +: "${ARGSH_VERSION:=unknown}";: "${ARGSH_COMMIT_SHA:=unknown}";: "${ARGSH_FIELD_WIDTH:=24}";COMMANDNAME=("$(s="${ARGSH_SOURCE:-"${0}"}"; echo "${s##*/}")");:usage() { local a23="${1}"; shift;declare -p usage &>/dev/null || local -a usage=();declare -p args &>/dev/null || local -a args=();[[ $(( ${#usage[@]} % 2 )) -eq 0 ]] || :args::_error "usage must be an associative array";[[ $(( ${#usage[@]} % 2 )) -eq 0 ]] || :args::_error "usage must be an associative array";if [[ -z ${1:-} || ${1} == "-h" || ${1} == "--help" ]];then :usage::text "${a23}";exit 0;fi;if ! (( ${#COMMANDNAME[@]} )) && [[ ${1:-} == "--argsh" ]];then echo "https://arg.sh ${ARGSH_COMMIT_SHA:-} ${ARGSH_VERSION:-}";exit 0;fi;local -A a18=();local -a a50=("${@}");local a49 a27="";while (( ${#a50[@]} ));do if [[ ${a50[0]:0:1} != "-" ]];then [[ -z "${a49:-}" ]] || break;a49="${a50[0]}";a50=("${a50[@]:1}");continue;fi;:args::parse_flag || break;a18["${a27}"]=1;done;:args::check_required_flags;local a36;for (( a63=0; a63 < ${#usage[@]}; a63+=2 ));do for a19 in $(echo "${usage[a63]/:*}" | tr '|' "\n");do a19="${a19#\#}";[[ "${a49}" == "${a19}" ]] || continue;a27="${usage[a63]#\#}";a36="${usage[a63]/*:-}";a36="${a36#\#}";[[ "${a36}" == "${usage[a63]}" ]] || break 2;a36="${a36/|*}";break 2;done;done;[[ -n "${a36:-}" ]] || :args::error_usage "Invalid command: ${a49}";COMMANDNAME+=("${a27/[|:]*}");usage=("${a36}" "${a50[@]}");};:usage::text() { local a23="${1:-}";string::indent "${a23}";echo;echo "Usage: ${COMMANDNAME[*]} [args]";[[ ${usage[0]:-} == '-' ]] || echo -e "\nAvailable Commands:";for (( a63=0; a63 < ${#usage[@]}; a63+=2 ));do [[ "${usage[a63]:0:1}" != "#" ]] || continue;[[ "${usage[a63]}" != "-" ]] || { echo;echo "${usage[a63+1]}";continue;};printf " %-${ARGSH_FIELD_WIDTH}s %s\n" "${usage[a63]/[:|]*}" "${usage[a63+1]}";done;:args::text_flags;echo;echo "Use \"${COMMANDNAME[*]} --help\" for more information about a command.";};:args() { local a23="${1}"; shift;declare -p args &>/dev/null || local -a args=();[[ $(( ${#args[@]} % 2 )) -eq 0 ]] || :args::_error "args must be an associative array";if [[ ${1:-} == "-h" || ${1:-} == "--help" ]];then :args::text;exit 0;fi;local a27="" a63 a0=1;local -A a18=();local -a a50=("${@}");while (( ${#a50[@]} ));do if [[ ${a50[0]:0:1} != "-" ]];then a63="$(:args::field_positional "${a0}")" || :args::error_usage "too many arguments: ${a50[0]}";a27="${args[a63]}";local -n a48="$(args::field_name "${a27}")";a48="$(:args::field_value "${a50[0]}")" || exit "${?}";a50=("${a50[@]:1}");(( ++a0 ));continue;fi;:args::parse_flag || :args::error_usage "unknown a39: ${a50[0]}";a18["${a27}"]=1;done;if a63="$(:args::field_positional "${a0}")";then a27="$(args::field_name "${args[a63]}")";if is::uninitialized "${a27}" && ! is::array "${a27}";then :args::error_usage "missing required argument: ${a27}";fi;fi;:args::check_required_flags;[[ ${#a50[@]} -eq 0 ]] || :args::error_usage "too many arguments: ${a50[*]}";};:args::text() { declare -p args &>/dev/null || return 0;local -a a2=() a11=();:args::positional;string::indent "${a23}";echo;echo "Usage:";echo " ${COMMANDNAME[*]} ${a11[*]}";(( ${#a2[@]} == 0 )) || { echo;echo "Arguments:";for a63 in "${a2[@]}";do [[ ${args[a63]} != "-" ]] || continue;a33="$( printf " %-${ARGSH_FIELD_WIDTH}s%s" " " "${args[a63+1]}" | fmt::tty;)";printf " %-${ARGSH_FIELD_WIDTH}s%s\n" "$(:args::fieldf "${args[a63]}")" "$(string::trim-left "${a33}")";done;};:args::text_flags;echo;};:args::text_flags() { local -a args=("${args[@]}");local -a a30=();array::contains 'help|h:+' "${args[@]}" || args+=('help|h:+' "Show this help message");:args::flags;(( ${#a30[@]} )) || return 0;[[ "${args[${a30[0]}]}" == "-" ]] || echo -e "\nOptions:";for a63 in "${a30[@]}";do [[ "${args[a63]:0:1}" != "#" ]] || continue;[[ "${args[a63]}" != "-" ]] || { echo;echo "${args[a63+1]}";continue;};:args::fieldf "${args[a63]}";{ echo -n " ";echo -e "${args[a63+1]}\n";} | fmt::tty;done;};:args::flags() { declare -p args &>/dev/null || local -a args;declare -p a30 &>/dev/null || local -a a30;for (( a63=0; a63 < "${#args[@]}"; a63+=2 ));do if [[ ${args[a63]} == *"|"* || ${args[a63]} == '-' ]];then a30+=("${a63}");fi;done;};:args::positional() { declare -p args &>/dev/null || local -a args;declare -p a2 &>/dev/null || local -a a2;declare -p a11 &>/dev/null || local -a a11;local a48;for (( a63=0; a63 < "${#args[@]}"; a63+=2 ));do [[ ${args[a63]} != *"|"* && ${args[a63]} != '-' ]] || continue;a48="$(args::field_name "${args[a63]}")";a2+=("${a63}");if is::array "${a48}";then a11+=("...${a48}");continue;fi;if ! is::uninitialized "${a48}";then a11+=("[${a48}]");continue;fi;a11+=("<${a48}>");done;};:args::parse_flag() { declare -p a50 a27 &>/dev/null || return 1;local a39="${a50[0]/=*}";if [[ ${a39:0:2} == "--" ]];then a27="$(:args::field_lookup "${a39:2}")" || return "${?}";elif [[ ${a39:0:1} == "-" ]];then a39="${a39:0:2}";a27="$(:args::field_lookup "${a39:1}")" || return "${?}";fi;:args::field_set_flag "${a27}";};:args::check_required_flags() { declare -p a18 args &>/dev/null || return 1;local a27;local -a a32;for (( a63=0; a63 < ${#args[@]}; a63+=2 ));do a27="${args[a63]}";:args::field_attrs "${a27}";if (( a32[2] )) && ! (( a32[4] ));then local -n a48="${a32[0]}";a48=0;fi;if (( a32[6] )) && [[ -z ${a18[${args[a63]}]:-} ]];then :args::error_usage "missing required a39: ${args[a63]/|*}";fi;done;};:args::field_set_flag() { local a27="${1}";declare -p a50 a39 &>/dev/null || return 1;local -a a32;:args::field_attrs "${a27}";local -n a48="${a32[0]}";local a5 a4;if (( a32[2] ));then a5=1;if [[ ${a39:0:2} == "--" ]];then a50=("${a50[@]:1}");else a50[0]="-${a50[0]:2}";[[ ${a50[0]} != "-" ]] || a50=("${a50[@]:1}");fi;fi;[[ -n ${a5:-} ]] || { a4="${a50[0]/${a39}}";if [[ ${a4} == "" ]];then (( ${#a50[@]} )) || :args::error "missing value for a39: ${a32[0]}";a5="${a50[1]}";a50=("${a50[@]:1}");else [[ "${a4:0:1}" != "=" ]] || a4="${a4:1}";a5="${a4}";fi;a5="$(:args::field_value "${a5}")" || exit "${?}";a50=("${a50[@]:1}");};if (( a32[5] ));then a48+=("${a5}");else a48="${a5}";fi;};:args::field_value() { local a20="${1}";declare -p a27 &>/dev/null || return 1;declare -p a32 &>/dev/null || { local -a a32;:args::field_attrs "${a27}";};declare -f "to::${a32[3]}" &>/dev/null || :args::_error "unknown type: ${a32[3]}";"to::${a32[3]}" "${a20}" "${a32[0]}" || :args::error_usage "invalid type (${a32[3]}): ${a20}";};:args::field_lookup() { local a27="${1}";declare -p args &>/dev/null || return 1;for (( a63=0; a63 < ${#args[@]}; a63+=2 ));do if [[ ${args[a63]} =~ (^${a27}\||\|${a27}:|\|${a27}$) ]];then echo "${args[a63]}";return 0;fi;done;return 1;};:args::field_positional() { local a6="${1:-1}";declare -p args &>/dev/null || return 1;for (( a63=0; a63 < ${#args[@]}; a63+=2 ));do if [[ ${args[a63]} != *"|"* && ${args[a63]} != '-' ]];then if is::array "$(args::field_name "${args[a63]}")" || (( --a6 == 0 ));then echo "${a63}";return 0;fi;fi;done;return 1;};args::field_name() { local a27="${1}";local a17="${2:-1}";a27="${a27/[|:]*}";a27="${a27#\#}";if (( a17 ));then a27="${a27//-/_}";fi;echo "${a27}";};:args::field_attrs() { local a27="${1}";declare -p a32 &>/dev/null || local -a a32;a32=( "" "" 0 "" 0 0 0 0 "" );local a38="+~!";local a47="${a27#*[:]}";[ "${a47}" != "${a27}" ] || a47="";a32[0]="$(args::field_name "${a27}")";a32[8]="$(args::field_name "${a27}" 0)";[[ ${a32[0]:0:1} != "#" ]] || { a32[7]=1;};local -n a48="${a32[0]}";local -a a30;mapfile -t a30 < <(echo "${a27/[:]*}" | tr '|' '\n');[[ ${#a30[@]} -eq 1 ]] || { a32[1]="${a30[1]}";};if is::array "${a32[0]}";then a32[5]=1;! is::uninitialized "${a32[0]}" || a48=();! (( ${#a48[@]} )) || a32[4]=1;elif ! is::uninitialized "${a32[0]}";then a32[4]=1;fi;while (( ${#a47} > 0 ));do if [[ ${a47:0:1} == "+" ]];then [[ -z ${a32[3]} ]] || :args::_error "cannot have multiple types: ${a32[3]} and boolean";a32[2]=1;a47="${a47:1}";continue;fi;if [[ ${a47:0:1} == "~" ]];then ! (( a32[2] )) || :args::_error "already flagged as boolean";a47="${a47:1}";a32[3]="${a47/[$a38]*}";a47="${a47:${#a32[3]}}";continue;fi;if [[ ${a47:0:1} == "!" ]];then ! (( a32[6] )) || :args::_error "field already flagged as required";a32[6]=1;a47="${a47:1}";continue;fi;echo ":args error: unknown modifier: ${a47:0:1}" >&2;exit 2;done;if [[ -z ${a32[3]} && ${a32[2]} -eq 0 ]];then a32[3]="string";fi;};:args::fieldf() { local a27="${1}";declare -p a32 &>/dev/null || { local -a a32;:args::field_attrs "${a27}";};[[ ${a27} == *"|"* ]] || { echo "${a32[8]} ${a32[3]}";return 0;};local -n a48="${a32[0]}";a16=" ";! (( a32[6] )) || a16=" ! ";if [[ -n ${a32[1]} ]];then a16+="-${a32[1]}, --${a32[8]}";else a16+=" --${a32[8]}";fi;a16+=" ";! (( a32[5] )) || a16+="...";a16+="${a32[3]}";if (( a32[4] )) && ! (( a32[2] ));then a16+=" (default: ${a48[*]})";fi;echo "${a16}";};args::run() { local a62="${1}"; shift;for (( a63=0; a63<${#}; a63++ ));do local a55="${1}"; shift;local a36="${1}"; shift;if ! (( a62 )) || (( a55 ));then "${a36}";fi;done;};array::contains() { local -r a15="${1}"; shift;for a7 in "${@}";do [[ "${a7}" != "${a15}" ]] || return 0;done;return 1;};array::join() { local -r a3="${1}"; shift;local a10;printf -v a10 "${a3}%s" "${@}";echo "${a10:${#a3}}";};array::nth() { local -n a51="${1}";local -r a54="${2}";shift 2;for (( a63=1; a63<=${#}; a63++ ));do (( a63 % a54 )) || a51+=("${!a63}");done;};bash::version() { local a26="${1:-4}";local a21="${2:-3}";local a28="${3:-0}";if [[ "${BASH_VERSINFO[0]}" -lt "${a26}" ]];then return 1;elif [[ "${BASH_VERSINFO[0]}" -gt "${a26}" ]];then return 0;fi;if [[ "${BASH_VERSINFO[1]}" -lt "${a21}" ]];then return 1;elif [[ "${BASH_VERSINFO[1]}" -gt "${a21}" ]];then return 0;fi;if [[ "${BASH_VERSINFO[2]}" -lt "${a28}" ]];then return 1;fi;return 0;};binary::exists() { local a9="${1}";command -v "${a9}" &> /dev/null || { echo "${a9} is required to run this script" >&2;return 1;};};binary::github() { local a35="${1}";local -r a9="$(basename "${a35}")";local a43="${2}";local a42="${3}";local a56="${4:-}";curl -Lso /dev/stdout "https://github.com/${a43}/releases/download/${a42}" | { if [[ -n "${a56}" ]];then tar -xz -C "$(dirname "${a35}")" "${a56}";else tee "${a35}" &> /dev/null;fi;chmod +x "${a35}";};};binary::arch() { local a22="${1}";local -r a46="$(uname -m)";case "${a46}" in +x86_64|amd64)if (( a22 )); then echo "64-bit"; else echo "amd64"; fi;; +armv7l)echo "arm";; +aarch64)echo "arm64";; +*)echo "${a46}";; +esac;};binary::jq() { binary::exists "jq" 2>/dev/null || { local -r a14="$(github::latest "stedolan/jq")" system="$(uname -s)";binary::github "${PATH_BIN?}/jq" "stedolan/jq" "${a14}/jq-${system,,}-$(binary::arch)";};};binary::vale() { binary::exists "vale" 2>/dev/null || { local -r a14="$(github::latest "errata-ai/vale")" system="$(uname -s)";binary::github "${PATH_BIN?}/vale" "errata-ai/vale" "${a14}/vale_${a14:1}_$(uname -s)_$(binary::arch 1).tar.gz" "vale";};};docker::user() { local a53="${1:-"$(id -u)"}";local a60="${2:-"$(id -g)"}";local a34="${3:-"$(whoami)"}";local a44="${4:-"/workspace"}";local a29="${5:-"/bin/sh"}";local a41;a41="$(pwd)";a41="${a41#"${PATH_BASE:-}"}";if [[ "${a41}" == "$(pwd)" ]];then a41="${a44}";else a41="${a44}${a41}";fi;echo "${a34}:x:${a53}:${a60}::${a44}:${a29}" > /tmp/docker_passwd;echo "${a34}:x:${a60}:" > /tmp/docker_group;echo "-v /tmp/docker_passwd:/etc/passwd -v /tmp/docker_group:/etc/group";echo "-u ${a53}:${a60}";echo "-v ${PATH_BASE:-"$(pwd)"}:${a44}";echo "-w ${a41}";};error::stacktrace() { local -r a45="${1:-${?}}";if (( a45 ));then echo -e "\n\033[38;5;196m■■ Stacktrace(${a45}): \e[1m${BASH_COMMAND}\e[22m";for a63 in $(seq 1 $((${#FUNCNAME[@]} - 2)));do echo -e "${a63}. ${BASH_SOURCE[a63]}:${BASH_LINENO[a63-1]} ➜ ${FUNCNAME[a63]}()";done;echo -e "\033[0m";return "${a45}";fi;};:args::_error() { declare -p a27 &>/dev/null || local a27="???";echo ":args error [${a27}] ➜ ${1}" >&2;exit 2;};:args::error() { declare -p a27 &>/dev/null || local a27="???";echo -e "[ ${a27/[:|]*} ] invalid argument\n➜ ${1}\n" >&2;exit 2;};:args::error_usage() { declare -p a27 &>/dev/null || local a27="???";echo -e "[ ${a27/[:|]*} ] invalid usage\n➜ ${1}\n" >&2;echo -e "Use \"${0##*/} -h\" for more information" >&2;exit 2;};fmt::tty() { local a57="${1:-"$(cat)"}";if ! command -v fmt &>/dev/null || [[ ! -t 1 ]];then echo "${a57}";return 0;fi;local a37;a37="$(tput cols)";echo "${a57}" | fmt -w "${a37}";};github::latest() { local a43="${1}";curl -fsSLI -o /dev/null -w "%{url_effective}" "https://github.com/${a43}/releases/latest" | rev | cut -d'/' -f1 | rev;};declare -gA a1=();import() { local a61="${1}";(( ${a1["${a61}"]:-} )) || { a1["${a61}"]=1;if [[ ${a61:0:1} == "@" ]];then a61="${PATH_BASE:?"PATH_BASE missing"}/${a61:1}";elif [[ ${a61:0:1} == "~" ]];then local _s="${ARGSH_SOURCE:-${BASH_SOURCE[-1]}}";a61="${_s%/*}/${a61:1}";else a61="${BASH_SOURCE[0]%/*}/${a61}";fi;import::source "${a61}" || exit 1;};};import::source() { local a61="${1}";for a58 in "" ".sh" ".bash";do if [[ -f "${a61}${a58}" ]];then . "${a61}${a58}";return;fi;done;echo "Library not found ${a61}" >&2;return 1;};import::clear() { a1=();};is::tty() { [[ -t 1 ]];};is::array() { declare -p "${1}" &>/dev/null && [[ $(declare -p "${1}") == "declare -a"* ]];};is::uninitialized() { local a52="${1}";if is::array "${a52}";then [[ $(declare -p "${a52}") == "declare -a ${a52}" ]];else [[ ! ${!a52+x} ]];fi;};is::set() { ! is::uninitialized "${1}";};argsh::shebang() { local -r a42="${1}";: "${ARGSH_SOURCE="${a42}"}";export ARGSH_SOURCE;[[ "${BASH_SOURCE[-1]}" != "${a42}" && -f "${a42}" ]] || { binary::exists docker || { echo "This script requires Docker to be installed";return 1;} >&2;local a59="";! tty -s || a59="-it";docker run --rm ${a59} $(docker::user) -e "BATS_LOAD" -e "ARGSH_SOURCE" -e "GIT_COMMIT_SHA=$(git rev-parse HEAD 2>/dev/null || :)" -e "GIT_VERSION=$(git describe --tags --dirty 2>/dev/null || :)" ghcr.io/arg-sh/argsh:latest "${@}";return 0;};bash::version 4 3 0 || { echo "This script requires bash 4.3.0 or later";return 1;} >&2;shift;. "${a42}";};string::drop-index() { local a13="${1}";local a24="${2}";local a12="${3:-1}";echo "${a13:0:a24}${a13:a24+a12}";};string::random() { local a12="${1:-42}";local a25="${2:-"a-zA-Z0-9"}";local a57;until [[ "${a57:-}" =~ ^[:alpha:] ]];do a57=$(tr -dc "${a25}" < /dev/urandom | fold -w "${a12}" | head -n 1 || :);done;echo "${a57}";};string::indent() { local a13="${1:-'-'}";local a8="${2:-0}";local a40 a31;[[ ${a13} != '-' ]] || a13="$(cat)";mapfile -t a31 < <(echo "${a13}");for a40 in "${a31[@]}";do a40="$(string::trim-left "${a40}")";(( a8 == 0 )) || printf "%${a8}s" " ";echo "${a40}";done;};string::trim-left() { local a13="${1}";local a25="${2:-" "$'\n'$'\t'}";[[ -n ${a13:-} ]] || return 0;[[ ${a13} != '-' ]] || a13="$(cat)";while [[ -n "${a13}" ]];do [[ ${a25} == *${a13:0:1}* ]] || break;a13="${a13:1}";done;echo "${a13}";};string::trim-right() { local a13="${1:-'-'}";local a25="${2:-" "$'\n'$'\t'}";[[ ${a13} != '-' ]] || a13="$(cat)";while [[ -n "${a13}" ]];do [[ ${a25} == *${a13: -1}* ]] || break;a13="${a13:0: -1}";done;echo "${a13}";};string::trim() { local a13="${1:-'-'}";local a25="${2:-" "$'\n'$'\t'}";[[ ${a13} != '-' ]] || a13="$(cat)";echo "${a13}" | string::trim-left - "${a25}" | string::trim-right - "${a25}";};to::string() { local a20="${1}";echo "${a20}";};to::boolean() { local a20="${1}";case "${a20}" in +""|"false"|"0")a20="0";; +*)a20="1";; +esac;echo "${a20}";};to::int() { local a20="${1}";[[ ${a20} =~ ^-?[0-9]+$ ]] || return 1;echo "${a20}";};to::float() { local a20="${1}";[[ ${a20} =~ ^-?[0-9]+(\.[0-9]+)?$ ]] || return 1;echo "${a20}";};to::stdin() { local a20="${1}";[[ ${a20} != "-" ]] || a20="$(cat)";echo "${a20}";};to::file() { local a20="${1}";[[ -f "${a20}" ]] || return 1;echo "${a20}";};[[ "${BASH_SOURCE[0]}" != "${0}" ]] || argsh::shebang "${@}" \ No newline at end of file