Compare commits

..

5 Commits

Author SHA1 Message Date
96992e9344 v2.3.0
=====================================================================

--- New Scripts --------------------------

zsh )
  latex + latex template engine
   - latex/build-pdf
   - latex/cleanup
   - latex/create-new
   - latex/get-pdf
   - latex/open-pdf

  beta SQL script -- got tired of floating this; works, but only OK
   - db/run-sql/postgres

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

- Added 'math', 'basic', and 'times-new-roman' templates to latex
- Added 'readlink' to list of required coreutils
- Added __INPUT to read into a variable with prompt (zsh/utils/io)
- Added $EXECUTION_DIR to interact with the user's working directory

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

- subscwrypts no longer force stdout/stderr to tty
2022-08-09 21:51:31 -06:00
e8bb889789 v2.2.0
=====================================================================

--- New Scripts --------------------------

zsh )
  amazon EKS
   - aws/eks/login

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

- moved global .config to global/config.zsh
- moved various global configurations to global/

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

- REDIS_AUTH no longer required to attempt connection
- global configurations now propagate to non-zsh scripts
2022-08-09 13:18:41 -06:00
89e899d49d v2.1.0
=====================================================================

--- New Scripts --------------------------

zsh )
  database backup/restore
   - db/postgres/pg_dump
   - db/postgres/pg_restore
   - aws/rds/create-backup
   - aws/rds/load-backup

  redis-cached curl commands
   - redis/curl

  youtube download
   - youtube/download
   - youtube/get-audio-clip

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

- 'scwrypts' executable now reloads upon execution to prevent staleness
- added various options to improve api/cli; see 'scwrypts --help' for more

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

- fixed an issue with .config settings' visibility to non-zsh scripts
- fixed an issue with command arguments globbing too early
2022-08-02 00:24:29 -06:00
f7eec633ef v2.0.3
=====================================================================

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

- rds/interactive-login now escapes special password characters
2022-07-30 11:02:47 -06:00
db0d0092db v2.0.2
=====================================================================

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

- improved colors readability by naming color variables in zsh/utils

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

- aws/efs/mount wouldn't mount if the previous session was not
  explicitly unmounted. now it does :)
2022-07-01 22:17:23 -06:00
51 changed files with 1359 additions and 402 deletions

42
global/common.zsh Normal file
View File

@ -0,0 +1,42 @@
#####################################################################
[ ! $SCWRYPTS_ROOT ] && SCWRYPTS_ROOT="$(dirname ${0:a:h})"
source "${0:a:h}/config.zsh"
#####################################################################
__SCWRYPT=1 # arbitrary; indicates scwrypts exists
__PREFERRED_PYTHON_VERSIONS=(3.10 3.9)
__NODE_VERSION=18.0.0
__ENV_TEMPLATE=$SCWRYPTS_ROOT/.env.template
#####################################################################
__GET_PATH_TO_RELATIVE_ARGUMENT() {
[[ $1 =~ ^[.] ]] \
&& echo $(readlink -f "$EXECUTION_DIR/$1") \
|| echo "$1" \
;
true
}
#####################################################################
__RUN_SCWRYPT() {
((SUBSCWRYPT+=1))
{ printf ' '; printf '--%.0s' {1..$SUBSCWRYPT}; printf " ($SUBSCWRYPT) "; } >&2
echo " BEGIN SUBSCWRYPT : $(basename $1)" >&2
SUBSCWRYPT=$SUBSCWRYPT SCWRYPTS_ENV=$ENV_NAME \
"$SCWRYPTS_ROOT/scwrypts" $@
EXIT_CODE=$?
{ printf ' '; printf '--%.0s' {1..$SUBSCWRYPT}; printf " ($SUBSCWRYPT) "; } >&2
echo " END SUBSCWRYPT : $(basename $1)" >&2
((SUBSCWRYPT-=1))
return $EXIT_CODE
}

Binary file not shown.

View File

@ -8,7 +8,7 @@ class RedisClient(StrictRedis):
super().__init__(
host = getenv('REDIS_HOST'),
port = getenv('REDIS_PORT'),
password = getenv('REDIS_AUTH'),
password = getenv('REDIS_AUTH', required=False),
decode_responses = True,
)

272
run Executable file
View File

