Files
improvise/scripts/fmt-workspaces.sh
T
Edward Langley 3d1430110c Narrow the fmt gate's exit contract to what it actually maintains
ChatGPT Codex on PR #159: both formatter invocations end `|| rc=1`, so any
failure after the rustfmt probe was reported as "misformatted" although no
verdict was produced. Correct, and the narrower form of the bug this gate
exists for.

Measured: an unparseable source exits 1, identical to a diff; an unknown
rustfmt.toml option is only a warning (exit 0).

Narrowed rather than re-classified, because telling a diff from a parse error
means parsing rustfmt's prose, which is the check-adjacent-to-its-subject this
repo keeps getting wrong. The line the split needs is "did the gate run":
exit 1 names a file and blames the tree; exit 2 names none and blames the
invocation, and every exit-2 cause is checked above the loop.

Two more rivals injected: deleting the `cargo fmt --version` probe, and
turning `|| rc=1` into `|| return 2`. The first exposed a vacuous test -- a
cargo stub that failed for every argument also breaks `cargo metadata`, so the
run exited 2 on the metadata arm and the probe could be deleted with the suite
green. The stub now delegates every subcommand but `fmt`, which is the shape a
missing rustfmt component actually has.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-22 20:09:04 -07:00

146 lines
5.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Format-checks every Cargo workspace root in the repo, from any directory.
# `cargo fmt --all` reaches only ONE of them. Reasoning: context/code/tooling.md
# section 4 -- including why `-p` scoped by `--manifest-path` is the only
# spelling that is neither blind nor boundary-crossing (improvise-b4ks).
set -uo pipefail
usage() {
cat >&2 <<'EOF'
usage: fmt-workspaces.sh [--list] [--fix] [repo-root]
repo-root the tree to scan; defaults to the directory above this script
--list print each workspace root and its members, then exit
--fix rewrite the offending files instead of reporting them
exit 0 every workspace root is formatted
exit 1 rustfmt did not certify a root clean: a file differs from rustfmt's
output, or rustfmt refused to parse one. Either way a FILE IS NAMED
and the tree is what is wrong.
exit 2 the gate did not run: usage error, no cargo, no rustfmt, cargo
metadata failed, or no [workspace] root found. NO verdict was
produced and NO file is named.
The split is "did the gate run", not "is every exit-1 cause a diff". That is
narrower than it sounds and it is deliberate -- see the note on rc=1 below.
Exit 2 exists because `cargo fmt -p opfs-contract -- --check` from the repo
root exits 1 with `not a member of the workspace`, having checked nothing and
named nothing, which a caller reading $? cannot tell from a real failure.
Never collapse 2 into 1.
EOF
}
# `[workspace]` at the start of a line, in a Cargo.toml that is not vendored
# build output. `harness/opfs-contract` carries an empty one, so it is its own
# root and the outer `--all` never reaches it.
#
# The find is RELATIVE to the tree being scanned: an absolute `-path` filter
# matches the ancestors too, and this repo is itself checked out under
# `.claude/worktrees/` in every agent worktree, where that excluded everything.
workspace_roots() {
local root="$1"
( cd "$root" && find . -name Cargo.toml \
-not -path './target/*' -not -path '*/target/*' \
-not -path './.git/*' \
-not -path '*/node_modules/*' \
-not -path './.claude/*' ) \
| sort \
| while IFS= read -r rel; do
if grep -q '^\[workspace\]' "$root/${rel#./}"; then
printf '%s\n' "$root/${rel#./}"
fi
done
}
# The members of ONE workspace, named by cargo rather than parsed out of the
# manifest: a `members = [...]` list may carry globs and path dependencies.
members_of() {
local manifest="$1" meta
meta="$(cargo metadata --manifest-path "$manifest" --no-deps --format-version 1 2>/dev/null)" || return 1
printf '%s' "$meta" | python3 -c '
import json, sys
doc = json.load(sys.stdin)
names = [p["name"] for p in doc["packages"]]
if not names:
sys.exit(1)
print("\n".join(names))
' || return 1
}
main() {
local list=0 mode=--check root=""
while [ $# -gt 0 ]; do
case "$1" in
--list) list=1 ;;
--fix) mode=--fix ;;
-h|--help) usage; return 2 ;;
-*) printf 'fmt-workspaces: unknown option %s\n' "$1" >&2; usage; return 2 ;;
*)
if [ -n "$root" ]; then
printf 'fmt-workspaces: at most one repo-root, got %s and %s\n' "$root" "$1" >&2
return 2
fi
root="$1" ;;
esac
shift
done
if [ -z "$root" ]; then root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"; fi
if [ ! -d "$root" ]; then
printf 'fmt-workspaces: not a directory: %s\n' "$root" >&2
return 2
fi
command -v cargo >/dev/null 2>&1 || {
echo 'fmt-workspaces: cargo is not on PATH' >&2; return 2; }
# Without this, a missing rustfmt component exits 1 from `cargo fmt` and
# reads as "your code is misformatted" -- the very confusion this exists for.
cargo fmt --version >/dev/null 2>&1 || {
echo 'fmt-workspaces: cargo fmt is unavailable (rustfmt component missing?)' >&2
return 2; }
local -a roots=()
while IFS= read -r m; do [ -n "$m" ] && roots+=("$m"); done < <(workspace_roots "$root")
if [ ${#roots[@]} -eq 0 ]; then
printf 'fmt-workspaces: no [workspace] root under %s\n' "$root" >&2
return 2
fi
local rc=0 manifest member
for manifest in "${roots[@]}"; do
local -a pkgs=()
while IFS= read -r member; do [ -n "$member" ] && pkgs+=("$member"); done \
< <(members_of "$manifest")
if [ ${#pkgs[@]} -eq 0 ]; then
printf 'fmt-workspaces: cargo metadata failed for %s\n' "$manifest" >&2
return 2
fi
if [ "$list" = 1 ]; then
printf '%s: %s\n' "$manifest" "${pkgs[*]}"
continue
fi
# `-p` for every member, scoped by this root's own manifest. NOT `--all`,
# which walks PAST a nested workspace boundary and reports the outer tree's
# files under the inner root's name; and not the bare manifest-path form,
# which silently checks only the root package and misses every member.
# `|| rc=1` deliberately does NOT try to separate a diff from a source
# rustfmt could not parse: both exit 1 and both NAME A FILE, so both are
# facts about the tree. Measured: an unclosed delimiter exits 1, and an
# unknown rustfmt.toml option is only a warning (exit 0). What exit 2 is
# reserved for is "the gate did not run", and every such cause is checked
# ABOVE this loop. Reasoning: context/test-evidence/tooling.md.
local -a flags=()
for member in "${pkgs[@]}"; do flags+=(-p "$member"); done
if [ "$mode" = --fix ]; then
cargo fmt --manifest-path "$manifest" "${flags[@]}" || rc=1
else
cargo fmt --manifest-path "$manifest" "${flags[@]}" -- --check || rc=1
fi
done
return $rc
}
main "$@"