diff --git a/CHANGELOG.md b/CHANGELOG.md index 84737ef..88e027b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and versions are tracked in the repo-root `VERSION` file. ### Documentation +- Repositioned the README around the v2 application framework, added a + runnable CLI/configuration/lifecycle example, and organized the library map + by layer. + - Link the pinned Base Bash Demo v0.1.2 learning path from the README, documentation index, and v2 quickstart, and refresh the consumer ledger. diff --git a/README.md b/README.md index 4921e08..158afea 100644 --- a/README.md +++ b/README.md @@ -10,26 +10,64 @@ The v2.2.1 release is published with a deterministic [bundle archive](https://github.com/basefoundry/base-bash-libs/releases/download/v2.2.1/base-bash-libs-v2.2.1.tar.gz), [checksum manifest](https://github.com/basefoundry/base-bash-libs/releases/download/v2.2.1/base-bash-libs-v2.2.1.SHA256SUMS), [SPDX SBOM](https://github.com/basefoundry/base-bash-libs/releases/download/v2.2.1/base-bash-libs-v2.2.1.spdx.json), and [provenance statement](https://github.com/basefoundry/base-bash-libs/releases/download/v2.2.1/base-bash-libs-v2.2.1.provenance.json). First-party consumers and Homebrew can promote to its exact immutable commit through the coordinated release handoff; the original v2.0.0 cutover is recorded in completed issue #240. -Reusable Bash standard library for reliable shell scripts. +Base Bash is a Bash 4.2.53+ application framework and standard library for +declarative CLIs, typed configuration, lifecycle-safe cleanup, and reliable +shell automation. -base-bash-libs provides sourceable Bash libraries for logging, error handling, -safe command execution, filesystem edits, Git helpers, string utilities, temp -paths, cleanup hooks, and import conventions. It is extracted from +Requires Bash 4.2.53+. On macOS, use Homebrew Bash instead of the system `/bin/bash`. + +It gives applications safe execution and filesystem primitives, a structured +command contract, configuration that is data-only and precedence-aware, and +immutable package identity. It is extracted from [Base](https://github.com/basefoundry/base), but can be installed and used independently through Homebrew, source checkouts, vendored copies, or git submodules. -Requires Bash 4.2.53+. On macOS, use Homebrew Bash instead of the system `/bin/bash`. +A minimal v2 application declares its interface and policy before dispatch: + + +```bash +#!/usr/bin/env base-bash + +base_launcher_import_base_bash_lib cli/lib_cli.sh app/lib_app.sh +base_cli_model_init hello name=hello version=1.0.0 +base_cli_command hello greet "Greet someone" handler=hello_dispatch +base_app_init hello_policy name=hello +base_app_config_define hello_policy name string default=world env=HELLO_NAME +base_app_add_standard_options hello "" +hello_cleanup() { :; } +hello_execute() { + local name="" + base_app_apply_standard_options hello_policy + base_app_config_load hello_policy || return $? + base_app_hook hello_policy cleanup hello_cleanup hello_cleanup || return $? + base_app_config_get hello_policy name name || return $? + printf 'hello=%s\n' "$name" +} +hello_dispatch() { base_app_run hello_policy hello_execute; } +main() { base_cli_run hello -- "$@"; } +``` + + +Run it with `HELLO_NAME=Base ./hello greet` to get `hello=Base`. Start with +the [v2 quickstart](docs/v2/quickstart.md) and then see the +[pinned Beacon reference consumer](https://github.com/basefoundry/base-bash-libs-demo/blob/v0.1.2/README.md) +for a complete offline application. + The shared Base ecosystem boundary is maintained in the [Base ecosystem platform, license, and release policy](https://github.com/basefoundry/base/blob/main/docs/ecosystem-policy.md). ## Libraries -- [`lib/bash/std/lib_std.sh`](lib/bash/std/README.md) +The libraries are layered from foundation to application. Start with `std` +for portable primitives, add the building blocks your script needs, and use +`cli` plus `app` when it becomes a user-facing application. + +- **Foundation:** [`lib/bash/std/lib_std.sh`](lib/bash/std/README.md) Foundation helpers for logging, error handling, command execution, PATH updates, assertions, prompts, imports, and the public `BASE_BASH_LIBS_VERSION` constant. -- [`lib/bash/process/lib_process.sh`](lib/bash/process/README.md) +- **Building blocks:** [`lib/bash/process/lib_process.sh`](lib/bash/process/README.md) Preview-only process-supervision primitives for owner-guardian liveness and asynchronous cleanup, layered on the stdlib. This post-GA module first shipped in `v2.1.0` and is included in the current immutable `v2.2.1` @@ -55,7 +93,7 @@ platform, license, and release policy](https://github.com/basefoundry/base/blob/ - [`lib/bash/list/lib_list.sh`](lib/bash/list/README.md) Indexed-array helpers built on the stdlib for in-place mutation, membership checks, deduplication, and length results. -- [`lib/bash/cli/lib_cli.sh`](lib/bash/cli/README.md) +- **Application framework:** [`lib/bash/cli/lib_cli.sh`](lib/bash/cli/README.md) Declarative command contracts with nested subcommands, validation, help, completion, and a handler boundary for Bash applications. - [`lib/bash/app/lib_app.sh`](lib/bash/app/README.md) diff --git a/tests/docs-contract.sh b/tests/docs-contract.sh index 91d5bea..f470362 100755 --- a/tests/docs-contract.sh +++ b/tests/docs-contract.sh @@ -94,6 +94,65 @@ grep -F 'five-minute, offline Beacon application' README.md > /dev/null || { printf 'README must describe Beacon as a runnable learning path.\n' >&2 exit 1 } +grep -F 'Bash 4.2.53+ application framework and standard library' README.md > /dev/null || { + printf 'README must lead with the v2 application-framework value proposition.\n' >&2 + exit 1 +} +for readme_application_contract_text in \ + 'BEGIN README APPLICATION EXAMPLE' \ + 'base_cli_model_init hello' \ + 'base_app_config_define hello_policy name string' \ + 'base_app_hook hello_policy cleanup' \ + 'base_app_run hello_policy hello_execute' \ + 'HELLO_NAME=Base'; do + grep -F "$readme_application_contract_text" README.md > /dev/null || { + printf 'README application example is missing: %s\n' "$readme_application_contract_text" >&2 + exit 1 + } +done +grep -F 'The libraries are layered from foundation to application.' README.md > /dev/null || { + printf 'README must describe the layered library map.\n' >&2 + exit 1 +} +grep -F '**Foundation:**' README.md > /dev/null || { + printf 'README library map is missing the foundation layer.\n' >&2 + exit 1 +} +grep -F '**Building blocks:**' README.md > /dev/null || { + printf 'README library map is missing the building-block layer.\n' >&2 + exit 1 +} +grep -F '**Application framework:**' README.md > /dev/null || { + printf 'README library map is missing the application-framework layer.\n' >&2 + exit 1 +} + +readme_application_example="$(mktemp "${TMPDIR:-/tmp}/base-bash-readme-example.XXXXXX")" || exit 1 +awk ' + /^$/ { in_region = 1; next } + /^$/ { exit } + in_region && /^```bash$/ { in_code = 1; next } + in_region && in_code && /^```$/ { in_code = 0; next } + in_region && in_code { print } +' README.md > "$readme_application_example" || exit 1 +[[ -s "$readme_application_example" ]] || { + printf 'README application example is empty.\n' >&2 + exit 1 +} +readme_application_output="$( + HELLO_NAME=Base BASE_BASH_LIBS_DIR="$repo_root/lib/bash" \ + "$repo_root/bin/base-bash" "$readme_application_example" greet +)" || { + printf 'README application example did not execute.\n' >&2 + rm -f -- "$readme_application_example" + exit 1 +} +rm -f -- "$readme_application_example" +[[ "$readme_application_output" == 'hello=Base' ]] || { + printf 'README application example produced unexpected output: %s\n' \ + "$readme_application_output" >&2 + exit 1 +} grep -F 'See a complete application' docs/v2/quickstart.md > /dev/null || { printf 'The v2 quickstart must link to the complete Beacon application.\n' >&2 exit 1