summaryrefslogtreecommitdiff
path: root/hooks
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2020-02-02 11:38:26 -0700
committerSean Whitton <spwhitton@spwhitton.name>2020-02-02 11:38:26 -0700
commit389125925095d1ffff276ac25671365f20540d98 (patch)
treed616ab4f260599a2bc20d605cc53268d1ff7a709 /hooks
parentbc687302753c78c8acdffbf89aa4b3a0ba3fb466 (diff)
downloaddotfiles-389125925095d1ffff276ac25671365f20540d98.tar.gz
add chained_hook hook
Diffstat (limited to 'hooks')
-rwxr-xr-xhooks/git/chained_hook60
1 files changed, 60 insertions, 0 deletions
diff --git a/hooks/git/chained_hook b/hooks/git/chained_hook
new file mode 100755
index 00000000..ad6a422e
--- /dev/null
+++ b/hooks/git/chained_hook
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+
+# Some aspects of this approach are due to:
+# http://blog.bluefeet.net/2011/08/chained-git-hooks/
+# see: http://web.archive.org/web/20111231092040/http://blog.bluefeet.net/2011/08/chained-git-hooks/
+#
+# This implementation using IO::Pipe is
+# Copyright (C) 2020 Sean Whitton <spwhitton@spwhitton.name>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Use by symlinking this hook to .git/hooks/pre-push (or whichever
+# hook you want to chain) and then add your hooks as
+# .git/hooks/pre-push_01foo, .git/hooks/pre-push_02bar etc.
+
+use 5.028;
+use strict;
+use warnings;
+
+use IO::Pipe;
+use File::Spec::Functions qw(catfile);
+
+(my $hook_type = $0) =~ s{^.+/}{};
+my $config_hooks_path = `git config core.hooksPath`;
+chomp(my $hook_dir = $config_hooks_path || `git rev-parse --git-path hooks`);
+opendir(my $dirh, $hook_dir);
+my @hooks = sort grep /^${hook_type}_/, readdir $dirh;
+
+my @stdin = <STDIN>;
+
+foreach my $hook (@hooks) {
+ my $pipe = IO::Pipe->new;
+ my $pid = fork;
+ die "fork() failed: $!" unless defined $pid;
+ if ($pid) {
+ $pipe->writer;
+ print $pipe $_ for @stdin;
+ $pipe->close;
+ wait;
+ # give up as soon as one hook fails; since we sort the hooks,
+ # we can put more expensive hooks later in the sequence
+ die "hook $hook exited non-zero" if $?;
+ } else {
+ $pipe->reader;
+ open STDIN, "<&=" . $pipe->fileno
+ or die "couldn't open child's STDIN";
+ exec catfile($hook_dir, $hook), @ARGV;
+ }
+}