3
# buildd-mail: mail answer processor for buildd
4
# Copyright © 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 2 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
# General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program. If not, see
18
# <http://www.gnu.org/licenses/>.
20
#######################################################################
26
use Sbuild qw(binNMU_version);
29
use MIME::QuotedPrint;
33
sub prepare_for_upload ($$);
34
sub redo_new_version ($$$);
36
sub remove_from_upload ($);
37
sub append_to_REDO ($$);
38
sub remove_from_REDO ($);
39
sub append_to_SKIP ($);
40
sub check_is_outdated ($$);
42
sub register_outdated ($$$);
43
sub set_to_failed ($$$);
44
sub set_to_depwait ($$$);
47
sub get_fail_msg ($$);
48
sub check_state ($$@);
49
sub check_building_any_dist ($);
50
sub get_files_from_changes ($);
51
sub is_for_non_us ($$);
52
sub is_for_security ($);
53
sub get_dists_from_changes ($);
55
sub is_blacklisted ($);
56
sub add_error_mail ();
60
chdir( $Buildd::Conf::HOME );
62
lock_file( "daemon.log" );
63
END { unlock_file( "daemon.log" ); }
66
my($error, $short_error, %header, $body_text);
78
$error = $short_error = "";
84
if (/^\s/ && $lastheader) {
86
$_ = "$lastheader $_";
92
if (/^([\w\d-]+):\s*(.*)\s*$/) {
94
($hname = $1) =~ y/A-Z/a-z/;
109
{ local($/); undef $/; $body_text .= <STDIN>; }
111
if ($header{'from'} =~ /mail\s+delivery\s+(sub)?system|mailer.\s*daemon/i) {
112
# is an error mail from a mailer daemon
113
# To avoid mail loops if this error resulted from a mail we sent
114
# outselves, we break the loop by not forwarding this mail after the 5th
115
# error mail within 8 hours or so.
116
my $n = add_error_mail();
118
logger( "Too much error mails ($n) within ",
119
int($Buildd::Conf::error_mail_window/(60*60)), " hours\n",
120
"Not forwarding mail from $header{'from'}\n",
121
"Subject: $header{'subject'}\n" );
126
goto forward_mail if !$header{'subject'};
127
my $subject = $header{'subject'};
129
if ($subject =~ /^Re: Log for \S+ build of (\S+)(?: on [\w-]+)? \(dist=(\S+)\)/i) {
130
# reply to a build log
131
my( $package, $dist ) = ( $1, $2 );
132
$body_text =~ /^(\S+)/;
133
if (defined($header{'content-transfer-encoding'})) {
134
# Decode the mail if necessary.
135
if ($header{'content-transfer-encoding'} =~ /quoted-printable/) {
136
$body_text = decode_qp($body_text);
137
} elsif ($header{'content-transfer-encoding'} =~ /base64/) {
138
$body_text = decode_base64($body_text);
142
my $from = $header{'from'};
143
$from = $1 if $from =~ /<(.+)>/;
144
logger( "Log reply from $from\n" );
147
if ($keyword =~ /^not-for-us/) {
148
no_build( $package, $dist );
149
purge_pkg( $package, $dist );
151
elsif ($keyword =~ /^up(l(oad)?)?-rem/) {
152
remove_from_upload( $package );
154
elsif (check_is_outdated( $dist, $package )) {
155
# $error has been set already -> no action here
157
elsif ($keyword =~ /^fail/) {
158
my $text = $body_text;
159
$text =~ s/^fail.*\n(\s*\n)*//;
161
set_to_failed( $package, $dist, $text );
162
purge_pkg( $package, $dist );
164
elsif ($keyword =~ /^ret/) {
165
if (!check_state( $package, $dist, "Building" )) {
169
append_to_REDO( $package, $dist );
172
elsif ($keyword =~ /^d(ep(endency)?)?-(ret|w)/) {
173
if (!check_state( $package, $dist, "Building" )) {
177
$body_text =~ /^\S+\s+(.*)$/m;
179
set_to_depwait( $package, $dist, $deps );
180
purge_pkg( $package, $dist );
183
elsif ($keyword =~ /^man/) {
184
if (!check_state( $package, $dist, "Building" )) {
189
logger( "$package($dist) will be finished manually\n" );
192
elsif ($keyword =~ /^newv/) {
193
# build a newer version instead
194
$body_text =~ /^newv\S*\s+(\S+)/;
197
logger( "Removing unneeded package name from $newv\n" );
199
logger( "Result: $newv\n" );
202
($pkgname = $package) =~ s/_.*$//;
203
redo_new_version( $dist, $package, "${pkgname}_${newv}" );
204
purge_pkg( $package, $dist );
206
elsif ($keyword =~ /^(give|back)/) {
207
$body_text =~ /^(give|back) ([-0-9]+)/;
209
if (!check_state( $package, $dist, "Building" )) {
213
give_back( $package, $dist );
214
purge_pkg( $package, $dist );
217
elsif ($keyword =~ /^purge/) {
218
purge_pkg( $package, $dist );
220
elsif ($body_text =~ /^---+\s*BEGIN PGP SIGNED MESSAGE/) {
221
if (prepare_for_upload( $package, $body_text )) {
222
purge_pkg( $package, $dist );
225
elsif ($body_text =~ /^--/ && $header{'content-type'} =~ m,multipart/signed,) {
226
my ($prot) = ($header{'content-type'} =~ m,protocol="([^"]*)",);
227
my ($bound) = ($header{'content-type'} =~ m,boundary="([^"]*)",);
228
$body_text =~ s,^--\Q$bound\E\nContent-Type: text/plain; charset=us-ascii\n\n,-----BEGIN PGP SIGNED MESSAGE-----\n\n,;
229
$body_text =~ s,--\Q$bound\E\nContent-Type: application/pgp-signature\n\n,,;
230
$body_text =~ s,\n\n--\Q$bound\E--\n,,;
231
if (prepare_for_upload( $package, $body_text )) {
232
purge_pkg( $package, $dist );
236
$short_error .= "Bad keyword in answer $keyword\n";
237
$error .= "Answer not understood (expected retry, failed, manual,\n".
238
"dep-wait, giveback, not-for-us, purge, upload-rem,\n".
239
"newvers, or a signed changes file)\n";
242
elsif ($subject =~ /^Re: Should I build (\S+) \(dist=(\S+)\)/i) {
243
# reply whether a prev-failed package should be built
244
my( $package, $dist ) = ( $1, $2 );
245
$body_text =~ /^(\S+)/;
247
logger( "Should-build reply for $package($dist)\n" );
248
if (check_is_outdated( $dist, $package )) {
249
# $error has been set already -> no action here
251
elsif (!check_state( $package, $dist, "Building" )) {
254
elsif ($keyword =~ /^(build|ok)/) {
255
append_to_REDO( $package, $dist );
257
elsif ($keyword =~ /^fail/) {
258
my $text = get_fail_msg( $package, $dist );
259
set_to_failed( $package, $dist, $text );
261
elsif ($keyword =~ /^(not|no-b)/) {
262
no_build( $package, $dist );
264
elsif ($keyword =~ /^(give|back)/) {
265
give_back( $package, $dist );
268
$short_error .= "Bad keyword in answer $keyword\n";
269
$error .= "Answer not understood (expected build, ok, fail, ".
270
"give-back, or no-build)\n";
273
elsif ($subject =~ /^Processing of (\S+)/) {
275
# mail from Erlangen queue daemon: forward all non-success messages
276
goto forward_mail if $body_text !~ /uploaded successfully/mi;
277
logger( "$job processed by upload queue\n" )
278
if $Buildd::Conf::log_queued_messages;
280
elsif ($subject =~ /^([-+~\.\w]+\.changes) (INSTALL|ACCEPT)ED/) {
281
# success mail from dinstall
283
my( @to_remove, $upload_f, $pkgv );
284
my $upload_dir = "$Buildd::Conf::HOME/upload";
285
$upload_dir .= "-security" if -f "$upload_dir-security/$changes_f";
287
if (-f "$upload_dir/$changes_f" && open( F, "<$upload_dir/$changes_f" )) {
289
my $changetext = <F>;
291
push( @to_remove, get_files_from_changes( $changetext ) );
293
foreach (split( "\n", $body_text )) {
294
if (/^(\[-+~\.\w]+\.(u?deb))$/) {
296
push( @to_remove, $f ) if !grep { $_ eq $f } @to_remove;
300
($upload_f = $changes_f) =~ s/\.changes$/\.upload/;
301
push( @to_remove, $changes_f, $upload_f );
302
($pkgv = $changes_f) =~ s/_(\S+)\.changes//;
303
logger( "$pkgv has been installed; removing from upload dir:\n",
307
if (open( F, "<$upload_dir/$changes_f" )) {
309
{ local($/); undef $/; $changes_text = <F>; }
311
@dists = get_dists_from_changes( $changes_text );
313
logger( "Cannot get dists from $upload_dir/$changes_f: $! (assuming unstable)\n" );
314
@dists = ( "unstable" );
317
FILE: foreach (@to_remove) {
320
foreach my $dist (@dists) {
321
if ( -d "$Buildd::Conf::HOME/build/chroot-$dist" && -w "$Buildd::Conf::HOME/build/chroot-$dist/var/cache/apt/archives/") {
322
# TODO: send all of to_remove to perl-apt if it's available, setting a try_mv list
323
# that only has build-depends in it.
324
# if that's too much cpu, have buildd use perl-apt if avail to export the
325
# build-depends list, which could then be read in at this point
326
if (system "mv $upload_dir/$_ $Buildd::Conf::HOME/build/chroot-$dist/var/cache/apt/archives/") {
327
logger( "Cannot move $upload_dir/$_ to cache dir\n" );
334
unlink "$upload_dir/$_"
335
or logger( "Can't remove $upload_dir/$_: $!\n" );
338
elsif ($subject =~ /^(\S+\.changes) is NEW$/) {
339
# "is new" mail from dinstall
342
($pkgv = $changes_f) =~ s/_(\S+)\.changes//;
343
logger( "$pkgv must be manually dinstall-ed -- delayed\n" );
345
elsif ($subject =~ /^new version of (\S+) \(dist=(\S+)\)$/) {
346
# notice from wanna-build
347
my ($pkg, $dist) = ($1, $2);
348
goto forward if $body_text !~ /^in version (\S+)\.$/m;
349
my $pkgv = $pkg."_".$1;
350
$body_text =~ /new source version (\S+)\./m;
352
logger( "Build of $pkgv ($dist) obsolete -- new version $newv\n" );
353
register_outdated( $dist, $pkgv, $pkg."_".$newv );
356
if (!(@ds = check_building_any_dist( $pkgv ))) {
357
if (!remove_from_REDO( $pkgv )) {
358
append_to_SKIP( $pkgv );
360
purge_pkg( $pkgv, $dist );
363
logger( "Not deleting, still building for @ds\n" );
366
elsif ($body_text =~ /^blacklist (\S+)\n$/) {
367
my $pattern = "\Q$1\E";
368
if (open( F, ">>mail-blacklist" )) {
369
print F "$pattern\n";
371
logger( "Added $pattern to blacklist.\n" );
374
logger( "Can't open mail-blacklist for appending: $!\n" );
382
logger( "Error: ", $short_error || $error );
383
reply( "Your mail could not be processed:\n$error" );
388
logger( "Mail from $header{'from'}\nSubject: $subject\n" );
389
if (is_blacklisted( $header{'from'} )) {
390
logger( "Address is blacklisted, deleting mail.\n" );
393
logger( "Not for me, forwarding to admin\n" );
394
ll_send_mail( $Buildd::Conf::admin_mail,
395
"To: $header{'to'}\n".
396
($header{'cc'} ? "Cc: $header{'cc'}\n" : "").
397
"From: $header{'from'}\n".
398
"Subject: $header{'subject'}\n".
399
"Date: $header{'date'}\n".
400
"Message-Id: $header{'message-id'}\n".
401
($header{'reply-to'} ? "Reply-To: $header{'reply-to'}\n" : "").
402
($header{'in-reply-to'} ? "In-Reply-To: $header{'in-reply-to'}\n" : "").
403
($header{'references'} ? "References: $header{'references'}\n" : "").
404
"Resent-From: $Buildd::gecos <$Buildd::username\@$Buildd::hostname>\n".
405
"Resent-To: $Buildd::Conf::admin_mail\n\n".
411
sub prepare_for_upload ($$) {
414
my( @files, @md5, @missing, @md5fail, $i );
416
my @to_dists = get_dists_from_changes( $changes );
417
if (!@to_dists) { # probably not a valid changes
418
$short_error = $error;
419
$error .= "Couldn't find a valid Distribution: line.\n";
422
$changes =~ /^Files:\s*\n((^[ ]+.*\n)*)/m;
423
foreach (split( "\n", $1 )) {
424
push( @md5, (split( /\s+/, $_ ))[1] );
425
push( @files, (split( /\s+/, $_ ))[5] );
427
if (!@files) { # probably not a valid changes
428
$short_error = $error;
429
$error .= "No files listed in changes.\n";
432
my @wrong_dists = ();
433
foreach my $d (@to_dists) {
434
push( @wrong_dists, $d )
435
if !check_state($pkg, $d, qw(Building Install-Wait Reupload-Wait));
438
$short_error = $error;
439
$error .= "Package $pkg has target distributions @wrong_dists\n".
440
"for which it isn't registered as Building.\n".
441
"Please fix this by either modifying the Distribution: ".
443
"taking the package in those distributions, too.\n";
447
for( $i = 0; $i < @files; ++$i ) {
448
if (! -f "$Buildd::Conf::HOME/build/$files[$i]") {
449
push( @missing, $files[$i] ) ;
452
chomp( my $sum = `md5sum $Buildd::Conf::HOME/build/$files[$i]` );
453
push( @md5fail, $files[$i] ) if (split(/\s+/,$sum))[0] ne $md5[$i];
457
$short_error .= "Missing files for move: @missing\n";
458
$error .= "While trying to move the built package $pkg to upload,\n".
459
"the following files mentioned in the .changes were not found:\n".
464
$short_error .= "md5 failure during move: @md5fail\n";
465
$error .= "While trying to move the built package $pkg to upload,\n".
466
"the following files had bad md5 checksums:\n".
471
my $upload_dir = "$Buildd::Conf::HOME/upload" .
472
(is_for_security( $changes ) ? "-security" : "");
474
if (! -d $upload_dir &&!mkdir( $upload_dir, 0750 )) {
475
$error .= "Cannot create directory $upload_dir";
476
logger( "Cannot create dir $upload_dir\n" );
480
lock_file( "$upload_dir" );
483
if (system "mv $Buildd::Conf::HOME/build/$_ $upload_dir/$_") {
484
logger( "Cannot move $_ to upload dir\n" );
489
$error .= "Could not move all files to upload dir.";
494
$pkg_noep =~ s/_\d*:/_/;
495
my $changes_name = "${pkg_noep}_$Buildd::Conf::arch.changes";
496
unlink( "$Buildd::Conf::HOME/build/$changes_name" )
497
or logger( "Cannot remove ~/build/$changes_name: $!\n" );
498
open( F, ">$upload_dir/$changes_name" );
501
unlock_file( "$upload_dir" );
502
logger( "Moved $pkg to ", basename($upload_dir), "\n" );
505
sub redo_new_version ($$$) {
511
if (open( PIPE,"$Buildd::Conf::sshcmd wanna-build -v ".
512
($Buildd::Conf::wanna_build_dbbase? "--database=$Buildd::Conf::wanna_build_dbbase ":"").
513
"--user=$Buildd::Conf::wanna_build_user --dist=$dist $newv 2>&1 |")) {
515
next if /^wanna-build Revision/ ||
516
/^\S+: Warning: Older version / ||
524
logger( "Can't spawn wanna-build: $!\n" );
525
$error .= "Can't spawn wanna-build: $!\n";
529
logger( "Can't take newer version $newv due to wanna-build errors\n" );
532
logger( "Going to build $newv instead of $oldv\n" );
534
append_to_REDO( $newv, $dist );
543
remove_from_REDO( $pkg );
545
# remove .changes and .deb in build dir (if existing)
547
$pkg_noep =~ s/_\d*:/_/;
548
my $changes = "${pkg_noep}_$Buildd::Conf::arch.changes";
549
if (-f "build/$changes" && open( F, "<build/$changes" )) {
551
my $changetext = <F>;
553
my @files = get_files_from_changes( $changetext );
554
push( @files, $changes );
555
logger( "Purging files: $changes\n" );
556
unlink( map { "build/$_" } @files );
559
# schedule dir for purging
560
($dir = $pkg_noep) =~ s/-[^-]*$//; # remove Debian revision
561
$dir =~ s/_/-/; # change _ to -
562
if (-d "build/chroot-$dist/build/$Buildd::username/$dir") {
563
$dir = "build/chroot-$dist/build/$Buildd::username/$dir";
570
lock_file( "build/PURGE" );
571
if (open( F, ">>build/PURGE" )) {
574
logger( "Scheduled $dir for purging\n" );
577
$error .= "Can't open build/PURGE: $!\n";
578
logger( "Can't open build/PURGE: $!\n" );
580
unlock_file( "build/PURGE" );
583
sub remove_from_upload ($) {
585
my($changes_f, $upload_f, $changes_text, @to_remove);
588
logger( "Remove $pkg from upload dir\n" );
590
$pkg_noep =~ s/_\d*:/_/;
591
$changes_f = "${pkg_noep}_$Buildd::Conf::arch.changes";
592
my $upload_dir = "$Buildd::Conf::HOME/upload";
593
$upload_dir .= "-security" if -f "$upload_dir-security/$changes_f";
595
if (!-f "$upload_dir/$changes_f") {
596
logger( "$changes_f does not exist\n" );
599
if (!open( F, "<$upload_dir/$changes_f" )) {
600
logger( "Cannot open $upload_dir/$changes_f: $!\n" );
603
{ local($/); undef $/; $changes_text = <F>; }
605
@to_remove = get_files_from_changes( $changes_text );
607
($upload_f = $changes_f) =~ s/\.changes$/\.upload/;
608
push( @to_remove, $changes_f, $upload_f );
610
logger( "Removing files:\n", "@to_remove\n" );
611
foreach (@to_remove) {
612
unlink "$upload_dir/$_"
613
or logger( "Can't remove $upload_dir/$_: $!\n" );
617
sub append_to_REDO ($$) {
622
lock_file( "build/REDO" );
624
if (open( F, "build/REDO" )) {
627
if (grep( /^\Q$pkg\E\s/, @pkgs )) {
628
logger( "$pkg is already in REDO -- not rescheduled\n" );
633
if (open( F, ">>build/REDO" )) {
634
print F "$pkg $dist\n";
636
logger( "Scheduled $pkg for rebuild\n" );
639
$error .= "Can't open build/REDO: $!\n";
640
logger( "Can't open build/REDO: $!\n" );
644
unlock_file( "build/REDO" );
647
sub remove_from_REDO ($) {
651
lock_file( "build/REDO" );
652
goto unlock if !open( F, "<build/REDO" );
655
if (!open( F, ">build/REDO" )) {
656
logger( "Can't open REDO for writing: $!\n",
657
"Would write: @pkgs\nminus $pkg\n" );
670
logger( "Deleted $pkg from REDO list.\n" ) if $done;
672
unlock_file( "build/REDO" );
676
sub append_to_SKIP ($) {
680
return if !open( F, "<build/build-progress" );
684
if (grep( /^\s*\Q$pkg\E$/, @lines )) {
685
# pkg is in build-progress, but without a suffix (failed,
686
# successful, currently building), so it can be skipped
687
lock_file( "build/SKIP" );
688
if (open( F, ">>build/SKIP" )) {
691
logger( "Told sbuild to skip $pkg\n" );
693
unlock_file( "build/SKIP" );
697
sub check_is_outdated ($$) {
701
my $have_changes = 0;
703
return 0 if !(%newv = is_outdated( $dist, $package ));
705
$have_changes = 1 if $body_text =~ /^---+\s*BEGIN PGP SIGNED MESSAGE/;
707
# If we have a changes file, we can see which distributions that
708
# package is aimed to. Otherwise, we're out of luck because we can't see
709
# reliably anymore for which distribs the package was for. Let the user
712
# If the package is outdated in all dists we have to consider,
713
# send a plain error message. If only outdated in some of them, send a
714
# modified error that tells to send a restricted changes (with
715
# Distribution: only for those dists where it isn't outdated), or to do
716
# the action manually, because it would be (wrongly) propagated.
717
goto all_outdated if !$have_changes;
719
my @check_dists = ();
720
@check_dists = get_dists_from_changes( $body_text );
722
my @not_outdated = ();
724
foreach (@check_dists) {
725
if (!exists $newv{$_}) {
726
push( @not_outdated, $_ );
729
push( @outdated, $_ );
732
return 0 if !@outdated;
734
$short_error .= "$package ($dist) partially outdated ".
735
"(ok for @not_outdated)\n";
737
"Package $package ($dist) is partially outdated.\n".
738
"The following new versions have appeared in the meantime:\n ".
739
join( "\n ", map { "$_: $newv{$_}" } keys %newv )."\n\n".
740
"Please send a .changes for the following distributions only:\n".
741
" Distribution: ".join( " ", @not_outdated )."\n";
745
$short_error .= "$package ($dist) outdated; new versions ".
746
join( ", ", map { "$_:$newv{$_}" } keys %newv )."\n";
748
"Package $package ($dist) is outdated.\n".
749
"The following new versions have appeared in the meantime:\n ".
750
join( "\n ", map { "$_: $newv{$_}" } keys %newv )."\n";
755
sub is_outdated ($$) {
761
lock_file( "outdated-packages" );
762
goto unlock if !open( F, "<outdated-packages" );
764
my($oldpkg, $newpkg, $t, $d) = split( /\s+/, $_ );
766
if ($oldpkg eq $pkg && $d eq $dist) {
767
$result{$d} = $newpkg;
772
unlock_file( "outdated-packages" );
776
sub register_outdated ($$$) {
783
lock_file( "outdated-packages" );
785
if (open( F, "<outdated-packages" )) {
790
if (!open( F, ">outdated-packages" )) {
791
logger( "Cannot open outdated-packages for writing: $!\n" );
797
my($oldpkg, $newpkg, $t, $d) = split( /\s+/, $_ );
799
next if ($oldpkg eq $oldv && $d eq $dist) || ($now - $t) > 21*24*60*60;
802
print F "$oldv $newv $now $dist\n";
805
unlock_file( "outdated-packages" );
808
sub set_to_failed ($$$) {
814
$text =~ s/^\.$/../mg;
815
$is_bugno = 1 if $text =~ /^\(see #\d+\)$/;
816
return if !check_state( $pkg, $dist, $is_bugno ? "Failed" : "Building" );
819
or (open( STDOUT, ">/dev/null"),
820
exec "$Buildd::Conf::sshcmd wanna-build --failed --no-down-propagation ".
821
"--user=$Buildd::Conf::wanna_build_user ".($Buildd::Conf::wanna_build_dbbase?
822
"--database=$Buildd::Conf::wanna_build_dbbase ":""). "--dist=$dist $pkg");
823
print PIPE "${text}.\n";
826
my $t = "wanna-build --failed failed with status ".exitstatus($?)."\n";
831
logger( "Bug# appended to fail message of $pkg ($dist)\n" );
834
logger( "Set package $pkg ($dist) to Failed\n" );
835
write_stats( "failed", 1 );
839
sub set_to_depwait ($$$) {
845
or (open( STDOUT, ">/dev/null"),
846
exec "$Buildd::Conf::sshcmd wanna-build --dep-wait --no-down-propagation ".
847
"--user=$Buildd::Conf::wanna_build_user ".($Buildd::Conf::wanna_build_dbbase?
848
"--database=$Buildd::Conf::wanna_build_dbbase ":""). "--dist=$dist $pkg");
849
print PIPE "$deps\n";
852
my $t = "wanna-build --dep-wait failed with status ".exitstatus($?)."\n";
857
logger( "Set package $pkg ($dist) to Dep-Wait\nDependencies: $deps\n" );
859
write_stats( "dep-wait", 1 );
867
$answer_cmd = "$Buildd::Conf::sshcmd wanna-build --give-back --no-down-propagation --user=$Buildd::Conf::wanna_build_user ".
868
($Buildd::Conf::wanna_build_dbbase? "--database=$Buildd::Conf::wanna_build_dbbase ":""). "--dist=$dist $pkg";
869
my $answer = `$answer_cmd`;
871
$error .= "wanna-build --give-back failed:\n$answer";
874
logger( "Given back package $pkg ($dist)\n" );
883
$answer_cmd = "$Buildd::Conf::sshcmd wanna-build --no-build --no-down-propagation --user=$Buildd::Conf::wanna_build_user ".
884
($Buildd::Conf::wanna_build_dbbase? "--database=$Buildd::Conf::wanna_build_dbbase ":""). "--dist=$dist $pkg";
885
my $answer = `$answer_cmd`;
887
$error .= "no-build failed:\n$answer";
890
logger( "Package $pkg ($dist) to set Not-For-Us\n" );
892
write_stats( "no-build", 1 );
895
sub get_fail_msg ($$) {
901
if (open( PIPE, "$Buildd::Conf::sshcmd wanna-build --info --dist=$dist ".
902
($Buildd::Conf::wanna_build_dbbase? "--database=$Buildd::Conf::wanna_build_dbbase ":""). "$pkg |" )) {
905
if (/^\s*Old-Failed\s*:/) {
909
if (/^----+\s+\S+\s+----+$/) {
921
$error .= "Couldn't find Old-Failed in info for $pkg\n";
922
return "Same as previous version (couldn't extract the text)\n";
925
$error .= "Couldn't start wanna-build --info: $!\n";
926
return "Same as previous version (couldn't extract the text)\n";
930
sub check_state ($$@) {
933
my @wanted_states = @_;
936
$pkgv =~ /^([^_]+)_(.+)/;
937
my ($pkg, $vers) = ($1, $2);
938
if (!open( PIPE, "$Buildd::Conf::sshcmd wanna-build --info ".
939
($Buildd::Conf::wanna_build_dbbase? "--database=$Buildd::Conf::wanna_build_dbbase ":""). "--dist=$dist $pkg |" )){
940
$error .= "Couldn't start wanna-build --info: $!\n";
944
my ($av, $as, $ab, $an);
946
$av = $1 if /^\s*Version\s*:\s*(\S+)/;
947
$as = $1 if /^\s*State\s*:\s*(\S+)/;
948
$ab = $1 if /^\s*Builder\s*:\s*(\S+)/;
949
$an = $1 if /^\s*Binary-NMU-Version\s*:\s*(\d+)/;
953
my $msg = "$pkgv($dist) check_state(@wanted_states): ";
954
$av = binNMU_version($av,$an) if (defined $an);
956
$error .= $msg."version $av registered as $as\n";
959
if (!Buildd::isin( $as, @wanted_states)) {
960
$error .= $msg."state is $as\n";
963
if ($as eq "Building" && $ab ne $Buildd::Conf::wanna_build_user) {
964
$error .= $msg."is building by $ab\n";
970
sub check_building_any_dist ($) {
975
$pkgv =~ /^([^_]+)_(.+)/;
976
my ($pkg, $vers) = ($1, $2);
977
if (!open( PIPE, "$Buildd::Conf::sshcmd wanna-build --info ".
978
($Buildd::Conf::wanna_build_dbbase? "--database=$Buildd::Conf::wanna_build_dbbase ":""). "--dist=all $pkg |" )){
979
$error .= "Couldn't start wanna-build --info: $!\n";
984
{ local ($/); $text = <PIPE>; }
987
while( $text =~ /^\Q$pkg\E\((\w+)\):(.*)\n((\s.*\n)*)/mg ) {
988
my ($dist, $rest, $info) = ($1, $2, $3);
989
next if $rest =~ /not registered/;
991
$av = $1 if $info =~ /^\s*Version\s*:\s*(\S+)/mi;
992
$as = $1 if $info =~ /^\s*State\s*:\s*(\S+)/mi;
993
$ab = $1 if $info =~ /^\s*Builder\s*:\s*(\S+)/mi;
994
push( @dists, $dist )
995
if $av eq $vers && $as eq "Building" &&
996
$ab eq $Buildd::Conf::wanna_build_user;
1001
sub get_files_from_changes ($) {
1002
my $changes_text = shift;
1003
my(@filelines, @files);
1005
$changes_text =~ /^Files:\s*\n((^[ ]+.*\n)*)/m;
1006
@filelines = split( "\n", $1 );
1007
foreach (@filelines) {
1008
push( @files, (split( /\s+/, $_ ))[5] );
1013
sub is_for_non_us ($$) {
1015
my $changes_text = shift;
1019
# check if there's a "non-US" in the sections
1020
$changes_text =~ /^Files:\s*\n((^[ ]+.*\n)*)/m;
1021
my @filelines = split( "\n", $1 );
1022
foreach (@filelines) {
1023
return 1 if (split( /\s+/, $_ ))[3] =~ /non-us/i;
1028
sub is_for_security ($) {
1029
my $changes_text = shift;
1031
# check if there's a "-security" in the distribution
1032
my @dists = get_dists_from_changes( $changes_text );
1034
return 1 if /-security$/;
1039
sub get_dists_from_changes ($) {
1040
my $changes_text = shift;
1042
$changes_text =~ /^Distribution:\s*(.*)\s*$/mi;
1043
return split( /\s+/, $1 );
1048
my( $to, $subj, $quoting );
1050
$to = $header{'reply-to'} || $header{'from'};
1051
$subj = $header{'subject'};
1052
$subj = "Re: $subj" if $subj !~ /^Re\S{0,2}:/;
1053
($quoting = $body_text) =~ s/\n+$/\n/;
1054
$quoting =~ s/^/> /mg;
1056
send_mail( $to, $subj, "$quoting\n$text",
1057
"In-Reply-To: $header{'message-id'}\n" );
1060
sub is_blacklisted ($) {
1064
$addr = $1 if $addr =~ /<(.*)>/;
1065
return 0 if !open( BL, "<mail-blacklist" );
1068
if ($addr =~ /$_$/) {
1077
sub add_error_mail () {
1082
if (open( F, "<mail-errormails" )) {
1087
shift @em while @em && ($now - $em[0]) > $Buildd::Conf::error_mail_window;
1090
open( F, ">mail-errormails" );
1091
print F join( "\n", @em ), "\n";
1095
unlink( "mail-errormails" );