diff --git a/webtools/tinderbox/showbuilds.cgi b/webtools/tinderbox/showbuilds.cgi index 910dc04b621..ed1c77b6066 100755 --- a/webtools/tinderbox/showbuilds.cgi +++ b/webtools/tinderbox/showbuilds.cgi @@ -29,7 +29,7 @@ $default_root = '/cvsroot'; # Show 12 hours by default # -$nowdate = time; +$nowdate = time; if (not defined($maxdate = $form{maxdate})) { $maxdate = $nowdate; } @@ -57,16 +57,10 @@ else { $tree = $form{tree}; -# $rel_path is the relative path to webtools/tinderbox used for links. -# It changes to "../" if the page is generated statically, because then -# it is placed in tinderbox/$tree. -$rel_path = ''; - if (exists $form{rebuildguilty} or exists $form{showall}) { system ("./buildwho.pl -days 7 $tree > /dev/null"); undef $form{rebuildguilty}; } - &show_tree_selector, exit if $form{tree} eq ''; &do_quickparse, exit if $form{quickparse}; &do_express, exit if $form{express}; @@ -151,7 +145,7 @@ sub do_static { } sub do_tinderbox { - &tb_load_data; + &load_data; &print_page_head; &print_table_header; &print_table_body; @@ -229,152 +223,163 @@ sub print_page_head { } sub print_table_body { - for (my $tt=0; $tt < $time_count; $tt++) { + for (my $tt=1; $tt <= $time_count; $tt++) { last if $build_time_times->[$tt] < $mindate; print_table_row($tt); } } -sub print_bloat_delta { +sub print_delta { my ($value, $min) = @_; # this function rounds off, and prints bad (> min) values in red my $worse = ($value - $min) > 1000; # heuristic -- allow 1k of noise - my $units = 'b'; + my $units = "b"; if ($value >= 1000000) { - $value = int($value / 1000000); - $min = int($min / 1000000); - $units = 'M'; - } elsif ($value >= 1000) { - $value = int($value / 1000); - $min = int($min / 1000); - $units = 'K'; + $value = int($value / 1000000); + $min = int($min / 1000000); + $units = "M"; + } + else { + if ($value >= 1000) { + $value = int($value / 1000); + $min = int($min / 1000); + $units = "K"; + } } if ($worse) { - return sprintf('%d%s', $value, $units); - } else { - return sprintf('%d%s', $value, $units); + return sprintf("%d%s", + $value, $units); + } + else { + return sprintf("%d%s", $value, $units); } } -BEGIN { - # Make $lasthour persistent private variable for print_table_row(). - my $lasthour = ''; +sub print_table_row { + my ($tt) = @_; - sub print_table_row { - my ($tt) = @_; + # Time column + # + my $query_link = ''; + my $end_query = ''; + my $pretty_time = &print_time($build_time_times->[$tt]); - # Time column - # - my $query_link = ''; - my $end_query = ''; - my $pretty_time = &print_time($build_time_times->[$tt]); - - ($hour) = $pretty_time =~ /(\d\d):/; + ($hour) = $pretty_time =~ /(\d\d):/; - if ($lasthour ne $hour or &has_who_list($tt)) { - $query_link = &query_ref($td, $build_time_times->[$tt]); - $end_query = ''; - } - if ($lasthour eq $hour) { - $pretty_time =~ s/^.* //; - } else { - $lasthour = $hour; - } - - my $hour_color = ''; - $hour_color = ' bgcolor=#e7e7e7' if $build_time_times->[$tt] % 7200 <= 3600; - print "", - "$query_link\n$pretty_time$end_query\n"; - - # Guilty - # - print ''; - for $who (sort keys %{$who_list->[$tt]} ){ - my $qr = &who_menu($td, $build_time_times->[$tt], - $build_time_times->[$tt-1],$who); - $who =~ s/%.*$//; - print " $qr$who\n"; - } - print ''; - - # Build Status - # - for (my $build_index=0; $build_index < $name_count; $build_index++) { - if (not defined($br = $build_table->[$tt][$build_index])) { - # No build data for this time - print "\n"; - next; - } - next if $br == -1; # rowspan has covered this row - - my $rowspan = $br->{rowspan}; - $rowspan = $mindate_time_count - $tt + 1 - if $tt + $rowspan - 1 > $mindate_time_count; - print "{buildstatus}}>\n"; - - my $logfile = $br->{logfile}; - my $buildtree = $br->{td}->{name}; - - print "\n"; - - # Build Note - # - my $logurl = "${rel_path}showlog.cgi?log=$buildtree/$logfile"; - - if ($br->{hasnote}) { - print "{noteid},'$logfile');\">", - "\n"; - } - - # Build Log - # - print "" - ."L"; - - # What Changed - # - # Only add the "C" link if there have been changes since the last build. - if( $br->{previousbuildtime} ){ - my $previous_br = $build_table->[$tt+$rowspan][$build_index]; - my $previous_rowspan = $previous_br->{rowspan}; - if (&has_who_list($tt+$rowspan, - $tt+$rowspan+$previous_rowspan-1)) { - print "\n", &query_ref($br->{td}, - $br->{previousbuildtime}, - $br->{buildtime}); - print "C"; - } - } - - # Leak/Bloat - # - if (defined $bloaty_by_log->{$logfile}) { - my ($leaks, $bloat); - ($leaks, $bloat) = @{ $bloaty_by_log->{$logfile} }; - printf "
Lk:%s
Bl:%s", - print_bloat_delta($leaks, $bloaty_min_leaks), - print_bloat_delta($bloat, $bloaty_min_bloat); - } - - # Binary - # - if ($br->{binaryname} ne '') { - $binfile = "$buildtree/bin/$br->{buildtime}/$br->{buildname}/" - ."$br->{binaryname}"; - $binfile =~ s/ //g; - print " B"; - } - print "
\n"; - } - print "\n"; + if ($lasthour != $hour or &has_who_list($tt)) { + $query_link = &query_ref($td1, $build_time_times->[$tt]); + $end_query = ''; } + if ($lasthour == $hour) { + $pretty_time =~ s/^.* //; + } else { + $lasthour = $hour; + } + + my $hour_color = ''; + $hour_color = ' bgcolor=#e7e7e7' if $build_time_times->[$tt] % 7200 <= 3600; + print "", + "$query_link\n$pretty_time$end_query\n"; + + # Guilty + # + print ''; + for $who (sort keys %{$who_list->[$tt]} ){ + $qr = &who_menu($td1, $build_time_times->[$tt], + $build_time_times->[$tt-1],$who); + $who =~ s/%.*$//; + print " ${qr}$who\n"; + } + print ''; + + # Build Status + # + for ($bn=1; $bn <= $name_count; $bn++) { + if (not defined($br = $build_table->[$tt][$bn])) { + # No build data for this time + print "\n"; + next; + } + next if $br == -1; # rowspan has covered this row + + $hasnote = $br->{hasnote}; + $noteid = $hasnote ? $br->{noteid} : 0; + $rowspan = $br->{rowspan}; + $rowspan = $mindate_time_count - $tt + 1 + if $tt + $rowspan - 1 > $mindate_time_count; + $color = $colormap{$br->{buildstatus}}; + $status = $br->{buildstatus}; + print "\n"; + + $logfile = $br->{logfile}; + $errorparser = $br->{errorparser}; + $buildname = $br->{buildname}; + $buildtime = $br->{buildtime}; + $buildtree = $br->{td}->{name}; + + print "\n"; + + # Build Note + # + $buildname = &url_encode($buildname); + my $logurl = "${rel_path}showlog.cgi?log=$buildtree/$logfile"; + + if ($hasnote) { + print "", + "\n"; + } + + # Build Log + # + print ""; + print "L"; + + # What Changed + # + if( $br->{previousbuildtime} ){ + my $previous_br = $build_table->[$tt+$rowspan][$bn]; + my $previous_rowspan = $previous_br->{rowspan}; + if (&has_who_list($tt+$rowspan, + $tt+$rowspan+$previous_rowspan-1)) { + print "\n", &query_ref($br->{td}, + $br->{previousbuildtime}, + $br->{buildtime}); + print "C"; + } + } + + # Leak/Bloat + # + if (defined $bloat_by_log->{$logfile}) { + my $leaks, $bloat; + ($leaks, $bloat) = @{ $bloat_by_log->{$logfile} }; + # Percentage, or absolute? + # printf "
%+.2f
%+.2f", $leaks, $bloat; + #printf "
%d
%d", $leaks, $bloat; + printf "
Lk:%s
Bl:%s", + print_delta($leaks, $minLeaks), + print_delta($bloat, $minBloat); + } + + # Binary + # + if ($br->{binaryname} ne '') { + $binfile = "$buildtree/bin/$buildtime/$br->{buildname}/" + ."$br->{binaryname}"; + $binfile =~ s/ //g; + print " B"; + } + print "
\n"; + } + print "\n"; } sub print_table_header { + my $ii, $nspan; + print "\n"; print "\n"; @@ -386,14 +391,14 @@ sub print_table_header { &open_showbuilds_href(rebuildguilty=>'1'), "Rebuild guilty list"; - for (my $ii=0; $ii < $name_count; $ii++) { + for ($ii=1; $ii <= $name_count; $ii++) { - my $bn = $build_names->[$ii]; + my $bn = $build_name_names->[$ii]; $bn =~ s/Clobber/Clbr/g; $bn =~ s/Depend/Dep/g; $bn = "$bn"; - my $last_status = tb_last_status($ii); + my $last_status = &last_status($ii); if ($last_status eq 'busted') { if ($form{nocrap}) { print ""; @@ -450,16 +455,24 @@ sub query_ref { $output .= "&branch=$td->{cvs_branch}" if $td->{cvs_branch} ne 'HEAD'; $output .= "&cvsroot=$td->{cvs_root}" if $td->{cvs_root} ne $default_root; $output .= "&date=explicit&mindate=$mindate"; - $output .= "&maxdate=$maxdate" if $maxdate and $maxdate ne ''; - $output .= "&who=$who" if $who and $who ne ''; + $output .= "&maxdate=$maxdate" if $maxdate ne ''; + $output .= "&who=$who" if $who ne ''; $output .= ">"; } +sub query_ref2 { + my ($td, $mindate, $maxdate, $who) = @_; + return "${rel_path}../bonsai/cvsquery.cgi?module=$td->{cvs_module}" + ."&branch=$td->{cvs_branch}&cvsroot=$td->{cvs_root}" + ."&date=explicit&mindate=$mindate&maxdate=$maxdate&who=" + . url_encode($who); +} + sub who_menu { my ($td, $mindate, $maxdate, $who) = @_; my $treeflag; - my $qr = "${rel_path}../registry/who.cgi?email=". url_encode($who) + $qr = "${rel_path}../registry/who.cgi?email=". url_encode($who) . "&d=$td->{cvs_module}|$td->{cvs_branch}|$td->{cvs_root}|$mindate|$maxdate"; return ""; @@ -473,13 +486,14 @@ sub has_who_list { if (not defined(@who_check_list)) { # Build a static array of true/false values for each time slot. - $who_check_list[$time_count - 1] = 0; - for (my $tt = 0; $tt < $time_count; $tt++) { - $who_check_list[$tt] = 1 if each %{$who_list->[$tt]}; + $who_check_list[$time_count] = 0; + my ($t) = 1; + for (; $t<=$time_count; $t++) { + $who_check_list[$t] = 1 if each %{$who_list->[$t]}; } } if ($time2) { - for (my $ii=$time1; $ii<=$time2; $ii++) { + for ($ii=$time1; $ii<=$time2; $ii++) { return 1 if $who_check_list[$ii] } return 0 @@ -489,7 +503,7 @@ sub has_who_list { } sub tree_open { - my ($line, $treestate); + my $line, $treestate; open(BID, "<../bonsai/data/$bonsai_tree/batchid.pl") or print "can't open batchid
"; $line = ; @@ -606,9 +620,9 @@ __ENDJS $ss =~ s/\n/\\n/g; print "\"$ss\";\n"; } - for ($ii=0; $ii < $name_count; $ii++) { - if (defined($br = $build_table->[0][$ii]) and $br != -1) { - my $bn = $build_names->[$ii]; + for ($ii=1; $ii <= $name_count; $ii++) { + if (defined($br = $build_table->[1][$ii]) and $br != -1) { + my $bn = $build_name_names->[$ii]; print "builds[$ii]='$bn';\n"; } } @@ -634,8 +648,8 @@ __ENDJS sub do_express { print "Content-type: text/html\nRefresh: 900\n\n\n"; - my (%build, %times); - tb_loadquickparseinfo($form{tree}, \%build, \%times); + my %build, %times; + loadquickparseinfo($form{tree}, \%build, \%times); my @keys = sort keys %build; my $keycount = @keys; @@ -653,8 +667,8 @@ sub do_express { sub do_panel { print "Content-type: text/html\n\n\n" unless $form{static}; - my (%build, %times); - tb_loadquickparseinfo($form{tree}, \%build, \%times); + my %build, %times; + loadquickparseinfo($form{tree}, \%build, \%times); print q( @@ -692,8 +706,8 @@ sub do_panel { sub do_flash { print "Content-type: text/rdf\n\n" unless $form{static}; - my (%build, %times); - tb_loadquickparseinfo($form{tree}, \%build, \%times); + my %build, %times; + loadquickparseinfo($form{tree}, \%build, \%times); my ($mac,$unix,$win) = (0,0,0); @@ -764,8 +778,8 @@ sub do_quickparse { my $state = tree_open() ? "Open" : "Close"; print "State|$t|$bonsai_tree|$state\n"; } - my (%build, %times); - tb_loadquickparseinfo($t, \%build, \%times); + my %build, %times; + loadquickparseinfo($t, \%build, \%times); foreach my $buildname (sort keys %build) { print "Build|$t|$buildname|$build{$buildname}\n"; @@ -781,8 +795,8 @@ sub do_rdf { $dirurl =~ s@/[^/]*$@@; - my (%build, %times); - tb_loadquickparseinfo($tree, \%build, \%times); + my %build, %times; + loadquickparseinfo($tree, \%build, \%times); my $image = "channelok.gif"; my $imagetitle = "OK"; diff --git a/webtools/tinderbox/tbglobals.pl b/webtools/tinderbox/tbglobals.pl index 1c90369b22e..b0524fac6dc 100755 --- a/webtools/tinderbox/tbglobals.pl +++ b/webtools/tinderbox/tbglobals.pl @@ -16,9 +16,6 @@ # Corporation. Portions created by Netscape are Copyright (C) 1998 # Netscape Communications Corporation. All Rights Reserved. -# Reading the log backwards saves time when we only want the tail. -use Backwards; - # # Global variabls and functions for tinderbox # @@ -27,39 +24,59 @@ use Backwards; # Global variables # -# From load_data() -$ignore_builds = {}; +$td1 = {}; +$td2 = {}; -# From get_build_name_index() -$build_name_index = {}; -$build_names = []; +$build_list = []; # array of all build records +$build_name_index = {}; +$ignore_builds = {}; +$build_name_names = []; $name_count = 0; -# Frome get_build_time_index() $build_time_index = {}; $build_time_times = []; -$mindate_time_count = 0; # time_count that corresponds to the mindate $time_count = 0; +$mindate_time_count = 0; # time_count that corresponds to the mindate $build_table = []; $who_list = []; +$who_list2 = []; @note_array = (); -# Yeah, more globals. -$bloaty_by_log = {}; -$bloaty_min_leaks = 0; -$bloaty_min_bloat = 0; +$bloat_by_log = {}; +$minLeaks = 0; +$minBloat = 0; -$gzip = '/usr/local/bin/gzip'; +#$body_tag = ""; +#$body_tag = ""; +if( $ENV{'USERNAME'} eq 'ltabb' ){ + $gzip = 'gzip'; +} +else { + $gzip = '/usr/local/bin/gzip'; +} $data_dir='data'; +$lock_count = 0; + 1; sub lock{ + #if( $lock_count == 0 ){ + # print "locking $tree/LOCKFILE.lck\n"; + # open( LOCKFILE_LOCK, ">$tree/LOCKFILE.lck" ); + # flock( LOCKFILE_LOCK, 2 ); + #} + #$lock_count++; } sub unlock{ + #$lock_count--; + #if( $lock_count == 0 ){ + # flock( LOCKFILE_LOCK, 8 ); + # close( LOCKFILE_LOCK ); + #} } sub print_time { @@ -103,48 +120,142 @@ sub value_encode { } -sub tb_load_data { +sub load_data { + $tree2 = $form{'tree2'}; + if( $tree2 ne '' ){ + require "$tree2/treedata.pl"; + if( -r "$tree2/ignorebuilds.pl" ){ + require "$tree2/ignorebuilds.pl"; + } + + $td2 = {}; + $td2->{name} = $tree2; + $td2->{cvs_module} = $cvs_module; + $td2->{cvs_branch} = $cvs_branch; + $td2->{num} = 1; + $td2->{ignore_builds} = $ignore_builds; + if( $cvs_root eq '' ){ + $cvs_root = '/m/src'; + } + $td2->{cvs_root} = $cvs_root; + + $tree = $form{'tree'}; + require "$tree/treedata.pl"; + if( $cvs_root eq '' ){ + $cvs_root = '/m/src'; + } + } + $tree = $form{'tree'}; - return undef unless $tree; + return unless $tree; + #die "the 'tree' parameter must be provided\n" unless $tree; - require "$tree/treedata.pl" if -r "$tree/treedata.pl"; - + if ( -r "$tree/treedata.pl" ) { + require "$tree/treedata.pl"; + } + $ignore_builds = {}; - - require "$tree/ignorebuilds.pl" if -r "$tree/ignorebuilds.pl"; + if( -r "$tree/ignorebuilds.pl" ){ + require "$tree/ignorebuilds.pl"; + } - $td = {}; - $td->{name} = $tree; - $td->{num} = 0; - $td->{cvs_module} = $cvs_module; - $td->{cvs_branch} = $cvs_branch; - $td->{ignore_builds} = $ignore_builds; - $cvs_root = '/m/src' if $cvs_root eq ''; - $td->{cvs_root} = $cvs_root; + $td1 = {}; + $td1->{name} = $tree; + $td1->{num} = 0; + $td1->{cvs_module} = $cvs_module; + $td1->{cvs_branch} = $cvs_branch; + $td1->{ignore_builds} = $ignore_builds; + if( $cvs_root eq '' ){ + $cvs_root = '/m/src'; + } + $td1->{cvs_root} = $cvs_root; - $build_list = &load_buildlog($td); + &lock; + &load_buildlog; + &unlock; - &get_build_name_index($build_list); - &get_build_time_index($build_list); + &get_build_name_index; + &get_build_time_index; - &load_who($td, $who_list); + &load_who($who_list, $td1); + if( $tree2 ne '' ){ + &load_who($who_list2, $td2); + } - &make_build_table($td, $build_list); + &make_build_table; - ($bloaty_min_leaks, $bloaty_min_bloat) = load_bloaty($td); - - return $td; + ($minLeaks, $minBloat) = load_bloat($td1); } -sub tb_loadquickparseinfo { - my ($tree, $build, $times, $includeStatusOfBuilding) = (@_); - local $_; +sub load_buildlog { + my $mailtime, $buildtime, $buildname, $errorparser; + my $buildstatus, $logfile,$binaryname; + my $buildrec, @treelist, $t; - $maxdate = time; - require "$tree/ignorebuilds.pl" if -r "$tree/ignorebuilds.pl"; + if (not defined $maxdate) { + $maxdate = time(); + } + if (not defined $mindate) { + $mindate = $maxdate - 24*60*60; + } + + if ($tree2 ne '') { + @treelist = ($td1, $td2); + } + else { + @treelist = ($td1); + } + + for $t (@treelist) { + use Backwards; + my ($bw) = Backwards->new("$t->{name}/build.dat") or die; + + my $tooearly = 0; + while( $_ = $bw->readline ) { + chomp; + ($mailtime, $buildtime, $buildname, + $errorparser, $buildstatus, $logfile, $binaryname) = split /\|/; + + #$buildtime -= $buildtime % 60; # Round to minute + # Ignore stuff in the future. + next if $buildtime > $maxdate; + + # Ignore stuff in the past (but get a 2 hours of extra data) + if ($buildtime < $mindate - 2*60*60) { + # Occasionally, a build might show up with a bogus time. So, + # we won't judge ourselves as having hit the end until we + # hit a full 20 lines in a row that are too early. + last if $tooearly++ > 20; + + next; + } + $tooearly = 0; + $buildrec = { + mailtime => $mailtime, + buildtime => $buildtime, + buildname => ($tree2 ne '' ? $t->{name} . ' ' : '' ) . $buildname, + errorparser => $errorparser, + buildstatus => $buildstatus, + logfile => $logfile, + binaryname => $binaryname, + td => $t + }; + if ($form{noignore} or not $t->{ignore_builds}->{$buildname}) { + push @{$build_list}, $buildrec; + } + } + } +} + +sub loadquickparseinfo { + my ($tree, $build, $times) = (@_); + + do "$tree/ignorebuilds.pl"; - my $bw = Backwards->new("$tree/build.dat") or die; + use Backwards; + + my ($bw) = Backwards->new("$form{tree}/build.dat") or die; my $latest_time = 0; my $tooearly = 0; @@ -152,8 +263,7 @@ sub tb_loadquickparseinfo { chop; my ($buildtime, $buildname, $buildstatus) = (split /\|/)[1,2,4]; - if ($includeStatusOfBuilding or - $buildstatus =~ /^success|busted|testfailed$/) { + if ($buildstatus =~ /^success|busted|testfailed$/) { # Ignore stuff in the future. next if $buildtime > $maxdate; @@ -180,28 +290,240 @@ sub tb_loadquickparseinfo { } } -sub tb_last_status { - my ($build_index) = @_; +# Load data about who checked in when +# File format: | +# +sub load_who { + my ($who_list, $treedata) = @_; + local $_; + + open(WHOLOG, "<$treedata->{name}/who.dat"); + while () { + chomp; + my ($checkin_time, $email) = split /\|/; - for (my $tt=0; $tt < $time_count; $tt++) { - my $br = $build_table->[$tt][$build_index]; - next unless defined $br and $br->{buildstatus}; + # Find the time slice where this checkin belongs. + for (my $ii = $time_count; $ii > 0; $ii--) { + if ($checkin_time <= $build_time_times->[$ii]) { + $who_list->[$ii+1]->{$email} = 1; + last; + } + } + } + + # Ignore the last one + # + if ($time_count > 0) { + $who_list->[$time_count] = {}; + } +} + +# Load data about code bloat +# File format: ||| +# +sub load_bloat { + my ($treedata) = @_; + local $_; + open(BLOATLOG, "<$treedata->{name}/bloat.dat"); + my $leaksList = []; + my $bloatList = []; + my $index = 0; + my $listMax = 5; # only take the minimum over the last few entries + while () { + chomp; + my ($logfile, $leaks, $bloat) = split /\|/; + $bloat_by_log->{$logfile} = [ $leaks, $bloat ]; + $leaksList[$index] = $leaks; + $bloatList[$index] = $bloat; + $index = ($index + 1) % $listMax; + } + my $leaksMin = 9999999999999; + my $bloatMin = 9999999999999; + for ($index = 0; $index < $listMax; $index++) { + print "min: $leaksList[$index] $bloatList[$index]\n"; + if ($leaksList[$index] < $leaksMin) { + $leaksMin = $leaksList[$index]; + } + if ($bloatList[$index] < $bloatMin) { + $bloatMin = $bloatList[$index]; + } + } + return ($leaksMin, $bloatMin); +} + +sub get_build_name_index { + my $i,$br; + + # Get all the unique build names. + # + foreach $br (@{$build_list}) { + $build_name_index->{$br->{buildname}} = 1; + } + + $i = 1; + foreach $n (sort keys (%{$build_name_index})) { + $build_name_names->[$i] = $n; + $i++; + } + + $name_count = @{$build_name_names}-1; + + # Update the map so it points to the right index + # + for ($i=1; $i < $name_count+1; $i++) { + $build_name_index->{$build_name_names->[$i]} = $i; + } +} + +sub get_build_time_index { + my $i,$br; + + # Get all the unique build names. + # + foreach $br (@{$build_list}) { + $build_time_index->{$br->{buildtime}} = 1; + } + + $i = 1; + foreach $n (sort {$b <=> $a} keys (%{$build_time_index})) { + $build_time_times->[$i] = $n; + $mindate_time_count = $i if $n >= $mindate; + $i++; + } + + $time_count = @{$build_time_times}-1; + + # Update the map so it points to the right index + # + for ($i=1; $i < $time_count+1; $i++) { + $build_time_index->{$build_time_times->[$i]} = $i; + } + + #for $i (@{$build_time_times}) { + # print $i . "\n"; + #} + + #while( ($k,$v) = each(%{$build_time_index})) { + # print "$k=$v\n"; + #} +} + +sub make_build_table { + my $i,$ti,$bi,$ti1,$br; + + # Create the build table + # + for ($i=1; $i <= $time_count; $i++){ + $build_table->[$i] = []; + } + + # Populate the build table with build data + # + foreach $br (reverse @{$build_list}) { + $ti = $build_time_index->{$br->{buildtime}}; + $bi = $build_name_index->{$br->{buildname}}; + $build_table->[$ti][$bi] = $br; + } + + &load_notes; + + for ($bi = $name_count; $bi > 0; $bi--) { + for ($ti = $time_count; $ti > 0; $ti--) { + if (defined($br = $build_table->[$ti][$bi]) + and not defined($br->{rowspan})) { + + # If the cell immediately after us is defined, then we + # can have a previousbuildtime. + if (defined($br1 = $build_table->[$ti+1][$bi])) { + $br->{previousbuildtime} = $br1->{buildtime}; + } + + $ti1 = $ti-1; + while ($ti1 > 0 and not defined($build_table->[$ti1][$bi])) { + $build_table->[$ti1][$bi] = -1; + $ti1--; + } + $br->{rowspan} = $ti - $ti1; + if ($br->{rowspan} != 1) { + $build_table->[$ti1+1][$bi] = $br; + $build_table->[$ti][$bi] = -1; + } + } + } + } +} + +sub load_notes { + if ($tree2 ne '') { + @treelist = ($td1, $td2); + } + else { + @treelist = ($td1); + } + + foreach $t (@treelist) { + open(NOTES,"<$t->{name}/notes.txt") + or print "

warning: Couldn't open $t->{name}/notes.txt

\n"; + while () { + chop; + ($nbuildtime,$nbuildname,$nwho,$nnow,$nenc_note) = split /\|/; + $nbuildname = "$t->{name} $nbuildname" if $tree2 ne ''; + $ti = $build_time_index->{$nbuildtime}; + $bi = $build_name_index->{$nbuildname}; + #print "[ti = $ti][bi=$bi][buildname='$nbuildname' $_
"; + if ($ti != 0 and $bi != 0) { + $build_table->[$ti][$bi]->{hasnote} = 1; + if (not defined($build_table->[$ti][$bi]->{noteid})) { + $build_table->[$ti][$bi]->{noteid} = (0+@note_array); + } + $noteid = $build_table->[$ti][$bi]->{noteid}; + $now_str = &print_time($nnow); + $note = &url_decode($nenc_note); + $note_array[$noteid] = "
\n["
+             ."$nwho - $now_str]\n$note\n
" + .$note_array[$noteid]; + } + } + close(NOTES); + } +} + +sub last_success_time { + my ($row) = @_; + + for (my $tt=1; $tt <= $time_count; $tt++) { + my $br = $build_table->[$tt][$row]; + next unless defined $br; + next unless $br->{buildstatus} eq 'success'; + return $build_time_times->[$tt + $br->{rowspan} ]; + } + return 0; +} + +sub last_status { + my ($row) = @_; + + for (my $tt=1; $tt <= $time_count; $tt++) { + my $br = $build_table->[$tt][$row]; + next unless defined $br; next unless $br->{buildstatus} =~ /^(success|busted|testfailed)$/; return $br->{buildstatus}; } return 'building'; } -sub tb_check_password { - if ($form{password} eq '' and defined $cookie_jar{tinderbox_password}) { - $form{password} = $cookie_jar{tinderbox_password}; +sub check_password { + if ($form{password} eq '') { + if (defined $cookie_jar{tinderbox_password}) { + $form{password} = $cookie_jar{tinderbox_password}; + } } my $correct = ''; - if (open(REAL, '; - close REAL; - $correct =~ s/\s+$//; # Strip trailing whitespace. - } + if (open(REAL, '; + close REAL; + $correct =~ s/\s+$//; # Strip trailing whitespace. + } $form{password} =~ s/\s+$//; # Strip trailing whitespace. if ($form{password} ne '') { open(TRAPDOOR, "../bonsai/data/trapdoor $form{'password'} |") @@ -249,19 +571,14 @@ sub tb_check_password { exit; } -sub tb_find_build_record { +sub find_build_record { my ($tree, $logfile) = @_; - local $_; - my $log_entry = ''; - my ($bw) = Backwards->new("$tree/build.dat") or die; - while( $_ = $bw->readline ) { - $log_entry = $_ if /$logfile/; - } + my $log_entry = `grep $logfile $tree/build.dat`; chomp($log_entry); my ($mailtime, $buildtime, $buildname, $errorparser, - $buildstatus, undef, $binaryname) = split /\|/, $log_entry; + $buildstatus, $logfile, $binaryname) = split /\|/, $log_entry; $buildrec = { mailtime => $mailtime, @@ -275,243 +592,3 @@ sub tb_find_build_record { }; return $buildrec; } - -sub tb_build_static { - # Build tinderbox static pages - $ENV{QUERY_STRING}="tree=$tree&static=1"; - $ENV{REQUEST_METHOD}="GET"; - system './showbuilds.cgi >/dev/null&'; -} - -# end of public functions -#============================================================ - -sub load_buildlog { - my ($treedata) = $_[0]; - - # In general you always want to make "$_" a local - # if it is used. That way it is restored upon return. - local $_; - my $build_list = []; - - - if (not defined $maxdate) { - $maxdate = time(); - } - if (not defined $mindate) { - $mindate = $maxdate - 24*60*60; - } - - my ($bw) = Backwards->new("$treedata->{name}/build.dat") or die; - - my $tooearly = 0; - while( $_ = $bw->readline ) { - chomp; - my ($mailtime, $buildtime, $buildname, - $errorparser, $buildstatus, $logfile, $binaryname) = split /\|/; - - # Ignore stuff in the future. - next if $buildtime > $maxdate; - - # Ignore stuff in the past (but get a 2 hours of extra data) - if ($buildtime < $mindate - 2*60*60) { - # Occasionally, a build might show up with a bogus time. So, - # we won't judge ourselves as having hit the end until we - # hit a full 20 lines in a row that are too early. - last if $tooearly++ > 20; - - next; - } - $tooearly = 0; - if ($form{noignore} or not $treedata->{ignore_builds}->{$buildname}) { - my $buildrec = { - mailtime => $mailtime, - buildtime => $buildtime, - buildname => $buildname, - errorparser => $errorparser, - buildstatus => $buildstatus, - logfile => $logfile, - binaryname => $binaryname, - td => $treedata - }; - push @{$build_list}, $buildrec; - } - } - return $build_list; -} - -# Load data about who checked in when -# File format: | -# -sub load_who { - my ($treedata, $who_list) = @_; - local $_; - - open(WHOLOG, "<$treedata->{name}/who.dat"); - while () { - chomp; - my ($checkin_time, $email) = split /\|/; - - # Find the time slice where this checkin belongs. - for (my $ii = $time_count - 1; $ii >= 0; $ii--) { - if ($checkin_time <= $build_time_times->[$ii]) { - $who_list->[$ii+1]->{$email} = 1; - last; - } - } - } - - # Ignore the last one - # - #if ($time_count > 0) { - # $who_list->[$time_count] = {}; - #} -} - -# Load data about code bloat -# File format: ||| -# -sub load_bloaty { - my $treedata = $_[0]; - local $_; - open(BLOATLOG, "<$treedata->{name}/bloat.dat"); - my $leaks_list = []; - my $bloat_list = []; - my $index = 0; - my $list_max = 5; # only take the minimum over the last few entries - - while () { - chomp; - my ($logfile, $leaks, $bloat) = split /\|/; - $bloaty_by_log->{$logfile} = [ $leaks, $bloat ]; - $leaks_list[$index] = $leaks; - $bloat_list[$index] = $bloat; - $index++; - $index = 0 unless $index < $list_max; - } - my $leaks_min = $leaks_list[0]; - my $bloat_min = $bloat_list[0]; - for ($index = 1; $index < $list_max; $index++) { - if ($leaks_list[$index] < $leaks_min) { - $leaks_min = $leaks_list[$index]; - } - if ($bloat_list[$index] < $bloat_min) { - $bloat_min = $bloat_list[$index]; - } - } - return ($leaks_min, $bloat_min); -} - -sub get_build_name_index { - my ($build_list) = @_; - - # Get all the unique build names. - # - foreach my $build_record (@{$build_list}) { - $build_name_index->{$build_record->{buildname}} = 1; - } - - my $ii = 0; - foreach my $name (sort keys %{$build_name_index}) { - $build_names->[$ii] = $name; - $build_name_index->{$name} = $ii; - $ii++; - } - $name_count = $#{$build_names} + 1; -} - -sub get_build_time_index { - my ($build_list) = @_; - - # Get all the unique build names. - # - foreach my $br (@{$build_list}) { - $build_time_index->{$br->{buildtime}} = 1; - } - - my $ii = 0; - foreach my $time (sort {$b <=> $a} keys %{$build_time_index}) { - $build_time_times->[$ii] = $time; - $build_time_index->{$time} = $ii; - $mindate_time_count = $ii if $time >= $mindate; - $ii++; - } - $time_count = $#{$build_time_times} + 1; -} - -sub make_build_table { - my ($treedata, $build_list) = @_; - my ($ti, $bi, $ti1, $br); - - # Create the build table - # - for (my $ii=0; $ii < $time_count; $ii++){ - $build_table->[$ii] = []; - } - - # Populate the build table with build data - # - foreach $br (reverse @{$build_list}) { - $ti = $build_time_index->{$br->{buildtime}}; - $bi = $build_name_index->{$br->{buildname}}; - $build_table->[$ti][$bi] = $br; - } - - &load_notes($treedata); - - for ($bi = $name_count - 1; $bi >= 0; $bi--) { - for ($ti = $time_count - 1; $ti >= 0; $ti--) { - if (defined($br = $build_table->[$ti][$bi]) - and not defined($br->{rowspan})) { - - # If the cell immediately after us is defined, then we - # can have a previousbuildtime. - if (defined($br1 = $build_table->[$ti+1][$bi])) { - $br->{previousbuildtime} = $br1->{buildtime}; - } - - $ti1 = $ti-1; - while ($ti1 >= 0 and not defined $build_table->[$ti1][$bi]) { - $build_table->[$ti1][$bi] = -1; - $ti1--; - } - $br->{rowspan} = $ti - $ti1; - unless ($br->{rowspan} == 1) { - $build_table->[$ti1+1][$bi] = $br; - $build_table->[$ti][$bi] = -1; - } - } - } - } -} - -sub load_notes { - my $treedata = $_[0]; - - open(NOTES,"<$treedata->{name}/notes.txt") - or print "

warning: Couldn't open $treedata->{name}/notes.txt

\n"; - while () { - chop; - my ($nbuildtime,$nbuildname,$nwho,$nnow,$nenc_note) = split /\|/; - my $ti = $build_time_index->{$nbuildtime}; - my $bi = $build_name_index->{$nbuildname}; - - if (defined $ti and defined $bi) { - $build_table->[$ti][$bi]->{hasnote} = 1; - unless (defined $build_table->[$ti][$bi]->{noteid}) { - $build_table->[$ti][$bi]->{noteid} = $#note_array + 1; - } - $noteid = $build_table->[$ti][$bi]->{noteid}; - $now_str = &print_time($nnow); - $note = &url_decode($nenc_note); - - $note_array[$noteid] = '' unless $note_array[$noteid]; - $note_array[$noteid] = "
\n["
-        ."$nwho - $now_str]\n$note\n
" - .$note_array[$noteid]; - } - } - close NOTES; -} - -
$bn