#! /usr/bonsaitools/bin/perl use FileHandle; $tree = 'SeaMonkey'; # tinderbox/globals.pl uses many shameful globals $form{tree} = $tree; require 'globals.pl'; $cvsroot = '/cvsroot/mozilla'; $lxr_data_root = '/export2/lxr-data'; @ignore = ( 'long long', '__cmsg_data' ); $ignore_pat = "(?:".join('|',@ignore).")"; print STDERR "Building hash of file names..."; %file_names = build_file_hash($cvsroot, $tree); print STDERR "done.\n"; for $br (last_successful_builds($tree)) { next unless $br->{errorparser} eq 'unix'; next unless $br->{buildname} =~ /\b(Clobber|Clbr)\b/; my $log_file = "$br->{logfile}"; warn "Parsing build log, $log_file\n"; $fh = new FileHandle "gunzip -c $tree/$log_file |"; &gcc_parser($fh, $cvsroot, $tree, $log_file, \%file_names); &build_blame; &print_warnings_as_html($br->{buildname}, $br->{buildtime}); last; } # end of main # =================================================================== sub build_file_hash { my ($cvsroot, $tree) = @_; $lxr_data_root = "/export2/lxr-data/\L$tree"; $lxr_file_list = "\L$lxr_data_root/.glimpse_filenames"; open(LXR_FILENAMES, "<$lxr_file_list") or die "Unable to open $lxr_file_list: $!\n"; use File::Basename; while () { my ($base, $dir, $ext) = fileparse($_,'\.[^/]*'); next unless $ext =~ /^\.(cpp|h|C|s|c)$/; $base = "$base$ext"; unless (exists $bases{$base}) { $dir =~ s|$lxr_data_root/mozilla/||; $dir =~ s|/$||; $bases{$base} = $dir; } else { $bases{$base} = ''; } } return %bases; } sub last_successful_builds { my $tree = shift; my @build_records = (); my $br; $maxdate = time; $mindate = $maxdate - 5*60*60; # Go back 5 hours print STDERR "Loading build data..."; &load_data; print STDERR "done\n"; for (my $ii=1; $ii <= $name_count; $ii++) { for (my $tt=1; $tt <= $time_count; $tt++) { if (defined($br = $build_table->[$tt][$ii]) and $br->{buildstatus} eq 'success') { push @build_records, $br; last; } } } return @build_records; } sub gcc_parser { my ($fh, $cvsroot, $tree, $log_file, $file_hash_ref) = @_; my $dir = ''; while (<$fh>) { # Directory # if (/^gmake\[\d\]: Entering directory \`(.*)\'$/) { ($build_dir = $1) =~ s|.*/mozilla/||; next; } # Now only match lines with "warning:" next unless /warning:/; next if /$ignore_pat/o; chomp; # Yum, yum my ($filename, $line, $warning_text); ($filename, $line, undef, $warning_text) = split /:\s*/; $filename =~ s/.*\///; my $dir; if (-e "$cvsroot/$tree/$builddir/$filename") { $dir = $build_dir; } else { unless(defined($dir = $file_hash_ref->{$filename})) { $dir = ''; } } my $file = "$dir/$filename"; unless (defined($warnings{"$file:$line"})) { # Remember where in the build log the warning occured $warnings{"$file:$line"} = { first_seen_line => $., log_file => $log_file, count => 0, warning_text => $warning_text, }; } $warnings{"$file:$line"}->{count}++; push @{$warnings_per_file{$file}}, $line; } } sub dump_warning_data { while (my ($file_and_line, $record) = each %warnings) { print join ':', "$file_and_line", $record->{first_seen_line}, $record->{count}, $record->{warning_text}; print "\n"; } } sub build_blame { use lib '../bonsai'; require 'utils.pl'; require 'cvsblame.pl'; while (($file, $lines) = each %warnings_per_file) { my $rcs_filename = "$cvsroot/$file,v"; unless (-e $rcs_filename) { warn "Unable to find $rcs_filename\n"; next; } my $revision = &parse_cvs_file($rcs_filename); @text = &extract_revision($revision); for $line (@{$lines}) { my $line_rev = $revision_map[$line-1]; my $who = $revision_author{$line_rev}; my $source_text = join '', @text[$line-4..$line+2]; chomp $source_text; my $warn_rec = $warnings{"$file:$line"}; $warn_rec->{line_rev} = $line_rev; $warn_rec->{source} = $source_text; $warnings_by_who{$who}{$file}{$line} = $warn_rec; $who_count{$who} += $warn_rec->{count}; } } } sub print_warnings_as_html { my ($buildname, $buildtime) = @_; my $time_str = print_time( $buildtime ); print <<"__END_HEADER"; Blamed Build Warnings Blamed Build Warnings
$buildname on $time_str

__END_HEADER for $who (sort { $who_count{$b} <=> $who_count{$a} || $a cmp $b } keys %who_count) { my $count = $who_count{$who}; my ($name, $email); ($name = $who) =~ s/%.*//; ($email = $who) =~ s/%/@/; print ""; print "$name"; print " (1 warning)" if $count == 1; print " ($count warnings)" if $count > 1; print ""; print "\n

    \n"; for $file (sort keys %{$warnings_by_who{$who}}) { for $linenum (sort keys %{$warnings_by_who{$who}{$file}}) { my $warn_rec = $warnings_by_who{$who}{$file}{$linenum}; my $warning = $warn_rec->{warning_text}; print "
  1. "; # File link print ""; print "$file:$linenum"; print " "; print "
    "; # Warning text print "\u$warning"; # Build log link my $log_line = $warn_rec->{first_seen_line}; print " ("; if ($warn_rec->{count} == 1) { print "See build log"; } else { print "See 1st of $warn_rec->{count} occurances in build log"; } print ")
    "; # Source code fragment # my ($keyword) = $warning =~ /\`([^\']*)\'/; print "
    "; print "
    ";
    
            my $source_text = $warn_rec->{source};
            my @source_lines = split /\n/, $source_text;
            my $line_index = $linenum - 3;
            for $line (@source_lines) {
              $line =~ s/&/&/g;
              $line =~ s//>/g;
              $line =~ s|$keyword|$keyword|g;
              print "" if $line_index == $linenum;
              print "$line_index $line
    "; print "
    " if $line_index == $linenum; $line_index++; } print "
    "; #
    "; print "
    \n"; } } print "
\n" } print <<"__END_FOOTER";


Send questions or comments to <slamm\@netcape.com>. __END_FOOTER } sub build_url { my ($tree, $log_file, $linenum) = @_; return "http://tinderbox.mozilla.org/showlog.cgi?tree=$tree" ."&logfile=$log_file" ."&line=$linenum" ."&numlines=50"; } sub file_url { my ($file, $linenum) = @_; return "http://cvs-mirror.mozilla.org/webtools/bonsai/cvsblame.cgi" ."?file=mozilla/$file&mark=$linenum#".($linenum-10); }