@ -0,0 +1,272 @@
#!/bin/zsh
export EXECUTION_DIR=$(pwd)
SCWRYPTS_ROOT="${0:a:h}"
source "$SCWRYPTS_ROOT/zsh/common.zsh" || exit 42
#####################################################################
__RUN() {
local USAGE='
Usage : scwrypts [OPTIONS ...] SCRIPT -- [SCRIPT OPTIONS ...]
OPTIONS
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
-n, --no-log skip logging (useful when calling scwrypts as an api)
-l, --list print out command list and exit
-h, --help display this message and exit
'
cd "$SCWRYPTS_ROOT"
local ENV_NAME="$SCWRYPTS_ENV"
local SEARCH_PATTERNS=()
local ARGS_ERROR=0
while [[ $# -gt 0 ]]
do
case $1 in
-h | --help )
echo $USAGE
return 0
;;
-n | --no-log )
[ ! $SUBSCWRYPT ] && SUBSCWRYPT=0
shift 1
;;
-e | --env )
[ $ENV_NAME ] && __WARNING 'overwriting session environment'
ENV_NAME="$2"
__STATUS "using CLI environment '$ENV_NAME'"
shift 2
;;
-l | --list )
__OUTPUT_COMMAND_LIST
return 0
;;
-- )
shift 1
break # pass arguments after '--' to the scwrypt
;;
-* )
__ERROR "unrecognized argument '$1'"
((ARGS_ERROR+=1))
shift 1
;;
* )
SEARCH_PATTERNS+=$1
shift 1
;;
esac
done
[[ $ARGS_ERROR -gt 0 ]] && {
echo $USAGE
return 1
}
##########################################
local SCRIPT=$(__SELECT_SCRIPT $SEARCH_PATTERNS)
[ ! $SCRIPT ] && exit 2
local ENV_REQUIRED=$(__CHECK_ENV_REQUIRED && echo 1 || echo 0)
[[ $ENV_REQUIRED -eq 1 ]] && {
[ ! $ENV_NAME ] && ENV_NAME=$(__SELECT_ENV)
local ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
[ -f "$ENV_FILE" ] && source "$ENV_FILE" \
|| __FAIL 5 "missing or invalid environment '$ENV_NAME'"
export ENV_NAME
}
[ ! $SUBSCWRYPT ] \
&& [[ $ENV_NAME =~ prod ]] \
&& { __VALIDATE_UPSTREAM_TIMELINE || __ABORT; }
local RUN_STRING=$(__GET_RUN_STRING $SCRIPT $ENV_NAME)
[ ! $RUN_STRING ] && exit 3
##########################################
local LOGFILE=$(__GET_LOGFILE $SCRIPT)
local HEADER=$(
[ $SUBSCWRYPT ] && return 0
echo '====================================================================='
echo "script : $SCRIPT"
echo "run at : $(date)"
echo "config : $ENV_NAME"
[ ! $LOGFILE ] && echo '\033[1;33m------------------------------------------\033[0m'
)
[ ! $LOGFILE ] && {
[ $HEADER ] && echo $HEADER
[ $SUBSCWRYPT ] && {
eval $RUN_STRING $@
exit $?
} || {
eval $RUN_STRING $@ </dev/tty >/dev/tty 2>&1
exit $?
}
}
{
[ $HEADER ] && echo $HEADER
echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m'
eval $RUN_STRING $@
EXIT_CODE=$?
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"
} 2>&1 | tee --append "$LOGFILE"
exit $(\
sed -n 's/^terminated with.*code \([0-9]*\).*$/\1/p' $LOGFILE \
| tail -n1
)
}
#####################################################################
__OUTPUT_COMMAND_LIST() {
local LAST_TYPE LAST_SUBSET
for SCRIPT in $(__GET_AVAILABLE_SCRIPTS)
do
TYPE=$(echo $SCRIPT | sed 's/\/.*//')
SUBSET=$(echo $SCRIPT | sed 's/.*\/\(.*\)\/[^\/]*$/\1/')
[[ ! $LAST_TYPE =~ $TYPE ]] && {
echo >&2
echo "\\033[1;32m$TYPE scwrypts\\033[0m" >&2
LAST_SUBSET=''
}
[ $LAST_SUBSET ] && [[ ! $LAST_SUBSET =~ $SUBSET ]] && {
echo >&2
}
printf ' - ' >&2
echo $SCRIPT
LAST_TYPE=$TYPE
LAST_SUBSET=$SUBSET
done
}
#####################################################################
__SELECT_SCRIPT() {
local SCRIPT
local SCRIPTS=$(__GET_AVAILABLE_SCRIPTS)
local SEARCH=($@)
[[ ${#SEARCH[@]} -eq 0 ]] && {
SCRIPT=$(echo $SCRIPTS | __FZF 'select a script')
}
[[ ${#SEARCH[@]} -eq 1 ]] && [ -f ./$SEARCH ] && {
SCRIPT=$SEARCH
}
[ ! $SCRIPT ] && [[ ${#SEARCH[@]} -gt 0 ]] && {
SCRIPT=$SCRIPTS
for PATTERN in $SEARCH
do
SCRIPT=$(echo $SCRIPT | grep $PATTERN)
done
[ ! $SCRIPT ] && __FAIL 2 "no script found by name '$@'"
[[ $(echo $SCRIPT | wc -l) -gt 1 ]] && {
__STATUS "more than one script matched '$@'"
SCRIPT=$(echo $SCRIPT | __FZF 'select a script')
}
}
echo $SCRIPT
}
__GET_RUN_STRING() {
local SCRIPT="$1"
local ENV_NAME="$2"
local TYPE=$(echo $SCRIPT | sed 's/\/.*$//')
local RUN_STRING
local _VIRTUALENV="$SCWRYPTS_VIRTUALENV_PATH/$TYPE/bin/activate"
[ -f $_VIRTUALENV ] && source $_VIRTUALENV
case $TYPE in
py ) __CHECK_DEPENDENCY python || return 1
RUN_STRING="python -m $(echo $SCRIPT | sed 's/\//./g; s/\.py$//; s/\.\.//')"
CURRENT_PYTHON_VERSION=$(python --version | sed 's/^[^0-9]*\(3\.[^.]*\).*$/\1/')
echo $__PREFERRED_PYTHON_VERSIONS | grep -q $CURRENT_PYTHON_VERSION || {
__WARNING "only tested on the following python versions: $(printf ', %s.x' ${__PREFERRED_PYTHON_VERSIONS[@]} | sed 's/^, //')"
__WARNING 'compatibility may vary'
}
;;
zsh ) __CHECK_DEPENDENCY zsh || return 1
RUN_STRING="noglob ./$SCRIPT"
;;
zx ) __CHECK_DEPENDENCY zx || return 1
RUN_STRING="FORCE_COLOR=3 ./$SCRIPT.mjs"
;;
* ) __ERROR "unsupported script type '$SCRIPT_TYPE'"
return 2
;;
esac
RUN_STRING="SCWRYPTS_ENV='$ENV_NAME' $RUN_STRING"
[ -f $_VIRTUALENV ] && RUN_STRING="source '$_VIRTUALENV'; $RUN_STRING"
echo $RUN_STRING
}
__CHECK_ENV_REQUIRED() {
[ $CI ] && return 1
echo $SCRIPT | grep -q 'zsh/scwrypts/logs' && return 1
return 0
}
__VALIDATE_UPSTREAM_TIMELINE() {
__STATUS "on '$ENV_NAME'; checking diff against origin/main"
git fetch --quiet origin main
local SYNC_STATUS=$?
git diff --exit-code origin/main -- . >&2
local DIFF_STATUS=$?
[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
__SUCCESS 'up-to-date with origin/main'
} || {
__WARNING
[[ $SYNC_STATUS -ne 0 ]] && __WARNING 'unable to synchronize with origin/main'
[[ $DIFF_STATUS -ne 0 ]] && __WARNING 'your branch differs from origin/main (diff listed above)'
__WARNING
__yN 'continue?' || return 1
}
}
__GET_LOGFILE() {
local SCRIPT="$1"
[ $SUBSCWRYPT ] \
|| [[ $SCRIPT =~ scwrypts/logs ]] \
|| [[ $SCRIPT =~ interactive ]] \
&& return 0
echo "$SCWRYPTS_LOG_PATH/$(echo $SCRIPT | sed 's/^\.\///; s/\//\%/g').log"
}
#####################################################################
__RUN $@

209
scwrypts
View File

@ -1,209 +1,2 @@
#!/bin/zsh
SCWRYPTS_ROOT="${0:a:h}"
source "$SCWRYPTS_ROOT/zsh/common.zsh" || exit 42
#####################################################################
__RUN() {
cd "$SCWRYPTS_ROOT"
local ENV_NAME="$SCWRYPTS_ENV"
local SEARCH_PATTERNS=()
while [[ $# -gt 0 ]]
do
case $1 in
-e|--env )
[ $ENV_NAME ] && __WARNING 'overwriting session environment'
ENV_NAME="$2"
__STATUS "using CLI environment '$ENV_NAME'"
shift 2
;;
-- )
shift 1
break # pass arguments after '--' to the scwrypt
;;
* )
SEARCH_PATTERNS+=$1
shift 1
;;
esac
done
##########################################
local SCRIPT=$(__SELECT_SCRIPT $SEARCH_PATTERNS)
[ ! $SCRIPT ] && exit 2
local ENV_REQUIRED=$(__CHECK_ENV_REQUIRED && echo 1 || echo 0)
[[ $ENV_REQUIRED -eq 1 ]] && {
[ ! $ENV_NAME ] && ENV_NAME=$(__SELECT_ENV)
local ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
[ -f "$ENV_FILE" ] && source "$ENV_FILE" \
|| __FAIL 5 "missing or invalid environment '$ENV_NAME'"
export ENV_NAME
}
[ ! $SUBSCWRYPT ] \
&& [[ $ENV_NAME =~ prod ]] \
&& { __VALIDATE_UPSTREAM_TIMELINE || __ABORT; }
local RUN_STRING=$(__GET_RUN_STRING $SCRIPT $ENV_NAME)
[ ! $RUN_STRING ] && exit 3
##########################################
local LOGFILE=$(__GET_LOGFILE $SCRIPT)
local HEADER=$(
[ $SUBSCWRYPT ] && return 0
echo '====================================================================='
echo "script : $SCRIPT"
echo "run at : $(date)"
echo "config : $ENV_NAME"
[ ! $LOGFILE ] && echo '\033[1;33m------------------------------------------\033[0m'
)
[ ! $LOGFILE ] && {
[ $HEADER ] && echo $HEADER
eval $RUN_STRING $@ </dev/tty >/dev/tty 2>&1
exit $?
}
{
[ $HEADER ] && echo $HEADER
echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m'
eval $RUN_STRING $@
EXIT_CODE=$?
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"
} 2>&1 | tee --append "$LOGFILE"
exit $(\
sed -n 's/^terminated with.*code \([0-9]*\).*$/\1/p' $LOGFILE \
| tail -n1
)
}
#####################################################################
__SELECT_SCRIPT() {
local SCRIPT
local SCRIPTS=$(__GET_AVAILABLE_SCRIPTS)
local SEARCH=($@)
[[ ${#SEARCH[@]} -eq 0 ]] && {
SCRIPT=$(echo $SCRIPTS | __FZF 'select a script')
}
[[ ${#SEARCH[@]} -eq 1 ]] && [ -f ./$SEARCH ] && {
SCRIPT=$SEARCH
}
[ ! $SCRIPT ] && [[ ${#SEARCH[@]} -gt 0 ]] && {
SCRIPT=$SCRIPTS
for PATTERN in $SEARCH
do
SCRIPT=$(echo $SCRIPT | grep $PATTERN)
done
[ ! $SCRIPT ] && __FAIL 2 "no script found by name '$@'"
[[ $(echo $SCRIPT | wc -l) -gt 1 ]] && {
__STATUS "more than one script matched '$@'"
SCRIPT=$(echo $SCRIPT | __FZF 'select a script')
}
}
echo $SCRIPT
}
__GET_RUN_STRING() {
local SCRIPT="$1"
local ENV_NAME="$2"
local TYPE=$(echo $SCRIPT | sed 's/\/.*$//')
local RUN_STRING
local _VIRTUALENV="$SCWRYPTS_VIRTUALENV_PATH/$TYPE/bin/activate"
[ -f $_VIRTUALENV ] && source $_VIRTUALENV
case $TYPE in
py ) __CHECK_DEPENDENCY python || return 1
RUN_STRING="python -m $(echo $SCRIPT | sed 's/\//./g; s/\.py$//; s/\.\.//')"
CURRENT_PYTHON_VERSION=$(python --version | sed 's/^[^0-9]*\(3\.[^.]*\).*$/\1/')
echo $__PREFERRED_PYTHON_VERSIONS | grep -q $CURRENT_PYTHON_VERSION || {
__WARNING "only tested on the following python versions: $(printf ', %s.x' ${__PREFERRED_PYTHON_VERSIONS[@]} | sed 's/^, //')"
__WARNING 'compatibility may vary'
}
;;
zsh ) __CHECK_DEPENDENCY zsh || return 1
RUN_STRING="./$SCRIPT"
;;
zx ) __CHECK_DEPENDENCY zx || return 1
RUN_STRING="FORCE_COLOR=3 ./$SCRIPT.mjs"
;;
* ) __ERROR "unsupported script type '$SCRIPT_TYPE'"
return 2
;;
esac
RUN_STRING="SCWRYPTS_ENV='$ENV_NAME' $RUN_STRING"
[ -f $_VIRTUALENV ] && RUN_STRING="source '$_VIRTUALENV'; $RUN_STRING"
echo $RUN_STRING
}
__CHECK_ENV_REQUIRED() {
[ $CI ] && return 1
echo $SCRIPT | grep -q 'zsh/scwrypts/logs' && return 1
return 0
}
__VALIDATE_UPSTREAM_TIMELINE() {
__STATUS "on '$ENV_NAME'; checking diff against origin/main"
git fetch --quiet origin main
local SYNC_STATUS=$?
git diff --exit-code origin/main -- . >&2
local DIFF_STATUS=$?
[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
__SUCCESS 'up-to-date with origin/main'
} || {
__WARNING
[[ $SYNC_STATUS -ne 0 ]] && __WARNING 'unable to synchronize with origin/main'
[[ $DIFF_STATUS -ne 0 ]] && __WARNING 'your branch differs from origin/main (diff listed above)'
__WARNING
__yN 'continue?' || return 1
}
}
__GET_LOGFILE() {
local SCRIPT="$1"
[ $CI ] \
|| [ $SUBSCWRYPT ] \
|| [[ $SCRIPT =~ scwrypts/logs ]] \
|| [[ $SCRIPT =~ interactive ]] \
&& return 0
echo "$SCWRYPTS_LOG_PATH/$(echo $SCRIPT | sed 's/^\.\///; s/\//\%/g').log"
}
#####################################################################
__RUN $@
source "${0:a:h}/run"

View File

@ -19,6 +19,7 @@ _EFS_CONNECT() {
[ ! $FS_ID ] && __ABORT
local MOUNT_POINT="$AWS__EFS__LOCAL_MOUNT_POINT/$FS_ID"
[ -d "$MOUNT_POINT" ] && sudo rmdir "$MOUNT_POINT" >/dev/null 2>&1
[ -d "$MOUNT_POINT" ] && {
__STATUS "$FS_ID is already mounted"
exit 0

6
zsh/aws/eks/common.zsh Normal file
View File

@ -0,0 +1,6 @@
_DEPENDENCIES+=(
kubectl
)
_REQUIRED_ENV+=()
source ${0:a:h}/../common.zsh
#####################################################################

19
zsh/aws/eks/login Executable file
View File

@ -0,0 +1,19 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
__STATUS "performing AWS ECR docker login"
CLUSTER_NAME=$(\
_AWS eks list-clusters \
| jq -r '.[] | .[]' \
| __FZF 'select a cluster'
)
[ ! $CLUSTER_NAME ] && __ABORT
__STATUS "updating kubeconfig for '$CLUSTER_NAME'"
_AWS eks update-kubeconfig --name $CLUSTER_NAME \
&& __SUCCESS "kubeconfig updated with '$CLUSTER_NAME'" \
|| __ERROR "failed to update kubeconfig; do you have permissions to access '$CLUSTER_NAME'?"

View File

@ -3,20 +3,127 @@ _REQUIRED_ENV+=()
source ${0:a:h}/../common.zsh
#####################################################################
__SELECT_CONNECTOR() {
local DB_TYPE="$1"
GET_DATABASE_CREDENTIALS() {
local PRINT_PASSWORD=0
local ARGS_ERRORS=0
CLIENTS_postgresql=(pgcli psql)
local C CLIENT=none
for C in $(eval 'echo $CLIENTS_'$DB_TYPE)
while [[ $# -gt 0 ]]
do
__CHECK_DEPENDENCY $C >/dev/null 2>&1 && {
CLIENT=$C
__STATUS "detected '$CLIENT' for $DB_TYPE"
break
}
case $1 in
--print-password ) PRINT_PASSWORD=1 ;;
* )
__WARNING "unrecognized argument $1"
ARGS_ERRORS+=1
;;
esac
shift 1
done
[[ $ARGS_ERRORS -ne 0 ]] && return 1
echo $CLIENT
##########################################
local DATABASE=$(SELECT_DATABASE)
[ ! $DATABASE ] && __ABORT
DB_HOST="$(echo $DATABASE | jq -r '.host')"
[ ! $DB_HOST ] && { __ERROR 'unable to find host'; return 2; }
DB_PORT="$(echo $DATABASE | jq -r '.port')"
[ ! $DB_PORT ] && DB_PORT=5432
[[ $DB_PORT =~ ^null$ ]] && DB_PORT=5432
##########################################
local AUTH_METHOD=$(\
echo "iam\nsecretsmanager\nuser-input" \
| __FZF 'select an authentication method' \
)
[ ! $AUTH_METHOD ] && __ABORT
case $AUTH_METHOD in
iam ) GET_AUTH__IAM ;;
secretsmanager ) GET_AUTH__SECRETSMANAGER ;;
user-input ) GET_AUTH__USER_INPUT ;;
esac
__STATUS
__STATUS "host : $DB_HOST"
__STATUS "type : $DB_TYPE"
__STATUS "port : $DB_PORT"
__STATUS "database : $DB_NAME"
__STATUS "username : $DB_USER"
[[ $PRINT_PASSWORD -eq 1 ]] && __STATUS "password : $DB_PASS"
__STATUS
}
GET_AUTH__IAM() {
DB_PASS=$(\
_AWS rds generate-db-auth-token \
--hostname $DB_HOST \
--port $DB_PORT \
--username $DB_USER \
)
}
GET_AUTH__SECRETSMANAGER() {
local CREDENTIALS=$(GET_SECRETSMANAGER_CREDENTIALS)
echo $CREDENTIALS | jq -e '.pass' >/dev/null 2>&1 \
&& DB_PASS="'$(echo $CREDENTIALS | jq -r '.pass' | sed "s/'/'\"'\"'/g")'"
echo $CREDENTIALS | jq -e '.password' >/dev/null 2>&1 \
&& DB_PASS="'$(echo $CREDENTIALS | jq -r '.password' | sed "s/'/'\"'\"'/g")'"
echo $CREDENTIALS | jq -e '.user' >/dev/null 2>&1 \
&& DB_USER=$(echo $CREDENTIALS | jq -r '.user')
echo $CREDENTIALS | jq -e '.username' >/dev/null 2>&1 \
&& DB_USER=$(echo $CREDENTIALS | jq -r '.username')
echo $CREDENTIALS | jq -e '.name' >/dev/null 2>&1 \
&& DB_NAME=$(echo $CREDENTIALS | jq -r '.name')
echo $CREDENTIALS | jq -e '.dbname' >/dev/null 2>&1 \
&& DB_NAME=$(echo $CREDENTIALS | jq -r '.dbname')
}
GET_SECRETSMANAGER_CREDENTIALS() {
local ID=$(\
_AWS secretsmanager list-secrets \
| jq -r '.[] | .[] | .Name' \
| __FZF 'select a secret' \
)
[ ! $ID ] && return 1
_AWS secretsmanager get-secret-value --secret-id "$ID" \
| jq -r '.SecretString' | jq
}
SELECT_DATABASE() {
local DATABASES=$(GET_AVAILABLE_DATABASES)
[ ! $DATABASES ] && __FAIL 1 'no databases available'
local ID=$(\
echo $DATABASES | jq -r '.instance + " @ " + .cluster' \
| __FZF 'select a database (instance@cluster)' \
)
[ ! $ID ] && __ABORT
local INSTANCE=$(echo $ID | sed 's/ @ .*$//')
local CLUSTER=$(echo $ID | sed 's/^.* @ //')
echo $DATABASES | jq "select (.instance == \"$INSTANCE\" and .cluster == \"$CLUSTER\")"
}
GET_AVAILABLE_DATABASES() {
_AWS rds describe-db-instances \
| jq -r '.[] | .[] | {
instance: .DBInstanceIdentifier,
cluster: .DBClusterIdentifier,
type: .Engine,
host: .Endpoint.Address,
port: .Endpoint.Port,
user: .MasterUsername,
database: .DBName
}'
}

