From f3e70c61cbf9b4cf458f05abfebb9e1ca92385d0 Mon Sep 17 00:00:00 2001 From: yage Date: Mon, 11 Dec 2023 17:07:09 -0700 Subject: [PATCH] v3.9.0 ===================================================================== --- Changes ------------------------------ - scwrypts runner has new arguments -q/--quiet allows quiet-mode operation while still logging to logfiles -v/--verbose forces verbose mode --version longform required (-v is now for "verbose" mode) - scwrypts runner now auto-detects certain CLI usage, running in quiet, logged mode if pattern match successfully identifies a single scwrypt (or when using --name); use --verbose to override this behavior - 'k exec' no longer requires double '--' if a '--' comes after - old : k exec -it my-pod-0 -- -- /bin/sh + new : k exec -it my-pod-0 -- /bin/sh + still works : k -- exec -it my-pod-0 -- /bin/sh --- Bug Fixes ---------------------------- - fixed various plugins/kubectl auto-completion settings; arguments after '--' or profile number (e.g. 'k 1 get deployments') will now appropriately autocomplete in the indicated profile - helm template functions now work on related .tpl files as well (renders from chart root) - fixed some goofy UTF-8 icons in zsh/lib/utils/io --- New Features ------------------------- - (experimental) scwrypts zsh plugin for interactive command selection (like CTRL+SPACE), but allows you to build command arguments, providing help dialogue for the selected command --- New Scripts -------------------------- - zsh/misc/tally ) helps keep tally-counts of things; helpful when running long scripts "what iteration am I on" --- plugins/kubectl/driver/kubectl.completion.zsh | 57 ++++-- plugins/kubectl/driver/kubectl.driver.zsh | 6 +- run | 179 +++++++++--------- scwrypts.plugin.zsh | 31 ++- zsh/lib/config.user.zsh | Bin 453 -> 502 bytes zsh/lib/helm/template.module.zsh | 1 + zsh/lib/helm/validate.module.zsh | 2 + zsh/lib/misc/tally.module.zsh | 106 +++++++++++ zsh/lib/utils/io.zsh | 4 +- zsh/misc/tally | 17 ++ 10 files changed, 289 insertions(+), 114 deletions(-) create mode 100644 zsh/lib/misc/tally.module.zsh create mode 100755 zsh/misc/tally diff --git a/plugins/kubectl/driver/kubectl.completion.zsh b/plugins/kubectl/driver/kubectl.completion.zsh index e99ddf5..bb02f5f 100644 --- a/plugins/kubectl/driver/kubectl.completion.zsh +++ b/plugins/kubectl/driver/kubectl.completion.zsh @@ -2,30 +2,45 @@ command -v compdef >/dev/null 2>&1 || return 0 ##################################################################### -_k() { - local C=$(k meta get context) - local NS=$(k meta get namespace) +for CLI in kubectl helm flux +do + eval "_${CLI[1]}() { + local SUBSESSION=0 + echo \${words[2]} | grep -q '^[0-9]\\+$' && SUBSESSION=\${words[2]} - local KUBEWORDS=(kubectl) - [ $C ] && KUBEWORDS+=(--context $C) - [ $NS ] && KUBEWORDS+=(--namespace $NS) + local PASSTHROUGH_WORDS=($CLI) + [[ \$CURRENT -gt 2 ]] && echo \${words[2]} | grep -qv '^[0-9]\\+$' && { + local KUBECONTEXT=\$(k \$SUBSESSION meta get context) + local NAMESPACE=\$(k \$SUBSESSION meta get namespace) - words="$KUBEWORDS ${words[@]:1}" - _kubectl -} + [ \$KUBECONTEXT ] \ + && PASSTHROUGH_WORDS+=($([[ $CLI =~ ^helm$ ]] && echo '--kube-context' || echo '--context') \$KUBECONTEXT) \ + ; + [ \$NAMESPACE ] \ + && PASSTHROUGH_WORDS+=(--namespace \$NAMESPACE) \ + ; + } -compdef _k k + local DELIMIT_COUNT=0 + local WORD + for WORD in \${words[@]:1} + do + case \$WORD in + [0-9]* ) continue ;; + -- ) + echo \$words | grep -q 'exec' && ((DELIMIT_COUNT+=1)) + [[ \$DELIMIT_COUNT -eq 0 ]] && ((DELIMIT_COUNT+=1)) && continue + ;; + esac + PASSTHROUGH_WORDS+=(\"\$WORD\") + done -##################################################################### -_h() { - local C=$(k meta get context) - local NS=$(k meta get namespace) + echo \"\$words\" | grep -q '\\s\\+$' && PASSTHROUGH_WORDS+=(' ') - local KUBEWORDS=(kubectl) - [ $C ] && KUBEWORDS+=(--context $C) - [ $NS ] && KUBEWORDS+=(--namespace $NS) + words=\"\$PASSTHROUGH_WORDS\" + _$CLI + } + " - words="$KUBEWORDS ${words[@]:1}" - _helm -} -compdef _h h + compdef _${CLI[1]} ${CLI[1]} +done diff --git a/plugins/kubectl/driver/kubectl.driver.zsh b/plugins/kubectl/driver/kubectl.driver.zsh index acb7b0a..b78523f 100644 --- a/plugins/kubectl/driver/kubectl.driver.zsh +++ b/plugins/kubectl/driver/kubectl.driver.zsh @@ -110,7 +110,11 @@ _SCWRYPTS_KUBECTL_DRIVER() { shift 1 ;; - -- ) shift 1; break ;; + -- ) + echo $USER_ARGS | grep -q 'exec' && USER_ARGS+=(--) + shift 1 + break + ;; * ) [ ! $CUSTOM_COMMAND ] && { diff --git a/run b/run index 3b99697..14cd51f 100755 --- a/run +++ b/run @@ -6,24 +6,35 @@ source "${0:a:h}/zsh/lib/import.driver.zsh" || exit 42 __RUN() { local USAGE=' - usage: scwrypts [OPTIONS ...] SCRIPT -- [SCRIPT OPTIONS ...] - - OPTIONS - -g, --group only use scripts from the indicated group - -t, --type only use scripts of the indicated type - -m, --name only run the script if there is an exact match - (requires type and group) - - -y, --yes auto-accept all [yn] prompts through current scwrypt - -e, --env set environment; overwrites SCWRYPTS_ENV - -n, --no-log skip logging and run in quiet mode - - --update update scwrypts library to latest version - --list-envs print out environment list and exit - - -v, --version print out scwrypts version and exit - -l, --list print out command list and exit - -h, --help display this message and exit + usage: scwrypts [... options ...] [patterns] -- [...script options...] + + options: + selection + -m, --name only run the script if there is an exact match + (requires type and group) + -g, --group only use scripts from the indicated group + -t, --type only use scripts of the indicated type + + runtime + -y, --yes auto-accept all [yn] prompts through current scwrypt + -e, --env set environment; overwrites SCWRYPTS_ENV + -q, --quiet run in quiet mode + -n, --no-log skip the log file and run in quiet mode + -v, --verbose override quiet mode settings and print all debug dialogue + + 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 + (usually "-- --help" will provide more information) ' cd "$SCWRYPTS_ROOT" @@ -32,70 +43,29 @@ __RUN() { local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME + local ALLOW_LOGFILE=1 + local VERBOSE=1 + + [ $CI ] && [ ! $SCWRYPTS_CI_FORCE_NON_VERBOSE ] && VERBOSE=2 + local ERROR=0 while [[ $# -gt 0 ]] do case $1 in - -t | --type ) - [ ! $2 ] && ERROR "missing value for argument $1" && break - SEARCH_TYPE=$2 - shift 2 - ;; - -g | --group ) - [ ! $2 ] && ERROR "missing value for argument $1" && break - SEARCH_GROUP=$2 - shift 2 - ;; - -m | --name ) - [ ! $2 ] && ERROR "missing value for argument $1" && break - SEARCH_NAME=$2 - shift 2 - ;; - -[a-z][a-z]* ) VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/') set -- $(echo " $VARSPLIT ") ${@:2} ;; - -h | --help ) - USAGE + -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 -C "$SCWRYPTS__ROOT__scwrypts" describe --tags) return 0 ;; - -n | --no-log ) - [ ! $SUBSCWRYPT ] && SUBSCWRYPT=0 - shift 1 - ;; - - -y | --yes ) - export __SCWRYPTS_YES=1 - shift 1 - ;; - - -e | --env ) - [ ! $2 ] && ERROR "missing value for argument $1" && break - [ ! $SUBSCWRYPTS ] \ - && [ $ENV_NAME ] \ - && WARNING 'overwriting session environment' \ - ; - - ENV_NAME="$2" - STATUS "using CLI environment '$ENV_NAME'" - shift 2 - ;; - -l | --list ) - SCWRYPTS__GET_AVAILABLE_SCWRYPTS - return 0 - ;; - --list-envs ) - SCWRYPTS__GET_ENV_NAMES - return 0 - ;; - -v | --version ) - echo scwrypts $(cd "$SCWRYPTS__ROOT__scwrypts"; git describe --tags) - return 0 - ;; --update ) cd "$SCWRYPTS__ROOT__scwrypts" git fetch --quiet origin main @@ -118,24 +88,53 @@ __RUN() { } return 0 ;; - -- ) + + -m | --name ) + [ ! $2 ] && ERROR "missing value for argument $1" && break + SEARCH_NAME=$2 shift 1 - break # pass arguments after '--' to the scwrypt ;; - --* ) - ERROR "unrecognized argument '$1'" + + -g | --group ) + [ ! $2 ] && ERROR "missing value for argument $1" && break + SEARCH_GROUP=$2 shift 1 ;; - * ) - SEARCH_PATTERNS+=($1) + + -t | --type ) + [ ! $2 ] && ERROR "missing value for argument $1" && break + SEARCH_TYPE=$2 shift 1 ;; + + -y | --yes ) export __SCWRYPTS_YES=1 ;; + -q | --quiet ) VERBOSE=0 ;; + -n | --no-log ) VERBOSE=0 ; [ ! $SUBSCWRYPT ] && SUBSCWRYPT=0 ;; + -v | --verbose ) VERBOSE=2 ;; + + -e | --env ) + [ ! $2 ] && ERROR "missing value for argument $1" && break + [ ! $SUBSCWRYPTS ] \ + && [ $ENV_NAME ] \ + && WARNING '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' + [ $SEARCH_TYPE ] || ERROR '--name requires --type argument' + [ $SEARCH_GROUP ] || ERROR '--name requires --group argument' } CHECK_ERRORS @@ -209,9 +208,12 @@ __RUN() { local TYPE="$SEARCH_TYPE" local GROUP="$SEARCH_GROUP" - [[ $(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) + [[ $VERBOSE -eq 2 ]] || VERBOSE=0 + } || { + SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | FZF "select a script to run" --header-lines 1) + } [ $SCWRYPT_SELECTION ] || exit 2 SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION @@ -254,7 +256,8 @@ __RUN() { ########################################## - [ ! $SUBSCWRYPT ] \ + : \ + && [ ! $SUBSCWRYPT ] \ && [[ $ENV_NAME =~ prod ]] \ && { __VALIDATE_UPSTREAM_TIMELINE || ABORT; } @@ -268,6 +271,7 @@ __RUN() { local LOGFILE=$(__GET_LOGFILE) local HEADER=$( + [[ $VERBOSE -gt 0 ]] || return 0 [ $SUBSCWRYPT ] && return 0 echo '=====================================================================' echo "script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME" @@ -289,14 +293,14 @@ __RUN() { { [ $HEADER ] && echo $HEADER - echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m' + [[ $VERBOSE -gt 0 ]] && echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m' (eval "$RUN_STRING $(printf "%q " "$@")") EXIT_CODE=$? - echo '\033[1;33m--- END OUTPUT ---------------------------\033[0m' + [[ $VERBOSE -gt 0 ]] && echo '\033[1;33m--- END OUTPUT ---------------------------\033[0m' [[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m' - 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" } 2>&1 | tee --append "$LOGFILE" exit $(\ @@ -338,10 +342,9 @@ __VALIDATE_UPSTREAM_TIMELINE() { } __GET_LOGFILE() { - [ $SUBSCWRYPT ] \ - || [[ $SCWRYPT_NAME =~ scwrypts/logs ]] \ - || [[ $SCWRYPT_NAME =~ interactive ]] \ - && return 0 + [ $SUBSCWRYPT ] && return 0 + [[ $SCWRYPT_NAME =~ scwrypts/logs ]] && return 0 + [[ $SCWRYPT_NAME =~ interactive ]] && return 0 echo "$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log" } diff --git a/scwrypts.plugin.zsh b/scwrypts.plugin.zsh index d83fa37..cd2ce74 100644 --- a/scwrypts.plugin.zsh +++ b/scwrypts.plugin.zsh @@ -6,7 +6,7 @@ SCWRYPTS__ZSH_PLUGIN() { local NAME local TYPE local GROUP - zle clear-command-line + LBUFFER= RBUFFER= [ ! $SCWRYPT_SELECTION ] && { zle accept-line; return 0; } SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION @@ -14,13 +14,40 @@ SCWRYPTS__ZSH_PLUGIN() { which scwrypts >/dev/null 2>&1\ && RBUFFER="scwrypts" || RBUFFER="$SCWRYPTS_ROOT/scwrypts" - RBUFFER+=" --name $NAME --group $GROUP --type $TYPE" + RBUFFER+=" --name $NAME --group $GROUP --type $TYPE --verbose" zle accept-line } zle -N scwrypts SCWRYPTS__ZSH_PLUGIN bindkey $SCWRYPTS_SHORTCUT scwrypts +##################################################################### +SCWRYPTS__ZSH_BUILDER_PLUGIN() { + local SCWRYPT_SELECTION=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS | FZF 'select a script' --header-lines 1) + local NAME + local TYPE + local GROUP + LBUFFER= RBUFFER= + [ ! $SCWRYPT_SELECTION ] && { zle accept-line; return 0; } + + SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION + + scwrypts --name $NAME --group $GROUP --type $TYPE -- --help >&2 || { + zle accept-line + return 0 + } + echo + + zle reset-prompt + which scwrypts >/dev/null 2>&1\ + && LBUFFER="scwrypts" || LBUFFER="$SCWRYPTS_ROOT/scwrypts" + + LBUFFER+=" --name $NAME --group $GROUP --type $TYPE -- " +} + +zle -N scwrypts-builder SCWRYPTS__ZSH_BUILDER_PLUGIN +bindkey $SCWRYPTS_BUILDER_SHORTCUT scwrypts-builder + ##################################################################### SCWRYPTS__ZSH_PLUGIN_ENV() { local RESET='reset' diff --git a/zsh/lib/config.user.zsh b/zsh/lib/config.user.zsh index 3f5831a5af658d9b779790f6a1a280eecbf13635..7610d9e92417df510fd4fc38036348571e5d2077 100644 GIT binary patch delta 68 zcmX@g{Ed0Sj)_}z%@u$^S;09Z$VWk2L7ywwIXoybAS5{6Db&-)#Wg5C*uy_4#5pv? OR$WpZp)hjd>stWF02Flq delta 24 gcmeyye3W^@j){9Txs(;0LxOx1v=#Ix%P`&o0CLm_CIA2c diff --git a/zsh/lib/helm/template.module.zsh b/zsh/lib/helm/template.module.zsh index 9bffa8e..df4f23b 100644 --- a/zsh/lib/helm/template.module.zsh +++ b/zsh/lib/helm/template.module.zsh @@ -4,6 +4,7 @@ DEPENDENCIES+=(helm kubeval) REQUIRED_ENV+=() use helm/validate +use scwrypts ##################################################################### diff --git a/zsh/lib/helm/validate.module.zsh b/zsh/lib/helm/validate.module.zsh index 9d3d621..f68ac50 100644 --- a/zsh/lib/helm/validate.module.zsh +++ b/zsh/lib/helm/validate.module.zsh @@ -38,6 +38,8 @@ HELM__VALIDATE() { HELM_ARGS+=(--values $TEMPLATE_FILENAME) USE_CHART_ROOT=1 } + [[ $TEMPLATE_FILENAME =~ .tpl$ ]] \ + && USE_CHART_ROOT=1 [[ $(dirname $TEMPLATE_FILENAME) =~ ^$CHART_ROOT$ ]] \ && USE_CHART_ROOT=1 diff --git a/zsh/lib/misc/tally.module.zsh b/zsh/lib/misc/tally.module.zsh new file mode 100644 index 0000000..6ff76b3 --- /dev/null +++ b/zsh/lib/misc/tally.module.zsh @@ -0,0 +1,106 @@ +##################################################################### + +DEPENDENCIES+=() +REQUIRED_ENV+=() + +##################################################################### + +TALLY_USE_REDIS=false # maybe someday +TALLY_PATH="$SCWRYPTS_DATA_PATH/tally" + +##################################################################### + +TALLY() { + local USAGE=" + usage: [...options...] + + options: + -c, --increment-count increment the tally by this much (default 1) + -n, --tally-name name of tally system (default 'default') + + -g, --get only output the current value + -s, --set set the tally to a specific value + -r, --reset set the tally back to zero + + --raw only output the tally value + + -h, --help print this dialogue and exit + + Simple tally mark system; keep track of a count. + " + + local INCREMENT_COUNT=1 + local TALLY_NAME=default + local RAW=false + + local SET_VALUE= + + while [[ $# -gt 0 ]] + do + case $1 in + -c | --increment-count ) INCREMENT_COUNT=$2; shift 1 ;; + -n | --tally-name ) TALLY_NAME=$2; shift 1 ;; + + -g | --get ) INCREMENT_COUNT=0 ;; + + -s | --set ) SET_VALUE=$2; shift 1 ;; + -r | --reset ) SET_VALUE=0 ;; + + --raw ) RAW=true ;; + + -h | --help ) USAGE; return 0 ;; + + * ) ERROR "unknown argument '$1'" ;; + esac + shift 1 + done + + [ $TALLY_NAME ] && echo "$TALLY_NAME" | grep -qv '/' \ + || ERROR "invalid tally name '$TALLY_NAME'" + + local TALLY_FILENAME="$TALLY_PATH/$TALLY_NAME.txt" + + CHECK_ERRORS --no-fail || return 1 + + ########################################## + + local NEW_VALUE CURRENT_VALUE=0 + [ $SET_VALUE ] && NEW_VALUE=$SET_VALUE || { + [ -f "$TALLY_FILENAME" ] && { + CURRENT_VALUE=$(cat "$TALLY_FILENAME" | tail -n1 | grep '^[0-9]\+') + } + + [ $CURRENT_VALUE ] || { + ERROR "malformed tally file '$TALLY_FILENAME'; aborting" + return 1 + } + + NEW_VALUE=$(($CURRENT_VALUE + $INCREMENT_COUNT)) + } + + ########################################## + + local TALLY_DIR="$(dirname "$TALLY_FILENAME")" + + [ -d "$TALLY_DIR" ] || mkdir -p "$TALLY_DIR" + [ -d "$TALLY_DIR" ] || { + ERROR "unable to write to '$TALLY_DIR'; aborting" + return 1 + } + + echo "# autogenerated tally file; avoid direct modification\n$NEW_VALUE" > "$TALLY_FILENAME" || { + ERROR "failed to write to '$TALLY_FILENAME': aborting" + return 1 + } + + ########################################## + + case $RAW in + true ) printf "$NEW_VALUE" ;; + false ) + case $TALLY_NAME in + default ) INFO "current tally : $NEW_VALUE" ;; + * ) INFO "$TALLY_NAME : $NEW_VALUE" ;; + esac + esac +} diff --git a/zsh/lib/utils/io.zsh b/zsh/lib/utils/io.zsh index ee134f5..a4698f1 100644 --- a/zsh/lib/utils/io.zsh +++ b/zsh/lib/utils/io.zsh @@ -43,11 +43,11 @@ 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 "$@"; } +INFO() { PREFIX="INFO ℹ" COLOR=$__WHITE PRINT "$@"; } PROMPT() { PREFIX="PROMPT " COLOR=$__CYAN PRINT "$@" - PREFIX="USER " COLOR=$__CYAN PRINT '' --no-line-end + PREFIX="USER ⌨" COLOR=$__CYAN PRINT '' --no-line-end } FAIL() { ERROR "${@:2}"; exit $1; } diff --git a/zsh/misc/tally b/zsh/misc/tally new file mode 100755 index 0000000..bf9677d --- /dev/null +++ b/zsh/misc/tally @@ -0,0 +1,17 @@ +#!/bin/zsh +##################################################################### +DEPENDENCIES+=() +REQUIRED_ENV+=() + +use misc/tally + +CHECK_ENVIRONMENT +##################################################################### + +MAIN() { + unset USAGE + TALLY $@ +} + +##################################################################### +MAIN $@