diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 40952cc..416dc1c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,3 +31,13 @@ repos: language: system pass_filenames: false types: [markdown] + + # always_run, not types: [markdown] — what breaks this gate is adding a + # script under src/just_bashit/, and that commit touches no markdown at + # all. A markdown-scoped hook would have stayed silent for make-run. + - id: docs-coverage + name: docs-coverage + entry: make -s docs-coverage + language: system + pass_filenames: false + always_run: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bc3aed..87f8670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,37 @@ ## [Unreleased] +### Added + +- **`make-run` is documented.** It shipped in 0.4.0 as the headline feature + and appeared in no page, no nav entry, and no line of the README — so the + one tool whose whole purpose is ending hand-transcribed commands could + only be found by reading its source. New page under Libraries covering + `mk-var`, `mk-vars`, `mk-run`, `mk-has` and `mk-origin`, the + undefined-is-not-empty rule, and why the queries avoid `--eval`. + +- **`docs-coverage` gate.** Two invariants, one for each way the above went + unnoticed: every file shipped in `src/just_bashit/` must be named + somewhere in the docs, and every page under `docs/` must be reachable + from `zensical.toml`'s nav. `docs/changelog.md` is excluded as a mention + source — it records every script ever added, so counting it would pass + everything the moment it was released. Dispatched from pre-commit with + `always_run`, so it runs inside `make lint` (which CI runs) and fires on + commits touching no markdown, which is what adding a script looks like. + +### Fixed + +- **The docs pointed at `src/`, where nothing has lived since 0.2.0.** + Scripts moved to `src/just_bashit/` for Python packaging and the docs kept + the old path, so every `. just-bashit/src/datetime.sh` in the README, the + getting-started guide, and all ten library pages failed for anyone who + copied one — including from an unpacked release tarball, which carries the + current layout. + +- **The README described a package layout that no longer existed**, and never + mentioned installation, the `jb` / `jbx` / `jb-inspect` entry points, or + `make-run`. + ## [0.4.0] - 2026-08-06 ### Added diff --git a/Makefile b/Makefile index b869fd4..bfeb6ac 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,19 @@ else \ fi endef +# ── docs coverage ───────────────────────────────────────────────────────────── +# A repo-local target, so it needs naming here or help-check reports a rule +# that help does not list. +# +# Dispatched from .pre-commit-config.yaml rather than DOCS_CHECK_PRE_CMDS: CI +# runs `make test`, `make coverage` and `make lint` — not `make docs-check` — +# so a docs gate hung off docs-check would be local-only, which is how a rule +# nobody enforces sits on main indefinitely. +LOCAL_TARGETS += docs-coverage + +docs-coverage: ## Verify every shipped script is documented and in the nav + @bash scripts/docs_coverage.sh + # ── all ─────────────────────────────────────────────────────────────────────── # Lint first: shellcheck and shfmt are seconds, the bats suite is minutes. # diff --git a/README.md b/README.md index df2e2e5..6837881 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,31 @@ Evolving set of [shfmt](https://github.com/mvdan/sh#shfmt)-conformant, [bats](ht **[Documentation](https://just-buildit.github.io/just-bashit/)** +## Install + +```bash +uv tool install just-bashit # or: pip install just-bashit +``` + +That puts three commands on `PATH`: `jb` (top-level CLI), `jbx` (ephemeral +runner — fetch a script, call a function, discard), and `jb-inspect`. + +Nothing needs installing to *use* a script. `jbx` fetches on demand: + +```bash +jbx install-deps # install this repo's packages +jbx make-run mk-var -C ~/doppler DOCS_BUILD_CMD +``` + ## Getting Started -A release package contains shell libraries along with a script and two function templates for developing your own tools. +A release package contains shell libraries along with script and function +templates for developing your own tools. ``` just-bashit +--README.md - +--src/ + +--src/just_bashit/ | +-- datetime.sh | +-- environment.sh : : @@ -36,7 +53,23 @@ just-bashit Some libraries depend on others so it's best to use the whole package and source whatever you need, for example: ```bash -. just-bashit/src/datetime.sh # contains iso-8601-basic() +. just-bashit/src/just_bashit/datetime.sh # contains iso-8601-basic() iso-8601-basic -d '10:32 AM EDT Jan 5 1982' 19820105T143200Z ``` + +## Ask a repo what its commands are + +`make-run` resolves a repository's targets and command variables from that +repository's own `Makefile`, so nothing downstream has to carry a second copy +of a command that will drift from it: + +```bash +jbx make-run mk-var -C ~/doppler DOCS_BUILD_CMD +# uv run --group docs zensical build --clean --strict + +jbx make-run mk-run -C ~/doppler docs # run it, whatever it is +``` + +An **undefined** variable is an error, never an empty string — see +[the docs](https://just-buildit.github.io/just-bashit/libraries/make-run/). diff --git a/docs/getting-started.md b/docs/getting-started.md index 6515121..3f35d7d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -35,8 +35,8 @@ All libraries **must be sourced**, not executed. Each file enforces this at load time and will exit with an error if you try to run it directly. ```bash -. just-bashit/src/logging.sh # correct -bash just-bashit/src/logging.sh # error: "This file must be sourced." +. just-bashit/src/just_bashit/logging.sh # correct +bash just-bashit/src/just_bashit/logging.sh # error: "This file must be sourced." ``` Some libraries depend on others (`logging.sh` sources `format.sh`, @@ -49,7 +49,7 @@ chain resolves automatically from relative paths. Every function accepts `-h`: ```bash -. just-bashit/src/datetime.sh +. just-bashit/src/just_bashit/datetime.sh iso-8601-basic -h ``` diff --git a/docs/index.md b/docs/index.md index 0e63d90..99ec7b9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,7 +29,7 @@ Download the latest release, extract it, and source whatever you need: ```bash tar xf just-bashit.tar.gz -. just-bashit/src/datetime.sh +. just-bashit/src/just_bashit/datetime.sh iso-8601-basic # 20260522T143200Z ``` @@ -61,6 +61,7 @@ package and source individual files from it. | [file](libraries/file.md) | `add-line` `remove-line` `add-contents` | | [format](libraries/format.md) | `trim-from` `color-echo` | | [logging](libraries/logging.md) | `log` `log-wait` | +| [make-run](libraries/make-run.md) | `mk-var` `mk-vars` `mk-run` `mk-has` `mk-origin` | | [match](libraries/match.md) | `is-number` | | [network](libraries/network.md) | `test-internet-access` | | [path](libraries/path.md) | `get-scriptpath` `set-scriptpath` | diff --git a/docs/inspect.md b/docs/inspect.md index d33aabc..6929dee 100644 --- a/docs/inspect.md +++ b/docs/inspect.md @@ -263,5 +263,5 @@ jbx inspect -v 2>&1 | head jbx inspect | diff jb.versions - # Pin script to a specific commit for reproducible CI output -jbx gh:just-buildit/just-bashit/src/inspect.sh@abc1234 -w +jbx gh:just-buildit/just-bashit/src/just_bashit/inspect.sh@abc1234 -w ``` diff --git a/docs/install-deps.md b/docs/install-deps.md index 25ce1c5..36dd04a 100644 --- a/docs/install-deps.md +++ b/docs/install-deps.md @@ -282,7 +282,7 @@ jbx install-deps --template deps.toml # write to file ### Pin to a specific script commit for reproducible CI ```bash -jbx gh:just-buildit/just-bashit/src/install-deps.sh@abc1234 +jbx gh:just-buildit/just-bashit/src/just_bashit/install-deps.sh@abc1234 ``` ______________________________________________________________________ diff --git a/docs/just-runit.md b/docs/just-runit.md index 5dc2d8b..c0f4395 100644 --- a/docs/just-runit.md +++ b/docs/just-runit.md @@ -155,7 +155,7 @@ used. # See which URL a cache file came from and when it was fetched cat ~/.cache/just-runit/.meta # ts=1779583354 -# url=https://raw.githubusercontent.com/just-buildit/just-bashit/main/src/install-deps.sh +# url=https://raw.githubusercontent.com/just-buildit/just-bashit/main/src/just_bashit/install-deps.sh ``` **Force a fresh fetch (keep the entry, overwrite it)** @@ -173,7 +173,7 @@ jbx -n https://example.com/tool.sh run **Purge a single entry** ```bash -jb cache clear https://raw.githubusercontent.com/just-buildit/just-bashit/main/src/install-deps.sh +jb cache clear https://raw.githubusercontent.com/just-buildit/just-bashit/main/src/just_bashit/install-deps.sh ``` Or manually — find the hash with `-v` then remove the pair: diff --git a/docs/libraries/datetime.md b/docs/libraries/datetime.md index adf963b..d737c04 100644 --- a/docs/libraries/datetime.md +++ b/docs/libraries/datetime.md @@ -1,13 +1,13 @@ # datetime -Source: `src/datetime.sh` +Source: `src/just_bashit/datetime.sh` ## iso-8601-basic Generate a path- and filename-friendly ISO 8601 UTC timestamp. ```bash -. just-bashit/src/datetime.sh +. just-bashit/src/just_bashit/datetime.sh iso-8601-basic # 20260522T143200Z ``` diff --git a/docs/libraries/environment.md b/docs/libraries/environment.md index d971645..c3a631e 100644 --- a/docs/libraries/environment.md +++ b/docs/libraries/environment.md @@ -1,6 +1,6 @@ # environment -Source: `src/environment.sh` +Source: `src/just_bashit/environment.sh` Idempotent management of `~/.bashrc` entries and command existence checks. @@ -11,7 +11,7 @@ ______________________________________________________________________ Write a line to `~/.bashrc` only if it is not already present. ```bash -. just-bashit/src/environment.sh +. just-bashit/src/just_bashit/environment.sh # Write a verbatim line set-bashrc 'alias ll="ls -la"' @@ -45,7 +45,7 @@ ______________________________________________________________________ Remove a line from `~/.bashrc` if present. No-op if not found. ```bash -. just-bashit/src/environment.sh +. just-bashit/src/just_bashit/environment.sh # Remove a verbatim line unset-bashrc 'alias ll="ls -la"' @@ -79,7 +79,7 @@ ______________________________________________________________________ Return 0 if a command is available in `PATH`, 1 otherwise. ```bash -. just-bashit/src/environment.sh +. just-bashit/src/just_bashit/environment.sh check-command-exists curl && echo "curl is available" check-command-exists nonexistent || echo "not found" diff --git a/docs/libraries/file.md b/docs/libraries/file.md index 8c04c0a..97c4ce4 100644 --- a/docs/libraries/file.md +++ b/docs/libraries/file.md @@ -1,6 +1,6 @@ # file -Source: `src/file.sh` +Source: `src/just_bashit/file.sh` Idempotent line-level file content management. @@ -12,7 +12,7 @@ Write a line to a file only if it is not already present. Optionally write a blank line. ```bash -. just-bashit/src/file.sh +. just-bashit/src/just_bashit/file.sh # Append a line (idempotent — safe to call repeatedly) add-line "export PATH=$PATH:/opt/myapp/bin" /etc/environment @@ -48,7 +48,7 @@ ______________________________________________________________________ Remove a line from a file if present. No-op if not found. ```bash -. just-bashit/src/file.sh +. just-bashit/src/just_bashit/file.sh remove-line "export PATH=$PATH:/opt/myapp/bin" /etc/environment @@ -82,7 +82,7 @@ ______________________________________________________________________ Copy every line from one file into another, skipping duplicates. ```bash -. just-bashit/src/file.sh +. just-bashit/src/just_bashit/file.sh # Merge new.conf into existing.conf without duplicating lines add-contents new.conf existing.conf diff --git a/docs/libraries/format.md b/docs/libraries/format.md index c38ae4d..79caae3 100644 --- a/docs/libraries/format.md +++ b/docs/libraries/format.md @@ -1,6 +1,6 @@ # format -Source: `src/format.sh` +Source: `src/just_bashit/format.sh` String trimming and colorized output. @@ -12,7 +12,7 @@ Trim a string at a marker character, from either direction, with optional greedy and keep-marker modes. ```bash -. just-bashit/src/format.sh +. just-bashit/src/just_bashit/format.sh trim-from 'report.2026.tar.gz' # report.2026.tar trim-from -r 'report.2026.tar.gz' # 2026.tar.gz @@ -53,7 +53,7 @@ ______________________________________________________________________ Print colorized text to stdout using ANSI escape sequences. ```bash -. just-bashit/src/format.sh +. just-bashit/src/just_bashit/format.sh color-echo -bc green "Build succeeded" color-echo -bc red "Build failed" diff --git a/docs/libraries/logging.md b/docs/libraries/logging.md index 30b2911..2ed00db 100644 --- a/docs/libraries/logging.md +++ b/docs/libraries/logging.md @@ -1,6 +1,6 @@ # logging -Source: `src/logging.sh` +Source: `src/just_bashit/logging.sh` Structured, colorized logging with timestamps. Depends on `format.sh`, `match.sh`, and `datetime.sh` — all resolved automatically from relative paths. @@ -12,7 +12,7 @@ ______________________________________________________________________ Log a message to stdout with a timestamp and type label. ```bash -. just-bashit/src/logging.sh +. just-bashit/src/just_bashit/logging.sh log "Starting deployment" # [20260522T143200Z::INFO]::Starting deployment @@ -74,7 +74,7 @@ ______________________________________________________________________ Sleep for a given duration with input validation. ```bash -. just-bashit/src/logging.sh +. just-bashit/src/just_bashit/logging.sh log-wait 5 # sleep 5 seconds log-wait 0.5 # sleep 500ms diff --git a/docs/libraries/make-run.md b/docs/libraries/make-run.md new file mode 100644 index 0000000..2ffb92c --- /dev/null +++ b/docs/libraries/make-run.md @@ -0,0 +1,166 @@ +# make-run + +Source: `src/just_bashit/make-run.sh` + +Ask a repository what its commands actually are, instead of transcribing +them. A repo bases its `Makefile` on +[`standard.mk`](https://just-buildit.github.io/standard.mk), which defines +the sanctioned defaults with `?=`; the repo then overrides what it must. +`make-run` reads the result of that layering, so there is no second copy to +vendor and nothing to keep in sync. + +The problem it removes is drift. A skill doc said `make docs` runs +`uv run zensical build --clean`, the sanctioned default was +`uv run --group dev zensical build --clean --strict`, and doppler — which +overrides `ZENSICAL` — actually ran `uv run --group docs ...`. Three answers, +two wrong, and nothing to make them disagree out loud. + +```bash +jbx make-run mk-var -C ~/doppler DOCS_BUILD_CMD +# uv run --group docs zensical build --clean --strict +``` + +______________________________________________________________________ + +## Functions + +| Function | Answers | +| ------------------------------ | -------------------------------------------- | +| `mk-var [-C DIR] NAME` | What is `NAME` set to, fully expanded? | +| `mk-vars [-C DIR] [REGEX]` | What is every file-defined variable set to? | +| `mk-run [-C DIR] TARGET [...]` | Run `TARGET` with the repo's own recipe | +| `mk-has [-C DIR] TARGET` | Does the repo define `TARGET`? (predicate) | +| `mk-origin [-C DIR] NAME` | Where did make get `NAME` — file, default, … | + +Every function takes `-C DIR` (default: the current directory) and `-h`. +Nothing is built and no recipe is run, except by `mk-run`, which is the one +function that is supposed to. + +______________________________________________________________________ + +## Usage + +`make-run.sh` is a library: it must be sourced, and it calls no other +just-bashit library. Either run it ephemerally through +[`jbx`](../just-runit.md), which sources the script and invokes the named +function: + +```bash +jbx make-run mk-var -C ~/doppler DOCS_BUILD_CMD +jbx make-run mk-has -C ~/doppler docs && echo "doppler builds docs" +jbx just-bashit:make-run -l # list the functions it defines +``` + +or source it into a shell that needs several of the functions: + +```bash +. just-bashit/src/just_bashit/make-run.sh + +mk-run -C ~/doppler docs +``` + +______________________________________________________________________ + +## The load-bearing rule: undefined is not empty + +`mk-var` **fails** when a variable was never defined, and **succeeds +printing an empty line** when it was defined as empty: + +```bash +mk-var -C ~/doppler DOCS_CHECK_CMD # legitimately empty → exit 0, blank line +mk-var -C ~/doppler DOSC_BUILD_CMD # typo, undefined → exit 1, message +# make-run: DOSC_BUILD_CMD is not defined in /home/you/doppler +``` + +Collapsing those two states is how a wrong command reads as a blank one — a +caller publishes an empty string where a real command belongs and nothing +looks broken. `mk-var` asks make's own `$(origin)` first, which is the only +reliable way to tell the two apart. `mk-origin` exposes that answer directly: + +```bash +mk-origin -C ~/doppler DOCS_BUILD_CMD # file +mk-origin -C ~/doppler CC # default +mk-origin -C ~/doppler NOPE # undefined +``` + +The same rule applies one level down. An unparseable makefile fails loudly +rather than handing back an empty database: `make -pRrq` exits 1 in question +mode, which is normal and ignored, and 2 when it cannot read the makefiles +at all, which is reported. + +______________________________________________________________________ + +## Examples + +### Read one command + +```bash +mk-var -C ~/doppler DOCS_BUILD_CMD +# uv run --group docs zensical build --clean --strict +``` + +### Read a whole family of them + +`mk-vars` takes no built-in list of "interesting" variables — such a list +would be exactly the hand-maintained copy this library exists to abolish. +Filter by name with an ERE instead, and note that all values resolve in a +single `make` invocation: + +```bash +mk-vars -C ~/doppler '_CMD$' +# DOCS_BUILD_CMD=uv run --group docs zensical build --clean --strict +# TEST_CMD=ctest --test-dir build --output-on-failure +``` + +### Run a target without knowing its recipe + +```bash +mk-run -C ~/doppler docs +``` + +`mk-run docs` runs whatever *that* repo means by `docs`, so a caller never +needs to know the command and therefore can never drift from it. The target +is verified to exist first, so a rename fails with a useful message instead +of make's `No rule to make target`. Arguments after the target pass straight +through to make: + +```bash +mk-run -C ~/doppler test -j8 +``` + +### Branch on whether a repo supports something + +```bash +if mk-has -C "${repo}" docs-check; then + mk-run -C "${repo}" docs-check +fi +``` + +`mk-has` reads make's target database rather than dry-running, so a target +with a missing prerequisite still answers honestly instead of erroring. + +______________________________________________________________________ + +## Requirements + +- **GNU make 3.81 or later.** The library expands its queries through a + throwaway sentinel makefile passed alongside the repo's own via `-f`, + rather than `--eval`, which arrived in 3.82 — macOS still ships 3.81 as + `/usr/bin/make`, so an `--eval` implementation passes every Linux runner + and fails only on the platform most likely to be running an old make. +- **A makefile in `DIR`.** `GNUmakefile`, `makefile`, or `Makefile`, in + make's own search order. Anything else exits 1 with + `make-run: no makefile in DIR`. +- `standard.mk` is not required. Any makefile can be queried; the defaults + layering is simply what makes the answers worth asking for. + +______________________________________________________________________ + +## What it does not do + +Nothing is built by `mk-var`, `mk-vars`, `mk-has`, or `mk-origin`. The +sentinel target is `.PHONY` with a no-op recipe, so make neither reports it +up to date nor runs any real recipe — the expansion happens at recipe run +time, which is what lets `$(info ...)` observe fully-layered values. +Evaluating the same expression while the makefiles are still being read +yields nothing, because the variables do not exist yet. diff --git a/docs/libraries/match.md b/docs/libraries/match.md index f422f98..02006a9 100644 --- a/docs/libraries/match.md +++ b/docs/libraries/match.md @@ -1,6 +1,6 @@ # match -Source: `src/match.sh` +Source: `src/just_bashit/match.sh` Regex pattern constants and numeric validation. @@ -18,7 +18,7 @@ Exported variables for use in `[[ =~ ]]` expressions: | `IS_ONLY_SIGNED_NUMBER` | `IS_SIGNED_NUMBER` anchored to full string | ```bash -. just-bashit/src/match.sh +. just-bashit/src/just_bashit/match.sh [[ "3.14" =~ $IS_ONLY_NUMBER ]] && echo "numeric" [[ "-7" =~ $IS_ONLY_SIGNED_NUMBER ]] && echo "signed numeric" @@ -31,7 +31,7 @@ ______________________________________________________________________ Return 0 (PASS) if a string is a valid number, 1 (FAIL) otherwise. ```bash -. just-bashit/src/match.sh +. just-bashit/src/just_bashit/match.sh is-number 42 # PASS is-number 3.14 # PASS diff --git a/docs/libraries/network.md b/docs/libraries/network.md index a4bce27..5a6d5d6 100644 --- a/docs/libraries/network.md +++ b/docs/libraries/network.md @@ -1,6 +1,6 @@ # network -Source: `src/network.sh` +Source: `src/just_bashit/network.sh` Network connectivity testing. Depends on `format.sh` and `environment.sh`. @@ -13,7 +13,7 @@ Test internet connectivity by probing URLs with `curl`, `wget`, and/or `ping` timeout. ```bash -. just-bashit/src/network.sh +. just-bashit/src/just_bashit/network.sh # Silent check — returns 0/1 test-internet-access && echo "online" || echo "offline" diff --git a/docs/libraries/path.md b/docs/libraries/path.md index 1e84e04..1e48322 100644 --- a/docs/libraries/path.md +++ b/docs/libraries/path.md @@ -1,6 +1,6 @@ # path -Source: `src/path.sh` +Source: `src/just_bashit/path.sh` Resolve the directory containing the calling script, regardless of how it was invoked (executed or sourced, symlinked or direct). @@ -13,7 +13,7 @@ Print the absolute, symlink-resolved path to the directory containing the calling script. ```bash -. just-bashit/src/path.sh +. just-bashit/src/just_bashit/path.sh # In your own script: SCRIPTDIR=$(get-scriptpath) @@ -45,7 +45,7 @@ Set the `SCRIPTPATH` environment variable to the calling script's directory. Must be called via `eval` so the export propagates to the calling environment. ```bash -. just-bashit/src/path.sh +. just-bashit/src/just_bashit/path.sh eval $(set-scriptpath) echo "${SCRIPTPATH}" # /absolute/path/to/your/script/dir diff --git a/docs/libraries/pkg.md b/docs/libraries/pkg.md index ffc7723..fbec6f9 100644 --- a/docs/libraries/pkg.md +++ b/docs/libraries/pkg.md @@ -1,6 +1,6 @@ # pkg -Source: `src/pkg.sh` +Source: `src/just_bashit/pkg.sh` Package manager detection and installed-version querying. @@ -12,7 +12,7 @@ Print the name of the active package manager for the running OS. Returns non-zero and prints to stderr if the OS is unrecognised. ```bash -. just-bashit/src/pkg.sh +. just-bashit/src/just_bashit/pkg.sh pm=$(get-pkg-mgr) # e.g. "pacman" on Arch, "apt" on Debian echo "Using ${pm}" @@ -52,7 +52,7 @@ Print the installed version of a package using the specified package manager. Prints nothing (not an error) if the package is not installed. ```bash -. just-bashit/src/pkg.sh +. just-bashit/src/just_bashit/pkg.sh get-pkg-version apt curl # e.g. "8.5.0-2" get-pkg-version pacman bash # e.g. "5.2.37-1" diff --git a/docs/libraries/toml.md b/docs/libraries/toml.md index 198ed50..5abe93a 100644 --- a/docs/libraries/toml.md +++ b/docs/libraries/toml.md @@ -1,6 +1,6 @@ # toml -Source: `src/toml.sh` +Source: `src/just_bashit/toml.sh` Pure-bash parser for the TOML subset used by just-bashit dependency files: `[group.pm]` sections with `packages = [...]` and `cmd = [...]` arrays. @@ -14,7 +14,7 @@ Extract each double-quoted string value from a TOML fragment, one per line. Skips empty quoted strings. ```bash -. just-bashit/src/toml.sh +. just-bashit/src/just_bashit/toml.sh toml_strings '"curl", "wget"' # prints: curl\nwget toml_strings '"a", "", "b"' # prints: a\nb (empty string skipped) diff --git a/docs/templates.md b/docs/templates.md index 4cfbb58..73f6f88 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -1,7 +1,7 @@ # Templates -Source: `src/function-template.sh`, `src/script-template`, -`src/bashrc-template.sh`, `src/profile-template.sh` +Source: `src/just_bashit/function-template.sh`, `src/just_bashit/script-template`, +`src/just_bashit/bashrc-template.sh`, `src/just_bashit/profile-template.sh` Copy-paste starting points for new bash functions and scripts, plus the opinionated shell configuration [`setup-system`](setup-system.md) installs. @@ -16,7 +16,7 @@ getopts-based option parsing, a heredoc help string, variable initialization before and after `getopts`, and a nested helper function. ```bash -. just-bashit/src/function-template.sh +. just-bashit/src/just_bashit/function-template.sh full-on-template -h # show usage full-on-template -p myvalue arg1 arg2 @@ -32,7 +32,7 @@ A stripped-down function template for simple functions that don't need the full getopts machinery. ```bash -. just-bashit/src/function-template.sh +. just-bashit/src/just_bashit/function-template.sh minimalist-template -h minimalist-template arg1 @@ -53,7 +53,7 @@ An executable script template (not a library) demonstrating: ```bash # Copy and rename -cp just-bashit/src/script-template my-script +cp just-bashit/src/just_bashit/script-template my-script chmod +x my-script ./my-script -h ``` diff --git a/scripts/docs_coverage.sh b/scripts/docs_coverage.sh new file mode 100644 index 0000000..10b54fe --- /dev/null +++ b/scripts/docs_coverage.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# ############################################################################ +# docs_coverage.sh — repo gate, not a shipped library. # +# ############################################################################ +# Two invariants, because make-run shipped in 0.4.0 breaking both and nothing # +# said so: it was documented nowhere, and a page written for it would still # +# have been invisible without a nav entry. # +# # +# 1. Every file shipped in src/just_bashit/ is named somewhere in the # +# user-facing docs. # +# 2. Every page under docs/ is reachable from zensical.toml's nav. # +# # +# docs/changelog.md is excluded as a mention source. It records every script # +# ever added, so counting it would pass every script the moment it was # +# released — a gate that is green by construction. # +# # +# Failures accumulate: both checks always run and every offender is listed, # +# so the set gets fixed once instead of being rediscovered one push at a # +# time. # +# ############################################################################ + +set -uo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")/.." || exit 1 + +rc=0 + +# --------------------------------------------------------------------------- +# 1. Shipped scripts are documented. +# +# Anything a user sources or executes counts. The Python launcher shims and +# the packaged template toml do not: they are packaging plumbing, not +# something anyone reads about. +# +# find rather than `git ls-files`, so a page that exists but is not yet staged +# still counts — a gate that fails until you `git add` reads as noise. Under +# pre-commit this is moot anyway, since it stashes unstaged work first and the +# gate then sees exactly the tree being committed. +# --------------------------------------------------------------------------- +undocumented=() +while IFS= read -r path; do + name="${path##*/}" + case "${name}" in + *.py | *.toml) continue ;; + esac + if ! grep -rqF -- "${name}" README.md docs \ + --exclude=changelog.md 2>/dev/null; then + undocumented+=("${name}") + fi +done < <(find src/just_bashit -type f) + +if ((${#undocumented[@]} > 0)); then + echo "ERROR: shipped scripts documented nowhere under docs/:" + printf ' %s\n' "${undocumented[@]}" + echo " Add a page (docs/libraries/NAME.md for a sourced library," + echo " docs/NAME.md for a command) and list it in zensical.toml nav." + rc=1 +fi + +# --------------------------------------------------------------------------- +# 2. Pages are reachable. +# +# A page absent from nav builds fine and is even served, so nothing fails — +# it is simply unlinked, which from the outside looks the same as never +# having been written. Nav paths are relative to docs/, so the prefix is +# stripped before looking each one up. +# --------------------------------------------------------------------------- +unlisted=() +while IFS= read -r page; do + if ! grep -qF -- "\"${page#docs/}\"" zensical.toml; then + unlisted+=("${page}") + fi +done < <(find docs -name '*.md') + +if ((${#unlisted[@]} > 0)); then + echo "ERROR: docs pages missing from zensical.toml nav:" + printf ' %s\n' "${unlisted[@]}" + rc=1 +fi + +if ((rc == 0)); then + echo "docs-coverage: every shipped script documented, every page in nav" +fi + +exit "${rc}" diff --git a/uv.lock b/uv.lock index d8f27e4..d511e11 100644 --- a/uv.lock +++ b/uv.lock @@ -38,9 +38,9 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "exceptiongroup" }, - { name = "idna" }, - { name = "typing-extensions" }, + { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, + { name = "idna", marker = "python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } wheels = [ @@ -55,9 +55,9 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, + { name = "idna", marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } wheels = [ @@ -153,7 +153,7 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } wheels = [ @@ -168,7 +168,7 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } wheels = [ @@ -207,7 +207,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -255,8 +255,8 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "certifi" }, - { name = "h11" }, + { name = "certifi", marker = "python_full_version < '3.10'" }, + { name = "h11", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c5/18/e51f5729684acaaab4d1cfca0777ac0f86440c65d2814992442ed5ef02e1/httpcore2-2.0.0.tar.gz", hash = "sha256:403692e0a0e8ea6de90993cdea815b2454d2ff5426e61d2a244846c12506af76", size = 63864, upload-time = "2026-05-12T17:59:22.073Z" } wheels = [ @@ -271,8 +271,8 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "h11" }, - { name = "truststore" }, + { name = "h11", marker = "python_full_version >= '3.10'" }, + { name = "truststore", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/a8/20ed1ed79cbc2ecdf5301c0968ab7c85547212e2a7bd126ddd2d986e206e/httpcore2-2.9.1.tar.gz", hash = "sha256:4d8acbf8b306f48c9d6046591fd5ba4037d1b1b1000d140fc2c3eab1e9a0c0e2", size = 67089, upload-time = "2026-07-24T09:21:03.867Z" } wheels = [ @@ -287,10 +287,10 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "anyio", version = "4.12.1", source = { registry = "https://pypi.org/simple" } }, - { name = "certifi" }, - { name = "httpcore2", version = "2.0.0", source = { registry = "https://pypi.org/simple" } }, - { name = "idna" }, + { name = "anyio", version = "4.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "certifi", marker = "python_full_version < '3.10'" }, + { name = "httpcore2", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "idna", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/70/95/868b3df4aa6f9cecb42aaf82a55a5a2c8ef40df76d709b812e1553d6a928/httpx2-2.0.0.tar.gz", hash = "sha256:f354249d2a9edce26e08fd2ad2276e98317b5763f673bb0d90f3ce9382cc2aed", size = 79506, upload-time = "2026-05-12T17:59:23.174Z" } wheels = [ @@ -305,11 +305,11 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "anyio", version = "4.14.2", source = { registry = "https://pypi.org/simple" } }, - { name = "httpcore2", version = "2.9.1", source = { registry = "https://pypi.org/simple" } }, - { name = "idna" }, - { name = "truststore" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "anyio", version = "4.14.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "httpcore2", version = "2.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "idna", marker = "python_full_version >= '3.10'" }, + { name = "truststore", marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/14/38128fbafd7e0ed41d874df6c9a653d47c2d111cfe59e2b4ac95161b4abd/httpx2-2.9.1.tar.gz", hash = "sha256:1932a768737e3666291582833da748cc4e563c337cf96706fccc04fa6e58764a", size = 95458, upload-time = "2026-07-24T09:21:04.972Z" } wheels = [ @@ -354,7 +354,7 @@ name = "jinja2" version = "3.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markupsafe" }, + { name = "markupsafe", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ @@ -363,7 +363,7 @@ wheels = [ [[package]] name = "just-bashit" -version = "0.3.2" +version = "0.4.0" source = { editable = "." } [package.dev-dependencies] @@ -410,7 +410,7 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "mdurl" }, + { name = "mdurl", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } wheels = [ @@ -425,7 +425,7 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "mdurl" }, + { name = "mdurl", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } wheels = [ @@ -533,8 +533,8 @@ name = "mdformat" version = "1.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py", version = "4.2.0", source = { registry = "https://pypi.org/simple" } }, - { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "markdown-it-py", version = "4.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "tomli", marker = "python_full_version == '3.10.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3f/05/32b5e14b192b0a8a309f32232c580aefedd9d06017cb8fe8fce34bec654c/mdformat-1.0.0.tar.gz", hash = "sha256:4954045fcae797c29f86d4ad879e43bb151fa55dbaf74ac6eaeacf1d45bb3928", size = 56953, upload-time = "2025-10-16T12:05:03.695Z" } wheels = [ @@ -546,9 +546,9 @@ name = "mdformat-frontmatter" version = "2.1.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mdformat" }, - { name = "mdit-py-plugins" }, - { name = "ruamel-yaml" }, + { name = "mdformat", marker = "python_full_version >= '3.10'" }, + { name = "mdit-py-plugins", marker = "python_full_version >= '3.10'" }, + { name = "ruamel-yaml", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/90/ae8a3d20066295367d9048ad480bcde3afe694eb592fec9c35bbdb7d68eb/mdformat_frontmatter-2.1.2.tar.gz", hash = "sha256:9c9c3159c38407f47e567202749c74ce7680017516cd158c82400f015c6a01d1", size = 9425, upload-time = "2026-05-23T05:14:26.324Z" } wheels = [ @@ -560,10 +560,10 @@ name = "mdformat-gfm" version = "1.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py", version = "4.2.0", source = { registry = "https://pypi.org/simple" } }, - { name = "mdformat" }, - { name = "mdit-py-plugins" }, - { name = "wcwidth" }, + { name = "markdown-it-py", version = "4.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "mdformat", marker = "python_full_version >= '3.10'" }, + { name = "mdit-py-plugins", marker = "python_full_version >= '3.10'" }, + { name = "wcwidth", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/6f/a626ebb142a290474401b67e2d61e73ce096bf7798ee22dfe6270f924b3f/mdformat_gfm-1.0.0.tar.gz", hash = "sha256:d1d49a409a6acb774ce7635c72d69178df7dce1dc8cdd10e19f78e8e57b72623", size = 10112, upload-time = "2025-10-16T09:12:22.402Z" } wheels = [ @@ -575,8 +575,8 @@ name = "mdformat-gfm-alerts" version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mdformat" }, - { name = "mdit-py-plugins" }, + { name = "mdformat", marker = "python_full_version >= '3.10'" }, + { name = "mdit-py-plugins", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/17/98382efef9d4a95fef60f1b5bf9e79a5f62f6698c747d2c99baacdf4cff8/mdformat_gfm_alerts-2.1.0.tar.gz", hash = "sha256:27673500976f08eb9e53cfa359f2a528c1be12052d3f8358996b9c5b1cc0c5c2", size = 9624, upload-time = "2026-07-26T06:46:31.343Z" } wheels = [ @@ -588,10 +588,10 @@ name = "mdformat-mkdocs" version = "5.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mdformat" }, - { name = "mdformat-gfm" }, - { name = "mdit-py-plugins" }, - { name = "more-itertools" }, + { name = "mdformat", marker = "python_full_version >= '3.10'" }, + { name = "mdformat-gfm", marker = "python_full_version >= '3.10'" }, + { name = "mdit-py-plugins", marker = "python_full_version >= '3.10'" }, + { name = "more-itertools", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2e/8c/ca9c13017fcb224e9a0c17c214279eb7273318d1890cd0adc80a3c30e443/mdformat_mkdocs-5.3.0.tar.gz", hash = "sha256:9ae35940cfc1d350c41dda717963c90c669937fbbe3be32412a2b975e4bf891d", size = 33319, upload-time = "2026-08-02T18:38:07.954Z" } wheels = [ @@ -603,7 +603,7 @@ name = "mdit-py-plugins" version = "0.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py", version = "4.2.0", source = { registry = "https://pypi.org/simple" } }, + { name = "markdown-it-py", version = "4.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" } wheels = [ @@ -669,11 +669,11 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "cfgv", version = "3.4.0", source = { registry = "https://pypi.org/simple" } }, - { name = "identify", version = "2.6.15", source = { registry = "https://pypi.org/simple" } }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, + { name = "cfgv", version = "3.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "identify", version = "2.6.15", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "nodeenv", marker = "python_full_version < '3.10'" }, + { name = "pyyaml", marker = "python_full_version < '3.10'" }, + { name = "virtualenv", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ff/29/7cf5bbc236333876e4b41f56e06857a87937ce4bf91e117a6991a2dbb02a/pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16", size = 193792, upload-time = "2025-08-09T18:56:14.651Z" } wheels = [ @@ -688,11 +688,11 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "cfgv", version = "3.5.0", source = { registry = "https://pypi.org/simple" } }, - { name = "identify", version = "2.6.19", source = { registry = "https://pypi.org/simple" } }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, + { name = "cfgv", version = "3.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "identify", version = "2.6.19", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "nodeenv", marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, + { name = "virtualenv", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8e/22/2de9408ac81acbb8a7d05d4cc064a152ccf33b3d480ebe0cd292153db239/pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9", size = 198525, upload-time = "2026-04-21T20:31:41.613Z" } wheels = [ @@ -707,7 +707,7 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "wcwidth" }, + { name = "wcwidth", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } wheels = [ @@ -722,7 +722,7 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "wcwidth" }, + { name = "wcwidth", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/ea/39b988c938f75cb75d7045b5c69f8bfed47ee2152c8837fb403de29d6fb8/prompt_toolkit-3.0.53.tar.gz", hash = "sha256:9ec8a0ad96d5c56148b3f914aa79c1564c3fde5d2e6b876e7bc327e353cf8fa6", size = 435492, upload-time = "2026-07-26T20:56:14.758Z" } wheels = [ @@ -883,9 +883,9 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv", version = "1.2.1", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-inspection" }, + { name = "pydantic", marker = "python_full_version < '3.10'" }, + { name = "python-dotenv", version = "1.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "typing-inspection", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/c5/dbbc27b814c71676593d1c3f718e6cd7d4f00652cefa24b75f7aa3efb25e/pydantic_settings-2.11.0.tar.gz", hash = "sha256:d0e87a1c7d33593beb7194adb8470fc426e95ba02af83a0f23474a04c9a08180", size = 188394, upload-time = "2025-09-24T14:19:11.764Z" } wheels = [ @@ -900,9 +900,9 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv", version = "1.2.2", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-inspection" }, + { name = "pydantic", marker = "python_full_version >= '3.10'" }, + { name = "python-dotenv", version = "1.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", size = 237700, upload-time = "2026-06-19T13:44:56.324Z" } wheels = [ @@ -923,8 +923,8 @@ name = "pymdown-extensions" version = "11.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown" }, - { name = "pyyaml" }, + { name = "markdown", marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/a9/5f0c535ba3b08fe09270c16808e053a968868242ecbd5676d4e3a488bf28/pymdown_extensions-11.0.1.tar.gz", hash = "sha256:dd2905ae6fc5b75582fafb139a1266ffc754705efa902aa50067fa7ff4f94ec0", size = 857113, upload-time = "2026-07-02T17:59:22.955Z" } wheels = [ @@ -1214,7 +1214,7 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "bracex", version = "2.6", source = { registry = "https://pypi.org/simple" } }, + { name = "bracex", version = "2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/79/3e/c0bdc27cf06f4e47680bd5803a07cb3dfd17de84cde92dd217dcb9e05253/wcmatch-10.1.tar.gz", hash = "sha256:f11f94208c8c8484a16f4f48638a85d771d9513f4ab3f37595978801cb9465af", size = 117421, upload-time = "2025-06-22T19:14:02.49Z" } wheels = [ @@ -1229,7 +1229,7 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "bracex", version = "3.0.1", source = { registry = "https://pypi.org/simple" } }, + { name = "bracex", version = "3.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/16/25/1da725838132221e33568973da484ff43813662ccc06ebf7f6e3abddfcd5/wcmatch-11.0.tar.gz", hash = "sha256:55d95c2447789712774b198ceec72939e88b5618f1f8f0a9b605bf7740b63b96", size = 141360, upload-time = "2026-07-10T05:50:24.183Z" } wheels = [ @@ -1250,14 +1250,14 @@ name = "zensical" version = "0.0.52" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click", version = "8.4.2", source = { registry = "https://pypi.org/simple" } }, - { name = "deepmerge" }, - { name = "jinja2" }, - { name = "markdown" }, - { name = "pygments" }, - { name = "pymdown-extensions" }, - { name = "pyyaml" }, - { name = "tomli" }, + { name = "click", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "deepmerge", marker = "python_full_version >= '3.10'" }, + { name = "jinja2", marker = "python_full_version >= '3.10'" }, + { name = "markdown", marker = "python_full_version >= '3.10'" }, + { name = "pygments", marker = "python_full_version >= '3.10'" }, + { name = "pymdown-extensions", marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, + { name = "tomli", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/22/53/f3657dc0ed7666b29cededfeb424b28b8cf1f6ca75f7066af76fca8c1bcf/zensical-0.0.52.tar.gz", hash = "sha256:b11b79dd1bb7da4c1a5293cbc5a2f4394d980bf2bf1c4c326062bc5ddcf2a2e8", size = 3991761, upload-time = "2026-07-30T10:22:51.45Z" } wheels = [ diff --git a/zensical.toml b/zensical.toml index c9230a7..f3395cc 100644 --- a/zensical.toml +++ b/zensical.toml @@ -26,6 +26,7 @@ nav = [ {"file" = "libraries/file.md"}, {"format" = "libraries/format.md"}, {"logging" = "libraries/logging.md"}, + {"make-run" = "libraries/make-run.md"}, {"match" = "libraries/match.md"}, {"network" = "libraries/network.md"}, {"path" = "libraries/path.md"},