Compare commits

...

31 Commits

Author SHA1 Message Date
d4ef1c70e0 plugins/ci migration from v3 to v4 2024-02-12 23:45:37 -07:00
c9e107d2fd plugins/kubectl migration from v3 to v4 2024-02-12 23:45:05 -07:00
b6b4f2e5b8 FZF_(HEAD|TAIL) refactor to FZF_USER_INPUT 2024-02-12 23:44:43 -07:00
432593a0f3 update ZLE plugin so it no more make errors 2024-02-12 23:43:28 -07:00
6629caf459 FINALLY fix the weird cases for zsh/read builtin (particularly around reading one character from tty/pipe/file); also gave a --force-user-input flag in case you want to require user input on a yn prompt 2024-02-12 23:42:55 -07:00
8bcc99b898 improved i/o handling on the run executable means this is no longer relevant 2024-02-12 23:41:42 -07:00
05694ed022 bring some much-needed tender love and care to the scwrypts runner 2024-02-12 23:39:56 -07:00
67bd712590 v3-to-v4 upgrade docs 2024-02-12 23:39:00 -07:00
a90482de8c swap INFO for DEBUG 2024-02-07 15:16:51 -07:00
261bbee1a4 introduce --verbosity flag rather than mixed logging settings; correct color misnaming to ANSI convention; added sanity-check; simplified hello-world; created FZF_USER_INPUT to replace the confusing FZF_HEAD and FZF_TAIL 2024-02-07 15:14:36 -07:00
fcf492c661 basic runner format; write a MAIN function 2024-02-06 14:06:44 -07:00
a200c1eb22 v3.9.1
=====================================================================

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

- Moved personal-environment specific scwrypts to wrynegade/dotwryn
2023-12-23 10:23:38 -07:00
f3e70c61cb v3.9.0
=====================================================================

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

- scwrypts runner has new arguments
  -q/--quiet   allows quiet-mode operation while still logging to logfiles
  -v/--verbose forces verbose mode
    --version  longform required (-v is now for "verbose" mode)

- scwrypts runner now auto-detects certain CLI usage, running in quiet,
  logged mode if pattern match successfully identifies a single scwrypt
  (or when using --name); use --verbose to override this behavior

- 'k exec' no longer requires double '--' if a '--' comes after
  - old : k exec -it my-pod-0 -- -- /bin/sh
  + new : k exec -it my-pod-0 -- /bin/sh
  + still works : k -- exec -it my-pod-0 -- /bin/sh

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

- fixed various plugins/kubectl auto-completion settings; arguments
  after '--' or profile number (e.g. 'k 1 get deployments') will now
  appropriately autocomplete in the indicated profile

- helm template functions now work on related .tpl files as well
  (renders from chart root)

- fixed some goofy UTF-8 icons in zsh/lib/utils/io

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

- (experimental) scwrypts zsh plugin for interactive command selection
  (like CTRL+SPACE), but allows you to build command arguments,
  providing help dialogue for the selected command

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

- zsh/misc/tally ) helps keep tally-counts of things; helpful when
                   running long scripts "what iteration am I on"
2023-12-11 18:19:37 -07:00
72e831da33 v3.8.0
=====================================================================

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

- kubectl driver updates; getting better, but still need to fix
  autocomplete in certain circumstances

- added -y|--yes flags to scwrypts to auto-accept user-prompts (use with
  caution)

- figured out the whole mikefarah/yq vs kislyuk/yq thing; use YQ for
  compatiblity

--- Bug fixes ----------------------------

- helm template generation now loads values in a more appropriate order
  which prevents overwrite by the wrong values file
2023-11-22 15:54:16 -07:00
a03885e8db v3.7.8
=====================================================================

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

- --list-envs now shows all available environments
2023-11-13 16:19:05 -07:00
6cc10e3f4f v3.7.7
=====================================================================

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

- GitHub Actions now autodetects groups within the "$GITHUB_WORKSPACE"
2023-11-13 13:16:04 -07:00
4a1208942d v3.7.6
=====================================================================

Documentation update
2023-11-13 12:30:49 -07:00
91780024f0 v3.7.5
=====================================================================

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

- adding variables of the format `^SCWRYPTS_GROUP_LOADERS__[a-z_]\+=`
  will let those files be explicitly sourced during run (this should
  allow custom group usage in CI)
2023-11-13 12:27:15 -07:00
3ca4fe0c65 v3.7.4
=====================================================================

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

- fixed typo in Vundle.vim clone
2023-11-11 15:27:34 -07:00
e6dfff255c v3.7.3
=====================================================================

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

- Helm template generation looks for default values in file://
  dependencies in addition to the standard values locations

- vundle installer now *actually installs Vundle.vim* if it is missing
2023-11-11 15:13:30 -07:00
15942bb08d v3.7.2
=====================================================================

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

- Various github-actions fixes
2023-11-10 17:41:01 -07:00
6f42c9cb16 v3.7.0
=====================================================================

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

- Github Actions integration from 3.7.0 and up!

```yaml
  # try it out in gh actions
  - uses: wrynegade/scwrypts@main
    with:
      version: v3.7.0
      scwrypt: --name hello-world --group scwrypts --type py
      args: --message "hello from github actions ci <3"
```

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

zsh/helm )
  smart helm template functions (simply pass a filename)
   - get-template
   - update-dependencies

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

- CHECK_ENVIRONMENT now uses proper argument parsing

- scwrypts/plugins loaded by setting in config or environment:
   SCWRYPTS_PLUGIN_ENABLED__plugin=1

- SCWRYPTS__GET_PATH_TO_RELATIVE_ARGUMENT was missed in the v2->v3
  refactor and has now been reincluded as SCWRYPTS__GET_REALPATH
2023-11-10 16:32:05 -07:00
570fc6a435 v3.6.6
=====================================================================

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

- Allow CI more leniency in preparing aws environment
2023-10-23 12:47:53 -06:00
768350e6ab v3.6.5
=====================================================================

--- Bug fixes ----------------------------

- Some exit error cases were not handled properly by the default eval
  string due to early exit failing within the primary subshell of the
  scwrypt; moving the runstring one subshell deeper allows the capture
  of exit cases
2023-10-19 20:04:25 -06:00
531aa52146 v3.6.4
=====================================================================

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

- Introduced lazy environment variable checking on ECR_LOGIN
2023-10-19 14:44:01 -06:00
f8ccce9285 v3.6.3
=====================================================================

--- Bug fixes ----------------------------

- Silenced a startup error
2023-10-05 14:40:45 -06:00
6fc17bcfe5 v3.6.2
=====================================================================

--- Bug fixes ----------------------------

- fixed some bugs with kubectl plugin preloading and argument processing
2023-10-05 14:36:40 -06:00
2034325ac9 v3.6.1
=====================================================================

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

- Adjusted USAGE (from zsh/lib/utils/io.zsh) to allow dynamic variable
  insertion in help dialogues by setting USAGE__<help-group> and using
  the syntax listed

- Various quality-of-life changes and and fixes to experimental kubectl
  plugin

--- Bug fixes ----------------------------

- sourcing 'scwrypts.plugin.zsh' no longer sets __SCWRYPT=1 in your
  current environment
2023-08-30 17:26:13 -06:00
ab567f6950 v3.6.0
=====================================================================

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

- Introducing an optional plugin for `kubectl` facilitation! Check out
  'plugins/kubectl/README.md' for more details.

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

- The function which lists all available scwrypts now ignores
  directories with a top-level base called "plugins." If this is a name
  conflict, you will need to define your own
  `SCWRYPTS__LIST_AVAILABLE_SCWRYPTS__<group>` function!

  (ref the changes in 'zsh/lib/scwrypts/run.module.zsh')
2023-08-28 20:31:04 -06:00
e199e9bf91 v3.5.0
=====================================================================

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

- AWS (the cli wrapper) now checks for it's required variables *on run*.
  This accomodates scwrypts which may need to run in multiple regions,
  but make the downstream scwrypt responsible for adding AWS_REGION to
  the REQUIRED_ENV list!

- Got rid of all kinds of hackiness surrounding postgres password evals
  between both the postgres library and the rds library

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

- scwrypts --update now pulls tags for proper versioning
2023-08-24 17:11:34 -06:00
4c161aba49 v3.4.0
=====================================================================

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

- Allow the group variable `REQUIRED_ENVIRONMENT_REGEX` to enforce that
  only some environments can run within the group
2023-08-22 14:20:03 -06:00
107 changed files with 3040 additions and 1211 deletions

16
.github/workflows/update-semver.yaml vendored Normal file
View File

@ -0,0 +1,16 @@
---
name: Update Semver
on: # yamllint disable-line rule:truthy
push:
branches-ignore:
- '**'
tags:
- 'v*.*.*'
jobs:
update-semver:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: rickstaa/action-update-semver@v1

View File

@ -6,6 +6,9 @@ In modern developer / dev-ops workflows, scripts require a complex configuration
Without a better solution, the developer is cursed to copy lines-upon-lines of variables into terminals, create random text artifacts, or maybe even commit secure credentials into source.
Scwrypts leverages ZSH to give hot-key access to run scripts in such environments.
## Major Version Upgrade Notice
Please refer to [Version 3 to Version 4 Upgrade Path](./docs/upgrade/v3-to-v4.md) when upgrading from scwrypts v3 to scwrypts v4!
## Dependencies
Due to the wide variety of resources used by scripting libraries, the user is expected to manually resolve dependencies.
@ -48,6 +51,8 @@ There are a few notable changes to this runtime:
- User yes/no prompts will **always be YES**
- Other user input will default to an empty string
- Logs will not be captured
- Setting the environment variable `SCWRYPTS_GROUP_LOADER__[a-z_]\+` will source the file indicated in the variable (this allows custom groups without needing to modify the `config.zsh` directly)
- In GitHub actions, `*.scwrypts.zsh` groups are detected automatically from the `$GITHUB_WORKSPACE`; set `SCWRYPTS_GITHUB_NO_AUTOLOAD=true` to disable
## Contributing

68
action.yaml Normal file
View File

@ -0,0 +1,68 @@
--- # allow running scwrypts in Github Actions
name: scwrypts
author: yage
description: check required dependencies and run a scwrypt
inputs:
scwrypt:
description: "args / identifiers for scwrypts CLI (e.g. '--name <scwrypt-name> --group <group-name> --type <type-name>')"
required: true
args:
description: "arguments to pass to the scwrypt-to-be-run"
required: false
version:
description: "scwrypts version; defaults to latest (minimum v3.7.0)"
required: false
scwrypts-env:
description: "override value for SCWRYPTS_ENV"
required: false
default: "ci.github-actions"
runs:
using: composite
steps:
- uses: actions/checkout@v4
with:
repository: wrynegade/scwrypts
path: ./wrynegade/scwrypts
ref: ${{ inputs.version }}
- name: check dependencies
shell: bash
env:
CI: true
SCWRYPTS_PLUGIN_ENABLED__ci: 1
run: |
[ $CI_SCWRYPTS_READY ] && [[ $CI_SCWRYPTS_READY -eq 1 ]] && echo 'setup completed previously' && exit 0
echo "updating package dependencies"
{
sudo apt-get update
sudo apt-get install --yes zsh fzf ripgrep
for D in $($GITHUB_WORKSPACE/wrynegade/scwrypts/scwrypts -n --name check-all-dependencies --group ci --type zsh)
do
echo "--- installing $D ---"
( sudo apt-get install --yes $D; exit 0; )
done
} > $HOME/.scwrypts.apt-get.log 2>&1
echo "updating virtual dependencies"
$GITHUB_WORKSPACE/wrynegade/scwrypts/scwrypts -n \
--name scwrypts/virtualenv/update-all \
--group scwrypts \
--type zsh \
> $HOME/.scwrypts.virtualenv.log 2>&1
echo "CI_SCWRYPTS_READY=1" >> $GITHUB_ENV
exit 0
- name: run scwrypt
shell: bash
env:
CI: true
SCWRYPTS_ENV: ${{ inputs.scwrypts-env }}
run: $GITHUB_WORKSPACE/wrynegade/scwrypts/scwrypts ${{inputs.scwrypt}} -- ${{inputs.args}} || exit 1

254
docs/upgrade/v3-to-v4.md Normal file
View File

