Add stage and total run times to log page.
[buildfarm-server.git] / cgi-bin / show_log.pl
1 #!/usr/bin/perl
2
3 =comment
4
5 Copyright (c) 2003-2010, Andrew Dunstan
6
7 See accompanying License file for license details
8
9 =cut 
10
11 use strict;
12 use DBI;
13 use Template;
14 use CGI;
15
16 use vars qw($dbhost $dbname $dbuser $dbpass $dbport 
17                         $template_dir @log_file_names $local_git_clone);
18
19 require "$ENV{BFConfDir}/BuildFarmWeb.pl";
20
21 my $template_opts = { INCLUDE_PATH => $template_dir, EVAL_PERL => 1};
22 my $template = new Template($template_opts);
23
24 die "no dbname" unless $dbname;
25 die "no dbuser" unless $dbuser;
26
27 my $dsn="dbi:Pg:dbname=$dbname";
28 $dsn .= ";host=$dbhost" if $dbhost;
29 $dsn .= ";port=$dbport" if $dbport;
30
31 my $query = new CGI;
32
33 my $system = $query->param('nm'); $system =~ s/[^a-zA-Z0-9_ -]//g;
34 my $logdate = $query->param('dt'); $logdate =~ s/[^a-zA-Z0-9_ :-]//g;
35
36 my $log = "";
37 my $conf = "";
38 my ($stage,$changed_this_run,$changed_since_success,$sysinfo,$branch,$scmurl);
39 my $scm;
40 my ($git_head_ref, $last_build_git_ref, $last_success_git_ref);
41 my ($stage_times, $run_time);
42
43 use vars qw($info_row);
44
45 if ($system && $logdate)
46 {
47
48         my $db = DBI->connect($dsn,$dbuser,$dbpass,{pg_expand_array => 0});
49
50         die $DBI::errstr unless $db;
51
52         my $statement = q{
53
54                 select log,conf_sum,stage, changed_this_run, changed_since_success,
55                 branch, log_archive_filenames, scm, scmurl, git_head_ref
56                 from build_status
57                 where sysname = ? and snapshot = ?
58
59         };
60         my $last_build_statement = q{
61                 select distinct on (sysname) sysname, snapshot, stage, git_head_ref 
62         from build_status 
63         where sysname = ? and branch = ? and snapshot < ? 
64         order by sysname, snapshot desc limit 1
65         };
66         my $last_success_statement = q{
67                 select distinct on (sysname) sysname, snapshot, git_head_ref 
68         from build_status 
69         where sysname = ? and branch = ? and snapshot < ? and stage = 'OK' 
70         order by sysname, snapshot desc limit 1
71         };
72         my $sth=$db->prepare($statement);
73         $sth->execute($system,$logdate);
74         my $row=$sth->fetchrow_arrayref;
75         $branch = $row->[5];
76         $git_head_ref = $row->[9];
77         $sth->finish;
78         my $last_build_row;
79         if ($git_head_ref)
80         {
81                 $last_build_row = 
82                   $db->selectrow_hashref($last_build_statement,undef,
83                                                                  $system,$branch,$logdate);
84                 $last_build_git_ref = $last_build_row->{git_head_ref}
85                   if $last_build_row;
86                 
87         }
88         my $last_success_row;
89         if (ref $last_build_row && $last_build_row->{stage} ne 'OK')
90         {
91                 $last_success_row =
92                   $db->selectrow_hashref($last_success_statement,undef,
93                                                                  $system,$branch,$logdate);
94                 $last_success_git_ref = $last_success_row->{git_head_ref}
95                   if $last_success_row;
96         }
97         $log=$row->[0];
98         $conf=$row->[1] || "not recorded" ;
99         $stage=$row->[2] || "unknown";
100         $changed_this_run = $row->[3];
101         $changed_since_success = $row->[4];
102         my $log_file_names = $row->[6];
103         $scm = $row->[7];
104         $scm ||= 'cvs'; # legacy scripts
105         $scmurl = $row->[8];
106         $log_file_names =~ s/^\{(.*)\}$/$1/;
107         @log_file_names=split(',',$log_file_names)
108             if $log_file_names;
109
110         $statement = q{
111
112           select operating_system, os_version, 
113                  compiler, compiler_version, 
114                  architecture,
115                  replace(owner_email,E'\@',' [ a t ] ') as owner_email,
116                  sys_notes_ts::date AS sys_notes_date, sys_notes
117           from buildsystems 
118           where status = 'approved'
119                 and name = ?
120
121         };
122         $sth=$db->prepare($statement);
123         $sth->execute($system);
124         $info_row=$sth->fetchrow_hashref;
125
126         my $latest_personality = $db->selectrow_arrayref(q{
127             select os_version, compiler_version
128             from personality
129             where effective_date < ?
130             and name = ?
131             order by effective_date desc limit 1
132         }, undef, $logdate, $system);
133         if ($latest_personality)
134         {
135             $info_row->{os_version} = $latest_personality->[0];
136             $info_row->{compiler_version} = $latest_personality->[1];
137         }
138         $sth->finish;
139         my $stage_times_query = q{
140            select log_stage, stage_duration
141            from build_status_log
142            where sysname = ? and snapshot = ?
143         };
144         $stage_times = 
145             $db->selectall_hashref($stage_times_query,'log_stage',undef,
146                                    $system,$logdate);
147         $stage_times_query = q{
148            select sum(stage_duration)
149            from build_status_log
150            where sysname = ? and snapshot = ?
151         };
152         ($run_time) = $db->selectrow_array($stage_times_query,undef,
153                                    $system,$logdate);
154         $db->disconnect;
155 }
156
157 my ($changed_this_run_logs, $changed_since_success_logs);
158 ($changed_this_run, $changed_this_run_logs) = 
159   process_changed($changed_this_run,
160                                   $git_head_ref,$last_build_git_ref);
161 ($changed_since_success, $changed_since_success_logs) = 
162   process_changed($changed_since_success,
163                                   $last_build_git_ref,$last_success_git_ref);
164
165 $conf =~ s/\@/ [ a t ] /g;
166
167 print "Content-Type: text/html\n\n";
168
169 $template->process('log.tt',
170         {
171                 scm => $scm,
172                 scmurl => $scmurl,
173                 system => $system,
174                 branch => $branch,
175                 stage => $stage,
176                 stage_times => $stage_times,
177                 run_time => $run_time,
178                 urldt => $logdate,
179                 log_file_names => \@log_file_names,
180                 conf => $conf,
181                 log => $log,
182                 changed_this_run => $changed_this_run,
183                 changed_since_success => $changed_since_success,
184                 changed_this_run_logs => $changed_this_run_logs,
185                 changed_since_success_logs => $changed_since_success_logs,
186                 info_row => $info_row,
187             git_head_ref => $git_head_ref,
188             last_build_git_ref => $last_build_git_ref,
189             last_success_git_ref => $last_success_git_ref,
190
191         });
192
193 exit;
194
195 ##########################################################
196
197 sub process_changed
198 {
199
200         my $chgd = shift;
201         my $git_to = shift;
202         my $git_from = shift;
203
204     my @lines = split(/!/,$chgd);
205     my @changed_rows;
206         my %commits;
207         my @commit_logs;
208         my $gitcmd = "TZ=UTC GIT_DIR=$local_git_clone git log --date=local";
209     foreach (@lines)
210     {
211                 next if ($scm eq 'cvs' and ! m!^(pgsql|master|REL\d_\d_STABLE)/!);
212                 push(@changed_rows,[$1,$3]) if (m!(^\S+)(\s+)(\S+)!);
213                 $commits{$3} = 1 if $scm eq 'git';
214     }
215         if ($git_from && $git_to)
216         {
217                 my $format = 'commit %h %cd UTC%w(160,2,2)%s';
218                 my $gitlog = `$gitcmd --pretty=format:"$format" $git_from..$git_to 2>&1`;
219                 @commit_logs = split(/(?=^commit)/m,$gitlog)
220         }
221         else
222         {
223                 # normally we expect to have the git refs. this is just a fallback.
224                 my $format = 'epoch: %at%ncommit %h %cd UTC%w(160,2,2)%s';
225                 foreach my $commit ( keys %commits )
226                 {
227                         my $commitlog = 
228                           `$gitcmd -n 1 --pretty=format:"$format" $commit 2>&1`;
229                         push(@commit_logs,$commitlog);
230                 }
231                 @commit_logs = reverse (sort @commit_logs);
232                 s/epoch:.*\n// for (@commit_logs);
233         }
234                 return (\@changed_rows,\@commit_logs);
235 }
236