Commit 6340cf7c authored by Michael Pyne's avatar Michael Pyne
Browse files

Fix a little bug with build-status I introduced last night.

Implement wish 109443 (E-mail report on compile failure).

This adds two configuration file options:

email-address: kdesvn-build uses this address to send email from.  You don't
have to set it, but it's probably better if you do if you use any features
kdesvn-build will send email for (like the one I'm committing).

email-on-compile-error: This should be set to the email address to send email
to whenever a build error occurs.

The email isn't sent until kdesvn-build is done trying to build/install modules
so that kdesvn-build can collate the results first.  kdesvn-build will also
include excerpts from the error log so that you won't necessarily have to pull
up the log to see what happened.  If you didn't set an email address to send
from, kdesvn-build will use the send-to address as the send-from address.

svn path=/trunk/KDE/kdesdk/doc/scripts/kdesvn-build/; revision=438049
parent 0cc38f69
......@@ -751,6 +751,38 @@ directive to choose directories that you want to check out.</para>
<row id="conf-email-address">
<entry>Can't be overridden</entry>
<para>Set this option to the e-mail address kdesvn-build should send from should
it ever need to send e-mail. You do not need to worry about this if you don't
use any feature which send e-mail. (They are all disabled by default).
<para>Currently only <link linkend="conf-email-on-compile-error">email-on-compile-error</link>
needs this option.
<row id="conf-email-on-compile-error">
<entry>Can't be overridden</entry>
<para>You can set this option to the email address to send a report to when a
module fails to build. kdesvn-build will wait until all the modules are done
and collate all of the results in the report. The report is only sent if a
module fails to build.
<para>Please see the <link linkend="conf-email-address">email-address</link>
option to set the address kdesvn-build should send from, since the default
is usually not what you want.
<row id="conf-inst-apps">
<entry>Overrides global</entry>
......@@ -270,6 +270,8 @@ my %package_opts = (
"dest-dir" => '${MODULE}', # single quotes used on purpose!
"disable-agent-check" => 0, # If true we don't check on ssh-agent
"do-not-compile" => "",
"email-address" => "",
"email-on-compile-error" => "",
"install-after-build" => "1", # Default to true
"inst-apps" => "",
"kdedir" => "$ENV{HOME}/kde",
......@@ -317,6 +319,7 @@ my @build_list; # List of modules to build.
# uses the key name to display text to the user so it should describe the
# actual category of failure. You should also add the key name to
# output_failed_module_lists since it uses its own sorted list.
my @fail_display_order = qw/build update install/;
my %fail_lists = (
'build' => [ ],
'install' => [ ],
......@@ -1600,7 +1603,7 @@ sub output_failed_module_list($@)
for (@fail_list)
$logfile = $package_opts{$_}{'#error-log-file'};
$logfile = get_option($_, '#error-log-file');
$logfile = "No log file" unless $logfile;
$logfile =~ s|$homedir|~|;
......@@ -1614,7 +1617,7 @@ sub output_failed_module_list($@)
# call.
sub output_failed_module_lists()
for my $type (qw/build update install/)
for my $type (@fail_display_order)
my @failures = @{$fail_lists{$type}};
output_failed_module_list("failed to $type", @failures);
......@@ -3476,7 +3479,7 @@ sub handle_build
# in the build-status file as well.
if ($outfile)
for my $failure (@{$fail_lists{'build'}})
for my $failure (@{$fail_lists{'update'}})
print STATUS_FILE "$failure: Failed on update.\n";
......@@ -3680,6 +3683,166 @@ sub munge_lists
# Subroutine to try an intelligently determine what caused the module to fail
# to build/update/whatever. The first parameter is the name of the module,
# and the return value is the best guess at the error. If no error is detected
# the last 30 lines of the file are returned instead.
sub whats_the_module_error
my $module = shift;
my $file = get_option($module, '#error-log-file');
open ERRORFILE, "<$file" or return "Can't open logfile $file.\n";
my @lastlines; # Used to buffer last lines read.
my @errors; # Tracks errors and the file they were found in.
my $lastfile = ''; # Tracks last filename read in error log.
my $errorCount = 0;
my $output;
# TODO: This code is tested for gcc and GNU ld, as, etc, I'm not sure how
# effective it is at parsing the error output of other build toolchains.
while (<ERRORFILE>)
# Keep last 30 lines.
push @lastlines, $_;
shift @lastlines if scalar @lastlines > 30;
my ($file, $line, $msg) = /^([^:]*):(\d+):\s*(.*)$/;
next unless ($file and $line and $msg);
next if $msg =~ /warn/i;
next if $msg =~ /^in file included from/i;
next if $msg =~ /^\s*$/ or $file =~ /^\s*$/;
$msg =~ s/^error: ?//i;
if ($file eq $lastfile)
push @errors, $msg if $errorCount < 5;
# Check is because we print info on the last file read, so there
# should be a last file. ;)
if ($lastfile)
my $error = $errorCount == 1 ? "error" : "errors";
$output .= "$errorCount $error in $lastfile\n";
$output .= "Error: $_\n" foreach (@errors);
$output .= "\t<clipped>\n" if $errorCount > 5;
$output .= "\n";
$errorCount = 1;
@errors = ($msg);
$lastfile = $file;
if (not $lastfile)
# Print out last lines read, hopefully a more descriptive error
# message is in there.
$output .= "Can't find errors, last " . scalar @lastlines . " line(s) of the output are:\n";
$output .= $_ foreach (@lastlines);
return $output;
# Don't forget to display info on last file read since it won't be done in
# the loop.
my $error = $errorCount == 1 ? "error" : "errors";
$output .= "$errorCount $error in $lastfile\n";
$output .= "Error: $_\n" foreach (@errors);
$output .= "\t<clipped>\n" if $errorCount > 5;
return $output;
# Subroutine to get the e-mail address to send e-mail from.
# It is pulled from the global email-address option by default.
# The first parameter is a default e-mail address to use (may be left off, in
# which case this function will create a default of its own if necessary.)
sub get_email_address
my $email = get_option('global', 'email-address');
my $default = shift;
# Use user's value if set.
return $email if $email;
# Let's use the provided default if set.
return $default if $default;
# Let's make a default of our own. It's likely to suck, so oh well.
use Sys::Hostname;
my $username = getpwuid($>);
my $hostname = hostname; # From Sys::Hostname
print "User has no email address, using $username\@$hostname\n" if debugging;
return "$username\@$hostname";
# Subroutine to look through the various failed lists, and send an email to the
# given email address with a description of the failures. If the user has
# selected no email address the subroutine does nothing.
sub email_error_report
my $email_addy = get_option('global', 'email-on-compile-error');
my $from_addy = get_email_address($email_addy);
return unless $email_addy;
# Initial e-mail header.
my $email_body = <<EOF;
The following errors were detected in the kdesvn-build run just completed.
# Loop through modules trying to find out what caused the errors.
my $had_error = 0;
for my $type (@fail_display_order)
for my $module (@{$fail_lists{$type}})
$email_body .= "$module failed to $type:\n";
$email_body .= "-------------------------------\n\n";
$email_body .= whats_the_module_error($module);
$email_body .= "-------------------------------\n\n";
$had_error = 1;
return unless $had_error;
# Detect Mail::Mailer.
my $mailer;
eval {
require Mail::Mailer;
$mailer = new Mail::Mailer;
} or do {
print clr " y[*] Can't open y[b[Mail::Mailer] module, so e-mailing is disabled.\n";
print clr " Why? $!\n" if debugging;
# Sendeth the email.
'From' => $from_addy,
'To' => $email_addy,
'Subject' => 'KDE Subversion build compile error',
print $mailer $email_body;
# Script starts.
# Use some exception handling to avoid ucky error messages
......@@ -3747,6 +3910,7 @@ eval
$time = localtime;
my $color = '';
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment