|
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."
|