22
zsh/aws/rds/create-backup Executable file
View File

@ -0,0 +1,22 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
RDS_INTERACTIVE_LOGIN() {
local DB_HOST DB_PORT DB_NAME DB_USER DB_PASS
GET_DATABASE_CREDENTIALS $@ || return 1
__RUN_SCWRYPT 'zsh/db/postgres/pg_dump' -- \
--host $DB_HOST \
--port $DB_PORT \
--name $DB_NAME \
--user $DB_USER \
--pass $DB_PASS \
;
}
#####################################################################
RDS_INTERACTIVE_LOGIN $@

View File

@ -4,118 +4,19 @@ _REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
__CONNECT_TO_RDS() {
local DATABASE=$(__SELECT_DATABASE)
[ ! $DATABASE ] && __ABORT
local DB_HOST DB_USER DB_PORT DB_NAME DB_AUTH DB_TYPE
DB_HOST=$(echo $DATABASE | jq -r '.host')
DB_USER=$(echo $DATABASE | jq -r '.user')
DB_PORT=$(echo $DATABASE | jq -r '.port')
DB_TYPE=$(echo $DATABASE | jq -r '.type')
[[ $DB_PORT =~ null ]] && DB_PORT=5432
DB_NAME=postgres
local AUTH_METHODS=(iam secretsmanager user-input)
local AUTH_METHOD=$(\
echo $AUTH_METHODS | sed 's/\s\+/\n/g' \
| __FZF 'select an authentication method' \
)
[ ! $AUTH_METHOD ] && __ABORT
case $AUTH_METHOD in
iam )
DB_AUTH=$(\
_AWS rds generate-db-auth-token \
--hostname $DB_HOST \
--port $DB_PORT \
--username $DB_USER \
)
;;
secretsmanager )
CREDENTIALS=$(__GET_SECRETSMANAGER_CREDENTIALS)
echo $CREDENTIALS | jq -e '.pass' >/dev/null 2>&1 \
&& DB_AUTH=$(echo $CREDENTIALS | jq -r '.pass')
echo $CREDENTIALS | jq -e '.password' >/dev/null 2>&1 \
&& DB_AUTH=$(echo $CREDENTIALS | jq -r '.password')
echo $CREDENTIALS | jq -e '.user' >/dev/null 2>&1 \
&& DB_USER=$(echo $CREDENTIALS | jq -r '.user')
echo $CREDENTIALS | jq -e '.username' >/dev/null 2>&1 \
&& DB_USER=$(echo $CREDENTIALS | jq -r '.username')
echo $CREDENTIALS | jq -e '.name' >/dev/null 2>&1 \
&& DB_NAME=$(echo $CREDENTIALS | jq -r '.name')
echo $CREDENTIALS | jq -e '.dbname' >/dev/null 2>&1 \
&& DB_NAME=$(echo $CREDENTIALS | jq -r '.dbname')
;;
user-input )
;;
esac
__STATUS
__STATUS "host : $DB_HOST"
__STATUS "type : $DB_TYPE"
__STATUS "port : $DB_PORT"
__STATUS "database : $DB_NAME"
__STATUS "username : $DB_USER"
__STATUS
RDS_INTERACTIVE_LOGIN() {
local DB_HOST DB_PORT DB_NAME DB_USER DB_PASS
GET_DATABASE_CREDENTIALS $@ || return 1
__RUN_SCWRYPT 'zsh/db/interactive/postgres' -- \
--host $DB_HOST \
--port $DB_PORT \
--name $DB_NAME \
--user $DB_USER \
--pass $DB_AUTH \
--pass $DB_PASS \
;
}
__SELECT_DATABASE() {
local DATABASES=$(__GET_AVAILABLE_DATABASES)
[ ! $DATABASES ] && __FAIL 1 'no databases available'
local ID=$(\
echo $DATABASES | jq -r '.instance + " @ " + .cluster' \
| __FZF 'select a database (instance@cluster)' \
)
[ ! $ID ] && __ABORT
local INSTANCE=$(echo $ID | sed 's/ @ .*$//')
local CLUSTER=$(echo $ID | sed 's/^.* @ //')
echo $DATABASES | jq "select (.instance == \"$INSTANCE\" and .cluster == \"$CLUSTER\")"
}
__GET_AVAILABLE_DATABASES() {
_AWS rds describe-db-instances \
| jq -r '.[] | .[] | {
instance: .DBInstanceIdentifier,
cluster: .DBClusterIdentifier,
type: .Engine,
host: .Endpoint.Address,
port: .Endpoint.Port,
user: .MasterUsername,
database: .DBName
}'
}
__GET_SECRETSMANAGER_CREDENTIALS() {
local ID=$(\
_AWS secretsmanager list-secrets \
| jq -r '.[] | .[] | .Name' \
| __FZF 'select a secret' \
)
[ ! $ID ] && return 1
_AWS secretsmanager get-secret-value --secret-id "$ID" \
| jq -r '.SecretString' | jq
}
#####################################################################
__CONNECT_TO_RDS
RDS_INTERACTIVE_LOGIN $@

