Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ members = [

[package]
name = "retch-cli"
version = "0.6.19"
version = "0.6.20"
edition = "2021"
authors = ["Ken Tobias"]
description = "A fast, feature-rich system information fetcher written in Rust (similar to fastfetch or neofetch)"
Expand Down
100 changes: 87 additions & 13 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,92 @@

# Required for shebang recipes to receive *ARGS as real argv ($@) instead of
# losing quoting via textual {{ARGS}} interpolation (see open-pr).
# ===== PROJECT — the only part of the install family this repo owns =====
#
# The COMMON block below is written against these so it can be byte-identical across repos
# that ship different binaries. `etr` sets BINS to two names; this repo has one.
BINS := "retch"
MAN_PAGES := "docs/retch.1"

# Do NOT edit inside the markers below. Edit templates/justfile-common.just and the two
# vendored helpers, bump their versions, and propagate to the sibling repos in their own PRs.
# `just standard-check` runs the helpers' self-tests and `just check` depends on it, so a
# violation fails the build rather than being discovered years later.
# >>> COMMON (template v2)
# The interpreter is resolved ONCE per line, and a missing one is a hard error. The
# `python3 … 2>/dev/null || python …` idiom is deliberately NOT used: it retries on ANY
# failure, so a real error inside the script gets re-run and reported as if the
# interpreter were the problem.
PY := `command -v python3 || command -v python || echo PYTHON-NOT-FOUND`

# Install from this checkout: binary, man page(s) and completions.
#
# The dependencies are the point. `cargo install` alone replaces the binary and leaves the
# man page and completions at whatever version last ran their recipe — measured on a host
# whose page was ELEVEN releases stale with nothing reporting it.
install: install-man install-completions
cargo install --path .

# Install a RELEASED tag: binary, man page(s) and completions, all three FROM THAT TAG.
#
# **It deliberately does NOT depend on `install-man`/`install-completions`**, because those
# work from the checkout. Reusing them would pair a tag's binary with the worktree's man
# page and completions — on a checkout one release ahead, a v0.2.22 binary with a v0.2.23
# page. Mismatched artefacts that each look fine is the failure class this standard exists
# to remove, so the three sources are made to agree: binary from the tag, completions from
# THE INSTALLED BINARY (`--from-path`), man page from the tag (`--from-tag`).
#
# Never `--path`: on a Syncthing-shared checkout that builds from a directory other
# machines write into. Takes a bare version and normalises a leading `v`.
install-tag VERSION:
#!/usr/bin/env bash
set -euo pipefail
V="{{VERSION}}"; V="${V#v}"
[ -n "$V" ] || { echo "error: install-tag needs a version, e.g. just install-tag 0.2.22" >&2; exit 1; }
git rev-parse -q --verify "refs/tags/v${V}" >/dev/null || {
echo "error: tag v${V} is not in this clone. Run: git fetch --tags" >&2; exit 1; }
REPO=$(git config --get remote.origin.url)
echo "Installing from tag v${V} of ${REPO}"
cargo install --git "$REPO" --tag "v${V}" --locked --force
# POST-CONDITION: cargo prints a replacement line, but only a version query proves which
# binary is on PATH now.
for b in {{BINS}}; do
command -v "$b" >/dev/null 2>&1 || { echo "error: $b is not on PATH after install" >&2; exit 1; }
echo " $b -> $("$b" --version)"
done
"{{PY}}" scripts/install_man.py {{MAN_PAGES}} --from-tag "v${V}"
"{{PY}}" scripts/install_completions.py {{BINS}} --from-path

# Install the man page(s) to the XDG man directory.
install-man: man
@"{{PY}}" scripts/install_man.py {{MAN_PAGES}}

# Generate and install shell completions for every binary.
#
# Python rather than a just recipe, which is retch's finding and the more portable
# mechanism: no `sh`, no `cygpath`, no coreutils, nothing from Git's `usr\bin` on Windows.
# A `bash` shebang recipe cannot run on Windows without `cygpath` at all, and even a plain
# `sh` recipe still needs an `sh` on PATH.
install-completions: build
@"{{PY}}" scripts/install_completions.py {{BINS}}

# Prove the vendored helpers still behave the way the standard requires.
#
# **This runs the helpers' own self-tests rather than diffing text**, and that is the whole
# point: three separate repositories cannot diff each other's files, but each can prove its
# copy still behaves correctly — which is the property that was actually violated when two
# repos quietly shipped the pre-fix nushell path for months. A text diff would also have
# passed happily on a repo that had never adopted the standard at all.
standard-check:
#!/usr/bin/env bash
set -euo pipefail
[ "{{PY}}" != "PYTHON-NOT-FOUND" ] || { echo "error: no python3/python on PATH" >&2; exit 1; }
"{{PY}}" scripts/install_completions.py --self-test
"{{PY}}" scripts/install_man.py --self-test
# <<< COMMON

# ===== PROJECT-SPECIFIC — everything below is this repo's own =====

set positional-arguments := true

# Default recipe
Expand Down Expand Up @@ -37,7 +123,7 @@ lint:
cargo clippy --workspace -- -D warnings

# Run strict checks (formatting and linting) as done in CI
check:
check: standard-check
cargo fmt -- --check
cargo clippy --workspace -- -D warnings
# Also lint the optional `graphics` feature (base64/image/icy_sixel in src/logo.rs),
Expand All @@ -50,22 +136,10 @@ audit:
@command -v cargo-audit >/dev/null || cargo install cargo-audit
cargo audit

# Install the binary, man page, and shell completions
install: install-man install-completions
cargo install --path .

# Generate man page from Markdown using mandown (requires: mandown)
man:
@python3 scripts/build_man.py 2>/dev/null || python scripts/build_man.py

# Install man page to XDG user location (~/.local/share/man)
install-man: man
@python3 scripts/install_man.py 2>/dev/null || python scripts/install_man.py

# Install shell completions for all supported shells to XDG user locations
install-completions: build
@python3 scripts/install_completions.py 2>/dev/null || python scripts/install_completions.py

# Convert all SVGs to PNGs (used for embedded logos)
logos:
#!/usr/bin/env bash
Expand Down
57 changes: 56 additions & 1 deletion NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,62 @@ The `retch-sysinfo` crate can be used independently as a library for cross-platf

---

## Current State (v0.6.19)
## Current State (v0.6.20)
- **v0.6.20 — nushell completions went where Windows nushell never looks; the install helpers
become a checked cross-repo standard** (tooling only; no runtime behavior change,
`retch-sysinfo` unchanged at `0.1.53`).
- **The bug: `scripts/install_completions.py` wrote nushell completions to
`$XDG_CONFIG_HOME/nushell/autoload`.** On Windows `$nu.user-autoload-dirs` is exactly
`%APPDATA%\nushell\autoload` — one entry — and nushell there does **not** read the XDG path at
all, whatever `XDG_CONFIG_HOME` says. So the helper wrote a real file to a directory nothing
consults, printed `Installed completions for retch:` with its full path, and delivered nothing.
Measured in `rusticprofile` (its `0.2.14`), where the same defect explained shell aliases absent
for months while present in the dotfiles the whole time. **Silent in exactly the direction that
matters.**
- **A second defect, in the reporting rather than the paths: the helper survived a failure and
then claimed success.** `except subprocess.CalledProcessError` logged to stderr and continued,
and `print("Installed completions for retch:")` plus the full path list ran unconditionally
afterwards — a step reporting success over work it did not do. The canonical helper raises.
- **Third, milder: nothing checked whether zsh would ever load the file.** zsh reads completion
functions only from directories on `fpath`, and `~/.local/share/zsh/site-functions` is not on it
by default on any distribution. This helper did not *claim* auto-loading (etr's does), but it did
not warn either. It now checks, using an **interactive** zsh — a non-interactive one sources
neither `.zshrc` nor anything it includes, so asking it returns the built-in default and gets the
answer confidently wrong in the other direction.
- **This repo's mechanism was right and is now the standard.** `v0.6.16` moved these recipes to
Python precisely so they run natively on Windows without Git's `usr\bin`, and that holds:
`rusticprofile` first proposed replacing them with plain-`sh` recipes because *it* held the
correctness fixes, which would have regressed this repo's portability work in the name of
consistency. **The two repos had each solved half the problem.** The standard keeps retch's
mechanism and rusticprofile's correctness.
- **`scripts/install_completions.py` and `scripts/install_man.py` are now canonical and vendored
byte-identically** across `retch`, `rusticprofile` and `etr` (`TEMPLATE_VERSION = 2`), alongside
`templates/justfile-common.just` — the reference for the Justfile block between
`# >>> COMMON (template v2)` and `# <<< COMMON`. Project facts (`BINS`, `MAN_PAGES`) sit in a
`PROJECT` header above it, because `etr` ships two binaries and a block with a hardcoded name
cannot be copied.
- **`just standard-check` runs the helpers' `--self-test`, and `just check` depends on it.** Not a
text diff: three separate repositories cannot diff each other's files, and a text diff would pass
happily on a repo that never adopted the standard. The self-tests assert the invariants directly
— the Windows nushell path, that `APPDATA` disturbs none of the other five directories, that XDG
overrides are honoured, and that an *empty* XDG variable falls back rather than resolving every
path against `/`. Each was watched failing; reverting the nushell line reports
`windows nushell dir: expected …AppData\Roaming… got …/.config/…`.
- **New recipe `install-tag VERSION`** — installs a released tag with all three artefacts *from
that tag*: binary via `cargo install --git --tag`, completions generated by **the installed
binary** so they cannot disagree with its CLI, and the man page read out of the tag via
`git show`. It deliberately does not depend on `install-man`/`install-completions`, which work
from the checkout: reusing them would pair a tag's binary with the worktree's man page. Prompted
by a fleet host found running a current binary beside a man page **eleven releases old**, because
every upgrade was a hand-typed `cargo install` and nothing re-ran the other two recipes.
- **The `python3 … 2>/dev/null || python …` idiom is gone.** It retries on *any* failure, so a real
error inside the script was re-run and reported as though the interpreter were missing. The
interpreter resolves once into `PY`, and its absence is a named error.
- Scope: the standard covers the install/man/completions family only. `check`/`lint`/`test`/`pr`
legitimately differ across the three repos (`--workspace` here, `--all-targets` in etr, bare in
rusticprofile) and reconciling them is a behaviour change per repo rather than a copy;
`templates/justfile-common.just` records that and the other known divergences.
- `retch-cli` → 0.6.20. Patch bump.
- **v0.6.19 — dependency bumps (consolidated Dependabot #188)** (chore; no runtime behavior
change). Rolls Dependabot's PR onto a gated branch so the release hygiene it bypasses —
version bump, NOTES entry, man regen — is actually done, following the #167/v0.6.3 and
Expand Down
2 changes: 1 addition & 1 deletion docs/retch.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH "RETCH" "1" "August 2026" "retch 0.6.19" "System Information Fetcher"
.TH "RETCH" "1" "August 2026" "retch 0.6.20" "System Information Fetcher"

.SH "NAME"
.PP
Expand Down
Loading