diff options
-rw-r--r-- | Makefile.am | 14 | ||||
-rw-r--r-- | bootstrap.conf | 25 | ||||
-rwxr-xr-x | scripts/git-hooks/applypatch-msg | 15 | ||||
-rwxr-xr-x | scripts/git-hooks/commit-msg | 153 | ||||
-rwxr-xr-x | scripts/git-hooks/pre-applypatch | 14 | ||||
-rwxr-xr-x | scripts/git-hooks/pre-commit | 49 |
6 files changed, 270 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index 244024e..edee5fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,3 +42,17 @@ gen-ChangeLog: ALL_RECURSIVE_TARGETS += distcheck-hook distcheck-hook: $(MAKE) my-distcheck + +# Some of our git hook scripts are supposed to be identical to git's samples. +# See if they are still in sync. +.PHONY: check-git-hook-script-sync +check-git-hook-script-sync: + @fail=0; \ + t=$$(mktemp -d) \ + && cd $$t && git init -q && cd .git/hooks \ + && for i in pre-commit pre-applypatch applypatch-msg; do \ + diff -u $(abs_top_srcdir)/scripts/git-hooks/$$i $$i.sample \ + || fail=1; \ + done; \ + rm -rf $$t; \ + test $$fail = 0 diff --git a/bootstrap.conf b/bootstrap.conf index 828ffef..ac3c278 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -129,4 +129,29 @@ bootstrap_post_import_hook() bootstrap_epilogue() { perl -pi -e "s/\@PACKAGE\@/$package/g" README-release + + # Since this is a "GNU" package, replace this line + # if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null \ + # | grep -v 'libtool:' >/dev/null; then + # with this: + # if true; then + # Why? That pipeline searches all files in $(top_srcdir), and if you + # happen to have large files (or apparently large sparse files), the + # first grep may well run out of memory. + perl -pi -e 's/if LC_ALL=C grep .GNU .PACKAGE.*; then/if true; then/' \ + po/Makefile.in.in + + # Install our git hooks, as long as "cp" accepts the --backup option, + # so that we can back up any existing files. + case $(cp --help) in *--backup*) backup=1;; *) backup=0;; esac + if test $backup = 1; then + hooks=$(cd scripts/git-hooks && git ls-files) + for f in $hooks; do + # If it is identical, skip it. + cmp scripts/git-hooks/$f .git/hooks/$f > /dev/null \ + && continue + cp --backup=numbered scripts/git-hooks/$f .git/hooks + chmod a-w .git/hooks/$f + done + fi } diff --git a/scripts/git-hooks/applypatch-msg b/scripts/git-hooks/applypatch-msg new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ b/scripts/git-hooks/applypatch-msg @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/scripts/git-hooks/commit-msg b/scripts/git-hooks/commit-msg new file mode 100755 index 0000000..888b83b --- /dev/null +++ b/scripts/git-hooks/commit-msg @@ -0,0 +1,153 @@ +eval '(exit $?0)' && eval 'exec perl -w "$0" ${1+"$@"}' + & eval 'exec perl -w "$0" $argv:q' + if 0; + +use strict; +use warnings; +(my $ME = $0) =~ s|.*/||; + +# Emulate Git's choice of the editor for the commit message. +chomp (my $editor = `git var GIT_EDITOR`); +# And have a sane, minimal fallback in case of weird failures. +$editor = "vi" if $? != 0 or $editor =~ /^\s*\z/; + +# Keywords allowed before the colon on the first line of a commit message: +# program names and a few general category names. +my @valid = qw( + diff diff3 cmp sdiff + + gnulib tests maint doc build scripts + ); +my $v_or = join '|', @valid; +my $valid_regex = qr/^(?:$v_or)$/; + +# Rewrite the $LOG_FILE (old contents in @$LINE_REF) with an additional +# a commented diagnostic "# $ERR" line at the top. +sub rewrite($$$) +{ + my ($log_file, $err, $line_ref) = @_; + local *LOG; + open LOG, '>', $log_file + or die "$ME: $log_file: failed to open for writing: $!"; + print LOG "# $err"; + print LOG @$line_ref; + close LOG + or die "$ME: $log_file: failed to rewrite: $!\n"; +} + +sub re_edit($) +{ + my ($log_file) = @_; + + warn "Interrupt (Ctrl-C) to abort...\n"; + + system 'sh', '-c', "$editor $log_file"; + ($? & 127) || ($? >> 8) + and die "$ME: $log_file: the editor ($editor) failed, aborting\n"; +} + +sub bad_first_line($) +{ + my ($line) = @_; + + $line =~ /^[Vv]ersion \d/ + and return ''; + + $line =~ /:/ + or return 'missing colon on first line of log message'; + + $line =~ /\.$/ + and return 'do not use a period "." at the end of the first line'; + + # The token(s) before the colon on the first line must be on our list + # Tokens may be space- or comma-separated. + (my $pre_colon = $line) =~ s/:.*//; + my @word = split (/[ ,]/, $pre_colon); + my @bad = grep !/$valid_regex/, @word; + @bad + and return 'invalid first word(s) of summary line: ' . join (', ', @bad); + + return ''; +} + +# Given a $LOG_FILE name and a \@LINE buffer, +# read the contents of the file into the buffer and analyze it. +# If the log message passes muster, return the empty string. +# If not, return a diagnostic. +sub check_msg($$) +{ + my ($log_file, $line_ref) = @_; + + local *LOG; + open LOG, '<', $log_file + or return "failed to open for reading: $!"; + @$line_ref = <LOG>; + close LOG; + + my @line = @$line_ref; + chomp @line; + + # Don't filter out blank or comment lines; git does that already, + # and if we were to ignore them here, it could lead to committing + # with lines that start with "#" in the log. + + # Filter out leading blank and comment lines. + # while (@line && $line[0] =~ /^(?:#.*|[ \t]*)$/) { shift @line; } + + # Filter out blank and comment lines at EOF. + # while (@line && $line[$#line] =~ /^(?:#.*|[ \t]*)$/) { pop @line; } + + @line == 0 + and return 'no log message'; + + my $bad = bad_first_line $line[0]; + $bad + and return $bad; + + # Second line should be blank or not present. + 2 <= @line && length $line[1] + and return 'second line must be empty'; + + # Limit line length to allow for the ChangeLog's leading TAB. + foreach my $line (@line) + { + 72 < length $line && $line =~ /^[^#]/ + and return 'line longer than 72'; + } + + my $buf = join ("\n", @line) . "\n"; + $buf =~ m!https?://bugzilla\.redhat\.com/show_bug\.cgi\?id=(\d+)!s + and return "use shorter http://bugzilla.redhat.com/$1"; + + $buf =~ m!https?://debbugs\.gnu\.org/(?:cgi/bugreport\.cgi\?bug=)?(\d+)!s + and return "use shorter http://bugs.gnu.org/$1"; + + $buf =~ /^ *Signed-off-by:/mi + and return q(do not use "Signed-off-by:"); + + return ''; +} + +{ + @ARGV == 1 + or die; + + my $log_file = $ARGV[0]; + + while (1) + { + my @line; + my $err = check_msg $log_file, \@line; + $err eq '' + and last; + $err = "$ME: $err\n"; + warn $err; + # Insert the diagnostic as a comment on the first line of $log_file. + rewrite $log_file, $err, \@line; + re_edit $log_file; + + # Stop if our parent is killed. + getppid() == 1 + and last; + } +} diff --git a/scripts/git-hooks/pre-applypatch b/scripts/git-hooks/pre-applypatch new file mode 100755 index 0000000..4142082 --- /dev/null +++ b/scripts/git-hooks/pre-applypatch @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/scripts/git-hooks/pre-commit b/scripts/git-hooks/pre-commit new file mode 100755 index 0000000..68d62d5 --- /dev/null +++ b/scripts/git-hooks/pre-commit @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- |