22
zsh/aws/rds/load-backup Executable file
View File

@ -0,0 +1,22 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
RDS_INTERACTIVE_LOGIN() {
local DB_HOST DB_PORT DB_NAME DB_USER DB_PASS
GET_DATABASE_CREDENTIALS $@ || return 1
__RUN_SCWRYPT 'zsh/db/postgres/pg_restore' -- \
--host $DB_HOST \
--port $DB_PORT \
--name $DB_NAME \
--user $DB_USER \
--pass $DB_PASS \
;
}
#####################################################################
RDS_INTERACTIVE_LOGIN $@

View File

@ -1,17 +1,8 @@
#####################################################################
[ ! $SCWRYPTS_ROOT ] && SCWRYPTS_ROOT="$(dirname ${0:a:h})"
__PREFERRED_PYTHON_VERSIONS=(3.10 3.9)
__NODE_VERSION=18.0.0
__ENV_TEMPLATE=$SCWRYPTS_ROOT/.env.template
__SCWRYPT=1
source $SCWRYPTS_ROOT/.config
source ${0:a:h}/utils/utils.module.zsh || {
[ $DONT_EXIT ] && return 1 || exit 1
}
source ${0:a:h}/../global/common.zsh
source ${0:a:h}/utils/utils.module.zsh \
|| { [ $DONT_EXIT ] && return 1 || exit 1; }
#####################################################################
@ -26,33 +17,15 @@ __GET_ENV_NAMES() { __GET_ENV_FILES | sed 's/.*\///'; }
__GET_ENV_FILE() { echo "$SCWRYPTS_CONFIG_PATH/env/$1"; }
__SELECT_OR_CREATE_ENV() { __GET_ENV_NAMES | __FZF_TAIL 'select/create an environment'; }
__SELECT_ENV() { __GET_ENV_NAMES | __FZF 'select an environment'; }
__SELECT_ENV() { __GET_ENV_NAMES | __FZF 'select an environment'; }
#####################################################################
__GET_AVAILABLE_SCRIPTS() {
cd $SCWRYPTS_ROOT;
find . -mindepth 2 -type f -executable \
| grep -v '\.git' \
| grep -v '\.env' \
| grep -v 'node_modules' \
| sed 's/^\.\///; s/\.[^.]*$//' \
;
}
#####################################################################
__RUN_SCWRYPT() {
# run a scwrypt inside a scwrypt w/stack-depth indicators
((SUBSCWRYPT+=1))
printf ' '; printf '--%.0s' {1..$SUBSCWRYPT}; printf " ($SUBSCWRYPT) "
echo " BEGIN SUBSCWRYPT : $(basename $1)"
SUBSCWRYPT=$SUBSCWRYPT SCWRYPTS_ENV=$ENV_NAME \
"$SCWRYPTS_ROOT/scwrypts" $@
EXIT_CODE=$?
printf ' '; printf '--%.0s' {1..$SUBSCWRYPT}; printf " ($SUBSCWRYPT) "
echo " END SUBSCWRYPT : $(basename $1)"
((SUBSCWRYPT-=1))
return $EXIT_CODE
}

View File

