Skip to main content

max / makeover

1.7 KB · 59 lines History Blame Raw
1 #!/bin/bash
2 # rustfmt gate: blocks a commit whose staged Rust files are not formatted.
3 #
4 # Activate in a fresh clone (one-time):
5 # git config core.hooksPath scripts/githooks
6 #
7 # Bypass for a work-in-progress commit: git commit --no-verify
8 #
9 # Only crates with staged .rs changes are checked, so the hook stays fast on a
10 # large repo. Each file maps to the nearest enclosing Cargo.toml, and the check
11 # runs as `cargo fmt` there, which picks up that crate's edition and any
12 # rustfmt.toml rather than guessing.
13 set -euo pipefail
14
15 ROOT="$(git rev-parse --show-toplevel)"
16 cd "$ROOT"
17
18 # Paths the gate ignores (extended regex, matched against repo-relative paths).
19 # Empty means check everything.
20 SKIP_PATHS="${SKIP_PATHS:-}"
21
22 staged="$(git diff --cached --name-only --diff-filter=ACMR -- '*.rs')"
23 if [ -n "$SKIP_PATHS" ]; then
24 staged="$(printf '%s\n' "$staged" | grep -Ev "$SKIP_PATHS" || true)"
25 fi
26 [ -n "$staged" ] || exit 0
27
28 # Map each staged file to the directory of its nearest Cargo.toml.
29 crates=""
30 while IFS= read -r f; do
31 [ -n "$f" ] || continue
32 d="$(dirname "$f")"
33 while [ "$d" != "." ] && [ ! -f "$d/Cargo.toml" ]; do
34 d="$(dirname "$d")"
35 done
36 [ -f "$d/Cargo.toml" ] || continue
37 crates="$crates$d"$'\n'
38 done <<< "$staged"
39
40 crates="$(printf '%s' "$crates" | sort -u)"
41 [ -n "$crates" ] || exit 0
42
43 failed=0
44 while IFS= read -r c; do
45 [ -n "$c" ] || continue
46 if ! (cd "$c" && cargo fmt --check >/dev/null 2>&1); then
47 echo "pre-commit: rustfmt gate failed in $c"
48 failed=1
49 fi
50 done <<< "$crates"
51
52 if [ "$failed" -ne 0 ]; then
53 echo "pre-commit: run 'cargo fmt' in the crates above, then restage."
54 echo "pre-commit: commit aborted (use --no-verify to bypass)."
55 exit 1
56 fi
57
58 echo "pre-commit: rustfmt gate clean."
59