~ubuntu-branches/ubuntu/utopic/gitolite3/utopic-proposed

« back to all changes in this revision

Viewing changes to src/lib/Gitolite/Hooks/Update.pm

  • Committer: Package Import Robot
  • Author(s): David Bremner
  • Date: 2013-05-18 17:59:21 UTC
  • Revision ID: package-import@ubuntu.com-20130518175921-ac4xe6vd0jtxvjot
Tags: upstream-3.5.1+4
ImportĀ upstreamĀ versionĀ 3.5.1+4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package Gitolite::Hooks::Update;
 
2
 
 
3
# everything to do with the update hook
 
4
# ----------------------------------------------------------------------
 
5
 
 
6
@EXPORT = qw(
 
7
  update
 
8
  update_hook
 
9
);
 
10
 
 
11
use Exporter 'import';
 
12
 
 
13
use Gitolite::Rc;
 
14
use Gitolite::Common;
 
15
use Gitolite::Conf::Load;
 
16
 
 
17
use strict;
 
18
use warnings;
 
19
 
 
20
# ----------------------------------------------------------------------
 
21
 
 
22
sub update {
 
23
    # this is the *real* update hook for gitolite
 
24
 
 
25
    bypass() if $ENV{GL_BYPASS_ACCESS_CHECKS};
 
26
 
 
27
    my ( $ref, $oldsha, $newsha, $oldtree, $newtree, $aa ) = args(@ARGV);
 
28
 
 
29
    trace( 1, 'update', $ENV{GL_REPO}, $ENV{GL_USER}, $aa, @ARGV );
 
30
 
 
31
    my $ret = access( $ENV{GL_REPO}, $ENV{GL_USER}, $aa, $ref );
 
32
    trigger( 'ACCESS_2', $ENV{GL_REPO}, $ENV{GL_USER}, $aa, $ref, $ret, $oldsha, $newsha );
 
33
    _die $ret if $ret =~ /DENIED/;
 
34
 
 
35
    check_vrefs( $ref, $oldsha, $newsha, $oldtree, $newtree, $aa );
 
36
 
 
37
    trace( 1, "-> $ret" );
 
38
    gl_log( 'update', $ENV{GL_REPO}, $ENV{GL_USER}, $aa, @ARGV );
 
39
    exit 0;
 
40
}
 
41
 
 
42
sub bypass {
 
43
    require Cwd;
 
44
    Cwd->import;
 
45
    gl_log( 'update', getcwd(), '(' . ( $ENV{USER} || '?' ) . ')', 'bypass', @ARGV );
 
46
    exit 0;
 
47
}
 
48
 
 
49
sub check_vrefs {
 
50
    my ( $ref, $oldsha, $newsha, $oldtree, $newtree, $aa ) = @_;
 
51
    my $name_seen = 0;
 
52
    my $n_vrefs   = 0;
 
53
    for my $vref ( vrefs( $ENV{GL_REPO}, $ENV{GL_USER} ) ) {
 
54
        $n_vrefs++;
 
55
        if ( $vref =~ m(^VREF/NAME/) ) {
 
56
            # this one is special; we process it right here, and only once
 
57
            next if $name_seen++;
 
58
 
 
59
            for my $ref ( map { chomp; s(^)(VREF/NAME/); $_; } `git diff --name-only $oldtree $newtree` ) {
 
60
                check_vref( $aa, $ref );
 
61
            }
 
62
        } else {
 
63
            my ( $dummy, $pgm, @args ) = split '/', $vref;
 
64
            $pgm = _which("VREF/$pgm", 'x');
 
65
            $pgm or _die "'$vref': helper program missing or unexecutable";
 
66
 
 
67
            open( my $fh, "-|", $pgm, @_, $vref, @args ) or _die "'$vref': can't spawn helper program: $!";
 
68
            while (<$fh>) {
 
69
                # print non-vref lines and skip processing (for example,
 
70
                # normal STDOUT by a normal update hook)
 
71
                unless (m(^VREF/)) {
 
72
                    print;
 
73
                    next;
 
74
                }
 
75
                my ( $ref, $deny_message ) = split( ' ', $_, 2 );
 
76
                check_vref( $aa, $ref, $deny_message );
 
77
            }
 
78
            close($fh) or _die $!
 
79
              ? "Error closing sort pipe: $!"
 
80
              : "$vref: helper program exit status $?";
 
81
        }
 
82
    }
 
83
    return $n_vrefs;
 
84
}
 