@ -2,3 +2,23 @@ _DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/../common.zsh
#####################################################################
GET_POSTGRES_LOGIN_ARGS() {
while [[ $# -gt 0 ]]
do
case $1 in
--host | -h ) _HOST="$2"; shift 2 ;;
--name | -d ) _NAME="$2"; shift 2 ;;
--pass | -w ) _PASS="$2"; shift 2 ;;
--port | -p ) _PORT="$2"; shift 2 ;;
--user | -U ) _USER="$2"; shift 2 ;;
* ) shift 1 ;;
esac
done
[ ! $_HOST ] && _HOST=127.0.0.1
[ ! $_NAME ] && _NAME=postgres
[ ! $_PORT ] && _PORT=5432
[ ! $_USER ] && _USER=postgres
}

View File

@ -8,23 +8,7 @@ source ${0:a:h}/common.zsh
_LOGIN_POSTGRES() {
local _HOST _NAME _PASS _PORT _USER
while [[ $# -gt 0 ]]
do
case $1 in
--host | -h ) _HOST="$2"; shift 2 ;;
--name | -d ) _NAME="$2"; shift 2 ;;
--pass | -w ) _PASS="$2"; shift 2 ;;
--port | -p ) _PORT="$2"; shift 2 ;;
--user | -U ) _USER="$2"; shift 2 ;;
* ) shift 1 ;;
esac
done
[ ! $_HOST ] && _HOST=127.0.0.1
[ ! $_NAME ] && _NAME=postgres
[ ! $_PORT ] && _PORT=5432
[ ! $_USER ] && _USER=postgres
GET_POSTGRES_LOGIN_ARGS $@
local DATA_DIR="$SCWRYPTS_DATA_PATH/db/$_HOST"
[ ! -d $DATA_DIR ] && mkdir -p $DATA_DIR

View File

@ -0,0 +1,4 @@
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/../common.zsh
#####################################################################

44
zsh/db/postgres/pg_dump Executable file
View File

@ -0,0 +1,44 @@
#!/bin/zsh
_DEPENDENCIES+=(
pg_dump
)
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
BACKUP_POSTGRES() {
local _HOST _NAME _PASS _PORT _USER
GET_POSTGRES_LOGIN_ARGS $@
local DATA_DIR="$SCWRYPTS_DATA_PATH/db/$_HOST/$_NAME/pg_dump"
[ ! -d $DATA_DIR ] && mkdir -p $DATA_DIR
cd $DATA_DIR
local OUTPUT_FILE="$DATA_DIR/$_NAME.dump"
[ -f $OUTPUT_FILE ] && {
local BACKUP_COUNT=$(ls "$DATA_DIR/$_NAME."*".dump" | wc -l)
ls "$DATA_DIR/$_NAME."*".dump"
__INFO "discovered previous dump for '$_HOST/$_NAME'"
__INFO "backing up previous dump to '$_NAME.$BACKUP_COUNT.dump'"
mv "$OUTPUT_FILE" "$DATA_DIR/$_NAME.$BACKUP_COUNT.dump"
}
__STATUS "making backup of : $_USER@$_HOST:$_PORT/$_NAME"
__STATUS "output file : $OUTPUT_FILE"
PGPASSWORD="$_PASS" pg_dump \
--verbose \
--format custom \
--host "$_HOST" \
--port "$_PORT" \
--username "$_USER" \
--dbname "$_NAME" \
--file "$OUTPUT_FILE" \
&& { __SUCCESS "finished backup of '$_HOST/$_NAME'"; __SUCCESS "saved to '$OUTPUT_FILE'"; } \
|| { __ERROR "error creating backup for '$_HOST/$_NAME' (see above)"; return 1; }
}
#####################################################################
BACKUP_POSTGRES $@

55
zsh/db/postgres/pg_restore Executable file
View File

@ -0,0 +1,55 @@
#!/bin/zsh
_DEPENDENCIES+=(
pg_dump
)
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
BACKUP_POSTGRES() {
local _HOST _NAME _PASS _PORT _USER
GET_POSTGRES_LOGIN_ARGS $@
local DATA_DIR="$SCWRYPTS_DATA_PATH/db/$_HOST/$_NAME/pg_restore"
[ ! -d $DATA_DIR ] && mkdir -p $DATA_DIR
cd $DATA_DIR
local INPUT_FILE="$DATA_DIR/$_NAME.dump"
[ ! -f $INPUT_FILE ] && {
local DUMP="$(dirname $DATA_DIR)/pg_dump/$_NAME.dump"
__STATUS $DUMP
ls $DUMP
[ -f "$DUMP" ] && {
__SUCCESS "discovered previous scwrypts dump"
__SUCCESS "$DUMP"
__Yn 'restore from this backup?' && INPUT_FILE="$DUMP"
}
[ ! -f "$INPUT_FILE" ] && {
__STATUS 'place backup in the following location:'
__STATUS "$INPUT_FILE"
}
while [ ! -f $INPUT_FILE ]; do sleep 1; done
}
__STATUS "backup file : $DATA_DIR"
__STATUS "database : $_USER@$_HOST:$_PORT/$_NAME"
PGPASSWORD="$_PASS" pg_restore \
--verbose \
--single-transaction \
--format custom \
--host "$_HOST" \
--port "$_PORT" \
--username "$_USER" \
--dbname "$_NAME" \
"$INPUT_FILE" \
&& { __SUCCESS "finished restoring backup for '$_HOST/$_NAME'"; } \
|| { __ERROR "error restoring backup for '$_HOST/$_NAME' (see above)"; return 1; }
}
#####################################################################
BACKUP_POSTGRES $@

View File

@ -0,0 +1,4 @@
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/../common.zsh
#####################################################################

72
zsh/db/run-sql/postgres Executable file
View File

@ -0,0 +1,72 @@
#!/bin/zsh
_DEPENDENCIES+=(
psql
)
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
_RUN_SQL_POSTGRES() {
local _HOST _NAME _PASS _PORT _USER INPUT_FILE
while [[ $# -gt 0 ]]
do
case $1 in
--host | -h ) _HOST="$2"; shift 2 ;;
--name | -d ) _NAME="$2"; shift 2 ;;
--pass | -w ) _PASS="$2"; shift 2 ;;
--port | -p ) _PORT="$2"; shift 2 ;;
--user | -U ) _USER="$2"; shift 2 ;;
--file | -i ) INPUT_FILE="$2"; shift 2 ;;
* ) shift 1 ;;
esac
done
[ ! $_HOST ] && _HOST=127.0.0.1
[ ! $_NAME ] && _NAME=postgres
[ ! $_PORT ] && _PORT=5432
[ ! $_USER ] && _USER=postgres
local SQL_DIR="$SCWRYPTS_DATA_PATH/sql"
[ ! -d $SQL_DIR ] && mkdir -p $SQL_DIR
cd $SQL_DIR
[[ $(ls "*.sql" 2>&1 | wc -l) -eq 0 ]] && {
__ERROR "you haven't made any SQL commands yet"
__REMINDER "add '.sql' files here: '$SQL_DIR/'"
exit 1
}
[ ! $INPUT_FILE ] && INPUT_FILE=$(\
__FZF 'select a sql file to run'
)
[ ! $INPUT_FILE ] && __ABORT
[ ! -f $INPUT_FILE ] && {
__FAIL 2 "no such sql file '$SQL_DIR/$INPUT_FILE'"
}
__STATUS "loading $INPUT_FILE preview..."
_LESS $INPUT_FILE
__STATUS "login : $_USER@$_HOST:$_PORT/$_NAME"
__STATUS "command : ./$INPUT_FILE"
__yN 'run this command?' || __ABORT
__STATUS "running './$INPUT_FILE'"
PGPASSWORD="$_PASS" psql \
-h $_HOST \
-p $_PORT \
-U $_USER \
-d $_NAME \
< $INPUT_FILE \
&& __SUCCESS "finished running './$INPUT_FILE'" \
|| __FAIL 3 "something went wrong running './$INPUT_FILE' (see above)"
}
#####################################################################
__WARNING
__WARNING 'this function is in a beta state'
__WARNING
_RUN_SQL_POSTGRES $@

31
zsh/latex/build-pdf Executable file
View File

