Compare commits

..

3 Commits

Author SHA1 Message Date
6081122e88 publish based on tag releases instead of main releases 2024-02-20 23:22:17 -07:00
db18183c94 add typescript dependency 2024-02-20 23:12:18 -07:00
fec8c5e560 basic runner format; write a MAIN function
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

swap INFO for DEBUG

v3-to-v4 upgrade docs

bring some much-needed tender love and care to the scwrypts runner

improved i/o handling on the run executable means this is no longer relevant

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

update ZLE plugin so it no more make errors

FZF_(HEAD|TAIL) refactor to FZF_USER_INPUT

plugins/kubectl migration from v3 to v4

plugins/ci migration from v3 to v4

refactor py/lib into python-scwrypts subproject

verbosity is stupid lets call it log-level

fix bug with virtualenv loading

mergedeep to slow so I made my options dict shallow

hokay first iteration of python-dudes is ready

circleci configuration for python builds

npm package for scwrypts

3.9.1

initial build/test steps for nodejs

go

go

ok

ok

fix output

ok

ok

finalize publish steps
2024-02-20 23:08:55 -07:00
36 changed files with 636 additions and 1339 deletions

View File

@ -4,14 +4,7 @@ version: 2.1
orbs:
python: circleci/python@2.1.1
executors:
archlinux:
docker:
- image: archlinux:base-devel
resource_class: small
working_directory: /
python:
docker:
- image: cimg/python:3.11
@ -23,134 +16,29 @@ executors:
resource_class: medium
commands:
archlinux-run:
description: execute command steps in the archlinux container from the CI user
parameters:
_name:
type: string
command:
type: string
working_directory:
type: string
default: /home/ci
steps:
- run:
name: << parameters._name >>
working_directory: << parameters.working_directory >>
command: su ci -c '<< parameters.command >>'
custom:
archlinux:
prepare:
- &archlinux-prepare
run:
name: prepare archlinux dependencies
command: |
pacman --noconfirm -Syu git openssh ca-certificates-utils
useradd -m ci
echo "ci ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
temp-downgrade-fakeroot:
- &archlinux-temp-downgrade-fakeroot
run:
name: downgrade fakeroot to v1.34 (v1.35 and v1.36 are confirmed to break)
command: |
pacman -U --noconfirm https://archive.archlinux.org/packages/f/fakeroot/fakeroot-1.34-1-x86_64.pkg.tar.zst
clone-aur:
- &archlinux-clone-aur
archlinux-run:
_name: clone aur/scwrypts
command: git clone https://aur.archlinux.org/scwrypts.git aur
clone-scwrypts:
- &archlinux-clone-scwrypts
run:
name: clone wrynegade/scwrypts
working_directory: /home/ci
command: |
GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" git clone -b "$(echo $CIRCLE_BRANCH | grep . || echo $CIRCLE_TAG)" "$CIRCLE_REPOSITORY_URL" scwrypts
chown -R ci:ci ./scwrypts
jobs:
require-full-semver:
python-test:
executor: python
working_directory: ~/scwrypts/py/lib
steps:
- checkout:
path: ~/scwrypts
- run:
name: check CIRCLE_TAG for full semantic version
name: pytest
command: |
: \
&& [ $CIRCLE_TAG ] \
&& [[ $CIRCLE_TAG =~ ^v[0-9]*.[0-9]*.[0-9]*$ ]] \
;
&& pip install . .[test] \
&& pytest \
;
aur-test:
executor: archlinux
python-publish:
executor: python
working_directory: ~/scwrypts/py/lib
steps:
- *archlinux-prepare
- *archlinux-temp-downgrade-fakeroot
- *archlinux-clone-aur
- *archlinux-clone-scwrypts
- archlinux-run:
_name: test aur build on current source
working_directory: /home/ci/aur
command: >-
:
&& PKGVER=$(sed -n "s/^pkgver=//p" ./PKGBUILD)
&& cp -r ../scwrypts ../scwrypts-$PKGVER
&& rm -rf ../scwrypts-$PKGVER/.circleci
&& rm -rf ../scwrypts-$PKGVER/.git
&& rm -rf ../scwrypts-$PKGVER/.gitattributes
&& rm -rf ../scwrypts-$PKGVER/.gitignore
&& rm -rf ../scwrypts-$PKGVER/.github
&& tar -czf scwrypts.tar.gz ../scwrypts-$PKGVER
&& echo "source=(scwrypts.tar.gz)" >> PKGBUILD
&& echo "sha256sums=(SKIP)" >> PKGBUILD
&& makepkg --noconfirm -si
&& echo validating scwrypts version
&& scwrypts --version | grep "^scwrypts v$PKGVER$"
;
aur-publish:
executor: archlinux
steps:
- *archlinux-prepare
- *archlinux-temp-downgrade-fakeroot
- *archlinux-clone-aur
- archlinux-run:
_name: update PKGBUILD and .SRCINFO
working_directory: /home/ci/aur
command: >-
:
&& NEW_VERSION=$(echo $CIRCLE_TAG | sed 's/^v//')
&& sed "s/pkgver=.*/pkgver=$NEW_VERSION/; s/^pkgrel=.*/pkgrel=1/; /sha256sums/d" PKGBUILD -i
&& makepkg -g >> PKGBUILD
&& makepkg --printsrcinfo > .SRCINFO
;
- archlinux-run:
_name: sanity check for version build
working_directory: /home/ci/aur
command: >-
:
&& makepkg --noconfirm -si
&& scwrypts --version
&& scwrypts --version | grep -q "^scwrypts $CIRCLE_TAG\$"
;
- archlinux-run:
_name: publish new version
working_directory: /home/ci/aur
command: >-
:
&& git add PKGBUILD .SRCINFO
&& git -c user.email=yage@yage.io -c user.name=yage commit -am "$CIRCLE_TAG"
&& eval $(ssh-agent)
&& echo -e $SSH_KEY_PRIVATE__AUR | ssh-add -
&& git remote add upstream ssh://aur@aur.archlinux.org/scwrypts.git
&& GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" git push upstream
;
- checkout:
path: ~/scwrypts
- python/dist
- run: pip install twine && twine upload dist/*
nodejs-test:
executor: nodejs
@ -214,88 +102,32 @@ jobs:
: \
&& [ $CIRCLE_TAG ] \
&& pnpm build \
&& pnpm version $CIRCLE_TAG \
&& pnpm version $(git describe --tags) \
&& pnpm set //registry.npmjs.org/:_authToken=$NPM_TOKEN \
&& pnpm publish --no-git-checks \
;
python-test:
executor: python
working_directory: ~/scwrypts/py/lib
steps:
- checkout:
path: ~/scwrypts
- run:
name: pytest
command: |
: \
&& pip install . .[test] \
&& pytest \
;
- run: pip install build && python -m build
python-publish:
executor: python
working_directory: ~/scwrypts/py/lib
steps:
- checkout:
path: ~/scwrypts
- run: pip install build && python -m build
- run: pip install twine && twine upload dist/*
workflows:
test:
python:
jobs:
- aur-test:
&dev-filters
- python-test
- python-publish:
requires: [python-test]
context: [pypi-yage]
filters:
branches:
ignore: /^main$/
- python-test: *dev-filters
- nodejs-test: *dev-filters
publish:
jobs:
- require-full-semver:
filters:
&only-run-on-full-semver-tag-filters
tags:
only: /^v\d+\.\d+\.\d+.*$/
only: /^v.*$/
branches:
ignore: /^.*$/
- aur-test:
&only-publish-for-full-semver
filters: *only-run-on-full-semver-tag-filters
requires:
- require-full-semver
- aur-publish:
#
# there's a crazy-low-chance race-condition between this job and the GH Action '../.github/workflows/automatic-release.yaml'
# - automatic-release creates the release artifact, but takes no more than 15-30 seconds (current avg:16s max:26s)
# - this publish step requires the release artifact, but waits for all language-repository publishes to complete first (a few minutes at least)
#
# if something goes wrong, this step can be safely rerun after fixing the release artifact :)
#
filters: *only-run-on-full-semver-tag-filters
context: [aur-yage]
requires:
- aur-test
- python-publish
- nodejs-publish
- python-test: *only-publish-for-full-semver
- python-publish:
filters: *only-run-on-full-semver-tag-filters
context: [pypi-yage]
requires:
- python-test
- nodejs-test: *only-publish-for-full-semver
nodejs:
jobs:
- nodejs-test
- nodejs-publish:
filters: *only-run-on-full-semver-tag-filters
requires: [nodejs-test]
context: [npm-wrynegade]
requires:
- nodejs-test
filters:
tags:
only: /^v.*$/
branches:
ignore: /^.*$/

View File

@ -12,9 +12,13 @@ export DISCORD__DEFAULT_AVATAR_URL=
export DISCORD__DEFAULT_CHANNEL_ID=
export DISCORD__DEFAULT_USERNAME=
export DISCORD__DEFAULT_WEBHOOK=
export I3__BORDER_PIXEL_SIZE=
export I3__DMENU_FONT_SIZE=
export I3__GLOBAL_FONT_SIZE=
export I3__MODEL_CONFIG=
export LINEAR__API_TOKEN=
export MEDIA_SYNC__S3_BUCKET=
export MEDIA_SYNC__TARGETS=
export MEDIA_SYNC__S3_BUCKET
export MEDIA_SYNC__TARGETS
export REDIS_AUTH=
export REDIS_HOST=
export REDIS_PORT=

View File

@ -15,6 +15,11 @@ DISCORD__DEFAULT_CHANNEL_ID |
DISCORD__DEFAULT_USERNAME |
DISCORD__DEFAULT_WEBHOOK |
I3__BORDER_PIXEL_SIZE | custom i3 configuration settings
I3__DMENU_FONT_SIZE |
I3__GLOBAL_FONT_SIZE |
I3__MODEL_CONFIG |
LINEAR__API_TOKEN | linear.app project management configuration
MEDIA_SYNC__S3_BUCKET | s3 bucket name and filesystem targets for media backups

View File

@ -1,19 +0,0 @@
---
name: Automatic Tag-release
on: # yamllint disable-line rule:truthy
push:
branches-ignore:
- '**'
tags:
- 'v*.*.*'
jobs:
automatic-tag-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: marvinpinto/action-automatic-releases@latest
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false

View File

@ -29,7 +29,6 @@ runs:
repository: wrynegade/scwrypts
path: ./wrynegade/scwrypts
ref: ${{ inputs.version }}
fetch-tags: true
- name: check dependencies
shell: bash
@ -52,7 +51,7 @@ runs:
} > $HOME/.scwrypts.apt-get.log 2>&1
echo "updating virtual dependencies"
$GITHUB_WORKSPACE/wrynegade/scwrypts/scwrypts \
$GITHUB_WORKSPACE/wrynegade/scwrypts/scwrypts -n \
--name scwrypts/virtualenv/update-all \
--group scwrypts \
--type zsh \

View File

@ -1,10 +1,11 @@
[[ $SCWRYPTS_KUBECTL_DRIVER_READY -eq 1 ]] && return 0
unalias k h f >/dev/null 2>&1
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)'"
@ -170,7 +171,7 @@ _SCWRYPTS_KUBECTL_DRIVER() {
[ $NAMESPACE ] && CLI_ARGS+=(--namespace $NAMESPACE)
[[ $VERBOSE -eq 1 ]] && {
REMINDER "
INFO "
context '$CONTEXT'
namespace '$NAMESPACE'
environment '$SCWRYPTS_ENV'
@ -179,7 +180,7 @@ _SCWRYPTS_KUBECTL_DRIVER() {
STATUS "running $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}"
} || {
[[ $(_SCWRYPTS_KUBECTL_SETTINGS get context) =~ ^show$ ]] && {
REMINDER "$SCWRYPTS_ENV.$SUBSESSION : $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}"
INFO "$SCWRYPTS_ENV.$SUBSESSION : $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}"
}
}
$CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}

View File

@ -112,8 +112,8 @@ KUBECTL__SERVE() {
SERVICE_PASSWORD="$(KUBECTL__GET_SERVICE_PASSWORD)"
KUBECTL__SERVICE_PARSE
REMINDER "attempting to serve ${NAMESPACE}/${SERVICE_NAME}:${SERVICE_PORT}"
[ $SERVICE_PASSWORD ] && REMINDER "password : $SERVICE_PASSWORD"
INFO "attempting to serve ${NAMESPACE}/${SERVICE_NAME}:${SERVICE_PORT}"
[ $SERVICE_PASSWORD ] && INFO "password : $SERVICE_PASSWORD"
KUBECTL port-forward service/$SERVICE_NAME $SERVICE_PORT
}

3
py/lib/.gitignore vendored
View File

@ -1,4 +1 @@
dist/
__pycache__/
*.py[cod]
*.so

View File

@ -55,5 +55,6 @@ source = 'versioningit'
[tool.hatch.build.targets.wheel]
packages = ['./']
[tool.versioningit.vcs]
match = ['v[0-9]*.[0-9]*.[0-9]*']
[tool.versioningit]
match = ['v*']

View File

@ -4,7 +4,7 @@ from .scwrypts.exceptions import MissingVariableError
def getenv(name, required=True):
value = os_getenv(f'{name}__override', os_getenv(name))
value = os_getenv(name, None)
if required and not value:
raise MissingVariableError(name)

View File

@ -2,22 +2,23 @@ from types import SimpleNamespace
from pytest import fixture
from scwrypts.test import get_generator
from scwrypts.test import generate
from scwrypts.test.character_set import uri
generate = get_generator({
options = {
'str_length_minimum': 8,
'str_length_maximum': 128,
'uuid_output_type': str,
})
}
def get_request_client_sample_data():
return {
'base_url' : generate(str, {'character_set': uri}),
'endpoint' : generate(str, {'character_set': uri}),
'method' : generate(str),
'response' : generate('requests_Response', {'depth': 4}),
'base_url' : generate(str, options | {'character_set': uri}),
'endpoint' : generate(str, options | {'character_set': uri}),
'method' : generate(str, options),
'response' : generate('requests_Response', options | {'depth': 4}),
'payload' : generate(dict, {
**options,
'depth': 1,
'data_types': { str, 'uuid' },
}),
@ -29,11 +30,13 @@ def fixture_sample():
**get_request_client_sample_data(),
headers = generate(dict, {
**options,
'depth': 1,
'data_types': { str, 'uuid' },
}),
payload_headers = generate(dict, {
**options,
'depth': 1,
'data_types': { str, 'uuid' },
}),

View File

@ -2,14 +2,15 @@ from types import SimpleNamespace
from pytest import fixture
from scwrypts.test import generate
from scwrypts.test.character_set import uri
from ..conftest import generate, get_request_client_sample_data
from ..conftest import options, get_request_client_sample_data
@fixture(name='sample')
def fixture_sample():
return SimpleNamespace(
**get_request_client_sample_data(),
api_token = generate(str, {'character_set': uri}),
query = generate(str),
api_token = generate(str, options | {'character_set': uri}),
query = generate(str, options),
)

View File

@ -3,8 +3,9 @@ from types import SimpleNamespace
from pytest import fixture
from scwrypts.test import generate
from scwrypts.test.character_set import uri
from ..conftest import generate, get_request_client_sample_data
from ..conftest import options, get_request_client_sample_data
@fixture(name='sample')
def fixture_sample():
@ -13,12 +14,12 @@ def fixture_sample():
**get_request_client_sample_data(),
'base_url': 'https://discord.com/api',
},
bot_token = generate(str, {'character_set': uri}),
username = generate(str, {'character_set': ascii_letters + digits}),
avatar_url = generate(str, {'character_set': uri}),
webhook = generate(str, {'character_set': uri}),
channel_id = generate(str, {'character_set': uri}),
content_header = generate(str),
content_footer = generate(str),
content = generate(str),
bot_token = generate(str, options | {'character_set': uri}),
username = generate(str, options | {'character_set': ascii_letters + digits}),
avatar_url = generate(str, options | {'character_set': uri}),
webhook = generate(str, options | {'character_set': uri}),
channel_id = generate(str, options | {'character_set': uri}),
content_header = generate(str, options),
content_footer = generate(str, options),
content = generate(str, options),
)

View File

@ -3,8 +3,9 @@ from types import SimpleNamespace
from pytest import fixture
from scwrypts.test import generate
from scwrypts.test.character_set import uri
from ..conftest import generate, get_request_client_sample_data
from ..conftest import options, get_request_client_sample_data
@fixture(name='sample')
def fixture_sample():
@ -13,6 +14,6 @@ def fixture_sample():
**get_request_client_sample_data(),
'base_url': 'https://api.linear.app',
},
api_token = generate(str, {'character_set': uri}),
query = generate(str),
api_token = generate(str, options | {'character_set': uri}),
query = generate(str, options),
)

View File

@ -13,7 +13,7 @@ class MissingFlagAndEnvironmentVariableError(EnvironmentError, ArgumentError):
class MissingScwryptsExecutableError(EnvironmentError):
def __init__(self):
super().__init__('scwrypts must be installed and available on your PATH')
super().__init__(f'scwrypts must be installed and available on your PATH')
class BadScwryptsLookupError(ValueError):

View File

@ -5,54 +5,44 @@ from subprocess import run
from .exceptions import MissingScwryptsExecutableError, BadScwryptsLookupError, MissingScwryptsGroupOrTypeError
def scwrypts(patterns=None, args=None, executable_args=None, name=None, group=None, _type=None):
def scwrypts(*args, patterns=None, name=None, group=None, _type=None, log_level=None):
'''
top-level scwrypts invoker from python
patterns str / list pattern-based scwrypt lookup
args str / list arguments forwarded to the invoked scwrypt
executable_args str / list arguments for the 'scwrypts' executable
(str above assumes space-delimited values)
- patterns allows for pattern-based scwrypt lookup
- name/group/type allos for precise-match lookup
name str exact scwrypt lookup name (requires group and _type)
group str exact scwrypt lookup group
_type str exact scwrypt lookup type
SCWRYPTS_EXECUTABLE configuration variable which defines the full path to scwrypts executable
*args should be a list of strings and is forwarded to the
invoked scwrypt
see 'scwrypts --help' for more information
'''
if patterns is None and name is None:
raise BadScwryptsLookupError()
if name is not None and (group is None or _type is None):
raise MissingScwryptsGroupOrTypeError(group, _type)
executable = which(getenv('SCWRYPTS_EXECUTABLE', 'scwrypts'))
executable = which('scwrypts')
if executable is None:
raise MissingScwryptsExecutableError()
lookup = _parse(patterns) if name is None else f'--name {name} --group {group} --type {_type}'
if patterns is None and name is None:
raise BadScwryptsLookupError()
pre_args = []
if name is None:
pre_args += patterns
else:
pre_args += ['--name', name, '--group', group, '--type', _type]
if group is None or _type is None:
raise MissingScwryptsGroupOrTypeError(group, _type)
if log_level is not None:
pre_args += ['--log-level', log_level]
depth = getenv('SUBSCWRYPT', '')
if depth != '':
depth = int(depth) + 1
return run(
f'SUBSCWRYPT={depth} {executable} {_parse(executable_args)} {lookup} -- {_parse(args)}',
f'SUBSCWRYPT={depth} {executable} {pre_args} -- {" ".join(args)}',
shell=True,
executable='/bin/zsh',
check=False,
capture_output=True,
text=True,
)
def _parse(string_or_list_args):
if string_or_list_args is None:
return ''
if isinstance(string_or_list_args, list):
return ' '.join(string_or_list_args)
return str(string_or_list_args)

View File

@ -1,184 +0,0 @@
from random import choice
from re import search
from string import ascii_letters, digits
from types import SimpleNamespace
from unittest.mock import patch
from pytest import fixture, raises
from scwrypts.test import get_generator
from .exceptions import MissingScwryptsExecutableError, BadScwryptsLookupError, MissingScwryptsGroupOrTypeError
from .scwrypts import scwrypts
#####################################################################
def test_scwrypts(sample, _scwrypts):
assert validate_scwrypts_output(sample, _scwrypts)
def test_scwrypts_finds_system_executable(sample, _scwrypts, mock_which):
mock_which.assert_called_once_with(sample.env['SCWRYPTS_EXECUTABLE'])
def test_scwrypts_uses_configured_executable_path(_scwrypts, mock_getenv):
mock_getenv.assert_any_call('SCWRYPTS_EXECUTABLE', 'scwrypts')
def test_scwrypts_uses_correct_depth(_scwrypts, mock_getenv):
mock_getenv.assert_any_call('SUBSCWRYPT', '')
def test_scwrypts_runs_subprocess(_scwrypts, mock_run):
mock_run.assert_called_once()
##########################################
def test_scwrypts_omit_optionals(sample, _scwrypts_omit_optionals):
assert validate_scwrypts_output(sample, _scwrypts_omit_optionals)
def test_scwrypts_omit_optionals_finds_system_executable(sample, _scwrypts_omit_optionals, mock_which):
mock_which.assert_called_once_with('scwrypts')
def test_scwrypts_omit_optionals_uses_configured_executable_path(_scwrypts_omit_optionals, mock_getenv):
mock_getenv.assert_any_call('SCWRYPTS_EXECUTABLE', 'scwrypts')
def test_scwrypts_omit_optionals_uses_correct_depth(_scwrypts_omit_optionals, mock_getenv):
mock_getenv.assert_any_call('SUBSCWRYPT', '')
def test_scwrypts_omit_optionals_runs_subprocess(_scwrypts_omit_optionals, mock_run):
mock_run.assert_called_once()
##########################################
def test_invalid_lookup_missing_patterns_and_name(sample):
sample.patterns = None
sample.name = None
with raises(BadScwryptsLookupError):
scwrypts(**get_scwrypts_args(sample))
def test_invalid_name_lookup_missing_group(sample):
sample.group = None
with raises(MissingScwryptsGroupOrTypeError):
scwrypts(**get_scwrypts_args(sample))
def test_invalid_name_lookup_missing_type(sample):
sample._type = None # pylint: disable=protected-access
with raises(MissingScwryptsGroupOrTypeError):
scwrypts(**get_scwrypts_args(sample))
def test_invalid_scwrypts_installation(sample, mock_which):
mock_which.return_value = None
with raises(MissingScwryptsExecutableError):
scwrypts(**get_scwrypts_args(sample))
#####################################################################
generate = get_generator({
'str_length_minimum': 8,
'str_length_maximum': 128,
'character_set': ascii_letters + digits + '/-_'
})
def _generate_str_or_list_arg():
random_arg = generate(list, {'data_types': {str}})
return random_arg if choice([str, list]) == list else ' '.join(random_arg)
@fixture(name='sample')
def fixture_sample():
sample = SimpleNamespace(
patterns = _generate_str_or_list_arg(),
args = _generate_str_or_list_arg(),
executable_args = _generate_str_or_list_arg(),
name = generate(str),
group = generate(str),
_type = generate(str),
executable = generate(str),
env = {
'SCWRYPTS_EXECUTABLE': generate(str),
'SUBSCWRYPT': str(generate(int, {'minimum': 1, 'maximum': 99})),
},
returncode = generate(int),
stdout = generate(str),
stderr = generate(str),
)
return sample
def get_scwrypts_args(sample):
return {
key: getattr(sample, key)
for key in [
'patterns',
'args',
'executable_args',
'name',
'group',
'_type',
]
}
#####################################################################
@fixture(name='mock_which', autouse=True)
def fixture_mock_which(sample):
with patch('scwrypts.scwrypts.scwrypts.which') as mock:
mock.return_value = sample.executable
yield mock
@fixture(name='mock_getenv', autouse=True)
def fixture_mock_getenv(sample):
with patch('scwrypts.scwrypts.scwrypts.getenv') as mock:
mock.side_effect = sample.env.get
yield mock
@fixture(name='mock_run', autouse=True)
def fixture_mock_run(sample):
with patch('scwrypts.scwrypts.scwrypts.run') as mock:
mock.side_effect = lambda *args, **_kwargs: SimpleNamespace(
args = args,
returncode = sample.returncode,
stdout = sample.stdout,
stderr = sample.stderr,
)
yield mock
#####################################################################
@fixture(name='_scwrypts')
def fixture_scwrypts(sample):
return scwrypts(**get_scwrypts_args(sample))
@fixture(name='_scwrypts_omit_optionals')
def fixture_scwrypts_omit_optionals(sample):
sample.args = None
sample.executable_args = None
del sample.env['SCWRYPTS_EXECUTABLE']
del sample.env['SUBSCWRYPT']
return scwrypts(**get_scwrypts_args(sample))
def validate_scwrypts_output(sample, output):
#
# I would love to use 'assert _scwrypts == SimpleNamespace(...expected...)'
# but the output.args is difficult to recreate without copying all the
# processing logic over from the scwrypts function
#
# opting for a bit of a strange equality test here, checking the args
# as closely as possible without copying parsing logic
#
run_args_reduced_to_a_single_string = len(output.args) == 1
run_args_follow_expected_form = search(
fr'^SUBSCWRYPT=.* {sample.executable} .*-- .*$',
output.args[0],
)
return all([
run_args_reduced_to_a_single_string,
run_args_follow_expected_form,
output.returncode == sample.returncode,
output.stdout == sample.stdout,
output.stderr == sample.stderr,
])

View File

@ -5,6 +5,6 @@ __all__ = [
'generate',
]
from .generate import generate, get_generator
from .generate import generate
from .character_set import *

View File

@ -45,21 +45,6 @@ DEFAULT_OPTIONS = {
'requests_response_status_code': status_codes.codes[200],
}
def get_generator(default_options=None):
if default_options is None:
default_options = {}
def generator_function(data_type=None, options_overrides=None):
if options_overrides is None:
options_overrides = {}
return generate(
data_type = data_type,
options = default_options | options_overrides,
)
return generator_function
def generate(data_type=None, options=None):
'''
generate random data with the call of a function

388
run Executable file
View File

@ -0,0 +1,388 @@
#!/bin/zsh
export EXECUTION_DIR=$(pwd)
source "${0:a:h}/zsh/lib/import.driver.zsh" || exit 42
#####################################################################
() {
cd "$SCWRYPTS_ROOT__scwrypts"
GIT_SCWRYPTS() { git -C "$SCWRYPTS_ROOT__scwrypts" $@; }
local ERRORS=0
local USAGE='
usage: scwrypts [...options...] [...patterns...] -- [...script options...]
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
runtime
-y, --yes auto-accept all [yn] prompts through current scwrypt
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
-n shorthand for "--log-level 0"
-v, --log-level [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 : (CI default) include warning messages
4 : include debug messages
alternate commands
-h, --help display this message and exit
-l, --list print out command list and exit
--list-envs print out environment list and exit
--update update scwrypts library to latest version
--version print out scwrypts version and exit
patterns:
- a list of glob patterns to loose-match a scwrypt by name
script options:
- everything after "--" is forwarded to the scwrypt you run
("-- --help" will provide more information)
'
#####################################################################
### cli argument parsing and global configuration ###################
#####################################################################
local ENV_NAME="$SCWRYPTS_ENV"
local SEARCH_PATTERNS=()
local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME
[ ! $SCWRYPTS_LOG_LEVEL ] && {
local SCWRYPTS_LOG_LEVEL
[ $CI ] && SCWRYPTS_LOG_LEVEL=3 || SCWRYPTS_LOG_LEVEL=2
}
while [[ $# -gt 0 ]]
do
case $1 in
-[a-z][a-z]* )
VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
set -- $(echo " $VARSPLIT ") ${@:2}
;;
### alternate commands ###################
-h | --help )
USAGE
return 0
;;
-l | --list )
SCWRYPTS__GET_AVAILABLE_SCWRYPTS
return 0
;;
--list-envs )
SCWRYPTS__GET_ENV_NAMES
return 0
;;
--version )
echo scwrypts $(GIT_SCWRYPTS describe --tags)
return 0
;;
--update )
GIT_SCWRYPTS fetch --quiet origin main
GIT_SCWRYPTS fetch --quiet origin main --tags
local SYNC_STATUS=$?
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_SCWRYPTS rebase --autostash origin/main \
&& SUCCESS 'up-to-date with origin/main' \
&& GIT_SCWRYPTS log -n1 \
|| {
GIT_SCWRYPTS rebase --abort
ERROR 'unable to update scwrypts; please try manual upgrade'
REMINDER "installation in '$(pwd)'"
}
}
return 0
;;
### scwrypts filters #####################
-m | --name )
[ $2 ] || { ERROR "missing value for argument $1"; break; }
SEARCH_NAME=$2
shift 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 | --log-level )
[[ $2 =~ ^[0-4]$ ]] || ERROR "invalid setting for log-level '$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'
}
CHECK_ERRORS
#####################################################################
### scwrypts selection / filtering ##################################
#####################################################################
local SCWRYPTS_AVAILABLE
SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS)
##########################################
[ $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 ] && {
SCWRYPTS_AVAILABLE=$(\
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep ' [^/]*'$SEARCH_TYPE'[^/]* '
} \
| awk '{$2=""; print $0;}' \
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
| column -ts '^'
)
}
[ $SEARCH_GROUP ] && {
SCWRYPTS_AVAILABLE=$(
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep "$SEARCH_GROUP"'[^/]*$'
} \
| awk '{$NF=""; print $0;}' \
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
| column -ts '^'
)
}
[[ ${#SEARCH_PATTERNS[@]} -gt 0 ]] && {
POTENTIAL_ERROR+="\n PATTERNS : $SEARCH_PATTERNS"
local P
for P in ${SEARCH_PATTERNS[@]}
do
SCWRYPTS_AVAILABLE=$(
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep $P
}
)
done
}
}
[[ $(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")"
}
##########################################
[[ $(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 ] || 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=true \
&& [ ! $CI ] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/environment ]] \
|| ENV_REQUIRED=false
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")
source "$ENV_FILE" || FAIL 5 "missing or invalid environment '$GROUP/$ENV_NAME'"
for f in $(eval 'echo $SCWRYPTS_STATIC_CONFIG__'$GROUP)
do
source "$f" || FAIL 5 "invalid static config '$f'"
done
done
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 ]] && {
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" ] || return 42
#####################################################################
### logging and pretty header/footer setup ##########################
#####################################################################
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 RUN_MODE=normal
[[ $LOGFILE =~ ^/dev/null$ ]] && RUN_MODE=no-logfile
[[ $SCWRYPT_NAME =~ interactive ]] && RUN_MODE=interactive
local HEADER FOOTER
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && {
HEADER=$(
echo "
=====================================================================
script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME
run at : $(date)
config : $ENV_NAME
log level : $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 #################################################
#####################################################################
[ ! $SUBSCWRYPT ] && export SUBSCWRYPT=0
set -o pipefail
{
[ $HEADER ] && echo $HEADER
case $RUN_MODE in
normal )
(eval "$RUN_STRING $(printf "%q " "$@")")
EXIT_CODE=$?
;;
no-logfile )
eval "$RUN_STRING $(printf "%q " "$@")"
EXIT_CODE=$?
;;
interactive )
eval "$RUN_STRING $(printf "%q " "$@")" </dev/tty >/dev/tty 2>&1
EXIT_CODE=$?
;;
esac
[ $FOOTER ] && echo $FOOTER
[[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m'
[[ $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"
} $@

482
scwrypts
View File

@ -1,482 +1,2 @@
#!/bin/zsh
export EXECUTION_DIR=$(pwd)
export SCWRYPTS_RUNTIME_ID=$(uuidgen)
source "$(dirname $(readlink -f "$0"))/zsh/lib/import.driver.zsh" || exit 42
#####################################################################
() {
cd "$SCWRYPTS_ROOT__scwrypts"
GIT_SCWRYPTS() { git -C "$SCWRYPTS_ROOT__scwrypts" $@; }
local ERRORS=0
local USAGE='
usage: scwrypts [...options...] [...patterns...] -- [...script options...]
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
runtime
-y, --yes auto-accept all [yn] prompts through current scwrypt
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
-n shorthand for "--log-level 0"
-v, --log-level <0-4> set incremental scwrypts log level to one of the following:
0 : only command output and critical failures; skips logfile
1 : include success / failure messages
2 : include status update messages
3 : (default) include warning messages
4 : include debug messages
-o, --output <format> specify output format; one of: pretty,json (default: pretty)
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
--list-groups print out configured scwrypts groups and exit
--config "eval"-ed to enable config and "use" import in non-scwrypts environments
--root print out SCWRYPTS_ROOT__scwrypts and exit
--update update scwrypts library to latest version
--version print out scwrypts version and exit
patterns:
- a list of glob patterns to loose-match a scwrypt by name
script options:
- everything after "--" is forwarded to the scwrypt you run
("-- --help" will provide more information)
'
#####################################################################
### cli argument parsing and global configuration ###################
#####################################################################
local ENV_NAME="$SCWRYPTS_ENV"
local SEARCH_PATTERNS=()
local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=3
local SHIFT_COUNT
while [[ $# -gt 0 ]]
do
SHIFT_COUNT=1
case $1 in
-[a-z][a-z]* )
VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
set -- throw-away $(echo " $VARSPLIT ") ${@:2}
;;
### alternate commands ###################
-h | --help )
USAGE
return 0
;;
-l | --list )
SCWRYPTS__GET_AVAILABLE_SCWRYPTS
return 0
;;
--list-envs )
SCWRYPTS__GET_ENV_NAMES
return 0
;;
--list-groups )
echo "${SCWRYPTS_GROUPS[@]}" | sed 's/\s\+/\n/g' | sort -u
return 0
;;
--version )
case $SCWRYPTS_INSTALLATION_TYPE in
manual ) echo "scwrypts $(GIT_SCWRYPTS describe --tags) (via GIT)" ;;
* ) echo "scwrypts $(cat "$SCWRYPTS_ROOT__scwrypts/VERSION")" ;;
esac
return 0
;;
--root )
echo "$SCWRYPTS_ROOT__scwrypts"
return 0
;;
--config )
echo "source '$SCWRYPTS_ROOT__scwrypts/zsh/lib/import.driver.zsh'"
echo "CHECK_ENVIRONMENT --no-fail --no-usage"
echo "unset __SCWRYPT"
return 0
;;
--update )
case $SCWRYPTS_INSTALLATION_TYPE in
aur )
SCWRYPTS_LOG_LEVEL=3 REMINDER "
This installation is built from the AUR. Update through 'makepkg' or use
your preferred AUR package management tool (e.g. 'yay -Syu scwrypts')
"
;;
homebrew )
SCWRYPTS_LOG_LEVEL=3 REMINDER "This installation is managed by homebrew. Update me with 'brew update'"
;;
manual )
GIT_SCWRYPTS fetch --quiet origin main
GIT_SCWRYPTS fetch --quiet origin main --tags
local SYNC_STATUS=$?
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_SCWRYPTS rebase --autostash origin/main \
&& SUCCESS 'up-to-date with origin/main' \
&& GIT_SCWRYPTS log -n1 \
|| {
GIT_SCWRYPTS rebase --abort
ERROR 'unable to update scwrypts; please try manual upgrade'
REMINDER "installation in '$SCWRYPTS_ROOT__scwrypts'"
}
}
;;
* )
SCWRYPTS_LOG_LEVEL=3 REMINDER "
This is a managed installation of scwrypts. Please update through your
system package manager.
"
;;
esac
return 0
;;
### scwrypts filters #####################
-m | --name )
((SHIFT_COUNT+=1))
[ $2 ] || { ERROR "missing value for argument $1"; break; }
SEARCH_NAME=$2
;;
-g | --group )
((SHIFT_COUNT+=1))
[ $2 ] || { ERROR "missing value for argument $1"; break; }
SEARCH_GROUP=$2
GROUP=$2
;;
-t | --type )
((SHIFT_COUNT+=1))
[ $2 ] || { ERROR "missing value for argument $1"; break; }
SEARCH_TYPE=$2
TYPE=$2
;;
### runtime settings #####################
-y | --yes ) export __SCWRYPTS_YES=1 ;;
-n ) SCWRYPTS_LOG_LEVEL=0 ;;
-v | --log-level )
((SHIFT_COUNT+=1))
[[ $2 =~ ^[0-4]$ ]] || ERROR "invalid setting for log-level '$2'"
SCWRYPTS_LOG_LEVEL=$2
;;
-o | --output )
((SHIFT_COUNT+=1))
export SCWRYPTS_OUTPUT_FORMAT=$2
case $SCWRYPTS_OUTPUT_FORMAT in
pretty | json ) ;;
* ) ERROR "unsupported format '$SCWRYPTS_OUTPUT_FORMAT'" ;;
esac
;;
-e | --env )
((SHIFT_COUNT+=1))
[ $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; break ;; # pass arguments after '--' to the scwrypt
--* ) ERROR "unrecognized argument '$1'" ;;
* ) SEARCH_PATTERNS+=($1) ;;
esac
shift $SHIFT_COUNT
done
[ $SCWRYPTS_OUTPUT_FORMAT ] || export SCWRYPTS_OUTPUT_FORMAT=pretty
[ $SEARCH_NAME ] && {
[ $SEARCH_TYPE ] || ERROR '--name requires --type argument'
[ $SEARCH_GROUP ] || ERROR '--name requires --group argument'
}
CHECK_ERRORS
#####################################################################
### scwrypts selection / filtering ##################################
#####################################################################
local SCWRYPTS_AVAILABLE
SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS)
##########################################
[ $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 ] && {
SCWRYPTS_AVAILABLE=$(\
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep ' [^/]*'$SEARCH_TYPE'[^/]* '
} \
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
| column -ts '^'
)
}
[ $SEARCH_GROUP ] && {
SCWRYPTS_AVAILABLE=$(
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep "$SEARCH_GROUP"'[^/ ]*$'
} \
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
| column -ts '^'
)
}
[[ ${#SEARCH_PATTERNS[@]} -gt 0 ]] && {
POTENTIAL_ERROR+="\n PATTERNS : $SEARCH_PATTERNS"
local P
for P in ${SEARCH_PATTERNS[@]}
do
SCWRYPTS_AVAILABLE=$(
{
echo $SCWRYPTS_AVAILABLE | head -n1
echo $SCWRYPTS_AVAILABLE | grep $P
}
)
done
}
}
[[ $(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")"
}
##########################################
[[ $(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 ] || 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=true \
&& [ ! $CI ] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/environment ]] \
|| ENV_REQUIRED=false
local REQUIRED_ENVIRONMENT_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$SCWRYPT_GROUP)
[ $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)"
}
[[ $ENV_REQUIRED =~ true ]] && {
[ ! $ENV_NAME ] && ENV_NAME=$(SCWRYPTS__SELECT_ENV)
[ ! $ENV_NAME ] && ABORT
export ENV_NAME
export SCWRYPTS_ENV=$ENV_NAME
for GROUP in ${SCWRYPTS_GROUPS[@]}
do
local REQUIRED_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$GROUP)
[ $REQUIRED_REGEX ] && {
[[ $ENV_NAME =~ $REQUIRED_REGEX ]] || continue
}
local ENV_FILE=$(SCWRYPTS__GET_ENV_FILE "$ENV_NAME" "$GROUP")
source "$ENV_FILE" || FAIL 5 "missing or invalid environment '$GROUP/$ENV_NAME'"
for f in $(eval 'echo $SCWRYPTS_STATIC_CONFIG__'$GROUP)
do
source "$f" || FAIL 5 "invalid static config '$f'"
done
done
}
[ $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 ] && export SUBSCWRYPT=0
[[ $SCWRYPTS_INSTALLATION_TYPE =~ ^manual$ ]] && {
[[ $SUBSCWRYPT -eq 0 ]] && [[ $ENV_NAME =~ prod ]] && [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] && {
STATUS "on '$ENV_NAME'; checking diff against origin/main"
local WARNING_MESSAGE
[ ! $WARNING_MESSAGE ] && {
GIT_SCWRYPTS fetch --quiet origin main \
|| WARNING_MESSAGE='I am unable to verify your scwrypts version'
}
[ ! $WARNING_MESSAGE ] && {
GIT_SCWRYPTS diff --exit-code origin/main -- . >/dev/null 2>&1 \
|| WARNING_MESSAGE='your scwrypts is currently out-of-date'
}
[ $WARNING_MESSAGE ] && {
[[ $SCWRYPTS_LOG_LEVEL -lt 3 ]] && {
REMINDER "you are running in ${__BRIGHT_RED}production${__BRIGHT_MAGENTA} and $WARNING_MESSAGE"
} || {
GIT_SCWRYPTS diff --exit-code origin/main -- . >&2
WARNING "you are trying to run in ${__BRIGHT_RED}production${__YELLOW} but $WARNING_MESSAGE (relevant diffs and errors 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" ] || return 42
#####################################################################
### logging and pretty header/footer setup ##########################
#####################################################################
local LOGFILE \
&& [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] \
&& [[ $SUBSCWRYPT -eq 0 ]] \
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
&& [[ ! $SCWRYPT_NAME =~ interactive ]] \
&& LOGFILE="$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log" \
|| LOGFILE='/dev/null' \
;
local RUN_MODE=normal
[[ $LOGFILE =~ ^/dev/null$ ]] && RUN_MODE=no-logfile
[[ $SCWRYPT_NAME =~ interactive ]] && RUN_MODE=interactive
local HEADER FOOTER
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && {
case $SCWRYPTS_OUTPUT_FORMAT in
pretty )
HEADER=$(
echo "
=====================================================================
scwrypt : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME
run at : $(date)
config : $ENV_NAME
log level : $SCWRYPTS_LOG_LEVEL
\\033[1;33m--- SCWRYPT BEGIN ---------------------------------------------------\\033[0m
" | sed 's/^\s\+//; 1d'
)
FOOTER="\\033[1;33m--- SCWRYPT END ---------------------------------------------------\\033[0m"
;;
json )
HEADER=$(echo '{}' | jq -c ".
| .timestamp = \"$(date +%s)\"
| .runtime = \"$SCWRYPTS_RUNTIME_ID\"
| .scwrypt = \"start of $SCWRYPT_NAME $SCWRYPT_GROUP $SCWRYPT_TYPE\"
| .config = \"$ENV_NAME\"
| .logLevel = \"$SCWRYPTS_LOG_LEVEL\"
| .subscwrypt = $SUBSCWRYPT
")
;;
esac
}
[[ $SUBSCWRYPT -eq 0 ]] || {
case $SCWRYPTS_OUTPUT_FORMAT in
pretty )
HEADER="\\033[0;33m--- ($SUBSCWRYPT) BEGIN $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
FOOTER="\\033[0;33m--- ($SUBSCWRYPT) END $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
;;
esac
}
#####################################################################
### run the scwrypt #################################################
#####################################################################
set -o pipefail
{
[ $HEADER ] && echo $HEADER
case $RUN_MODE in
normal )
(eval "$RUN_STRING $(printf "%q " "$@")")
EXIT_CODE=$?
;;
no-logfile )
eval "$RUN_STRING $(printf "%q " "$@")"
EXIT_CODE=$?
;;
interactive )
eval "$RUN_STRING $(printf "%q " "$@")" </dev/tty >/dev/tty 2>&1
EXIT_CODE=$?
;;
esac
[ $FOOTER ] && echo $FOOTER
[[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m'
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && [ ! $SUBSCWRYPT ] \
&& echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
return $EXIT_CODE
} | tee --append "$LOGFILE"
} $@
source "${0:a:h}/run" $@

View File

@ -1,223 +1,69 @@
#
# typically you do not need to reload this plugin in a single session;
# if for some reason you do, you can run the following command and
# source this file again
#
# unset __SCWRYPTS_PLUGIN_LOADED
#
[[ $__SCWRYPTS_PLUGIN_LOADED =~ true ]] && return 0
NO_EXPORT_CONFIG=1 source "${0:a:h}/zsh/lib/import.driver.zsh" || return 42
#####################################################################
SCWRYPTS__ZSH_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; }
: \
&& command -v scwrypts &>/dev/null \
&& eval "$(scwrypts --config)" \
|| {
echo 'scwrypts must be in PATH and properly configured; skipping zsh plugin setup' >&2
SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
which scwrypts >/dev/null 2>&1\
&& RBUFFER="scwrypts" || RBUFFER="$SCWRYPTS_ROOT/scwrypts"
RBUFFER+=" --name $NAME --group $GROUP --type $TYPE"
zle accept-line
}
zle -N scwrypts SCWRYPTS__ZSH_PLUGIN
bindkey $SCWRYPTS_SHORTCUT scwrypts
#####################################################################
SCWRYPTS__ZSH_BUILDER_PLUGIN() {
local SCWRYPT_SELECTION=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS | FZF 'select a script' --header-lines 1)
local NAME
local TYPE
local GROUP
LBUFFER= RBUFFER=
[ ! $SCWRYPT_SELECTION ] && { zle accept-line; return 0; }
SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
scwrypts --name $NAME --group $GROUP --type $TYPE -- --help >&2 || {
zle accept-line
return 0
}
echo
__SCWRYPTS_PARSE() {
SCWRYPT_SELECTION=$(scwrypts --list | fzf --ansi --prompt 'select a script : ' --header-lines 1)
LBUFFER= RBUFFER=
[ $SCWRYPT_SELECTION ] || return 1
zle reset-prompt
which scwrypts >/dev/null 2>&1\
&& LBUFFER="scwrypts" || LBUFFER="$SCWRYPTS_ROOT/scwrypts"
NAME=$(echo "$SCWRYPT_SELECTION" | awk '{print $1;}')
TYPE=$(echo "$SCWRYPT_SELECTION" | awk '{print $2;}')
GROUP=$(echo "$SCWRYPT_SELECTION" | awk '{print $3;}')
[ $NAME ] && [ $TYPE ] && [ $GROUP ]
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'
local SELECTED=$(\
{ [ $SCWRYPTS_ENV ] && echo $RESET; SCWRYPTS__GET_ENV_NAMES; } \
| FZF 'select an environment' \
)
[ $SCWRYPTS_SHORTCUT ] && {
SCWRYPTS__ZSH_PLUGIN() {
local SCWRYPT_SELECTION NAME TYPE GROUP
__SCWRYPTS_PARSE || { zle accept-line; return 0; }
RBUFFER="scwrypts --name $NAME --type $TYPE --group $GROUP"
zle accept-line
zle clear-command-line
[ $SELECTED ] && {
[[ $SELECTED =~ ^$RESET$ ]] \
&& RBUFFER='unset SCWRYPTS_ENV' \
|| RBUFFER="export SCWRYPTS_ENV=$SELECTED"
}
zle -N scwrypts SCWRYPTS__ZSH_PLUGIN
bindkey $SCWRYPTS_SHORTCUT scwrypts
unset SCWRYPTS_SHORTCUT
zle accept-line
}
#####################################################################
[ $SCWRYPTS_BUILDER_SHORTCUT ] && {
SCWRYPTS__ZSH_BUILDER_PLUGIN() {
local SCWRYPT_SELECTION NAME TYPE GROUP
__SCWRYPTS_PARSE || { echo >&2; zle accept-line; return 0; }
echo $SCWRYPT_SELECTION >&2
scwrypts -n --name $NAME --group $GROUP --type $TYPE -- --help >&2 || {
zle accept-line
return 0
}
echo
zle reset-prompt
LBUFFER="scwrypts --name $NAME --type $TYPE --group $GROUP -- "
}
zle -N scwrypts-builder SCWRYPTS__ZSH_BUILDER_PLUGIN
bindkey $SCWRYPTS_BUILDER_SHORTCUT scwrypts-builder
unset SCWRYPTS_BUILDER_SHORTCUT
}
#####################################################################
[ $SCWRYPTS_ENV_SHORTCUT ] && {
SCWRYPTS__ZSH_PLUGIN_ENV() {
local RESET='reset'
local SELECTED=$(\
{ [ $SCWRYPTS_ENV ] && echo $RESET; scwrypts --list-envs; } \
| fzf --prompt 'select an environment : ' \
)
zle clear-command-line
[ $SELECTED ] && {
[[ $SELECTED =~ ^$RESET$ ]] \
&& RBUFFER='unset SCWRYPTS_ENV' \
|| RBUFFER="export SCWRYPTS_ENV=$SELECTED"
}
zle accept-line
}
zle -N scwrypts-setenv SCWRYPTS__ZSH_PLUGIN_ENV
bindkey $SCWRYPTS_ENV_SHORTCUT scwrypts-setenv
unset SCWRYPTS_ENV_SHORTCUT
}
#####################################################################
# badass(/terrifying?) zsh autocompletion
command -v compdef &>/dev/null && {
_scwrypts() {
echo $words | grep -q "\s--\s" && _arguments && return 0
eval "_arguments $(
{
HELP=$(scwrypts --help 2>&1 | sed -n 's/^\s\+\(-.* .\)/\1/p' | sed 's/[[]/(/g; s/[]]/)/g')
echo $HELP \
| sed 's/^\(\(-[^-\s]\),*\s*\|\)\(\(--[-a-z0-9A-Z\]*\)\s\(<\([^>]*\)>\|\)\|\)\s\+\(.*\)/\2[\7]:\6:->\2/' \
| grep -v '^[[]' \
;
echo $HELP \
| sed 's/^\(\(-[^-\s]\),*\s*\|\)\(\(--[-a-z0-9A-Z\]*\)\s\(<\([^>]*\)>\|\)\|\)\s\+\(.*\)/\4[\7]:\6:->\4/' \
| grep -v '^[[]' \
;
echo ":pattern:->pattern"
echo ":pattern:->pattern"
echo ":pattern:->pattern"
echo ":pattern:->pattern"
echo ":pattern:->pattern"
} | sed 's/::->.*$//g' | sed "s/\\(^\\|$\\)/'/g" | tr '\n' ' '
)"
local _group=''
echo $words | grep -q ' -g [^\s]' \
&& _group=$(echo $words | sed 's/.*-g \([^ ]\+\)\s*.*/\1/')
echo $words | grep -q ' --group .' \
&& _group=$(echo $words | sed 's/.*--group \([^ ]\+\)\s*.*/\1/')
local _type=''
echo $words | grep -q ' -t [^\s]' \
&& _type=$(echo $words | sed 's/.*-t \([^ ]\+\)\s*.*/\1/')
echo $words | grep -q ' --type .' \
&& _type=$(echo $words | sed 's/.*--type \([^ ]\+\)\s*.*/\1/')
local _name=''
echo $words | grep -q ' -m [^\s]' \
&& _name=$(echo $words | sed 's/.*-m \([^ ]\+\)\s*.*/\1/')
echo $words | grep -q ' --name .' \
&& _name=$(echo $words | sed 's/.*--name \([^ ]\+\)\s*.*/\1/')
local _pattern _patterns=()
[ ! $_name ] \
&& _patterns=($(echo "${words[@]:1}" | sed 's/\s\+/\n/g' | grep -v '^-'))
_get_remaining_scwrypts() {
[ $_name ] || local _name='[^ ]\+'
[ $_type ] || local _type='[^ ]\+'
[ $_group ] || local _group='[^ ]\+'
local remaining=$(\
scwrypts --list \
| sed "1d; s,\x1B\[[0-9;]*[a-zA-Z],,g" \
| grep "^$_name\s" \
| grep "\s$_group$" \
| grep "\s$_type\s" \
)
for _pattern in ${_patterns[@]}
do
remaining=$(echo "$remaining" | grep "$_pattern")
done
echo "$remaining"
}
case $state in
( -m | --name )
compadd $(_get_remaining_scwrypts | awk '{print $1;}' | sort -u)
;;
( -t | --type )
compadd $(_get_remaining_scwrypts | awk '{print $2;}' | sort -u)
;;
( -g | --group )
[[ $_name$_type$_group =~ ^$ ]] \
&& compadd $(scwrypts --list-groups) \
|| compadd $(_get_remaining_scwrypts | awk '{print $3;}' | sort -u) \
;;
( -e | --env )
compadd $(scwrypts --list-envs)
;;
( -v | --log-level )
local _help="$(\
scwrypts --help 2>&1 \
| sed -n '/-v, --log-level/,/^$/p' \
| sed -n 's/\s\+\([0-9]\) : \(.*\)/\1 -- \2/p' \
)"
eval "local _descriptions=($(echo "$_help" | sed "s/\\(^\|$\\)/'/g"))"
local _values=($(echo "$_help" | sed 's/ --.*//'))
compadd -d _descriptions -a _values
;;
( -o | --output )
compadd pretty json
;;
( pattern )
[[ $_name =~ ^$ ]] && {
local _remaining_scwrypts="$(_get_remaining_scwrypts)"
# stop providing suggestions if your pattern is sufficient
[[ $(echo $_remaining_scwrypts | wc -l) -le 1 ]] && return 0
local _remaining_patterns="$(echo "$_remaining_scwrypts" | sed 's/\s\+/\n/g; s|/|\n|g;' | sort -u)"
for _pattern in ${_patterns[@]}
do
_remaining_patterns="$(echo "$_remaining_patterns" | grep -v "^$_pattern$")"
done
compadd $(echo $_remaining_patterns)
}
;;
( * ) ;;
esac
}
compdef _scwrypts scwrypts
}
__SCWRYPTS_PLUGIN_LOADED=true
zle -N scwrypts-setenv SCWRYPTS__ZSH_PLUGIN_ENV
bindkey $SCWRYPTS_ENV_SHORTCUT scwrypts-setenv

View File

@ -1,11 +0,0 @@
SCWRYPTS_GROUPS+=(scwrypts)
export SCWRYPTS_ROOT__scwrypts="$SCWRYPTS_ROOT"
export SCWRYPTS_COLOR__scwrypts='\033[0;32m'
#export SCWRYPTS_TYPE__scwrypts=
#export SCWRYPTS_LIBRARY_ROOT__scwrypts=
export SCWRYPTS_VIRTUALENV_PATH__scwrypts="$SCWRYPTS_DATA_PATH/virtualenv"
export SCWRYPTS_PREFERRED_PYTHON_VERSIONS__scwrypts=(3.12 3.11 3.10)
export SCWRYPTS_NODE_VERSION__scwrypts=18.0.0

View File

@ -27,9 +27,6 @@ EKS() {
local CONTEXT="arn:aws:eks:${AWS_REGION}:${AWS_ACCOUNT}:cluster/${CLUSTER_NAME}"
kubectl config get-contexts | grep -q $CONTEXT \
|| EKS__CLUSTER_LOGIN -c $CLUSTER_NAME >/dev/null
local CONTEXT_ARGS=()
case $1 in
helm ) CONTEXT_ARGS+=(--kube-context $CONTEXT) ;;
@ -55,7 +52,6 @@ EKS__CLUSTER_LOGIN() {
"
REQUIRED_ENV=(AWS_ACCOUNT AWS_REGION) CHECK_ENVIRONMENT || return 1
local CLUSTER_NAME
while [[ $# -gt 0 ]]

10
zsh/lib/config.group.zsh Normal file
View File

@ -0,0 +1,10 @@
export SCWRYPTS_ROOT__scwrypts="$SCWRYPTS_ROOT"
export SCWRYPTS_LIBRARY_ROOT__scwrypts="$SCWRYPTS_ROOT/zsh/lib"
export SCWRYPTS_COLOR__scwrypts='\033[0;32m'
export SCWRYPTS_VIRTUALENV_PATH__scwrypts="$SCWRYPTS_DATA_PATH/virtualenv"
[ ! -d "$SCWRYPTS_VIRTUALENV_PATH__scwrypts" ] && mkdir -p "$SCWRYPTS_VIRTUALENV_PATH__scwrypts"
export SCWRYPTS_PREFERRED_PYTHON_VERSIONS__scwrypts=(3.11 3.10 3.9)
export SCWRYPTS_NODE_VERSION__scwrypts=18.0.0

View File

@ -1,31 +1,12 @@
[[ $__SCWRYPT -eq 1 ]] && return 0
#####################################################################
# Apparently MacOS puts ALL of the homebrew stuff inside of a top level git repository
# with bizarre git ignores; so:
# - USE the git root if it's a manual install...
# - UNLESS that git root is just the $(brew --prefix)
SCWRYPTS_ROOT="$(cd -- ${0:a:h}; git rev-parse --show-toplevel 2>/dev/null | grep -v "^$(brew --prefix 2>/dev/null)$")"
[ $SCWRYPTS_ROOT ] && [ -d "$SCWRYPTS_ROOT" ] \
|| SCWRYPTS_ROOT="$(echo "${0:a:h}" | sed -n 's|\(share/scwrypts\).*$|\1|p')"
[ $SCWRYPTS_ROOT ] && [ -d "$SCWRYPTS_ROOT" ] || {
echo "cannot determine scwrypts root path for current installation; aborting"
exit 1
}
export SCWRYPTS_ROOT__scwrypts="$SCWRYPTS_ROOT"
[ -f "$SCWRYPTS_ROOT__scwrypts/MANAGED_BY" ] \
&& export SCWRYPTS_INSTALLATION_TYPE=$(cat "$SCWRYPTS_ROOT__scwrypts/MANAGED_BY") \
|| export SCWRYPTS_INSTALLATION_TYPE=manual \
;
[ ! $SCWRYPTS_ROOT ] \
&& SCWRYPTS_ROOT="$(cd $(dirname "${0:a:h}"); git rev-parse --show-toplevel)"
#####################################################################
DEFAULT_CONFIG="$SCWRYPTS_ROOT__scwrypts/zsh/lib/config.user.zsh"
DEFAULT_CONFIG="$SCWRYPTS_ROOT/zsh/lib/config.user.zsh"
source "$DEFAULT_CONFIG"
USER_CONFIG_OVERRIDES="$SCWRYPTS_CONFIG_PATH/config.zsh"
@ -35,13 +16,11 @@ USER_CONFIG_OVERRIDES="$SCWRYPTS_CONFIG_PATH/config.zsh"
}
source "$USER_CONFIG_OVERRIDES"
mkdir -p \
"$SCWRYPTS_CONFIG_PATH" \
"$SCWRYPTS_DATA_PATH" \
"$SCWRYPTS_ENV_PATH" \
"$SCWRYPTS_LOG_PATH" \
"$SCWRYPTS_OUTPUT_PATH" \
;
[ ! -d $SCWRYPTS_CONFIG_PATH ] && mkdir -p $SCWRYPTS_CONFIG_PATH
[ ! -d $SCWRYPTS_DATA_PATH ] && mkdir -p $SCWRYPTS_DATA_PATH
[ ! -d $SCWRYPTS_ENV_PATH ] && mkdir -p $SCWRYPTS_ENV_PATH
[ ! -d $SCWRYPTS_LOG_PATH ] && mkdir -p $SCWRYPTS_LOG_PATH
[ ! -d $SCWRYPTS_OUTPUT_PATH ] && mkdir -p $SCWRYPTS_OUTPUT_PATH
export \
SCWRYPTS_GROUPS \
@ -53,9 +32,11 @@ export \
SCWRYPTS_OUTPUT_PATH \
;
source "$SCWRYPTS_ROOT/scwrypts.scwrypts.zsh" \
|| FAIL 69 'failed to set up scwrypts group; aborting'
SCWRYPTS_GROUPS+=(scwrypts) # 'scwrypts' group is required!
SCWRYPTS_GROUPS=($(echo $SCWRYPTS_GROUPS | sed 's/\s\+/\n/g' | sort -u))
source "$SCWRYPTS_ROOT/zsh/lib/config.group.zsh" \
|| FAIL 69 'failed to set up scwrypts group; aborting'
#####################################################################
@ -77,8 +58,7 @@ done
&& [ ! "$SCWRYPTS_AUTODETECT_GROUP_BASEDIR" ] \
&& [ $GITHUB_WORKSPACE ] \
&& [ ! $SCWRYPTS_GITHUB_NO_AUTOLOAD ] \
&& SCWRYPTS_AUTODETECT_GROUP_BASEDIR="$GITHUB_WORKSPACE" \
;
&& 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)
@ -88,8 +68,5 @@ done
}
#####################################################################
SCWRYPTS_GROUPS=(scwrypts $(echo $SCWRYPTS_GROUPS | sed 's/\s\+/\n/g' | sort -u | grep -v '^scwrypts$'))
#####################################################################
__SCWRYPT=1 # arbitrary; indicates currently inside a scwrypt
[ $NO_EXPORT_CONFIG ] || __SCWRYPT=1 # arbitrary; indicates currently inside a scwrypt
true

