From 31a5408a6c60fdd765426714c31119ca3d89a59b Mon Sep 17 00:00:00 2001 From: Oleg Lukasonok Date: Thu, 30 Jul 2026 22:18:55 +0300 Subject: [PATCH] Add development-scripts agent skill Ports generic-scripts-module-v1 into a routed skill: module anatomy, shared loggers/base modules, Taskfile integration, workflows, and pattern decisions. Fixes a latent defect in the loggers example that silenced all logging in the module scaffold: loggers/lib/--index-api.sh now sources --env-vars-reader.sh, and the reader preserves already-exported values so caller overrides still win. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 56 ++++- SKILL.md | 198 +++++++++++++++++ ...l-storage-ensure-existance-file-dot-env.sh | 11 + ...al-storage-read-lines-from-file-dot-env.sh | 11 + .../api/local-storage-reset-file-dot-env.sh | 11 + ...torage-save-env-variable-2-file-dot-env.sh | 11 + .../api/local-storage-view-file-dot-env.sh | 11 + assets/base/lib/--env-vars-reader.sh | 75 +++++++ assets/base/lib/--env-vars-validator.sh | 15 ++ assets/base/lib/--index-api.sh | 19 ++ assets/base/lib/--index.sh | 24 +++ .../lib/-ensure-env-var-ibm-user-api-key.sh | 41 ++++ .../lib/-ensure-env-var-ibm-user-email.sh | 41 ++++ assets/base/lib/-ensure-env-var-key.sh | 34 +++ assets/base/lib/-ensure-env-var-value.sh | 34 +++ assets/base/lib/-export-env-variable.sh | 35 +++ ...-export-env-variables-from-file-dot-env.sh | 19 ++ .../lib/-export-env-variables-from-file.sh | 40 ++++ .../lib/-get-env-variable-key-from-line.sh | 23 ++ .../lib/-get-env-variable-value-from-line.sh | 22 ++ assets/base/lib/-log-env-vars.sh | 19 ++ assets/base/lib/-prompt-for-env-var.sh | 35 +++ assets/base/lib/local-storage/--index-api.sh | 22 ++ .../-ensure-existance-file-dot-env.sh | 22 ++ .../local-storage/-ensure-existance-file.sh | 33 +++ .../-read-lines-from-file-dot-env.sh | 26 +++ .../local-storage/-read-lines-from-file.sh | 35 +++ .../lib/local-storage/-reset-file-dot-env.sh | 21 ++ assets/base/lib/local-storage/-reset-file.sh | 29 +++ .../-save-env-variable-2-file-dot-env.sh | 22 ++ .../-save-env-variable-2-file.sh | 62 ++++++ .../lib/local-storage/-view-file-dot-env.sh | 25 +++ assets/base/lib/local-storage/-view-file.sh | 30 +++ assets/loggers/lib/--env-vars-reader.sh | 23 ++ assets/loggers/lib/--index-api.sh | 25 +++ assets/loggers/lib/--index.sh | 12 ++ assets/loggers/lib/-debug.sh | 21 ++ assets/loggers/lib/-empty-line.sh | 14 ++ .../loggers/lib/-enable-trailing-new-line.sh | 16 ++ assets/loggers/lib/-error.sh | 22 ++ assets/loggers/lib/-info.sh | 21 ++ assets/loggers/lib/-trace.sh | 22 ++ assets/loggers/lib/-waiting-dot.sh | 14 ++ assets/loggers/lib/-warn.sh | 21 ++ assets/module-example-v1/README.md | 13 ++ assets/module-example-v1/Taskfile.yml | 10 + .../module-example-v1/api/initialize-one.sh | 5 + .../lib/--env-vars-reader.sh | 25 +++ .../lib/--env-vars-validator.sh | 8 + assets/module-example-v1/lib/--index-api.sh | 6 + assets/module-example-v1/lib/--index.sh | 15 ++ .../module-example-v1/lib/-initialize-one.sh | 19 ++ references/module-anatomy.md | 203 ++++++++++++++++++ references/module-patterns.md | 66 ++++++ references/shared-modules.md | 165 ++++++++++++++ references/taskfile.md | 76 +++++++ references/workflows.md | 118 ++++++++++ 57 files changed, 2051 insertions(+), 1 deletion(-) create mode 100644 SKILL.md create mode 100755 assets/base/api/local-storage-ensure-existance-file-dot-env.sh create mode 100755 assets/base/api/local-storage-read-lines-from-file-dot-env.sh create mode 100755 assets/base/api/local-storage-reset-file-dot-env.sh create mode 100755 assets/base/api/local-storage-save-env-variable-2-file-dot-env.sh create mode 100755 assets/base/api/local-storage-view-file-dot-env.sh create mode 100755 assets/base/lib/--env-vars-reader.sh create mode 100755 assets/base/lib/--env-vars-validator.sh create mode 100755 assets/base/lib/--index-api.sh create mode 100755 assets/base/lib/--index.sh create mode 100755 assets/base/lib/-ensure-env-var-ibm-user-api-key.sh create mode 100755 assets/base/lib/-ensure-env-var-ibm-user-email.sh create mode 100755 assets/base/lib/-ensure-env-var-key.sh create mode 100755 assets/base/lib/-ensure-env-var-value.sh create mode 100755 assets/base/lib/-export-env-variable.sh create mode 100755 assets/base/lib/-export-env-variables-from-file-dot-env.sh create mode 100755 assets/base/lib/-export-env-variables-from-file.sh create mode 100755 assets/base/lib/-get-env-variable-key-from-line.sh create mode 100755 assets/base/lib/-get-env-variable-value-from-line.sh create mode 100755 assets/base/lib/-log-env-vars.sh create mode 100644 assets/base/lib/-prompt-for-env-var.sh create mode 100755 assets/base/lib/local-storage/--index-api.sh create mode 100755 assets/base/lib/local-storage/-ensure-existance-file-dot-env.sh create mode 100755 assets/base/lib/local-storage/-ensure-existance-file.sh create mode 100755 assets/base/lib/local-storage/-read-lines-from-file-dot-env.sh create mode 100755 assets/base/lib/local-storage/-read-lines-from-file.sh create mode 100755 assets/base/lib/local-storage/-reset-file-dot-env.sh create mode 100755 assets/base/lib/local-storage/-reset-file.sh create mode 100755 assets/base/lib/local-storage/-save-env-variable-2-file-dot-env.sh create mode 100755 assets/base/lib/local-storage/-save-env-variable-2-file.sh create mode 100755 assets/base/lib/local-storage/-view-file-dot-env.sh create mode 100755 assets/base/lib/local-storage/-view-file.sh create mode 100755 assets/loggers/lib/--env-vars-reader.sh create mode 100755 assets/loggers/lib/--index-api.sh create mode 100755 assets/loggers/lib/--index.sh create mode 100755 assets/loggers/lib/-debug.sh create mode 100755 assets/loggers/lib/-empty-line.sh create mode 100755 assets/loggers/lib/-enable-trailing-new-line.sh create mode 100755 assets/loggers/lib/-error.sh create mode 100755 assets/loggers/lib/-info.sh create mode 100755 assets/loggers/lib/-trace.sh create mode 100755 assets/loggers/lib/-waiting-dot.sh create mode 100755 assets/loggers/lib/-warn.sh create mode 100644 assets/module-example-v1/README.md create mode 100644 assets/module-example-v1/Taskfile.yml create mode 100644 assets/module-example-v1/api/initialize-one.sh create mode 100644 assets/module-example-v1/lib/--env-vars-reader.sh create mode 100644 assets/module-example-v1/lib/--env-vars-validator.sh create mode 100644 assets/module-example-v1/lib/--index-api.sh create mode 100644 assets/module-example-v1/lib/--index.sh create mode 100644 assets/module-example-v1/lib/-initialize-one.sh create mode 100644 references/module-anatomy.md create mode 100644 references/module-patterns.md create mode 100644 references/shared-modules.md create mode 100644 references/taskfile.md create mode 100644 references/workflows.md diff --git a/README.md b/README.md index 7eae57d..346f6d8 100644 --- a/README.md +++ b/README.md @@ -1 +1,55 @@ -# development-scripts \ No newline at end of file +# development-scripts + +Agent Skill for shell script modules under a repository's `.scripts/` directory — the +`api/` + `lib/` split, the `--index.sh` bootstrap chain, Taskfile integration, and the shared +`loggers` and `base` foundation modules. + +## Layout + +```text +development-scripts/ +├── SKILL.md # Entry point — routing, anatomy, naming, runtime flow +├── references/ +│ ├── module-anatomy.md # Reader, validator, index files, implementations, wrappers +│ ├── shared-modules.md # loggers and base, and the logging bootstrap rule +│ ├── taskfile.md # Module and root Taskfile integration +│ ├── workflows.md # Create, change, validate +│ └── module-patterns.md # Module type and dependency decision guide +└── assets/ + ├── module-example-v1/ # Scaffold to copy for a new module + ├── loggers/ # Working reference implementation + └── base/ # Working reference implementation +``` + +## The model + +```text +/ + Taskfile.yml + .scripts/ + / + api/ # public command wrappers — what users run + lib/ # implementation functions — what the code calls + Taskfile.yml # only when exposed through task +``` + +Commands run from the repository root: + +```bash +./.scripts//api/.sh --dry-run +task : -- --dry-run +``` + +Every source path is repository-root-relative, and the bootstrap chain — reader, then +validator, then API index — guarantees an implementation function sees a fully-prepared +environment. + +## Deploy + +```bash +cd ../skill-manager/scripts +task deploy -- --skill-dir="$(cd ../../development-scripts && pwd)" +``` + +Built with the `skill-manager` skill, following the +[agentskills.io specification](https://agentskills.io/specification). diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..6b4d397 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,198 @@ +--- +name: development-scripts +description: > + Create, refactor, review, document, and maintain shell script modules under a repository's + .scripts/ directory — the api/ + lib/ split, the --index.sh / --index-api.sh / + --env-vars-reader.sh / --env-vars-validator.sh bootstrap chain, module and root Taskfile.yml + integration, logging through the shared loggers module, and shared helpers from the base + module. Use when adding a new script module or a new command to an existing one; writing an + api/ wrapper or a lib/ implementation function; adding a CLI flag or a required environment + variable; wiring a module into task; debugging a script that produces no output, cannot find + a function, or unexpectedly loads .env; or reviewing shell module work for naming, sourcing + order, and secret-safety — even when the user only says ".scripts", "Taskfile", "task + runner", "shell module", or names a specific module like loggers or base. +license: Proprietary +metadata: + author: workspace-skills-code-agent + version: "1.0" + spec: agentskills.io/specification +compatibility: Requires bash. Taskfile (task) needed only for task-runner integration. Designed for Cline, Claude Code, GitHub Copilot, OpenAI Codex, and other compatible agent environments +--- + +# Repository Script Modules + +Work rules for shell automation organised as modules under a repository's `.scripts/` +directory, with a strict public/private split and a fixed sourcing order. + +The whole model rests on one idea: **`api/` is what people run, `lib/` is what the code +calls, and a single bootstrap chain guarantees that by the time an implementation function +runs, its environment has been read, validated, and its dependencies sourced.** + +## Scope routing + +Pick the reference that matches the change; do not load all of them. + +| The change touches | Read | +|---|---| +| A reader, validator, implementation function, or `api/` wrapper | `references/module-anatomy.md` | +| The `loggers` or `base` module, or logging that produces no output | `references/shared-modules.md` | +| A module `Taskfile.yml` or the root `Taskfile.yml` | `references/taskfile.md` | +| Creating a module, changing one, or checking work before delivery | `references/workflows.md` | +| Deciding what kind of module something should be | `references/module-patterns.md` | + +Copy-ready modules live in `assets/`: `module-example-v1/` is the scaffold for a new module; +`loggers/` and `base/` are working reference implementations. + +## 1. Repository model + +```text +/ + Taskfile.yml # root task runner, includes module Taskfiles + .scripts/ + / + api/ # public command wrappers — what users run + lib/ # implementation functions — what the code calls + Taskfile.yml # only when the module is exposed through task +``` + +Commands always run **from the repository root**, never from inside the module: + +```bash +./.scripts//api/.sh [args] +task : -- [args] +``` + +Every `.` source path in every file is written relative to the repository root +(`. ./.scripts/loggers/lib/--index-api.sh`). This is why running a script from inside its own +directory fails to find its dependencies — that is the convention working as designed, not a +bug to patch with `dirname "$0"`. + +## 2. Module anatomy + +```text +.scripts// + api/ + .sh + lib/ + --env-vars-reader.sh # defaults + CLI flag parsing + --env-vars-validator.sh # required-input checks + --index-api.sh # sources dependencies + this module's implementations + --index.sh # full runtime bootstrap + -.sh # one implementation function per command + Taskfile.yml # optional +``` + +| File | Responsibility | +|---|---| +| `api/.sh` | Thin public entrypoint. Sources `lib/--index.sh`, calls one function. | +| `lib/-.sh` | The command implementation function. | +| `lib/--index-api.sh` | Sources upstream module APIs, then this module's implementation files. | +| `lib/--index.sh` | Runtime bootstrap: reader, then validator, then API index. | +| `lib/--env-vars-reader.sh` | Exports defaults and parses CLI arguments into environment variables. | +| `lib/--env-vars-validator.sh` | Validates required variables, failing with an actionable log. | +| `Taskfile.yml` | Maps task names to `api/` scripts, forwarding `{{.CLI_ARGS}}`. | + +Not every module has every file — a support-only library like `loggers` has no `api/` and no +`Taskfile.yml`. See `references/module-patterns.md`. + +## 3. Standard runtime flow + +```text +api/.sh + └── source lib/--index.sh + ├── source lib/--env-vars-reader.sh # defaults + CLI flags → env vars + ├── source lib/--env-vars-validator.sh # required vars present? + └── source lib/--index-api.sh + ├── source dependencies (loggers, base, …) + └── source lib/-.sh # defines the function + └── call __ +``` + +**The order is load-bearing.** The reader runs before the validator so the validator has +something to check; both run before the API index so implementation functions see a +fully-prepared environment. Reordering produces failures that look like missing variables. + +Arguments reach the reader because sourcing happens with the wrapper's own arguments still in +scope — this is why `api/` wrappers need no argument forwarding of their own. + +## 4. Naming conventions + +| Kind | Convention | Example | +|---|---|---| +| Module directory | lowercase kebab-case | `module-example-v1`, `repositories-nodejs` | +| Public command | lowercase kebab-case, action-oriented | `initialize-one.sh`, `find-many-by-query.sh` | +| Implementation file | single leading dash | `lib/-initialize-one.sh` | +| Index / lifecycle file | double leading dash | `lib/--index.sh`, `lib/--env-vars-reader.sh` | +| Function | `__` | `_moduleExampleV1_initializeOne` | +| Environment variable | uppercase module prefix | `MODULE_EXAMPLE_V1_OUTPUT_DIR` | + +Kebab-case module names convert to camelCase function namespaces: + +| Module | Function prefix | Env prefix | +|---|---|---| +| `module-example-v1` | `_moduleExampleV1_` | `MODULE_EXAMPLE_V1_` | +| `repositories-nodejs` | `_repositoriesNodejs_` | `REPOSITORIES_NODEJS_` | +| `operation-utilities` | `_operationUtilities_` | `OPERATION_UTILITIES_` | + +The dash count is not decoration — it is how you tell at a glance whether a file defines a +command (`-name.sh`) or wires the module together (`--name.sh`). + +## 5. Non-negotiable rules + +- **`api/` wrappers stay thin.** Source `lib/--index.sh`, call one function, nothing else. No + implementation, no argument parsing, no validation. +- **CLI flags are parsed only in `--env-vars-reader.sh`.** Never in an implementation file. +- **Every new `lib/-*.sh` gets added to `lib/--index-api.sh`.** Forgetting this is the most + common cause of "command not found" for a function that plainly exists. +- **Readers preserve already-exported values** — `export X="${X:-default}"` — so a caller can + override any setting before invoking the module. +- **Log through `_loggers_*` helpers, never raw `echo`.** Loggers write to `stderr`, keeping + `stdout` clean for real output. +- **Never log secrets.** Redact tokens, API keys, passwords, and kube config. +- **Quote variable expansions** unless word splitting is intended. +- **`return` non-zero from implementation functions; reserve `exit 1` for validators and + bootstrap.** An `exit` inside a sourced library kills the caller's shell. + +## 6. Creating a module + +Full walkthrough in `references/workflows.md`. The short path: + +1. Copy `assets/module-example-v1/` to `.scripts//`. +2. Replace every `module-example-v1` path, the `MODULE_EXAMPLE_V1_` env prefix, and the + `_moduleExampleV1_` function prefix. +3. Add implementation files as `lib/-.sh` and source them from `lib/--index-api.sh`. +4. Add `api/.sh` wrappers for user-facing commands only. +5. Add a module `Taskfile.yml`, and a root include only if the namespace is stable. +6. Validate (section 7). + +## 7. Validation + +```bash +# Syntax-check every script in the module +find .scripts/ -name '*.sh' -print0 | xargs -0 -n1 bash -n + +# Confirm task exposure resolves +task --list + +# Run the command itself, from the repository root +./.scripts//api/.sh --dry-run +``` + +`bash -n` catches syntax errors but **not** a missing entry in `--index-api.sh` — that only +surfaces at call time. Always run the command once, from the repository root, before +delivering. A dry-run flag is worth adding precisely so this check is cheap. + +## 8. Mistakes to avoid + +- Putting implementation logic into `api/*.sh`. +- Adding a `lib/-*.sh` file and forgetting to source it from `lib/--index-api.sh`. +- Parsing CLI flags in an implementation function instead of the reader. +- Sourcing `base/lib/--index.sh` from a library function — it reads `.env` and + environment-specific files as a side effect. Use `base/lib/--index-api.sh` when you only + need shared functions. +- Writing source paths relative to the script instead of the repository root. +- Using `exit` inside a sourced implementation function. +- Printing secrets, or documenting their values. +- Adding a root `Taskfile.yml` include for an experimental module. +- Assuming logging works because the code compiles — a logger whose level flags were never + exported is silent and returns 0. See `references/shared-modules.md` §3. diff --git a/assets/base/api/local-storage-ensure-existance-file-dot-env.sh b/assets/base/api/local-storage-ensure-existance-file-dot-env.sh new file mode 100755 index 0000000..1f25a38 --- /dev/null +++ b/assets/base/api/local-storage-ensure-existance-file-dot-env.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/base/lib/--index.sh + +_base_localStorage_ensureExistance_fileDotEnv diff --git a/assets/base/api/local-storage-read-lines-from-file-dot-env.sh b/assets/base/api/local-storage-read-lines-from-file-dot-env.sh new file mode 100755 index 0000000..3397fcc --- /dev/null +++ b/assets/base/api/local-storage-read-lines-from-file-dot-env.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/base/lib/--index.sh + +_base_localStorage_readLinesFrom_fileDotEnv diff --git a/assets/base/api/local-storage-reset-file-dot-env.sh b/assets/base/api/local-storage-reset-file-dot-env.sh new file mode 100755 index 0000000..9dfd3f9 --- /dev/null +++ b/assets/base/api/local-storage-reset-file-dot-env.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/base/lib/--index.sh + +_base_localStorage_reset_fileDotEnv diff --git a/assets/base/api/local-storage-save-env-variable-2-file-dot-env.sh b/assets/base/api/local-storage-save-env-variable-2-file-dot-env.sh new file mode 100755 index 0000000..f4e9429 --- /dev/null +++ b/assets/base/api/local-storage-save-env-variable-2-file-dot-env.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/base/lib/--index.sh + +_base_localStorage_saveEnvVariable2_fileDotEnv diff --git a/assets/base/api/local-storage-view-file-dot-env.sh b/assets/base/api/local-storage-view-file-dot-env.sh new file mode 100755 index 0000000..96961dd --- /dev/null +++ b/assets/base/api/local-storage-view-file-dot-env.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/base/lib/--index.sh + +_base_localStorage_view_fileDotEnv diff --git a/assets/base/lib/--env-vars-reader.sh b/assets/base/lib/--env-vars-reader.sh new file mode 100755 index 0000000..6575734 --- /dev/null +++ b/assets/base/lib/--env-vars-reader.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--env-vars-reader.sh + +TMP_BASE_LIB_ENV_VARS_READER=".scripts/base/lib/--env-vars-reader.sh" + +export LOCAL_OS_TYPE="darwin" +export LOCAL_CPU_TYPE="amd64" +export LOCAL_HOME_DIR=$(pwd) +export LOCAL_HOME_DIR_NAME=${PWD##*/} +export LOCAL_GIT_ROOT_DIR=$(dirname "${LOCAL_HOME_DIR}") +export LOCAL_CACHE_DIR_KUBE=".kube" + +export LOCAL_FILE_DOT_ENV=".env" + +# Pre-load CA_ENVIRONMENT from .env if not already set +if [ -z "${CA_ENVIRONMENT}" ] && [ -f "${LOCAL_FILE_DOT_ENV}" ]; then + export CA_ENVIRONMENT=$(grep '^CA_ENVIRONMENT=' "${LOCAL_FILE_DOT_ENV}" | cut -d'=' -f2- | tr -d '"' | tr -d "'") +fi + +export LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT=".env-${CA_ENVIRONMENT}" + +. ./.scripts/base/lib/-export-env-variables-from-file-dot-env.sh + +_loggers_info "${CA_ENVIRONMENT}" "CA_ENVIRONMENT: ${CA_ENVIRONMENT}" +_loggers_info "${CA_ENVIRONMENT}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}" +_loggers_info "${CA_ENVIRONMENT}" "LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT: ${LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT}" + +if + [ ! -e "${LOCAL_FILE_DOT_ENV}" ] +then + _loggers_error "${LOCAL_FILE_DOT_ENV}" "Missing ${LOCAL_FILE_DOT_ENV} file." + exit 1 +else + set -o allexport + . "./${LOCAL_FILE_DOT_ENV}" + set +o allexport +fi + +if + [ ! -e "${LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT}" ] +then + _loggers_error "${TMP_BASE_LIB_ENV_VARS_READER}" "Missing ${LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT} file." + exit 1 +else + set -o allexport + . "./${LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT}" + set +o allexport +fi + +mkdir -p "${LOCAL_CACHE_DIR_KUBE}" + +ALL_ARGS=("$@") +while [[ "$#" -gt 0 ]]; do + case $1 in + --local-os-type) + export LOCAL_OS_TYPE="$2" + ;; + --local-cpu-type) + export LOCAL_CPU_TYPE="$2" + ;; + --local-file-dot-env) + export LOCAL_FILE_DOT_ENV="$2" + ;; + *) ;; + esac + shift +done +set -- "${ALL_ARGS[@]}" diff --git a/assets/base/lib/--env-vars-validator.sh b/assets/base/lib/--env-vars-validator.sh new file mode 100755 index 0000000..ecad441 --- /dev/null +++ b/assets/base/lib/--env-vars-validator.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/-ensure-env-var-ibm-user-email.sh +. ./.scripts/base/lib/-ensure-env-var-ibm-user-api-key.sh + +_base_ensureEnvVarIbmUserEmail +_base_ensureEnvVarIbmUserApiKey diff --git a/assets/base/lib/--index-api.sh b/assets/base/lib/--index-api.sh new file mode 100755 index 0000000..5b41a26 --- /dev/null +++ b/assets/base/lib/--index-api.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/base/lib/-export-env-variable.sh +. ./.scripts/base/lib/-export-env-variables-from-file-dot-env.sh +. ./.scripts/base/lib/-export-env-variables-from-file.sh + +. ./.scripts/base/lib/-get-env-variable-key-from-line.sh +. ./.scripts/base/lib/-get-env-variable-value-from-line.sh + +. ./.scripts/base/lib/local-storage/--index-api.sh + +. ./.scripts/base/lib/-log-env-vars.sh +. ./.scripts/base/lib/-prompt-for-env-var.sh diff --git a/assets/base/lib/--index.sh b/assets/base/lib/--index.sh new file mode 100755 index 0000000..ed2c1d7 --- /dev/null +++ b/assets/base/lib/--index.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- +# +# --> passed parameters are read & exported environment variables +# +. ./.scripts/base/lib/--env-vars-reader.sh +# +# --> required environment variables are validated for existance +# +. ./.scripts/base/lib/--env-vars-validator.sh +# +# --> Importing local shell packages +# +. ./.scripts/loggers/lib/--index-api.sh +# +# --> available functions are imported/exported +# +. ./.scripts/base/lib/--index-api.sh +# ------------------------------------------------------------------------------------- diff --git a/assets/base/lib/-ensure-env-var-ibm-user-api-key.sh b/assets/base/lib/-ensure-env-var-ibm-user-api-key.sh new file mode 100755 index 0000000..e5ee2aa --- /dev/null +++ b/assets/base/lib/-ensure-env-var-ibm-user-api-key.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- +set -e + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/--index-api.sh + +_base_ensureEnvVarIbmUserApiKey() { + local FUNCTION_NAME="_base_ensureEnvVarIbmUserApiKey" + + local TMP_IBM_USER_API_KEY="" + if + [ -z "${IBM_USER_API_KEY}" ] + then + while + true + do + _loggers_emptyLine + read -rep $'Provide for IBM_USER_API_KEY environment variable! \n\n> ' TMP_IBM_USER_API_KEY + if + [ ! -z "${TMP_IBM_USER_API_KEY}" ] + then + export IBM_USER_API_KEY="${TMP_IBM_USER_API_KEY}" + export ENV_VAR_KEY="IBM_USER_API_KEY" + export ENV_VAR_VALUE="${IBM_USER_API_KEY}" + _base_localStorage_saveEnvVariable2_fileDotEnv + break + else + _loggers_emptyLine + _loggers_warn "${FUNCTION_NAME}" "Provided value can not be empty!" + fi + done + fi + _loggers_debug "${FUNCTION_NAME}" "IBM_USER_API_KEY: *REDACTED*" +} diff --git a/assets/base/lib/-ensure-env-var-ibm-user-email.sh b/assets/base/lib/-ensure-env-var-ibm-user-email.sh new file mode 100755 index 0000000..e4cbd83 --- /dev/null +++ b/assets/base/lib/-ensure-env-var-ibm-user-email.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- +set -e + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/--index-api.sh + +_base_ensureEnvVarIbmUserEmail() { + local FUNCTION_NAME="_base_ensureEnvVarIbmUserEmail" + + local TMP_IBM_USER_EMAIL="" + if + [ -z "${IBM_USER_EMAIL}" ] + then + while + true + do + _loggers_emptyLine + read -rep $'Provide for IBM_USER_EMAIL environment variable! \n\n> ' TMP_IBM_USER_EMAIL + if + [ ! -z "${TMP_IBM_USER_EMAIL}" ] + then + export IBM_USER_EMAIL="${TMP_IBM_USER_EMAIL}" + export ENV_VAR_KEY="IBM_USER_EMAIL" + export ENV_VAR_VALUE="${IBM_USER_EMAIL}" + _base_localStorage_saveEnvVariable2_fileDotEnv + break + else + _loggers_emptyLine + _loggers_warn "${FUNCTION_NAME}" "Provided value can not be empty!" + fi + done + fi + _loggers_debug "${FUNCTION_NAME}" "IBM_USER_EMAIL: ${IBM_USER_EMAIL}" +} diff --git a/assets/base/lib/-ensure-env-var-key.sh b/assets/base/lib/-ensure-env-var-key.sh new file mode 100755 index 0000000..d57406b --- /dev/null +++ b/assets/base/lib/-ensure-env-var-key.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_ensure_evnVarKey() { + local FUNCTION_NAME="_base_ensure_evnVarKey" + _loggers_debug "${FUNCTION_NAME}" + + while + true + do + if + [ ! -z "${ENV_VAR_KEY}" ] + then + break + fi + _loggers_emptyLine + read -rep $'Provide environment variable key! \n> ' TMP_ENV_VAR_KEY + if + [ -z "$TMP_ENV_VAR_KEY" ] + then + _loggers_errorX "${FUNCTION_NAME}" "Provided environment variable key can not be empty!" + else + export ENV_VAR_KEY="$TMP_ENV_VAR_KEY" + fi + _loggers_emptyLine + done +} diff --git a/assets/base/lib/-ensure-env-var-value.sh b/assets/base/lib/-ensure-env-var-value.sh new file mode 100755 index 0000000..2c6d199 --- /dev/null +++ b/assets/base/lib/-ensure-env-var-value.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_ensure_evnVarValue() { + local FUNCTION_NAME="_base_ensure_evnVarValue" + _loggers_debug "${FUNCTION_NAME}" + + while + true + do + if + [ ! -z "${ENV_VAR_VALUE}" ] + then + break + fi + _loggers_emptyLine + read -rep $'Provide environment variable value! \n> ' TMP_ENV_VAR_VALUE + if + [ -z "${TMP_ENV_VAR_VALUE}" ] + then + _loggers_errorX "${FUNCTION_NAME}" "Provided environment variable value can not be empty!" + else + export ENV_VAR_VALUE="${TMP_ENV_VAR_VALUE}" + fi + _loggers_emptyLine + done +} diff --git a/assets/base/lib/-export-env-variable.sh b/assets/base/lib/-export-env-variable.sh new file mode 100755 index 0000000..86aebaa --- /dev/null +++ b/assets/base/lib/-export-env-variable.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_exportEnvVariable() { + local FUNCTION_NAME="_base_exportEnvVariable" + + local PARAM_ENV_VAR_KEY="${1}" + local PARAM_ENV_VAR_VALUE="${2}" + + if + [ true ] && + [ ! -z "${PARAM_ENV_VAR_KEY}" ] && + [ ! -z "${PARAM_ENV_VAR_VALUE}" ] + then + _loggers_trace "${FUNCTION_NAME}" "PARAM_ENV_VAR_KEY: ${PARAM_ENV_VAR_KEY}" + _loggers_trace "${FUNCTION_NAME}" "PARAM_ENV_VAR_VALUE: ${PARAM_ENV_VAR_VALUE}" + + printf -v "${PARAM_ENV_VAR_KEY}" "${PARAM_ENV_VAR_VALUE}" + export $PARAM_ENV_VAR_KEY + else + _loggers_warn "${FUNCTION_NAME}" + _loggers_warn "${FUNCTION_NAME}" "Missing one of passed parameters!" + _loggers_warn "${FUNCTION_NAME}" "" + _loggers_warn "${FUNCTION_NAME}" "PARAM_ENV_VAR_KEY: ${PARAM_ENV_VAR_KEY}" + _loggers_warn "${FUNCTION_NAME}" "PARAM_ENV_VAR_VALUE: ${PARAM_ENV_VAR_VALUE}" + fi + +} diff --git a/assets/base/lib/-export-env-variables-from-file-dot-env.sh b/assets/base/lib/-export-env-variables-from-file-dot-env.sh new file mode 100755 index 0000000..0c059e2 --- /dev/null +++ b/assets/base/lib/-export-env-variables-from-file-dot-env.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/-export-env-variables-from-file.sh + +_base_exportEnvVarsFrom_fileDotEnv() { + local FUNCTION_NAME="_base_exportEnvVarsFrom_fileDotEnv" + + _loggers_debug "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}" + + _base_exportEnvVariablesFrom_file "${LOCAL_FILE_DOT_ENV}" +} diff --git a/assets/base/lib/-export-env-variables-from-file.sh b/assets/base/lib/-export-env-variables-from-file.sh new file mode 100755 index 0000000..a7628ba --- /dev/null +++ b/assets/base/lib/-export-env-variables-from-file.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh + +. ./.scripts/base/lib/-export-env-variable.sh + +. ./.scripts/base/lib/-get-env-variable-key-from-line.sh +. ./.scripts/base/lib/-get-env-variable-value-from-line.sh + +_base_exportEnvVariablesFrom_file() { + local FUNCTION_NAME="_base_exportEnvVariablesFrom_file" + local FILE_RELATIVE_PATH=${1} + + _loggers_trace "${FUNCTION_NAME}" "FILE_RELATIVE_PATH: ${FILE_RELATIVE_PATH}" + _base_localStorage_ensureExistance_file "${FILE_RELATIVE_PATH}" + + while read TMP_FILE_ENV_LINE; do + if + [ ! -z "${TMP_FILE_ENV_LINE}" ] + then + + local TMP_KEY=$( + _base_getEnvVariableKey_fromLine "${TMP_FILE_ENV_LINE}" + ) + local TMP_VALUE=$( + _base_getEnvVariableValue_fromLine "${TMP_FILE_ENV_LINE}" + ) + _base_exportEnvVariable "${TMP_KEY}" "${TMP_VALUE}" + + fi + done <"${FILE_RELATIVE_PATH}" +} diff --git a/assets/base/lib/-get-env-variable-key-from-line.sh b/assets/base/lib/-get-env-variable-key-from-line.sh new file mode 100755 index 0000000..7908f42 --- /dev/null +++ b/assets/base/lib/-get-env-variable-key-from-line.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_getEnvVariableKey_fromLine() { + local FUNCTION_NAME="_base_getEnvVariableKey_fromLine" + + local PARAM_LINE="${1}" + _loggers_trace "${FUNCTION_NAME}" "PARAM_LINE: ${PARAM_LINE}" + + local RET_VAL=$( + echo "${PARAM_LINE}" | awk -F "=" '{print $1}' + ) + _loggers_trace "${FUNCTION_NAME}" "RET_VAL: ${RET_VAL}" + + echo "${RET_VAL}" +} diff --git a/assets/base/lib/-get-env-variable-value-from-line.sh b/assets/base/lib/-get-env-variable-value-from-line.sh new file mode 100755 index 0000000..85ec01b --- /dev/null +++ b/assets/base/lib/-get-env-variable-value-from-line.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_getEnvVariableValue_fromLine() { + local FUNCTION_NAME="_base_getEnvVariableValue_fromLine" + local TMP_LINE="${1}" + local RET_VAL=$( + echo $TMP_LINE | awk -F "=" '{print $2}' + ) + RET_VAL=$( + echo "${RET_VAL}" | sed 's/^"\(.*\)"$/\1/' + ) + _loggers_trace "${FUNCTION_NAME}" "RET_VAL: ${RET_VAL}" + echo "${RET_VAL}" +} diff --git a/assets/base/lib/-log-env-vars.sh b/assets/base/lib/-log-env-vars.sh new file mode 100755 index 0000000..84080b6 --- /dev/null +++ b/assets/base/lib/-log-env-vars.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_logEnvVars() { + local FUNCTION_NAME="_base_logEnvVars" + _loggers_debug "${FUNCTION_NAME}" + + _loggers_info "${FUNCTION_NAME}" "LOCAL_OS_TYPE: ${LOCAL_OS_TYPE}" + _loggers_info "${FUNCTION_NAME}" "LOCAL_CPU_TYPE: ${LOCAL_CPU_TYPE}" + _loggers_info "${FUNCTION_NAME}" "LOCAL_HOME_DIR: ${LOCAL_HOME_DIR}" + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}" +} diff --git a/assets/base/lib/-prompt-for-env-var.sh b/assets/base/lib/-prompt-for-env-var.sh new file mode 100644 index 0000000..3e76868 --- /dev/null +++ b/assets/base/lib/-prompt-for-env-var.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +prompt_for_env_var() { + local var_name="$1" + local function_name="${FUNCNAME[1]:-unknown_function}" + + if [ -z "${!var_name}" ]; then + while true; do + _loggers_emptyLine + echo -e "Provide a value for ${var_name} environment variable!\n" + read -rep "> " tmp_value + + if [ -n "${tmp_value}" ]; then + export "${var_name}=${tmp_value}" + export ENV_VAR_KEY="${var_name}" + export ENV_VAR_VALUE="${tmp_value}" + _base_localStorage_saveEnvVariable2_fileDotEnv + break + else + _loggers_emptyLine + _loggers_warn "${function_name}" "Provided value cannot be empty!" + fi + done + fi + + _loggers_debug "${function_name}" "${var_name}: *REDACTED*" +} + diff --git a/assets/base/lib/local-storage/--index-api.sh b/assets/base/lib/local-storage/--index-api.sh new file mode 100755 index 0000000..0b9eabd --- /dev/null +++ b/assets/base/lib/local-storage/--index-api.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/base/lib/local-storage/-ensure-existance-file-dot-env.sh +. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh + +. ./.scripts/base/lib/local-storage/-read-lines-from-file-dot-env.sh +. ./.scripts/base/lib/local-storage/-read-lines-from-file.sh + +. ./.scripts/base/lib/local-storage/-reset-file-dot-env.sh +. ./.scripts/base/lib/local-storage/-reset-file.sh + +. ./.scripts/base/lib/local-storage/-save-env-variable-2-file-dot-env.sh +. ./.scripts/base/lib/local-storage/-save-env-variable-2-file.sh + +. ./.scripts/base/lib/local-storage/-view-file-dot-env.sh +. ./.scripts/base/lib/local-storage/-view-file.sh diff --git a/assets/base/lib/local-storage/-ensure-existance-file-dot-env.sh b/assets/base/lib/local-storage/-ensure-existance-file-dot-env.sh new file mode 100755 index 0000000..8e5c58f --- /dev/null +++ b/assets/base/lib/local-storage/-ensure-existance-file-dot-env.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh + +_base_localStorage_ensureExistance_fileDotEnv() { + local FUNCTION_NAME="_base_localStorage_ensureExistance_fileDotEnv" + _loggers_debug "${FUNCTION_NAME}" + + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}" + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}" + + _base_localStorage_ensureExistance_file "${LOCAL_FILE_DOT_ENV}" + +} diff --git a/assets/base/lib/local-storage/-ensure-existance-file.sh b/assets/base/lib/local-storage/-ensure-existance-file.sh new file mode 100755 index 0000000..811de08 --- /dev/null +++ b/assets/base/lib/local-storage/-ensure-existance-file.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_localStorage_ensureExistance_file() { + local FUNCTION_NAME="_base_localStorage_ensureExistance_file" + # _loggers_info "${FUNCTION_NAME}" + + local FILE_RELATIVE_PATH="${1}" + + if + [ -z "${FILE_RELATIVE_PATH}" ] + then + _loggers_error "${FUNCTION_NAME}" + _loggers_error "${FUNCTION_NAME}" "Missing mandatory 1st paramter (FILE_RELATIVE_PATH)!" + _loggers_error "${FUNCTION_NAME}" + exit 1 + fi + if + [ ! -e "${FILE_RELATIVE_PATH}" ] + then + touch "${FILE_RELATIVE_PATH}" + _loggers_warn "${FUNCTION_NAME}" + _loggers_warn "${FUNCTION_NAME}" "Was absent -> had to create!" + _loggers_warn "${FUNCTION_NAME}" + fi +} diff --git a/assets/base/lib/local-storage/-read-lines-from-file-dot-env.sh b/assets/base/lib/local-storage/-read-lines-from-file-dot-env.sh new file mode 100755 index 0000000..f46ba65 --- /dev/null +++ b/assets/base/lib/local-storage/-read-lines-from-file-dot-env.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh + +_base_localStorage_readLinesFrom_fileDotEnv() { + local FUNCTION_NAME="_base_localStorage_readLinesFrom_fileDotEnv" + _loggers_debug "${FUNCTION_NAME}" + + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}" + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}" + + local RET_VAL=$( + _base_localStorage_readLinesFrom_file "${LOCAL_FILE_DOT_ENV}" + ) + _loggers_emptyLine + + echo "${RET_VAL[@]}" +} diff --git a/assets/base/lib/local-storage/-read-lines-from-file.sh b/assets/base/lib/local-storage/-read-lines-from-file.sh new file mode 100755 index 0000000..35385ad --- /dev/null +++ b/assets/base/lib/local-storage/-read-lines-from-file.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh + +_base_localStorage_readLinesFrom_file() { + local FUNCTION_NAME="_base_localStorage_readLinesFrom_file" + _loggers_debug "${FUNCTION_NAME}" + + local FILE_RELATIVE_PATH="${1}" + + _base_localStorage_ensureExistance_file "${FILE_RELATIVE_PATH}" + + local RET_VAL=() + + while + read -r TMP_FILE_LINE + do + if + [ ! -z "${TMP_FILE_LINE}" ] + then + RET_VAL+=($TMP_FILE_LINE) + fi + + done <"${FILE_RELATIVE_PATH}" + + echo "${RET_VAL[*]}" +} diff --git a/assets/base/lib/local-storage/-reset-file-dot-env.sh b/assets/base/lib/local-storage/-reset-file-dot-env.sh new file mode 100755 index 0000000..a7f1ef2 --- /dev/null +++ b/assets/base/lib/local-storage/-reset-file-dot-env.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/-reset-file.sh + +_base_localStorage_reset_fileDotEnv() { + local FUNCTION_NAME="_base_localStorage_reset_fileDotEnv" + _loggers_debug "${FUNCTION_NAME}" + + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}" + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}" + + _base_localStorage_reset_file "${LOCAL_FILE_DOT_ENV}" +} diff --git a/assets/base/lib/local-storage/-reset-file.sh b/assets/base/lib/local-storage/-reset-file.sh new file mode 100755 index 0000000..d90676d --- /dev/null +++ b/assets/base/lib/local-storage/-reset-file.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_localStorage_reset_file() { + local FUNCTION_NAME="_base_localStorage_reset_file" + _loggers_debug "${FUNCTION_NAME}" + + local FILE_RELATIVE_PATH="${1}" + + if + [ -z "${FILE_RELATIVE_PATH}" ] + then + _loggers_error "${FUNCTION_NAME}" + _loggers_error "${FUNCTION_NAME}" "Missing mandatory 1st paramter (FILE_RELATIVE_PATH)!" + _loggers_error "${FUNCTION_NAME}" + exit 1 + fi + + rm "${FILE_RELATIVE_PATH}" + + touch "${FILE_RELATIVE_PATH}" +} diff --git a/assets/base/lib/local-storage/-save-env-variable-2-file-dot-env.sh b/assets/base/lib/local-storage/-save-env-variable-2-file-dot-env.sh new file mode 100755 index 0000000..a28ea78 --- /dev/null +++ b/assets/base/lib/local-storage/-save-env-variable-2-file-dot-env.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/-save-env-variable-2-file.sh + +_base_localStorage_saveEnvVariable2_fileDotEnv() { + local FUNCTION_NAME="_base_localStorage_saveEnvVariable2_fileDotEnv" + _loggers_debug "${FUNCTION_NAME}" + + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}" + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}" + + _base_localStorage_saveEnvVariable2_file "${LOCAL_FILE_DOT_ENV}" + +} diff --git a/assets/base/lib/local-storage/-save-env-variable-2-file.sh b/assets/base/lib/local-storage/-save-env-variable-2-file.sh new file mode 100755 index 0000000..67bc447 --- /dev/null +++ b/assets/base/lib/local-storage/-save-env-variable-2-file.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/-ensure-env-var-key.sh +. ./.scripts/base/lib/-ensure-env-var-value.sh + +. ./.scripts/base/lib/-get-env-variable-key-from-line.sh + +. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh +. ./.scripts/base/lib/local-storage/-read-lines-from-file.sh +. ./.scripts/base/lib/local-storage/-reset-file.sh + +_base_localStorage_saveEnvVariable2_file() { + local FUNCTION_NAME="_base_localStorage_saveEnvVariable2_file" + _loggers_debug "${FUNCTION_NAME}" + + _base_ensure_evnVarKey + _base_ensure_evnVarValue + + local FILE_RELATIVE_PATH="${1}" + _base_localStorage_ensureExistance_file "${FILE_RELATIVE_PATH}" + + local PARAM_ENV_VAR_KEY="${ENV_VAR_KEY}" + local PARAM_ENV_VAR_VALUE="${ENV_VAR_VALUE}" + + _loggers_debug "${FUNCTION_NAME}" "ENV_VAR_KEY: ${ENV_VAR_KEY}" + _loggers_debug "${FUNCTION_NAME}" "ENV_VAR_VALUE: ${ENV_VAR_VALUE}" + + local FILE_LINES=$(cat "$FILE_RELATIVE_PATH") + + _base_localStorage_reset_file "${FILE_RELATIVE_PATH}" + + local TMP_KEY_STATUS="" + + echo "$FILE_LINES" | while IFS= read -r FILE_LINE; do + local TMP_ENV_VAR_KEY=$( + _base_getEnvVariableKey_fromLine "${FILE_LINE}" + ) + if + [ "${PARAM_ENV_VAR_KEY}" = "${TMP_ENV_VAR_KEY}" ] + then + echo "${PARAM_ENV_VAR_KEY}=\"${PARAM_ENV_VAR_VALUE}\"" >>"${FILE_RELATIVE_PATH}" + TMP_KEY_STATUS="REPLACED" + else + echo "${FILE_LINE}" >>"${FILE_RELATIVE_PATH}" + fi + done + + if + [ ! "${TMP_KEY_STATUS}" = "REPLACED" ] + then + echo "${PARAM_ENV_VAR_KEY}=\"${PARAM_ENV_VAR_VALUE}\"" >>"${FILE_RELATIVE_PATH}" + fi + +} diff --git a/assets/base/lib/local-storage/-view-file-dot-env.sh b/assets/base/lib/local-storage/-view-file-dot-env.sh new file mode 100755 index 0000000..302646d --- /dev/null +++ b/assets/base/lib/local-storage/-view-file-dot-env.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +. ./.scripts/base/lib/local-storage/-ensure-existance-file-dot-env.sh +. ./.scripts/base/lib/local-storage/-view-file.sh + +_base_localStorage_view_fileDotEnv() { + local FUNCTION_NAME="_base_localStorage_view_fileDotEnv" + _loggers_debug "${FUNCTION_NAME}" + + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}" + _loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}" + + _base_localStorage_ensureExistance_file "${LOCAL_FILE_DOT_ENV}" + + _base_localStorage_view_file "${LOCAL_FILE_DOT_ENV}" + +} diff --git a/assets/base/lib/local-storage/-view-file.sh b/assets/base/lib/local-storage/-view-file.sh new file mode 100755 index 0000000..83e4b1c --- /dev/null +++ b/assets/base/lib/local-storage/-view-file.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/--index-api.sh + +_base_localStorage_view_file() { + local FUNCTION_NAME="_base_localStorage_view_file" + _loggers_debug "${FUNCTION_NAME}" + + local FILE_RELATIVE_PATH="${1}" + + if + [ -z "${FILE_RELATIVE_PATH}" ] + then + _loggers_error "${FUNCTION_NAME}" + _loggers_error "${FUNCTION_NAME}" "Missing mandatory 1st paramter (FILE_RELATIVE_PATH)!" + _loggers_error "${FUNCTION_NAME}" + exit 1 + fi + + _loggers_emptyLine + cat "${FILE_RELATIVE_PATH}" + _loggers_emptyLine + +} diff --git a/assets/loggers/lib/--env-vars-reader.sh b/assets/loggers/lib/--env-vars-reader.sh new file mode 100755 index 0000000..b8e7cc1 --- /dev/null +++ b/assets/loggers/lib/--env-vars-reader.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- +# +# --> defaults preserve already-exported values so a caller can override +# any level before sourcing the loggers module +# +export LOGGER_TRAILING_NEW_LINE_ENABLED="${LOGGER_TRAILING_NEW_LINE_ENABLED:-TRUE}" + +export LOGGER_IS_ENABLED_ERROR="${LOGGER_IS_ENABLED_ERROR:-true}" +export LOGGER_IS_ENABLED_INFO="${LOGGER_IS_ENABLED_INFO:-true}" +export LOGGER_IS_ENABLED_WARN="${LOGGER_IS_ENABLED_WARN:-true}" +export LOGGER_IS_ENABLED_DEBUG="${LOGGER_IS_ENABLED_DEBUG:-true}" +export LOGGER_IS_ENABLED_TRACE="${LOGGER_IS_ENABLED_TRACE:-false}" + +export LOCAL_STRING_005_SPACES=" " +export LOCAL_STRING_010_SPACES="${LOCAL_STRING_005_SPACES}${LOCAL_STRING_005_SPACES}" +export LOCAL_STRING_050_SPACES="${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}" +export LOCAL_STRING_070_SPACES="${LOCAL_STRING_050_SPACES}${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}" diff --git a/assets/loggers/lib/--index-api.sh b/assets/loggers/lib/--index-api.sh new file mode 100755 index 0000000..a21562c --- /dev/null +++ b/assets/loggers/lib/--index-api.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +# +# --> logger level flags and padding strings must exist before any logger +# function runs; the reader preserves already-exported values, so this +# is safe to source repeatedly and from any dependent module +# +. ./.scripts/loggers/lib/--env-vars-reader.sh + +. ./.scripts/loggers/lib/-enable-trailing-new-line.sh + +. ./.scripts/loggers/lib/-info.sh +. ./.scripts/loggers/lib/-trace.sh +. ./.scripts/loggers/lib/-debug.sh +. ./.scripts/loggers/lib/-error.sh +. ./.scripts/loggers/lib/-warn.sh + +. ./.scripts/loggers/lib/-empty-line.sh +. ./.scripts/loggers/lib/-waiting-dot.sh diff --git a/assets/loggers/lib/--index.sh b/assets/loggers/lib/--index.sh new file mode 100755 index 0000000..aa810d9 --- /dev/null +++ b/assets/loggers/lib/--index.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- +# +# --> available functions are imported/exported +# +. ./.scripts/loggers/lib/--index-api.sh +# ------------------------------------------------------------------------------------- diff --git a/assets/loggers/lib/-debug.sh b/assets/loggers/lib/-debug.sh new file mode 100755 index 0000000..1f199b7 --- /dev/null +++ b/assets/loggers/lib/-debug.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/-enable-trailing-new-line.sh + +_loggers_debug() { + _loggers_enableLoggerTrailingNewLine + if + [ "${LOGGER_IS_ENABLED_DEBUG}" = true ] + then + local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}" + TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}" + local TMP_LINE="# DEBUG # ${TMP_1ST_PARAM} # ${2}" + echo -e "\033[1;36m${TMP_LINE}\033[0m" >&2 + fi +} diff --git a/assets/loggers/lib/-empty-line.sh b/assets/loggers/lib/-empty-line.sh new file mode 100755 index 0000000..101492c --- /dev/null +++ b/assets/loggers/lib/-empty-line.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/-enable-trailing-new-line.sh + +_loggers_emptyLine() { + _loggers_enableLoggerTrailingNewLine + echo -e "" >&2 +} diff --git a/assets/loggers/lib/-enable-trailing-new-line.sh b/assets/loggers/lib/-enable-trailing-new-line.sh new file mode 100755 index 0000000..46f2149 --- /dev/null +++ b/assets/loggers/lib/-enable-trailing-new-line.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +_loggers_enableLoggerTrailingNewLine() { + if + [ -z "$LOGGER_TRAILING_NEW_LINE_DISABLED" ] + then + echo "" >&2 + export LOGGER_TRAILING_NEW_LINE_DISABLED="TRUE" + fi +} diff --git a/assets/loggers/lib/-error.sh b/assets/loggers/lib/-error.sh new file mode 100755 index 0000000..475415c --- /dev/null +++ b/assets/loggers/lib/-error.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/-enable-trailing-new-line.sh + +_loggers_error() { + _loggers_enableLoggerTrailingNewLine + if + [ "${LOGGER_IS_ENABLED_ERROR}" = true ] + then + local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}" + TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}" + local TMP_LINE="# ERROR # ${TMP_1ST_PARAM} # $2" + echo -e "\033[1;31m${TMP_LINE}\033[0m" >&2 + fi + +} diff --git a/assets/loggers/lib/-info.sh b/assets/loggers/lib/-info.sh new file mode 100755 index 0000000..8f62af3 --- /dev/null +++ b/assets/loggers/lib/-info.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/-enable-trailing-new-line.sh + +_loggers_info() { + _loggers_enableLoggerTrailingNewLine + if + [ "${LOGGER_IS_ENABLED_INFO}" = true ] + then + local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}" + TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}" + local TMP_LINE="# INFO # ${TMP_1ST_PARAM} # ${2}" + echo -e "${TMP_LINE}" >&2 + fi +} diff --git a/assets/loggers/lib/-trace.sh b/assets/loggers/lib/-trace.sh new file mode 100755 index 0000000..1feb7ac --- /dev/null +++ b/assets/loggers/lib/-trace.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/-enable-trailing-new-line.sh + +_loggers_trace() { + _loggers_enableLoggerTrailingNewLine + if + [ "${LOGGER_IS_ENABLED_TRACE}" = true ] + then + local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}" + TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}" + local TMP_LINE="# TRACE # ${TMP_1ST_PARAM} # $2" + echo -e "\033[0;94m${TMP_LINE}\033[0m" >&2 + fi + +} diff --git a/assets/loggers/lib/-waiting-dot.sh b/assets/loggers/lib/-waiting-dot.sh new file mode 100755 index 0000000..f5d820f --- /dev/null +++ b/assets/loggers/lib/-waiting-dot.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/-enable-trailing-new-line.sh + +_loggers_waitingDot() { + echo -n "." >&2 + export LOGGER_TRAILING_NEW_LINE_DISABLED="" +} diff --git a/assets/loggers/lib/-warn.sh b/assets/loggers/lib/-warn.sh new file mode 100755 index 0000000..f43b9d6 --- /dev/null +++ b/assets/loggers/lib/-warn.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# ------------------------------------------------------------------------------------- +# IBM Confidential +# 6949-70F, 6949-80D +# © Copyright IBM Corp. 2018, 2024 +# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +# ------------------------------------------------------------------------------------- + +. ./.scripts/loggers/lib/-enable-trailing-new-line.sh + +_loggers_warn() { + _loggers_enableLoggerTrailingNewLine + if + [ "${LOGGER_IS_ENABLED_WARN}" = true ] + then + local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}" + TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}" + local TMP_LINE="# WARN # ${TMP_1ST_PARAM} # $2" + echo -e "\033[1;33m${TMP_LINE}\033[0m" >&2 + fi +} diff --git a/assets/module-example-v1/README.md b/assets/module-example-v1/README.md new file mode 100644 index 0000000..7b753bd --- /dev/null +++ b/assets/module-example-v1/README.md @@ -0,0 +1,13 @@ +# `module-example-v1` Generic Scaffold + +This is a generic reference scaffold for a new Cognitive Architect script module. + +To adapt it: + +1. Copy `module-example-v1/` into `.scripts//`. +2. Replace paths containing `module-example-v1`. +3. Replace environment prefix `MODULE_EXAMPLE_V1_`. +4. Replace function prefix `_moduleExampleV1_`. +5. Add public API wrappers and implementation files as needed. +6. Add a root `Taskfile.yml` include only if the module should be task-runner public. +7. Run `bash -n` against all generated `.sh` files. diff --git a/assets/module-example-v1/Taskfile.yml b/assets/module-example-v1/Taskfile.yml new file mode 100644 index 0000000..1214e08 --- /dev/null +++ b/assets/module-example-v1/Taskfile.yml @@ -0,0 +1,10 @@ +# https://taskfile.dev + +version: "3" + +tasks: + initialize-one: + cmds: + - | + ./.scripts/module-example-v1/api/initialize-one.sh {{.CLI_ARGS}} + silent: true diff --git a/assets/module-example-v1/api/initialize-one.sh b/assets/module-example-v1/api/initialize-one.sh new file mode 100644 index 0000000..13526b0 --- /dev/null +++ b/assets/module-example-v1/api/initialize-one.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +. ./.scripts/module-example-v1/lib/--index.sh + +_moduleExampleV1_initializeOne diff --git a/assets/module-example-v1/lib/--env-vars-reader.sh b/assets/module-example-v1/lib/--env-vars-reader.sh new file mode 100644 index 0000000..d69af8f --- /dev/null +++ b/assets/module-example-v1/lib/--env-vars-reader.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +export MODULE_EXAMPLE_V1_NAME="${MODULE_EXAMPLE_V1_NAME:-default-name}" +export MODULE_EXAMPLE_V1_OUTPUT_DIR="${MODULE_EXAMPLE_V1_OUTPUT_DIR:-.tmp/module-example-v1}" +export MODULE_EXAMPLE_V1_DRY_RUN="${MODULE_EXAMPLE_V1_DRY_RUN:-false}" + +ALL_ARGS=("$@") +while [[ "$#" -gt 0 ]]; do + case $1 in + --name) + export MODULE_EXAMPLE_V1_NAME="$2" + shift + ;; + --output-dir) + export MODULE_EXAMPLE_V1_OUTPUT_DIR="$2" + shift + ;; + --dry-run) + export MODULE_EXAMPLE_V1_DRY_RUN="true" + ;; + *) ;; + esac + shift +done +set -- "${ALL_ARGS[@]}" diff --git a/assets/module-example-v1/lib/--env-vars-validator.sh b/assets/module-example-v1/lib/--env-vars-validator.sh new file mode 100644 index 0000000..04431b6 --- /dev/null +++ b/assets/module-example-v1/lib/--env-vars-validator.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +. ./.scripts/loggers/lib/--index-api.sh + +if [ -z "${MODULE_EXAMPLE_V1_NAME}" ]; then + _loggers_error "module-example-v1" "Missing required --name / MODULE_EXAMPLE_V1_NAME" + exit 1 +fi diff --git a/assets/module-example-v1/lib/--index-api.sh b/assets/module-example-v1/lib/--index-api.sh new file mode 100644 index 0000000..ef99c1f --- /dev/null +++ b/assets/module-example-v1/lib/--index-api.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +. ./.scripts/loggers/lib/--index-api.sh +. ./.scripts/base/lib/--index-api.sh + +. ./.scripts/module-example-v1/lib/-initialize-one.sh diff --git a/assets/module-example-v1/lib/--index.sh b/assets/module-example-v1/lib/--index.sh new file mode 100644 index 0000000..d8f40c9 --- /dev/null +++ b/assets/module-example-v1/lib/--index.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# +# --> passed parameters are read & exported environment variables +# +. ./.scripts/module-example-v1/lib/--env-vars-reader.sh +# +# --> required environment variables are validated for existence +# +. ./.scripts/module-example-v1/lib/--env-vars-validator.sh +# +# --> available functions are imported/exported +# +. ./.scripts/module-example-v1/lib/--index-api.sh +# ------------------------------------------------------------------------------------- diff --git a/assets/module-example-v1/lib/-initialize-one.sh b/assets/module-example-v1/lib/-initialize-one.sh new file mode 100644 index 0000000..88e0235 --- /dev/null +++ b/assets/module-example-v1/lib/-initialize-one.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +. ./.scripts/loggers/lib/--index-api.sh + +_moduleExampleV1_initializeOne() { + local FUNCTION_NAME="_moduleExampleV1_initializeOne" + + _loggers_info "${FUNCTION_NAME}" "Initializing module-example-v1" + _loggers_debug "${FUNCTION_NAME}" "Name: ${MODULE_EXAMPLE_V1_NAME}" + _loggers_debug "${FUNCTION_NAME}" "Output directory: ${MODULE_EXAMPLE_V1_OUTPUT_DIR}" + + if [ "${MODULE_EXAMPLE_V1_DRY_RUN}" = "true" ]; then + _loggers_info "${FUNCTION_NAME}" "Dry run enabled; no files will be changed." + return 0 + fi + + mkdir -p "${MODULE_EXAMPLE_V1_OUTPUT_DIR}" + _loggers_info "${FUNCTION_NAME}" "Initialization complete." +} diff --git a/references/module-anatomy.md b/references/module-anatomy.md new file mode 100644 index 0000000..e56d467 --- /dev/null +++ b/references/module-anatomy.md @@ -0,0 +1,203 @@ +# Module Anatomy + +The four file types inside `lib/`, the `api/` wrapper, and the patterns each follows. + +Read this when writing or changing a reader, a validator, an implementation function, or a +public wrapper. + +--- + +## 1. `--env-vars-reader.sh` — defaults and CLI parsing + +Responsibilities, in order: + +1. export defaults, preserving any value already exported by the caller; +2. parse CLI flags into environment variables; +3. restore the positional arguments so later consumers still see them. + +```bash +#!/bin/bash + +export MODULE_EXAMPLE_V1_NAME="${MODULE_EXAMPLE_V1_NAME:-default-name}" +export MODULE_EXAMPLE_V1_OUTPUT_DIR="${MODULE_EXAMPLE_V1_OUTPUT_DIR:-.tmp/module-example-v1}" +export MODULE_EXAMPLE_V1_DRY_RUN="${MODULE_EXAMPLE_V1_DRY_RUN:-false}" + +ALL_ARGS=("$@") +while [[ "$#" -gt 0 ]]; do + case $1 in + --name) + export MODULE_EXAMPLE_V1_NAME="$2" + shift + ;; + --output-dir) + export MODULE_EXAMPLE_V1_OUTPUT_DIR="$2" + shift + ;; + --dry-run) + export MODULE_EXAMPLE_V1_DRY_RUN="true" + ;; + *) ;; + esac + shift +done +set -- "${ALL_ARGS[@]}" +``` + +Rules: + +- Use a stable uppercase environment prefix per module. +- **Always use `${VAR:-default}`**, never a bare `export VAR=value`. A bare assignment + silently discards a caller's override, and the caller has no way to detect it. This is what + makes a reader safe to source more than once. +- Prefer explicit CLI flags over positional arguments. +- Defaults must be safe to run locally — a default that writes outside `.tmp/` or touches a + shared system is not a safe default. +- Never print secrets here. + +The `ALL_ARGS` save/restore matters because `shift` consumes the arguments. Without the +`set --` at the end, anything sourced after the reader sees an empty argument list. + +--- + +## 2. `--env-vars-validator.sh` — required inputs + +```bash +#!/bin/bash + +. ./.scripts/loggers/lib/--index-api.sh + +if [ -z "${MODULE_EXAMPLE_V1_NAME}" ]; then + _loggers_error "module-example-v1" "Missing required --name / MODULE_EXAMPLE_V1_NAME" + exit 1 +fi +``` + +Rules: + +- Runs from `--index.sh`, after the reader and before the API index, so failures happen before + any implementation function is even defined. +- Use `_loggers_error` for the failure and `_loggers_info` for a usage hint. +- `exit 1` is correct **here** — the validator runs during bootstrap of a top-level command, + and stopping is the intent. +- Validate only what every command in the module needs. A variable that only one command + requires is validated inside that command's function, not globally — otherwise unrelated + commands fail on input they never use. + +--- + +## 3. `--index-api.sh` — dependency and implementation wiring + +```bash +#!/bin/bash + +. ./.scripts/loggers/lib/--index-api.sh +. ./.scripts/base/lib/--index-api.sh + +. ./.scripts/module-example-v1/lib/-initialize-one.sh +``` + +Rules: + +- Upstream dependencies first, then this module's own implementation files. +- Source other modules' `--index-api.sh`, **not** their `--index.sh` — see + `references/shared-modules.md` §2. +- **Every implementation file must appear here.** A `lib/-*.sh` that is never sourced defines + nothing, and the failure surfaces as `command not found` for a function you can see on disk. +- Safe to source repeatedly. Sourcing defines functions; it should have no other side effect. + +--- + +## 4. `--index.sh` — runtime bootstrap + +```bash +#!/bin/bash + +# --> passed parameters are read & exported environment variables +. ./.scripts/module-example-v1/lib/--env-vars-reader.sh + +# --> required environment variables are validated for existence +. ./.scripts/module-example-v1/lib/--env-vars-validator.sh + +# --> available functions are imported/exported +. ./.scripts/module-example-v1/lib/--index-api.sh +``` + +Rules: + +- Exactly these three sources, in exactly this order. +- This is the module's **own** entrypoint, sourced by its `api/` wrappers. Other modules never + source it — they take `--index-api.sh`. +- A module with no required inputs may omit the validator, but keeping an empty one makes the + next required variable a one-line change. + +--- + +## 5. Implementation functions — `lib/-.sh` + +```bash +#!/bin/bash + +. ./.scripts/loggers/lib/--index-api.sh + +_moduleExampleV1_initializeOne() { + local FUNCTION_NAME="_moduleExampleV1_initializeOne" + + _loggers_info "${FUNCTION_NAME}" "Initializing module-example-v1" + _loggers_debug "${FUNCTION_NAME}" "Output directory: ${MODULE_EXAMPLE_V1_OUTPUT_DIR}" + + if [ "${MODULE_EXAMPLE_V1_DRY_RUN}" = "true" ]; then + _loggers_info "${FUNCTION_NAME}" "Dry run enabled; no files will be changed." + return 0 + fi + + mkdir -p "${MODULE_EXAMPLE_V1_OUTPUT_DIR}" + _loggers_info "${FUNCTION_NAME}" "Initialization complete." +} +``` + +Rules: + +- Open with `local FUNCTION_NAME="__"` — every logger call takes it as the + first argument, which is what makes log output traceable to a specific function. +- One file, one primary function. Small private helpers may live alongside it. +- Use `_loggers_*` helpers, never raw `echo`, for status and errors. +- **`return` non-zero on failure; never `exit`.** The file is sourced, so `exit` terminates + the caller's shell — including an interactive one. +- Read configuration from the module's environment variables. Never re-parse `$@` here. +- Quote every expansion unless word splitting is deliberate. +- Never expose secret values in a log line. + +--- + +## 6. `api/` wrappers + +```bash +#!/bin/bash + +. ./.scripts/module-example-v1/lib/--index.sh + +_moduleExampleV1_initializeOne +``` + +That is the whole file. Rules: + +- Source exactly `lib/--index.sh`, then call exactly one function. +- No implementation, no flag parsing, no validation, no argument forwarding. +- Arguments reach the reader automatically: sourcing happens while the wrapper's own `$@` is + still in scope, so `--env-vars-reader.sh` sees them without being passed anything. +- Create a wrapper only for a genuinely user-facing command. An internal helper stays in + `lib/` — every file in `api/` is a public interface someone may come to depend on. + +--- + +## 7. Diagnosing a broken module + +| Symptom | Cause | +|---|---| +| `command not found` for a function that exists on disk | Its file is missing from `lib/--index-api.sh` | +| No log output at all, exit code 0 | Logger level flags never exported — see `references/shared-modules.md` §3 | +| A flag is ignored | Not handled in `--env-vars-reader.sh`, or handled after the `set --` restore | +| Later sources see no arguments | Reader is missing the `ALL_ARGS` save/`set --` restore | +| `No such file or directory` for a `lib/` path | Run from inside the module instead of the repository root | +| `.env` loaded unexpectedly | Something sourced `base/lib/--index.sh` instead of `base/lib/--index-api.sh` | +| The shell exits on a handled error | `exit` used inside a sourced implementation function | diff --git a/references/module-patterns.md b/references/module-patterns.md new file mode 100644 index 0000000..21ee06f --- /dev/null +++ b/references/module-patterns.md @@ -0,0 +1,66 @@ +# Module Patterns + +A decision guide for what kind of module you are building and how it should connect to the +others. + +--- + +## 1. Module type + +| Module type | Has `api/` | Has `Taskfile.yml` | Example | +|---|:---:|:---:|---| +| Support-only library | No | No | `loggers` | +| Shared foundation with public commands | Yes | Optional / no | `base` | +| Feature module | Yes | Usually yes | `kube`, `github`, `data-migration` | +| Wrapper around an external CLI | Yes | Usually yes | `helm`, `openshift`, `github` | + +Pick the type before creating any file — it decides whether `api/` and `Taskfile.yml` exist at +all, and adding them later means reworking every consumer that has already started sourcing +the module. + +A module with no user-facing command is a support library. Do not give it an `api/` directory +speculatively; every file in `api/` is a public interface someone may come to depend on. + +--- + +## 2. Dependency sourcing + +| You need | Source | +|---|---| +| Logging | `./.scripts/loggers/lib/--index-api.sh` | +| Shared base functions | `./.scripts/base/lib/--index-api.sh` | +| Another module's exported functions | that module's `lib/--index-api.sh` | +| Your own module's full runtime, from its `api/` wrapper | your `lib/--index.sh` | + +The rule underneath: **`--index-api.sh` is the public edge between modules; `--index.sh` is a +module's own private entrypoint.** Sourcing another module's `--index.sh` runs its reader and +validator inside your command — importing its defaults, its required-input checks, and in +`base`'s case its `.env` loading. Symptoms show up as variables nobody set, or a validation +failure naming a module the user never invoked. + +--- + +## 3. Command exposure + +Three independent decisions, in increasing order of commitment: + +1. **`lib/` only** — internal. Reachable from other modules that source your `--index-api.sh`. +2. **`api/.sh`** — user-facing. Someone can run it directly from the repository root. +3. **Module `Taskfile.yml`** — discoverable through `task --list-all`. +4. **Root `Taskfile.yml` include** — a stable public namespace, effectively permanent. + +Escalate only as far as the command genuinely needs. Each step is easy to add later and +disruptive to withdraw, because each one is a promise someone may already be relying on. + +--- + +## 4. Common mistakes + +- Putting full implementation logic into `api/*.sh`. +- Adding a `lib/-*.sh` file and forgetting to source it from `lib/--index-api.sh`. +- Parsing CLI flags in implementation files instead of `--env-vars-reader.sh`. +- Printing secrets in logs. +- Sourcing `base/lib/--index.sh` from a library function and unexpectedly loading `.env`. +- Adding root Taskfile includes for experimental modules. +- Giving a support-only library an `api/` directory it does not need. +- Mixing function prefixes inside one module after a rename. diff --git a/references/shared-modules.md b/references/shared-modules.md new file mode 100644 index 0000000..efb3140 --- /dev/null +++ b/references/shared-modules.md @@ -0,0 +1,165 @@ +# Shared Modules — `loggers` and `base` + +The two foundation modules every other module depends on, and the bootstrap rule that decides +whether logging works at all. + +Working implementations are in `assets/loggers/` and `assets/base/`. + +--- + +## 1. `loggers` — support-only library + +No `api/` commands, no `Taskfile.yml`. It exists to be sourced. + +```text +.scripts/loggers/ + lib/ + --env-vars-reader.sh # level flags + padding strings + --index-api.sh # sources the reader, then every logger function + --index.sh + -debug.sh -error.sh -info.sh -trace.sh -warn.sh + -empty-line.sh -enable-trailing-new-line.sh -waiting-dot.sh +``` + +Consume it from any module: + +```bash +. ./.scripts/loggers/lib/--index-api.sh +``` + +Available functions: + +```bash +_loggers_info "${FUNCTION_NAME}" "message" +_loggers_debug "${FUNCTION_NAME}" "message" +_loggers_warn "${FUNCTION_NAME}" "message" +_loggers_error "${FUNCTION_NAME}" "message" +_loggers_trace "${FUNCTION_NAME}" "message" +_loggers_emptyLine +``` + +Levels are controlled by environment flags, defaulting to everything except trace: + +```bash +LOGGER_IS_ENABLED_ERROR=true +LOGGER_IS_ENABLED_INFO=true +LOGGER_IS_ENABLED_WARN=true +LOGGER_IS_ENABLED_DEBUG=true +LOGGER_IS_ENABLED_TRACE=false +``` + +Export any of them before invoking a command to change verbosity for that run: + +```bash +LOGGER_IS_ENABLED_DEBUG=false ./.scripts//api/.sh +``` + +Rules: + +1. Do not add `api/` wrappers to `loggers` without a real user-facing requirement. +2. Keep logger helpers small and side-effect-light. +3. Log to `stderr` — `stdout` stays clean so command output remains pipeable. +4. Dependent modules source the logger API directly. + +--- + +## 2. `base` — shared foundation + +Has public `api/` wrappers but no `Taskfile.yml`. Provides local environment handling and +local-storage helpers over `.env` files. + +```text +.scripts/base/ + api/ + local-storage-ensure-existance-file-dot-env.sh + local-storage-read-lines-from-file-dot-env.sh + local-storage-reset-file-dot-env.sh + local-storage-save-env-variable-2-file-dot-env.sh + local-storage-view-file-dot-env.sh + lib/ + --env-vars-reader.sh --env-vars-validator.sh + --index-api.sh --index.sh + -export-env-variable.sh + -export-env-variables-from-file-dot-env.sh + -export-env-variables-from-file.sh + -get-env-variable-key-from-line.sh + -get-env-variable-value-from-line.sh + -log-env-vars.sh + -prompt-for-env-var.sh + local-storage/ + --index-api.sh + -ensure-existance-file.sh -ensure-existance-file-dot-env.sh + -read-lines-from-file.sh -read-lines-from-file-dot-env.sh + -reset-file.sh -reset-file-dot-env.sh + -save-env-variable-2-file.sh -save-env-variable-2-file-dot-env.sh + -view-file.sh -view-file-dot-env.sh +``` + +### Which entrypoint to source — this matters + +```bash +# From another module, when you only need base's shared functions: +. ./.scripts/base/lib/--index-api.sh + +# Only from base's own api/ wrappers: +. ./.scripts/base/lib/--index.sh +``` + +`base/lib/--index.sh` runs base's reader and validator, and **reads `.env` and +environment-specific files as a side effect**. Sourcing it from a library function pulls that +whole environment into an unrelated command — values appear that nobody set, and the failure +is hard to trace because nothing in the calling module mentions `.env`. + +`--index-api.sh` defines functions and nothing else, which is why it is the correct dependency +edge between modules. + +Rules: + +1. Prefer `base/lib/--index-api.sh` from other modules. +2. Nested lib packages such as `lib/local-storage/` carry their own `--index-api.sh` and are + sourced from the parent's. +3. Never log secret values — redact tokens, API keys, passwords, kube config, credentials. + +--- + +## 3. The logging bootstrap rule + +**A logger function whose level flag is unset prints nothing and returns 0.** + +Every `_loggers_*` function is guarded by its level flag: + +```bash +if [ "${LOGGER_IS_ENABLED_INFO}" = true ]; then ... fi +``` + +An unset flag is not `true`, so the call is a silent no-op with a success exit code. Nothing +fails, nothing warns — the command simply produces no output, which reads like a bug in the +command rather than in its bootstrap. + +Those flags are exported by `loggers/lib/--env-vars-reader.sh`. For logging to work, that +reader must have run before any logger call. + +In the shipped `assets/loggers/`, `--index-api.sh` sources the reader itself, so any module +that sources the logger API gets working logging with no extra step. The reader uses +`${VAR:-default}` throughout, so it is safe to source repeatedly and a caller's override +still wins. + +**If you are adapting an existing `loggers` module rather than using the shipped one, check +this first.** A `--index-api.sh` that sources only the logger function files, without the +reader, silences every module that depends on it — while `bash -n` passes and every command +exits 0. + +Quick check in any repository: + +```bash +grep -n 'env-vars-reader' .scripts/loggers/lib/--index-api.sh \ + || echo "WARNING: loggers API does not bootstrap its level flags — logging may be silent" +``` + +Direct test: + +```bash +bash -c '. ./.scripts/loggers/lib/--index-api.sh; _loggers_info "check" "visible?"' +``` + +No output means the flags were never exported. diff --git a/references/taskfile.md b/references/taskfile.md new file mode 100644 index 0000000..abb77c3 --- /dev/null +++ b/references/taskfile.md @@ -0,0 +1,76 @@ +# Taskfile Integration + +Exposing module commands through the `task` runner. + +Add a module `Taskfile.yml` only when its commands should be discoverable through `task`. A +module that is only consumed by other modules does not need one. + +--- + +## 1. Module `Taskfile.yml` + +```yaml +# https://taskfile.dev + +version: "3" + +tasks: + initialize-one: + cmds: + - | + ./.scripts/module-example-v1/api/initialize-one.sh {{.CLI_ARGS}} + silent: true +``` + +Rules: + +1. Task names mirror the public `api/` command names, unless an alias is deliberate. A task + named differently from the script it runs makes `task --list` output impossible to map back + to files. +2. Forward `{{.CLI_ARGS}}` whenever the command accepts flags. +3. `silent: true` suppresses task's own command echo, so only the script's logger output + appears. +4. Invoke the `api/` wrapper — never a `lib/` file directly. +5. The path is repository-root-relative, matching how the scripts source their dependencies. + +Arguments pass through after `--`: + +```bash +task module-example-v1:initialize-one -- --name demo --dry-run +``` + +Without the `--`, task treats the flags as its own and the script never sees them. + +--- + +## 2. Root `Taskfile.yml` include + +```yaml +includes: + module-example-v1: ./.scripts/module-example-v1/Taskfile.yml +``` + +Rules: + +1. Add a root include only for a module intended as a **stable public task namespace**. The + include name becomes a permanent user-facing prefix; renaming it later breaks every + documented command and every CI invocation. +2. Choose a short, clear namespace. Existing examples include `ca`, `kube`, `npmrc`, + `repos-local`, and `repos-local-nodejs`. +3. Do not add includes for experimental or in-progress modules — run them through their `api/` + path until the interface settles. + +--- + +## 3. Verifying + +```bash +# Every included namespace and task, with descriptions +task --list-all + +# Confirm a specific task resolves and forwards arguments +task : -- --dry-run +``` + +`task --list` shows only tasks carrying a `desc:`; `task --list-all` shows everything. A task +missing from `--list-all` means the root include is absent or its path is wrong. diff --git a/references/workflows.md b/references/workflows.md new file mode 100644 index 0000000..b782ac8 --- /dev/null +++ b/references/workflows.md @@ -0,0 +1,118 @@ +# Workflows + +Creating a module, changing an existing one, and the checks to run before delivering either. + +--- + +## 1. Creating a new module + +1. **Confirm the module name and namespace** — the kebab-case directory name, the + `_camelCase_` function prefix, and the `UPPER_SNAKE_` environment prefix all derive from it + and must agree. +2. **Inspect nearby modules** for a comparable pattern before designing a new one. Matching an + existing module beats inventing a variant. +3. **Copy the scaffold:** + + ```bash + cp -R assets/module-example-v1 .scripts/ + ``` + +4. **Rename throughout** — every `module-example-v1` path, `MODULE_EXAMPLE_V1_`, and + `_moduleExampleV1_`: + + ```bash + cd .scripts/ + grep -rl 'module-example-v1\|MODULE_EXAMPLE_V1_\|_moduleExampleV1_' . | while read -r f; do + sed -i '' \ + -e 's|module-example-v1||g' \ + -e 's|MODULE_EXAMPLE_V1_|_|g' \ + -e 's|_moduleExampleV1_|__|g' "$f" + done + grep -rn 'module-example-v1\|MODULE_EXAMPLE_V1_\|_moduleExampleV1_' . || echo "rename complete" + ``` + + (`sed -i ''` is BSD/macOS; use `sed -i` on GNU.) + +5. **Set the defaults and flags** in `lib/--env-vars-reader.sh`, using `${VAR:-default}`. +6. **Set the required-input checks** in `lib/--env-vars-validator.sh`. +7. **Write implementation files** as `lib/-.sh`, one function each. +8. **Source every implementation file** from `lib/--index-api.sh`. +9. **Add `api/.sh` wrappers** for user-facing commands only. +10. **Add a module `Taskfile.yml`**, and a root include only if the namespace is stable — + `references/taskfile.md`. +11. **Make scripts executable** where they will be invoked directly: + `chmod +x .scripts//api/*.sh`. +12. **Validate** — section 3. +13. **Update the repository's script documentation** if it has a memory bank or equivalent. + +--- + +## 2. Changing an existing module + +1. **Read `lib/--index.sh` and `lib/--index-api.sh` first.** They show what the module loads + and in what order, which determines where a change can safely go. +2. **Decide which layer the change belongs to:** + + | The change is | It belongs in | + |---|---| + | A new user-facing command | `api/` + `lib/-.sh` + `--index-api.sh` | + | New behaviour in an existing command | that command's `lib/-.sh` | + | A new CLI flag or default | `--env-vars-reader.sh` | + | A new required input | `--env-vars-validator.sh` | + | Task-runner exposure | module `Taskfile.yml`, and the root include if public | + +3. **Preserve the existing naming and function prefixes.** Consistency inside a module beats + matching a newer convention used elsewhere — mixed prefixes in one module are worse than an + old prefix used uniformly. +4. **Add every new `lib/-*.sh` to `--index-api.sh`** as you create it, not afterwards. +5. **Add `api/` wrappers only for user-facing commands**; internal helpers stay in `lib/`. +6. **Validate** — section 3. +7. **Update the script documentation** when public behaviour changes. + +--- + +## 3. Validation checklist + +- [ ] Public commands are under `api/`; reusable implementation is under `lib/`. +- [ ] `api/` wrappers are thin — source `lib/--index.sh`, call one function. +- [ ] `lib/--index.sh` sources reader, validator, API index, in that order. +- [ ] `lib/--index-api.sh` sources every implementation file the wrappers need. +- [ ] New CLI flags are parsed in `--env-vars-reader.sh`, using `${VAR:-default}`. +- [ ] Required variables are validated before use. +- [ ] Logs use `_loggers_*` helpers, and logging actually produces output. +- [ ] No secret values are printed or documented. +- [ ] Implementation functions `return` rather than `exit`. +- [ ] Taskfile entries invoke `./.scripts//api/.sh {{.CLI_ARGS}}`. +- [ ] A root `Taskfile.yml` include was added only if intended. +- [ ] `bash -n` passes for every changed script. +- [ ] The command was actually run once from the repository root. +- [ ] Script documentation is updated when public behaviour changed. + +--- + +## 4. Validation commands + +```bash +# Syntax check every script in the module +find .scripts/ -name '*.sh' -print0 | xargs -0 -n1 bash -n + +# Every implementation file is wired into the API index. +# Note the `--` before the pattern: implementation basenames start with a dash, +# which grep would otherwise parse as an option flag and report every file. +cd .scripts/ +for f in lib/-*.sh; do + case "$f" in lib/--*) continue;; esac + grep -qF -- "$(basename "$f")" lib/--index-api.sh || echo "NOT INDEXED: $f" +done + +# Task exposure resolves +task --list-all + +# Run it — the only check that proves the wiring works +./.scripts//api/.sh --dry-run +``` + +`bash -n` proves a file parses. It does **not** prove a function is reachable, that a flag is +handled, or that logging is bootstrapped — all three fail silently at runtime while every +static check passes. The final run is the one that matters; a `--dry-run` flag exists to make +it cheap and safe.