@ -0,0 +1,31 @@
#!/bin/zsh
_DEPENDENCIES+=(
pdflatex
rg
)
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
PDFLATEX() {
[ ! $1 ] && __FAIL 1 'must provide filename'
local FILENAME=$(GET_MAIN_LATEX_FILENAME "$1")
local ARGS=(-interaction=nonstopmode)
ARGS+=("$FILENAME")
cd "$(dirname $FILENAME)"
__STATUS 'running compile (1/2)'
pdflatex ${ARGS[@]} \
|| __FAIL 2 'first compile failed (see above)'
__STATUS 'running compile (2/2)'
pdflatex ${ARGS[@]} >/dev/null 2>&1 \
|| __FAIL 3 'second compile failed :c'
__SUCCESS "created '$(echo $FILENAME | sed 's/\.[^.]*$/.pdf/')'"
}
#####################################################################
PDFLATEX $@

20
zsh/latex/cleanup Executable file
View File

@ -0,0 +1,20 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
CLEAN_LATEX_LOGFILES() {
local DIRECTORY=$(__GET_PATH_TO_RELATIVE_ARGUMENT ".")
[ $1 ] && DIRECTORY="$(dirname "$(GET_MAIN_LATEX_FILENAME "$1")")"
[ $DIRECTORY ] && [ -d $DIRECTORY ] \
|| __FAIL 1 'unable to parse valid directory'
cd $DIRECTORY
rm $(ls | grep '\.\(aux\)\|\(log\)\|\(pdf\)\|\(out\)\|\(dvi\)$')
__SUCCESS "cleaned up latex artifacts in '$DIRECTORY'"
}
#####################################################################
CLEAN_LATEX_LOGFILES $@

34
zsh/latex/common.zsh Normal file
View File

@ -0,0 +1,34 @@
_DEPENDENCIES+=(
rg
)
_REQUIRED_ENV+=()
source ${0:a:h}/../common.zsh
#####################################################################
GET_MAIN_LATEX_FILENAME() {
local FILENAME=$(__GET_PATH_TO_RELATIVE_ARGUMENT "$1")
local DIRNAME="$FILENAME"
for _ in {1..3}
do
CHECK_IS_MAIN_LATEX_FILE && return 0
DIRNAME="$(dirname "$FILENAME")"
__STATUS "checking '$DIRNAME'"
[[ $DIRNAME =~ ^$HOME$ ]] && break
FILENAME=$(
rg -l --max-depth 1 'documentclass' "$DIRNAME/" \
| grep '\.tex$' \
| head -n1 \
)
__STATUS "here is '$FILENAME'"
done
__WARNING 'unable to find documentclass; pdflatex will probably fail'
echo "$1"
}
CHECK_IS_MAIN_LATEX_FILE() {
[ ! $FILENAME ] && return 1
grep -q 'documentclass' $FILENAME 2>/dev/null && echo $FILENAME || return 3
}

63
zsh/latex/create-new Executable file
View File

@ -0,0 +1,63 @@
#!/bin/zsh
_DEPENDENCIES+=(
pdflatex
rg
)
_REQUIRED_ENV+=()
TEMPLATE_DIR="${0:a:h}/templates"
source ${0:a:h}/common.zsh
#####################################################################
CREATE_NEW_LATEX_DOCUMENT_FROM_TEMPLATE() {
local DOCUMENT_DIR="$EXECUTION_DIR"
local TEMPLATE=$(GET_TEMPLATES | __FZF 'select a template')
[ ! $TEMPLATE ] && __ABORT
__SUCCESS "selected template '$TEMPLATE'"
__INPUT DOC_TITLE 'document title' || __ABORT
local DOCUMENT_FILE="$DOCUMENT_DIR/$(SLUGIFY_TITLE).tex"
[ -f "$DOCUMENT_FILE" ] && __FAIL 1 "'$(basename $DOCUMENT_FILE)' already exists"
__INPUT DOC_ID 'document id/subtitle'
__INPUT AUTHOR 'author name'
__INPUT AUTHOR_ID 'author id/title'
{
PRINT_TITLE_INFO
cat "$TEMPLATE_DIR/$TEMPLATE/template.tex"
} > "$DOCUMENT_FILE"
cp "$TEMPLATE_DIR/gitignore" "$DOCUMENT_DIR/.gitignore"
for FILE in $(find "$TEMPLATE_DIR/$TEMPLATE" -type f | grep -v '/template.tex$')
do
cp "$FILE" "$DOCUMENT_DIR/" || return 2
done
[[ ! $TEMPLATE =~ ^basic$ ]] \
&& mkdir "$DOCUMENT_DIR/sections" "$DOCUMENT_DIR/graphics"
__SUCCESS "finished generating '$(basename $DOCUMENT_FILE)' from '$TEMPLATE'"
}
GET_TEMPLATES() {
find "$TEMPLATE_DIR" -type d | sed "s^$TEMPLATE_DIR/*^^; /^$/d"
}
PRINT_TITLE_INFO() {
local DATESTRING=$(date '+%B %_d, %Y' | sed 's/ \{1,\}/ /g')
sed "
s^LATEX-DOC-TITLE^$DOC_TITLE^
s^LATEX-DOC-DATE^$DATESTRING^
s^LATEX-DOC-ID^$DOC_ID^
s^LATEX-AUTHOR-NAME^$AUTHOR^
s^LATEX-AUTHOR-ID^$AUTHOR_ID^
" "$TEMPLATE_DIR/main.tex"
}
SLUGIFY_TITLE() {
echo $DOC_TITLE | sed "s^['\"\\/,\!@#\$%^&*()]*^^g; s^\s\+^-^g;"
}
#####################################################################
CREATE_NEW_LATEX_DOCUMENT_FROM_TEMPLATE $@

15
zsh/latex/get-pdf Executable file
View File

@ -0,0 +1,15 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
GET_PDF() {
local FILENAME=$(GET_MAIN_LATEX_FILENAME "$1" | sed 's/\.[^.]*$/.pdf/')
[ $FILENAME ] && [ -f $FILENAME ] || __FAIL 1 "no compiled pdf found for '$1'; have you run 'build-pdf'?"
__SUCCESS 'found main pdf'
echo $FILENAME
}
#####################################################################
GET_PDF $@

15
zsh/latex/open-pdf Executable file
View File

@ -0,0 +1,15 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
OPEN_PDF() {
local PDF=$(__RUN_SCWRYPT latex/get-pdf -n -- $1)
[ ! $PDF ] && return 1
__OPEN "$PDF"
}
#####################################################################
OPEN_PDF $@

View File

@ -0,0 +1,37 @@
\usepackage[margin=.75in,bottom=0.5in,top=1.0in]{geometry}
\usepackage{enumitem}
\usepackage{fancyhdr}
\usepackage{hyperref}
\usepackage{lastpage}
\newcommand{\headerL} {\documentTitle: \documentDate}
\newcommand{\headerC} {\documentId}
\newcommand{\headerR} {\authorName\ (\authorId)}
\newcommand{\pageOfTotal} {\thepage\ of~\pageref{LastPage}}
\pagestyle{fancy}
\fancypagestyle{plain}{%
\fancyhf{}
\fancyhead[L]{\headerL}\fancyhead[R]{\headerR}\fancyhead[C]{\headerC}
\fancyfoot[C]{\pageOfTotal}
}
\renewcommand{\baselinestretch}{1}
\setlength{\parskip}{0em}
\hyphenpenalty=5000%
\fancyhf{}
\fancyhead[L]{\headerL}\fancyhead[R]{\headerR}\fancyhead[C]{\headerC}
\fancyfoot[C]{\pageOfTotal}
\title{\documentTitle}
\author{\authorName\ \\ \authorId}
\date{\documentDate}
\begin{document}
\maketitle%
% ---------------------------------------------------------------------
% ---------------------------------------------------------------------
\end{document}

View File

@ -0,0 +1,5 @@
*.aux
*.log
*.out
*.pdf
*.dvi

View File

@ -0,0 +1,9 @@
\documentclass[letterpaper]{article}
\newcommand{\documentTitle} {LATEX-DOC-TITLE}
\newcommand{\documentDate} {LATEX-DOC-DATE}
\newcommand{\documentId} {LATEX-DOC-ID}
\newcommand{\authorName} {LATEX-AUTHOR-NAME}
\newcommand{\authorId} {LATEX-AUTHOR-ID}

View File

