v2.0.0
===================================================================== Subscwrypts + Environment Inheritance --- Release Notes ------------------------ - added support for environment inheritance - added support for arbitrarily nested scripts (subscwrypts) - added support for CI mode - improved modularity of zsh/utils module - refactored to move some data from ~/.config/scwrypts to ~/.local/share/scwrypts - refactored various scripts to use new subscwrypt api --- New Scripts -------------------------- zsh ) - db/interactive/postgres - aws/rds/interactive-login
This commit is contained in:
parent
2dcf94199b
commit
eaefc99774
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1 +1,2 @@
|
||||
*.zsh diff
|
||||
.config diff
|
||||
|
15
README.md
15
README.md
@ -28,12 +28,9 @@ Check out [Meta Scwrypts](./zsh/scwrypts) to quickly set up environments and adj
|
||||
### No Install / API Usage
|
||||
Alternatively, the `scwrypts` API can be used directly:
|
||||
```zsh
|
||||
./scwrypts (environment-name) (...script-patterns)
|
||||
./scwrypts [--env environment-name] (...script-name-patterns...) [-- ...passthrough arguments... ]
|
||||
```
|
||||
|
||||
If not already set with `$SCWRYPTS_ENV`, Scwrypts will try to load `$1` as an environment.
|
||||
If no environment with the name `$1` is found, `$1` is assumed to be a script pattern.
|
||||
|
||||
Given one or more script patterns, Scwrypts will filter the commands by pattern conjunction.
|
||||
If only one command is found which matches the pattern(s), it will immediately begin execution.
|
||||
If multiple commands match, the user will be prompted to select from the filtered list.
|
||||
@ -44,6 +41,16 @@ Given no script patterns, Scwrypts becomes an interactive CLI, prompting the use
|
||||
After determining which script to run, if no environment has been specified, Scwrypts prompts the user to choose one.
|
||||
|
||||
|
||||
### Using in CI/CD or Automated Workflows
|
||||
Set environment variable `CI=true` (and use the no install method) to run in an automated pipeline.
|
||||
There are a few notable changes to this runtime:
|
||||
- **The Scwrypts sandbox environment will not load.** All variables will be read from context.
|
||||
- The underscore-prefixed `_AWS_(PROFILE|REGION|ACCOUNT)` variables will be read from the standard `AWS_` variables
|
||||
- User yes/no prompts will **always be YES**
|
||||
- Other user input will default to an empty string
|
||||
- Logs will not be captured
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Before contributing an issue, idea, or pull request, check out the [super-brief contributing guide](./docs/CONTRIBUTING.md)
|
||||
|
1
py/.gitignore
vendored
1
py/.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.so
|
||||
.env/
|
||||
|
@ -1,16 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
from os import getenv
|
||||
|
||||
from py.redis.client import Client
|
||||
from py.scwrypts import interactive
|
||||
from py.scwrypts import interactive, getenv
|
||||
|
||||
|
||||
@interactive
|
||||
def main():
|
||||
r = Client
|
||||
|
||||
print('''
|
||||
r = StrictRedis("{getenv("REDIS_HOST")}")
|
||||
print(f'''
|
||||
>>> r = StrictRedis({getenv("REDIS_HOST")}:{getenv("REDIS_PORT")})
|
||||
''')
|
||||
|
||||
return locals()
|
||||
|
@ -1,2 +1,3 @@
|
||||
from py.scwrypts.getenv import getenv
|
||||
from py.scwrypts.interactive import interactive
|
||||
from py.scwrypts.run import run
|
||||
|
@ -1,23 +1,16 @@
|
||||
from os import getenv as os_getenv
|
||||
from pathlib import Path
|
||||
from subprocess import run
|
||||
|
||||
from py.scwrypts.exceptions import MissingVariableError
|
||||
from py.scwrypts.run import run
|
||||
|
||||
|
||||
def getenv(name, required=True):
|
||||
value = os_getenv(name, None)
|
||||
|
||||
if value == None:
|
||||
ZSH_COMMAND = Path(__file__).parents[2] / 'zsh/scwrypts/environment/stage-variables'
|
||||
run('zsh/scwrypts/environment/stage-variables', name)
|
||||
|
||||
run(
|
||||
f'{ZSH_COMMAND} {name}',
|
||||
shell=True,
|
||||
executable='/bin/zsh',
|
||||
)
|
||||
|
||||
if required:
|
||||
raise MissingVariableError(name)
|
||||
if required and not value:
|
||||
raise MissingVariableError(name)
|
||||
|
||||
return value
|
||||
|
@ -3,7 +3,9 @@ from bpython import embed
|
||||
|
||||
def interactive(function):
|
||||
def main(*args, **kwargs):
|
||||
print('preparing interactive environment...')
|
||||
local_vars = function(*args, **kwargs)
|
||||
print('environment ready; user, GO! :)')
|
||||
embed(local_vars)
|
||||
|
||||
return main
|
||||
|
17
py/scwrypts/run.py
Normal file
17
py/scwrypts/run.py
Normal file
@ -0,0 +1,17 @@
|
||||
from os import getenv
|
||||
from pathlib import Path
|
||||
from subprocess import run as subprocess_run
|
||||
|
||||
|
||||
def run(scwrypt_name, *args):
|
||||
DEPTH = int(getenv('SUBSCWRYPT', '0'))
|
||||
DEPTH += 1
|
||||
|
||||
print(f'\n {"--"*DEPTH} ({DEPTH}) BEGIN SUBSCWRYPT : {Path(scwrypt_name).name}')
|
||||
subprocess_run(
|
||||
f'SUBSCWRYPT={DEPTH} {Path(__file__).parents[2] / "scwrypts"} {scwrypt_name} -- {" ".join([str(x) for x in args])}',
|
||||
shell=True,
|
||||
executable='/bin/zsh',
|
||||
)
|
||||
|
||||
print(f' {"--"*DEPTH} ({DEPTH}) END SUBSCWRYPT : {Path(scwrypt_name).name}\n')
|
244
scwrypts
244
scwrypts
@ -1,32 +1,117 @@
|
||||
#!/bin/zsh
|
||||
SCWRYPTS_ROOT="${0:a:h}"
|
||||
source "$SCWRYPTS_ROOT/zsh/common.zsh"
|
||||
source "$SCWRYPTS_ROOT/zsh/common.zsh" || exit 42
|
||||
#####################################################################
|
||||
|
||||
__RUN() {
|
||||
cd "$SCWRYPTS_ROOT"
|
||||
|
||||
##########################################
|
||||
### parse arguments ######################
|
||||
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 ENV_NAME
|
||||
[ $SCWRYPTS_ENV ] && ENV_NAME="$SCWRYPTS_ENV" || {
|
||||
[ $1 ] && [ -f $(__GET_ENV_FILE $1) ] && {
|
||||
ENV_NAME="$1"
|
||||
shift 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
|
||||
|
||||
[ -f $_VIRTUALENV ] && source $_VIRTUALENV
|
||||
|
||||
##########################################
|
||||
|
||||
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=($@)
|
||||
|
||||
[ $1 ] && {
|
||||
for PATTERN in $*
|
||||
[[ ${#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
|
||||
shift 1
|
||||
[[ $PATTERN =~ ^--$ ]] && break
|
||||
SCRIPT=$(echo $SCRIPTS | grep $PATTERN)
|
||||
SCRIPT=$(echo $SCRIPT | grep $PATTERN)
|
||||
done
|
||||
|
||||
[ ! $SCRIPT ] && __FAIL 2 "no script found by name '$@'"
|
||||
@ -35,108 +120,91 @@ __RUN() {
|
||||
__STATUS "more than one script matched '$@'"
|
||||
SCRIPT=$(echo $SCRIPT | __FZF 'select a script')
|
||||
}
|
||||
true
|
||||
} || SCRIPT=$(echo $SCRIPTS | __FZF 'select a script')
|
||||
}
|
||||
|
||||
[ ! $SCRIPT ] && exit 2
|
||||
echo $SCRIPT
|
||||
}
|
||||
|
||||
##########################################
|
||||
### check type and min dependencies ######
|
||||
##########################################
|
||||
|
||||
local ENV_REQUIRED=1
|
||||
local RUN_STRING="./$SCRIPT"
|
||||
__GET_RUN_STRING() {
|
||||
local SCRIPT="$1"
|
||||
local ENV_NAME="$2"
|
||||
local TYPE=$(echo $SCRIPT | sed 's/\/.*$//')
|
||||
|
||||
local VIRTUALENV="$SCWRYPTS_ROOT/$TYPE/.env/bin/activate"
|
||||
[ -f $VIRTUALENV ] && source $VIRTUALENV
|
||||
local RUN_STRING
|
||||
|
||||
local _VIRTUALENV="$SCWRYPTS_VIRTUALENV_PATH/$TYPE/bin/activate"
|
||||
[ -f $_VIRTUALENV ] && source $_VIRTUALENV
|
||||
|
||||
case $TYPE in
|
||||
py ) __CHECK_DEPENDENCY python || exit 3
|
||||
py ) __CHECK_DEPENDENCY python || return 1
|
||||
RUN_STRING="python -m $(echo $SCRIPT | sed 's/\//./g; s/\.py$//; s/\.\.//')"
|
||||
|
||||
python --version | grep -q '3.[91]' || {
|
||||
__WARNING 'only tested on python>=3.9'
|
||||
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'
|
||||
}
|
||||
|
||||
RUN_STRING="python -m $(echo $SCRIPT | sed 's/\//./g; s/\.py$//; s/\.\.//')"
|
||||
;;
|
||||
|
||||
zsh ) __CHECK_DEPENDENCY zsh || exit 3
|
||||
echo $SCRIPT | grep -q 'scwrypts' && ENV_REQUIRED=0
|
||||
|
||||
zsh ) __CHECK_DEPENDENCY zsh || return 1
|
||||
RUN_STRING="./$SCRIPT"
|
||||
;;
|
||||
|
||||
zx ) __CHECK_DEPENDENCY zx || exit 3
|
||||
|
||||
zx ) __CHECK_DEPENDENCY zx || return 1
|
||||
RUN_STRING="FORCE_COLOR=3 ./$SCRIPT.mjs"
|
||||
;;
|
||||
|
||||
* ) __FAIL 4 "unsupported script type '$SCRIPT_TYPE'" ;;
|
||||
* ) __ERROR "unsupported script type '$SCRIPT_TYPE'"
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
|
||||
##########################################
|
||||
### load scwrypts env and virtualenv #####
|
||||
##########################################
|
||||
RUN_STRING="SCWRYPTS_ENV='$ENV_NAME' $RUN_STRING"
|
||||
[ -f $_VIRTUALENV ] && RUN_STRING="source '$_VIRTUALENV'; $RUN_STRING"
|
||||
|
||||
[[ $ENV_REQUIRED -eq 1 ]] && {
|
||||
[ ! $ENV_NAME ] && ENV_NAME=$(__SELECT_ENV)
|
||||
[ ! $ENV_NAME ] && __ABORT
|
||||
echo $RUN_STRING
|
||||
}
|
||||
|
||||
local ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
|
||||
__CHECK_ENV_REQUIRED() {
|
||||
[ $CI ] && return 1
|
||||
|
||||
[ -f "$ENV_FILE" ] \
|
||||
&& source "$ENV_FILE" \
|
||||
&& export ENV_NAME \
|
||||
|| __FAIL 5 "missing or invalid environment '$ENV_NAME'"
|
||||
echo $SCRIPT | grep -q 'zsh/scwrypts/logs' && return 1
|
||||
|
||||
[[ $ENV_NAME =~ prod ]] && {
|
||||
__STATUS "on '$ENV_NAME'; checking diff against origin/main"
|
||||
return 0
|
||||
}
|
||||
|
||||
git fetch --quiet origin main \
|
||||
&& git diff --exit-code origin/main -- . >&2 \
|
||||
&& __SUCCESS 'up-to-date with main!' \
|
||||
|| {
|
||||
__WARNING
|
||||
__WARNING 'your branch differs from origin/main'
|
||||
__WARNING 'in '$ENV_NAME', being out-of-sync with main may have BAD CONSEQUENCES'
|
||||
__WARNING
|
||||
__yN 'continue?' || __ABORT
|
||||
}
|
||||
}
|
||||
__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
|
||||
}
|
||||
}
|
||||
|
||||
##########################################
|
||||
### run the scwrypt ######################
|
||||
##########################################
|
||||
__GET_LOGFILE() {
|
||||
local SCRIPT="$1"
|
||||
|
||||
local HEADER=$(
|
||||
echo '====================================================================='
|
||||
echo "script : $SCRIPT"
|
||||
echo "run at : $(date)"
|
||||
echo "config : $ENV_NAME"
|
||||
echo '------------------------------------------'
|
||||
)
|
||||
[ $CI ] \
|
||||
|| [ $SUBSCWRYPT ] \
|
||||
|| [[ $SCRIPT =~ scwrypts/logs ]] \
|
||||
|| [[ $SCRIPT =~ interactive ]] \
|
||||
&& return 0
|
||||
|
||||
echo $SCRIPT | grep -q 'interactive' && {
|
||||
echo $HEADER
|
||||
eval $RUN_STRING $@ </dev/tty >/dev/tty 2>&1; exit $?
|
||||
}
|
||||
|
||||
local LOGFILE="$SCWRYPTS_LOG_PATH/$(echo $SCRIPT | sed 's/^\.\///; s/\//\%/g').log"
|
||||
[[ $SCRIPT =~ scwrypts/logs ]] && LOGFILE=/dev/null
|
||||
{
|
||||
echo $HEADER
|
||||
echo '--- BEGIN OUTPUT--------------------------'
|
||||
eval $RUN_STRING $@; local EXIT_CODE="$?"
|
||||
echo '--- END OUTPUT ---------------------------'
|
||||
|
||||
local C
|
||||
[[ $EXIT_CODE -eq 0 ]] && C='32m' || C='31m';
|
||||
|
||||
echo "terminated with\\033[1;$C code $EXIT_CODE\\033[0m"
|
||||
} 2>&1 | tee --append "$LOGFILE"
|
||||
echo "$SCWRYPTS_LOG_PATH/$(echo $SCRIPT | sed 's/^\.\///; s/\//\%/g').log"
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
|
Binary file not shown.
@ -4,6 +4,7 @@
|
||||
[](https://github.com/junegunn/fzf)
|
||||
[](https://github.com/mikefarah/yq)
|
||||
[](https://github.com/stedolan/jq)
|
||||
[](https://github.com/dbcli/pgcli)
|
||||
<br>
|
||||
|
||||
Since they emulate direct user interaction, shell scripts are often the straightforward choice for task automation.
|
||||
|
@ -1,6 +1,22 @@
|
||||
_DEPENDENCIES+=(
|
||||
psql
|
||||
)
|
||||
_DEPENDENCIES+=()
|
||||
_REQUIRED_ENV+=()
|
||||
source ${0:a:h}/../common.zsh
|
||||
#####################################################################
|
||||
|
||||
__SELECT_CONNECTOR() {
|
||||
local DB_TYPE="$1"
|
||||
|
||||
CLIENTS_postgresql=(pgcli psql)
|
||||
|
||||
local C CLIENT=none
|
||||
for C in $(eval 'echo $CLIENTS_'$DB_TYPE)
|
||||
do
|
||||
__CHECK_DEPENDENCY $C >/dev/null 2>&1 && {
|
||||
CLIENT=$C
|
||||
__STATUS "detected '$CLIENT' for $DB_TYPE"
|
||||
break
|
||||
}
|
||||
done
|
||||
|
||||
echo $CLIENT
|
||||
}
|
||||
|
121
zsh/aws/rds/interactive-login
Executable file
121
zsh/aws/rds/interactive-login
Executable file
@ -0,0 +1,121 @@
|
||||
#!/bin/zsh
|
||||
_DEPENDENCIES+=()
|
||||
_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
|
||||
|
||||
__RUN_SCWRYPT 'zsh/db/interactive/postgres' -- \
|
||||
--host $DB_HOST \
|
||||
--port $DB_PORT \
|
||||
--name $DB_NAME \
|
||||
--user $DB_USER \
|
||||
--pass $DB_AUTH \
|
||||
;
|
||||
}
|
||||
|
||||
__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
|
@ -2,25 +2,20 @@
|
||||
|
||||
[ ! $SCWRYPTS_ROOT ] && SCWRYPTS_ROOT="$(dirname ${0:a:h})"
|
||||
|
||||
source $SCWRYPTS_ROOT/.config
|
||||
[ -f $SCWRYPTS_CONFIG_PATH/config ] && source $SCWRYPTS_CONFIG_PATH/config
|
||||
|
||||
[ ! -d $SCWRYPTS_CONFIG_PATH ] && mkdir -p $SCWRYPTS_CONFIG_PATH
|
||||
[ ! -d $SCWRYPTS_ENV_PATH ] && mkdir -p $SCWRYPTS_ENV_PATH
|
||||
[ ! -d $SCWRYPTS_LOG_PATH ] && mkdir -p $SCWRYPTS_LOG_PATH
|
||||
|
||||
__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}/utils/utils.zsh
|
||||
|
||||
#####################################################################
|
||||
|
||||
__ENV_TEMPLATE=$SCWRYPTS_ROOT/.template.env
|
||||
|
||||
__GET_ENV_FILES() { find $SCWRYPTS_CONFIG_PATH/env -maxdepth 1 -type f; }
|
||||
__GET_ENV_FILES() { find $SCWRYPTS_CONFIG_PATH/env -maxdepth 1 -type f | sort -r }
|
||||
[ ! "$(__GET_ENV_FILES)" ] && {
|
||||
cp $__ENV_TEMPLATE "$SCWRYPTS_CONFIG_PATH/env/dev"
|
||||
cp $__ENV_TEMPLATE "$SCWRYPTS_CONFIG_PATH/env/local"
|
||||
@ -42,3 +37,22 @@ __GET_AVAILABLE_SCRIPTS() {
|
||||
| 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
|
||||
}
|
||||
|
4
zsh/db/common.zsh
Normal file
4
zsh/db/common.zsh
Normal file
@ -0,0 +1,4 @@
|
||||
_DEPENDENCIES+=()
|
||||
_REQUIRED_ENV+=()
|
||||
source ${0:a:h}/../common.zsh
|
||||
#####################################################################
|
4
zsh/db/interactive/common.zsh
Normal file
4
zsh/db/interactive/common.zsh
Normal file
@ -0,0 +1,4 @@
|
||||
_DEPENDENCIES+=()
|
||||
_REQUIRED_ENV+=()
|
||||
source ${0:a:h}/../common.zsh
|
||||
#####################################################################
|
45
zsh/db/interactive/postgres
Executable file
45
zsh/db/interactive/postgres
Executable file
@ -0,0 +1,45 @@
|
||||
#!/bin/zsh
|
||||
_DEPENDENCIES+=(
|
||||
pgcli
|
||||
)
|
||||
_REQUIRED_ENV+=()
|
||||
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
|
||||
|
||||
local DATA_DIR="$SCWRYPTS_DATA_PATH/db/$_HOST"
|
||||
[ ! -d $DATA_DIR ] && mkdir -p $DATA_DIR
|
||||
cd $DATA_DIR
|
||||
|
||||
__STATUS "performing login : $_USER@$_HOST:$_PORT/$_NAME"
|
||||
__STATUS "working directory : $DATA_DIR"
|
||||
|
||||
PGPASSWORD="$_PASS" pgcli \
|
||||
--host $_HOST \
|
||||
--port $_PORT \
|
||||
--user $_USER \
|
||||
--dbname $_NAME \
|
||||
;
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
_LOGIN_POSTGRES $@
|
@ -15,12 +15,21 @@ This will immediately open your custom configuration file and reload any necessa
|
||||
If you use Scwrypts, **you should use these commands all the time**.
|
||||
This is your gateway to managing scwrypts sandboxed environments.
|
||||
|
||||
Command | Description
|
||||
------------- | ---------------------------------------------------------------------------------------
|
||||
`edit` | edit an existing environment; synchronizes environments if new variables are added
|
||||
`copy` | copy an existing environment to a new one
|
||||
`delete` | permanently delete an environment by name
|
||||
`synchronize` | uses [template](../../.template.env) to add missing and remove extemporaneous variables
|
||||
Command | Description
|
||||
----------------- | ---------------------------------------------------------------------------------------
|
||||
`edit` | edit an existing environment
|
||||
`copy` | create and edit a new environment from an existing one
|
||||
`delete` | permanently delete an environment by name
|
||||
`stage-variables` | stage missing variables; [helpful for non-ZSH scwrypts](../../py/scwrypts/getenv.py)
|
||||
`synchronize` | uses [template](../../.env.template) to add missing and remove extemporaneous variables
|
||||
|
||||
### Environment Inheritance
|
||||
You can make a child environment by naming an environment `<parent-name>.<child-name>`.
|
||||
Children inherit all parent-set values, and **parent-set values overwrite child-set values**.
|
||||
Remember that synchronize runs *every time you edit an environment*, so changes propagate to children immediately.
|
||||
Inherited values are denoted by `# inherited from <parent-name>` in the environment file.
|
||||
|
||||
Nested children will inherit values from all parents.
|
||||
|
||||
## Logs
|
||||
Quickly view or clear Scwrypts logs.
|
||||
|
26
zsh/scwrypts/configure
vendored
26
zsh/scwrypts/configure
vendored
@ -6,12 +6,20 @@ source ${0:a:h}/common.zsh
|
||||
|
||||
[ ! -f $SCWRYPTS_CONFIG_PATH/config ] && {
|
||||
__STATUS 'first-time setup detected; creating local configuration override...'
|
||||
cp $SCWRYPTS_ROOT/.config $SCWRYPTS_CONFIG_PATH/config \
|
||||
touch $SCWRYPTS_CONFIG_PATH/config \
|
||||
&& __SUCCESS 'created!' \
|
||||
|| __FAIL 1 "unable to create config at '$SCWRYPTS_CONFIG_PATH/config'"
|
||||
{
|
||||
echo '#'
|
||||
echo '# configuration for scwrypts'
|
||||
echo '#'
|
||||
sed -n '1d; /^###/q; p' $SCWRYPTS_ROOT/.config | sed '$d'
|
||||
} > $SCWRYPTS_CONFIG_PATH/config
|
||||
|
||||
__EDIT $SCWRYPTS_CONFIG_PATH/config
|
||||
|
||||
__STATUS 'attempting to build virtual environments'
|
||||
$SCWRYPTS_ROOT/zsh/scwrypts/virutalenv/update-all \
|
||||
__RUN_SCWRYPT zsh/scwrypts/virtualenv/update-all \
|
||||
&& __SUCCESS 'finished updating virtualenvs' \
|
||||
|| __WARNING 'unable to create one or more virtualenv (see above)' \
|
||||
;
|
||||
@ -20,16 +28,12 @@ source ${0:a:h}/common.zsh
|
||||
__REMINDER 'use "zsh/scwrypts/virtualenv/update-all" to update environments'
|
||||
__REMINDER '(equivalent to "npm install" or "pip install -r requirements.txt")'
|
||||
__REMINDER
|
||||
} || {
|
||||
__STATUS 'opening local config for editing'
|
||||
__EDIT $SCWRYPTS_CONFIG_PATH/config
|
||||
__STATUS 'finished editing!'
|
||||
}
|
||||
|
||||
__STATUS 'opening local config for editing'
|
||||
__EDIT $SCWRYPTS_CONFIG_PATH/config
|
||||
__STATUS 'finished editing!'
|
||||
|
||||
which __SCWRYPTS >/dev/null 2>&1 && {
|
||||
__STATUS 'reloading configuration for current session'
|
||||
source $SCWRYPTS_ROOT/zsh/common.zsh \
|
||||
|| __FAIL 2 'unable to reload configuration :c'
|
||||
}
|
||||
|
||||
__SUCCESS 'saved new configuration'
|
||||
__REMINDER 'changes which affect the hot-key plugin will require a ZSHRC reload'
|
||||
|
@ -2,3 +2,10 @@ _DEPENDENCIES+=()
|
||||
_REQUIRED_ENV+=()
|
||||
source ${0:a:h}/../common.zsh
|
||||
#####################################################################
|
||||
|
||||
_SORT_ENV() {
|
||||
local ENV_FILE="$1"
|
||||
|
||||
sed -i "s/^[A-Z]/export &/; s/^[^#=]\\+$/&=/" "$ENV_FILE"
|
||||
LC_COLLATE=C sort -uo "$ENV_FILE" "$ENV_FILE"
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ TEMPLATE_ENV_NAME=$(__SELECT_ENV)
|
||||
__STATUS "selected '$TEMPLATE_ENV_NAME'"
|
||||
|
||||
__PROMPT 'enter new environment name'
|
||||
ENV_NAME=$(__FZF_HEAD 'new environment')
|
||||
ENV_NAME=$(echo '' | __FZF_HEAD 'new environment')
|
||||
[ ! $ENV_NAME ] && __ABORT
|
||||
|
||||
TEMPLATE_ENV_FILE=$(__GET_ENV_FILE $TEMPLATE_ENV_NAME)
|
||||
@ -19,7 +19,19 @@ ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
|
||||
|
||||
[ -f "$ENV_FILE" ] && __FAIL 2 "'$ENV_NAME' already exists"
|
||||
|
||||
__STATUS "creating environment"
|
||||
__STATUS "creating environment '$ENV_NAME'"
|
||||
cp "$TEMPLATE_ENV_FILE" "$ENV_FILE" \
|
||||
&& __SUCCESS "created '$ENV_NAME'" \
|
||||
|| __FAIL 3 "unable to create '$ENV_NAME'"
|
||||
|
||||
__STATUS 'stripping inherited values'
|
||||
sed -i 's/ # inherited from.*$//' "$ENV_FILE" 2>/dev/null
|
||||
|
||||
__RUN_SCWRYPT zsh/scwrypts/environment/synchronize -- --no-prompt \
|
||||
|| __FAIL 4 'failed to run environment sync'
|
||||
|
||||
__RUN_SCWRYPT zsh/scwrypts/environment/edit -- $ENV_NAME \
|
||||
|| __FAIL 4 'failed to edit new environment'
|
||||
;
|
||||
|
||||
__SUCCESS "finished copy environment '$TEMPLATE_ENV_NAME > $ENV_NAME'"
|
||||
|
@ -4,9 +4,13 @@ _REQUIRED_ENV+=()
|
||||
source ${0:a:h}/common.zsh
|
||||
#####################################################################
|
||||
|
||||
[ $SCWRYPTS_ENV ] \
|
||||
&& ENV_NAME=$SCWRYPTS_ENV \
|
||||
|| ENV_NAME=$(__SELECT_OR_CREATE_ENV)
|
||||
[ $1 ] && ENV_NAME="$1"
|
||||
|
||||
[ ! $1 ] && {
|
||||
[ $SCWRYPTS_ENV ] \
|
||||
&& ENV_NAME=$SCWRYPTS_ENV \
|
||||
|| ENV_NAME=$(__SELECT_OR_CREATE_ENV)
|
||||
}
|
||||
[ ! $ENV_NAME ] && __ABORT
|
||||
|
||||
ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
|
||||
@ -33,18 +37,8 @@ do
|
||||
}
|
||||
done < $ENV_FILE
|
||||
|
||||
[ $NEW_VAR ] && {
|
||||
LC_COLLATE=C sort -uo $__ENV_TEMPLATE $__ENV_TEMPLATE
|
||||
NOPROMPT=1 ${0:a:h}/synchronize
|
||||
git add $__ENV_TEMPLATE \
|
||||
&& __SUCCESS "auto-staged the $(basename $__ENV_TEMPLATE) changes" \
|
||||
|| {
|
||||
__WARNING "unable to stage $(basename $__ENV_TEMPLATE) changes"
|
||||
__REMINDER "don't forget to commit changes to $(basename $__ENV_TEMPLATE)"
|
||||
}
|
||||
true
|
||||
} || {
|
||||
__STATUS 'no new environment variables'
|
||||
}
|
||||
__RUN_SCWRYPT zsh/scwrypts/environment/synchronize -- --no-prompt \
|
||||
|| __FAIL 4 'failed to run environment sync' \
|
||||
;
|
||||
|
||||
__SUCCESS "environment '$ENV_NAME' successfully modified"
|
||||
|
@ -4,4 +4,4 @@ _REQUIRED_ENV+=()
|
||||
source ${0:a:h}/common.zsh
|
||||
#####################################################################
|
||||
|
||||
__CHECK_ENV_VARS $@ || NOPROMPT=1 $SCWRYPTS_ROOT/zsh/scwrypts/environment/synchronize
|
||||
__CHECK_REQUIRED_ENV $@
|
||||
|
@ -1,47 +1,130 @@
|
||||
#!/bin/zsh
|
||||
#!/bin/zsh
|
||||
_DEPENDENCIES+=()
|
||||
_REQUIRED_ENV+=()
|
||||
source ${0:a:h}/common.zsh
|
||||
#####################################################################
|
||||
|
||||
[ ! $NOPROMPT ] && {
|
||||
__yN 'change the template before sync?' && __EDIT $__ENV_TEMPLATE
|
||||
sed -i "s/^[A-Z]/export &/; s/^[^#=]\\+$/&=/; s/=.*$/=/" $__ENV_TEMPLATE
|
||||
LC_COLLATE=C sort -uo $__ENV_TEMPLATE $__ENV_TEMPLATE
|
||||
git add $__ENV_TEMPLATE >/dev/null 2>&1
|
||||
_SYNCHRONIZE() {
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case $1 in
|
||||
--no-prompt ) SLIENT=1; shift 1 ;;
|
||||
|
||||
* ) __WARNING "argument '$1' not recognized"
|
||||
shift 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ ! $SLIENT ] && {
|
||||
__yN 'change the template before sync?' && __EDIT $__ENV_TEMPLATE
|
||||
_SORT_ENV "$__ENV_TEMPLATE"
|
||||
git add $__ENV_TEMPLATE >/dev/null 2>&1
|
||||
}
|
||||
|
||||
ENVIRONMENTS=$(__GET_ENV_NAMES | sort -r)
|
||||
|
||||
_CLEAR_INHERITED_VARIABLES
|
||||
_INSERT_NEW_VARIABLES
|
||||
_REMOVE_OLD_VARIABLES
|
||||
_SORT_AND_CASCADE
|
||||
|
||||
__SUCCESS 'finished sync!'
|
||||
}
|
||||
|
||||
ENVIRONMENTS=$(__GET_ENV_FILES)
|
||||
#####################################################################
|
||||
|
||||
__STATUS 'inserting new environment variables...'
|
||||
while read line
|
||||
do
|
||||
for ENV_FILE in $(echo $ENVIRONMENTS)
|
||||
do
|
||||
grep -q "^$line" $ENV_FILE || {
|
||||
echo $line >> $ENV_FILE && __STATUS "added '$line' to '$ENV_FILE'"
|
||||
}
|
||||
done
|
||||
done < <(sed -n '/^./p' $__ENV_TEMPLATE)
|
||||
_CLEAR_INHERITED_VARIABLES() {
|
||||
for ENV_NAME in $(echo $ENVIRONMENTS)
|
||||
do
|
||||
ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
|
||||
sed -i 's/ # inherited from.*//' "$ENV_FILE"
|
||||
done
|
||||
}
|
||||
|
||||
__STATUS 'removing old environment variables...'
|
||||
for ENV_FILE in $(echo $ENVIRONMENTS)
|
||||
do
|
||||
while read line
|
||||
do
|
||||
ENV_VAR=$(echo "$line" | sed 's/=.*/=/')
|
||||
grep -q "$ENV_VAR" $__ENV_TEMPLATE || {
|
||||
sed -i "\\%$ENV_VAR%d" $ENV_FILE
|
||||
__WARNING "removed unwanted '$ENV_VAR' from '$ENV_FILE'"
|
||||
}
|
||||
done < $ENV_FILE
|
||||
done
|
||||
_INSERT_NEW_VARIABLES() {
|
||||
__STATUS 'inserting new environment variables...'
|
||||
|
||||
for ENV_FILE in $(echo $ENVIRONMENTS)
|
||||
do
|
||||
sed -i "s/^[A-Z]/export &/; s/^[^#=]\\+$/&=/" $ENV_FILE
|
||||
LC_COLLATE=C sort -uo $ENV_FILE $ENV_FILE
|
||||
done
|
||||
LC_COLLATE=C sort -uo $__ENV_TEMPLATE $__ENV_TEMPLATE
|
||||
local ENV_NAME ENV_FILE line
|
||||
while read line
|
||||
do
|
||||
for ENV_NAME in $(echo $ENVIRONMENTS)
|
||||
do
|
||||
ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
|
||||
grep -q "$line" $ENV_FILE || {
|
||||
echo $line >> $ENV_FILE && __STATUS "added '$line' to '$ENV_NAME'"
|
||||
}
|
||||
done
|
||||
done < <(sed -n '/^./p' "$__ENV_TEMPLATE")
|
||||
}
|
||||
|
||||
__SUCCESS 'finished sync!'
|
||||
_REMOVE_OLD_VARIABLES() {
|
||||
__STATUS 'removing old environment variables...'
|
||||
|
||||
local ENV_NAME ENV_FILE line
|
||||
for ENV_NAME in $(echo $ENVIRONMENTS)
|
||||
do
|
||||
ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
|
||||
while read line
|
||||
do
|
||||
ENV_VAR=$(echo "$line" | sed 's/=.*/=/')
|
||||
grep -q "$ENV_VAR" "$__ENV_TEMPLATE" || {
|
||||
sed -i "\\%$ENV_VAR%d" "$ENV_FILE"
|
||||
echo "$ENV_VAR" | grep -qv '^#' \
|
||||
&& __WARNING "removed unwanted '$ENV_VAR' from '$ENV_NAME'"
|
||||
}
|
||||
done < $ENV_FILE
|
||||
done
|
||||
}
|
||||
|
||||
_SORT_AND_CASCADE() {
|
||||
local ENV_NAM ENV_FILE
|
||||
|
||||
for ENV_NAME in $(echo $ENVIRONMENTS)
|
||||
do
|
||||
ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
|
||||
_CASCADE_ENVIRONMENT $ENV_NAME
|
||||
done
|
||||
|
||||
for ENV_NAME in $(echo $ENVIRONMENTS)
|
||||
do
|
||||
ENV_FILE=$(__GET_ENV_FILE $ENV_NAME)
|
||||
_SORT_ENV "$ENV_FILE"
|
||||
done
|
||||
}
|
||||
|
||||
_CASCADE_ENVIRONMENT() {
|
||||
local PARENT_NAME="$1"
|
||||
local PARENT_FILE=$(__GET_ENV_FILE $PARENT_NAME)
|
||||
|
||||
local CHILD_NAMES=$(echo $ENVIRONMENTS | grep "^$PARENT_NAME\\.")
|
||||
[ ! $CHILD_NAMES ] && return 0
|
||||
|
||||
__STATUS "cascading '$PARENT_NAME' to children"
|
||||
for CHILD_NAME in $(echo $CHILD_NAMES)
|
||||
do
|
||||
__SUCCESS "detected child '$CHILD_NAME'"
|
||||
done
|
||||
|
||||
local PARENT_VAR VAR_PATTERN CHILD_NAME CHILD_FILE
|
||||
|
||||
while read PARENT_VAR
|
||||
do
|
||||
VAR_PATTERN=$(echo "$PARENT_VAR" | sed 's/=.*/=/; s/\//\/\//g')
|
||||
__STATUS "propagating '$(echo $VAR_PATTERN | sed 's/^export \([^=]*\)=/\1/')' to children"
|
||||
|
||||
PARENT_VAR+=" # inherited from $PARENT_NAME"
|
||||
|
||||
for CHILD_NAME in $(echo $CHILD_NAMES)
|
||||
do
|
||||
CHILD_FILE=$(__GET_ENV_FILE $CHILD_NAME)
|
||||
|
||||
sed -i "/^$VAR_PATTERN/d" "$CHILD_FILE"
|
||||
echo $PARENT_VAR >> "$CHILD_FILE"
|
||||
done
|
||||
done < <(sed -n '/^[^#][^=]*=[^#]\+$/p' "$PARENT_FILE")
|
||||
|
||||
__SUCCESS "finished '$PARENT_NAME' propagation"
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
_SYNCHRONIZE $@
|
||||
|
@ -6,7 +6,7 @@ source ${0:a:h}/common.zsh
|
||||
|
||||
cd $SCWRYPTS_ROOT
|
||||
__PROMPT 'select a script log'
|
||||
LOG_FILE=$(ls $SCWRYPTS_LOG_PATH | __FZF 'logfile')
|
||||
LOG_FILE=$(ls -t $SCWRYPTS_LOG_PATH | __FZF 'logfile')
|
||||
[ ! $LOG_FILE ] && { __ERROR 'user abort'; exit 1; }
|
||||
|
||||
__STATUS 'opening logfile'
|
||||
|
@ -42,11 +42,11 @@ __UPDATE_VIRTUALENV() {
|
||||
return 1
|
||||
}
|
||||
|
||||
cd $VIRTUALENV_PATH/../
|
||||
cd $SCWRYPTS_ROOT
|
||||
local UPDATE_CODE=0
|
||||
case $TYPE in
|
||||
python ) pip install -r requirements.txt; UPDATE_CODE=$? ;;
|
||||
node ) npm install ;
|
||||
python ) cd py; pip install -r requirements.txt; UPDATE_CODE=$? ;;
|
||||
node ) cd zx; npm install ;;
|
||||
esac
|
||||
UPDATE_CODE=$?
|
||||
[[ $UPDATE_CODE -eq 0 ]] \
|
||||
@ -78,8 +78,8 @@ __DELETE_VIRTUALENV() {
|
||||
__GET_VIRTUALENV_PATH() {
|
||||
local TYPE="$1"
|
||||
case $TYPE in
|
||||
python ) echo "$SCWRYPTS_ROOT/py/.env" ;;
|
||||
node ) echo "$SCWRYPTS_ROOT/zx/.env" ;;
|
||||
python ) echo "$SCWRYPTS_VIRTUALENV_PATH/py" ;;
|
||||
node ) echo "$SCWRYPTS_VIRTUALENV_PATH/zx" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
71
zsh/utils/README.md
Normal file
71
zsh/utils/README.md
Normal file
@ -0,0 +1,71 @@
|
||||
# ZSH Utilities
|
||||
|
||||
A shell-scripting utilities module made for ZSH.
|
||||
This module is definitely a major component of Scwrypts, but is also standalone and can be sourced by any ZSH script to utilize (almost) all of the features.
|
||||
|
||||
## Usage
|
||||
Import `utils.module.zsh` to activate all of the features.
|
||||
Doing so will *also* check for path dependencies and required environment variables (see [Dependencies](#dependencies) and [Environment](#environment) below).
|
||||
|
||||
|
||||
```shell
|
||||
#!/bin/zsh
|
||||
source ./path/to/utils.plugin.zsh
|
||||
__SUCCESS 'ZSH utilities online!'
|
||||
```
|
||||
|
||||
Checkout [io](./io.zsh) and [os](./os.zsh) for available simple functions.
|
||||
|
||||
### Dependencies
|
||||
Ensures dependent programs are available for execution.
|
||||
Specify a simple name to check the current `PATH`, or give a fully-qualified path for arbitrary dependency inclusion.
|
||||
|
||||
Include a dependency by adding to the `_DEPENDENCIES` array.
|
||||
*Always using `+=` makes your dependencies extensible to other scripts :)*
|
||||
|
||||
If any dependencies are missing, `source utils.module.zsh` will return an error code and count the number of missing dependencies in the variable `DEP_ERROR_COUNT`.
|
||||
|
||||
```shell
|
||||
#!/bin/zsh
|
||||
_DEPENDENCIES+=(
|
||||
path-executable-1
|
||||
path-executable-2
|
||||
/path/to/arbitrary/program
|
||||
)
|
||||
source ./path/to/utils.plugin.zsh
|
||||
echo "missing $DEP_ERROR required dependencies"
|
||||
```
|
||||
|
||||
### Environment
|
||||
Similar to [Dependencies](#dependencies), `environment.zsh` ensures a list of environment variables are *set to non-empty values*.
|
||||
|
||||
Include an environment variable by adding to the `_REQUIRED_ENV` array.
|
||||
*Something something use `+=` here too ;)*
|
||||
|
||||
If any environment variables are missing, `source utils.module.zsh` will return an error code and count the number of missing variables in `ENV_ERROR_COUNT`.
|
||||
|
||||
Missing environment variables will be added to the environment template (*exclusive to Scwrypts*).
|
||||
|
||||
```shell
|
||||
#!/bin/zsh
|
||||
_REQUIRED_ENV+=(
|
||||
AWS_PROFILE
|
||||
AWS_REGION
|
||||
)
|
||||
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
|
@ -1,5 +1,5 @@
|
||||
__CREDITS() {
|
||||
# only applicable within scwrypts ("credits" pulled from README files)
|
||||
# scwrypts exclusive ("credits" pulled from README files)
|
||||
[ ! $SCWRYPTS_ROOT ] && return 0
|
||||
|
||||
local COMMAND="$1"
|
||||
|
@ -1,38 +1,37 @@
|
||||
__CHECK_REQUIRED_ENV() {
|
||||
local VAR ERROR=0
|
||||
for VAR in $*; do __CHECK_ENV_VAR $VAR_NAME || ((ERROR+=1)); done
|
||||
for VAR in $*; do __CHECK_ENV_VAR $VAR || ((ERROR+=1)); done
|
||||
return $ERROR
|
||||
}
|
||||
|
||||
__CHECK_ENV_VAR() {
|
||||
local NAME="$1"
|
||||
[ ! $NAME ] && return 1
|
||||
|
||||
local OPTIONAL="$2"
|
||||
local DEFAULT_VALUE="$3"
|
||||
|
||||
local VALUE=$(eval echo '$'$NAME)
|
||||
[ $VALUE ] && return 0
|
||||
|
||||
local LINE="export $NAME="
|
||||
local TEMPLATE="$SCWRYPTS_ROOT/.template.env"
|
||||
|
||||
grep -q -- "^$LINE" "$TEMPLATE" || {
|
||||
__STATUS 'staging new variable in template'
|
||||
[ $__SCWRYPT ] && {
|
||||
# scwrypts exclusive (missing vars staged in env.template)
|
||||
local LINE="export $NAME="
|
||||
|
||||
echo "$LINE" >> "$TEMPLATE" \
|
||||
&& NOPROMPT=1 $SCWRYPTS_ROOT/zsh/scwrypts/environment/synchronize \
|
||||
&& git add $TEMPLATE >/dev/null 2>&1 \
|
||||
&& __SUCCESS "staged '$NAME'" \
|
||||
|| {
|
||||
__WARNING "failed to stage '$NAME'"
|
||||
__REMINDER "add/commit '$NAME' to template manually"
|
||||
}
|
||||
grep -q -- "^$LINE" "$__ENV_TEMPLATE" || {
|
||||
__STATUS 'staging new variable in template'
|
||||
|
||||
echo "$LINE" >> "$__ENV_TEMPLATE" \
|
||||
&& __RUN_SCWRYPT zsh/scwrypts/environment/synchronize -- --no-prompt
|
||||
}
|
||||
}
|
||||
|
||||
[ $OPTIONAL ] && {
|
||||
__ERROR "'$NAME' required"
|
||||
return 1
|
||||
} || {
|
||||
[ $DEFAULT_VALUE ] && $NAME="$DEFAULT_VALUE"
|
||||
return 0
|
||||
} || {
|
||||
__ERROR "'$NAME' required"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ __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; }
|
||||
|
||||
__PROMPT() {
|
||||
echo "\\033[1;36mPROMPT : $@\\033[0m" >&2
|
||||
printf "\\033[1;36mUSER : \\033[0m" >&2
|
||||
@ -10,12 +11,16 @@ __PROMPT() {
|
||||
|
||||
__Yn() {
|
||||
__PROMPT "$@ [Yn]"
|
||||
[ $CI ] && { echo y; return 0; }
|
||||
|
||||
local Yn; __READ -k Yn; echo
|
||||
[[ $Yn =~ [nN] ]] && return 1 || return 0
|
||||
}
|
||||
|
||||
__yN() {
|
||||
__PROMPT "$@ [yN]"
|
||||
[ $CI ] && { echo y; return 0; }
|
||||
|
||||
local yN; __READ -k yN; echo
|
||||
[[ $yN =~ [yY] ]] && return 0 || return 1
|
||||
}
|
||||
@ -35,10 +40,29 @@ __GETSUDO() {
|
||||
|
||||
__LESS() { less -R $@ </dev/tty >/dev/tty; }
|
||||
|
||||
__FZF() { fzf -i --height=30% --layout=reverse --prompt "$@ : "; }
|
||||
__FZF_HEAD() { fzf -i --height=30% --layout=reverse --print-query --prompt "$@ : " | head -n1; }
|
||||
__FZF_TAIL() { fzf -i --height=30% --layout=reverse --print-query --prompt "$@ : " | tail -n1; }
|
||||
__FZF() {
|
||||
[ $CI ] && {
|
||||
__ERROR 'currently in CI, but __FZF requires user input'
|
||||
exit 1
|
||||
}
|
||||
|
||||
__READ() { read $@ </dev/tty; }
|
||||
fzf -i --height=30% --layout=reverse --prompt "$1 : " ${@:2}
|
||||
}
|
||||
__FZF_HEAD() { __FZF $@ --print-query | sed '/^$/d' | head -n1; } # prefer user input over selected
|
||||
__FZF_TAIL() { __FZF $@ --print-query | sed '/^$/d' | tail -n1; } # prefer selected over user input
|
||||
|
||||
__EDIT() { $EDITOR $@ </dev/tty >/dev/tty; }
|
||||
__READ() {
|
||||
[ $CI ] && {
|
||||
__ERROR 'currently in CI, but __READ explicitly requires terminal input'
|
||||
return 1
|
||||
}
|
||||
read $@ </dev/tty
|
||||
}
|
||||
|
||||
__EDIT() {
|
||||
[ $CI ] && {
|
||||
__ERROR 'currently in CI, but __EDIT explicitly requires terminal input'
|
||||
return 1
|
||||
}
|
||||
$EDITOR $@ </dev/tty >/dev/tty
|
||||
}
|
||||
|
@ -13,17 +13,33 @@ source ${0:a:h}/credits.zsh
|
||||
|
||||
IMPORT_ERROR=0
|
||||
|
||||
[ $CI ] && {
|
||||
export _AWS_PROFILE="$AWS_PROFILE"
|
||||
export _AWS_ACCOUNT="$AWS_ACCOUNT"
|
||||
export _AWS_REGION="$AWS_REGION"
|
||||
}
|
||||
|
||||
source ${0:a:h}/dependencies.zsh
|
||||
_DEP_ERROR=0
|
||||
_DEPENDENCIES=($(echo $_DEPENDENCIES | sort -u))
|
||||
__CHECK_DEPENDENCIES $_DEPENDENCIES || ((IMPORT_ERROR+=$?))
|
||||
__CHECK_DEPENDENCIES $_DEPENDENCIES || _DEP_ERROR=$?
|
||||
|
||||
source ${0:a:h}/environment.zsh
|
||||
_REQUIRED_ENV=($(echo $__CHECK_REQUIRED_ENV | sort -u))
|
||||
__CHECK_REQUIRED_ENV $_REQUIRED_ENV || ((IMPORT_ERROR+=$?))
|
||||
_ENV_ERROR=0
|
||||
_REQUIRED_ENV=($(echo $_REQUIRED_ENV | sort -u))
|
||||
__CHECK_REQUIRED_ENV $_REQUIRED_ENV || _ENV_ERROR=$?
|
||||
|
||||
[[ $IMPORT_ERROR -eq 0 ]] || {
|
||||
[[ $_ENV_ERROR -ne 0 ]] && {
|
||||
__REMINDER 'to update missing environment variables, run:'
|
||||
__REMINDER "'scwrypts zsh/scwrypts/environment/edit'"
|
||||
}
|
||||
|
||||
((IMPORT_ERROR+=$_DEP_ERROR))
|
||||
((IMPORT_ERROR+=$_ENV_ERROR))
|
||||
|
||||
[[ $IMPORT_ERROR -ne 0 ]] && {
|
||||
__ERROR "encountered $IMPORT_ERROR import error(s)"
|
||||
return 1
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
[[ $IMPORT_ERROR -eq 0 ]]
|
1
zx/.gitignore
vendored
1
zx/.gitignore
vendored
@ -1,2 +1 @@
|
||||
node_modules/
|
||||
.env/
|
||||
|
Loading…
x
Reference in New Issue
Block a user