View File

@ -34,7 +34,7 @@ source "${0:a:h}/config.zsh"
use() {
local SCWRYPTS_LIBRARY SCWRYPTS_LIBRARY_ROOT SCWRYPTS_LIBRARY_GROUP
local DEFER_ENVIRONMENT_CHECK=true
local DEFER_ENVIRONMENT_CHECK=1
while [[ $# -gt 0 ]]
do
@ -49,8 +49,8 @@ use() {
SCWRYPTS_LIBRARY_ROOT=$2
shift 1
;;
-c | --check-environment )
DEFER_ENVIRONMENT_CHECK=false
--check-environment )
DEFER_ENVIRONMENT_CHECK=0
;;
* )
[ ! $SCWRYPTS_LIBRARY ] \
@ -106,7 +106,7 @@ use() {
return 1
}
[[ $DEFER_ENVIRONMENT_CHECK =~ false ]] && {
[[ $DEFER_ENVIRONMENT_CHECK -eq 0 ]] && {
CHECK_ENVIRONMENT || {
((IMPORT_ERRORS+=1))
ERROR "import error for '$SCWRYPTS_LIBRARY_GROUP/$SCWRYPTS_LIBRARY'"

View File

@ -12,10 +12,7 @@ SCWRYPTS__RUN() { # context wrapper to run scwrypts within scwrypts
local EXIT_CODE=0
((SUBSCWRYPT+=1))
SCWRYPTS_LOG_LEVEL=$SCWRYPTS_LOG_LEVEL \
SUBSCWRYPT=$SUBSCWRYPT \
$SCWRYPTS_ROOT__scwrypts/scwrypts $@
SUBSCWRYPT=$SUBSCWRYPT $SCWRYPTS_ROOT/run $@
EXIT_CODE=$?
((SUBSCWRYPT-=1))

View File

@ -12,7 +12,7 @@ SCWRYPTS__GET_AVAILABLE_SCWRYPTS() {
local GROUP GROUP_PATH GROUP_COLOR LOOKUP_PIDS=()
{
echo 'NAME^TYPE^GROUP'
for GROUP in ${SCWRYPTS_GROUPS[@]}
for GROUP in ${SCWRYPTS_GROUPS}
do
GROUP_PATH=$(eval echo '$SCWRYPTS_ROOT__'$GROUP)
GROUP_COLOR=$(eval echo '$SCWRYPTS_COLOR__'$GROUP)
@ -94,7 +94,7 @@ SCWRYPTS__GET_RUNSTRING() {
}
RUNSTRING="SCWRYPTS_ENV=$ENV_NAME; $RUNSTRING"
RUNSTRING="source $SCWRYPTS_ROOT__scwrypts/zsh/lib/import.driver.zsh; $RUNSTRING"
RUNSTRING="source $SCWRYPTS_ROOT/zsh/lib/import.driver.zsh; $RUNSTRING"
local _VIRTUALENV=$(eval echo '$SCWRYPTS_VIRTUALENV_PATH__'$SCWRYPT_GROUP'/$SCWRYPT_TYPE/bin/activate')
[ -f $_VIRTUALENV ] && RUNSTRING="source $_VIRTUALENV; $RUNSTRING"
@ -119,27 +119,6 @@ SCWRYPTS__GET_RUNSTRING__zsh() {
|| SCWRYPT_FILENAME="$GROUP_PATH/$SCWRYPT_TYPE/$SCWRYPT_NAME" \
;
SCWRYPTS__GET_RUNSTRING__zsh__generic "$SCWRYPT_FILENAME"
return 0
}
SCWRYPTS__GET_RUNSTRING__zsh__generic() {
# boilerplate to allow
# - multiflag splitting (e.g. -abc = -a -b -c)
# - help flag injection (e.g. -h | --help)
# - default USAGE definition (allows USAGE__options style usage definition)
# - required MAIN() function wrapping
#
# this is available automatically in SCWRYPTS_GROUP declaration contexts
# (e.g. my-group.scwrypts.zsh)
local ZSH_FILENAME="$1"
[ $ZSH_FILENAME ] || {
ERROR '
to use SCWRYPTS__GET_RUNSTRING__zsh__generic, you must provide a
ZSH_FILENAME (arg $1) where the MAIN function is defined
'
return 1
}
printf "
source '$SCWRYPT_FILENAME'
CHECK_ENVIRONMENT
@ -175,6 +154,22 @@ SCWRYPTS__GET_RUNSTRING__zsh__generic() {
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" \
;
return 0
}
SCWRYPTS__GET_RUNSTRING__py() {

View File

@ -74,8 +74,6 @@ _VIRTUALENV__GET_PATH() {
local ENV_PATH="$(eval echo '$SCWRYPTS_VIRTUALENV_PATH__'$GROUP 2>/dev/null)"
[ ! $ENV_PATH ] && ENV_PATH="$SCWRYPTS_VIRTUALENV_PATH__scwrypts"
mkdir -p "$ENV_PATH/$TYPE" &>/dev/null
echo $ENV_PATH/$TYPE
}
@ -97,7 +95,7 @@ CREATE_VIRTUALENV__scwrypts__py() {
}
done
[ ! $PYTHON ] && {
ERROR 'python>=3.10 not available; skipping python env'
ERROR 'python>=3.9 not available; skipping python env'
return 1
}
@ -124,7 +122,7 @@ UPDATE_VIRTUALENV__scwrypts__py() {
PIP_INSTALL_ARGS+=(--no-cache-dir)
PIP_INSTALL_ARGS+=(-r requirements.txt)
cd "$SCWRYPTS_ROOT__scwrypts/py"
cd "$SCWRYPTS_ROOT/py"
pip install ${PIP_INSTALL_ARGS[@]}
}
@ -161,9 +159,7 @@ ACTIVATE_VIRTUALENV__scwrypts__zx() {
UPDATE_VIRTUALENV__scwrypts__zx() {
local NPM_INSTALL_ARGS=()
[ $CI ] && NPM_INSTALL_ARGS+=(--ignore-scripts)
cd "$SCWRYPTS_ROOT__scwrypts/zx"
cd "$SCWRYPTS_ROOT/zx"
npm install ${NPM_INSTALL_ARGS[@]}
}

View File

@ -37,7 +37,7 @@ __CHECK_COREUTILS() {
do
__CHECK_DEPENDENCY $UTIL || { ((MISSING_DEPENDENCY_COUNT+=1)); continue; }
$UTIL --version 2>&1 | grep 'GNU' | grep -qv 'BSD' || {
$UTIL --version 2>&1 | grep -q 'GNU' || {
WARNING "non-GNU version of $UTIL detected"
((NON_GNU_DEPENDENCY_COUNT+=1))
}

View File

@ -1,8 +1,5 @@
FZF() {
[ $CI ] && {
DEBUG "invoked FZF with $@"
FAIL 1 'currently in CI, but FZF requires user input'
}
[ $CI ] && FAIL 1 'currently in CI, but FZF requires user input'
local FZF_ARGS=()
@ -43,3 +40,18 @@ FZF_USER_INPUT() { # allow user to type custom answers; reconfirm if ambiguous w
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

@ -5,61 +5,34 @@ PRINT() {
local STDOUT=0
local LTRIM=1
local FORMAT=$SCWRYPTS_OUTPUT_FORMAT
local _S
while [[ $# -gt 0 ]]
do
_S=1
case $1 in
-n | --no-trim-tabs ) LTRIM=0 ;;
-x | --no-line-end ) LAST_LINE_END='' ;;
-o | --use-stdout ) STDOUT=1; STDERR=0 ;;
-f | --format ) ((_S+=1)); FORMAT=$2 ;;
* ) MESSAGE+="$(echo $1) " ;;
esac
shift $_S
shift 1
done
[ $FORMAT ] || FORMAT=pretty
local STYLED_MESSAGE
case $FORMAT in
pretty )
STYLED_MESSAGE="$(echo "$MESSAGE" | sed 's/%/%%/g')"
STYLED_MESSAGE="$({
printf "${COLOR}"
while IFS='' read line
do
[[ $PREFIX =~ ^[[:space:]]\+$ ]] && printf '\n'
MESSAGE="$(echo "$MESSAGE" | sed 's/%/%%/g')"
printf "${PREFIX} : $(echo "$line" | sed 's/^ \+//; s/ \+$//')"
local STYLED_MESSAGE="$({
printf "${COLOR}"
while IFS='' read line
do
[[ $PREFIX =~ ^[[:space:]]\+$ ]] && printf '\n'
PREFIX=$(echo $PREFIX | sed 's/./ /g')
done <<< $MESSAGE
})"
STYLED_MESSAGE="${COLOR}$(echo "$STYLED_MESSAGE" | sed 's/%/%%/g')${__COLOR_RESET}${LAST_LINE_END}"
;;
json )
STYLED_MESSAGE="$(
echo '{}' | jq -c ".
| .timestamp = \"$(date +%s)\"
| .runtime = \"$SCWRYPTS_RUNTIME_ID\"
| .status = \"$(echo "$PREFIX" | sed 's/ .*//')\"
| .message = $(echo $MESSAGE | sed 's/^\t\+//' | jq -Rs)
" | sed 's/\\/\\\\/g'
)\n"
;;
* )
echo "ERROR : unsupported format '$FORMAT'" >&2
return 1
;;
esac
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"
[[ $STDERR -eq 1 ]] && printf $STYLED_MESSAGE >&2
[[ $STDOUT -eq 1 ]] && printf $STYLED_MESSAGE
return 0
}

View File

@ -6,7 +6,6 @@ source "${0:a:h}/io.print.zsh"
[ ! $ERRORS ] && ERRORS=0
ERROR() { # command encountered an error
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=4
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="ERROR ✖" COLOR=$__RED PRINT "$@"
((ERRORS+=1))
@ -14,47 +13,35 @@ ERROR() { # command encountered an error
}
SUCCESS() { # command completed successfully
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=4
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="SUCCESS ✔" COLOR=$__GREEN PRINT "$@"
return 0
}
REMINDER() { # include sysadmin reminder or other important notice to users
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=4
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="REMINDER " COLOR=$__BRIGHT_MAGENTA PRINT "$@"
return 0
}
STATUS() { # general status updates (prefer this to generic 'echo')
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=4
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] \
&& PREFIX="STATUS " COLOR=$__BLUE PRINT "$@"
return 0
}
WARNING() { # warning-level messages; not errors
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=4
[[ $SCWRYPTS_LOG_LEVEL -ge 3 ]] \
&& PREFIX="WARNING " COLOR=$__YELLOW PRINT "$@"
return 0
}
DEBUG() { # helpful during development or (sparingly) to help others' development
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=4
[[ $SCWRYPTS_LOG_LEVEL -ge 4 ]] \
&& PREFIX="DEBUG " COLOR=$__WHITE PRINT "$@"
return 0
}
PROMPT() { # you probably want to use yN or INPUT from below
[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=4
[[ $SCWRYPTS_LOG_LEVEL -ge 1 ]] \
&& PREFIX="PROMPT " COLOR=$__CYAN PRINT "$@" \
&& PREFIX="USER ⌨" COLOR=$__BRIGHT_CYAN PRINT '' --no-line-end \
;
return 0
}
FAIL() { SCWRYPTS_LOG_LEVEL=1 ERROR "${@:2}"; exit $1; }
@ -224,21 +211,15 @@ READ_YN() { # yes/no read is suprisingly tricky
local yn
PROMPT "${USERPROMPT[@]}"
local PERFORM_FAKE_PROMPT=false
case $SKIP_USER_INPUT in
true ) yn=y ;;
false )
[[ $SCWRYPTS_LOG_LEVEL -lt 1 ]] && {
[[ $FORCE_USER_INPUT =~ false ]] && [ ! -t 0 ] \
|| PERFORM_FAKE_PROMPT=true
}
[[ $PERFORM_FAKE_PROMPT =~ true ]] \
[[ $FORCE_USER_INPUT =~ true ]] && [[ $SCWRYPTS_LOG_LEVEL -lt 1 ]] \
&& echo -n "${USERPROMPT[@]} : " >&2
READ ${READ_ARGS[@]} -s -k yn
[[ $PERFORM_FAKE_PROMPT =~ true ]] \
[[ $FORCE_USER_INPUT =~ true ]] && [[ $SCWRYPTS_LOG_LEVEL -lt 1 ]] \
&& echo $yn >&2
;;
esac

View File

@ -72,7 +72,7 @@ CHECK_ENVIRONMENT() {
$E "environment errors found (see above)\n$ERROR_MESSAGE"
}
[[ $MISSING_ENVIRONMENT_VARIABLES -ne 0 ]] && [[ $__SCWRYPT ]] && {
[[ $MISSING_ENVIRONMENT_VARIABLES -ne 0 ]] && {
REMINDER "
to quickly update missing environment variables, run:
'scwrypts zsh/scwrypts/environment/edit'

6
zx/package-lock.json generated
View File

@ -31,7 +31,6 @@
"prettier": "^3.2.5",
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"typescript": "^5.3.3",
"uuid": "^9.0.1"
}
},
@ -4998,6 +4997,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
"dev": true,
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@ -8596,7 +8596,6 @@
"prettier": "^3.2.5",
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"typescript": "^5.3.3",
"uuid": "^9.0.1"
}
},
@ -8885,7 +8884,8 @@
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
"dev": true
"dev": true,
"peer": true
},
"undici-types": {
"version": "5.26.5",