@ -0,0 +1,11 @@
\ProvidesPackage{code}
% ---------------------------------------------------------------------
\newcommand{\clispsnippet}[2]{%
\lstinputlisting[%
caption=#1,
language=Lisp,
showstringspaces=false,
numbers=left,
]{#2}
}

View File

@ -0,0 +1,46 @@
\ProvidesPackage{formatting}
% ---------------------------------------------------------------------
\newcommand{\headerLeft} {\documentTitle: \documentDate}
\newcommand{\headerCenter} {\documentId}
\newcommand{\headerRight} {\authorName\ (\authorId)}
\newcommand{\pageOfTotal} {\thepage\ of~\pageref{LastPage}}
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}
\newtheorem{corollary}{Corollary}[theorem]
\RequirePackage[margin=1in,bottom=.5in,includefoot]{geometry}
\RequirePackage{lastpage}
\RequirePackage{fancyhdr}
% ---------------------------------------------------------------------
% Page 1
\pagestyle{fancy}
\fancypagestyle{plain}{%
\fancyhf{}
\fancyhead[L]{\headerLeft}
\fancyhead[R]{\headerRight}
\fancyhead[C]{\headerCenter}
\fancyfoot[C]{\pageOfTotal}
}
\renewcommand{\baselinestretch}{1}
\setlength{\parskip}{0em}
\setlength{\parindent}{0em}
% ---------------------------------------------------------------------
% Pages 2+
\fancyhf{}
\fancyhead[L]{\headerLeft}
\fancyhead[R]{\headerRight}
\fancyhead[C]{\headerCenter}
\fancyfoot[C]{\pageOfTotal}
% ---------------------------------------------------------------------
\title{\documentTitle}
\author{\authorName\ \\ \authorId}
\date{\documentDate}

View File

View File

@ -0,0 +1,16 @@
\ProvidesPackage{imports}
% ---------------------------------------------------------------------
\RequirePackage{amssymb} % "bold" math letters (e.g. set of integers )
\RequirePackage{amsmath} % advanced math symbols
\RequirePackage{listings} % code snippet styling block
\RequirePackage{tikz} % graphic drawing / generation
\usetikzlibrary{arrows,automata}
\usetikzlibrary{trees}
\RequirePackage{graphicx} % include images
\graphicspath{{./graphics/}}
\RequirePackage[english]{babel} % -- English compilation rules

View File

