Make standalone listen only on localhost and use local version of common.css
[build-farm.git] / cvslog.pl
1 #!/usr/bin/perl -w
2 #
3 # Extract information about recent CVS commits
4 #
5 # tridge@samba.org, April 2001
6
7 use strict;
8 use util;
9 use POSIX;
10 use Data::Dumper;
11 use File::stat;
12 use Date::Parse;
13
14 ####################################
15 # parse a CVS date 
16 sub cvs_parse_date($)
17 {
18     my $s = shift;
19
20     if (! ($s =~ /@/)) {
21       return str2time($s);
22     }
23
24     if ($s =~ /(.*) (.*) ([0-9]+), ([0-9]+) @ ([0-9]+):([0-9]+)/) {
25         my $day = $1;
26         my $month = $2;
27         my $mday = $3;
28         my $year = $4;
29         my $hour = $5;
30         my $min = $6;
31         my (%months) = ('January' => 1, 'February' => 2, 'March' => 3, 'April' => 4,
32                         'May' => 5, 'June' => 6, 'July' => 7, 'August' => 8, 'September' => 9,
33                         'October' => 10, 'November' => 11, 'December' => 12);
34         my $t = mktime(0, $min, $hour, $mday, $months{$month}-1, $year-1900);
35         return $t;
36     }
37
38     print "ERROR: bad date format $s\n";
39     return 0;
40 }
41
42
43 ####################################
44 # push an entry onto the array
45
46 # FIXME: This incorrectly handles multiple commits with the same log
47 # message.  The cvslog output only shows the revisions for the last
48 # commit, but actually we want to either not coalesce, or show the
49 # overall delta.
50
51 sub push_entry($$$$$)
52 {
53   my $entry = shift;
54   my $log = shift;
55   my $days = shift;
56   my $tree = shift;
57   my $tag = shift;
58   my $lastentry = $log->[$#{$log}];
59
60   if ($lastentry->{DATE} && $lastentry->{AUTHOR} &&
61       ($lastentry->{DATE} > $entry->{DATE}-600) &&
62       ($lastentry->{AUTHOR} eq $entry->{AUTHOR}) &&
63       ((!$lastentry->{TAG} && !$entry->{TAG}) ||
64        ($lastentry->{TAG} eq $entry->{TAG})) &&
65       ((!$lastentry->{MESSAGE} && !$entry->{MESSAGE}) ||
66        ($lastentry->{MESSAGE} eq $entry->{MESSAGE}))) {
67
68     if (exists $lastentry->{FILES}) {
69       $lastentry->{FILES} .= " $entry->{FILES}";
70     } else {
71       $lastentry->{FILES} = $entry->{FILES};
72     }
73
74     if (exists $lastentry->{ADDED}) {
75       $lastentry->{ADDED} .= " $entry->{ADDED}";
76     } else {
77       $lastentry->{ADDED} = $entry->{ADDED};
78     }
79
80     if (exists $lastentry->{REMOVED}) {
81       $lastentry->{REMOVED} .= " $entry->{REMOVED}";
82     } else {
83       $lastentry->{REMOVED} = $entry->{REMOVED};
84     }
85
86     if (exists $lastentry->{REVISIONS}) {
87             $lastentry->{REVISIONS} = {%{$lastentry->{REVISIONS}},%{$entry->{REVISIONS}}};
88     } else {
89             $lastentry->{REVISIONS} = $entry->{REVISIONS};
90     }
91   } else {
92     if (($entry->{DATE} > time() - $days*24*60*60) &&
93         ((!$entry->{TAG} && !$tag) || 
94          ($entry->{TAG} eq $tag)) &&
95         ($entry->{TREE} eq $tree)) {
96       push(@{$log}, $entry);
97     }
98   }
99   return $log;
100 }
101
102 ####################################
103 # return an array of logfile entries given a cvs log file. 
104 # Only return entries newer than $days old
105 sub cvs_parse($$$$)
106 {
107     my $file = shift;
108     my $days = shift;
109     my $tree = shift;
110     my $tag = shift;
111     my $log;
112     my $entry;
113
114     open(FILE, "< $file");
115     while (<FILE>) {
116         my $line = $_;
117
118         # ignore separator lines
119         if ($line =~ /^[*]+/) { next; }
120
121         if ($line =~ /^Date:\s*(.*)/) {
122             if ($entry->{DATE}) {
123               $log = push_entry($entry, $log, $days, $tree, $tag);
124             }
125             $entry = {};
126             $entry->{DATE} = cvs_parse_date($1);
127             $entry->{DIR} = "";
128             next;
129         }
130
131         if ($line =~ /^Author:\s*(.*)/) {
132             $entry->{AUTHOR} = $1;
133             next;
134         }
135
136         if ($line =~ /^Update of (.*)/) {
137             $entry->{TREE} = $1;
138             if ($entry->{TREE} =~ /\/(data|home)\/cvs\/([^\/]*)\/?(.*)/) {
139                 $entry->{TREE} = $2;
140                 $entry->{DIR} = $3;
141                 if ($entry->{DIR}) { $entry->{DIR} .= "/"; }
142             } elsif ($entry->{TREE} =~ /\/home\/tridge\/cvstest\/([^\/]*)\/?(.*)/) {
143                 $entry->{TREE} = $1;
144                 $entry->{DIR} = $2;
145                 if ($entry->{DIR}) { $entry->{DIR} .= "/"; }
146             } else {
147                 print "badly formed tree $entry->{TREE}\n";
148             }
149             if (! $entry->{DIR}) { $entry->{DIR} = ""; }
150             next;
151         }
152
153         if ($line =~ /^Modified Files:/) {
154             while (<FILE>) {
155                 $line = $_;
156                 if ($line =~ /^[*A-Z]/) { last; }
157
158                 if ($line =~ /^\s*Tag: (.*)/) {
159                     $entry->{TAG} = $1;
160                     next;
161                 }
162                 
163                 while ($line =~ /\s*([^\s]+)(.*)/) {
164                   if ($entry->{FILES}) { 
165                       $entry->{FILES} .= " $entry->{DIR}$1";
166                     } else {
167                         $entry->{FILES} = "$entry->{DIR}$1";
168                     }
169                   $line = $2;
170                 }
171             }
172         }
173
174         if ($line =~ /^Added Files:/) {
175             while (<FILE>) {
176                 $line = $_;
177                 if ($line =~ /^[*A-Z]/) { last; }
178
179                 if ($line =~ /^\s*Tag: (.*)/) {
180                     $entry->{TAG} = $1;
181                     next;
182                 }
183                 
184                 while ($line =~ /\s*([^\s]+)(.*)/) {
185                     if ($entry->{ADDED}) { 
186                         $entry->{ADDED} .= " $entry->{DIR}$1";
187                     } else {
188                         $entry->{ADDED} = "$entry->{DIR}$1";
189                     }
190                     $line = $2;
191                 }
192             }
193         }
194
195         if ($line =~ /^Removed Files:/) {
196             while (<FILE>) {
197                 $line = $_;
198                 if ($line =~ /^[*A-Z]/) { last; }
199
200                 if ($line =~ /^\s*Tag: (.*)/) {
201                     $entry->{TAG} = $1;
202                     next;
203                 }
204                 
205                 while ($line =~ /\s*([^\s]+)(.*)/) {
206                     if ($entry->{REMOVED}) { 
207                         $entry->{REMOVED} .= " $entry->{DIR}$1";
208                     } else {
209                         $entry->{REMOVED} = "$entry->{DIR}$1";
210                     }
211                     $line = $2;
212                 }
213             }
214         }
215
216         if ($line =~ /^Log Message:/) {
217             while (<FILE>) {
218                 $line = $_;
219                 if ($line eq "****************************************\n") { last; }
220                 if ($line =~ /^Revisions:/) { last; }
221                 $entry->{MESSAGE} .= $line;
222             }
223         }
224
225         if ($line =~ /^Revisions:/) {
226             while (<FILE>) {
227                 $line = $_;
228                 if ($line =~ /^[*]/) { last; }
229                 if ($line =~ /^\s*http/) { next; }
230                 if ($line =~ /^\s*(.*?)\s*(NONE|[0-9][0-9.]*) => (NONE|[0-9][0-9.]*)/) { 
231                   my $file = "$entry->{DIR}$1";
232                   my $rev1 = $2;
233                   my $rev2 = $3;
234                   $entry->{REVISIONS}->{$file}->{REV1} = $rev1;
235                   $entry->{REVISIONS}->{$file}->{REV2} = $rev2;
236                 }
237             }
238         }
239     }
240
241     if ($entry->{DATE}) {
242       $log = push_entry($entry, $log, $days, $tree, $tag);
243     }
244
245     close(FILE);
246
247     # cleanup the messages
248     for (my $line=0; $line <= $#{$log}; $line++) {
249         $entry = $log->[$line];
250         if ($entry->{MESSAGE}) {
251             while (chomp($entry->{MESSAGE})) { }
252         }
253     }
254     
255     return $log;
256 }
257
258
259 ######################################
260 # main program
261 if ($#ARGV < 4) {
262     print "
263 Usage: cvslog.pl <FILE> <DAYS> <TREE> <TAG> <DEST>
264
265 Opens CVS log file \$FILE and extracts all commit info
266 from the last \$DAYS days for \$TREE with tag \$TAG. The result
267 is stored in \$DEST in a format that the build farm web scripts
268 can easily read, aggregating the messages from a
269 multiple-directory commit into a single entry.
270 ";
271     exit(1);
272 }
273
274 my $file = $ARGV[0];
275 my $days = $ARGV[1];
276 my $tree = $ARGV[2];
277 my $tag =  $ARGV[3];
278 my $dest = $ARGV[4];
279
280 my $log = cvs_parse($ARGV[0], $days, $tree, $tag);
281
282 util::SaveStructure($dest, $log);