@ -0,0 +1,254 @@
# Scwrypts Upgrade v3 to v4 Notes
Scwrypts v4 brings a big update to the *runstring for `zsh`-type scwrypts*.
I've found some of the boilerplate required by each individual script to be confusing and terse, and the goal here is to make it easier and safer to write and run scwrypts in this critical format.
Jump to [Technical Bits](#technical-bits) if you just want to get started with migration steps.
The actual migration _should take less than a minute per script_.
This document is deliberately verbose for future reference when I don't remember how any of this works.
## Ideology and History
Originally (scwrypts v2 and below) wanted to preserve the direct-use of individual scwrypts.
In those versions, executable files could be executed directly (outside of the `scwrypts` function) and still operate with minimal, unwanted consequences.
This resulted in a rigid structure which made code-sharing difficult at small scales and untenable in many non-trivial cases.
Scwrypts v3, begrudgingly introduced a pseudo-import syntax with `use`.
This sought to combat the issues of code-sharing and open up the structure of executable scwrypts to the scwrypts-writer.
Beyond just clarity, this allowed external libraries to be written and cross-referenced.
Although "importing" is an odd (anti?)feature to shell scripting, the way libraries could be written and reused was too helpful and I succumbed to write the `import.driver.zsh` module.
Throughout v3, I tried to maintain the "executability" of individual scwrypts.
It's ugly though.
Every individual scwrypt relies on `import.driver.zsh` and the context set up by the `scwrypts` executable.
While you _could_ run the executable file directly, it would misbehave at-best and fail pretty reliably.
So... here's v4!
Scwrypts v4 accepts the reality that, although `zsh` scwrypts are zsh, they do not stand alone without the proper context setup provided by `scwrypts`.
To improve usability, I've abstracted much of the boilerplate so you never have to see it.
I've injected safety mechanisms like `--help` arguments and utility mechanisms like flag separation (`-abc` is really `-a -b -c`) into all v4 zsh scwrypts.
You don't have to worry about checking the context, v4 does that for you!
You don't have to worry about execution, v4 does that for you!
So!
Are you coupling your zsh scripts to `scwrypts` when you write them? Yes.
Is that a bad thing? I don't think so.
Shell-scripting is such a critical coupler to real-life systems.
High-risk-high-impact to SLAs means we cannot allow context mistakes by sysadmins and users.
Reusability between local machine, cloud runtime, and CI pipelines is a must.
And if you have a need to reign all that in to single, isolated executable files...
...then good luck <3
## Technical Bits
Big idea: let's get rid of v3 boilerplate and make things easy.
### Your executable must be in a MAIN function
A main function in shell scripts?
Weird!
Don't worry, it's easy.
Take your original scwrypt, and slap the executable stuff into a function called `MAIN` (yes, it must be _exactly_, all-caps `MAIN`):
```diff
#!/bin/zsh
#####################################################################
DEPENDENCIES+=(dep-function-a dep-function-b)
REQUIRED_ENV+=()
use do/awesome/stuff --group my-custom-library
CHECK_ENVIRONMENT
#####################################################################
- echo "do some stuff here"
- # ... etc ...
- SUCCESS "completed the stuff"
+ MAIN() {
+ echo "do some stuff here"
+ # ... etc ...
+ SUCCESS "completed the stuff
+ }
```
**Don't invoke the function!**
Scwrypts will now do that on your behalf.
I've already written many scwrypts which _almost_ used this syntax.
All I had to do in this case was delete the function invocation at the end:
```diff
# ... top boilerplate ...
MAIN() {
SUCCESS "look at me I'm so cool I already wrote this in a main function"
}
-
- #####################################################################
- MAIN $@
```
Again, **do not invoke the function**. Just name it `MAIN` and you're good-to-go!
### Great news!
Great news!
We have finished with *all of the necessary steps* to migrate to v4!
Easy!
While you're here, let's do a couple more things to cleanup your scwrypts (I promise they are also easy and will take less than a few seconds for each)!
### Remove the boilerplate
Were you confused by all that garbage at the top?
Awesome!
Just get rid of any of it you don't use.
While you _probably_ will still need whatever dependencies you already defined, feel free to get rid of empty config lists like `DEPENDENCIES+=()`.
For non-empty lists, the syntax remains the same (use the `+=` and make sure it's an array-type `()` just like before!)
Also you can ditch the `CHECK_ENVIRONMENT`.
While it won't hurt, v4 already does this, so just get rid of it.
Here's my recommended formatting:
```diff
#!/bin/zsh
- #####################################################################
DEPENDENCIES+=(dep-function-a dep-function-b)
- REQUIRED_ENV+=()
use do/awesome/stuff --group my-custom-library
-
- CHECK_ENVIRONMENT
#####################################################################
MAIN() {
echo "do some stuff here"
# ... etc ...
SUCCESS "completed the stuff
}
```
### Get rid of `--help` argument processing
Scwrypts v4 injects the `--help` argument into every zsh scwrypt.
So there's no need to process it manually anymore!
We can now eliminate the help case from any MAIN body or library function:
```diff
MAIN() {
while [[ $# -gt 0 ]]
do
case $1 in
# ... a bunch of cases ...
- -h | --help ) USAGE; return 0 ;;
# ... a bunch of cases ...
esac
shift 1
done
}
```
While you probably weren't doing this, you can also do the same for any logic which splits arguments input like `-abc` which should be read as `-a -b -c`.
If you know how to do this, you know how to get rid of it.
### Write some help docs
Okay this one might take a little bit of time if you haven't done it already (but this is the last recommended step! hang in there and make your stuff better!).
If you _have_ done it already, typically by writing a variable called "USAGE" in your code, maybe consider the _new and improved_ way to write your help strings.
Returning to our original `MAIN()` example, I'll add some options parsing so we should now look something like this:
```sh
#!/bin/zsh
DEPENDENCIES+=(dep-function-a dep-function-b)
use do/awesome/stuff --group my-custom-library
#####################################################################
MAIN() {
local A
local B=false
local ARGS=()
while [[ $# -gt 0 ]]
do
case $1 in
-a | --option-a ) A=$2; shift 1 ;;
-b | --allow-b ) B=true ;;
* ) ARGS+=($1) ;;
esac
shift 1
done
echo "A : $A\nB : $B\nARGS : $ARGS"
}
```
All we have to do is add some usage variables and we're done!
I want to call out a few specific ones:
- `USAGE__options` provides descriptions for CLI flags like `-a` `--some-flag` and `-a <some value>` (reminder, you *don't* need '-h, --help' anymore!)
- `USAGE__args` provides descriptions for non-flag CLI arguments, where order matters (e.g. `cat file-a file-b ... etc`)
- `USAGE__description` provides the human-readable description of what your function does
- `USAGE__usage` you probably don't need to adjust this one, but it will be everything after the `--` in the usage-line. Defaults to include `[...options...]`, but I suppose you might want to write `USAGE__usage+=' [...args...]` if you 1) have args and 2) are really specific about your help strings.
Just add another section to define these values before declaring `MAIN`:
```sh
#!/bin/zsh
DEPENDENCIES+=(dep-function-a dep-function-b)
use do/awesome/stuff --group my-custom-library
#####################################################################
USAGE__options='
-a, --option-a <string> sets the value of the A variable
-b, --allow-b enables the B option
'
# remember there's no specific formatting here, just write it nice
USAGE__args='
N-args All remaining args are inserted into the ARGS variable
'
USAGE__description="
This is my cool example function. It's really neato, but does
very little.
"
#####################################################################
MAIN() {
# ... etc ...
}
```
Now, when we run `scwrypts my sample -- --help`, we get:
```txt
usage: scwrypts my sample -- [...options...]
args:
N-args All remaining args are inserted into the ARGS variable
options:
-a, --option-a <string> sets the value of the A variable
-b, --allow-b enables the B option
-h, --help display this message and exit
This is my cool example function. It's really neato, but does
very little.
```
### All done
No more recommendations at this time.
Someday I'll have an auto-formatter and a language server to help with go-to-definition, but that's still for the future.
Thanks for your time and welcome to v4!

View File

@ -0,0 +1 @@
#!/bin/zsh

10
plugins/ci/README.md Normal file
View File

@ -0,0 +1,10 @@
# Kubernetes `kubectl` Helper Plugin
Leverages a local `redis` application to quickly and easily set an alias `k` for `kubectl --context <some-context> --namespace <some-namespace>`.
Much like scwrypts environments, `k` aliases are *only* shared amongst session with the same `SCWRYPTS_ENV` to prevent accidental cross-contamination.
## Getting Started
Enable the plugin in `~/.config/scwrypts/config.zsh` by adding `SCWRYPTS_PLUGIN_ENABLED__KUBECTL=1`.
Use `k` as your new `kubectl` and checkout `k --help` and `k meta --help`.

View File

@ -0,0 +1,33 @@
#!/bin/zsh
#####################################################################
MAIN() {
cd "$SCWRYPTS_ROOT__scwrypts/"
DEPENDENCIES+=()
for group in ${SCWRYPTS_GROUPS[@]}
do
[[ $group =~ ^ci$ ]] && continue
GROUP_HOME="$(eval 'echo $SCWRYPTS_ROOT__'$group)"
[ $GROUP_HOME ] && [ -d "$GROUP_HOME" ] || continue
STATUS "checking dependencies for $group"
DEPENDENCIES+=($(
for file in $(
{
cd "$GROUP_HOME"
rg -l '^DEPENDENCIES\+=\($'
rg -l '^DEPENDENCIES\+=\([^)]\+\)'
} | grep -v '\.md$' | grep -v 'check-all-dependencies$')
do
sed -z 's/.*DEPENDENCIES+=(\([^)]*\)).*/\1\n/; s/#.*\n//g; s/\s\+/\n/g' "$GROUP_HOME/$file"
done
))
done
DEPENDENCIES=(zsh $(echo $DEPENDENCIES | sed 's/ /\n/g' | sort -u | grep '^[-_a-zA-Z]\+$'))
STATUS "discovered dependencies: ($DEPENDENCIES)"
echo $DEPENDENCIES | sed 's/ /\n/g'
CHECK_ENVIRONMENT && SUCCESS "all dependencies satisfied"
}

View File

@ -0,0 +1,5 @@
SCWRYPTS_GROUPS+=(ci)
export SCWRYPTS_TYPE__ci=zsh
export SCWRYPTS_ROOT__ci="$SCWRYPTS_ROOT__scwrypts/plugins/ci"
export SCWRYPTS_COLOR__ci='\033[0m'

View File

@ -0,0 +1,2 @@
#!/bin/zsh
export SCWRYPTS_KUBECTL_REDIS=

View File

@ -0,0 +1 @@
SCWRYPTS_KUBECTL_REDIS | (currently only 'managed') 'managed' or 'custom' redis configuration

View File

@ -0,0 +1,4 @@
export SCWRYPTS_KUBECTL_REDIS_HOST__managed=127.0.0.1
export SCWRYPTS_KUBECTL_REDIS_PORT__managed=26379
export SCWRYPTS_KUBECTL_REDIS_AUTH__managed=
export SCWRYPTS_KUBECTL_REDIS_KEY_PREFIX__managed=

10
plugins/kubectl/README.md Normal file
View File

@ -0,0 +1,10 @@
# Kubernetes `kubectl` Helper Plugin
Leverages a local `redis` application to quickly and easily set an alias `k` for `kubectl --context <some-context> --namespace <some-namespace>`.
Much like scwrypts environments, `k` aliases are *only* shared amongst session with the same `SCWRYPTS_ENV` to prevent accidental cross-contamination.
## Getting Started
Enable the plugin in `~/.config/scwrypts/config.zsh` by adding `SCWRYPTS_PLUGIN_ENABLED__KUBECTL=1`.
Use `k` as your new `kubectl` and checkout `k --help` and `k meta --help`.

View File

@ -0,0 +1,46 @@
#####################################################################
command -v compdef >/dev/null 2>&1 || return 0
#####################################################################
for CLI in kubectl helm flux
do
eval "_${CLI[1]}() {
local SUBSESSION=0
echo \${words[2]} | grep -q '^[0-9]\\+$' && SUBSESSION=\${words[2]}
local PASSTHROUGH_WORDS=($CLI)
[[ \$CURRENT -gt 2 ]] && echo \${words[2]} | grep -qv '^[0-9]\\+$' && {
local KUBECONTEXT=\$(k \$SUBSESSION meta get context)
local NAMESPACE=\$(k \$SUBSESSION meta get namespace)
[ \$KUBECONTEXT ] \
&& PASSTHROUGH_WORDS+=($([[ $CLI =~ ^helm$ ]] && echo '--kube-context' || echo '--context') \$KUBECONTEXT) \
;
[ \$NAMESPACE ] \
&& PASSTHROUGH_WORDS+=(--namespace \$NAMESPACE) \
;
}
local DELIMIT_COUNT=0
local WORD
for WORD in \${words[@]:1}
do
case \$WORD in
[0-9]* ) continue ;;
-- )
echo \$words | grep -q 'exec' && ((DELIMIT_COUNT+=1))
[[ \$DELIMIT_COUNT -eq 0 ]] && ((DELIMIT_COUNT+=1)) && continue
;;
esac
PASSTHROUGH_WORDS+=(\"\$WORD\")
done
echo \"\$words\" | grep -q '\\s\\+$' && PASSTHROUGH_WORDS+=(' ')
words=\"\$PASSTHROUGH_WORDS\"
_$CLI
}
"
compdef _${CLI[1]} ${CLI[1]}
done

View File

@ -0,0 +1,199 @@
[[ $SCWRYPTS_KUBECTL_DRIVER_READY -eq 1 ]] && return 0
unalias k h >/dev/null 2>&1
k() { _SCWRYPTS_KUBECTL_DRIVER kubectl $@; }
h() { _SCWRYPTS_KUBECTL_DRIVER helm $@; }
f() { _SCWRYPTS_KUBECTL_DRIVER flux $@; }
_SCWRYPTS_KUBECTL_DRIVER() {
[ ! $SCWRYPTS_ENV ] && {
ERROR "must set SCWRYPTS_ENV in order to use '$(echo $CLI | head -c1)'"
return 1
}
which REDIS >/dev/null 2>&1 \
|| eval "$(scwrypts -n --name meta/get-static-redis-definition --type zsh --group kubectl)"
local CLI="$1"; shift 1
local SCWRYPTS_GROUP CUSTOM_COMMANDS=(meta)
for SCWRYPTS_GROUP in ${SCWRYPTS_GROUPS[@]}
do
CUSTOM_COMMANDS+=($(eval echo '$SCWRYPTS_KUBECTL_CUSTOM_COMMANDS__'$SCWRYPTS_GROUP))
done
##########################################
local USAGE="
usage: - [...args...] [...options...] -- [...$CLI options...]
args: -
options: -
--subsession [0-9] use indicated subsession (use for script clarity instead of positional arg)
-h, --help display this help dialogue
-v, --verbose output debugging information
description: -
"
local USAGE__usage=$(echo $CLI | head -c1)
local USAGE__args="$(
{
echo "\\033[0;32m[0-9]\\033[0m^if the first argument is a number 0-9, uses or creates a subsession (default 0)"
echo " ^ "
for C in ${CUSTOM_COMMANDS[@]}
do
echo "\\033[0;32m$C\\033[0m^$(SCWRYPTS_KUBECTL_CUSTOM_COMMAND_DESCRIPTION__$C 2>/dev/null)"
done
} | column -ts '^'
)"
local USAGE__options="
-n, --namespace set the namespace
-k, --context set the context
"
local USAGE__description="
Provides 'k' (kubectl), 'h' (helm), and 'f' (flux) shorthands to the respective
utility. These functions leverage redis and scwrypts environments to
allow quick selection of contexts and namespaces usable across all
active shell instances.
The scwrypts group 'kubectl' has simple selection executables for
kubecontext and namespace, but also provides the library to enable
enriched, use-case-sensitive setup of kubernetes context.
All actions are scoped to the current SCWRYPTS_ENV
currently : \\033[0;33m$SCWRYPTS_ENV\\033[0m
"
##########################################
local USER_ARGS=()
local CUSTOM_COMMAND=0
local VERBOSE=0
local HELP=0
local ERRORS=0
local COMMAND_SWITCH_CASE="@($(echo $CUSTOM_COMMANDS | sed 's/ /|/g'))"
[ ! $SUBSESSION ] && local SUBSESSION=0
[[ $1 =~ ^[0-9]$ ]] && SUBSESSION=$1 && shift 1
while [[ $# -gt 0 ]]
do
case $1 in
meta )
CUSTOM_COMMAND=$1
SCWRYPTS_KUBECTL_CUSTOM_COMMAND_PARSE__$1 ${@:2}
break
;;
-v | --verbose ) VERBOSE=1 ;;
-h | --help ) HELP=1 ;;
--subsession ) SUBSESSION=$2; shift 1 ;;
-n | --namespace )
_SCWRYPTS_KUBECTL_DRIVER kubectl meta set namespace $2
shift 1
;;
-k | --context | --kube-context )
_SCWRYPTS_KUBECTL_DRIVER kubectl meta set context $2
shift 1
;;
-- )
echo $USER_ARGS | grep -q 'exec' && USER_ARGS+=(--)
shift 1
break
;;
* )
[ ! $CUSTOM_COMMAND ] && {
for C in ${CUSTOM_COMMANDS[@]}
do
[[ $1 =~ ^$C$ ]] && {
SCWRYPTS_KUBECTL_CUSTOM_COMMAND_PARSE__$1 ${@:2}
break
}
done
}
USER_ARGS+=($1)
;;
esac
shift 1
done
while [[ $# -gt 0 ]]; do USER_ARGS+=($1); shift 1; done
CHECK_ERRORS --no-fail || return 1
[[ $HELP -eq 1 ]] && { USAGE; return 0; }
#####################################################################
local STRICT=$(_SCWRYPTS_KUBECTL_SETTINGS get strict || echo 1)
case $CUSTOM_COMMAND in
0 )
local CLI_ARGS=()
local CONTEXT=$(k meta get context)
local NAMESPACE=$(k meta get namespace)
[ $CONTEXT ] && [[ $CLI =~ ^helm$ ]] && CLI_ARGS+=(--kube-context $CONTEXT)
[ $CONTEXT ] && [[ $CLI =~ ^kubectl$ ]] && CLI_ARGS+=(--context $CONTEXT)
[ $CONTEXT ] && [[ $CLI =~ ^flux$ ]] && CLI_ARGS+=(--context $CONTEXT)
[[ $STRICT -eq 1 ]] && {
[ $CONTEXT ] || ERROR "missing kubectl 'context'"
[ $NAMESPACE ] || ERROR "missing kubectl 'namespace'"
CHECK_ERRORS --no-fail --no-usage || {
ERROR "with 'strict' settings enabled, context and namespace must be set!"
REMINDER "
these values can be set directly with
$(echo $CLI | head -c1) meta set (namespace|context)
"
return 2
}
}
[ $NAMESPACE ] && CLI_ARGS+=(--namespace $NAMESPACE)
[[ $VERBOSE -eq 1 ]] && {
INFO "
context '$CONTEXT'
namespace '$NAMESPACE'
environment '$SCWRYPTS_ENV'
subsession '$SUBSESSION'
"
STATUS "running $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}"
} || {
[[ $(_SCWRYPTS_KUBECTL_SETTINGS get context) =~ ^show$ ]] && {
INFO "$SCWRYPTS_ENV.$SUBSESSION : $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}"
}
}
$CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}
;;
* ) SCWRYPTS_KUBECTL_CUSTOM_COMMAND__$CUSTOM_COMMAND ${USER_ARGS[@]} ;;
esac
}
_SCWRYPTS_KUBECTL_SETTINGS() {
# (get setting-name) or (set setting-name setting-value)
REDIS h$1 ${SCWRYPTS_ENV}:kubectl:settings ${@:2} | grep .
}
#####################################################################
source ${0:a:h}/kubectl.completion.zsh
source ${0:a:h}/meta.zsh

View File

@ -0,0 +1,147 @@
SCWRYPTS_KUBECTL_CUSTOM_COMMAND_PARSE__meta() {
USAGE__usage+=" meta"
USAGE__args="
- get output value of meta variable
- set interactively configure value of meta variable
- clear clear current subsession variables
(settings args)
- show output context for every command
- hide (default) hide output context for every command
- strict (default) require context *and* namespace to be set
- loose do not require context and namespace to be set
"
USAGE__options=''
USAGE__description=$(SCWRYPTS_KUBECTL_CUSTOM_COMMAND_DESCRIPTION__meta)
META_SUBARGS="
- namespace
- context
"
while [[ $# -gt 0 ]]
do
case $1 in
-h | --help ) HELP=1 ;;
set )
USAGE__usage+=" set"
USAGE__args="set (namespace|context)"
USAGE__description="interactively set a namespace or context for '$SCWRYPTS_ENV'"
case $2 in
namespace | context ) USER_ARGS+=($1 $2 $3); [ $3 ] && shift 1 ;;
-h | --help ) HELP=1 ;;
'' )
: \
&& SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta set context \
&& SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta set namespace \
;
return $?
;;
* ) ERROR "cannot set '$2'" ;;
esac
shift 1
;;
get )
USAGE__usage+=" get"
USAGE__args="get (namespace|context|all)"
USAGE__description="output the current namespace or context for '$SCWRYPTS_ENV'"
case $2 in
namespace | context | all ) USER_ARGS+=($1 $2) ;;
-h | --help ) HELP=1 ;;
* ) ERROR "cannot get '$2'" ;;
esac
shift 1
;;
copy )
USAGE__usage+=" copy"
USAGE__args+="copy [0-9]"
USAGE__description="copy current subsession ($SUBSESSION) to target subsession id"
case $2 in
[0-9] ) USER_ARGS+=($1 $2) ;;
-h | --help ) HELP=1 ;;
* ) ERROR "target session must be a number [0-9]" ;;
esac
shift 1
;;
clear | show | hide | strict | loose ) USER_ARGS+=($1) ;;
* ) ERROR "no meta command '$1'"
esac
shift 1
done
}
SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta() {
case $1 in
get )
[[ $2 =~ ^all$ ]] && {
local CONTEXT=$(REDIS get --prefix current:context | grep . || echo "\\033[1;31mnone set\\033[0m")
local NAMESPACE=$(REDIS get --prefix current:namespace | grep . || echo "\\033[1;31mnone set\\033[0m")
echo "
environment : $SCWRYPTS_ENV
context : $CONTEXT
namespace : $NAMESPACE
CLI settings
command context : $(_SCWRYPTS_KUBECTL_SETTINGS get context)
strict mode : $([[ $STRICT -eq 1 ]] && echo "on" || echo "\\033[1;31moff\\033[0m")
" | sed 's/^ \+//' >&2
return 0
}
REDIS get --prefix current:$2
;;
set )
scwrypts -n --name set-$2 --type zsh --group kubectl -- $3 --subsession $SUBSESSION >/dev/null \
&& SUCCESS "$2 set"
;;
copy )
: \
&& STATUS "copying $1 to $2" \
&& scwrypts -n --name set-context --type zsh --group kubectl -- --subsession $2 $(k meta get context | grep . || echo 'reset') \
&& scwrypts -n --name set-namespace --type zsh --group kubectl -- --subsession $2 $(k meta get namespace | grep . || echo 'reset') \
&& SUCCESS "subsession $1 copied to $2" \
;
;;
clear )
scwrypts -n --name set-context --type zsh --group kubectl -- --subsession $SUBSESSION reset >/dev/null \
&& SUCCESS "subsession $SUBSESSION reset to default"
;;
show )
_SCWRYPTS_KUBECTL_SETTINGS set context show >/dev/null \
&& SUCCESS "now showing full command context"
;;
hide )
_SCWRYPTS_KUBECTL_SETTINGS set context hide >/dev/null \
&& SUCCESS "now hiding command context"
;;
loose )
_SCWRYPTS_KUBECTL_SETTINGS set strict 0 >/dev/null \
&& WARNING "now running in 'loose' mode"
;;
strict )
_SCWRYPTS_KUBECTL_SETTINGS set strict 1 >/dev/null \
&& SUCCESS "now running in 'strict' mode"
;;
esac
}
SCWRYPTS_KUBECTL_CUSTOM_COMMAND_DESCRIPTION__meta() {
[ $CLI ] || CLI='kubectl'
echo "operations for $CLI session variables and other CLI settings"
}

7
plugins/kubectl/get-context Executable file
View File

@ -0,0 +1,7 @@
#!/bin/zsh
use kubectl --group kubectl
#####################################################################
MAIN() {
KUBECTL__GET_CONTEXT
}

7
plugins/kubectl/get-namespace Executable file
View File

@ -0,0 +1,7 @@
#!/bin/zsh
use kubectl --group kubectl
#####################################################################
MAIN() {
KUBECTL__GET_NAMESPACE
}

View File

@ -0,0 +1,11 @@
SCWRYPTS_GROUPS+=(kubectl)
export SCWRYPTS_TYPE__kubectl=zsh
export SCWRYPTS_ROOT__kubectl="$SCWRYPTS_ROOT__scwrypts/plugins/kubectl"
export SCWRYPTS_COLOR__kubectl='\033[0;31m'
SCWRYPTS_STATIC_CONFIG__kubectl+=(
"$SCWRYPTS_ROOT__kubectl/.config/static/redis.zsh"
)
source "$SCWRYPTS_ROOT__kubectl/driver/kubectl.driver.zsh"

View File

@ -0,0 +1,158 @@
#####################################################################
DEPENDENCIES+=(
kubectl
)
REQUIRED_ENV+=()
use redis --group kubectl
#####################################################################
KUBECTL() {
local NAMESPACE=$(REDIS get --prefix "current:namespace")
local CONTEXT=$(KUBECTL__GET_CONTEXT)
local KUBECTL_ARGS=()
[ $NAMESPACE ] && KUBECTL_ARGS+=(--namespace $NAMESPACE)
[ $CONTEXT ] && KUBECTL_ARGS+=(--context $CONTEXT)
kubectl ${KUBECTL_ARGS[@]} $@
}
#####################################################################
KUBECTL__GET_CONTEXT() { REDIS get --prefix "current:context"; }
KUBECTL__SET_CONTEXT() {
local CONTEXT=$1
[ ! $CONTEXT ] && return 1
[[ $CONTEXT =~ reset ]] && {
: \
&& REDIS del --prefix "current:context" \
&& KUBECTL__SET_NAMESPACE reset \
;
return $?
}
: \
&& REDIS set --prefix "current:context" "$CONTEXT" \
&& KUBECTL__SET_NAMESPACE reset \
;
}
KUBECTL__SELECT_CONTEXT() {
KUBECTL__LIST_CONTEXTS | FZF 'select a context'
}
KUBECTL__LIST_CONTEXTS() {
echo reset
local ALL_CONTEXTS=$(KUBECTL config get-contexts -o name | sort)
echo $ALL_CONTEXTS | grep -v '^arn:aws:eks'
[[ $AWS_ACCOUNT ]] && {
echo $ALL_CONTEXTS | grep "^arn:aws:eks:.*:$AWS_ACCOUNT"
true
} || {
echo $ALL_CONTEXTS | grep '^arn:aws:eks'
}
}
#####################################################################
KUBECTL__GET_NAMESPACE() { REDIS get --prefix "current:namespace"; }
KUBECTL__SET_NAMESPACE() {
local NAMESPACE=$1
[ ! $NAMESPACE ] && return 1
[[ $NAMESPACE =~ reset ]] && {
REDIS del --prefix "current:namespace"
return $?
}
REDIS set --prefix "current:namespace" "$NAMESPACE"
}
KUBECTL__SELECT_NAMESPACE() {
KUBECTL__LIST_NAMESPACES | FZF 'select a namespace'
}
KUBECTL__LIST_NAMESPACES() {
echo reset
echo default
KUBECTL get namespaces -o name | sed 's/^namespace\///' | sort
}
#####################################################################
KUBECTL__SERVE() {
[ $CONTEXT ] || local CONTEXT=$(KUBECTL__GET_CONTEXT)
[ $CONTEXT ] || ERROR 'must configure a context in which to serve'
[ $NAMESPACE ] || local NAMESPACE=$(KUBECTL__GET_NAMESPACE)
[ $NAMESPACE ] || ERROR 'must configure a namespace in which to serve'
CHECK_ERRORS --no-fail --no-usage || return 1
[ $SERVICE ] && SERVICE=$(KUBECTL__LIST_SERVICES | jq -c "select (.service == \"$SERVICE\")" || echo $SERVICE)
[ $SERVICE ] || local SERVICE=$(KUBECTL__SELECT_SERVICE)
[ $SERVICE ] || ERROR 'must provide or select a service'
KUBECTL__LIST_SERVICES | grep -q "^$SERVICE$"\
|| ERROR "no service '$SERVICE' in '$CONFIG/$NAMESPACE'"
CHECK_ERRORS --no-fail --no-usage || return 1
##########################################
SERVICE_PASSWORD="$(KUBECTL__GET_SERVICE_PASSWORD)"
KUBECTL__SERVICE_PARSE
INFO "attempting to serve ${NAMESPACE}/${SERVICE_NAME}:${SERVICE_PORT}"
[ $SERVICE_PASSWORD ] && INFO "password : $SERVICE_PASSWORD"
KUBECTL port-forward service/$SERVICE_NAME $SERVICE_PORT
}
KUBECTL__SELECT_SERVICE() {
[ $NAMESPACE ] || local NAMESPACE=$(KUBECTL__GET_NAMESPACE)
[ $NAMESPACE ] || return 1
local SERVICES=$(KUBECTL__LIST_SERVICES)
local SELECTED=$({
echo "namespace service port"
echo $SERVICES \
| jq -r '.service + " " + .port' \
| sed "s/^/$NAMESPACE /" \
;
} \
| column -t \
| FZF 'select a service' --header-lines=1 \
| awk '{print $2;}' \
)
echo $SERVICES | jq -c "select (.service == \"$SELECTED\")"
}
KUBECTL__LIST_SERVICES() {
KUBECTL get service --no-headers\
| awk '{print "{\"service\":\""$1"\",\"ip\":\""$3"\",\"port\":\""$5"\"}"}' \
| jq -c 'select (.ip != "None")' \
;
}
KUBECTL__GET_SERVICE_PASSWORD() {
[ $PASSWORD_SECRET ] && [ $PASSWORD_KEY ] || return 0
KUBECTL get secret $PASSWORD_SECRET -o jsonpath="{.data.$PASSWORD_KEY}" \
| base64 --decode
}
KUBECTL__SERVICE_PARSE() {
SERVICE_NAME=$(echo $SERVICE | jq -r .service)
SERVICE_PORT=$(echo $SERVICE | jq -r .port | sed 's|/.*$||')
}

View File

@ -0,0 +1,97 @@
#####################################################################
DEPENDENCIES+=(
redis-cli
docker
)
# TODO; allow custom redis configuration
export SCWRYPTS_KUBECTL_REDIS=managed
REQUIRED_ENV+=(
SCWRYPTS_KUBECTL_REDIS
)
#####################################################################
REDIS() {
[ ! $USAGE ] && local USAGE="
usage: [...options...]
options:
--subsession [0-9] use a particular subsession
-p, --prefix apply dynamic prefix to the next command line argument
--get-prefix output key prefix for current session+subsession
--get-static-definition output the static ZSH function definition for REDIS
additional arguments and options are passed through to 'redis-cli'
"
local REDIS_ARGS=() USER_ARGS=()
[ $SUBSESSION ] || local SUBSESSION=0
local REDIS_PREFIX=$(eval echo '$SCWRYPTS_KUBECTL_REDIS_KEY_PREFIX__'$SCWRYPTS_KUBECTL_REDIS)
[ $REDIS_PREFIX ] && REDIS_PREFIX+=':'
while [[ $# -gt 0 ]]
do
case $1 in
-p | --prefix ) USER_ARGS+=("${REDIS_PREFIX}${SCWRYPTS_ENV}:${SUBSESSION}:$2"); shift 1 ;;
--subsession ) SUBSESSION=$2; shift 1 ;;
--get-prefix ) echo $REDIS_PREFIX; return 0 ;;
--get-static-definition ) ECHO_STATIC_DEFINITION=1 ;;
* ) USER_ARGS+=($1) ;;
esac
shift 1
done
local REDIS_HOST=$(eval echo '$SCWRYPTS_KUBECTL_REDIS_HOST__'$SCWRYPTS_KUBECTL_REDIS)
local REDIS_PORT=$(eval echo '$SCWRYPTS_KUBECTL_REDIS_PORT__'$SCWRYPTS_KUBECTL_REDIS)
local REDIS_AUTH=$(eval echo '$SCWRYPTS_KUBECTL_REDIS_AUTH__'$SCWRYPTS_KUBECTL_REDIS)
[ $REDIS_HOST ] && REDIS_ARGS+=(-h $REDIS_HOST)
[ $REDIS_PORT ] && REDIS_ARGS+=(-p $REDIS_PORT)
[ $REDIS_AUTH ] && REDIS_ARGS+=(-a $REDIS_AUTH)
REDIS_ARGS+=(--raw)
[[ $ECHO_STATIC_DEFINITION -eq 1 ]] && {
echo "REDIS() {\
local USER_ARGS=(); \
[ ! \$SUBSESSION ] && local SUBSESSION=0 ;\
while [[ \$# -gt 0 ]]; \
do \
case \$1 in
-p | --prefix ) USER_ARGS+=(\"${REDIS_PREFIX}\${SCWRYPTS_ENV}:\${SUBSESSION}:\$2\"); shift 1 ;; \
* ) USER_ARGS+=(\$1) ;; \
esac; \
shift 1; \
done; \
redis-cli ${REDIS_ARGS[@]} \${USER_ARGS[@]}; \
}" | sed 's/\s\+/ /g'
return 0
}
redis-cli ${REDIS_ARGS[@]} ${USER_ARGS[@]}
}
REDIS ping | grep -qi pong || {
RPID=$(docker ps -a | grep scwrypts-kubectl-redis | awk '{print $1;}')
[ $RPID ] && STATUS 'refreshing redis instance' && docker rm -f $RPID
unset RPID
docker run \
--detach \
--name scwrypts-kubectl-redis \
--publish $SCWRYPTS_KUBECTL_REDIS_PORT__managed:6379 \
redis >/dev/null 2>&1
STATUS 'awaiting redis connection'
until REDIS ping 2>/dev/null | grep -qi pong; do sleep 0.5; done
}

View File

@ -0,0 +1,7 @@
#!/bin/zsh
use redis --group kubectl
#####################################################################
MAIN() {
echo $(REDIS --get-static-definition)
}

49
plugins/kubectl/serve Executable file
View File

@ -0,0 +1,49 @@
#!/bin/zsh
use kubectl --group kubectl
#####################################################################
MAIN() {
local USAGE="
usage: [service] [...options...]
args:
service (optional) name of the service to forward locally
options:
--context override context
--namespace override namespace
--subsession REDIS subsession (default 0)
to show a required password on screen, use both:
--password-secret Secret resource
--password-key key within Secret's 'data'
-h, --help show this dialogue and exit
"
local CONTEXT NAMESPACE SERVICE
local SUBSESSION=0
while [[ $# -gt 0 ]]
do
case $1 in
--context ) CONTEXT=$2; shift 1 ;;
--namespace ) NAMESPACE=$2; shift 1 ;;
--subsession ) SUBSESSION=$2; shift 1 ;;
--password-secret ) PASSWORD_SECRET=$2; shift 1 ;;
--password-key ) PASSWORD_KEY=$2; shift 1 ;;
-h | --help ) USAGE; return 0 ;;
* )
[ $SERVICE ] && ERROR "unexpected argument '$2'"
SERVICE=$1
;;
esac
shift 1
done
CHECK_ERRORS
KUBECTL__SERVE
}

41
plugins/kubectl/set-context Executable file
View File

@ -0,0 +1,41 @@
#!/bin/zsh
use kubectl --group kubectl
#####################################################################
MAIN() {
local USAGE="
usage: [context] [...options...]
args:
context (optional) the full name of the kubeconfig context to set
options:
--subsession REDIS subsession (default 0)
-h, --help show this dialogue and exit
"
local CONTEXT
local SUBSESSION=0
while [[ $# -gt 0 ]]
do
case $1 in
--subsession ) SUBSESSION=$2; shift 1 ;;
-h | --help ) USAGE; return 0 ;;
* )
[ $CONTEXT ] && ERROR "unexpected argument '$2'"
CONTEXT=$1
;;
esac
shift 1
done
[ $CONTEXT ] || CONTEXT=$(KUBECTL__SELECT_CONTEXT)
[ $CONTEXT ] || ERROR 'must provide or select a valid kube context'
CHECK_ERRORS
KUBECTL__SET_CONTEXT $CONTEXT
}

41
plugins/kubectl/set-namespace Executable file
View File

@ -0,0 +1,41 @@
#!/bin/zsh
use kubectl --group kubectl
#####################################################################
MAIN() {
local USAGE="
usage: [namespace] [...options...]
args:
namespace (optional) the full name of the namespace context to set
options:
--subsession REDIS subsession (default 0)
-h, --help show this dialogue and exit
"
local NAMESPACE
local SUBSESSION=0
while [[ $# -gt 0 ]]
do
case $1 in
--subsession ) SUBSESSION=$2; shift 1 ;;
-h | --help ) USAGE; return 0 ;;
* )
[ $NAMESPACE ] && ERROR "unexpected argument '$2'"
NAMESPACE=$1
;;
esac
shift 1
done
[ $NAMESPACE ] || NAMESPACE=$(KUBECTL__SELECT_NAMESPACE)
[ $NAMESPACE ] || ERROR 'must provide or select a valid namespace'
CHECK_ERRORS
KUBECTL__SET_NAMESPACE $NAMESPACE
}

387
run
View File

@ -1,150 +1,189 @@
#!/bin/zsh
export EXECUTION_DIR=$(pwd)
source "${0:a:h}/zsh/lib/import.driver.zsh" || exit 42
#####################################################################
__RUN() {
() {
cd "$SCWRYPTS_ROOT__scwrypts"
GIT_SCWRYPTS() { git -C "$SCWRYPTS_ROOT__scwrypts" $@; }
local ERRORS=0
local USAGE='
usage: scwrypts [OPTIONS ...] SCRIPT -- [SCRIPT OPTIONS ...]
usage: scwrypts [...options...] [...patterns...] -- [...script options...]
OPTIONS
-g, --group <group-name> only use scripts from the indicated group
-t, --type <type-name> only use scripts of the indicated type
-m, --name <scwrypt-name> only run the script if there is an exact match
(requires type and group)
options:
selection
-m, --name <scwrypt-name> only run the script if there is an exact match
(requires type and group)
-g, --group <group-name> only use scripts from the indicated group
-t, --type <type-name> only use scripts of the indicated type
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
-n, --no-log skip logging and run in quiet mode
runtime
-y, --yes auto-accept all [yn] prompts through current scwrypt
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
-n shorthand for "--verbosity 0"
-v, --verbosity [0-4] set scwrypts log level to one of the following:
0 : only command output and critical failures; skips logfile
1 : add success / failure messages
2 : (default) include status update messages
3 : include warning messages
4 : include debug messages
--update update scwrypts library to latest version
alternate commands
-h, --help display this message and exit
-l, --list print out command list and exit
--list-envs print out environment list and exit
--update update scwrypts library to latest version
--version print out scwrypts version and exit
-v, --version print out scwrypts version and exit
-l, --list print out command list and exit
-h, --help display this message and exit
patterns:
- a list of glob patterns to loose-match a scwrypt by name
script options:
- everything after "--" is forwarded to the scwrypt you run
("-- --help" will provide more information)
'
cd "$SCWRYPTS_ROOT"
#####################################################################
### cli argument parsing and global configuration ###################
#####################################################################
local ENV_NAME="$SCWRYPTS_ENV"
local SEARCH_PATTERNS=()
local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME
local ERROR=0
[ ! $SCWRYPTS_LOG_LEVEL ] && {
local SCWRYPTS_LOG_LEVEL
[ $CI ] && SCWRYPTS_LOG_LEVEL=3 || SCWRYPTS_LOG_LEVEL=2
}
while [[ $# -gt 0 ]]
do
case $1 in
-t | --type )
[ ! $2 ] && ERROR "missing value for argument $1" && break
SEARCH_TYPE=$2
shift 2
;;
-g | --group )
[ ! $2 ] && ERROR "missing value for argument $1" && break
SEARCH_GROUP=$2
shift 2
;;
-m | --name )
[ ! $2 ] && ERROR "missing value for argument $1" && break
SEARCH_NAME=$2
shift 2
;;
-[a-z][a-z]* )
VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
set -- $(echo " $VARSPLIT ") ${@:2}
;;
### alternate commands ###################
-h | --help )
USAGE
return 0
;;
-n | --no-log )
[ ! $SUBSCWRYPT ] && SUBSCWRYPT=0
shift 1
;;
-e | --env )
[ ! $2 ] && ERROR "missing value for argument $1" && break
[ ! $SUBSCWRYPTS ] \
&& [ $ENV_NAME ] \
&& WARNING 'overwriting session environment' \
;
ENV_NAME="$2"
STATUS "using CLI environment '$ENV_NAME'"
shift 2
;;
-l | --list )
SCWRYPTS__GET_AVAILABLE_SCWRYPTS
return 0
;;
-v | --version )
echo scwrypts $(cd "$SCWRYPTS__ROOT__scwrypts"; git describe --tags)
--list-envs )
SCWRYPTS__GET_ENV_NAMES
return 0
;;
--version )
echo scwrypts $(GIT_SCWRYPTS describe --tags)
return 0
;;
--update )
cd "$SCWRYPTS__ROOT__scwrypts"
git fetch --quiet origin main
GIT_SCWRYPTS fetch --quiet origin main
GIT_SCWRYPTS fetch --quiet origin main --tags
local SYNC_STATUS=$?
git diff --exit-code origin/main -- . >&2
GIT_SCWRYPTS diff --exit-code origin/main -- . >/dev/null 2>&1
local DIFF_STATUS=$?
[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
SUCCESS 'already up-to-date with origin/main'
} || {
git rebase --autostash origin/main \
GIT_SCWRYPTS rebase --autostash origin/main \
&& SUCCESS 'up-to-date with origin/main' \
&& GIT_SCWRYPTS log -n1 \
|| {
git rebase --abort
GIT_SCWRYPTS rebase --abort
ERROR 'unable to update scwrypts; please try manual upgrade'
REMINDER "installation in '$(pwd)'"
}
}
return 0
;;
-- )
shift 1
break # pass arguments after '--' to the scwrypt
;;
--* )
ERROR "unrecognized argument '$1'"
### scwrypts filters #####################
-m | --name )
[ $2 ] || { ERROR "missing value for argument $1"; break; }
SEARCH_NAME=$2
shift 1
;;
* )
SEARCH_PATTERNS+=($1)
-g | --group )
[ $2 ] || { ERROR "missing value for argument $1"; break; }
SEARCH_GROUP=$2
shift 1
;;
-t | --type )
[ $2 ] || { ERROR "missing value for argument $1"; break; }
SEARCH_TYPE=$2
shift 1
;;
### runtime settings #####################
-y | --yes ) export __SCWRYPTS_YES=1 ;;
-n | --no-log )
SCWRYPTS_LOG_LEVEL=0
[[ $1 =~ ^--no-log$ ]] && WARNING 'the --no-log flag is deprecated and will be removed in scwrypts v4.2'
;;
-v | --verbosity )
[[ $2 =~ ^[0-4]$ ]] || ERROR "invalid setting for verbosity '$2'"
SCWRYPTS_LOG_LEVEL=$2
shift 1
;;
-e | --env )
[ $2 ] || { ERROR "missing value for argument $1"; break; }
[ $ENV_NAME ] && DEBUG 'overwriting session environment'
ENV_NAME="$2"
STATUS "using CLI environment '$ENV_NAME'"
shift 1
;;
##########################################
-- ) shift 1; break ;; # pass arguments after '--' to the scwrypt
--* ) ERROR "unrecognized argument '$1'" ;;
* ) SEARCH_PATTERNS+=($1) ;;
esac
shift 1
done
[ $SEARCH_NAME ] && {
[ ! $SEARCH_TYPE ] && ERROR '--name requires --type argument'
[ ! $SEARCH_GROUP ] && ERROR '--name requires --group argument'
[ $SEARCH_TYPE ] || ERROR '--name requires --type argument'
[ $SEARCH_GROUP ] || ERROR '--name requires --group argument'
}
CHECK_ERRORS
##########################################
#####################################################################
### scwrypts selection / filtering ##################################
#####################################################################
local SCWRYPTS_AVAILABLE
local POTENTIAL_ERROR="no such scwrypt exists:"
SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS)
[ $SEARCH_NAME ] && {
POTENTIAL_ERROR+="\n NAME : '$SEARCH_NAME'"
POTENTIAL_ERROR+="\n TYPE : '$SEARCH_TYPE'"
POTENTIAL_ERROR+="\n GROUP : '$SEARCH_GROUP'"
SCWRYPTS_AVAILABLE=$({
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | sed -e 's/\x1b\[[0-9;]*m//g' | grep "^$SEARCH_NAME *$SEARCH_TYPE *$SEARCH_GROUP\$"
})
}
##########################################
[ ! $SEARCH_NAME ] && {
[ $SEARCH_NAME ] && SCWRYPTS_AVAILABLE=$({
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | sed -e 's/\x1b\[[0-9;]*m//g' | grep "^$SEARCH_NAME *$SEARCH_TYPE *$SEARCH_GROUP\$"
}) || {
[ $SEARCH_TYPE ] && {
POTENTIAL_ERROR+="\n TYPE : '$SEARCH_TYPE'"
SCWRYPTS_AVAILABLE=$(\
{
echo $SCWRYPTS_AVAILABLE | head -n1
@ -157,7 +196,6 @@ __RUN() {
}
[ $SEARCH_GROUP ] && {
POTENTIAL_ERROR+="\n GROUP : '$SEARCH_GROUP'"
SCWRYPTS_AVAILABLE=$(
{
echo $SCWRYPTS_AVAILABLE | head -n1
@ -184,33 +222,49 @@ __RUN() {
}
}
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -lt 2 ]] && ERROR "$POTENTIAL_ERROR"
CHECK_ERRORS
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -lt 2 ]] && {
FAIL 1 "$(echo "
no such scwrypt exists
NAME : '$SEARCH_NAME'
TYPE : '$SEARCH_TYPE'
GROUP : '$SEARCH_GROUP'
PATTERNS : '$SEARCH_PATTERNS'
" | sed "1d; \$d; /''$/d")"
}
##########################################
local NAME="$SEARCH_NAME"
local TYPE="$SEARCH_TYPE"
local GROUP="$SEARCH_GROUP"
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -eq 2 ]] \
&& SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | tail -n1) \
|| SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | FZF "select a script to run" --header-lines 1)
|| SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | FZF "select a script to run" --header-lines 1) \
;
[ $SCWRYPT_SELECTION ] || exit 2
##########################################
local NAME TYPE GROUP
SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
export SCWRYPT_NAME=$NAME
export SCWRYPT_TYPE=$TYPE
export SCWRYPT_GROUP=$GROUP
##########################################
#####################################################################
### environment variables and configuration validation ##############
#####################################################################
local ENV_REQUIRED=$(__CHECK_ENV_REQUIRED && echo 1 || echo 0)
local ENV_REQUIRED=true \
&& [ ! $CI ] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/environment ]] \
|| ENV_REQUIRED=false
[[ $ENV_REQUIRED -eq 1 ]] && {
local REQUIRED_ENVIRONMENT_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$SCWRYPT_GROUP)
[[ $ENV_REQUIRED =~ true ]] && {
[ ! $ENV_NAME ] && ENV_NAME=$(SCWRYPTS__SELECT_ENV)
for GROUP in ${SCWRYPTS_GROUPS[@]}
do
local ENV_FILE=$(SCWRYPTS__GET_ENV_FILE "$ENV_NAME" "$GROUP")
@ -225,100 +279,97 @@ __RUN() {
export ENV_NAME
}
##########################################
[ $REQUIRED_ENVIRONMENT_REGEX ] && {
[[ $ENV_NAME =~ $REQUIRED_ENVIRONMENT_REGEX ]] \
|| FAIL 5 "group '$SCWRYPT_GROUP' requires current environment name to match '$REQUIRED_ENVIRONMENT_REGEX' (currently $ENV_NAME)"
}
##########################################
[ ! $SUBSCWRYPT ] \
&& [[ $ENV_NAME =~ prod ]] \
&& { __VALIDATE_UPSTREAM_TIMELINE || ABORT; }
[ ! $SUBSCWRYPT ] && [[ $ENV_NAME =~ prod ]] && {
STATUS "on '$ENV_NAME'; checking diff against origin/main"
GIT_SCWRYPTS fetch --quiet origin main
local SYNC_STATUS=$?
GIT_SCWRYPTS diff --exit-code origin/main -- . >&2
local DIFF_STATUS=$?
[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
SUCCESS 'up-to-date with origin/main'
} || {
SCWRYPTS_LOG_LEVEL=3 WARNING "you are trying to run in ${__BRIGHT_RED}production${__YELLOW} but $([[ $SYNC_STATUS -ne 0 ]] && echo 'I am unable to verify your scwrypts version')$([[ $DIFF_STATUS -ne 0 ]] && echo 'your scwrypts is out-of-date (diff listed above)')"
yN 'continue?' || {
REMINDER "you can use 'scwrypts --update' to quickly update scwrypts to latest"
ABORT
}
}
}
##########################################
local RUN_STRING=$(SCWRYPTS__GET_RUNSTRING $SCWRYPT_NAME $SCWRYPT_TYPE $SCWRYPT_GROUP)
[ ! $RUN_STRING ] && exit 3
[ "$RUN_STRING" ] || return 42
##########################################
#####################################################################
### logging and pretty header/footer setup ##########################
#####################################################################
local LOGFILE=$(__GET_LOGFILE)
local LOGFILE \
&& [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] \
&& [ ! $SUBSCWRYPT ] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
&& [[ ! $SCWRYPT_NAME =~ interactive ]] \
&& LOGFILE="$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log" \
|| LOGFILE='/dev/null' \
;
local HEADER=$(
[ $SUBSCWRYPT ] && return 0
echo '====================================================================='
echo "script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME"
echo "run at : $(date)"
echo "config : $ENV_NAME"
[ ! $LOGFILE ] && echo '\033[1;33m------------------------------------------\033[0m'
)
local HEADER FOOTER
[ ! $LOGFILE ] && {
[ $HEADER ] && echo $HEADER
[ $SUBSCWRYPT ] && {
eval "$RUN_STRING $(printf "%q " "$@")"
exit $?
} || {
eval "$RUN_STRING $(printf "%q " "$@")" </dev/tty >/dev/tty 2>&1
exit $?
}
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && {
HEADER=$(
echo "
=====================================================================
script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME
run at : $(date)
config : $ENV_NAME
verbosity : $SCWRYPTS_LOG_LEVEL
\\033[1;33m--- SCWRYPT BEGIN ---------------------------------------------------\\033[0m
" | sed 's/^\s\+//; 1d'
)
FOOTER="\\033[1;33m--- SCWRYPT END ---------------------------------------------------\\033[0m"
}
[ $SUBSCWRYPT ] && {
HEADER="\\033[0;33m--- ($SUBSCWRYPT) BEGIN $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
FOOTER="\\033[0;33m--- ($SUBSCWRYPT) END $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
}
#####################################################################
### run the scwrypt #################################################
#####################################################################
set -o pipefail
{
[ $HEADER ] && echo $HEADER
echo '\033[1;33m--- BEGIN OUTPUT -------------------------\033[0m'
eval "$RUN_STRING $(printf "%q " "$@")"
EXIT_CODE=$?
echo '\033[1;33m--- END OUTPUT ---------------------------\033[0m'
[[ $LOGFILE =~ ^/dev/null$ ]] && {
eval "$RUN_STRING $(printf "%q " "$@")" </dev/tty >/dev/tty 2>&1
EXIT_CODE=$?
} || {
(eval "$RUN_STRING $(printf "%q " "$@")")
EXIT_CODE=$?
}
[ $FOOTER ] && echo $FOOTER
[[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m'
echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && [ ! $SUBSCWRYPT ] \
&& echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
return $EXIT_CODE
} 2>&1 | tee --append "$LOGFILE"
exit $(\
sed -n 's/^terminated with.*code \([0-9]*\).*$/\1/p' $LOGFILE \
| tail -n1
)
}
#####################################################################
__CHECK_ENV_REQUIRED() {
[ $CI ] && return 1
echo $SCWRYPT_NAME | grep -q 'scwrypts/logs/' && return 1
echo $SCWRYPT_NAME | grep -q 'scwrypts/environment/' && 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() {
[ $SUBSCWRYPT ] \
|| [[ $SCWRYPT_NAME =~ scwrypts/logs ]] \
|| [[ $SCWRYPT_NAME =~ interactive ]] \
&& return 0
echo "$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log"
}
#####################################################################
__RUN $@
} $@

View File

@ -6,7 +6,7 @@ SCWRYPTS__ZSH_PLUGIN() {
local NAME
local TYPE
local GROUP
zle clear-command-line
LBUFFER= RBUFFER=
[ ! $SCWRYPT_SELECTION ] && { zle accept-line; return 0; }
SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
@ -21,6 +21,33 @@ SCWRYPTS__ZSH_PLUGIN() {
zle -N scwrypts SCWRYPTS__ZSH_PLUGIN
bindkey $SCWRYPTS_SHORTCUT scwrypts
#####################################################################
SCWRYPTS__ZSH_BUILDER_PLUGIN() {
local SCWRYPT_SELECTION=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS | FZF 'select a script' --header-lines 1)
local NAME
local TYPE
local GROUP
LBUFFER= RBUFFER=
[ ! $SCWRYPT_SELECTION ] && { zle accept-line; return 0; }
SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
scwrypts --name $NAME --group $GROUP --type $TYPE -- --help >&2 || {
zle accept-line
return 0
}
echo
zle reset-prompt
which scwrypts >/dev/null 2>&1\
&& LBUFFER="scwrypts" || LBUFFER="$SCWRYPTS_ROOT/scwrypts"
LBUFFER+=" --name $NAME --group $GROUP --type $TYPE -- "
}
zle -N scwrypts-builder SCWRYPTS__ZSH_BUILDER_PLUGIN
bindkey $SCWRYPTS_BUILDER_SHORTCUT scwrypts-builder
#####################################################################
SCWRYPTS__ZSH_PLUGIN_ENV() {
local RESET='reset'

View File

@ -1,10 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use cloud/aws/ecr
CHECK_ENVIRONMENT
#####################################################################
ECR_LOGIN $@
MAIN() {
ECR_LOGIN $@
}

View File

@ -3,11 +3,9 @@ DEPENDENCIES+=(jq)
REQUIRED_ENV+=(AWS__EFS__LOCAL_MOUNT_POINT)
use cloud/aws/cli
CHECK_ENVIRONMENT
#####################################################################
EFS_CONNECT() {
MAIN() {
GETSUDO || exit 1
[ ! -d $AWS__EFS__LOCAL_MOUNT_POINT ] && {
sudo mkdir $AWS__EFS__LOCAL_MOUNT_POINT \
@ -64,6 +62,3 @@ EFS_CONNECT() {
FAIL 2 "unable to mount '$FS_ID'"
}
}
#####################################################################
EFS_CONNECT $@

View File

@ -3,11 +3,9 @@ DEPENDENCIES+=(jq)
REQUIRED_ENV+=(AWS__EFS__LOCAL_MOUNT_POINT)
use cloud/aws/cli
CHECK_ENVIRONMENT
#####################################################################
EFS_DISCONNECT() {
MAIN() {
[ ! -d "$AWS__EFS__LOCAL_MOUNT_POINT" ] && {
STATUS 'no efs currently mounted'
exit 0
@ -32,6 +30,3 @@ EFS_DISCONNECT() {
&& SUCCESS "done" \
|| FAIL 2 "failed to unmount '$EFS'"
}
#####################################################################
EFS_DISCONNECT $@

View File

@ -1,10 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use cloud/aws/eks
CHECK_ENVIRONMENT
#####################################################################
EKS_CLUSTER_LOGIN $@
MAIN() {
EKS__CLUSTER_LOGIN $@
}

View File

@ -1,25 +1,11 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use cloud/aws/rds
use db/postgres
CHECK_ENVIRONMENT
#####################################################################
CREATE_BACKUP() {
MAIN() {
local DB_HOST DB_PORT DB_NAME DB_USER DB_PASS
RDS__GET_DATABASE_CREDENTIALS $@ || return 1
PG_DUMP \
--host $DB_HOST \
--port $DB_PORT \
--name $DB_NAME \
--user $DB_USER \
--pass $DB_PASS \
;
PG_DUMP
}
#####################################################################
CREATE_BACKUP $@

View File

@ -1,26 +1,11 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use cloud/aws/rds
use db/postgres
CHECK_ENVIRONMENT
#####################################################################
RDS_INTERACTIVE_LOGIN() {
MAIN() {
local DB_HOST DB_PORT DB_NAME DB_USER DB_PASS
RDS__GET_DATABASE_CREDENTIALS $@ || return 1
POSTGRES__LOGIN_INTERACTIVE \
--host $DB_HOST \
--port $DB_PORT \
--name $DB_NAME \
--user $DB_USER \
--pass $DB_PASS \
;
POSTGRES__LOGIN_INTERACTIVE
}
#####################################################################
RDS_INTERACTIVE_LOGIN $@

View File

@ -1,26 +1,11 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use cloud/aws/rds
use db/postgres
CHECK_ENVIRONMENT
#####################################################################
LOAD_BACKUP() {
MAIN() {
local DB_HOST DB_PORT DB_NAME DB_USER DB_PASS
RDS__GET_DATABASE_CREDENTIALS $@ || return 1
PG_RESTORE \
--host $DB_HOST \
--port $DB_PORT \
--name $DB_NAME \
--user $DB_USER \
--pass $DB_PASS \
;
PG_RESTORE
}
#####################################################################
LOAD_BACKUP $@

View File

@ -1,11 +1,9 @@
#!/bin/zsh
DEPENDENCIES+=(cli53)
REQUIRED_ENV+=(AWS_PROFILE)
CHECK_ENVIRONMENT
#####################################################################
ROUTE53_BACKUP() {
MAIN() {
local BACKUP_PATH="$SCWRYPTS_OUTPUT_PATH/$ENV_NAME/aws-dns-backup/$(date '+%Y-%m-%d')"
mkdir -p $BACKUP_PATH >/dev/null 2>&1
@ -25,12 +23,11 @@ ROUTE53_BACKUP() {
for P in ${JOBS[@]}; do wait $P >/dev/null 2>&1; done
}
#####################################################################
ROUTE53_GET_DOMAINS() {
cli53 list --profile $AWS_PROFILE \
| awk '{print $2;}' \
| sed '1d; s/\.$//'\
;
}
#####################################################################
ROUTE53_BACKUP

View File

@ -1,10 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use cloud/media-sync
CHECK_ENVIRONMENT
#####################################################################
MEDIA_SYNC__PULL $@
MAIN() {
MEDIA_SYNC__PULL $@
}

View File

@ -1,10 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use cloud/media-sync
CHECK_ENVIRONMENT
#####################################################################
MEDIA_SYNC__PUSH $@
MAIN() {
MEDIA_SYNC__PUSH $@
}

View File

@ -1,9 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use db/postgres
CHECK_ENVIRONMENT
#####################################################################
POSTGRES__LOGIN_INTERACTIVE $@
MAIN() {
POSTGRES__LOGIN_INTERACTIVE $@
}

View File

@ -1,9 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use db/postgres
CHECK_ENVIRONMENT
#####################################################################
PG_DUMP $@
MAIN() {
PG_DUMP $@
}

View File

@ -1,9 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use db/postgres
CHECK_ENVIRONMENT
#####################################################################
PG_RESTORE $@
MAIN() {
PG_RESTORE $@
}

View File

@ -1,13 +1,9 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use db/postgres
CHECK_ENVIRONMENT
#####################################################################
RUN_SQL_POSTGRES() {
MAIN() {
WARNING " \nthis function is in a beta state\n "
local _PASS _ARGS=()
POSTGRES__SET_LOGIN_ARGS $@
@ -43,9 +39,3 @@ RUN_SQL_POSTGRES() {
&& 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 $@

View File

@ -1,11 +1,8 @@
#!/bin/zsh
DEPENDENCIES+=(docker)
REQUIRED_ENV+=()
CHECK_ENVIRONMENT
#####################################################################
DOCKER_CLEAN() {
MAIN() {
WARNING 'this will prune all docker resources from the current machine'
WARNING 'pruned resources are PERMANENTLY DELETED'
yN 'continue?' || return 1
@ -14,6 +11,3 @@ DOCKER_CLEAN() {
SUCCESS "IMAGE : $(docker image prune -f 2>/dev/null | tail -n 1)"
SUCCESS "VOLUME : $(docker volume prune -f 2>/dev/null | tail -n 1)"
}
#####################################################################
DOCKER_CLEAN $@

View File

@ -1,8 +1,6 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
CHECK_ENVIRONMENT
#####################################################################
SUCCESS 'hello world!'
MAIN() {
SUCCESS 'Hello, World!'
}

9
zsh/helm/get-template Executable file
View File

@ -0,0 +1,9 @@
#!/bin/zsh
use helm
use scwrypts
#####################################################################
MAIN() {
unset USAGE
HELM__TEMPLATE__GET $@
}

9
zsh/helm/update-dependencies Executable file
View File

@ -0,0 +1,9 @@
#!/bin/zsh
use helm
use scwrypts
#####################################################################
MAIN() {
unset USAGE
HELM__DEPENDENCY__UPDATE $@
}

View File

@ -4,18 +4,20 @@ DEPENDENCIES+=(
aws
)
REQUIRED_ENV+=(
AWS_ACCOUNT
AWS_PROFILE
AWS_REGION
)
REQUIRED_ENV+=()
#####################################################################
AWS() {
aws \
--profile $AWS_PROFILE \
--region $AWS_REGION \
--output json \
$@
local ARGS=()
ARGS+=(--output json)
[ ! $CI ] && {
REQUIRED_ENV=(AWS_REGION AWS_ACCOUNT AWS_PROFILE) CHECK_ENVIRONMENT || return 1
ARGS+=(--profile $AWS_PROFILE)
ARGS+=(--region $AWS_REGION)
}
aws ${ARGS[@]} $@
}

View File

@ -4,16 +4,15 @@ DEPENDENCIES+=(
docker
)
REQUIRED_ENV+=(
AWS_ACCOUNT
AWS_REGION
)
REQUIRED_ENV+=()
use cloud/aws/cli
#####################################################################
ECR_LOGIN() {
REQUIRED_ENV=(AWS_REGION AWS_ACCOUNT) CHECK_ENVIRONMENT || return 1
STATUS "performing AWS ECR docker login"
AWS ecr get-login-password \
| docker login \

View File

@ -1,19 +1,44 @@
#####################################################################
DEPENDENCIES+=(
kubectl
)
REQUIRED_ENV+=(
AWS_ACCOUNT
AWS_REGION
)
DEPENDENCIES+=(kubectl yq)
REQUIRED_ENV+=()
use cloud/aws/cli
#####################################################################
EKS_CLUSTER_LOGIN() {
EKS__KUBECTL() { EKS kubectl $@; }
EKS__FLUX() { EKS flux $@; }
#####################################################################
EKS() {
local USAGE="
usage: cli [...kubectl args...]
args:
cli a kubectl-style CLI (e.g. kubectl, helm, flux, etc)
Allows access to kubernetes CLI commands by configuring environment
to point to a specific cluster.
"
REQUIRED_ENV=(AWS_REGION AWS_ACCOUNT CLUSTER_NAME) DEPENDENCIES=(kubectl $1) CHECK_ENVIRONMENT || return 1
local CONTEXT="arn:aws:eks:${AWS_REGION}:${AWS_ACCOUNT}:cluster/${CLUSTER_NAME}"
local CONTEXT_ARGS=()
case $1 in
helm ) CONTEXT_ARGS+=(--kube-context $CONTEXT) ;;
* ) CONTEXT_ARGS+=(--context $CONTEXT) ;;
esac
$1 ${CONTEXT_ARGS[@]} ${@:2}
}
#####################################################################
EKS__CLUSTER_LOGIN() {
local USAGE="
usage: [...options...]
@ -25,6 +50,7 @@ EKS_CLUSTER_LOGIN() {
cluster in EKS. Also creates the kubeconfig entry if it does not
already exist.
"
REQUIRED_ENV=(AWS_ACCOUNT AWS_REGION) CHECK_ENVIRONMENT || return 1
local CLUSTER_NAME

View File

@ -0,0 +1,116 @@
#####################################################################
DEPENDENCIES+=(eksctl)
REQUIRED_ENV+=()
use cloud/aws/eks
#####################################################################
EKSCTL() {
REQUIRED_ENV=(AWS_PROFILE AWS_REGION) CHECK_ENVIRONMENT || return 1
AWS_PROFILE=$AWS_PROFILE AWS_REGION=$AWS_REGION \
eksctl $@
}
EKSCTL__CREATE_IAMSERVICEACCOUNT() {
local USAGE="
usage: serviceaccount-name namespace [...options...] -- [...'eksctl create iamserviceaccount' args...]
options:
--serviceaccount (required) target k8s:ServiceAccount
--namespace (required) target k8s:Namespace
--role-name (required) name of the IAM role to assign
--force don't check for existing serviceaccount and override any existing configuration
eksctl create iamserviceaccount args:
$(eksctl create iamserviceaccount --help 2>&1 | grep -v -- '--name' | grep -v -- '--namespace' | grep -v -- '--role-name' | sed 's/^/ /')
"
REQUIRED_ENV=(AWS_REGION AWS_ACCOUNT CLUSTER_NAME) CHECK_ENVIRONMENT || return 1
local SERVICEACCOUNT NAMESPACE ROLE_NAME
local FORCE=0
local EKSCTL_ARGS=()
while [[ $# -gt 0 ]]
do
case $1 in
--serviceaccount ) SERVICEACCOUNT=$2; shift 1 ;;
--namespace ) NAMESPACE=$2; shift 1 ;;
--role-name ) ROLE_NAME=$2; shift 1 ;;
--force ) FORCE=1 ;;
-- ) shift 1; break ;;
* ) ERROR "unknown argument '$1'" ;;
esac
shift 1
done
while [[ $# -gt 0 ]]; do EKSCTL_ARGS+=($1); shift 1; done
[ $SERVICEACCOUNT ] || ERROR "--serviceaccount is required"
[ $NAMESPACE ] || ERROR "--namespace is required"
[ $ROLE_NAME ] || ERROR "--role-name is required"
CHECK_ERRORS --no-fail || return 1
##########################################
[[ $FORCE -eq 0 ]] && {
_EKS__CHECK_IAMSERVICEACCOUNT_EXISTS
local EXISTS_STATUS=$?
case $EXISTS_STATUS in
0 )
SUCCESS "'$NAMESPACE/$SERVICEACCOUNT' already configured with '$ROLE_NAME'"
return 0
;;
1 ) ;; # role does not exist yet; continue with rollout
2 )
ERROR "'$NAMESPACE/$SERVICEACCOUNT' has been configured with a different role than '$ROLE_NAME'"
REMINDER "must use --force flag to overwrite"
return 2
;;
esac
}
STATUS "creating iamserviceaccount" \
&& EKSCTL create iamserviceaccount \
--cluster $CLUSTER_NAME \
--namespace $NAMESPACE \
--name $SERVICEACCOUNT \
--role-name $ROLE_NAME \
--override-existing-serviceaccounts \
--approve \
${EKSCTL_ARGS[@]} \
&& SUCCESS "successfully configured '$NAMESPACE/$SERVICEACCOUNT' with IAM role '$ROLE_NAME'" \
|| { ERROR "unable to configure '$NAMESPACE/$SERVICEACCOUNT' with IAM role '$ROLE_NAME' (check cloudformation dashboard for details)"; return 3; }
}
_EKS__CHECK_IAMSERVICEACCOUNT_EXISTS() {
STATUS "checking for existing role-arn"
local CURRENT_ROLE_ARN=$(
EKS__KUBECTL --namespace $NAMESPACE get serviceaccount $SERVICEACCOUNT -o yaml \
| YQ -r '.metadata.annotations["eks.amazonaws.com/role-arn"]' \
| grep -v '^null$' \
)
[ $CURRENT_ROLE_ARN ] || {
STATUS "serviceaccount does not exist or has no configured role"
return 1
}
[[ $CURRENT_ROLE_ARN =~ "$ROLE_NAME$" ]] || {
STATUS "serviceaccount current role does not match desired role:
CURRENT : $CURRENT_ROLE_ARN
DESIRED : arn:aws:iam::${AWS_ACCOUNT}:role/$ROLE_NAME
"
return 2
}
STATUS "serviceaccount current role matches desired role"
return 0
}

View File

@ -86,14 +86,9 @@ RDS__GET_DATABASE_CREDENTIALS() {
user-input ) _RDS_AUTH__userinput ;;
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
[[ $PRINT_PASSWORD -eq 1 ]] && DEBUG "password : $DB_PASS"
return 0
}
_RDS_AUTH__iam() {
@ -108,10 +103,10 @@ _RDS_AUTH__iam() {
_RDS_AUTH__secretsmanager() {
local CREDENTIALS=$(_RDS__GET_SECRETSMANAGER_CREDENTIALS)
echo $CREDENTIALS | jq -e '.pass' >/dev/null 2>&1 \
&& DB_PASS="'$(echo $CREDENTIALS | jq -r '.pass' | sed "s/'/'\"'\"'/g")'"
&& DB_PASS="$(echo $CREDENTIALS | jq -r '.pass')"
echo $CREDENTIALS | jq -e '.password' >/dev/null 2>&1 \
&& DB_PASS="'$(echo $CREDENTIALS | jq -r '.password' | sed "s/'/'\"'\"'/g")'"
&& DB_PASS="$(echo $CREDENTIALS | jq -r '.password')"
echo $CREDENTIALS | jq -e '.user' >/dev/null 2>&1 \
&& DB_USER=$(echo $CREDENTIALS | jq -r '.user')

Binary file not shown.

View File

@ -39,4 +39,34 @@ source "$SCWRYPTS_ROOT/zsh/lib/config.group.zsh" \
|| FAIL 69 'failed to set up scwrypts group; aborting'
#####################################################################
__SCWRYPT=1 # arbitrary; indicates currently inside a scwrypt
for plugin in $(ls $SCWRYPTS_ROOT__scwrypts/plugins)
do
[[ $(eval 'echo $SCWRYPTS_PLUGIN_ENABLED__'$plugin) -eq 1 ]] && {
source "$SCWRYPTS_ROOT/plugins/$plugin/$plugin.scwrypts.zsh"
}
done
#####################################################################
for GROUP_LOADER in $(env | sed -n 's/^SCWRYPTS_GROUP_LOADER__[a-z_]\+=//p')
do
[ -f "$GROUP_LOADER" ] && source "$GROUP_LOADER"
done
: \
&& [ ! "$SCWRYPTS_AUTODETECT_GROUP_BASEDIR" ] \
&& [ $GITHUB_WORKSPACE ] \
&& [ ! $SCWRYPTS_GITHUB_NO_AUTOLOAD ] \
&& SCWRYPTS_AUTODETECT_GROUP_BASEDIR="$GITHUB_WORKSPACE"
[ "$SCWRYPTS_AUTODETECT_GROUP_BASEDIR" ] && [ -d "$SCWRYPTS_AUTODETECT_GROUP_BASEDIR" ] && {
for GROUP_LOADER in $(find "$SCWRYPTS_AUTODETECT_GROUP_BASEDIR" -type f -name \*scwrypts.zsh)
do
[ -f "$GROUP_LOADER" ] && source "$GROUP_LOADER"
done
}
#####################################################################
[ $NO_EXPORT_CONFIG ] || __SCWRYPT=1 # arbitrary; indicates currently inside a scwrypt
true

View File

@ -4,7 +4,6 @@ DEPENDENCIES+=(
pg_dump
pg_restore
psql
pgcli
)
REQUIRED_ENV+=()
@ -12,22 +11,22 @@ REQUIRED_ENV+=()
#####################################################################
PSQL() {
[[ ${#ARGS[@]} -eq 0 ]] && POSTGRES__SET_LOGIN_ARGS $@
eval PGPASSWORD=$_PASS psql ${_ARGS[@]}
POSTGRES__SET_LOGIN_ARGS $@
eval PGPASSWORD=$(printf '%q ' "$DB_PASS") psql ${PSQL_ARGS[@]}
}
#####################################################################
PG_DUMP() {
local _HOST _NAME _PORT _USER _FILE
local DATA_DIR _PASS _ARGS=()
local DATA_DIR
POSTGRES__SET_LOGIN_ARGS --verbose $@
local OUTPUT_FILE="$DATA_DIR/backup.$(date '+%Y-%m-%d.%H-%M')"
STATUS "
making backup of : $_USER@$_HOST:$_PORT/$_NAME
making backup of : $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME
(compressed) : '$OUTPUT_FILE.dump'
(safe-raw) : '$OUTPUT_FILE.sql'
@ -36,23 +35,33 @@ PG_DUMP() {
: \
&& STATUS "creating compressed backup..." \
&& eval PGPASSWORD=$_PASS pg_dump ${_ARGS[@]} --format custom --file "$OUTPUT_FILE.dump" \
&& eval PGPASSWORD=$(printf '%q ' "$DB_PASS") psql ${PSQL_ARGS[@]} \
--format custom \
--file "$OUTPUT_FILE.dump" \
--verbose \
&& SUCCESS "completed compressed backup" \
&& STATUS "creating raw backup..." \
&& eval PGPASSWORD=$_PASS pg_dump ${_ARGS[@]} > "$OUTPUT_FILE.raw.sql" \
&& pg_restore -f "$OUTPUT_FILE.raw.sql" "$OUTPUT_FILE.dump" \
&& SUCCESS "completed raw backup" \
&& STATUS "creating single-transaction raw backup..." \
&& { echo "BEGIN;"; cat "$OUTPUT_FILE.raw.sql"; echo "END;" } > "$OUTPUT_FILE.sql" \
&& { echo "BEGIN;\n"; cat "$OUTPUT_FILE.raw.sql"; echo "\nEND;" } > "$OUTPUT_FILE.sql" \
&& SUCCESS "completed single-transaction raw backup" \
|| { ERROR "error creating backup for '$_HOST/$_NAME' (see above)"; return 1; }
|| { ERROR "error creating backup for '$DB_HOST/$DB_NAME' (see above)"; return 1; }
SUCCESS "
completed backup : $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME
(compressed) : '$OUTPUT_FILE.dump'
(safe-raw) : '$OUTPUT_FILE.sql'
(raw) : '$OUTPUT_FILE.raw.sql'
"
}
#####################################################################
PG_RESTORE() {
local _HOST _NAME _PORT _USER
local _PASS _ARGS=()
local _FILE
local _ARGS=()
local FILE
POSTGRES__SET_LOGIN_ARGS $@
local INPUT_FILE=$(find "$DATA_DIR"/backup.* -type f | FZF 'select database file to restore')
@ -72,7 +81,7 @@ PG_RESTORE() {
[[ $INPUT_FILE =~ \\.dump$ ]] && RAW=0
STATUS "
loading backup for : $_USER@$_HOST:$_PORT/$_NAME
loading backup for : $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME
file : '$INPUT_FILE'
"
@ -92,7 +101,7 @@ PG_RESTORE() {
}
[[ $RAW -eq 0 ]] && {
PGPASSWORD="$_PASS" pg_restore ${_ARGS[@]} \
eval PGPASSWORD=$(printf '%q ' "$DB_PASS") pg_restore ${PSQL_ARGS[@]} \
--verbose \
--format custom \
--single-transaction \
@ -101,8 +110,8 @@ PG_RESTORE() {
}
[[ $EXIT_CODE -eq 0 ]] \
&& SUCCESS "finished restoring backup for '$_HOST/$_NAME'" \
|| ERROR "error restoring backup for '$_HOST/$_NAME' (see above)" \
&& SUCCESS "finished restoring backup for '$DB_HOST/$DB_NAME'" \
|| ERROR "error restoring backup for '$DB_HOST/$DB_NAME' (see above)" \
;
return $EXIT_CODE
@ -111,48 +120,70 @@ PG_RESTORE() {
#####################################################################
POSTGRES__LOGIN_INTERACTIVE() {
local _PASS _ARGS=()
DEPENDENCIES=(pgcli) CHECK_ENVIRONMENT --optional \
&& COMMAND=pgcli || COMMAND=psql
[[ $COMMAND =~ psql ]] && WARNING "using 'psql' instead"
POSTGRES__SET_LOGIN_ARGS $@
STATUS "performing login : $_USER@$_HOST:$_PORT/$_NAME"
STATUS "working directory : $DATA_DIR"
STATUS "
performing login : $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME
working directory : $DATA_DIR
"
eval PGPASSWORD=$_PASS pgcli ${_ARGS[@]}
eval PGPASSWORD=$(printf '%q ' "$DB_PASS") $COMMAND ${PSQL_ARGS[@]}
}
#####################################################################
POSTGRES__SET_LOGIN_ARGS() {
# allow for manual override with PSQL_ARGS
[[ ${#PSQL_ARGS[@]} -gt 0 ]] && return 0
local DATA_DIR_PREFIX
while [[ $# -gt 0 ]]
do
case $1 in
--host ) _ARGS+=(-h $2); _HOST="$2"; shift 1 ;;
--name ) _ARGS+=(-d $2); _NAME="$2"; shift 1 ;;
--port ) _ARGS+=(-p $2); _PORT="$2"; shift 1 ;;
--user ) _ARGS+=(-U $2); _USER="$2"; shift 1 ;;
-h | --host ) DB_HOST="$2"; shift 1 ;;
-p | --port ) DB_PORT="$2"; shift 1 ;;
-d | --name ) DB_NAME="$2"; shift 1 ;;
-U | --user ) DB_USER="$2"; shift 1 ;;
-P | --pass ) DB_PASS="$2"; shift 1 ;;
--pass ) _PASS="$2"; shift 1 ;;
--file ) PSQL_FILE="$2"; shift 1 ;;
--file ) _FILE="$2"; shift 1 ;;
--data-dir-prefix ) DATA_DIR_PREFIX="$2"; shift 1 ;;
* ) _ARGS+=($1) ;;
* ) PSQL_ARGS+=($1) ;;
esac
shift 1
done
[ $_FILE ] && [ ! -f "$_FILE" ] && {
ERROR "no such file '$_FILE'"
exit 1
[ $PSQL_FILE ] && [ ! -f "$PSQL_FILE" ] \
&& ERROR "no such file available:\n'$PSQL_FILE'"
CHECK_ERRORS
##########################################
[ $DATA_DIR_PREFIX ] && {
DATA_DIR="$SCWRYPTS_DATA_PATH/$DATA_DIR_PREFIX"
} || {
[ $DB_HOST ] && [ $DB_NAME ] \
&& DATA_DIR="$SCWRYPTS_DATA_PATH/db/$DB_HOST/$DB_NAME" \
|| DATA_DIR="$EXECUTION_DIR/temp-db" \
;
}
[ $_HOST ] && [ $_NAME ] \
&& DATA_DIR="$SCWRYPTS_DATA_PATH/db/$_HOST/$_NAME" \
|| DATA_DIR="$EXECUTION_DIR/temp-db" \
;
[ ! -d "$DATA_DIR" ] && mkdir -p "$DATA_DIR"
mkdir -p "$DATA_DIR"
cd "$DATA_DIR"
return 0
}
[ $DB_HOST ] || DB_HOST=127.0.0.1
[ $DB_PORT ] || DB_PORT=5432
[ $DB_NAME ] || DB_NAME=postgres
[ $DB_USER ] || DB_USER=postgres
PSQL_ARGS+=(-h $DB_HOST -p $DB_PORT -d $DB_NAME -U $DB_USER)
}

View File

@ -0,0 +1,42 @@
#####################################################################
DEPENDENCIES+=(helm kubeval)
REQUIRED_ENV+=()
use helm/validate
#####################################################################
HELM__DEPENDENCY__UPDATE() {
[ ! $USAGE ] && local USAGE="
usage: [...options...]
options
-t, --template-filename path to a template/*.yaml file of a helm chart
Auto-detect chart and build dependencies for any file within a helm chart.
"
local TEMPLATE_FILENAME CHART_ROOT VALUES_FILES=()
local COLORIZE=0 RAW=0 DEBUG=0
while [[ $# -gt 0 ]]
do
case $1 in
-t | --template-filename ) TEMPLATE_FILENAME="$(SCWRYPTS__GET_REALPATH "$2")"; shift 1 ;;
* ) ERROR "unexpected argument '$1'" ;;
esac
shift 1
done
HELM__VALIDATE
CHECK_ERRORS || return 1
##########################################
STATUS "updating helm dependencies for '$CHART_ROOT'" \
&& cd $CHART_ROOT \
&& helm dependency update \
&& SUCCESS "helm chart dependencies updated" \
|| { ERROR "unable to update helm chart dependencies (see above)"; return 1; }
}

View File

@ -0,0 +1,9 @@
#####################################################################
DEPENDENCIES+=()
REQUIRED_ENV+=()
use helm/dependency
use helm/template
#####################################################################

View File

@ -0,0 +1,111 @@
#####################################################################
DEPENDENCIES+=(helm kubeval)
REQUIRED_ENV+=()
use helm/validate
use scwrypts
#####################################################################
HELM__TEMPLATE__GET() {
[ ! $USAGE ] && local USAGE="
usage: [...options...] (--) [...helm args...]
options
-t, --template-filename path to a template/*.yaml file of a helm chart
--colorize use 'bat' to colorize output
--raw remove scwrypts-added fluff and only output helm template details
-h, --help show this help dialogue
Smart helm-template generator which auto-detects the chart
and sample values for testing and developing helm charts.
"
local HELM_ARGS=()
local TEMPLATE_FILENAME TEMPLATE_NAME CHART_ROOT CHART_NAME VALUES_FILES=()
local COLORIZE=0 RAW=0 DEBUG=0
while [[ $# -gt 0 ]]
do
case $1 in
-t | --template-filename ) TEMPLATE_FILENAME="$(SCWRYPTS__GET_REALPATH "$2")"; shift 1 ;;
--colorize )
DEPENDENCIES=(bat) CHECK_ENVIRONMENT || return 1
COLORIZE=1
;;
--raw ) RAW=1 ;;
-h | --help ) USAGE; return 0 ;;
-- ) shift 1; break ;;
* ) HELM_ARGS+=($1) ;;
esac
shift 1
done
while [[ $# -gt 0 ]]; do HELM_ARGS+=($1); shift 1; done
HELM__VALIDATE
CHECK_ERRORS || return 1
##########################################
local EXIT_CODE=0
local TEMPLATE_OUTPUT DEBUG_OUTPUT
[ $USE_CHART_ROOT ] && [[ $USE_CHART_ROOT -eq 1 ]] && {
CAPTURE TEMPLATE_OUTPUT DEBUG_OUTPUT helm template "$CHART_ROOT" ${HELM_ARGS[@]} --debug
true
} || {
CAPTURE TEMPLATE_OUTPUT DEBUG_OUTPUT helm template "$CHART_ROOT" ${HELM_ARGS[@]} --debug --show-only "$(echo $TEMPLATE_FILENAME | sed "s|^$CHART_ROOT/||")"
}
[ ! $TEMPLATE_OUTPUT ] && EXIT_CODE=1
[[ $RAW -eq 1 ]] && {
[ $USE_CHART_ROOT ] && [[ $USE_CHART_ROOT -eq 1 ]] || HELM_ARGS+=(--show-only $(echo $TEMPLATE_FILENAME | sed "s|^$CHART_ROOT/||"))
[[ $COLORIZE -eq 1 ]] \
&& helm template "$CHART_ROOT" ${HELM_ARGS[@]} 2>&1 | bat --language yaml --color always \
|| helm template "$CHART_ROOT" ${HELM_ARGS[@]} | grep -v '^# Source:.*$' \
;
return $EXIT_CODE
}
[ $TEMPLATE_OUTPUT ] && {
KUBEVAL_RAW=$(echo $TEMPLATE_OUTPUT | kubeval --schema-location https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master)
true
} || {
TEMPLATE_OUTPUT="---\nerror: chart or '$(basename $(dirname $TEMPLATE_FILENAME))/$(basename $TEMPLATE_FILENAME)' invalid"
KUBEVAL_RAW="no template output; kubeval skipped"
[ $USE_CHART_ROOT ] && [[ $USE_CHART_ROOT -eq 1 ]] || {
DEBUG_OUTPUT="$(helm template "$CHART_ROOT" ${HELM_ARGS[@]} --debug 2>&1 >/dev/null)"
}
}
TEMPLATE_OUTPUT="$TEMPLATE_OUTPUT
---
debug: |
$(echo $DEBUG_OUTPUT | sed 's/^/ /g')
kubeval: |
$(echo $KUBEVAL_RAW | sed 's/^/ /g')
lint: |
$(helm lint $CHART_ROOT ${HELM_ARGS[@]} 2>&1 | sed 's/^/ /g')
"
[[ $COLORIZE -eq 1 ]] && {
echo $TEMPLATE_OUTPUT | bat --language yaml --color always
} || {
echo $TEMPLATE_OUTPUT
}
return $EXIT_CODE
}

View File

@ -0,0 +1,95 @@
#####################################################################
DEPENDENCIES+=(yq)
REQUIRED_ENV+=()
#####################################################################
HELM__VALIDATE() {
[ ! $USAGE ] && USAGE="
usage:
environment
TEMPLATE_FILENAME target template filename
Smart helm-detection / validator which determines the helm
chart root and other details given a particular filename.
"
[ $TEMPLATE_FILENAME ] && [ -f "$TEMPLATE_FILENAME" ] || {
ERROR 'must provide a template filename'
return 1
}
_HELM__GET_CHART_ROOT
[ $CHART_ROOT ] && [ -d "$CHART_ROOT" ] || {
ERROR 'unable to determine helm root; is this a helm template file?'
return 1
}
CHART_NAME=$(YQ -r .name "$CHART_ROOT/Chart.yaml")
[[ $TEMPLATE_FILENAME =~ values.*.yaml$ ]] && {
HELM_ARGS+=(--values $TEMPLATE_FILENAME)
USE_CHART_ROOT=1
}
[[ $TEMPLATE_FILENAME =~ tests/.*.yaml$ ]] && {
HELM_ARGS+=(--values $TEMPLATE_FILENAME)
USE_CHART_ROOT=1
}
[[ $TEMPLATE_FILENAME =~ .tpl$ ]] \
&& USE_CHART_ROOT=1
[[ $(dirname $TEMPLATE_FILENAME) =~ ^$CHART_ROOT$ ]] \
&& USE_CHART_ROOT=1
_HELM__GET_DEFAULT_VALUES_ARGS
return 0
}
_HELM__GET_CHART_ROOT() {
local SEARCH_DIR=$(dirname "$TEMPLATE_FILENAME")
while [ ! $CHART_ROOT ] && [[ ! $SEARCH_DIR =~ ^/$ ]]
do
[ -f "$SEARCH_DIR/Chart.yaml" ] && CHART_ROOT="$SEARCH_DIR" && return 0
SEARCH_DIR="$(dirname "$SEARCH_DIR")"
done
return 1
}
_HELM__GET_DEFAULT_VALUES_ARGS() {
for F in \
"$CHART_ROOT/tests/default.yaml" \
"$CHART_ROOT/values.test.yaml" \
"$CHART_ROOT/values.yaml" \
;
do
[ -f "$F" ] && HELM_ARGS=(--values "$F" $HELM_ARGS)
done
for LOCAL_REPOSITORY in $(\
cat "$CHART_ROOT/Chart.yaml" \
| YQ -r '.dependencies[] | .repository' \
| grep '^file://' \
| sed 's|file://||' \
)
do
[[ $LOCAL_REPOSITORY =~ ^[/~] ]] \
&& LOCAL_REPOSITORY_ROOT="$LOCAL_REPOSITORY" \
|| LOCAL_REPOSITORY_ROOT="$CHART_ROOT/$LOCAL_REPOSITORY" \
;
for F in \
"$LOCAL_REPOSITORY_ROOT/tests/default.yaml" \
"$LOCAL_REPOSITORY_ROOT/values.test.yaml" \
"$LOCAL_REPOSITORY_ROOT/values.yaml" \
;
do
[ -f "$F" ] && HELM_ARGS=(--values "$F" $HELM_ARGS)
done
done
}

View File

@ -0,0 +1,106 @@
#####################################################################
DEPENDENCIES+=()
REQUIRED_ENV+=()
#####################################################################
TALLY_USE_REDIS=false # maybe someday
TALLY_PATH="$SCWRYPTS_DATA_PATH/tally"
#####################################################################
TALLY() {
local USAGE="
usage: [...options...]
options:
-c, --increment-count increment the tally by this much (default 1)
-n, --tally-name name of tally system (default 'default')
-g, --get only output the current value
-s, --set set the tally to a specific value
-r, --reset set the tally back to zero
--raw only output the tally value
-h, --help print this dialogue and exit
Simple tally mark system; keep track of a count.
"
local INCREMENT_COUNT=1
local TALLY_NAME=default
local RAW=false
local SET_VALUE=
while [[ $# -gt 0 ]]
do
case $1 in
-c | --increment-count ) INCREMENT_COUNT=$2; shift 1 ;;
-n | --tally-name ) TALLY_NAME=$2; shift 1 ;;
-g | --get ) INCREMENT_COUNT=0 ;;
-s | --set ) SET_VALUE=$2; shift 1 ;;
-r | --reset ) SET_VALUE=0 ;;
--raw ) RAW=true ;;
-h | --help ) USAGE; return 0 ;;
* ) ERROR "unknown argument '$1'" ;;
esac
shift 1
done
[ $TALLY_NAME ] && echo "$TALLY_NAME" | grep -qv '/' \
|| ERROR "invalid tally name '$TALLY_NAME'"
local TALLY_FILENAME="$TALLY_PATH/$TALLY_NAME.txt"
CHECK_ERRORS --no-fail || return 1
##########################################
local NEW_VALUE CURRENT_VALUE=0
[ $SET_VALUE ] && NEW_VALUE=$SET_VALUE || {
[ -f "$TALLY_FILENAME" ] && {
CURRENT_VALUE=$(cat "$TALLY_FILENAME" | tail -n1 | grep '^[0-9]\+')
}
[ $CURRENT_VALUE ] || {
ERROR "malformed tally file '$TALLY_FILENAME'; aborting"
return 1
}
NEW_VALUE=$(($CURRENT_VALUE + $INCREMENT_COUNT))
}
##########################################
local TALLY_DIR="$(dirname "$TALLY_FILENAME")"
[ -d "$TALLY_DIR" ] || mkdir -p "$TALLY_DIR"
[ -d "$TALLY_DIR" ] || {
ERROR "unable to write to '$TALLY_DIR'; aborting"
return 1
}
echo "# autogenerated tally file; avoid direct modification\n$NEW_VALUE" > "$TALLY_FILENAME" || {
ERROR "failed to write to '$TALLY_FILENAME': aborting"
return 1
}
##########################################
case $RAW in
true ) printf "$NEW_VALUE" ;;
false )
case $TALLY_NAME in
default ) SUCCESS "current tally : $NEW_VALUE" ;;
* ) SUCCESS "$TALLY_NAME : $NEW_VALUE" ;;
esac
esac
}

View File

@ -10,7 +10,7 @@ REQUIRED_ENV+=()
#####################################################################
LATEX__GET_MAIN_FILENAME() {
local FILENAME=$(SCWRYPTS__GET_PATH_TO_RELATIVE_ARGUMENT "$1")
local FILENAME=$(SCWRYPTS__GET_REALPATH "$1")
local DIRNAME="$FILENAME"
for _ in {1..3}

View File

@ -12,7 +12,7 @@ SCWRYPTS__SELECT_ENV() {
}
SCWRYPTS__SELECT_OR_CREATE_ENV() {
SCWRYPTS__GET_ENV_NAMES | FZF_TAIL 'select / create an environment'
SCWRYPTS__GET_ENV_NAMES | FZF_USER_INPUT 'select / create an environment'
}
SCWRYPTS__GET_ENV_FILES() {
@ -64,7 +64,11 @@ SCWRYPTS__GET_ENV_NAMES() {
ERROR 'environment initialization error'
return 1
}
ls "$SCWRYPTS_ENV_PATH/scwrypts" | sort -r
[ $REQUIRED_ENVIRONMENT_REGEX ] && {
ls "$SCWRYPTS_ENV_PATH/scwrypts" | grep "$REQUIRED_ENVIRONMENT_REGEX" | sort -r
} || {
ls "$SCWRYPTS_ENV_PATH/scwrypts" | sort -r
}
}
SCWRYPTS__INIT_ENVIRONMENTS() {

View File

@ -8,15 +8,13 @@ use scwrypts/run
#####################################################################
SCWRYPTS__RUN() {
SCWRYPTS__RUN() { # context wrapper to run scwrypts within scwrypts
local EXIT_CODE=0
((SUBSCWRYPT+=1))
echo "--- START SUBSCWRYPT=$SUBSCWRYPT $@"
SUBSCWRYPT=$SUBSCWRYPT $SCWRYPTS_ROOT/run $@
EXIT_CODE=$?
((SUBSCWRYPT-=1))
return $EXIT_CODE
echo "--- END SUBSCWRYPT=$SUBSCWRYPT $@"
}

View File

@ -54,6 +54,7 @@ SCWRYPTS__LIST_AVAILABLE_SCWRYPTS__scwrypts() {
| grep -v '\.git' \
| grep -v 'node_modules' \
| sed "s/^\\.\\///; s/\\.[^.]*$//; s/^/$GROUP_TYPE/" \
| grep -v '^plugins/' \
;
}
@ -111,6 +112,58 @@ SCWRYPTS__GET_RUNSTRING() {
SCWRYPTS__GET_RUNSTRING__zsh() {
__CHECK_DEPENDENCY zsh || return 1
local SCWRYPT_FILENAME
[ $(eval echo '$SCWRYPTS_TYPE__'$SCWRYPT_GROUP) ] \
&& SCWRYPT_FILENAME="$GROUP_PATH/$SCWRYPT_NAME" \
|| SCWRYPT_FILENAME="$GROUP_PATH/$SCWRYPT_TYPE/$SCWRYPT_NAME" \
;
printf "
source '$SCWRYPT_FILENAME'
CHECK_ENVIRONMENT
ERRORS=0
export USAGE=\"
usage: -
args: -
options: -
-h, --help display this message and exit
description: -
\"
[ ! \$USAGE__usage ] && export USAGE__usage='[...options...]'
() {
local MAIN_ARGS=()
local VARSPLIT
while [[ \$# -gt 0 ]]
do
case \$1 in
-[a-z][a-z]* )
VARSPLIT=\$(echo \"\$1 \" | sed 's/^\\\\(-.\\\\)\\\\(.*\\\\) /\\\\1 -\\\\2/')
set -- throw-away \$(echo \" \$VARSPLIT \") \${@:2}
;;
-h | --help ) USAGE; exit 0 ;;
* ) MAIN_ARGS+=(\$1) ;;
esac
shift 1
done
MAIN \${MAIN_ARGS[@]}
} "
return 0
}
SCWRYPTS__GET_RUNSTRING__zsh_v3() {
WARNING "scwrypts zsh/v3 runstrings are now deprecated; please update to scwrypts v4 format"
__CHECK_DEPENDENCY zsh || return 1
[ $(eval echo '$SCWRYPTS_TYPE__'$SCWRYPT_GROUP) ] \
&& echo "source $GROUP_PATH/$SCWRYPT_NAME" \
|| echo "source $GROUP_PATH/$SCWRYPT_TYPE/$SCWRYPT_NAME" \

View File

@ -0,0 +1,15 @@
#####################################################################
DEPENDENCIES+=()
REQUIRED_ENV+=()
#####################################################################
SCWRYPTS__GET_REALPATH() {
[[ ! $1 =~ ^[/~] ]] \
&& echo $(readlink -f "$EXECUTION_DIR/$1") \
|| echo "$1" \
;
return 0
}

View File

@ -1,9 +1,6 @@
#####################################################################
DEPENDENCIES+=(
virtualenv
nodeenv
)
DEPENDENCIES+=()
REQUIRED_ENV+=()
use utils
@ -15,14 +12,14 @@ AVAILABLE_VIRTUALENVS=(py zx)
REFRESH_VIRTUALENV() {
local GROUP="$1"
local TYPE="$2"
[ ! $TYPE ] && {
ERROR 'no virtualenv type specified'
return 1
}
STATUS "refreshing $GROUP/$TYPE virtual environment"
local VIRTUALENV_PATH="$(_VIRTUALENV__GET_PATH)"
[ ! $TYPE ] && { ERROR 'no virtualenv type specified'; return 1; }
STATUS "refreshing $GROUP/$TYPE virtualenv"
DELETE_VIRTUALENV $GROUP $TYPE \
&& UPDATE_VIRTUALENV $GROUP $TYPE \
&& SUCCESS 'successfully refreshed virtual environment' \
&& SUCCESS 'successfully refreshed virtualenv' \
|| { ERROR 'something went wrong during refresh (see above)'; return 1; } \
;
}
@ -30,64 +27,50 @@ REFRESH_VIRTUALENV() {
UPDATE_VIRTUALENV() {
local GROUP="$1"
local TYPE="$2"
[ ! $TYPE ] && {
ERROR 'no virtualenv type specified'
return 1
}
local VIRTUALENV_PATH="$(_VIRTUALENV__GET_PATH)"
local VIRTUALENV_PATH=$(GET_VIRTUALENV_PATH $GROUP $TYPE)
[ ! $TYPE ] && { ERROR 'no virtualenv type specified'; return 1; }
[ ! -d $VIRTUALENV_PATH ] && {
which CREATE_VIRTUALENV__${GROUP}__${TYPE} >/dev/null 2>&1 \
&& CREATE_VIRTUALENV__${GROUP}__${TYPE} $VIRTUALENV_PATH \
|| return 0
}
: \
&& which CREATE_VIRTUALENV__${GROUP}__${TYPE} >/dev/null 2>&1 \
&& which ACTIVATE_VIRTUALENV__${GROUP}__${TYPE} >/dev/null 2>&1 \
&& which UPDATE_VIRTUALENV__${GROUP}__${TYPE} >/dev/null 2>&1 \
&& which DEACTIVATE_VIRTUALENV__${GROUP}__${TYPE} >/dev/null 2>&1 \
|| { STATUS "no virtualenv available for $GROUP/$TYPE; skipping"; return 0; }
STATUS "updating $TYPE virtual environment"
source $VIRTUALENV_PATH/bin/activate || {
ERROR 'failed to activate virtualenv; did create fail?'
return 1
}
cd $SCWRYPTS_ROOT
local UPDATE_CODE=0
case $TYPE in
py ) cd py; pip install --no-cache-dir -r requirements.txt; UPDATE_CODE=$? ;;
zx ) cd zx; npm install ;;
esac
UPDATE_CODE=$?
[[ $UPDATE_CODE -eq 0 ]] \
&& SUCCESS "$TYPE virtual environment up-to-date" \
|| ERROR "failed to update $TYPE virtual environment (see errors above)" \
;
deactivate_node >/dev/null 2>&1
deactivate >/dev/null 2>&1
return $UPDATE_CODE
STATUS "updating $GROUP/$TYPE virtualenv" \
&& CREATE_VIRTUALENV__${GROUP}__${TYPE} \
&& ACTIVATE_VIRTUALENV__${GROUP}__${TYPE} \
&& UPDATE_VIRTUALENV__${GROUP}__${TYPE} \
&& DEACTIVATE_VIRTUALENV__${GROUP}__${TYPE} \
&& SUCCESS "$GROUP/$TYPE virtualenv up-to-date" \
|| { ERROR "failed to update $GROUP/$TYPE virtualenv (see errors above)"; return 2; }
}
DELETE_VIRTUALENV() {
[ $CI ] && return 0
local GROUP="$1"
local TYPE="$2"
local VIRTUALENV_PATH="$(GET_VIRTUALENV_PATH $GROUP $TYPE)"
local VIRTUALENV_PATH="$(_VIRTUALENV__GET_PATH)"
STATUS "dropping $TYPE virtual environment artifacts"
[ ! $TYPE ] && { ERROR 'no virtualenv type specified'; return 1; }
STATUS "dropping $GROUP/$TYPE virtualenv artifacts"
[ ! -d $VIRTUALENV_PATH ] && {
SUCCESS "no $TYPE environment detected"
SUCCESS "no $GROUP/$TYPE environment detected"
return 0
}
rm -rf $VIRTUALENV_PATH \
&& SUCCESS "succesfully cleaned up $TYPE virtual environment" \
&& SUCCESS "succesfully cleaned up $GROUP/$TYPE virtualenv" \
|| { ERROR "unabled to remove '$VIRTUALENV_PATH'"; return 1; }
}
GET_VIRTUALENV_PATH() {
local GROUP="$1"
local TYPE="$2"
#####################################################################
_VIRTUALENV__GET_PATH() {
local ENV_PATH="$(eval echo '$SCWRYPTS_VIRTUALENV_PATH__'$GROUP 2>/dev/null)"
[ ! $ENV_PATH ] && ENV_PATH="$SCWRYPTS_VIRTUALENV_PATH__scwrypts"
@ -97,9 +80,14 @@ GET_VIRTUALENV_PATH() {
#####################################################################
CREATE_VIRTUALENV__scwrypts__py() {
[ $CI ] && return 0
[ -d $VIRTUALENV_PATH ] && return 0
DEPENDENCIES=(virtualenv) CHECK_ENVIRONMENT || return 1
local VIRTUALENV_PATH="$1"
STATUS 'creating python virtual environment'
STATUS 'creating python virtualenv'
local PY PYTHON
for PY in $(echo $SCWRYPTS_PREFERRED_PYTHON_VERSIONS__scwrypts)
do
@ -122,7 +110,37 @@ CREATE_VIRTUALENV__scwrypts__py() {
}
}
ACTIVATE_VIRTUALENV__scwrypts__py() {
[ $CI ] && return 0
source $VIRTUALENV_PATH/bin/activate || {
ERROR "failed to activate virtualenv $GROUP/$TYPE; did create fail?"
return 1
}
}
UPDATE_VIRTUALENV__scwrypts__py() {
local PIP_INSTALL_ARGS=()
PIP_INSTALL_ARGS+=(--no-cache-dir)
PIP_INSTALL_ARGS+=(-r requirements.txt)
cd "$SCWRYPTS_ROOT/py"
pip install ${PIP_INSTALL_ARGS[@]}
}
DEACTIVATE_VIRTUALENV__scwrypts__py() {
deactivate >/dev/null 2>&1
return 0
}
##########################################
CREATE_VIRTUALENV__scwrypts__zx() {
[ $CI ] && return 0
[ -d $VIRTUALENV_PATH ] && return 0
DEPENDENCIES=(nodeenv) CHECK_ENVIRONMENT || return 1
local VIRTUALENV_PATH="$1"
STATUS 'setting up nodeenv'
@ -133,3 +151,23 @@ CREATE_VIRTUALENV__scwrypts__zx() {
return 2
}
}
ACTIVATE_VIRTUALENV__scwrypts__zx() {
[ $CI ] && return 0
source $VIRTUALENV_PATH/bin/activate || {
ERROR "failed to activate virtualenv $GROUP/$TYPE; did create fail?"
return 1
}
}
UPDATE_VIRTUALENV__scwrypts__zx() {
local NPM_INSTALL_ARGS=()
cd "$SCWRYPTS_ROOT/zx"
npm install ${NPM_INSTALL_ARGS[@]}
}
DEACTIVATE_VIRTUALENV__scwrypts__zx() {
deactivate_node >/dev/null 2>&1
return 0
}

View File

@ -20,7 +20,7 @@ VUNDLE__PLUGIN_LIST=$(ls $VUNDLE__PLUGIN_DIR | grep -v 'Vundle.vim' | grep -v 'b
source $VUNDLE__BUILD_DEFINITIONS
for PLUGIN in $(echo $VUNDLE__PLUGIN_LIST)
do
typeset -f VUNDLE__BUILD__$PLUGIN >/dev/null 2>/dev/null || {
which VUNDLE__BUILD__$PLUGIN >/dev/null 2>/dev/null || {
echo -e "\nVUNDLE__BUILD__$PLUGIN() {\n # ... build steps from $HOME/.vim/$PLUGIN \n}" \
>> $VUNDLE__BUILD_DEFINITIONS
VUNDLE__BUILD__$PLUGIN() {}

View File

@ -2,22 +2,22 @@ __BLACK='\033[0;30m'
__DARK_GRAY='\033[1;30m'
__RED='\033[0;31m'
__LIGHT_RED='\033[1;31m'
__BRIGHT_RED='\033[1;31m'
__GREEN='\033[0;32m'
__LIGHT_GREEN='\033[1;32m'
__BRIGHT_GREEN='\033[1;32m'
__ORANGE='\033[0;33m'
__YELLOW='\033[1;33m'
__YELLOW='\033[0;33m'
__BRIGHT_YELLOW='\033[1;33m'
__BLUE='\033[1;34m'
__DARK_BLUE='\033[0;34m'
__BLUE='\033[0;34m'
__BRIGHT_BLUE='\033[1;34m'
__PURPLE='\033[1;35m'
__DARK_PURPLE='\033[0;35m'
__MAGENTA='\033[0;35m'
__BRIGHT_MAGENTA='\033[1;35m'
__CYAN='\033[1;36m'
__DARK_CYAN='\033[0;36m'
__CYAN='\033[0;36m'
__BRIGHT_CYAN='\033[1;36m'
__WHITE='\033[1;37m'
__LIGHT_GRAY='\033[0;37m'
@ -27,17 +27,17 @@ __COLOR_RESET='\033[0m'
__GET_RANDOM_COLOR() {
local COLORS=(
$__RED
$__LIGHT_RED
$__BRIGHT_RED
$__GREEN
$__LIGHT_GREEN
$__ORANGE
$__BRIGHT_GREEN
$__YELLOW
$__BRIGHT_YELLOW
$__BLUE
$__DARK_BLUE
$__PURPLE
$__DARK_PURPLE
$__BRIGHT_BLUE
$__MAGENTA
$__BRIGHT_MAGENTA
$__CYAN
$__DARK_CYAN
$__BRIGHT_CYAN
$__WHITE
)
print "$__COLOR_RESET${COLORS[$(shuf -i 1-${#COLORS[@]} -n 1)]}"

View File

@ -1,21 +1,30 @@
__CHECK_DEPENDENCIES() {
local DEP ERROR=0
local DEP ERRORS=0
local SCWRYPTS_LOG_LEVEL=1
[ ! $E ] && E=ERROR
DEPENDENCIES=($(echo $DEPENDENCIES | sed 's/ \+/\n/g' | sort -u))
for DEP in ${DEPENDENCIES[@]}; do __CHECK_DEPENDENCY $DEP || ((ERROR+=1)); done
__CHECK_COREUTILS || ((ERROR+=$?))
for DEP in ${DEPENDENCIES[@]}; do __CHECK_DEPENDENCY $DEP || ((ERRORS+=1)); done
__CHECK_COREUTILS || ((ERRORS+=$?))
return $ERROR
return $ERRORS
}
__CHECK_DEPENDENCY() {
local DEPENDENCY="$1"
[ ! $DEPENDENCY ] && return 1
command -v $DEPENDENCY >/dev/null 2>&1 || {
ERROR "'$1' required but not available on PATH $(__CREDITS $1)"
$E "application '$1' "$([[ $OPTIONAL -eq 1 ]] && echo preferred || echo required)" but not available on PATH $(__CREDITS $1)"
return 1
}
[[ $DEPENDENCY =~ ^yq$ ]] && {
yq --version | grep -q mikefarah \
|| WARNING 'detected kislyuk/yq but mikefarah/yq is preferred (compatibility may vary)'
}
return 0
}
__CHECK_COREUTILS() {
@ -35,7 +44,7 @@ __CHECK_COREUTILS() {
done
[[ $NON_GNU_DEPENDENCY_COUNT -gt 0 ]] && {
WARNING 'scripts rely on GNU coreutils; functionality may be limited'
WARNING 'scripts rely on GNU coreutils; compatibility may vary'
IS_MACOS && REMINDER 'GNU coreutils can be installed and linked through Homebrew'
}

View File

@ -1,4 +1,5 @@
__CHECK_REQUIRED_ENV() {
local SCWRYPTS_LOG_LEVEL=1
local VAR ERROR=0
REQUIRED_ENV=($(echo $REQUIRED_ENV | sed 's/\s\+/\n/g' | sort -u))
for VAR in ${REQUIRED_ENV[@]}; do __CHECK_ENV_VAR $VAR || ((ERROR+=1)); done
@ -32,7 +33,7 @@ __CHECK_ENV_VAR() {
[ $DEFAULT_VALUE ] && $NAME="$DEFAULT_VALUE"
return 0
} || {
ERROR "'$NAME' required"
ERROR "variable '$NAME' required"
return 1
}
}

57
zsh/lib/utils/io.fzf.zsh Normal file
View File

@ -0,0 +1,57 @@
FZF() {
[ $CI ] && FAIL 1 'currently in CI, but FZF requires user input'
local FZF_ARGS=()
FZF_ARGS+=(-i)
FZF_ARGS+=(--ansi)
FZF_ARGS+=(--bind=ctrl-c:cancel)
FZF_ARGS+=(--height=50%)
FZF_ARGS+=(--layout=reverse)
local SELECTION=$(fzf ${FZF_ARGS[@]} --prompt "$1 : " ${@:2})
PROMPT "$1"
[ $BE_QUIET ] || {
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] && echo $SELECTION >&2
}
echo $SELECTION
[ $SELECTION ]
}
FZF_USER_INPUT() { # allow user to type custom answers; reconfirm if ambiguous with select
local FZF_OUTPUT=$(BE_QUIET=1 FZF $@ --print-query | sed '/^$/d' | sort -u)
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] && echo $FZF_OUTPUT | head -n1 >&2
[ ! $FZF_OUTPUT ] && return 1
[[ $(echo "$FZF_OUTPUT" | wc -l) -eq 1 ]] \
&& { echo "$FZF_OUTPUT"; return 0; }
local FZF_OUTPUT=$(
echo "$FZF_OUTPUT" \
| sed "1s/\$/^$(printf "$__LIGHT_GRAY\\033[3m")<- what you typed$(printf $__COLOR_RESET)/" \
| sed "2s/\$/^$(printf "$__LIGHT_GRAY\\033[3m")<- what you selected$(printf $__COLOR_RESET)/" \
| column -ts '^' \
| BE_QUIET=1 FZF "$@ (clarify)" \
)
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] && echo $FZF_OUTPUT >&2
FZF_OUTPUT=$(echo $FZF_OUTPUT | sed 's/\s\+<- what you .*$//')
echo $FZF_OUTPUT
[ $FZF_OUTPUT ]
}
#####################################################################
### vvv DEPRECATED vvv ##############################################
#####################################################################
FZF_HEAD() { # prefer user input over selected
WARNING 'FZF_HEAD is deprecated and will be unavailable in v4.2; please switch to FZF_USER_INPUT (drop-in fix!)'
FZF $@ --print-query | sed '/^$/d' | head -n1;
}
FZF_TAIL() { # prefer selected over user input
WARNING 'FZF_TAIL is deprecated and will be unavailable in v4.2; please switch to FZF_USER_INPUT (drop-in fix!)'
FZF $@ --print-query | sed '/^$/d' | tail -n1;
}
#####################################################################

View File

@ -0,0 +1,38 @@
PRINT() {
local MESSAGE
local LAST_LINE_END='\n'
local STDERR=1
local STDOUT=0
local LTRIM=1
while [[ $# -gt 0 ]]
do
case $1 in
-n | --no-trim-tabs ) LTRIM=0 ;;
-x | --no-line-end ) LAST_LINE_END='' ;;
-o | --use-stdout ) STDOUT=1; STDERR=0 ;;
* ) MESSAGE+="$(echo $1) " ;;
esac
shift 1
done
MESSAGE="$(echo "$MESSAGE" | sed 's/%/%%/g')"
local STYLED_MESSAGE="$({
printf "${COLOR}"
while IFS='' read line
do
[[ $PREFIX =~ ^[[:space:]]\+$ ]] && printf '\n'
printf "${PREFIX} : $(echo "$line" | sed 's/^ \+//; s/ \+$//')"
PREFIX=$(echo $PREFIX | sed 's/./ /g')
done <<< $MESSAGE
})"
STYLED_MESSAGE="${COLOR}$(echo "$STYLED_MESSAGE" | sed 's/%/%%/g')${__COLOR_RESET}${LAST_LINE_END}"
[[ $STDERR -eq 1 ]] && printf $STYLED_MESSAGE >&2
[[ $STDOUT -eq 1 ]] && printf $STYLED_MESSAGE
return 0
}

View File

@ -0,0 +1,65 @@
USAGE() { # formatter for USAGE variable
[ ! $USAGE ] && return 0
local USAGE_LINE=$(echo $USAGE | grep -i '^[ ]*usage *:' | sed 's/^[ ]*//')
[ $USAGE__usage ] && echo $USAGE_LINE | grep -q 'usage: -' \
&& USAGE_LINE=$(echo $USAGE_LINE | sed "s/usage: -/usage: $USAGE__usage/")
[ $__SCWRYPT ] \
&& USAGE_LINE=$(
echo $USAGE_LINE \
| sed "s;^[^:]*:;& scwrypts $SCWRYPT_NAME --;" \
| sed 's/ \{2,\}/ /g; s/scwrypts -- scwrypts/scwrypts/' \
)
local THE_REST=$(echo $USAGE | grep -vi '^[ ]*usage *:' )
local DYNAMIC_USAGE_ELEMENT
#
# create dynamic usage elements (like 'args') by defining USAGE__<element>
# then using the syntax "<element>: -" in your USAGE variable
#
# e.g.
#
# USAGE__args="
# subcommand arg 1 arg 1 description
# subcommand arg 2 some other description
# "
#
# USAGE="
# usage: some-command [...args...]
#
# args: -
# -h, --help some arguments are applicable everywhere
# "
#
for DYNAMIC_USAGE_ELEMENT in $(echo $THE_REST | sed -n 's/^\([^:]*\): -$/\1/p')
do
DYNAMIC_USAGE_ELEMENT_TEXT=$(eval echo '$USAGE__'$DYNAMIC_USAGE_ELEMENT)
#[ $DYNAMIC_USAGE_ELEMENT_TEXT ] || continue
case $DYNAMIC_USAGE_ELEMENT in
description )
DYNAMIC_USAGE_ELEMENT_TEXT=$(echo "$DYNAMIC_USAGE_ELEMENT_TEXT" | perl -p0e 's/^[\n\s]+//')
DYNAMIC_USAGE_ELEMENT_TEXT="$__YELLOW\\033[03m$DYNAMIC_USAGE_ELEMENT_TEXT\\033[0m"
;;
* )
DYNAMIC_USAGE_ELEMENT_TEXT=$(echo $DYNAMIC_USAGE_ELEMENT_TEXT | sed 's/[^ ]/ &/')
;;
esac
THE_REST=$(echo $THE_REST | perl -pe "s$DYNAMIC_USAGE_ELEMENT: -$DYNAMIC_USAGE_ELEMENT:\n$DYNAMIC_USAGE_ELEMENT_TEXT\n\n")
done
# allow for dynamic 'description: -' but delete the 'description:' header line
THE_REST=$(echo $THE_REST | sed '/^[ ]*description:$/d')
echo "$__BLUE$USAGE_LINE$__COLOR_RESET\n\n$THE_REST" \
| sed "s/^\t\+//; s/\s\+$//; s/^\\s*$//;" \
| sed '/./,$!d; :a; /^\n*$/{$d;N;ba;};' \
| perl -p0e 's/\n{2,}/\n\n/g' \
| perl -p0e 's/:\n{2,}/:\n/g' \
| perl -p0e 's/([a-z]+:)\n([a-z]+:)/\2/g' \
>&2
}

View File

@ -1,117 +1,143 @@
PRINT() {
local MESSAGE
local LAST_LINE_END='\n'
local STDERR=1
local STDOUT=0
local LTRIM=1
while [[ $# -gt 0 ]]
do
case $1 in
-n | --no-trim-tabs ) LTRIM=0 ;;
-x | --no-line-end ) LAST_LINE_END='' ;;
-o | --use-stdout ) STDOUT=1; STDERR=0 ;;
* ) MESSAGE+="$(echo $1) " ;;
esac
shift 1
done
MESSAGE="$(echo "$MESSAGE" | sed 's/%/%%/g')"
local STYLED_MESSAGE="$({
printf "${COLOR}"
while IFS='' read line
do
[[ $PREFIX =~ ^[[:space:]]\+$ ]] && printf '\n'
printf "${PREFIX} : $(echo "$line" | sed 's/^ \+//; s/ \+$//')"
PREFIX=$(echo $PREFIX | sed 's/./ /g')
done <<< $MESSAGE
})"
STYLED_MESSAGE="${COLOR}$(echo "$STYLED_MESSAGE" | sed 's/%/%%/g')${__COLOR_RESET}${LAST_LINE_END}"
[[ $STDERR -eq 1 ]] && printf $STYLED_MESSAGE >&2
[[ $STDOUT -eq 1 ]] && printf $STYLED_MESSAGE
return 0
}
#####################################################################
### basic colorized print messages ##################################
#####################################################################
source "${0:a:h}/io.print.zsh"
[ ! $ERRORS ] && ERRORS=0
ERROR() { PREFIX="ERROR ✖" COLOR=$__RED PRINT "$@"; ((ERRORS+=1)); }
SUCCESS() { PREFIX="SUCCESS ✔" COLOR=$__GREEN PRINT "$@"; }
WARNING() { PREFIX="WARNING " COLOR=$__ORANGE PRINT "$@"; }
STATUS() { PREFIX="STATUS " COLOR=$__BLUE PRINT "$@"; }
REMINDER() { PREFIX="REMINDER " COLOR=$__PURPLE PRINT "$@"; }
INFO() { PREFIX="INFO " COLOR=$__WHITE PRINT "$@"; }
PROMPT() {
PREFIX="PROMPT " COLOR=$__CYAN PRINT "$@"
PREFIX="USER " COLOR=$__CYAN PRINT '' --no-line-end
ERROR() { # command encountered an error
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="ERROR " COLOR=$__RED PRINT "$@"
((ERRORS+=1))
return $ERRORS
}
FAIL() { ERROR "${@:2}"; exit $1; }
SUCCESS() { # command completed successfully
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="SUCCESS ✔" COLOR=$__GREEN PRINT "$@"
}
REMINDER() { # include sysadmin reminder or other important notice to users
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="REMINDER " COLOR=$__BRIGHT_MAGENTA PRINT "$@"
}
STATUS() { # general status updates (prefer this to generic 'echo')
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] \
&& PREFIX="STATUS " COLOR=$__BLUE PRINT "$@"
}
WARNING() { # warning-level messages; not errors
[[ $SCWRYPTS_LOG_LEVEL -ge 3 ]] \
&& PREFIX="WARNING " COLOR=$__YELLOW PRINT "$@"
}
DEBUG() { # helpful during development or (sparingly) to help others' development
[[ $SCWRYPTS_LOG_LEVEL -ge 4 ]] \
&& PREFIX="DEBUG " COLOR=$__WHITE PRINT "$@"
}
PROMPT() { # you probably want to use yN or INPUT from below
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="PROMPT " COLOR=$__CYAN PRINT "$@" \
&& PREFIX="USER ⌨" COLOR=$__BRIGHT_CYAN PRINT '' --no-line-end \
;
}
FAIL() { SCWRYPTS_LOG_LEVEL=1 ERROR "${@:2}"; exit $1; }
ABORT() { FAIL 69 'user abort'; }
#####################################################################
### check for reported errors and format USAGE contents #############
#####################################################################
CHECK_ERRORS() {
local FAIL_OUT=1
local FAIL_OUT=true
local DISPLAY_USAGE=true
[ ! $ERRORS ] && ERRORS=0
while [[ $# -gt 0 ]]
do
case $1 in
-n | --no-fail ) FAIL_OUT=0 ;;
--fail ) FAIL_OUT=true ;;
--no-fail ) FAIL_OUT=false ;;
--usage ) DISPLAY_USAGE=true ;;
--no-usage ) DISPLAY_USAGE=false ;;
esac
shift 1
done
[ ! $ERRORS ] && ERRORS=0
[[ $ERRORS -ne 0 ]] && USAGE
[[ $ERRORS -eq 0 ]] || {
[[ $FAIL_OUT -eq 1 ]] \
&& exit $ERRORS \
|| return $ERRORS
}
[[ $ERRORS -eq 0 ]] && return 0
[[ $DISPLAY_USAGE =~ true ]] && USAGE
[[ $FAIL_OUT =~ true ]] && exit $ERRORS || return $ERRORS
}
USAGE() {
[ ! $USAGE ] && return 0
USAGE=$(echo $USAGE | sed "s/^\t\+//; s/\s\+$//")
source "${0:a:h}/io.usage.zsh"
local USAGE_LINE=$(\
echo $USAGE \
| grep -i '^ *usage *:' \
| sed "s;^[^:]*:;& scwrypts $SCWRYPT_NAME --;" \
| sed 's/ \{2,\}/ /g; s/scwrypts -- scwrypts/scwrypts/' \
)
local THE_REST=$(echo $USAGE | grep -vi '^ *usage *:' | sed 'N;/^\n$/D;P;D;')
#####################################################################
### facilitate user prompt and input ################################
#####################################################################
{ echo; printf "$__DARK_BLUE $USAGE_LINE$__COLOR_RESET\n"; echo $THE_REST; echo } >&2
}
# yes/no prompts && = yes (exit code 0)
# || = no (exit code 1)
Yn() { [[ ! $(READ_YN $@ '[Yn]') =~ [nN] ]]; } # default 'yes'
yN() { [[ $(READ_YN $@ '[yN]') =~ [yY] ]]; } # default 'no'
INPUT() {
INPUT() { # read a single line of user input
PROMPT "${@:2}"
READ $1
local VALUE=$(eval echo '$'$1)
[ $VALUE ]
}
Yn() {
PROMPT "$@ [Yn]"
[ $CI ] && { echo y; return 0; }
source "${0:a:h}/io.fzf.zsh" # allow user to select from a list of inputs
local Yn; READ -k Yn; echo
[[ $Yn =~ [nN] ]] && return 1 || return 0
}
EDIT() { # edit a file in user's preferred editor
[ $CI ] && {
WARNING 'currently in CI, skipping EDIT'
return 0
}
yN() {
PROMPT "$@ [yN]"
[ $CI ] && { echo y; return 0; }
local yN; READ -k yN; echo
[[ $yN =~ [yY] ]] && return 0 || return 1
STATUS "opening '$1' for editing"
$EDITOR $@ </dev/tty >/dev/tty
SUCCESS "finished editing '$1'!"
}
#####################################################################
### basic commands with tricky states or default requirements #######
#####################################################################
LESS() { less -R $@ </dev/tty >/dev/tty; }
YQ() {
yq --version | grep -q mikefarah || {
yq $@
return $?
}
yq eval '... comments=""' | yq $@
}
#####################################################################
### other i/o utilities #############################################
#####################################################################
CAPTURE() {
[ ! $USAGE ] && USAGE="
usage: stdout-varname stderr-varname [...cmd and args...]
captures stdout and stderr on separate variables for a command
"
{
IFS=$'\n' read -r -d '' $2;
IFS=$'\n' read -r -d '' $1;
} < <((printf '\0%s\0' "$(${@:3})" 1>&2) 2>&1)
}
GETSUDO() {
echo "\\033[1;36mPROMPT  : checking sudo password...\\033[0m" >&2
@ -120,45 +146,85 @@ GETSUDO() {
|| { ERROR 'failed :c'; return 1; }
}
LESS() { less -R $@ </dev/tty >/dev/tty; }
FZF() {
[ $CI ] && {
ERROR 'currently in CI, but FZF requires user input'
exit 1
}
local FZF_ARGS=()
FZF_ARGS+=(-i)
FZF_ARGS+=(--ansi)
FZF_ARGS+=(--bind=ctrl-c:cancel)
FZF_ARGS+=(--height=50%)
FZF_ARGS+=(--layout=reverse)
local SELECTION=$(fzf ${FZF_ARGS[@]} --layout=reverse --prompt "$1 : " ${@:2})
PROMPT "$1"
echo $SELECTION >&2
echo $SELECTION
}
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
READ() {
[ $CI ] && {
INFO 'currently in CI, skipping READ'
return 0
}
read $@ </dev/tty
[ $CI ] && [ -t 0 ] \
&& FAIL 42 'currently in CI, but attempting interactive read; aborting'
local FORCE_USER_INPUT=false
local ARGS=()
while [[ $# -gt 0 ]]
do
case $1 in
--force-user-input ) FORCE_USER_INPUT=true ;;
-k )
ARGS+=($1)
;;
* ) ARGS+=($1) ;;
esac
shift 1
done
while read -k -t 0; do :; done; # flush user stdin
case $FORCE_USER_INPUT in
true )
read ${PREARGS[@]} ${ARGS[@]} $@ </dev/tty
;;
false )
[ -t 0 ] || ARGS=(-u 0 ${ARGS[@]})
read ${ARGS[@]} $@
;;
esac
}
EDIT() {
[ $CI ] && {
INFO 'currently in CI, skipping EDIT'
return 0
}
READ_YN() { # yes/no read is suprisingly tricky
local FORCE_USER_INPUT=false
local USERPROMPT=()
local READ_ARGS=()
STATUS "opening '$1' for editing"
$EDITOR $@ </dev/tty >/dev/tty
SUCCESS "finished editing '$1'!"
while [[ $# -gt 0 ]]
do
case $1 in
--force-user-input )
# overrides 'scwrypts -y' and stdin pipe but not CI
FORCE_USER_INPUT=true
READ_ARGS+=($1)
;;
* ) USERPROMPT+=($1) ;;
esac
shift 1
done
##########################################
local SKIP_USER_INPUT=false
[ $CI ] \
&& SKIP_USER_INPUT=true
[ $__SCWRYPTS_YES ] && [[ $__SCWRYPTS_YES -eq 1 ]] && [[ $FORCE_USER_INPUT =~ false ]] \
&& SKIP_USER_INPUT=true
##########################################
local yn
PROMPT "${USERPROMPT[@]}"
case $SKIP_USER_INPUT in
true ) yn=y ;;
false )
[[ $FORCE_USER_INPUT =~ true ]] && [[ $SCWRYPTS_LOG_LEVEL -lt 1 ]] \
&& echo -n "${USERPROMPT[@]} : " >&2
READ ${READ_ARGS[@]} -s -k yn
[[ $FORCE_USER_INPUT =~ true ]] && [[ $SCWRYPTS_LOG_LEVEL -lt 1 ]] \
&& echo $yn >&2
;;
esac
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] && echo $yn >&2
echo $yn
}

View File

@ -18,6 +18,18 @@ source ${0:a:h}/environment.zsh
#####################################################################
CHECK_ENVIRONMENT() {
local OPTIONAL=0
while [[ $# -gt 0 ]]
do
case $1 in
--optional ) OPTIONAL=1 ;;
esac
shift 1
done
[[ $OPTIONAL -eq 1 ]] && E=WARNING || E=ERROR
local ENVIRONMENT_STATUS=0
__CHECK_DEPENDENCIES $DEPENDENCIES
@ -55,9 +67,9 @@ CHECK_ENVIRONMENT() {
##########################################
[[ ENVIRONMENT_STATUS -eq 0 ]] || {
[[ ENVIRONMENT_STATUS -ne 0 ]] && [[ $OPTIONAL -eq 0 ]] && {
ERROR_MESSAGE=$(echo $ERROR_MESSAGE | sed '1d; s/^/ /')
ERROR "environment errors found (see above)\n$ERROR_MESSAGE"
$E "environment errors found (see above)\n$ERROR_MESSAGE"
}
[[ $MISSING_ENVIRONMENT_VARIABLES -ne 0 ]] && {
@ -67,10 +79,11 @@ CHECK_ENVIRONMENT() {
"
}
[[ $ENVIRONMENT_STATUS -eq 0 ]] || {
[[ $NO_EXIT -eq 1 ]] && return $ENVIRONMENT_STATUS
[[ $ENVIRONMENT_STATUS -ne 0 ]] && [[ $NO_EXIT -ne 1 ]] && [[ $OPTIONAL -eq 0 ]] && {
exit $ENVIRONMENT_STATUS
}
return $ENVIRONMENT_STATUS
}
CHECK_ENVIRONMENT

View File

@ -1,16 +1,11 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use media/youtube
CHECK_ENVIRONMENT
#####################################################################
DOWNLOAD_VIDEO() {
MAIN() {
local URLS=($@)
[[ ${#URLS[@]} -eq 0 ]] && URLS=($(echo '' | FZF_HEAD 'enter URL'))
[[ ${#URLS[@]} -eq 0 ]] && URLS=($(echo '' | FZF_USER_INPUT 'enter URL'))
[[ ${#URLS[@]} -eq 0 ]] && ABORT
local FILENAME=$(YT__GET_FILENAME $URLS)
@ -23,6 +18,3 @@ DOWNLOAD_VIDEO() {
&& SUCCESS "downloaded to '$YT__OUTPUT_DIR/$FILENAME'" \
|| { ERROR "failed to download '$FILENAME'"; return 2; }
}
#####################################################################
DOWNLOAD_VIDEO $@

View File

@ -1,16 +1,11 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use media/youtube
CHECK_ENVIRONMENT
#####################################################################
GET_AUDIO_CLIP() {
MAIN() {
local URLS=($@)
[[ ${#URLS[@]} -eq 0 ]] && URLS=($(echo '' | FZF_HEAD 'enter URL'))
[[ ${#URLS[@]} -eq 0 ]] && URLS=($(echo '' | FZF_USER_INPUT 'enter URL'))
[[ ${#URLS[@]} -eq 0 ]] && ABORT
local FILENAME=$(YT__GET_FILENAME $URLS)
@ -26,9 +21,9 @@ GET_AUDIO_CLIP() {
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=$(echo 0 | FZF_USER_INPUT "enter start time (0 ≤ t < $LENGTH)")
[ ! $START_TIME ] && ABORT
END_TIME=$(echo $LENGTH | FZF_HEAD "enter end time ($START_TIME > t ≥ $LENGTH)")
END_TIME=$(echo $LENGTH | FZF_USER_INPUT "enter end time ($START_TIME > t ≥ $LENGTH)")
[ ! $END_TIME ] && ABORT
STATUS
@ -37,7 +32,7 @@ GET_AUDIO_CLIP() {
STATUS "end time : $END_TIME"
STATUS
OUTPUT_FILE=$(echo '' \
| FZF_HEAD 'what should I call this clip? (.mp3)' \
| FZF_USER_INPUT 'what should I call this clip? (.mp3)' \
| sed 's/\.mp3$//' \
)
[ ! $OUTPUT_FILE ] && ABORT
@ -49,6 +44,3 @@ GET_AUDIO_CLIP() {
&& SUCCESS "created clip '$OUTPUT_FILE'" \
|| { ERROR "error creating clip '$(basename $OUTPUT_FILE)' (see above)"; return 3; }
}
#####################################################################
GET_AUDIO_CLIP $@

8
zsh/misc/tally Executable file
View File

@ -0,0 +1,8 @@
#!/bin/zsh
use misc/tally
#####################################################################
MAIN() {
unset USAGE
TALLY $@
}

View File

@ -1,13 +1,8 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use office/latex
CHECK_ENVIRONMENT
#####################################################################
PDFLATEX() {
MAIN() {
[ ! $1 ] && FAIL 1 'must provide filename'
local FILENAME=$(LATEX__GET_MAIN_FILENAME "$1")
@ -26,6 +21,3 @@ PDFLATEX() {
SUCCESS "created '$(echo $FILENAME | sed 's/\.[^.]*$/.pdf/')'"
}
#####################################################################
PDFLATEX $@

View File

@ -1,14 +1,9 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use office/latex
CHECK_ENVIRONMENT
#####################################################################
CLEAN_LATEX_LOGFILES() {
local DIRECTORY=$(SCWRYPTS__GET_PATH_TO_RELATIVE_ARGUMENT ".")
MAIN() {
local DIRECTORY=$(SCWRYPTS__GET_REALPATH ".")
[ $1 ] && DIRECTORY="$(dirname "$(LATEX__GET_MAIN_FILENAME "$1")")"
[ $DIRECTORY ] && [ -d $DIRECTORY ] \
|| FAIL 1 'unable to parse valid directory'
@ -18,6 +13,3 @@ CLEAN_LATEX_LOGFILES() {
SUCCESS "cleaned up latex artifacts in '$DIRECTORY'"
}
#####################################################################
CLEAN_LATEX_LOGFILES $@

View File

@ -1,15 +1,10 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use office/latex
CHECK_ENVIRONMENT
#####################################################################
TEMPLATE_DIR="${0:a:h}/templates"
CREATE_NEW_LATEX_DOCUMENT_FROM_TEMPLATE() {
MAIN() {
local DOCUMENT_DIR="$EXECUTION_DIR"
local TEMPLATE=$(GET_TEMPLATES | FZF 'select a template')
[ ! $TEMPLATE ] && ABORT
@ -39,6 +34,8 @@ CREATE_NEW_LATEX_DOCUMENT_FROM_TEMPLATE() {
SUCCESS "finished generating '$(basename $DOCUMENT_FILE)' from '$TEMPLATE'"
}
#####################################################################
GET_TEMPLATES() {
find "$TEMPLATE_DIR" -type d | sed "s^$TEMPLATE_DIR/*^^; /^$/d"
}
@ -59,4 +56,4 @@ SLUGIFY_TITLE() {
}
#####################################################################
CREATE_NEW_LATEX_DOCUMENT_FROM_TEMPLATE $@
MAIN $@

View File

@ -1,10 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use office/latex
CHECK_ENVIRONMENT
#####################################################################
LATEX__GET_PDF $@
MAIN() {
LATEX__GET_PDF $@
}

View File

@ -1,18 +1,10 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use office/latex
CHECK_ENVIRONMENT
#####################################################################
OPEN_PDF() {
MAIN() {
local PDF=$(LATEX__GET_PDF $@)
[ ! $PDF ] && return 1
OPEN "$PDF"
}
#####################################################################
OPEN_PDF $@

View File

@ -1,14 +1,9 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use office/memo
CHECK_ENVIRONMENT
#####################################################################
OPEN_MEMO() {
local MEMO_NAME=$(MEMO__LIST_ALL | FZF_TAIL 'select/create a memo')
MAIN() {
local MEMO_NAME=$(MEMO__LIST_ALL | FZF_USER_INPUT 'select/create a memo')
[ ! "$MEMO_NAME" ] && ABORT
MEMO_FILE="$MEMO__DIR/$MEMO_NAME.$MEMO__FILETYPE"
@ -26,6 +21,3 @@ OPEN_MEMO() {
EDIT "$MEMO_FILE"
}
#####################################################################
OPEN_MEMO $@

View File

@ -1,13 +1,8 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use office/memo
CHECK_ENVIRONMENT
#####################################################################
DELETE_MEMO() {
MAIN() {
local MEMO_NAME=$(MEMO__LIST_ALL | FZF 'select a memo to delete')
local MEMO_FILE="$MEMO__DIR/$MEMO_NAME.$MEMO__FILETYPE"
[ "$MEMO_NAME" ] && [ -f "$MEMO_FILE" ] || ABORT
@ -28,6 +23,3 @@ DELETE_MEMO() {
|| FAIL 1 "failed to remove memo '$MEMO_NAME'" \
;
}
#####################################################################
DELETE_MEMO $@

View File

@ -1,13 +1,8 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use redis
CHECK_ENVIRONMENT
#####################################################################
CURL_WITH_CACHE() {
MAIN() {
[ ! $TTL ] && TTL=10
[[ $(REDIS__ENABLED) -eq 0 ]] && {
@ -46,7 +41,6 @@ CURL_WITH_CACHE() {
echo $OUTPUT
}
GET_URL_KEY() { echo "scwrypts:curl:$1" | sed 's/\s\+/+/g'; }
#####################################################################
CURL_WITH_CACHE $@
GET_URL_KEY() { echo "scwrypts:curl:$1" | sed 's/\s\+/+/g'; }

52
zsh/sanity-check Executable file
View File

@ -0,0 +1,52 @@
#!/bin/zsh
#####################################################################
USAGE__options='
-e, --exit-code desired exit code of the function (default "0")
-f, --output-function one of the zsh/utils output functions (default "SUCCESS")
-m, --message a message to display (default "Hello, World!")
'
USAGE__description='
a simple hello-world-style script which allows specific scwrypts
conditions to be quickly emulated
'
#####################################################################
MAIN() {
local OUTPUT_FUNCTION=SUCCESS
local EXIT_CODE=0
local MESSAGE='Hello, world!'
ARGUMENT_REQUIRED() { ERROR "'$1' requires an argument"; }
while [[ $# -gt 0 ]]
do
case $1 in
-e | --exit-code )
EXIT_CODE="$2"
[ $2 ] && shift 1 || ARGUMENT_REQUIRED
;;
-f | --output-function )
OUTPUT_FUNCTION="$2"
[ $2 ] && shift 1 || ARGUMENT_REQUIRED
;;
-m | --message )
MESSAGE="$2"
[ $2 ] && shift 1 || ARGUMENT_REQUIRED
;;
* ) ERROR "unknown argument '$1'" ;;
esac
shift 1
done
CHECK_ERRORS
##########################################
[[ $OUTPUT_FUNCTION =~ ^FAIL$ ]] && FAIL $EXIT_CODE "$MESSAGE"
$OUTPUT_FUNCTION "$MESSAGE"
return $EXIT_CODE
}

View File

@ -1,36 +1,33 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use scwrypts/meta
CHECK_ENVIRONMENT
#####################################################################
USER_CONFIG_OVERRIDES="$SCWRYPTS_CONFIG_PATH/config.zsh"
MAIN() {
local USER_CONFIG_OVERRIDES="$SCWRYPTS_CONFIG_PATH/config.zsh"
[ ! -f "$USER_CONFIG_OVERRIDES" ] && {
STATUS 'first-time setup detected; creating local configuration override...'
cp "$DEFAULT_CONFIG" "$USER_CONFIG_OVERRIDES"
[ ! -f "$USER_CONFIG_OVERRIDES" ] && {
STATUS 'first-time setup detected; creating local configuration override...'
cp "$DEFAULT_CONFIG" "$USER_CONFIG_OVERRIDES"
EDIT $USER_CONFIG_OVERRIDES
EDIT $USER_CONFIG_OVERRIDES
STATUS 'attempting first-time build for virtual environments'
SCWRYPTS__RUN --name scwrypts/virtualenv/update-all --group scwrypts --type zsh \
&& SUCCESS 'finished updating virtualenvs' \
|| WARNING 'unable to create one or more virtualenv (see above)' \
;
STATUS 'attempting first-time build for virtual environments'
SCWRYPTS__RUN --name scwrypts/virtualenv/update-all --group scwrypts --type zsh \
&& SUCCESS 'finished updating virtualenvs' \
|| WARNING 'unable to create one or more virtualenv (see above)' \
;
REMINDER '
in the future, you can use the following scwrypt to update required virtual
environments (equivalent to "npm install" or "pip install -r requirements"):
REMINDER '
in the future, you can use the following scwrypt to update required virtual
environments (equivalent to "npm install" or "pip install -r requirements"):
scwrypts --name scwrypts/virtualenv/update-all --group scwrypts --type zsh
'
} || {
EDIT "$USER_CONFIG_OVERRIDES"
scwrypts --name scwrypts/virtualenv/update-all --group scwrypts --type zsh
'
} || {
EDIT "$USER_CONFIG_OVERRIDES"
}
SUCCESS 'saved new configuration'
REMINDER 'changes which affect the hot-key plugin will require a ZSHRC reload'
}
SUCCESS 'saved new configuration'
REMINDER 'changes which affect the hot-key plugin will require a ZSHRC reload'

View File

@ -1,38 +1,35 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use scwrypts/environment-files
CHECK_ENVIRONMENT
#####################################################################
PROMPT 'choose an environment to copy'
TEMPLATE_ENV_NAME=$(SCWRYPTS__SELECT_ENV)
[ ! $TEMPLATE_ENV_NAME ] && ABORT
MAIN() {
PROMPT 'choose an environment to copy'
TEMPLATE_ENV_NAME=$(SCWRYPTS__SELECT_ENV)
[ ! $TEMPLATE_ENV_NAME ] && ABORT
STATUS "selected '$TEMPLATE_ENV_NAME'"
STATUS "selected '$TEMPLATE_ENV_NAME'"
PROMPT 'enter new environment name'
ENV_NAME=$(echo '' | FZF_HEAD 'new environment')
[ ! $ENV_NAME ] && ABORT
SCWRYPTS__GET_ENV_NAMES | grep -q $ENV_NAME && FAIL 1 "'$ENV_NAME' already exists"
PROMPT 'enter new environment name'
ENV_NAME=$(echo '' | FZF_USER_INPUT 'new environment')
[ ! $ENV_NAME ] && ABORT
SCWRYPTS__GET_ENV_NAMES | grep -q $ENV_NAME && FAIL 1 "'$ENV_NAME' already exists"
for GROUP in ${SCWRYPTS_GROUPS[@]}
do
TEMPLATE_ENV_FILE=$(SCWRYPTS__GET_ENV_FILE $TEMPLATE_ENV_NAME $GROUP 2>/dev/null)
ENV_FILE=$(SCWRYPTS__GET_ENV_FILE $ENV_NAME $GROUP 2>/dev/null)
for GROUP in ${SCWRYPTS_GROUPS[@]}
do
TEMPLATE_ENV_FILE=$(SCWRYPTS__GET_ENV_FILE $TEMPLATE_ENV_NAME $GROUP 2>/dev/null)
ENV_FILE=$(SCWRYPTS__GET_ENV_FILE $ENV_NAME $GROUP 2>/dev/null)
STATUS "creating environment '$ENV_NAME'"
cat "$TEMPLATE_ENV_FILE" \
| sed 's/ # from.*//' \
> "$ENV_FILE" \
&& SUCCESS "created '$ENV_FILE'" \
|| FAIL 2 "something went wrong creating '$ENV_FILE'"
done
STATUS "creating environment '$ENV_NAME'"
cat "$TEMPLATE_ENV_FILE" \
| sed 's/ # from.*//' \
> "$ENV_FILE" \
&& SUCCESS "created '$ENV_FILE'" \
|| FAIL 2 "something went wrong creating '$ENV_FILE'"
done
STATUS "synchronizing environments"
SCWRYPTS__RUN --name scwrypts/environment/synchronize --group scwrypts --type zsh -- --no-prompt \
&& SUCCESS "finished copy environment '$TEMPLATE_ENV_NAME > $ENV_NAME'" \
|| FAIL 3 'error during synchronization of new environment (see above)' \
;
STATUS "synchronizing environments"
SCWRYPTS__RUN --name scwrypts/environment/synchronize --group scwrypts --type zsh -- --no-prompt \
&& SUCCESS "finished copy environment '$TEMPLATE_ENV_NAME > $ENV_NAME'" \
|| FAIL 3 'error during synchronization of new environment (see above)' \
;
}

View File

@ -1,36 +1,33 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use scwrypts/environment-files
CHECK_ENVIRONMENT
#####################################################################
PROMPT 'choose an environment to delete'
ENV_NAME=$(SCWRYPTS__SELECT_ENV)
[ ! $ENV_NAME ] && ABORT
MAIN() {
PROMPT 'choose an environment to delete'
ENV_NAME=$(SCWRYPTS__SELECT_ENV)
[ ! $ENV_NAME ] && ABORT
ENV_FILES=($(SCWRYPTS__GET_ENV_FILES $ENV_NAME))
ENV_FILES=($(SCWRYPTS__GET_ENV_FILES $ENV_NAME))
STATUS "preparing to remove '$ENV_NAME'"
STATUS "preparing to remove '$ENV_NAME'"
WARNING "
the '$ENV_NAME' environment will be removed configured options
and stored credentials will be lost forever:
WARNING "
the '$ENV_NAME' environment will be removed configured options
and stored credentials will be lost forever:
$(echo $ENV_FILES | sed 's| /|\n - /|g; s/^/ - /')
"
$(echo $ENV_FILES | sed 's| /|\n - /|g; s/^/ - /')
"
yN 'continue?' || ABORT
yN 'continue?' || ABORT
STATUS "removing environment"
for ENV_FILE in ${ENV_FILES[@]}
do
rm "$ENV_FILE" \
&& SUCCESS "removed '$ENV_FILE'" \
|| ERROR "unable to remove '$ENV_FILE'; is it protected?" \
;
done
STATUS "removing environment"
for ENV_FILE in ${ENV_FILES[@]}
do
rm "$ENV_FILE" \
&& SUCCESS "removed '$ENV_FILE'" \
|| ERROR "unable to remove '$ENV_FILE'; is it protected?" \
;
done
CHECK_ERRORS -n || FAIL 2 "some errors ocurred when cleaning up $ENV_NAME"
CHECK_ERRORS -n || FAIL 2 "some errors ocurred when cleaning up $ENV_NAME"
}

View File

@ -1,45 +1,42 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use scwrypts/environment-files
CHECK_ENVIRONMENT
#####################################################################
[ $1 ] && ENV_NAME="$1"
MAIN() {
[ $1 ] && ENV_NAME="$1"
[ ! $1 ] && {
[ $SCWRYPTS_ENV ] \
&& ENV_NAME=$SCWRYPTS_ENV \
|| ENV_NAME=$(SCWRYPTS__SELECT_OR_CREATE_ENV)
}
[ ! $ENV_NAME ] && ABORT
ENV_FILES=($(SCWRYPTS__GET_ENV_FILES $ENV_NAME 2>/dev/null))
for ENV_FILE in ${ENV_FILES[@]}
do
[ ! -f "$ENV_FILE" ] && {
STATUS "Creating '$ENV_FILE'..." \
&& mkdir -p "$(dirname "$ENV_FILE")" \
&& touch "$ENV_FILE" \
&& ((CREATED+=1)) \
&& SUCCESS "created '$ENV_NAME'" \
|| { ERROR "failed to create '$ENV_FILE'"; exit 1; }
[ ! $1 ] && {
[ $SCWRYPTS_ENV ] \
&& ENV_NAME=$SCWRYPTS_ENV \
|| ENV_NAME=$(SCWRYPTS__SELECT_OR_CREATE_ENV)
}
[ ! $ENV_NAME ] && ABORT
[ $CREATED ] && [[ $CREATED -gt 0 ]] && {
STATUS "detected new environment files; performing sync" \
&& SCWRYPTS__RUN --name scwrypts/environment/synchronize --group scwrypts --type zsh -- --no-prompt \
|| FAIL 1 "failure during sync for '$ENV_NAME'" \
}
ENV_FILES=($(SCWRYPTS__GET_ENV_FILES $ENV_NAME 2>/dev/null))
for ENV_FILE in ${ENV_FILES[@]}
do
[ ! -f "$ENV_FILE" ] && {
STATUS "Creating '$ENV_FILE'..." \
&& mkdir -p "$(dirname "$ENV_FILE")" \
&& touch "$ENV_FILE" \
&& ((CREATED+=1)) \
&& SUCCESS "created '$ENV_NAME'" \
|| { ERROR "failed to create '$ENV_FILE'"; exit 1; }
}
[ $CREATED ] && [[ $CREATED -gt 0 ]] && {
STATUS "detected new environment files; performing sync" \
&& SCWRYPTS__RUN --name scwrypts/environment/synchronize --group scwrypts --type zsh -- --no-prompt \
|| FAIL 1 "failure during sync for '$ENV_NAME'" \
}
;
done
EDIT $ENV_FILES
SCWRYPTS__RUN --name scwrypts/environment/synchronize --group scwrypts --type zsh -- --no-prompt \
|| FAIL 4 'failed to run environment sync' \
;
done
EDIT $ENV_FILES
SCWRYPTS__RUN --name scwrypts/environment/synchronize --group scwrypts --type zsh -- --no-prompt \
|| FAIL 4 'failed to run environment sync' \
;
SUCCESS "environment '$ENV_NAME' successfully modified"
SUCCESS "environment '$ENV_NAME' successfully modified"
}

View File

@ -1,13 +1,8 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use scwrypts/environment-files
CHECK_ENVIRONMENT
#####################################################################
SYNCHRONIZE() {
MAIN() {
while [[ $# -gt 0 ]]
do
case $1 in
@ -176,4 +171,4 @@ CLEANUP_ENVIRONMENT_FILE() {
rm "$1.temp"
}
#####################################################################
#####################################################################

View File

@ -1,22 +1,20 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
CHECK_ENVIRONMENT
#####################################################################
cd $SCWRYPTS_ROOT
MAIN() {
cd $SCWRYPTS_ROOT
STATUS "Found $(ls $SCWRYPTS_LOG_PATH | wc -l) log files"
WARNING "
this will permanently clear all local cloud script logs found in
'$SCWRYPTS_LOG_PATH'
"
STATUS "Found $(ls $SCWRYPTS_LOG_PATH | wc -l) log files"
WARNING "
this will permanently clear all local cloud script logs found in
'$SCWRYPTS_LOG_PATH'
"
yN 'continue?' || ABORT
yN 'continue?' || ABORT
STATUS 'removing logfiles'
rm -rf $SCWRYPTS_LOG_PATH/* \
&& SUCCESS 'done' \
|| { ERROR 'failed :c'; exit 2; }\
;
STATUS 'removing logfiles'
rm -rf $SCWRYPTS_LOG_PATH/* \
&& SUCCESS 'done' \
|| { ERROR 'failed :c'; exit 2; }\
;
}

View File

@ -1,15 +1,13 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
CHECK_ENVIRONMENT
#####################################################################
cd $SCWRYPTS_ROOT
PROMPT 'select a script log'
LOG_FILE=$(ls -t $SCWRYPTS_LOG_PATH | FZF 'logfile')
[ ! $LOG_FILE ] && { ERROR 'user abort'; exit 1; }
MAIN() {
cd $SCWRYPTS_ROOT
PROMPT 'select a script log'
LOG_FILE=$(ls -t $SCWRYPTS_LOG_PATH | FZF 'logfile')
[ ! $LOG_FILE ] && { ERROR 'user abort'; exit 1; }
STATUS 'opening logfile'
LESS "$SCWRYPTS_LOG_PATH/$LOG_FILE"
SUCCESS 'done'
STATUS 'opening logfile'
LESS "$SCWRYPTS_LOG_PATH/$LOG_FILE"
SUCCESS 'done'
}

View File

@ -1,30 +1,27 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use scwrypts/virtualenv
CHECK_ENVIRONMENT
#####################################################################
while [[ $# -gt 0 ]]
do
case $1 in
-g | --group ) ENV_GROUP="$2"; shift 1 ;;
esac
shift 1
done
MAIN() {
while [[ $# -gt 0 ]]
do
case $1 in
-g | --group ) ENV_GROUP="$2"; shift 1 ;;
esac
shift 1
done
[ ! $ENV_GROUP ] && ENV_GROUP=scwrypts
[ ! $ENV_GROUP ] && ENV_GROUP=scwrypts
ENV_TYPE=$(echo $AVAILABLE_VIRTUALENVS | sed 's/ \+/\n/' | FZF 'select an environment to refresh')
[ ! $ENV_TYPE ] && ABORT
ENV_TYPE=$(echo $AVAILABLE_VIRTUALENVS | sed 's/ \+/\n/' | FZF 'select an environment to refresh')
[ ! $ENV_TYPE ] && ABORT
REMINDER "
this will permanently remove all artifacts for the scwrypts $ENV_TYPE environment
(safe unless you have put something important in $(GET_VIRTUALENV_PATH $ENV_GROUP $ENV_TYPE))
"
REMINDER "
this will permanently remove all artifacts for the scwrypts $ENV_TYPE environment
(safe unless you have put something important in $(GET_VIRTUALENV_PATH $ENV_GROUP $ENV_TYPE))
"
Yn "drop and recreate $ENV_TYPE virtual environment?" || ABORT
Yn "drop and recreate $ENV_TYPE virtual environment?" || ABORT
REFRESH_VIRTUALENV $ENV_GROUP $ENV_TYPE
REFRESH_VIRTUALENV $ENV_GROUP $ENV_TYPE
}

View File

@ -1,25 +1,21 @@
#!/bin/zsh
echo hey
DEPENDENCIES+=()
REQUIRED_ENV+=()
use scwrypts/virtualenv
CHECK_ENVIRONMENT
#####################################################################
STATUS 'beginning update for all environments'
MAIN() {
STATUS 'beginning update for all environments'
FAILED_COUNT=0
FAILED_COUNT=0
for ENV_GROUP in ${SCWRYPTS_GROUPS[@]}
do
for ENV_TYPE in ${AVAILABLE_VIRTUALENVS[@]}
for ENV_GROUP in ${SCWRYPTS_GROUPS[@]}
do
UPDATE_VIRTUALENV $ENV_GROUP $ENV_TYPE || ((FAILED_COUNT+=1))
for ENV_TYPE in ${AVAILABLE_VIRTUALENVS[@]}
do
UPDATE_VIRTUALENV $ENV_GROUP $ENV_TYPE || ((FAILED_COUNT+=1))
done
done
done
[[ $FAILED_COUNT -eq 0 ]] \
&& SUCCESS 'all environments up-to-date' \
|| FAIL $FAILED_COUNT 'failed to update one or more environments'
[[ $FAILED_COUNT -eq 0 ]] \
&& SUCCESS 'all environments up-to-date' \
|| FAIL $FAILED_COUNT "failed to update $FAILED_COUNT more environment(s)"
}

View File

@ -1,9 +1,7 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use system/config
CHECK_ENVIRONMENT
#####################################################################
EDIT "$CONFIG__USER_SETTINGS"
MAIN() {
EDIT "$CONFIG__USER_SETTINGS"
}

View File

@ -1,19 +1,16 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use system/config
CHECK_ENVIRONMENT
#####################################################################
SETUP_SYMLINKS() {
MAIN() {
while read SYMLINK
do
SETUP_SYMLINK $(echo $SYMLINK | awk '{print $1;}') $(echo $SYMLINK | awk '{print $2}')
done < <(echo $SYMLINKS | sed -n '/^[^#]/p')
}
#####################################################################
SETUP_SYMLINK() {
[ ! $2 ] && FAIL 1 'must provide SOURCE_CONFIG and TARGET_CONFIG'
@ -21,7 +18,7 @@ SETUP_SYMLINK() {
local TARGET_CONFIG="$HOME/.config/$2"
[ ! -f "$SOURCE_CONFIG" ] && [ ! -d "$SOURCE_CONFIG" ] && [ -f "$TARGET_CONFIG" ] && {
INFO 'SOURCE_CONFIG is not tracked; copying from TARGET_CONFIG'
DEBUG 'SOURCE_CONFIG is not tracked; copying from TARGET_CONFIG'
mkdir -p "$(dirname "$SOURCE_CONFIG")"
cp "$TARGET_CONFIG" "$SOURCE_CONFIG"
}
@ -42,6 +39,3 @@ SETUP_SYMLINK() {
|| FAIL 3 "failed to create link '$TARGET_CONFIG'" \
;
}
#####################################################################
SETUP_SYMLINKS $@

View File

@ -1,13 +1,10 @@
#!/bin/zsh
DEPENDENCIES+=(tic)
REQUIRED_ENV+=()
use system/config
CHECK_ENVIRONMENT
#####################################################################
SETUP_TERMINFO() {
MAIN() {
[ ! $TERMINFO_PATH ] && return 0
[ ! -d $TERMINFO_PATH ] && FAIL 1 "TERMINFO_PATH='$TERMINFO_PATH' does not exist"
@ -22,6 +19,3 @@ SETUP_TERMINFO() {
CHECK_ERRORS
}
#####################################################################
SETUP_TERMINFO $@

View File

@ -1,13 +1,10 @@
#!/bin/zsh
DEPENDENCIES+=()
REQUIRED_ENV+=()
use scwrypts/meta
CHECK_ENVIRONMENT
#####################################################################
STATUS 'updating all config files and links'
SCWRYPTS__RUN --name system/config/symlinks --group scwrypts --type zsh || exit 1
SCWRYPTS__RUN --name system/config/terminfo --group scwrypts --type zsh || exit 2
SUCCESS 'finished updating config files and links'
MAIN() {
STATUS 'updating all config files and links'
SCWRYPTS__RUN --name system/config/symlinks --group scwrypts --type zsh || exit 1
SCWRYPTS__RUN --name system/config/terminfo --group scwrypts --type zsh || exit 2
SUCCESS 'finished updating config files and links'
}

View File

@ -1,102 +0,0 @@
#!/bin/zsh
DEPENDENCIES+=(
diff
)
REQUIRED_ENV+=(
I3__MODEL_CONFIG
)
CHECK_ENVIRONMENT
#####################################################################
REGEX_FONT='^\(font [^0-9]*\)\(.*\)'
REGEX_DMENU="^\\(.*dmenu_run .*-fn '[^0-9]*\\)\\([0-9]*\\)'"
REGEX_BORDER='^\(for_window.*border pixel \)\(.*\)'
INSTALL() {
local USAGE="
usage: [...options...]
options
-f, --force force replacement of existing i3config
-n, --no-link if output config and template are the same, don't create link
-h, --help print this message and exit
environment
I3__MODEL_CONFIG fully-qualified path to sourced i3config
I3__GLOBAL_FONT_SIZE global font size
I3__DMENU_FONT_SIZE (optional) font size for 'dmenu' command
I3__BORDER_PIXEL_SIZE (optional) pixel-width of window borders
I3 provides no way to include dynamic variables in your config.
The main difference I want between my i3 configurations is font-size
to match the current monitor. Since i3-msg provides no way to change
font size, I run this command to update those variables on a local
copy of my sourced config
"
local FORCE=0
local AUTOLINK=1
while [[ $# -gt 0 ]]
do
case $1 in
-f | --force ) FORCE=1 ;;
-n | --no-link ) AUTOLINK=0 ;;
-h | --help ) USAGE; exit 0 ;;
esac
shift 1
done
STATUS 'reading local i3config'
[[ ^$I3__MODEL_CONFIG$ =~ ^$HOME/.config/i3/config$ ]] && {
STATUS "model configuration is default configuration"
I3__MODEL_CONFIG="$I3__MODEL_CONFIG.template"
[ ! -f "$I3__MODEL_CONFIG" ] && {
STATUS "creating template"
cp "$HOME/.config/i3/config" "$I3__MODEL_CONFIG.template"
}
STATUS "referring to '$I3__MODEL_CONFIG'"
}
local CONFIG=$(cat "$I3__MODEL_CONFIG")
[ ! $CONFIG ] && FAIL 1 "failed to read config at '$I3__MODEL_CONFIG'"
local CONFIG_FILE="$HOME/.config/i3/config"
[ ! -d $(dirname "$CONFIG_FILE") ] && mkdir -p "$(dirname "$CONFIG_FILE")"
[ -f "$CONFIG_FILE" ] && mv "$CONFIG_FILE" "$CONFIG_FILE.bak"
[ $I3__GLOBAL_FONT_SIZE ] && {
STATUS "setting global font size to '$I3__GLOBAL_FONT_SIZE'"
CONFIG=$(echo $CONFIG | sed "s/$REGEX_FONT/\\1$I3__GLOBAL_FONT_SIZE/")
}
[ $I3__DMENU_FONT_SIZE ] && {
STATUS "setting dmenu font size to '$I3__DMENU_FONT_SIZE'"
CONFIG=$(echo $CONFIG | sed "s/$REGEX_DMENU/\\1$I3__DMENU_FONT_SIZE'/")
}
[ $I3__BORDER_PIXEL_SIZE ] && {
STATUS "setting border pixel size to '$I3__BORDER_PIXEL_SIZE'"
CONFIG=$(echo $CONFIG | sed "s/$REGEX_BORDER/\\1$I3__BORDER_PIXEL_SIZE/")
}
echo $CONFIG > "$CONFIG_FILE"
[ -f "$CONFIG_FILE.bak" ] \
&& diff "$CONFIG_FILE" "$CONFIG_FILE.bak" -q >/dev/null \
&& mv "$CONFIG_FILE.bak" "$CONFIG_FILE" \
&& INFO "no changes were made" \
;
[[ $AUTOLINK -eq 1 ]] \
&& diff "$CONFIG_FILE" "$I3__MODEL_CONFIG" -q >/dev/null \
&& rm "$CONFIG_FILE" \
&& ln -s "$I3__MODEL_CONFIG" "$CONFIG_FILE" \
&& INFO "output is the same as model, i3config has been linked to model" \
;
[[ $FORCE -eq 1 ]] && rm "$CONFIG.bak" >/dev/null 2>&1
return 0
}
#####################################################################
INSTALL $@

View File

@ -1,136 +0,0 @@
#!/bin/zsh
DEPENDENCIES+=(
i3-msg
xdotool
xrandr
)
REQUIRED_ENV+=()
use system/desktop/notify
CHECK_ENVIRONMENT
#####################################################################
LAUNCH_OR_SHOW() {
INFO $@
local USAGE="
usage: <path-executable> [client-class] [...options...]
options
-c, --client <string> if different from the executable name, xprop CLIENT_CLASS
-s, --scale <value> (default: 0.8 or 0.5 if screen width >3000px)
-x, --x-offset <value> (default: 0.0)
-y, --y-offset <value> (default: 0.0)
-a, --always-launch invoke executable even if client-class exists
-n, --no-resize don't resize the window (ignores -sxy flags)
-l, --no-center leave the window wherever it was last positioned
--has-statusbar-icon (default: false) use if program has a statusbar icon
-h, --help print this message and exit
Makes it easy to bind appications to key shortcuts without having to
spin up redundant instances or cycle through the scratchpad queue.
Performs a variety of tasks based on states:
1) starts and application
2) adds all instances of the specified application to the scratchpad
3) (toggle) hides all visible instances
4) (toggle) shows all scratchpad-hidden instances
"
local APPLICATION CLIENT_CLASS
local XFFSET=0.0
local YFFSET=0.0
local SCALE=0.8
[[ $(xrandr | grep primary | awk '{print $4;}' | sed 's/x.*//') -gt 3000 ]] \
&& SCALE=0.5
local ALWAYS_LAUNCH=0
local RESIZE=1
local MOVE=1
local MIN_ACTIVE=1
while [[ $# -gt 0 ]]
do
case $1 in
-c | --client ) CLIENT_CLASS="$2"; shift 1 ;;
-x | --x-offset ) XFFSET=$2; shift 1 ;;
-y | --y-offset ) YFFSET=$2; shift 1 ;;
-s | --scale ) SCALE=$2; shift 1 ;;
-a | --always-launch ) ALWAYS_LAUNCH=1 ;;
-n | --no-resize ) RESIZE=0 ;;
-l | --no-center ) MOVE=0 ;;
--has-statusbar-icon ) MIN_ACTIVE=2 ;;
-h | --help ) USAGE; exit 0 ;;
* )
[ ! $APPLICATION ] && APPLICATION="$1" \
|| ERROR "extra positional argument '$1'"
esac
shift 1
done
[ ! $APPLICATION ] && ERROR 'path-executable required'
[ ! $CLIENT_CLASS ] && CLIENT_CLASS=$APPLICATION
[ $APPLICATION ] && {
__CHECK_DEPENDENCY $APPLICATION || {
ERROR "$APPLICATION is not installed"
NOTIFY "ERROR: $APPLICATION not found"
}
}
CHECK_ERRORS
xrandr | grep primary | awk '{print $4;}' | grep -q '^[0-9]\+$' || {
xrandr --output $(xrandr | grep ' connected' | awk '{print $1;}' | head -n1) --primary
}
local CURRENTLY_ACTIVE=$(xdotool search --onlyvisible --classname $CLIENT_CLASS 2>/dev/null | wc -l)
local LAUNCH_APP=$ALWAYS_LAUNCH
STATUS "looking for window process ids"
xdotool search --class $CLIENT_CLASS || LAUNCH_APP=1
[[ $LAUNCH_APP -eq 1 ]] && {
STATUS 'launching application'
i3-msg "exec --no-startup-id $APPLICATION;"
sleep .5
}
STATUS 'getting target window size'
WINDOW_SIZE=$(\
xrandr \
| grep 'connected primary' \
| sed 's/.*connected primary \([^x]*\)x\([^+]*\).*/\1 \2/' \
| awk -v f=$SCALE -v x=$XFFSET -v y=$YFFSET \
'{print int($1*f+x)," ",int($2*f+y);}'\
)
INFO "window size: $WINDOW_SIZE"
STATUS 'moving window to scratchpad'
i3-msg "[class=$CLIENT_CLASS] move scratchpad"
[[ $RESIZE -eq 1 ]] \
&& STATUS 'resizing window' \
&& i3-msg "[class=$CLIENT_CLASS] resize set $WINDOW_SIZE"
[[ $CURRENTLY_ACTIVE -lt $MIN_ACTIVE ]] && {
STATUS 'pulling window from scratchpad to foreground'
i3-msg "[class=$CLIENT_CLASS] scratchpad show"
}
STATUS 'moving window to center of current screen'
[[ $MOVE -eq 1 ]] && i3-msg "[class=$CLIENT_CLASS] move position center"
return 0
}
#####################################################################
LAUNCH_OR_SHOW $@

Some files were not shown because too many files have changed in this diff Show More