tinymux/hooks/pre-commit
Stephen Dennis 6ef95166d3 Make pre-commit hook bash 3.2 compatible
The hook used `declare -A` (associative array, bash 4+ only).  On
macOS where /bin/bash is still 3.2, the declaration silently failed
and the loop iterated zero entries — so the hook printed a parse
error to stderr but skipped its actual check, defeating the
protection against committing generated files without their source.

Rewrite with parallel arrays (GENERATED_GENS / GENERATED_SRCS
indexed in lockstep), which work on bash 3.2 onward.  Verified the
hook executes cleanly under /bin/bash 3.2.57.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 19:51:41 -06:00

110 lines
3.1 KiB
Bash
Executable file

#!/bin/bash
#
# Pre-commit hook: warn when committing generated files without their sources.
# This catches the common mistake of editing generated output instead of the
# real source (e.g., editing art_scan.cpp instead of art_scan.rl).
#
# Uses parallel arrays (not associative arrays) for bash 3.2 compatibility,
# since macOS still ships /bin/bash as 3.2.
# Generated file (index N) maps to source file at GENERATED_SRCS[N].
# Use "NEVER_EDIT" for third-party vendored files that should not be edited.
GENERATED_GENS=(
# Ragel scanners
"mux/modules/engine/art_scan.cpp"
"mux/modules/engine/ast_scan.cpp"
"mux/lib/color_ops.c"
"mux/muxescape/muxescape.cpp"
# Unicode tables (source is the utf/ pipeline, not a single file)
"mux/include/utf8tables.h"
"mux/lib/utf8tables.cpp"
"mux/include/unicode_tables_c.h"
"mux/lib/unicode_tables.c"
"mux/include/ducet_cetable.h"
"mux/rv64/src/unicode_tables.c"
# Autoconf
"mux/configure"
"mux/aclocal.m4"
# Protocol Buffers
"client/console/src/hydra.pb.h"
"client/console/src/hydra.pb.cc"
"client/console/src/hydra.grpc.pb.h"
"client/console/src/hydra.grpc.pb.cc"
"client/win32gui/src/hydra.pb.h"
"client/win32gui/src/hydra.pb.cc"
"client/win32gui/src/hydra.grpc.pb.h"
"client/win32gui/src/hydra.grpc.pb.cc"
"client/tf/src/proto/hydra.pb.h"
"client/tf/src/proto/hydra.pb.cc"
"client/tf/src/proto/hydra.grpc.pb.h"
"client/tf/src/proto/hydra.grpc.pb.cc"
# SQLite amalgamation (third-party)
"mux/sqlite/sqlite3.c"
"mux/sqlite/sqlite3.h"
)
GENERATED_SRCS=(
"mux/modules/engine/art_scan.rl"
"mux/modules/engine/ast_scan.rl"
"mux/lib/color_ops.rl"
"mux/muxescape/muxescape.rl"
"utf/"
"utf/"
"utf/"
"utf/"
"utf/"
"utf/"
"mux/configure.ac"
"mux/configure.ac"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"mux/proxy/hydra.proto"
"NEVER_EDIT"
"NEVER_EDIT"
)
staged=$(git diff --cached --name-only)
warnings=""
for i in "${!GENERATED_GENS[@]}"; do
gen="${GENERATED_GENS[$i]}"
src="${GENERATED_SRCS[$i]}"
if echo "$staged" | grep -qx "$gen"; then
if [ "$src" = "NEVER_EDIT" ]; then
# Third-party vendored file — should never be hand-edited
warnings="${warnings} ${gen} (third-party vendored file — replace, don't edit)\n"
elif ! echo "$staged" | grep -q "^${src}"; then
# Check if the source is also staged
warnings="${warnings} ${gen} (source: ${src})\n"
fi
fi
done
if [ -n "$warnings" ]; then
echo ""
echo "WARNING: Generated file(s) staged WITHOUT their source:"
echo ""
printf "$warnings"
echo ""
echo "Did you edit a generated file by mistake?"
echo "Edit the source and regenerate instead."
echo ""
echo "To commit anyway: git commit --no-verify"
exit 1
fi