Merge remote-tracking branch 'origin/master' into HEAD
[platform/upstream/gst-common.git] / hooks / post-receive.hook
1 #!/usr/bin/perl -w
2 #
3 # Copyright 2005 Alexandre Julliard
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as
7 # published by the Free Software Foundation; either version 2 of
8 # the License, or (at your option) any later version.
9
10 use strict;
11 use open ':utf8';
12 use Encode 'encode';
13 use Cwd 'realpath';
14
15 binmode STDIN, ':utf8';
16 binmode STDOUT, ':utf8';
17
18 sub git_config($);
19 sub get_repos_name();
20
21 # some parameters you may want to change
22
23 # set this to something that takes "-s"
24 my $mailer = "/usr/bin/mail";
25
26 # debug mode
27 my $debug = 0;
28
29 # configuration parameters
30
31 # base URL of the gitweb repository browser
32 my $gitweb_url = "http://cgit.freedesktop.org/gstreamer";
33
34 # default repository name
35 my $repos_name = get_repos_name();
36
37 # max size of diffs in bytes
38 my $max_diff_size = 10000;
39
40 # address for mail notices
41 my $commitlist_address = 'gstreamer-commits@lists.freedesktop.org';
42 #my $commitlist_address = "bilboed";
43
44 # max number of individual notices before falling back to a single global notice
45 my $max_individual_notices = 100;
46
47 # format an integer date + timezone as string
48 # algorithm taken from git's date.c
49 sub format_date($$)
50 {
51     my ($time,$tz) = @_;
52
53     if ($tz < 0)
54     {
55         my $minutes = (-$tz / 100) * 60 + (-$tz % 100);
56         $time -= $minutes * 60;
57     }
58     else
59     {
60         my $minutes = ($tz / 100) * 60 + ($tz % 100);
61         $time += $minutes * 60;
62     }
63     return gmtime($time) . sprintf " %+05d", $tz;
64 }
65
66 # fetch a parameter from the git config file
67 sub git_config($)
68 {
69     my ($param) = @_;
70
71     open CONFIG, "-|" or exec "git", "config", $param;
72     my $ret = <CONFIG>;
73     chomp $ret if $ret;
74     close CONFIG or $ret = undef;
75     return $ret;
76 }
77
78 # send an email notification
79 sub mail_notification($$$@)
80 {
81     my ($name, $subject, $content_type, @text) = @_;
82     $subject = encode("MIME-Q",$subject);
83     if ($debug)
84     {
85         print "---------------------\n";
86         print "To: $name\n";
87         print "Subject: $subject\n";
88         print "Content-Type: $content_type\n";
89         print "\n", join("\n", @text), "\n";
90     }
91     else
92     {
93         my $pid = open MAIL, "|-";
94         return unless defined $pid;
95         if (!$pid)
96         {
97             exec $mailer, "-s", $subject, $name, or die "Cannot exec $mailer";
98         }
99         print MAIL join("\n", @text), "\n";
100         close MAIL;
101     }
102 }
103
104 # get the default repository name
105 sub get_repos_name()
106 {
107     my $dir = `git rev-parse --git-dir`;
108     chomp $dir;
109     my $repos = realpath($dir);
110     $repos =~ s/(.*?)((\.git\/)?\.git)$/$1/;
111     $repos =~ s/(.*)\/([^\/]+)\/?$/$2/;
112     return $repos;
113 }
114
115 # extract the information from a commit or tag object and return a hash containing the various fields
116 sub get_object_info($)
117 {
118     my $obj = shift;
119     my %info = ();
120     my @log = ();
121     my $do_log = 0;
122
123     open TYPE, "-|" or exec "git", "cat-file", "-t", $obj or die "cannot run git-cat-file";
124     my $type = <TYPE>;
125     chomp $type;
126     close TYPE;
127
128     open OBJ, "-|" or exec "git", "cat-file", $type, $obj or die "cannot run git-cat-file";
129     while (<OBJ>)
130     {
131         chomp;
132         if ($do_log)
133         {
134             last if /^-----BEGIN PGP SIGNATURE-----/;
135             push @log, $_;
136         }
137         elsif (/^(author|committer|tagger) ((.*)(<.*>)) (\d+) ([+-]\d+)$/)
138         {
139             $info{$1} = $2;
140             $info{$1 . "_name"} = $3;
141             $info{$1 . "_email"} = $4;
142             $info{$1 . "_date"} = $5;
143             $info{$1 . "_tz"} = $6;
144         }
145         elsif (/^tag (.*)$/)
146         {
147             $info{"tag"} = $1;
148         }
149         elsif (/^$/) { $do_log = 1; }
150     }
151     close OBJ;
152
153     $info{"type"} = $type;
154     $info{"log"} = \@log;
155     return %info;
156 }
157
158 # send a commit notice to a mailing list
159 sub send_commit_notice($$)
160 {
161     my ($ref,$obj) = @_;
162     my %info = get_object_info($obj);
163     my @notice = ();
164     my $subject;
165
166     printf "sending e-mail for $obj\n";
167
168     # TODO normal tags are not identified
169     if ($info{"type"} eq "tag")
170     {
171         push @notice,
172         "Module: $repos_name",
173         "Branch: $ref",
174         "Tag:    $obj",
175         $gitweb_url ? "URL:    $gitweb_url/tag/?id=$obj\n" : "",
176         "Tagger: " . $info{"tagger"},
177         "Date:   " . format_date($info{"tagger_date"},$info{"tagger_tz"}),
178         "",
179         join "\n", @{$info{"log"}};
180         $subject = "Tag " . $info{"tag"} . ": " . ${$info{"log"}}[0];
181     }
182     else
183     {
184         push @notice,
185         "Module: $repos_name",
186         "Branch: $ref",
187         "Commit: $obj",
188         $gitweb_url ? "URL:    $gitweb_url/commit/?id=$obj\n" : "",
189         "Author: " . $info{"author"},
190         "Date:   " . format_date($info{"author_date"},$info{"author_tz"}),
191         "",
192         join "\n", @{$info{"log"}},
193         "",
194         "---",
195         "";
196
197         open STAT, "-|" or exec "git", "diff-tree", "--stat", "-M", "--no-commit-id", $obj or die "cannot exec git-diff-tree";
198         push @notice, join("", <STAT>);
199         close STAT;
200
201         open DIFF, "-|" or exec "git", "diff-tree", "-p", "-M", "--no-commit-id", $obj or die "cannot exec git-diff-tree";
202         my $diff = join( "", <DIFF> );
203         close DIFF;
204
205         if (($max_diff_size == -1) || (length($diff) < $max_diff_size))
206         {
207             push @notice, $diff;
208         }
209         else
210         {
211             push @notice, "Diff:   $gitweb_url/diff/?id=$obj" if $gitweb_url;
212         }
213
214         if ($ref eq 'master')
215         {
216             $subject = $repos_name . ": " . ${$info{"log"}}[0];
217         }
218         else
219         {
220             $subject = "[$ref] " . $repos_name . ": " . ${$info{"log"}}[0];
221         }
222     }
223
224     mail_notification($commitlist_address, $subject, "text/plain; charset=UTF-8", @notice);
225 }
226
227 # send a global commit notice when there are too many commits for individual mails
228 sub send_global_notice($$$)
229 {
230     my ($ref, $old_sha1, $new_sha1) = @_;
231     my @notice = ();
232
233     open LIST, "-|" or exec "git", "rev-list", "--pretty", "^$old_sha1", "$new_sha1" or die "cannot exec git-rev-list";
234     while (<LIST>)
235     {
236         chomp;
237         s/^commit /URL:    $gitweb_url\/commit\/?id=/ if $gitweb_url;
238         push @notice, $_;
239     }
240     close LIST;
241
242     mail_notification($commitlist_address, "New commits on branch $ref", "text/plain; charset=UTF-8", @notice);
243 }
244
245 # send all the notices
246 sub send_all_notices($$$)
247 {
248     my ($old_sha1, $new_sha1, $ref) = @_;
249
250     $ref =~ s/^refs\/heads\///;
251
252     if ($old_sha1 eq '0' x 40)  # new ref
253     {
254         send_commit_notice( $ref, $new_sha1 ) if $commitlist_address;
255         return;
256     }
257
258     my @commits = ();
259
260     open LIST, "-|" or exec "git", "rev-list", "--topo-order", "^$old_sha1", "$new_sha1" or die "cannot exec git-rev-list";
261     while (<LIST>)
262     {
263         chomp;
264         die "invalid commit $_" unless /^[0-9a-f]{40}$/;
265         unshift @commits, $_;
266     }
267     close LIST;
268
269     if (@commits > $max_individual_notices)
270     {
271         send_global_notice( $ref, $old_sha1, $new_sha1 ) if $commitlist_address;
272         return;
273     }
274
275     foreach my $commit (@commits)
276     {
277         send_commit_notice( $ref, $commit ) if $commitlist_address;
278     }
279 }
280
281 # append repository path to URL
282 $gitweb_url .= "/$repos_name" if $gitweb_url;
283
284 while (<>)
285 {
286     chomp;
287     if (/^([0-9a-f]{40}) ([0-9a-f]{40}) (.*)$/) { send_all_notices( $1, $2, $3 ); }
288 }
289
290 exit 0;