#!/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 a file is misformatted; the files are named on stdout exit 2 usage error, or cargo could not be run -- NOT a formatting verdict Exit 2 exists because `cargo fmt -p opfs-contract -- --check` from the repo root exits 1 with `not a member of the workspace`, which is indistinguishable from a real failure to a caller reading $?. 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. 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 "$@"