@ -0,0 +1,13 @@
\ProvidesPackage{shorthand}
% ---------------------------------------------------------------------
\newcommand{\egfcoefficient}{\ensuremath{\left[\frac{x^n}{n!}\right]}}
\newcommand{\ogfcoefficient}{\ensuremath{\left[x^n\right]}}
\newcommand{\falling}[1]{^{\underline{#1}}}
\newcommand{\divides}{\ensuremath{\;\backslash\;}}
\newcommand{\sumgz}{\ensuremath{\sum_{n\geq 0}}}
\newcommand{\sumdiv}{\ensuremath{\sum_{d\divides n}}}
\newcommand{\union}{\ensuremath{\cup}}
\newcommand{\intersect}{\ensuremath{\cap}}

View File

@ -0,0 +1,12 @@
\usepackage{imports}
\usepackage{formatting}
\usepackage{shorthand}
\usepackage{code}
\begin{document}
\maketitle
% ---------------------------------------------------------------------
% \input{sections/01.introduction.tex}
% \includegraphic{graphics/diagram-a.png}
% ---------------------------------------------------------------------
\end{document}

View File

@ -0,0 +1,7 @@
\ProvidesPackage{custom-headers}
% ---------------------------------------------------------------------
\newcommand{\firstH}[1] {\begin{large}\textbf{#1}\end{large}\par}
\newcommand{\secondH}[1] {\textbf{#1}\par}
\newcommand{\thirdH}[1] {\textbf{#1}. }
\newcommand{\fourthH}[1] {\textbf{\textit{#1}}. }

View File

@ -0,0 +1,31 @@
\ProvidesPackage{formatting}
% ---------------------------------------------------------------------
\newcommand{\horizontalHeader} {%
\authorName\hfill
\authorId\hfill
\documentId\hfill
\documentDate%
}
\RequirePackage[margin=1in]{geometry}
\RequirePackage{fancyhdr}
% ---------------------------------------------------------------------
\pagestyle{fancy}
\renewcommand{\headrulewidth}{0pt}
\fancyhead[C]{\horizontalHeader}
\fancyfoot[C]{\thepage}
\renewcommand{\baselinestretch}{1}
\setlength{\parskip}{1em}
\setlength{\parindent}{0em}
\raggedright%
% ---------------------------------------------------------------------
\newcommand{\insertTitle} {%
\centerline{\begin{large}\textbf{\documentTitle}\end{large}}
}

View File

@ -0,0 +1,11 @@
\ProvidesPackage{imports}
% ---------------------------------------------------------------------
\RequirePackage{times} % "Times New Roman" font
\RequirePackage{kantlipsum} % generate Kantian lorem ipsum
\RequirePackage{graphicx} % include images
\graphicspath{{./graphics/}}
\RequirePackage[english]{babel} % -- English compilation rules

View File

@ -0,0 +1,15 @@
\usepackage{imports}
\usepackage{formatting}
\usepackage{custom-headers}
\begin{document}
\insertTitle%
% ---------------------------------------------------------------------
% \input{sections/abstract.tex}
% \includgraphics{graphics/table-a.png}
\firstH{First-level Header}
\kant%
% ---------------------------------------------------------------------
\end{document}

22
zsh/redis/common.zsh Normal file
View File

@ -0,0 +1,22 @@
_DEPENDENCIES+=(
redis-cli
)
_REQUIRED_ENV+=()
source ${0:a:h}/../common.zsh
[ ! $SCWRYPTS_CACHE_HOST ] && SCWRYPTS_CACHE_HOST=localhost
[ ! $SCWRYPTS_CACHE_PORT ] && SCWRYPTS_CACHE_PORT=6379
#####################################################################
_REDIS() {
local ARGS=()
ARGS+=(-h $SCWRYPTS_CACHE_HOST)
ARGS+=(-p $SCWRYPTS_CACHE_PORT)
[ $SCWRYPTS_CACHE_AUTH ] && ARGS+=(-a $SCWRYPTS_CACHE_AUTH)
redis-cli ${ARGS[@]} $@
}
CACHE_ENABLED=$(_REDIS ping 2>&1 | grep -qi pong && echo 1 || echo 0)

48
zsh/redis/curl Executable file
View File

@ -0,0 +1,48 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
CURL_WITH_CACHE() {
[ ! $TTL ] && TTL=10
[[ $CACHE_ENABLED -eq 0 ]] && {
curl $@
return $?
}
local ARGS=()
local URL
while [[ $# -gt 0 ]]
do
case $1 in
-- ) shift 1 ;;
--*= ) ARGS+=($1); shift 1 ;;
--* ) ARGS+=($1 $2); shift 2 ;;
-* ) ARGS+=($1); shift 1 ;;
* ) URL=$1; break ;;
esac
done
local KEY=$(GET_URL_KEY $URL)
local OUTPUT=$(_REDIS get $KEY 2>&1)
[ $OUTPUT ] && {
[[ ${#ARGS[@]} -gt 0 ]] && __WARN "cache hit found; ignoring arguments ($ARGS)"
echo $OUTPUT
return
}
local OUTPUT=$(curl -s $@)
[ ! $OUTPUT ] && return 1
_REDIS set $KEY "$OUTPUT" >/dev/null
_REDIS expire $KEY $TTL >/dev/null
echo $OUTPUT
}
GET_URL_KEY() { echo "scwrypts:curl:$1" | sed 's/\s\+/+/g'; }
#####################################################################
CURL_WITH_CACHE $@

View File

@ -13,7 +13,7 @@ source ${0:a:h}/common.zsh
echo '#'
echo '# configuration for scwrypts'
echo '#'
sed -n '1d; /^###/q; p' $SCWRYPTS_ROOT/.config | sed '$d'
sed -n '1d; /^###/q; p' $SCWRYPTS_ROOT/global/config.zsh | sed '$d'
} > $SCWRYPTS_CONFIG_PATH/config
__EDIT $SCWRYPTS_CONFIG_PATH/config

View File

@ -55,17 +55,3 @@ _REQUIRED_ENV+=(
source ./path/to/utils.plugin.zsh
echo "missing $ENV_ERROR_COUNT required environment variables"
```
io.zsh
os.zsh
## Basic Utilities
One of my biggest pet-peeves with scripting is when every line of a *(insert-language-here)* program is escaped to shell.
This kind of program, which doesn't use language features, should be a shell script.
While there are definitely unavoidable limitations to shell scripting, we can minimize a variety of problems with a modern shell and shared utilities library.
Loaded by `common.zsh`, the [`utils/` library](./utils) provides:
- common function wrappers to unify flags and context
- lazy dependency and environment variable validation
- consistent (and pretty) user input / output

25
zsh/utils/colors.zsh Normal file
View File

@ -0,0 +1,25 @@
__BLACK='\033[0;30m'
__DARK_GRAY='\033[1;30m'
__RED='\033[0;31m'
__LIGHT_RED='\033[1;31m'
__GREEN='\033[0;32m'
__LIGHT_GREEN='\033[1;32m'
__ORANGE='\033[0;33m'
__YELLOW='\033[1;33m'
__BLUE='\033[1;34m'
__DARK_BLUE='\033[0;34m'
__PURPLE='\033[1;35m'
__DARK_PURPLE='\033[0;35m'
__CYAN='\033[1;36m'
__DARK_CYAN='\033[0;36m'
__WHITE='\033[1;37m'
__LIGHT_GRAY='\033[0;37m'
__COLOR_RESET='\033[0m'

View File

@ -17,7 +17,7 @@ __CHECK_DEPENDENCY() {
}
__CHECK_COREUTILS() {
local COREUTILS=(awk find grep sed)
local COREUTILS=(awk find grep sed readlink)
local MISSING_DEPENDENCY_COUNT=0
local NON_GNU_DEPENDENCY_COUNT=0

View File

@ -1,12 +1,33 @@
__ERROR() { echo "\\033[1;31mERROR ✖ : $@\\033[0m" >&2; }
__SUCCESS() { echo "\\033[1;32mSUCCESS ✔ : $@\\033[0m" >&2; }
__WARNING() { echo "\\033[1;33mWARNING  : $@\\033[0m" >&2; }
__STATUS() { echo "\\033[1;34mSTATUS : $@\\033[0m" >&2; }
__REMINDER() { echo "\\033[1;35mREMINDER  : $@\\033[0m" >&2; }
__PRINT() {
local COLOR="$1"
local MESSAGE="$2"
local LINE_END
[ $3 ] && LINE_END='' || LINE_END='\n'
printf "${COLOR}${MESSAGE}${__COLOR_RESET}${LINE_END}"
}
__ERROR() { __PRINT $__RED "ERROR ✖ : $@" >&2; }
__SUCCESS() { __PRINT $__GREEN "SUCCESS ✔ : $@" >&2; }
__WARNING() { __PRINT $__ORANGE "WARNING  : $@" >&2; }
__STATUS() { __PRINT $__BLUE "STATUS : $@" >&2; }
__REMINDER() { __PRINT $__PURPLE "REMINDER  : $@" >&2; }
__INFO() { __PRINT $__WHITE "INFO  : $@" >&2; }
__PROMPT() {
echo "\\033[1;36mPROMPT : $@\\033[0m" >&2
printf "\\033[1;36mUSER : \\033[0m" >&2
__PRINT $__CYAN "PROMPT : $@" >&2
__PRINT $__CYAN "USER : " --no-end >&2
}
__FAIL() { __ERROR "${@:2}"; exit $1; }
__ABORT() { __FAIL 69 'user abort'; }
__INPUT() {
__PROMPT "${@:2}"
__READ $1
local VALUE=$(eval echo '$'$1)
[ $VALUE ]
}
__Yn() {
@ -25,10 +46,6 @@ __yN() {
[[ $yN =~ [yY] ]] && return 0 || return 1
}
__FAIL() { __ERROR "${@:2}"; exit $1; }
__ABORT() { __FAIL 69 'user abort'; }
#####################################################################
__GETSUDO() {

View File

@ -5,6 +5,7 @@ _REQUIRED_ENV+=() # (extensible) list of required environment variables
#####################################################################
source ${0:a:h}/colors.zsh
source ${0:a:h}/io.zsh
source ${0:a:h}/os.zsh
source ${0:a:h}/credits.zsh

5
zsh/youtube/README.md Normal file
View File

@ -0,0 +1,5 @@
# ZSH Scwrypts
[![Generic Badge](https://img.shields.io/badge/ytdl--org-youtube--dl-informational.svg)](https://github.com/ytdl-org/youtube-dl)
<br>
Quick wrappers for downloading and trimming YouTube videos.

45
zsh/youtube/common.zsh Normal file
View File

@ -0,0 +1,45 @@
_DEPENDENCIES+=(
youtube-dl
ffmpeg
)
_REQUIRED_ENV+=()
source ${0:a:h}/../common.zsh
#####################################################################
YT__GLOBAL_ARGS=(
--no-call-home
--restrict-filenames
)
YT__OUTPUT_DIR="$SCWRYPTS_DATA_PATH/youtube"
YT__GET_INFO() {
youtube-dl --dump-json ${YT__GLOBAL_ARGS[@]} $@
}
YT__GET_FILENAME() {
YT__GET_INFO $@ \
| jq -r '._filename' \
| sed 's/\.[^.]*$/\.mp4/' \
;
}
YT__DOWNLOAD() {
local OUTPUT_DIR="$SCWRYPTS_DATA_PATH/youtube"
[ ! -d $YT__OUTPUT_DIR ] && mkdir -p $YT__OUTPUT_DIR
cd "$YT__OUTPUT_DIR"
youtube-dl ${YT__GLOBAL_ARGS[@]} $@ \
--format 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4' \
;
}
GET_VIDEO_LENGTH() {
local FILENAME="$1"
ffprobe \
-v quiet \
-show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 \
-i $FILENAME \
;
}

25
zsh/youtube/download Executable file
View File

@ -0,0 +1,25 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
DOWNLOAD_VIDEO() {
local URLS=($@)
[[ ${#URLS[@]} -eq 0 ]] && URLS=($(echo '' | __FZF_HEAD 'enter URL'))
[[ ${#URLS[@]} -eq 0 ]] && __ABORT
local FILENAME=$(YT__GET_FILENAME $URLS)
[ ! $FILENAME ] && __ERROR "unable to download '$URLS'"
__SUCCESS "Found '$FILENAME'"
__Yn "Proceed with download?" || return 1
YT__DOWNLOAD $URLS \
&& __SUCCESS "downloaded to '$YT__OUTPUT_DIR/$FILENAME'" \
|| { __ERROR "failed to download '$FILENAME'"; return 2; }
}
#####################################################################
DOWNLOAD_VIDEO $@

51
zsh/youtube/get-audio-clip Executable file
View File

@ -0,0 +1,51 @@
#!/bin/zsh
_DEPENDENCIES+=()
_REQUIRED_ENV+=()
source ${0:a:h}/common.zsh
#####################################################################
GET_AUDIO_CLIP() {
local URLS=($@)
[[ ${#URLS[@]} -eq 0 ]] && URLS=($(echo '' | __FZF_HEAD 'enter URL'))
[[ ${#URLS[@]} -eq 0 ]] && __ABORT
local FILENAME=$(YT__GET_FILENAME $URLS)
[ ! $FILENAME ] && __ERROR "unable to download '$URLS'"
INPUT_FILE="$YT__OUTPUT_DIR/$FILENAME"
[ ! -f "$INPUT_FILE" ] && {
__RUN_SCWRYPT youtube/download -- $URLS || return 1
}
__SUCCESS "video download '$FILENAME' detected!"
LENGTH=$(GET_VIDEO_LENGTH "$INPUT_FILE")
[ ! $LENGTH ] && { __ERROR "unable to determine video length for '$INPUT_FILE'"; return 2; }
START_TIME=$(echo 0 | __FZF_HEAD "enter start time (0 ≤ t < $LENGTH)")
[ ! $START_TIME ] && __ABORT
END_TIME=$(echo $LENGTH | __FZF_HEAD "enter end time ($START_TIME > t ≥ $LENGTH)")
[ ! $END_TIME ] && __ABORT
__STATUS
__STATUS "video : $FILENAME"
__STATUS "start time : $START_TIME"
__STATUS "end time : $END_TIME"
__STATUS
OUTPUT_FILE=$(echo '' \
| __FZF_HEAD 'what should I call this clip? (.mp3)' \
| sed 's/\.mp3$//' \
)
[ ! $OUTPUT_FILE ] && __ABORT
OUTPUT_FILE="$YT__OUTPUT_DIR/$OUTPUT_FILE.mp3"
ffmpeg -i "$INPUT_FILE" -q:a 0 -map a \
-ss $START_TIME -t $(($END_TIME - $START_TIME))\
"$OUTPUT_FILE" \
&& __SUCCESS "created clip '$OUTPUT_FILE'" \
|| { __ERROR "error creating clip '$(basename $OUTPUT_FILE)' (see above)"; return 3; }
}
#####################################################################
GET_AUDIO_CLIP $@