diff options
Diffstat (limited to 'lib/Buildd/Uploader.pm')
-rw-r--r-- | lib/Buildd/Uploader.pm | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/lib/Buildd/Uploader.pm b/lib/Buildd/Uploader.pm new file mode 100644 index 0000000..302f5da --- /dev/null +++ b/lib/Buildd/Uploader.pm @@ -0,0 +1,274 @@ +# buildd-uploader: upload finished packages for buildd +# Copyright © 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> +# Copyright © 2009 Roger Leigh <rleigh@debian.org> +# Copyright © 2005 Ryan Murray <rmurray@debian.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# <http://www.gnu.org/licenses/>. +# +####################################################################### + +package Buildd::Uploader; + +use strict; +use warnings; + +use Buildd qw(lock_file unlock_file unset_env exitstatus send_mail); +use Buildd::Base; +use Buildd::Conf qw(); + +BEGIN { + use Exporter (); + our (@ISA, @EXPORT); + + @ISA = qw(Exporter Buildd::Base); + + @EXPORT = qw(); +} + +sub new { + my $class = shift; + my $conf = shift; + + my $self = $class->SUPER::new($conf); + bless($self, $class); + + $self->set('Uploader Lock', undef); + $self->set('Uploaded Pkgs', {}); + + $self->open_log(); + + return $self; +} + +sub run { + my $self = shift; + + unset_env(); + + $self->set('Uploader Lock', + lock_file("$main::HOME/buildd-uploader", 1)); + + if (!$self->get('Uploader Lock')) { + $self->log("exiting; another buildd-uploader is still running"); + return 1; + } + + for my $queue_config (@{$self->get_conf('UPLOAD_QUEUES')}) { + $self->upload( + $queue_config->get('DUPLOAD_LOCAL_QUEUE_DIR'), + $queue_config->get('DUPLOAD_ARCHIVE_NAME')); + } + + my $uploaded_pkgs = $self->get('Uploaded Pkgs'); + + foreach my $archdist (keys %{$uploaded_pkgs}) { + $self->log("Set to Uploaded($archdist):$uploaded_pkgs->{$archdist}"); + } + + return 0; +} + +sub uploaded ($@) { + my $self = shift; + my $pkg = shift; + my $arch_name = shift; + my $dist_name = shift; + + my $msgs = ""; + + my $dist_config = $self->get_arch_dist_config_by_name($arch_name, $dist_name); + my $db = $self->get_db_handle($dist_config); + + my $pipe = $db->pipe_query('--uploaded', $pkg); + + if ($pipe) { + while(<$pipe>) { + if (!/^(\S+): Propagating new state /) { + $msgs .= $_; + } + } + close($pipe); + if ($msgs or $?) { + $self->log($msgs) if $msgs; + $self->log("wanna-build --uploaded failed with status ", + exitstatus($?), "\n" ) + if $?; + } else { + my $archdist_name = "$arch_name/$dist_name"; + $self->get('Uploaded Pkgs')->{$archdist_name} .= " $pkg"; + } + } else { + $self->log("Can't spawn wanna-build --uploaded: $!\n"); + } +} + +sub upload ($$) { + my $self = shift; + my $udir = shift; + my $upload_to = shift; + + chdir( "$main::HOME/$udir" ) || return; + lock_file( "$main::HOME/$udir" ); + + my( $f, $g, @before, @after ); + + foreach $f (<*.changes>) { + ($g = $f) =~ s/\.changes$/\.upload/; + push( @before, $f ) if ! -f $g; + } + + unlock_file( "$main::HOME/$udir" ); + + if (!@before) { + $self->log("Nothing to do for $udir\n"); + return; + } + + $self->log(scalar(@before), " jobs to upload in $udir: @before\n"); + + foreach $f (@before) { + ($g = $f) =~ s/\.changes$/\.upload/; + my $logref = $self->do_dupload( $upload_to, $f ); + + if (defined $logref and scalar(@$logref) > 0) { + my $line; + + foreach $line (@$logref) { + $self->log($line); + } + } + + if ( -f $g ) { + if (!open( F, "<$f" )) { + $self->log("Cannot open $f: $!\n"); + next; + } + my $text; + { local($/); undef $/; $text = <F>; } + close( F ); + if ($text !~ /^Architecture:\s*(.*)\s*$/m) { + $self->log("$f doesn't have a Architecture: field\n"); + next; + } + my @archs = split( /\s+/, $1 ); + if ($text !~ /^Distribution:\s*(.*)\s*$/m) { + $self->log("$f doesn't have a Distribution: field\n"); + next; + } + my @dists = split( /\s+/, $1 ); + my ($version,$source,$pkg); + if ($text =~ /^Version:\s*(\S+)\s*$/m) { + $version = $1; + } + if ($text =~ /^Source:\s*(\S+)(?:\s+\(\S+\))?\s*$/m) { + $source = $1; + } + if (defined($version) and defined($source)) { + $pkg = "${source}_$version"; + } else { + ($pkg = $f) =~ s/_\S+\.changes$//; + } + $self->uploaded($pkg, @archs, @dists); + } else { + push (@after, $f); + } + } + + if (@after) { + $self->log("The following jobs were not processed (successfully):\n" . + "@after\n"); + } + else { + $self->log("dupload successful.\n"); + } + $self->write_stats("uploads", scalar(@before) - scalar(@after)); +} + +sub do_dupload ($@) { + my $self = shift; + my $upload_to = shift; + + my @jobs = @_; + my @log; + local( *PIPE ); + my( $current_job, $current_file, @failed, $errs ); + + if (!open( PIPE, "dupload -k --to $upload_to @jobs </dev/null 2>&1 |" )) { + return "Cannot spawn dupload: $!"; + } + + my $dup_log = ""; + while( <PIPE> ) { + $dup_log .= $_; + chomp; + if (/^\[ job \S+ from (\S+\.changes)$/) { + $current_job = $1; + } + elsif (/^warning: MD5sum mismatch for (\S+), skipping/i) { + my $f = $1; + push( @log, "dupload error: md5sum mismatch for $f\n" ); + $errs .= "md5sum mismatch on file $f ($current_job)\n"; + push( @failed, $current_job ); + } + elsif (/^\[ Uploading job (\S+)$/) { + $current_job = "$1.changes"; + } + elsif (/dupload fatal error: Can't upload (\S+)/i || + /^\s(\S+).*scp: (.*)$/) { + my($f, $e) = ($1, $2); + push( @log, "dupload error: upload error for $f\n" ); + push( @log, "($e)\n" ) if $e; + $errs .= "upload error on file $f ($current_job)\n"; + push( @failed, $current_job ); + } + elsif (/Timeout at [\S]+ line [\d]+$/) { + $errs .= "upload timeout on file $current_job\n"; + push( @failed, $current_job ); + } + elsif (/^\s(\S+)\s+[\d.]+ kB /) { + $current_file = $1; + } + } + close( PIPE ); + if ($?) { + if (($? >> 8) == 141) { + push( @log, "dupload error: SIGPIPE (broken connection)\n" ); + $errs .= "upload error (broken connection) during ". + "file $current_file ($current_job)\n"; + push( @failed, $current_job ); + } + else { + push( @log, "dupload exit status ". exitstatus($?) ); + $errs .= "dupload exit status ".exitstatus($?)."\n"; + push( @failed, $current_job ); + } + } + + foreach (@failed) { + my $u = $_; + $u =~ s/\.changes$/\.upload/; + unlink( $u ); + push( @log, "Removed $u due to upload errors.\n" ); + $errs .= "Removed $u to reupload later.\n"; + } + + if ($errs) { + $errs .= "\nComplete output from dupload:\n\n$dup_log"; + send_mail($self->get_conf('ADMIN_MAIL'), "dupload errors", $errs); + } + return \@log; +} + +1; |