aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Iurt/Chroot.pm87
-rw-r--r--lib/Iurt/Config.pm57
-rw-r--r--lib/Iurt/Emi.pm26
-rw-r--r--lib/Iurt/Process.pm59
-rw-r--r--lib/Iurt/Queue.pm112
-rw-r--r--lib/Iurt/RPM.pm55
-rwxr-xr-xlib/Iurt/Ulri.pm160
-rw-r--r--lib/Iurt/Urpmi.pm159
-rw-r--r--lib/Iurt/Util.pm2
9 files changed, 498 insertions, 219 deletions
diff --git a/lib/Iurt/Chroot.pm b/lib/Iurt/Chroot.pm
index 1427aa3..8a2e04b 100644
--- a/lib/Iurt/Chroot.pm
+++ b/lib/Iurt/Chroot.pm
@@ -96,8 +96,12 @@ sub clean_and_build_chroot {
}
if ($run->{additional_media} && $run->{additional_media}{repository}) {
- _setup_additional_media($run, $config, $chroot) or return;
+ if (!_setup_additional_media($run, $config, $chroot)) {
+ _clean_mounts($run, $config, $chroot);
+ return;
+ }
}
+
1;
}
@@ -232,7 +236,7 @@ sub clean_all_chroot_tmp {
}
foreach (readdir($dir)) {
/$prefix/ or next;
- clean_chroot($run, $config, "$chroot_dir/$_");
+ clean_chroot("$chroot_dir/$_", $run, $config);
}
closedir $dir;
}
@@ -268,12 +272,13 @@ sub check_mounted {
}
sub check_chroot_need_update {
- my ($tmp_chroot, $run) = @_;
+ my ($tmp_chroot, $run, $config) = @_;
- my $tmp_urpmi = mktemp("$tmp_chroot/tmp.XXXXXX");
+ sudo($config, '--mkdir', "-m", 01777, "$tmp_chroot/tmp");
+ my $tmp_urpmi = mktemp("$tmp_chroot/tmp/tmp.XXXXXX");
mkdir_p("$tmp_urpmi/tmp");
my @installed_pkgs = grep { !/^gpg-pubkey/ } chomp_(cat_("$tmp_chroot/var/log/qa"));
- my @available_pkgs = chomp_(`urpmq --urpmi-root $tmp_urpmi --use-distrib $run->{urpmi}{distrib_url} --list -f 2>/dev/null`);
+ my @available_pkgs = chomp_(`urpmq --urpmi-root $tmp_urpmi --use-distrib $run->{urpmi}{distrib_url} --list -f`);
my @removed_pkgs = difference2(\@installed_pkgs, \@available_pkgs);
rm_rf($tmp_urpmi);
@@ -303,16 +308,6 @@ sub create_build_chroot {
$ret = create_build_chroot_tar($chroot, $chroot_ref, $run, $config);
}
- if ($ret) {
- my $urpmi = $run->{urpmi};
- if ($urpmi->{use__urpmi_root} && !$run->{chrooted_urpmi}) {
- if (!$urpmi->add_media__urpmi_root($chroot, $config->{base_media})) {
- plog('ERROR', "urpmi.addmedia --urpmi-root failed");
- return;
- }
- }
- }
-
if ($ret && $use_netns) {
sudo($config, '--netns_create', $chroot);
}
@@ -322,47 +317,44 @@ sub create_build_chroot {
sub create_build_chroot_tar {
my ($chroot, $chroot_tar, $run, $config) = @_;
- my $tmp_chroot = mktemp("$chroot.tmp.XXXXXX");
my $rebuild;
- my $clean = sub {
- plog("Remove temporary chroot");
- sudo($config, '--rm', '-r', $tmp_chroot);
- };
plog('NOTIFY', "creating chroot");
- mkdir_p($tmp_chroot);
if (!-f $chroot_tar) {
plog("rebuild chroot tarball");
$rebuild = 1;
} elsif (!$run->{fixed_media}) {
- plog('DEBUG', "decompressing /var/log/qa from $chroot_tar in $tmp_chroot");
- sudo($config, '--untar', $chroot_tar, $tmp_chroot, "./var/log/qa");
- $rebuild = check_chroot_need_update($tmp_chroot, $run);
+ my $tmp_chroot = mktemp("$chroot.tmp.XXXXXX");
+ sudo($config, "--mkdir", "-p", "$tmp_chroot");
+ plog('DEBUG', "decompressing /var/log/qa from $chroot_tar in $tmp_chroot");
+ sudo($config, '--untar', $chroot_tar, $tmp_chroot, "./var/log/qa");
+ $rebuild = check_chroot_need_update($tmp_chroot, $run, $config);
+ sudo($config, '--rm', '-r', $tmp_chroot);
}
+ sudo($config, '--rm', '-r', $chroot);
+ # Create this directory as root as it will be / of the chroot
+ sudo($config, "--mkdir", "-p", "$chroot");
if ($rebuild) {
- sudo($config, '--rm', '-r', $chroot);
- if (!build_chroot($run, $config, $tmp_chroot)) {
+ if (!build_chroot($run, $config, $chroot)) {
plog('NOTIFY', "creating chroot failed.");
- $clean->();
+ sudo($config, '--rm', '-r', $chroot);
return;
}
- sudo($config, "--tar", $chroot_tar, $tmp_chroot);
- # This rename may fail if for example tmp chroots are in another FS
- # This does not matter as it will then be rm + untar
- rename $tmp_chroot, $chroot;
- }
-
- if (!-d $chroot) {
- plog('DEBUG', "recreate chroot $chroot");
- plog('NOTIFY', "recreate chroot");
- mkdir_p $chroot;
+ plog('NOTIFY', "chroot recreated in $chroot");
+ my $tmp_tar = mktemp("$chroot_tar.tmp.XXXXXX");
+ sudo($config, "--tar", $chroot_tar, $chroot);
+ if (rename($tmp_tar, $chroot_tar)) {
+ plog('NOTIFY', "archive creation failed.");
+ unlink($tmp_tar);
+ return;
+ }
+ plog('NOTIFY', "chroot archived in $chroot_tar");
+ } else {
sudo($config, '--untar', $chroot_tar, $chroot);
- plog('NOTIFY', "chroot recreated in $chroot_tar (live in $chroot)");
+ plog('NOTIFY', "chroot recreated in $chroot (from $chroot_tar)");
}
-
- $clean->();
1;
}
@@ -373,7 +365,7 @@ sub create_build_chroot_btrfs {
plog('NOTIFY', "creating btrfs chroot");
# TODO: Handle $run{fixed_media}
- if (check_chroot_need_update($chroot_ref, $run)) {
+ if (check_chroot_need_update($chroot_ref, $run, $config)) {
sudo($config, '--btrfs_delete', $chroot_ref);
if (!sudo($config, '--btrfs_create', $chroot_ref)) {
plog('ERROR', "creating btrfs subvolume failed.");
@@ -408,16 +400,13 @@ sub build_chroot {
# install chroot
my $urpmi = $run->{urpmi}; # perl_checker: $urpmi = Iurt::Urpmi->new
- if ($urpmi->{use__urpmi_root}) {
- if (!$urpmi->add_media__urpmi_root($tmp_chroot, $config->{base_media})) {
- plog('ERROR', "urpmi.addmedia --urpmi-root failed");
- return 0;
- }
- $urpmi->set_command__urpmi_root($tmp_chroot);
- } else {
- $urpmi->set_command__use_distrib($tmp_chroot);
+ if (!$urpmi->add_media__urpmi_root($tmp_chroot, $config->{base_media})) {
+ plog('ERROR', "urpmi.addmedia --urpmi-root failed");
+ return 0;
}
+ $urpmi->set_command($tmp_chroot);
+
# (blino) install meta-task first for prefer.vendor.list to be used
foreach my $packages ([ 'meta-task' ], $config->{basesystem_packages}) {
if (!$urpmi->install_packages(
diff --git a/lib/Iurt/Config.pm b/lib/Iurt/Config.pm
index 32b87e4..3b8bbe1 100644
--- a/lib/Iurt/Config.pm
+++ b/lib/Iurt/Config.pm
@@ -1,7 +1,6 @@
package Iurt::Config;
use base qw(Exporter);
-use RPM4::Header;
use Data::Dumper;
use MDK::Common;
use Iurt::Util qw(plog);
@@ -17,8 +16,6 @@ our @EXPORT = qw(
get_date
get_prefix
get_author_email
- check_arch
- check_noarch
get_package_prefix
get_mandatory_arch
get_target_arch
@@ -26,15 +23,13 @@ our @EXPORT = qw(
);
our %arch_comp = (
- 'i586' => { 'i386' => 1, 'i486' => 1, 'i586' => 1 },
- 'i686' => { 'i386' => 1, 'i486' => 1, 'i586' => 1, 'i686' => 1 },
- 'x86_64' => { 'x86_64' => 1 },
- 'ppc' => { 'ppc' => 1 },
- 'ppc64' => { 'ppc' => 1, 'ppc64' => 1 },
+ 'i586' => { 'i386' => 1, 'i486' => 1 },
+ 'i686' => { 'i386' => 1, 'i486' => 1, 'i586' => 1 },
+ 'ppc64' => { 'ppc' => 1 },
'armv5tejl' => { 'armv5tl' => 1 },
'armv5tel' => { 'armv5tl' => 1 },
- 'armv5tl' => { 'armv5tl' => 1 },
- 'armv7l' => { 'armv5tl' => 1, 'armv7hl' => 1, 'armv7hnl' => 1 },
+ 'armv7l' => { 'armv5tl' => 1, 'armv7hnl' => 1 },
+ 'armv8l' => { 'armv5tl' => 1, 'armv7hl' => 1, 'armv7hnl' => 1 },
);
@@ -151,48 +146,6 @@ sub get_author_email {
return $authoremail;
}
-sub check_noarch {
- my ($rpm) = @_;
- my $hdr = RPM4::Header->new($rpm);
-
- # Stupid rpm doesn't return an empty list so we must check for (none)
-
- my ($build_archs) = $hdr->queryformat('%{BUILDARCHS}');
-
- if ($build_archs ne '(none)') {
- ($build_archs) = $hdr->queryformat('[%{BUILDARCHS} ]');
- my @list = split ' ', $build_archs;
- return 1 if member('noarch', @list);
- }
-
- return 0;
-}
-
-sub check_arch {
- my ($rpm, $arch) = @_;
- my $hdr = RPM4::Header->new($rpm);
-
- # Stupid rpm doesn't return an empty list so we must check for (none)
-
- my ($exclusive_arch) = $hdr->queryformat('%{EXCLUSIVEARCH}');
-
- if ($exclusive_arch ne '(none)') {
- ($exclusive_arch) = $hdr->queryformat('[%{EXCLUSIVEARCH} ]');
- my @list = split ' ', $exclusive_arch;
- return 0 unless member($arch, @list);
- }
-
- my ($exclude_arch) = $hdr->queryformat('[%{EXCLUDEARCH} ]');
-
- if ($exclude_arch ne '(none)') {
- ($exclude_arch) = $hdr->queryformat('[%{EXCLUDEARCH} ]');
- my @list = split ' ', $exclude_arch;
- return 0 if member($arch, @list);
- }
-
- return 1;
-}
-
sub get_mandatory_arch {
my ($config, $target) = @_;
find { ref($_) eq 'ARRAY' } $config->{mandatory_arch},
diff --git a/lib/Iurt/Emi.pm b/lib/Iurt/Emi.pm
index 851307c..bf76a64 100644
--- a/lib/Iurt/Emi.pm
+++ b/lib/Iurt/Emi.pm
@@ -6,12 +6,14 @@ use Iurt::Config qw(get_author_email get_mandatory_arch get_target_arch);
use Iurt::Mail qw(sendmail);
use Iurt::Queue qw(check_if_all_archs_processed);
use Iurt::Util qw(plog);
+use MDK::Common::File qw(touch);
use MDK::Common::Func qw(find);
use MDK::Common::DataStructure qw(difference2);
use strict;
our @EXPORT = qw(
find_prefixes_ready_to_upload
+ record_uploaded_packages
upload_prefix_in_media
);
@@ -150,11 +152,10 @@ sub upload_prefix_in_media {
plog('OK', " uploading $rpm in $done/$path");
}
- # This should not happen :(
+ # When a package is not marked as noarch but only has noarch subpackages, there will be nothing
+ # left to upload when it finishes building on non mandaory arch.
return unless @packages;
- $user ||= $config->{upload_user};
-
my $command = generate_upload_command($prefix, $media, $target, $user, \@packages, $o_finish, "$done$path/$youri_file");
plog('DEBUG', "running $command");
if (!system($command)) {
@@ -193,3 +194,22 @@ sub upload_prefix_in_media {
}
}
}
+
+sub record_uploaded_packages {
+ my ($config, $pkg_tree, $prefix, $media) = @_;
+ my $done = "$config->{queue}/done";
+ my $path = $pkg_tree->{$prefix}{media}{$media}{path};
+
+ my %arches;
+ foreach my $pkg (@{$pkg_tree->{$prefix}{media}{$media}{rpms}}) {
+ my ($arch) = $pkg =~ /\.([^.]*)\.rpm$/;
+ $arches{$arch} = 1 unless $arch eq 'src';
+ }
+ # Only keep noarch if it's the only architecture
+ delete $arches{'noarch'} if 1 < keys %arches;
+
+ foreach my $arch (keys %arches) {
+ touch("$done/$path/${prefix}_$arch.uploaded");
+ }
+ touch("$done/$path/$prefix.upload");
+}
diff --git a/lib/Iurt/Process.pm b/lib/Iurt/Process.pm
index 46b8de2..c234d0b 100644
--- a/lib/Iurt/Process.pm
+++ b/lib/Iurt/Process.pm
@@ -14,8 +14,8 @@ our @EXPORT = qw(
clean_process
check_pid
perform_command
- set_alarm_message
sudo
+ wait_for_lock
);
my $sudo = '/usr/bin/sudo';
@@ -24,6 +24,7 @@ my $sudo = '/usr/bin/sudo';
Check that there is no other program running and create a pidfile lock
I<$run> current running options
+I<$exit> whether to exit when the lock is in use
Return true.
=cut
@@ -32,7 +33,7 @@ Return true.
# should be designed
sub check_pid {
- my ($run) = @_;
+ my ($run, $exit) = @_;
my $pidfile = "$run->{pidfile_home}/$run->{pidfile}";
@@ -59,9 +60,7 @@ sub check_pid {
if ($time < time()-7200 || $state eq 'Z') {
my $i;
- my $msg = "another instance [$pid] is too old, killing it";
- set_alarm_message($msg);
- plog('WARN', $msg);
+ plog('WARN', "another instance [$pid] is too old, killing it");
while ($i < 5 && getpgrp $pid != -1) {
kill_for_good($pid);
@@ -69,9 +68,10 @@ sub check_pid {
sleep 1;
}
} else {
- plog('WARN', "another instance [$pid] is already running for ",
- time()-$time, " seconds");
- exit();
+ plog('WARN', "another instance [$pid] is already running for",
+ time()-$time, "seconds");
+ exit() if $exit;
+ return;
}
} else {
plog('WARN', "cleaning stale lockfile");
@@ -84,6 +84,20 @@ sub check_pid {
$pidfile;
}
+sub wait_for_lock {
+ my ($run) = @_;
+
+ plog('INFO', 'Waiting for ulri lock to be available');
+ my $delay = 10;
+ my $pidfile = check_pid($run, 0);
+ while (!defined($pidfile)) {
+ plog('WARN', "waiting $delay seconds before retrying");
+ sleep $delay;
+ $pidfile = check_pid($run, 0);
+ }
+
+ $pidfile;
+}
sub fork_to_monitor {
my ($run, $config, $logfile, %opt) = @_;
@@ -105,18 +119,14 @@ sub fork_to_monitor {
my (@stat) = stat $logfile;
if ($stat[7] > $size_limit) {
# FIXME: we left runaway processes (eg: urpmi)
- my $msg = "Killing current command because of log size exceeding limit ($stat[7] > $config->{log_size_limit})";
- set_alarm_message($msg);
- plog('ERROR', $msg);
+ plog('ERROR', "Killing current command because of log size exceeding limit ($stat[7] > $config->{log_size_limit})");
kill 14, "-$parent_pid";
exit();
}
if ($opt{stalled_timeout} && $stat[9] && $stat[9] + $opt{stalled_timeout} < time()) {
# If nothing was written to the logfile for more than stalled_timeout, check if the system seems busy
if ((getload())[1] < 0.5) {
- my $msg = "Killing current command because it seems blocked";
- set_alarm_message($msg);
- plog('ERROR', $msg);
+ plog('ERROR', "Killing current command because it seems blocked");
kill 14, "-$parent_pid";
exit();
}
@@ -125,8 +135,7 @@ sub fork_to_monitor {
my $df = df $opt{log};
if ($df->{per} >= 99) {
# FIXME: we left runaway processes (eg: urpmi)
- set_alarm_message(my $msg = "Killing current command because running out of disk space at $opt{log} (only $df->{bavail}KB left)");
- plog('ERROR', $msg);
+ plog('ERROR', "Killing current command because running out of disk space at $opt{log} (only $df->{bavail}KB left)");
kill 14, "-$parent_pid";
exit();
}
@@ -192,7 +201,7 @@ sub handle_wait_regexp {
sub generate_comment {
my ($run, $config, $output, $command, $comment, $pipe, $kill, %opt) = @_;
if ($kill && $opt{type} ne 'shell') {
- $comment = "Command killed after $opt{timeout}s: $command\n";
+ $comment = "Command killed: $command\n";
my ($cmd_to_kill) = $command =~ /sudo(?: chroot \S+)? (.*)/;
clean_process($cmd_to_kill);
} elsif ($pipe) {
@@ -210,13 +219,6 @@ sub generate_comment {
}
}
-my $alarm_message;
-
-sub set_alarm_message {
- my ($msg) = @_;
- $alarm_message = $msg;
-}
-
=head2 perform_command($command, $run, $config, %opt)
Run a command and check various running parameters such as log size, timeout...
@@ -258,19 +260,18 @@ sub perform_command {
my $retry = $opt{retry} || 1;
my $call_ret = 1;
my ($err, $try);
- my $logfile = "$opt{log}/$opt{logname}.$run->{run}.log";
+ my $logfile = "$opt{log}/$opt{logname}.$run->{my_arch}.$run->{run}.log";
my $max_retry = max($config->{max_command_retry}, $retry);
while ($retry) {
$try++;
- $logfile = "$opt{log}/$opt{logname}-$try.$run->{run}.log" if $opt{retry} > 1;
+ $logfile = "$opt{log}/$opt{logname}-$try.$run->{my_arch}.$run->{run}.log" if $opt{retry} > 1;
my $pid = $opt{log} ? fork_to_monitor($run, $config, $logfile, %opt) : 0;
eval {
# handle timeout:
- set_alarm_message("Timeout! (timeout was $opt{timeout})");
local $SIG{ALRM} = sub {
- print $alarm_message, "\n";
+ print "Killed! (probably because of the $opt{timeout} timeout)\n";
$kill = 1;
die "alarm\n"; # NB: \n required
};
@@ -306,7 +307,6 @@ sub perform_command {
$err = 0 if any { $_ == $err } @{$opt{error_ok}};
# kill pid watching log file size
- set_alarm_message("kill pid watching log file size");
kill_for_good($pid) if $pid;
if ($perl_err) { # timed out
@@ -382,7 +382,6 @@ sub kill_for_good {
my ($pid) = @_;
# try SIGALARM first:
- set_alarm_message("Killing current command because it seems blocked");
kill 14, $pid;
sleep 1;
waitpid(-1, POSIX::WNOHANG);
diff --git a/lib/Iurt/Queue.pm b/lib/Iurt/Queue.pm
index 3930ca4..e78bd39 100644
--- a/lib/Iurt/Queue.pm
+++ b/lib/Iurt/Queue.pm
@@ -3,8 +3,9 @@ package Iurt::Queue;
use base qw(Exporter);
use File::Copy 'move';
use File::Path 'make_path';
+use File::stat 'stat';
use Iurt::Config qw(get_mandatory_arch get_target_arch);
-use Iurt::File qw(read_line);
+use Iurt::File qw(read_line create_file);
use Iurt::Util qw(plog);
use MDK::Common qw(cat_ find member partition);
use strict;
@@ -14,6 +15,10 @@ our @EXPORT = qw(
cleanup_failed_build
check_if_all_archs_processed
check_if_mandatory_arch_failed
+ load_lock_file_data
+ record_bot_complete
+ remove_bot_from_package
+ schedule_next_retry
);
sub apply_to_upload_tree {
@@ -145,6 +150,51 @@ sub cleanup_failed_build {
}
}
+sub load_lock_file_data {
+ my ($ent, $lock_path, $media, $config) = @_;
+ if ($lock_path !~ /\/(\d{14}\.\w+\.\w+\.\d+)_([\w-]+)\.(\w+)\.([\w-]+)\.(\d{14})\.(\d+)\.lock$/) {
+ plog('ERROR', "invalid lock file name: $lock_path");
+ return;
+ }
+ my ($prefix, $arch, $bot, $host, $date, $pid) = ($1, $2, $3, $4, $5, $6);
+
+ $arch = $config->{arch_translation}{$arch} if $config->{arch_translation}{$arch};
+ plog('DEBUG', "found lock on $host/$arch for $prefix");
+
+ if ($arch =~ /noarch/) {
+ plog('DEBUG', "... and $prefix is noarch");
+ $ent->{media}{$media}{arch}{noarch} = 1;
+ $arch =~ s/-.*//;
+ }
+
+ $ent->{media}{$media}{arch}{$arch} = 1;
+
+ my $time = read_line($lock_path);
+ $time = (split ' ', $time)[2];
+ push @{$ent->{media}{$media}{bot}}, {
+ bot => $bot,
+ host => $host,
+ date => $date,
+ pid => $pid,
+ 'arch' => $arch,
+ 'time' => $time
+ };
+}
+
+sub remove_bot_from_package {
+ my ($ent, $media, $host, $pid) = @_;
+ @{$ent->{media}{$media}{bot}} = grep { $_->{host} ne $host || $_->{pid} != $pid} @{$ent->{media}{$media}{bot}};
+}
+
+sub record_bot_complete {
+ my ($run, $bot, $arch, $lock_file, $prefix, $ent, $media, $host, $pid) = @_;
+ plog('INFO', "delete lock file for $prefix on $host/$arch");
+ unlink $lock_file;
+ $run->{bot}{$host}{$bot} = 0;
+ remove_bot_from_package($ent, $media, $host, $pid);
+ $ent->{media}{$media}{arch}{$arch} = 0;
+}
+
sub get_upload_tree_state {
our ($config) = @_;
@@ -170,33 +220,13 @@ sub get_upload_tree_state {
$pkg_tree{$prefix}{srpm_name}{$name} = $srpm;
}
- if ($r =~ /(\d{14}\.\w+\.\w+\.\d+)_([\w-]+)\.(\w+)\.(\w+)\.(\d{14})\.(\d+)\.lock$/) {
- my ($prefix, $arch, $bot, $host, $date, $pid) = ($1, $2, $3, $4, $5, $6);
+ if ($r =~ /(\d{14}\.\w+\.\w+\.\d+)_([\w-]+)\.(\w+)\.([\w-]+)\.(\d{14})\.(\d+)\.lock$/) {
+ my $prefix = $1;
# Set path here too has we may have a lock without the src.rpm
$pkg_tree{$prefix}{media}{$media}{path} = "/$f/$m/$s";
- $arch = $config->{arch_translation}{$arch} if $config->{arch_translation}{$arch};
- plog('DEBUG', "found lock on $host/$arch for $prefix");
-
- if ($arch =~ /noarch/) {
- plog('DEBUG', "... and $prefix is noarch");
- $pkg_tree{$prefix}{media}{$media}{arch}{noarch} = 1;
- $arch =~ s/-.*//;
- }
-
- $pkg_tree{$prefix}{media}{$media}{arch}{$arch} = 1;
-
- my $time = read_line("$todo/$f/$m/$s/$r");
- $time = (split ' ', $time)[2];
- push @{$pkg_tree{$prefix}{media}{$media}{bot}}, {
- bot => $bot,
- host => $host,
- date => $date,
- pid => $pid,
- 'arch' => $arch,
- 'time' => $time
- };
+ load_lock_file_data(\%{$pkg_tree{$prefix}}, "$todo/$f/$m/$s/$r", $media, $config);
}
if ($r =~ /(\d{14}\.\w+\.\w+\.\d+)_.*\.deps$/) {
@@ -206,6 +236,20 @@ sub get_upload_tree_state {
$pkg_tree{$prefix}{deps} = \@deps;
}
+
+ if ($r =~ /(\d{14}\.\w+\.\w+\.\d+)_(.*)\.retry$/) {
+ my $prefix = $1;
+ my $arch = $2;
+ my $mtime = stat("$todo/$f/$m/$s/$r")->mtime;
+ my $nb_failures = cat_("$todo/$f/$m/$s/$r");
+ plog('DEBUG', "$prefix failed $nb_failures times, last one was as " . localtime($mtime));
+ if ($mtime > time) {
+ plog('INFO', "Too early to retry $prefix, waiting until " . localtime($mtime));
+ $pkg_tree{$prefix}{media}{$media}{later}{$arch} = 1;
+ } else {
+ $pkg_tree{$prefix}{media}{$media}{retries}{arch}{nb_failures} = $nb_failures;
+ }
+ }
}
sub done_func {
@@ -238,6 +282,8 @@ sub get_upload_tree_state {
$pkg_tree{$prefix}{media}{$media}{failed_arch}{$arch} = 1;
} elsif ($result eq 'cancelled') {
$pkg_tree{$prefix}{media}{$media}{cancelled_arch}{$arch} = 1;
+ } elsif ($result eq 'uploaded') {
+ $pkg_tree{$prefix}{media}{$media}{uploaded_arch}{$arch} = 1;
} else {
plog('WARNING', "unknown state $arch.$result for $prefix");
}
@@ -256,3 +302,21 @@ sub get_upload_tree_state {
return %pkg_tree;
}
+
+sub schedule_next_retry {
+ my ($config, $todo_dir, $prefix, $arch, $nb_failures) = @_;
+
+ # If backoff_delays is not set, do nothing and retry forever
+ return 1 unless defined $config->{backoff_delays};
+
+ my $backoff_delays = $config->{backoff_delays};
+ my $file = "$todo_dir/${prefix}_$arch.retry";
+ create_file($file, $nb_failures+1);
+ if ($nb_failures >= scalar(@$backoff_delays)) {
+ plog('INFO', "$prefix failed too many times with a retriable error ($nb_failures)");
+ return;
+ }
+ my $mtime = time + @$backoff_delays[$nb_failures];
+ utime(time, $mtime, $file);
+ return 1;
+}
diff --git a/lib/Iurt/RPM.pm b/lib/Iurt/RPM.pm
new file mode 100644
index 0000000..de09ba4
--- /dev/null
+++ b/lib/Iurt/RPM.pm
@@ -0,0 +1,55 @@
+package Iurt::RPM;
+
+use base qw(Exporter);
+use RPM4::Header;
+use MDK::Common;
+use strict;
+
+our @EXPORT = qw(
+ check_arch
+ check_noarch
+);
+
+sub check_noarch {
+ my ($rpm) = @_;
+ my $hdr = RPM4::Header->new($rpm);
+
+ # Stupid rpm doesn't return an empty list so we must check for (none)
+
+ my ($build_archs) = $hdr->queryformat('%{BUILDARCHS}');
+
+ if ($build_archs ne '(none)') {
+ ($build_archs) = $hdr->queryformat('[%{BUILDARCHS} ]');
+ my @list = split ' ', $build_archs;
+ return 1 if member('noarch', @list);
+ }
+
+ return 0;
+}
+
+sub check_arch {
+ my ($rpm, $arch) = @_;
+ my $hdr = RPM4::Header->new($rpm);
+
+ # Stupid rpm doesn't return an empty list so we must check for (none)
+
+ my ($exclusive_arch) = $hdr->queryformat('%{EXCLUSIVEARCH}');
+
+ if ($exclusive_arch ne '(none)') {
+ ($exclusive_arch) = $hdr->queryformat('[%{EXCLUSIVEARCH} ]');
+ my @list = split ' ', $exclusive_arch;
+ return 0 unless member($arch, @list);
+ }
+
+ my ($exclude_arch) = $hdr->queryformat('[%{EXCLUDEARCH} ]');
+
+ if ($exclude_arch ne '(none)') {
+ ($exclude_arch) = $hdr->queryformat('[%{EXCLUDEARCH} ]');
+ my @list = split ' ', $exclude_arch;
+ return 0 if member($arch, @list);
+ }
+
+ return 1;
+}
+
+1;
diff --git a/lib/Iurt/Ulri.pm b/lib/Iurt/Ulri.pm
index ce9d104..09be6b0 100755
--- a/lib/Iurt/Ulri.pm
+++ b/lib/Iurt/Ulri.pm
@@ -3,18 +3,155 @@ package Iurt::Ulri;
use base qw(Exporter);
use File::Path qw(make_path);
use File::Temp qw(mktemp);
-use Iurt::Config qw(get_author_email);
+use Iurt::Config qw(config_init config_usage get_author_email);
use Iurt::File qw(check_file_timeout);
use Iurt::Mail qw(sendmail);
-use Iurt::Util qw(plog ssh_setup ssh sput);
+use Iurt::Util qw(plog ssh_setup sget ssh sput);
use File::Slurp qw(read_file);
+use MDK::Common qw(cat_);
use strict;
our @EXPORT = qw(
build_package
+ fetch_logs_and_cleanup
+ load_config
warn_about_failure
);
+sub load_config {
+ my ($run) = @_;
+ my $HOME = $ENV{HOME};
+ my $configfile = "$HOME/.upload.conf";
+ my $sysconfigfile = "/etc/iurt/upload.conf";
+
+ my $config = {};
+ foreach my $f ($configfile, $sysconfigfile) {
+ plog('DEBUG', "load config: $f");
+ if (-f $f) {
+ $config = eval(cat_($f))
+ or die "FATAL $run->{program_name}: syntax error in $f";
+ last;
+ }
+ }
+
+ my %config_usage = (
+ admin => {
+ desc => 'mail address of the bot administrator',
+ default => 'distrib-admin@mandrivalinux.org'
+ },
+ 'arch_translation' => {
+ desc => "Renaming of arch",
+ default => { 'sparc64' => 'sparcv9' }
+ },
+ bot => {
+ desc => "List of bot able to compile the packages",
+ default => {
+ i586 => {
+ localhost => {
+ iurt => {
+ user => 'builder',
+ command => qq(iurt --copy_srpm --group --config local_spool /home/builder/iurt/__DIR__ --no_rsync --chrooted-urpmi -m __MEDIA__ -- http://localhost/distrib/ -p "__PACKAGER__" -r __TARGET__ __ARCH__),
+ packages => '/home/builder/iurt/',
+ },
+ },
+ },
+ },
+ },
+ media => {
+ desc => 'Corresponding media to add given the current media',
+ default => {
+ default => {
+ "core/backports" => [ "core/backports", "core/release", "core/updates" ],
+ "core/backports_testing" => [
+ "core/backports", "core/backports_testing",
+ "core/release", "core/updates"
+ ],
+ "core/release" => [ "core/release" ],
+ "core/updates" => [ "core/release", "core/updates" ],
+ "core/updates_testing" => [
+ "core/release", "core/updates", "core/updates_testing"
+ ],
+ "nonfree/backports" => [
+ "core/backports", "core/release", "core/updates",
+ "nonfree/backports", "nonfree/release", "nonfree/updates"
+ ],
+ "nonfree/backports_testing" => [
+ "core/backports", "core/backports_testing",
+ "core/release", "core/updates",
+ "nonfree/backports", "nonfree/backports_testing",
+ "nonfree/release", "nonfree/updates"
+ ],
+ "nonfree/release" => [ "core/release", "nonfree/release" ],
+ "nonfree/updates" => [
+ "core/release", "core/updates",
+ "nonfree/release", "nonfree/updates"
+ ],
+ "nonfree/updates_testing" => [
+ "core/release", "core/updates", "core/updates_testing",
+ "nonfree/release", "nonfree/updates", "nonfree/updates_testing"
+ ],
+ "tainted/backports" => [
+ "core/backports", "core/release", "core/updates",
+ "tainted/backports", "tainted/release", "tainted/updates"
+ ],
+ "tainted/backports_testing" => [
+ "core/backports", "core/backports_testing",
+ "core/release", "core/updates",
+ "tainted/backports", "tainted/backports_testing",
+ "tainted/release", "tainted/updates"
+ ],
+ "tainted/release" => [ "core/release", "tainted/release" ],
+ "tainted/updates" => [
+ "core/release", "core/updates",
+ "tainted/release", "tainted/updates"
+ ],
+ "tainted/updates_testing" => [
+ "core/release", "core/updates", "core/updates_testing",
+ "tainted/release", "tainted/updates", "tainted/updates_testing"
+ ],
+ },
+ },
+ },
+ faildelay => {
+ desc => "Time after which the rebuild is considered as a failure",
+ default => 36000
+ },
+ http_queue => {
+ desc => 'Address where log can be consulted',
+ default => 'http://pkgsubmit.mageia.org/uploads/'
+ },
+ queue => {
+ desc => "Root of the tree where the packages to compile are located",
+ default => "$HOME/uploads"
+ },
+ tmp => {
+ desc => "Temporary directory",
+ default => "$HOME/tmp"
+ },
+ ssh_options => {
+ desc => "SSH options",
+ default => "-o ConnectTimeout=5 -o BatchMode=yes -o ServerAliveInterval=5"
+ },
+ packager => {
+ desc => 'Default packager tag user by bot',
+ default => 'Mageia Team <http://www.mageia.org>'
+ },
+ 'arch' => {
+ desc => 'Architectures list for each target',
+ default => {
+ default => [ 'i586', 'x86_64' ],
+ },
+ },
+ 'backoff_delays' => {
+ desc => 'List of delays in seconds before retrying retriable errors. Error becomes permanent after reaching the end of the list.',
+ default => [5*60, 30*60, 60*60, 120*60]
+ },
+ );
+ config_usage(\%config_usage, $config) if $run->{config_usage};
+ config_init(\%config_usage, $config, $run);
+ return $config;
+}
+
sub build_package {
my ($config, $pkg_tree, $media, $prefix, $host, $arch, $bot) = @_;
@@ -80,13 +217,13 @@ sub build_package {
plog('DEBUG', "Will compile only with media $media_to_add");
$cmd =~ s!__MEDIA__!$media_to_add!g;
- #- allow x86_64 hosts to build i586 packages
- if ($arch eq 'i586') {
- $cmd = "setarch i586 $cmd";
+ #- force 32bit if needed, this allows to build 32 bits package on 64 bit hosts
+ if ($arch =~ /^(i.86|armv5tl|armv7hl)/) {
+ $cmd = "setarch linux32 $cmd";
}
plog('DEBUG', "Build $pkgs");
- ssh($remote, "'echo PID=\$\$; exec $cmd $pkgs &>$prefix_dir/log/botcmd.\$(date +%s).\$(hostname -s).log' > $temp &");
+ ssh($remote, "'echo PID=\$\$; exec $cmd $pkgs &>$prefix_dir/log/botcmd.\$(date +%s).$arch.\$(hostname -s).log' > $temp &");
# wait 10 seconds or until we have the log file
# plus 20 seconds if it timeouts.
@@ -144,6 +281,13 @@ sub get_pid_from_file {
$pid;
}
+sub fetch_logs_and_cleanup {
+ my ($remote, $remote_dir, $target_dir) = @_;
+ make_path($target_dir);
+ sget($remote, "$remote_dir/log/*", $target_dir);
+ ssh($remote, "rm -rf $remote_dir");
+}
+
sub warn_about_failure {
my ($config, $user, $ent, $arch, $fail_dir, $path, $prefix) = @_;
my $text = join("\n", "Build of the following packages failed:\n", map { "- $_" } @{$ent->{srpms}}) . "\n";
@@ -161,11 +305,11 @@ sub warn_about_failure {
$text .= "\nLog files generated:\n";
opendir my $DP1, "$fail_dir/$prefix/log/";
- foreach my $f1 (sort(readdir($DP1))) {
+ foreach my $f1 (readdir($DP1)) {
next if ! -d "$fail_dir/$prefix/log/$f1" || $f1 =~ m/^\./;
opendir my $DP2, "$fail_dir/$prefix/log/$f1";
- foreach my $f2 (readdir $DP2) {
+ foreach my $f2 (sort(readdir $DP2)) {
next if $f2 =~ m/^\./;
$text .= "$fpath/log/$f1/$f2\n";
}
diff --git a/lib/Iurt/Urpmi.pm b/lib/Iurt/Urpmi.pm
index 7ac6a74..53d0756 100644
--- a/lib/Iurt/Urpmi.pm
+++ b/lib/Iurt/Urpmi.pm
@@ -5,6 +5,7 @@ use RPM4::Header;
use File::Basename;
use File::NCopy qw(copy);
use MDV::Distribconf::Build;
+use MDK::Common qw(cat_);
use Iurt::Chroot qw(add_local_user create_temp_chroot);
use Iurt::Process qw(perform_command clean_process sudo);
use Iurt::Config qw(get_package_prefix);
@@ -21,31 +22,15 @@ sub new {
my $config = $self->{config};
my $run = $self->{run};
- if ($run->{chrooted_urpmi}) {
- $run->{chrooted_media} = $run->{chrooted_urpmi}{rooted_media} .
- "/$run->{distro}/$run->{my_arch}";
-
- # Now squash all slashes that don't follow colon
- $run->{chrooted_media} =~ s|(?<!:)/+|/|g;
-
- plog('DEBUG', "installation media: $run->{chrooted_media}");
- }
- $self->{use__urpmi_root} = !urpm::is_local_url($config->{repository});
$self->{distrib_url} = "$config->{repository}/$run->{distro}/$run->{my_arch}";
$self;
}
-sub set_command__urpmi_root {
+sub set_command {
my ($self, $chroot_tmp) = @_;
- $self->{use_iurt_root_command} = 1;
$self->{urpmi_command} = "urpmi $self->{urpmi_options} --urpmi-root $chroot_tmp";
}
-sub set_command__use_distrib {
- my ($self, $chroot_tmp) = @_;
- $self->{use_iurt_root_command} = 1;
- $self->{urpmi_command} = "urpmi $self->{urpmi_options} --use-distrib $self->{distrib_url} --root $chroot_tmp";
-}
sub set_local_media {
my ($self, $local_media) = @_;
@@ -65,10 +50,7 @@ sub urpmi_command {
my $run = $self->{run};
my $local_media = $self->{local_media};
- if ($run->{chrooted_urpmi}) {
- # FIXME chrooted_urpmi should always use urpmi_root and not support local media
- $self->{use__urpmi_root} ? &set_command__urpmi_root : &set_command__use_distrib;
-
+ &set_command;
# Here should be added only the needed media for the given package
# main/release -> main/release
# main/testing -> main/release main/testing
@@ -82,18 +64,17 @@ sub urpmi_command {
my $m_name = $m;
$m_name =~ s,/,_,g;
if (!add_media($self, $chroot_tmp, $m_name,
- "$m_name $run->{chrooted_media}/media/$m")) {
+ "$m_name $self->{distrib_url}/media/$m")) {
$run->{chrooted_urpmi} = 0;
- plog('ERROR', "Failed to add media $m_name. Disabling chrooted_urpmi.");
+ plog('ERROR', "Failed to add media $m_name.");
return;
}
}
} else {
# FIXME Do not hardcode Core
- if (!add_media($self, $chroot_tmp, 'Core', "--distrib $run->{chrooted_media}")) {
- if (!add_media($self, $chroot_tmp, 'Core', "--wget --distrib $run->{chrooted_media}")) {
- $run->{chrooted_urpmi} = 0;
- plog('ERROR', "Failed to add media $run->{chrooted_media}. Disabling chrooted_urpmi.");
+ if (!add_media($self, $chroot_tmp, 'Core', "--distrib $self->{distrib_url}")) {
+ if (!add_media($self, $chroot_tmp, 'Core', "--wget --distrib $self->{distrib_url}")) {
+ plog('ERROR', "Failed to add media $self->{distrib_url}.");
return;
}
}
@@ -149,9 +130,6 @@ sub urpmi_command {
}
return 1;
- } else {
- &set_command__use_distrib;
- }
}
sub check_media_added {
@@ -188,12 +166,9 @@ sub add_media {
my $run = $self->{run};
my $config = $self->{config};
- plog("add chroot media: $run->{chrooted_media}");
+ plog("add chroot media: $self->{distrib_url}");
- my $cmd = "chroot $chroot urpmi.addmedia $media";
- if ($run->{chrooted_urpmi}) {
- $cmd = "urpmi-addmedia -v --urpmi-root $chroot $media";
- }
+ my $cmd = "urpmi-addmedia -v --urpmi-root $chroot $media";
perform_command($cmd,
$run, $config,
mail => $config->{admin},
@@ -208,6 +183,24 @@ sub add_media {
1;
}
+sub update {
+ my ($self, $chroot) = @_;
+ my $run = $self->{run};
+ my $config = $self->{config};
+
+ plog('INFO', "updating packages in $chroot");
+
+ my $cmd = "urpmi --urpmi-root $chroot --auto-update --auto";
+ perform_command($cmd,
+ $run, $config,
+ mail => $config->{admin},
+ retry => 2,
+ use_iurt_root_command => 1,
+ debug_mail => $run->{debug})
+ or return;
+ 1;
+}
+
sub get_local_provides {
my ($self) = @_;
my $run = $self->{run};
@@ -341,8 +334,6 @@ sub _install_callback {
# it seems the is needed urpmi error is due to something else (likely a
# database corruption error).
# my @missing_deps = $output =~ /(?:(\S+) is needed by )|(?:\(due to unsatisfied ([^[ ]*)(?: (.*)|\[(.*)\])?\))/g;
- #
-
my @missing_deps = $output =~ /([^ \n]+) \(due to unsatisfied ([^[ \n]*)(?: ([^\n]*)|\[([^\n]*)\])?\)/g;
# <mrl> 20071106 FIXME: This should not be needed anymore
@@ -392,13 +383,13 @@ sub install_packages {
@to_install or return 1;
- (my $log_dirname = $title) =~ s/.*:(.*)\.src.rpm/$1/;
+ (my $log_dirname = $title) =~ s/^[^:]*:?([^:]*)\.(buildreqs\.nosrc|src).rpm/$1/;
my $log_spool = "$local_spool/log/$log_dirname/";
mkdir $log_spool;
- my @rpm = grep { !/\.src\.rpm$/ } @to_install;
+ my @rpm = grep { !/src\.rpm$/ } @to_install;
if ($opt->{check}
&& -f "$chroot_tmp/bin/rpm"
@@ -415,7 +406,7 @@ sub install_packages {
if (!perform_command(
join(' ', $self->{urpmi_command}, @options, @to_install),
$run, $config,
- use_iurt_root_command => $self->{use_iurt_root_command},
+ use_iurt_root_command => 1,
error => $error,
logname => $log,
hash => "${log}_$title",
@@ -452,16 +443,16 @@ sub install_packages {
$ok;
}
-sub clean_urpmi_process {
- my ($self) = @_;
- my $run = $self->{run};
- my $program_name = $run->{program_name};
- if (!$run->{chrooted_urpmi}) {
- my $match = $self->{urpmi_command} or return;
- if (!clean_process($match)) {
- die "FATAL $program_name: Could not have urpmi working !";
- }
+sub get_srpm_name {
+ my ($run, $config, $chroot_tmp, $srpm, $luser, $spec) = @_;
+ if (!perform_command(qq(chroot $chroot_tmp su $luser -c "rpmspec -q --qf %{NVR}.src.rpm --srpm /home/$luser/rpmbuild/SPECS/$spec > /home/$luser/rpmbuild/SPECS/$spec.srpm_name"),
+ $run, $config,
+ use_iurt_root_command => 1,
+ hash => "identify_$srpm")) {
+ plog("ERROR: failed to get the name of the generated src.rpm");
+ return;
}
+ return cat_("$chroot_tmp/home/$luser/rpmbuild/SPECS/$spec.srpm_name");
}
# return ("exit_code", srpm, spec)
@@ -518,7 +509,7 @@ sub recreate_srpm {
my $filelist = `rpm -qlp $oldsrpm`;
my ($name) = $srpm =~ /(?:.*:)?(.*)-[^-]+-[^-]+\.src\.rpm$/;
foreach my $file (split "\n", $filelist) {
- if ($file =~ /(.*)\.spec/) {
+ if ($file =~ /(.*)\.spec$/) {
if (!$spec) {
$spec = $file;
} elsif ($1 eq $name) {
@@ -545,8 +536,12 @@ sub recreate_srpm {
#
return 0 unless $ret;
- my $file = (glob "$chroot_tmp/home/$luser/rpmbuild/SRPMS/$name-*.src.rpm")[0];
- my ($new_srpm) = basename($file);
+ my $new_srpm = get_srpm_name($run, $config, $chroot_tmp, $srpm, $luser, $spec);
+ if (!$new_srpm) {
+ plog("ERROR: failed to get the name of the generated src.rpm");
+ return;
+ }
+ my $file = "$chroot_tmp/home/$luser/rpmbuild/SRPMS/$new_srpm";
my $prefix = get_package_prefix($srpm);
my $newfile = "$chroot_tmp/home/$luser/rpmbuild/SRPMS/$prefix$new_srpm";
if (-f $file && $newfile ne $file) {
@@ -561,4 +556,64 @@ sub recreate_srpm {
($ret, "$prefix$new_srpm", $spec);
}
+sub install_dynamic_buildrequires {
+ my ($self, $run, $config, $chroot_tmp, $luser, $spec, $srpm) = @_;
+ my $program_name = $run->{program_name};
+ my $with_flags = $run->{with_flags};
+
+ plog('INFO', "handling dynamic buildrequires");
+
+ if (`rpm -qp --requires "$chroot_tmp/home/$luser/rpmbuild/SRPMS/$srpm"` !~ /rpmlib\(DynamicBuildRequires\)/) {
+ plog('DEBUG', "DynamicBuildRequires not required for $srpm");
+ return 1;
+ }
+
+ my $new_srpm = get_srpm_name($run, $config, $chroot_tmp, $srpm, $luser, $spec);
+ if (!$new_srpm) {
+ plog("ERROR: failed to get the name of the generated src.rpm");
+ return;
+ }
+ my $nosrc = $new_srpm =~ s/src.rpm$/buildreqs.nosrc.rpm/r;
+
+ while (1) {
+ # There is no way with perform_command to get the actual error code.
+ # We can however tell it that error 11 (missing BuildRequires) is ok so
+ # that we get an error if it fails for any other reason.
+ my $ret = perform_command(qq(chroot $chroot_tmp su $luser -c "rpmbuild -br $with_flags /home/$luser/rpmbuild/SPECS/$spec"),
+ $run, $config,
+ use_iurt_root_command => 1,
+ hash => "generatebuildrequires_$srpm"
+ );
+ return 1 if $ret;
+
+ # Unfortunately iurt_root_command hides the original error code so
+ # we need to find out if the file was created rather than relying on
+ # the command exiting with 11.
+ if (-f "$chroot_tmp/home/$luser/rpmbuild/SRPMS/$nosrc") {
+ plog("INFO: Some dynamic BuildRequires are missing");
+ my @packages = ("$chroot_tmp/home/$luser/rpmbuild/SRPMS/$nosrc");
+ if (!$self->install_packages(
+ $srpm,
+ $chroot_tmp,
+ $run->{local_spool},
+ 'dynamic_buildrequires',
+ "[DYNAMIC BUILDREQUIRES] installation of dynamic BuildRequires failed for $srpm on $run->{my_arch}",
+ {},
+ @packages
+ )) {
+ plog('ERROR', "Failed to install dynamic BuildRequires.");
+ return 0;
+ }
+ # TODO: Have a max retry counter for safety
+ # Delete the file if it exists so that we know if it got created again
+ unlink("$chroot_tmp/home/$luser/rpmbuild/SRPMS/$nosrc");
+ } else {
+ # This was a failure for another reason, no point retrying
+ plog('ERROR', "Failed to generate dynamic BuildRequires.");
+ $run->{status}{$srpm} = 'build_failure';
+ return 0;
+ }
+ }
+}
+
1;
diff --git a/lib/Iurt/Util.pm b/lib/Iurt/Util.pm
index f9dfa9f..bf726d0 100644
--- a/lib/Iurt/Util.pm
+++ b/lib/Iurt/Util.pm
@@ -167,7 +167,7 @@ execute I<@command>. Return the command output.
sub sout {
my $conf = shift;
my ($opt, $user, $host) = @$conf;
- `ssh $opt -x $user\@$host @_ 2>/dev/null`;
+ `ssh $opt -x $user\@$host "@_" 2>/dev/null`;
}
=item sget($handle, $from, $to)