85
 
 
86
sub check_vref {
 
87
    my ( $aa, $ref, $deny_message ) = @_;
 
88
 
 
89
    my $ret = access( $ENV{GL_REPO}, $ENV{GL_USER}, $aa, $ref );
 
90
    trace( 2, "access($ENV{GL_REPO}, $ENV{GL_USER}, $aa, $ref)", "-> $ret" );
 
91
    trigger( 'ACCESS_2', $ENV{GL_REPO}, $ENV{GL_USER}, $aa, $ref, $ret );
 
92
    _die "$ret" . ( $deny_message ? "\n$deny_message" : '' )
 
93
      if $ret =~ /DENIED/ and $ret !~ /by fallthru/;
 
94
    trace( 2, "remember, fallthru is success here!" ) if $ret =~ /by fallthru/;
 
95
}
 
96
 
 
97
{
 
98
    my $text = '';
 
99
 
 
100
    sub update_hook {
 
101
        if ( not $text ) {
 
102
            local $/ = undef;
 
103
            $text = <DATA>;
 
104
        }
 
105
        return $text;
 
106
    }
 
107
}
 
108
 
 
109
# ----------------------------------------------------------------------
 
110
 
 
111
sub args {
 
112
    my ( $ref, $oldsha, $newsha ) = @_;
 
113
    my ( $oldtree, $newtree, $aa );
 
114
 
 
115
    # this is special to git -- the hash of an empty tree
 
116
    my $empty = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
 
117
    $oldtree = $oldsha eq '0' x 40 ? $empty : $oldsha;
 
118
    $newtree = $newsha eq '0' x 40 ? $empty : $newsha;
 
119
 
 
120
    my $merge_base = '0' x 40;
 
121
    # for branch create or delete, merge_base stays at '0'x40
 
122
    chomp( $merge_base = `git merge-base $oldsha $newsha` )
 
123
      unless $oldsha eq '0' x 40
 
124
          or $newsha eq '0' x 40;
 
125
 
 
126
    $aa = 'W';
 
127
    # tag rewrite
 
128
    $aa = '+' if $ref =~ m(refs/tags/) and $oldsha ne ( '0' x 40 );
 
129
    # non-ff push to ref (including ref delete)
 
130
    $aa = '+' if $oldsha ne $merge_base;
 
131
 
 
132
    $aa = 'D' if ( option( $ENV{GL_REPO}, 'DELETE_IS_D' ) ) and $newsha eq '0' x 40;
 
133
    $aa = 'C' if ( option( $ENV{GL_REPO}, 'CREATE_IS_C' ) ) and $oldsha eq '0' x 40;
 
134
 
 
135
    # and now "M" commits.  All the other accesses (W, +, C, D) were mutually
 
136
    # exclusive in some sense.  Sure a W could be a C or a + could be a D but
 
137
    # that's by design.  A merge commit, however, could still be any of the
 
138
    # others (except a "D").
 
139
 
 
140
    # so we have to *append* 'M' to $aa (if the repo has MERGE_CHECK in
 
141
    # effect and this push contains a merge inside)
 
142
 
 
143
    if ( option( $ENV{GL_REPO}, 'MERGE_CHECK' ) ) {
 
144
        if ( $oldsha eq '0' x 40 or $newsha eq '0' x 40 ) {
 
145
            _warn "ref create/delete ignored for purposes of merge-check\n";
 
146
        } else {
 
147
            $aa .= 'M' if `git rev-list -n 1 --merges $oldsha..$newsha` =~ /./;
 
148
        }
 
149
    }
 
150
 
 
151
    return ( $ref, $oldsha, $newsha, $oldtree, $newtree, $aa );
 
152
}
 
153
 
 
154
1;
 
155
 
 
156
__DATA__
 
157
#!/usr/bin/perl
 
158
 
 
159
use strict;
 
160
use warnings;
 
161
 
 
162
use lib $ENV{GL_LIBDIR};
 
163
use Gitolite::Hooks::Update;
 
164
 
 
165
# gitolite update hook
 
166
# ----------------------------------------------------------------------
 
167
 
 
168
update();               # is not expected to return
 
169
exit 1;                 # so if it does, something is wrong