ソースを参照

Widen the tidy hook, and fix the bug that stopped it working

It now covers .PL, which is how Makefile.PL had drifted to two-space indent
without anyone noticing, and anything executable with perl on its shebang
line, which is how the extensionless scripts in bin/ were escaping it.

Three things were also plainly broken:

  [ $to_tidy ] is a syntax error the moment two files are staged -- sh says
  "unexpected operator" and the test is false -- so the hook quietly stopped
  tidying in exactly the commits that touched the most Perl.  Now [ -n "..." ].

  perltidy -b leaves <name>.bak next to every file it touches, and .gitignore
  does not cover those.  -bext='/' makes it clean up after itself.

  egrep ".p[m|l]$" has an unescaped dot and a character class containing a
  literal pipe, so it matched xpm and d.p| while missing Makefile.PL.
  A case statement on the extension does the intended job.

Also skips deleted paths, which perltidy cannot open, and says so and stands
down when perltidy is not installed rather than re-adding files it never
touched.

Note .t files still match none of the three rules unless they happen to be
+x, and only one of the seven is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJ2NAMQyytncwHKSmD5dFe
George Baugh 1 ヶ月 前
親
コミット
1b9551d39c
1 ファイル変更、49 行追加、3 行削除
  1. 49 3
      git-hooks/pre-commit

+ 49 - 3
git-hooks/pre-commit

@@ -1,14 +1,60 @@
 #!/bin/sh
 
-to_tidy=$(git diff --cached --name-only  | egrep ".p[m|l]$")
+# Auto-tidy staged Perl before it lands.
+#
+# A file qualifies three ways:
+#   - a .pm or .pl extension
+#   - a .PL extension, which is how Makefile.PL gets covered
+#   - executable with perl on its shebang line, which is how the extensionless
+#     scripts in bin/ get covered
+#
+# Note that a .t file matches none of these unless it happens to be +x.
 
 # Redirect output to stderr.
 exec 1>&2
 
-if [ $to_tidy  ]
+if ! command -v perltidy >/dev/null 2>&1
+then
+    echo "pre-commit: perltidy is not on PATH, skipping the tidy pass."
+    exit 0
+fi
+
+# ACMR so that a file deleted in this commit is not handed to perltidy, which
+# would fail on a path that is no longer there.
+staged=$(git diff --cached --name-only --diff-filter=ACMR)
+
+to_tidy=''
+for file in $staged
+do
+    test -f "$file" || continue
+
+    case "$file" in
+        *.pm|*.pl|*.PL)
+            to_tidy="$to_tidy $file"
+            continue
+            ;;
+    esac
+
+    if test -x "$file" && head -n 1 "$file" | grep -Eq '^#!.*perl'
+    then
+        to_tidy="$to_tidy $file"
+    fi
+done
+
+# -n and quoted, unlike the version this replaces: bare [ $to_tidy ] is a
+# syntax error the moment there is more than one file, so the hook quietly
+# stopped tidying in exactly the commits that needed it most.
+if [ -n "$to_tidy" ]
 then
     echo "Auto-tidying perl changes..."
-    perltidy -b $to_tidy
+
+    # -bext='/' makes perltidy delete the backup it would otherwise leave
+    # sitting next to the file as <name>.bak.
+    perltidy -b -bext='/' $to_tidy || {
+        echo "pre-commit: perltidy failed, leaving the commit alone."
+        exit 1
+    }
+
     git update-index --add $to_tidy
     echo "Done."
 fi