make pre-receive repo-specific hooks bail on non-zero exit
[gitolite.git] / src / triggers / repo-specific-hooks
bloba4c86cccbf52558999f4ec9cc9a2d1dda9e543a0
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
5 # setup repo-specific hooks
7 use lib $ENV{GL_LIBDIR};
8 use Gitolite::Rc;
9 use Gitolite::Common;
11 _die "repo-specific-hooks: LOCAL_CODE not defined in rc" unless $rc{LOCAL_CODE};
12 _die "repo-specific-hooks: '$rc{LOCAL_CODE}/hooks/repo-specific' does not exist or is not a directory" unless -d "$rc{LOCAL_CODE}/hooks/repo-specific";
14 _chdir( $ENV{GL_REPO_BASE} );
16 if ($ARGV[0] eq 'POST_CREATE') {
17 # just the repo given in arg-2
18 @ARGV = ("gitolite git-config -ev -r $ARGV[1] gitolite-options\\.hook\\. |");
19 } else {
20 # POST_COMPILE, all repos
21 @ARGV = ("gitolite list-phy-repos | gitolite git-config -ev -r % gitolite-options\\.hook\\. |");
24 my $driver = $rc{MULTI_HOOK_DRIVER} || "$rc{LOCAL_CODE}/hooks/multi-hook-driver";
25 # Hook Driver
27 local $/ = undef;
28 my $hook_text = <DATA>;
29 _print( $driver, $hook_text );
30 chmod 0755, $driver;
33 my %repo_hooks;
34 while (<>) {
35 chomp;
36 my ( $repo, $hook, $codes ) = split /\t/, $_;
37 $codes ||= '';
39 # get the hook name
40 $hook =~ s/^gitolite-options\.hook\.//;
41 $hook =~ s/\..*//;
43 my @codes = split /\s+/, $codes;
44 next unless @codes;
46 # this is a special case
47 if ( $repo eq 'gitolite-admin' and $hook eq 'post-update' ) {
48 _warn "repo-specific-hooks: ignoring attempts to set post-update hook for the admin repo";
49 next;
52 unless ( $hook =~ /^(pre-receive|post-receive|post-update|pre-auto-gc)$/ ) {
53 _warn "repo-specific-hooks: '$hook' is not allowed, ignoring";
54 _warn " (only pre-receive, post-receive, post-update, and pre-auto-gc are allowed)";
55 next;
58 push @{ $repo_hooks{$repo}{$hook} }, @codes if @codes;
61 for my $repo (keys %repo_hooks) {
62 for my $hook (keys %{ $repo_hooks{$repo} }) {
63 my @codes = @{ $repo_hooks{$repo}{$hook} };
65 my $dst = "$repo.git/hooks/$hook";
66 unlink( glob("$dst.*") );
68 my $counter = "h00";
69 foreach my $code (@codes) {
70 if ( $code =~ m(^/|\.\.) ) {
71 _warn "repo-specific-hooks: double dot or leading slash not allowed in '$code'";
72 next;
75 my $src = $rc{LOCAL_CODE} . "/hooks/repo-specific/$code";
77 # if $code has slashes in it, flatten it for use in $dst, to avoid
78 # having to re-create those intermediate sub-directories
79 $code =~ s(/)(_)g;
80 my $dst = "$repo.git/hooks/$hook.$counter-$code";
82 unless ( -x $src ) {
83 _warn "repo-specific-hooks: '$src' doesn't exist or is not executable";
84 next;
86 unlink $dst;
87 symlink $src, $dst or _warn "could not symlink '$src' to '$dst'";
88 $counter++;
90 # no sanity checks for multiple overwrites of the same hook
93 unlink $dst;
94 symlink $driver, $dst or die "could not symlink '$driver' to '$dst'";
98 __DATA__
99 #!/bin/sh
101 # Determine what input the hook needs
102 # post-update takes args, pre/post-receive take stdin
103 type=args
104 stdin=''
105 [ $0 != hooks/post-update ] && {
106 type=stdin
107 stdin=`cat`
110 for h in $0.*; do
111 [ -x $h ] || continue
112 if [ $type = args ]
113 then
114 $h $@ || { [ $0 = hooks/pre-receive ] && exit 1; }
115 else
116 echo "$stdin" | $h || { [ $0 = hooks/pre-receive ] && exit 1; }
118 done