/[soft]/build_system/iurt/trunk/iurt2
ViewVC logotype

Contents of /build_system/iurt/trunk/iurt2

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3056 - (show annotations) (download)
Sat Feb 25 17:14:58 2012 UTC (12 years, 7 months ago) by tv
File size: 57355 byte(s)
catch chroot creation failures

(see eg http://pkgsubmit.mageia.org/uploads/failure/cauldron/core/release/20120225155856.tv.valstar.5624/log/botcmd.1330185537.ecosse.log)

1 #!/usr/bin/perl
2 #
3 # Copyright (C) 2005 Mandrakesoft
4 # Copyright (C) 2005,2006 Mandriva
5 #
6 # Author: Florent Villard <warly@mandriva.com>
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2, or (at your option)
11 # any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #
22 # compare and rebuild packages on different architecture
23 #
24 # TODO
25 #
26 # - use a cache (rpmctl cache for example) to find maintainer
27 # - add icecream compilation support
28 # - add a --group option to compile a set of packages (in progress)
29 # - add a function to update a packages when it obviously need to be recompile
30 # - Maybe call the function from the initial todo list (thus making the
31 # argument ordering important)
32 # - Change the packager tag in the chroot to have the one who submit the package
33
34 use strict;
35 use RPM4::Header;
36 use Iurt::Config qw(config_usage get_date get_prefix config_init dump_cache_par get_maint check_arch %arch_comp get_package_prefix);
37 use Data::Dumper;
38 use URPM;
39 use Iurt::DKMS;
40
41 use Iurt::Urpmi;
42 use Iurt::Chroot qw(add_local_user create_temp_chroot remove_chroot clean_unionfs clean_all_unionfs clean_all_chroot_tmp check_build_chroot clean_chroot);
43 use Iurt::Process qw(perform_command clean kill_for_good sudo);
44 use Iurt::Mail qw(sendmail);
45 use Iurt::Util qw(plog_init plog);
46 use File::NCopy qw(copy);
47 use File::Path qw(mkpath);
48 use File::Spec::Functions qw(rel2abs);
49 use File::Basename qw(fileparse);
50 # I did not manage to make locks work over the network
51 #use File::lockf;
52 use Mkcd::Commandline qw(parseCommandLine usage);
53 use MDK::Common;
54 use Filesys::Df qw(df);
55 use POSIX;
56
57
58 sub bug_handler {
59 my ($error, $is_signal) = @_;
60
61 # exceptions in eval are OK:
62 return if $error && $^S && !$is_signal;
63
64 # we want the full backtrace:
65 $error .= "\n" if $is_signal;
66 $error .= backtrace() if $error;
67
68 warn "We got an uncatched exception:\n$error\n";
69 #exit(1);
70 }
71
72 $SIG{SEGV} = sub { bug_handler(@_, 1) };
73 #$SIG{__DIE__} = \&bug_handler;
74 $SIG{TERM} = sub {
75 warn "Got KILLED by SIGTERM at " . strftime("%c", localtime()) . " .\n";
76 exit(1);
77 };
78
79 my $program_name = 'iurt2';
80 my $VERSION = '0.6.5';
81 # sessing parameters
82 my $sudo = '/usr/bin/sudo';
83 my $arg = @ARGV;
84 my (@params, %run);
85 $run{program_name} = $program_name;
86
87 $run{todo} = [];
88 @params = (
89 # [ "one letter option", "long name option", "number of args (-X means ´at least X´)", "help text", "function to call", "log info"]
90 #
91 # no_rsync, config_help and copy_srpm kept for compatibility reasons
92 #
93 [ "", $program_name, 0, "[--cache] [--chrooted-urpmi <media prefix>] [--concurrent-run] [--config foo value] [--warn] [--verbose integer]
94 [--copy-srpm] [--debug] [--distro] [--no-rsync] [--clean user1 user2 user3] [--clean-all] [--shell] [--stop {p|c|i|l|b|a|s}]
95 [--use-system-distrib] [--dir] [--help foo?] [--log filename] [--group] [--unionfs]
96 [--upload [--markrelease] [--source]] [--dir] [--help foo?] [--log filename] [--unionfs] [--status] [--ignore-failure]
97 [--repository <distribution path>]
98 [--rpmmacros <macro definition> [<macro definition>...]]
99 {--config_help | --dkms {--media <media regexp>}
100 --chroot --arch {i586|x86_64|ppc} --distro {cooker|2006.0|community/2006.0|...} } |
101 --build-user <user> --rebuild {cooker|2006.0|community/2006.0|...} {i586|x86_64|ppc|...} {filename1.src.rpm} {filename2.src.rpm} ... {filenamen.src.rpm} }",
102 "$program_name is a perl script to rebuild automatically several rpm in chroot, given a sourcerpm repository, and mail authors or rebuilder when problems occurs.
103
104 e.g.: iurt --repository /dis/ -p foo\@foo.net -r cooker x86_64 /SRPMS/main/release/mkcd-4.2.5-1mdv2007.1.src.rpm",
105 sub { $arg or usage($program_name, \@params) }, "" ],
106 [ "", "distro", 1, "<distro>",
107 "Set the distribution",
108 sub { ($run{distro}) = @_; 1 }, "Setting the distribution" ],
109 [ "", "dkms", [
110 ["", "dkms", 0, "",
111 "Set the DKMS rebuild mode",
112 sub {
113 my ($tmp, @arg) = @_;
114 $tmp->[0] ||= {};
115 push @$tmp, @arg;
116 1;
117 }, "Setting auto mode arguments"],
118 ["k", "kmedia", 1, "<kernel media regexp>",
119 "Media Regexp to limit the kernel search to",
120 sub { my ($tmp, $kmedia) = @_; $tmp->[0]{kmedia} = $kmedia; 1 }, "Limiting rebuild to the kernel in the given media regexp"],
121 ["m", "media", 1, "<media regexp>",
122 "Media Regexp to limit rebuild to",
123 sub { my ($tmp, $media) = @_; $tmp->[0]{media} = $media; 1 }, "Limiting rebuild to the given media regexp"],
124 ["u", "umedia", 1, "<upload media>",
125 "Media where rebuilt DKMS packages will be uploaded",
126 sub { my ($tmp, $media) = @_; $tmp->[0]{umedia} = $media; 1 }, "Uploading rebuilt DKMS packages to the given media"],
127 ["v", "kversion", 1, "<kernel version>",
128 "kernel for which DKMS packages should be rebuilt",
129 sub { my ($tmp, $kversion) = @_; $tmp->[0]{kversion} = $kversion; 1 }, "Rebuilding only for given kernel version"],
130 ["p", "package", 1, "<package>",
131 "DKMS package which should be rebuilt",
132 sub { my ($tmp, $package) = @_; $tmp->[0]{package} = $package; 1 }, "Rebuilding only given DKMS packages"],
133 ], "[options]",
134 "Set the DKMS rebuild mode",
135 sub { my ($opt) = @_; $run{dkms} = $opt; 1 }, "Running a DKMS rebuild run" ],
136 [ "a", "arch", 1, "<architecture>",
137 "Set the architecture",
138 sub { ($run{my_arch}) = @_; 1 }, "Setting architecture" ],
139 [ "", "cache", 0, "",
140 "Use the global cache file",
141 sub { $run{use_cache} = 1 }, "Activating cache use" ],
142 [ "", "copy-srpm", 0, "",
143 "Copy also the regenerated SRPM",
144 sub { $run{copy_srpm} = 1 }, "Activating the copy_srpm mode" ],
145 [ "", "copy_srpm", 0, "",
146 "Copy also the regenerated SRPM",
147 sub { $run{copy_srpm} = 1 }, "Activating the copy_srpm mode" ],
148 [ "c", "chroot", 0, "",
149 "Check chroot and update it if needed",
150 sub { $run{chroot} = 1 }, "Activating chroot updating" ],
151 [ "", "chrooted-urpmi", [
152 [ "", "chrooted-urpmi", 1, "",
153 "Create urpmi media inside the chroot instead of using --root (media prefix is like http:///server.mandriva.com/dis/)",
154 sub {
155 my ($tmp, @arg) = @_;
156 $tmp->[0] ||= {};
157 push @$tmp, @arg;
158 1;
159 }, "Setting chrooted-urpmi options" ],
160 ["m", "media", -1, "<media1> <media2> ... <median>",
161 "Media to add instead of --distrib",
162 sub { my ($tmp, @media) = @_; $tmp->[0]{media} = \@media; 1 }, "Limiting rebuild to the kernel in the given media regexp"],
163 ] , "[options] <media prefix>",
164 "Create urpmi media inside the chroot instead of using --root (media prefix is like http:///server.mandriva.com/dis/)",
165 sub { my ($opt, $media) = @_; $opt->{rooted_media} = $media; $run{chrooted_urpmi} = $opt; 1 }, "Activating chroot media" ],
166 [ "", "clean-all", 0, "",
167 "Clean all remaining chroots for all the users",
168 sub { $run{clean_all} = 1 }, "Activating clean chroot flag" ],
169 [ "", "clean", -1, "<user 1> <user 2> ... <user n>",
170 "Clean remaining chroot before runing",
171 sub { $run{clean} = \@_ }, "Activating clean chroot flag" ],
172 [ "", "concurrent-run", 0, "",
173 "Allow several iurt to run on different machines (slower)",
174 sub { $run{concurrent_run} = 1 }, "Activating concurrent run checks" ],
175 [ "d", "dir", -1, "",
176 "Directory where to find packages to rebuild",
177 sub { $run{extra_dir} = \@_; 1 }, "Adding extra source packages directories" ],
178 [ "", "config", 2, "<configuration keyword> <value>",
179 "Override a configuration file variable",
180 sub { my ($key, $value) = @_; $run{config}{$key} = $value }, "Overriding configuration variable" ],
181 [ "", "config-help", 0, "",
182 "Explain configuration files keywords",
183 sub { $run{config_usage} = 1 }, "Activating debug mode" ],
184 [ "", "config_help", 0, "",
185 "Explain configuration files keywords",
186 sub { $run{config_usage} = 1 }, "Activating debug mode" ],
187 [ "", "debug", 0, "",
188 "Activate debug mode",
189 sub { $run{debug} = 1 }, "Activating debug mode" ],
190 [ "g", "group", 0, "",
191 "Activate group mode, packages will be compiled as a global set, not as individual packages",
192 sub { $run{group} = 1 }, "Activating the group mode" ],
193 [ "", "ignore-failure", 0, "",
194 "Do not take into account the failure cache, try to recompile all the packages not synchronized",
195 sub { $run{ignore_failure} = 1 }, "Activating the mode ignoring previous failure" ],
196 [ "u", "unionfs", 0, "",
197 "Activate unionfs mode",
198 sub { $run{unionfs} = 1 }, "Activating unionfs mode" ],
199 [ "l", "log", 1, "<log file>",
200 "Log file.",
201 sub {
202 $run{log} = pop @_;
203 open my $log, ">$run{log}" or die "unable to open $run{log}\n";
204 $run{LOG} = sub { print $log @_ };
205 $run{logfd} = $log;
206 print *$log, "command line: @ARGV\n";
207 1;
208 }, "Log file" ],
209 [ "m", "media", -1, "<media 1> <media 2> ... <media 3>",
210 "Media to rebuild",
211 sub { ($run{media}) = @_; 1 }, "Adding a media to rebuild" ],
212 [ "", "build-all", 0, "",
213 "Build all packages of the media, even if they are up to date",
214 sub { $run{build_all} = 1 }, "Setting the full build flag" ],
215 [ "n", "no", 0, "",
216 "Perform all the check but do not compile anything",
217 sub { ($run{no_compile}) = 1 }, "Setting the no compilation flag" ],
218 [ "p", "packager", 1, "<packager>",
219 "Use a specific packager",
220 sub { ($run{packager}) = @_ }, 'Setting packager tag' ],
221 [ "", "build-user", 1, "<user>",
222 "Use this username to build package",
223 sub { ($run{user}) = @_ }, 'Setting build username' ],
224 [ "r", "rebuild", -2, "<distro> <architecture> <srpm 1> <srpm 2> ... <srpm n>",
225 "Rebuild the packages, e.g. $program_name -r cooker x86_64 /home/foo/rpm/SRPMS/foo-2.3-12mdv2007.0.src.rpm",
226 sub {
227 $run{rebuild} = 1;
228 $run{distro} = shift @_;
229 $run{my_arch} = shift @_;
230
231 foreach (@_) {
232 my ($path, $srpm);
233
234 unless (-f $_ && -r $_) {
235 die "FATAL $program_name: $_ not a file or cannot be read\n";
236 }
237
238 ($srpm, $path) = fileparse(rel2abs($_));
239 ($srpm =~ /\.src\.rpm$/) or die "FATAL: $_ doesn't look like an SRPM";
240
241 if (check_arch($_, $run{my_arch})) {
242 plog('DEBUG', "force build for $2 (from $1)");
243 push @{$run{todo}}, [ $path, $srpm, 1 ];
244 } else {
245 plog("ERROR: $_ could not be build on $run{my_arch}, ignored.");
246 }
247 }
248 1;
249 }, "Activating rebuild mode" ],
250 [ "", "rpmmacros", -1, "<macro definition 1> .. <macro definition n>",
251 "Additional rpm macros to define",
252 sub { $run{rpmmacros} = \@_ }, 'Setting rpm macros' ],
253 [ "", "upload", [
254 ["", "upload", 0, "[options]",
255 "Upload the rebuild packages",
256 sub { my ($tmp) = @_;
257 $tmp->[0] ||= {};
258 1;
259 }, "Setting upload options"],
260 [ "m", "markrelease", 0, "",
261 "Mark SVN directory when uploading the packages",
262 sub { $run{markrelease} = 1 }, "Adding markrelease repsys option" ],
263 [ "s", "source", 0, "",
264 "Upload the source package as wells",
265 sub { $run{source_upload} = 1 }, "Setting source flag for upload" ],
266 ], "[options]",
267 "Upload the rebuild packages",
268 sub { $run{upload} = 1 }, "Setting the upload flag" ],
269 [ "", "use-old-chroot", 1, "<chroot path>",
270 "Use the given chroot as chroot (usefull for debugging)",
271 sub { ($run{use_old_chroot}) = @_ }, "Using given chroot" ],
272 [ "", "no-rsync", 0, "",
273 "Do not send build log to the distant rsync server",
274 sub { $run{no_rsync} = 1 }, "Setting the no rsync warn flag" ],
275 [ "", "no_rsync", 0, "",
276 "Do not send build log to the distant rsync server",
277 sub { $run{no_rsync} = 1 }, "Setting the no rsync warn flag" ],
278 [ "", "delete-on-success", 0, "",
279 "Don't keep generated packages and their logs",
280 sub { $run{delete_on_success} = 1 }, "Setting the delete on success flag" ],
281 [ "v", "verbose", 1, "<verbose level>",
282 "Give more info messages about what is going on (level from 1 to 10)",
283 sub { $run{verbose} = $_[0]; 1 }, "Setting verbose level" ],
284 [ "w", "warn", 0, "",
285 "Warn maintainer of the packages about problem in the rebuild",
286 sub { $run{warn} = 1; 1 }, "Setting warn flag to warn maintainers" ],
287 [ "", "shell", 0, "",
288 "Dump to a shell into the newly created chroot with sudo on rpm, urpmi, urpme and urpmi.addmedia",
289 sub {
290 ($run{shell}) = 1;
291 1 }, "Setting option to dump to a shell" ],
292 [ "", "stop", 1, "<rpm step>",
293 "Perform rpmbuild -b<rpm step> (p c i l b a s) instead of rpmbuild -ba and then open a shell in the chroot",
294 sub {
295 ($run{stop}) = @_;
296 1;
297 }, "Setting rpm build option" ],
298 [ "", "repository", 1, "<distribution root path>",
299 "Set a repository path if one is not created in the configuration file",
300 sub {
301 ($run{repository}) = @_;
302 1;
303 } , "Setting the repository" ],
304 [ "", "status", 1, "<mail>",
305 "Send a status mail to the provided mail address",
306 sub {
307 ($run{status_mail}) = @_;
308 1;
309 }, "Setting status mail option" ],
310 [ "", "with", 1, "<flag>",
311 "Use specified --with flag with rpm (can be used multiple times)",
312 sub {
313 ($run{with_flags}) = $run{with_flags} . " --with " . @_[0];
314 1;
315 }, "Adding specified extra --with parameter to rpm" ],
316 [ "", "without", 1, "<flag>",
317 "Use specified --without flag with rpm (can be used multiple times)",
318 sub {
319 ($run{with_flags}) = $run{with_flags} . " --without " . @_[0];
320 1;
321 }, "Adding specified extra --without parameter to rpm" ],
322 # [ short option, long option, # of args, syntax description,
323 # action description, action, execution message ]
324 #############################
325 [ "", "additional-media",
326 [
327 [ "", "additional-media", 1, "",
328 "Use additional medias (media prefix is like http:///server.mandriva.com/dis/)",
329 sub {
330 my ($tmp, @arg) = @_;
331 $tmp->[0] ||= {};
332 push @$tmp, @arg;
333 1;
334 }, "Setting additional medias options"
335 ],
336 [ "m", "media", -1, "<media1> <media2> ... <median>",
337 "Media to add instead of --distrib",
338 sub {
339 my ($tmp, @media) = @_;
340 $tmp->[0]{media} = \@media;
341 1;
342 }, "Limiting rebuild to the kernel in the given media regexp"
343 ],
344 ],
345 "[options] <media prefix>",
346 "Also uses these medias (media prefix is like http:///server.mandriva.com/dis/)",
347 sub {
348 my ($opt, $media) = @_;
349 $opt->{repository} = $media;
350 $run{additional_media} = $opt;
351 1;
352 }, "Activating additional medias"
353 ],
354 ###############################
355 [ "", "icecream", 1, "<procs>",
356 "Enables icecream usage by <procs> procs",
357 sub {
358 $run{icecream} = @_[0];
359 }, "Enabling icecream usage" ],
360 );
361
362 open(my $LOG, ">&STDERR");
363 $run{LOG} = sub { print $LOG @_ };
364
365 plog_init($program_name, $run{logfd}||$LOG, 7, 1); # For parsing command line
366
367 # Display version information
368 #
369 (my $iurt_rev = '$Rev: 271258 $') =~ s/.*: (\d+).*/$1/;
370 (my $iurt_aut = '$Author: blino $') =~ s/.*: (..).*/$1/;
371 (my $iurt_dat = '$Date: 2010-10-31 23:10:12 +0100 (Sun, 31 Oct 2010) $')
372 =~ s/.*: ([\d-]* [\d:]*) .*/$1/;
373 plog("MSG", "This is iurt2 revision $iurt_rev-$iurt_aut ($iurt_dat)");
374
375
376 my $todo = parseCommandLine($program_name, \@ARGV, \@params);
377 @ARGV and usage($program_name, \@params, "@ARGV, too many arguments");
378 foreach my $t (@$todo) {
379 plog('DEBUG', $t->[2]);
380 &{$t->[0]}(@{$t->[1]}) or plog('ERR', $t->[2]);
381 }
382
383 # Use the real verbose level
384 plog_init($program_name, $run{logfd}||$LOG, $run{verbose}, 1);
385
386 $run{distro_tag} = $run{distro};
387 $run{distro_tag} =~ s,/,-,g;
388
389 my $real_arch = `uname -m`;
390 chomp $real_arch;
391 my $HOME = $ENV{HOME};
392 my $configfile = "$HOME/.iurt.$run{distro_tag}.conf";
393 my $sysconfigfile = "/etc/iurt/build/$run{distro_tag}.conf";
394
395 my $config = {};
396 foreach my $f ($configfile, $sysconfigfile) {
397 plog('DEBUG', "load config: $f");
398 if (-f $f) {
399 $config = eval(cat_($f))
400 or die "FATAL $program_name: syntax error in $f";
401 last;
402 }
403 }
404
405 if ($run{repository}) {
406 plog('DEBUG', "overriding configuration repository by the one given in the command line");
407 $config->{repository} = $run{repository};
408 }
409
410 if (!$config->{repository}) {
411 die "FATAL $program_name: no repository have been defined (use --repository to specify one on the command line";
412 }
413
414 my $urpmi = Iurt::Urpmi->new(run => \%run, config => $config, urpmi_options => "-v --no-verify-rpm --nolock --auto --no-suggests --ignoresize $config->{urpmi_options}");
415 $run{urpmi} = $urpmi;
416
417 if (!$run{chrooted_urpmi} && $run{group}) {
418 die "FATAL $program_name: option --chrooted-urpmi is mandatory if --group is selected";
419 }
420
421 my %config_usage = (
422 admin => {
423 desc => 'Mail of the administrator of packages builds',
424 default => ''
425 },
426 all_media => {
427 desc => 'List of known media',
428 default => {
429 'main' => [ 'release' ],
430 'contrib' => [ 'release' ]
431 }
432 },
433 base_media => {
434 desc => 'List of base media used to build chroot',
435 default => [ 'core/release' ],
436 },
437 basesystem_packages => {
438 desc => 'List of packages needed for the chroot creation',
439 default => [
440 'basesystem-minimal',
441 'rpm-build',
442 'sudo',
443 'urpmi',
444 'curl',
445 ]
446 },
447 build_timeout => {
448 desc => 'Maximum build time after which the build process is terminated',
449 default => {
450 default => 18000,
451 },
452 },
453 cache_home => {
454 desc => 'Where to store the cache files',
455 default => "$HOME/.bugs"
456 },
457 cache_min_size => {
458 desc => 'Minimal size to consider a cache file valid',
459 default => 1000000
460 },
461 check_binary_file => {
462 desc => 'Packages rebuild should be checked, however sometime rpm is segfaulting and the test is not correct',
463 default => 0
464 },
465 iurt_root_command => {
466 desc => 'Program to run sudo command',
467 default => '/usr/sbin/iurt_root_command'
468 },
469 distribution => {
470 desc => 'Name of the packages distribution',
471 default => 'Mageia'
472 },
473 email_domain => {
474 desc => 'Domain to append to usernames when sending emails',
475 default => 'mageia.org'
476 },
477 home => {
478 desc => 'Home dir',
479 default => $HOME
480 },
481 local_home => {
482 desc => 'Where to build packages',
483 default => $HOME
484 },
485 local_upload => {
486 desc => 'Where to store build packages and log',
487 default => ''
488 },
489 local_spool => {
490 desc => 'To override the directory where all the results are stored',
491 default => ''
492 },
493 log_size_limit => {
494 desc => 'Maximum authorized size for a log file',
495 default => '100M'
496 },
497 log_size_date => {
498 desc => 'Number of days log should be kept',
499 default => '30'
500 },
501 log_url => {
502 desc => 'Where the log can be seen',
503 default => ''
504 },
505 minimum_package_number => {
506 "Minimum number of packages in a synthesis file to consider it valid",
507 default => 1000
508 },
509 max_command_retry => {
510 "Maximum number of retry Iurt will perform for a given command",
511 default => 20
512 },
513 no_mail => {
514 desc => 'Hash table with people mail address where we should not send any mails',
515 default => {}
516 },
517 packager => {
518 desc => 'Name of the build bot',
519 default => 'Iurt'
520 },
521 prompt => {
522 desc => 'Default prompt in the chroot',
523 default => qq{PS1='[\\[\\033[00;33m\\]iurt $run{distro}\\[\\033[00m\\]] \\[\\033[00;31m\\]\\u\\[\\033[00;32m\\]\\h\\[\\033[00m\\]\\w\$ '},
524 },
525 repository => {
526 desc => 'Prefix of the repositories',
527 default => ''
528 },
529 rsync_to => {
530 desc => 'Server where the result of the builds should be rsynced (name@server:path format)',
531 default => ''
532 },
533 sendmail => {
534 desc => 'If the bot will send mail reports regarding build',
535 default => 0
536 },
537 supported_arch => {
538 desc => 'Table of supported architecture',
539 default => ['i586', 'x86_64']
540 },
541 upload => {
542 desc => 'Where to copy build packages',
543 default => "$HOME/uploads/"
544 },
545 vendor => {
546 desc => 'Name of the packages vendor',
547 default => 'Mageia.Org'
548 },
549 additional_media => {
550 desc => 'Additional medias to be used',
551 default => []
552 },
553 icecream => {
554 desc => 'Enabled icecream usage and uses N procs',
555 default => 0
556 },
557 );
558
559 config_usage() if $run{config_usage};
560 $run{my_arch} or usage($program_name, \@params, "no architecture given (media $run{media}, run{my_arch} $run{my_arch}, todo", join(', ', @{$run{todo}}));
561 if (!$arch_comp{$real_arch}{$run{my_arch}}) {
562 die "FATAL $program_name: could not compile $run{my_arch} binaries on a $real_arch";
563 }
564 config_init(\%config_usage, $config, \%run);
565
566 $config->{upload} .= $run{distro};
567 $config->{upload} =~ s/community//g;
568 if ($run{distro} ne 'cooker') {
569 if ($run{media} ne 'main') {
570 $config->{upload} .= "/$run{media}";
571 }
572 } elsif ($run{media} eq 'contrib') {
573 $config->{upload} =~ s/cooker/contrib/g;
574 }
575
576 my $lock = $run{media};
577 my $local; # FIXME: (tv) variable $local assigned, but not read
578 if (!$lock && $run{chroot}) {
579 $lock = 'chroot';
580 $local = 1;
581 }
582 if (!$lock && $run{dkms}) {
583 $lock = 'dkms';
584 $local = 0;
585 }
586 $run{lock} = $lock;
587
588 # cache file name is needed early to remove the manual lock file if the
589 # lock mechanism does not work
590
591 mkpath $config->{cache_home};
592 my $cachefile = "$config->{cache_home}/iurt.$run{distro_tag}.$run{my_arch}.$lock.cache";
593 $run{cachefile} = $cachefile;
594 if (!$run{debug} && $run{media} || $run{chroot}) {
595 $run{pidfile_home} = "$config->{cache_home}/";
596 $run{pidfile} = "iurt.$run{distro_tag}.$run{my_arch}.$lock";
597 check_pid(\%run);
598 }
599
600 $config->{local_upload} ||= $config->{local_home};
601 my $local_spool;
602 if ($config->{local_spool}) {
603 $local_spool = $config->{local_spool};
604 } else {
605 $local_spool = "$config->{local_upload}/iurt/$run{distro_tag}/$run{my_arch}/$run{media}/";
606 }
607
608 # Squash double slashes
609 $local_spool =~ s!/+!/!g;
610 #/
611
612 plog('INFO', "local spool: $local_spool");
613 if (!-d "$local_spool/log") {
614 plog('DEBUG', "creating local spool $local_spool");
615 mkpath("$local_spool/log")
616 or die "FATAL: could not create local spool dir $local_spool ($!)";
617 }
618 $run{local_spool} = $local_spool;
619
620 my $cache;
621 my $clear_cache = 1;
622 if (-f $cachefile && $run{use_cache}) {
623 plog('INFO', "loading cache file $cachefile");
624
625 $cache = eval(cat_($cachefile))
626 or plog('ERR', "FATAL: could not load cache $cachefile ($!)");
627
628 if (!$cache) {
629 opendir my $cache_dir, $config->{cache_home};
630 my $to_load;
631
632 foreach my $file (readdir $cache_dir) {
633 (my $date) = $file =~ /iurt\.$run{distro_tag}\.$run{my_arch}\.$run{media}\.cache\.tmp\.(\d{8})/ or next;
634 if ($date > $to_load && -s "$config->{cache_home}/$file" > $config->{cache_min_size}) {
635 $to_load = $date;
636 $cachefile = "$config->{cache_home}/$file";
637 }
638 }
639
640 plog('NOTIFY', "loading alternate cache file $cachefile");
641 $cache = eval(cat_($cachefile))
642 or plog('ERR', "FATAL: could not load cache $cachefile ($!)");
643 }
644 $clear_cache = 0 if $cache;
645 }
646
647 if ($clear_cache) {
648 $cache = {
649 rpm_srpm => {},
650 failure => {},
651 queue => {},
652 warning => {},
653 run => 1,
654 needed => {},
655 no_unionfs => {}
656 };
657 }
658 $run{cache} = $cache;
659
660 my (%srpm_version, @wrong_rpm, %provides, %pack_provide, $to_compile, %maint);
661 $to_compile = @{$run{todo}};
662 $to_compile += check_media(\%run, $cache, $config, \%srpm_version,
663 \@wrong_rpm, \%provides, \%pack_provide, \%maint) if $run{media};
664 $to_compile += search_packages(1, $cache, \%provides, \%run, \%maint,
665 \%srpm_version, @{$run{extra_dir}}) if $run{extra};
666
667 my $dkms;
668 if ($run{dkms}) {
669 $dkms = Iurt::DKMS->new(run => \%run, config => $config);
670 $to_compile += $dkms->search_dkms;
671 }
672 $run{to_compile} = $to_compile;
673
674 dump_cache_par(\%run);
675
676 plog("Packages to build: $to_compile");
677
678 my ($fulldate, $daydate) = get_date();
679 if ($run{use_cache}) {
680 $run{run} = $cache->{run};
681 $run{run} ||= 1;
682 $cache->{run} = $run{run} + 1;
683 } else {
684 $run{run} = "0.$fulldate";
685 }
686 $run{daydate} = $daydate;
687 plog('DEBUG', "using $run{run} as chroot extension");
688 $run{user} ||= $ENV{USER};
689 die "Iurt should not be executed as root." if $run{user} eq "root";
690 $run{uid} = getpwnam $run{user};
691
692 plog('DEBUG', "using local user $run{user}, id $run{uid}");
693 my $luser = $run{user} || 'builder';
694
695 check_sudo_access()
696 or die "FATAL: you need to have sudo access on $config->{iurt_root_command} to run $program_name";
697
698 my $debug_tag = $run{debug} && '_debug';
699 $run{debug_tag} = $debug_tag;
700 if ($run{unionfs} && !$run{use_old_chroot}) {
701 plog(1, "adding unionfs module");
702 sudo(\%run, $config, "--modprobe", "unionfs") or $run{unionfs} = 0;
703 if ($run{unionfs}) {
704 $run{unionfs_dir} = "$config->{local_home}/iurt_unionfs$debug_tag/";
705 remove_chroot(\%run, $run{unionfs_dir}, \&clean_all_unionfs);
706 $run{unionfs_dir} = "$run{unionfs_dir}/$run{user}/";
707 -d $run{unionfs_dir} or mkdir $run{unionfs_dir};
708 }
709 }
710
711 my (%done, $done);
712 $run{done} = \%done;
713 my $home = $config->{local_home};
714 my $union_id = 1;
715 $run{unionfs_tmp} = $run{unionfs};
716
717 my ($chroot_name, $chroot_tmp, $chroot, $chroot_tar);
718 $chroot_name = "chroot_$run{distro_tag}$debug_tag.$run{my_arch}";
719 if (!$run{use_old_chroot}) {
720 $chroot_tmp = "$config->{local_home}/chroot_tmp";
721
722 if (!-d $chroot_tmp) {
723 mkdir $chroot_tmp;
724 } else {
725 remove_chroot(\%run, $chroot_tmp, \&clean_all_chroot_tmp, $chroot_name);
726 }
727
728 $chroot_tmp = "$config->{local_home}/chroot_tmp/$run{user}";
729 mkdir_p($chroot_tmp);
730 $chroot_tmp = "$config->{local_home}/chroot_tmp/$run{user}/$chroot_name.$run{run}";
731 $run{chroot_tmp} = $chroot_tmp;
732
733 $chroot = "$config->{local_home}/$chroot_name";
734 } else {
735 plog(1, "using given chroot $run{use_old_chroot}");
736 $chroot_tmp = $run{use_old_chroot};
737 $chroot = $run{use_old_chroot};
738 }
739 $run{chroot_path} = $chroot;
740 $chroot_tar = "$config->{local_home}/$chroot_name.tar.gz";
741 $run{chroot_tar} = $chroot_tar;
742 # 20061222 warly
743 # even in use_old_chroot mode we create the chroot if it does not exist (useful
744 # if the option is used for the first time
745 if ($run{chroot} || !-d "$chroot/dev") {
746 check_build_chroot($chroot, $chroot_tar, \%run, $config) or die "FATAL $program_name: could not prepare initial chroot";
747 }
748
749 # now exit if there is nothing to do and it was just a cleaning pass
750 if ($run{no_compile} || !@{$run{todo}} && !$run{debug} && !$run{shell} && !$run{rebuild}) {
751 send_status_mail(\%run, $config, $cache) if $run{status_mail};
752 plog("no package to compile :(");
753 unlink "$run{pidfile_home}/$run{pidfile}" if $run{pidfile};
754 exit();
755 }
756
757 plog('DEBUG', "running with pid $$");
758 $run{prefix} = get_prefix($luser);
759
760 my $df = df $home;
761 if ($df->{per} >= 99) {
762 die "FATAL: not enough space on the filesystem, only $df->{bavail} KB on $home, full at $df->{per}%";
763 }
764
765 if ($run{shell}) {
766 if (!$run{use_old_chroot}) {
767 ($union_id, my $chroot_tmp) = create_temp_chroot(\%run, $config,
768 $cache, $union_id, $chroot_tmp, $chroot_tar)
769 or die "FATAL $program_name: could not create temporary chroot";
770 }
771 add_local_user($chroot_tmp, \%run, $config, $luser, $run{uid}) or die "FATAL $program_name: could not add local user";
772
773 #$urpmi->set_command($chroot_tmp);
774 $urpmi->urpmi_command($chroot_tmp, $luser);
775
776 $urpmi->install_packages('chroot', $chroot_tmp, $local_spool, \%pack_provide, 'configure', "[ADMIN] installation of urpmi and sudo failed in the chroot $run{my_arch}", { check => 1, maintainer => $config->{admin} }, 'urpmi', 'sudo') or die "FATAL $program_name: could not add urpmi and sudo in the chroot";
777 add_sudoers(\%run, $chroot_tmp, $luser);
778 if ($run{shell}) {
779 plog('NOTIFY', "dumping to a chrooted shell into $chroot_tmp");
780 exec $sudo, $config->{iurt_root_command}, '--chroot', $chroot_tmp, '/bin/su', '-', $luser, '-c', "$config->{prompt} bash";
781 die "FATAL $program_name: could not exec chroot to $chroot_tmp ($!)";
782 }
783 }
784
785 # perform some cleaning before running to have some more space, rsync to
786 # the server too in case previous iurt crashed
787
788 if ($config->{rsync_to} && !$run{no_rsync}) {
789 # remove some old and very big log files not to saturate the server
790 system(qq(find $local_spool/log/ -name "*.log" \\( -size +$config->{log_size_limit} -or -mtime +$config->{log_size_date} \\) -exec rm -f {} \\;));
791 system('rsync', '--delete', '-alHPe', 'ssh -xc arcfour', "$local_spool/log/", "$config->{rsync_to}/$run{distro_tag}/$run{my_arch}/$run{media}/log/");
792 }
793
794 if ($run{dkms} && $run{dkms_todo}) {
795 $done += $dkms->dkms_compile($local_spool, $done);
796 }
797
798 # The next loop should be moved in a module someday
799
800 # FIXME: (tv) kill this dead code or use it!!
801 my $_s = sub {
802 if ($run{main}) {
803 plog("dumping cache...");
804 dump_cache_par(\%run);
805 $Data::Dumper::Indent = 0;
806 $Data::Dumper::Terse = 1;
807 plog("Running environment:\n", Data::Dumper->Dump([\%run]), "\n");
808 plog("Configuration:\n", Data::Dumper->Dump([$config]), "\n");
809 }
810 exit();
811 };
812 #$SIG{TERM} = $s;
813 #$SIG{INT} = $s;
814 $run{main} = 1;
815
816 my $rebuild;
817 $run{group} = 0 if @{$run{todo}} == 1;
818 if ($run{group}) {
819 $rebuild = 1;
820 $urpmi->set_local_media($local_spool);
821 $urpmi->order_packages($union_id, \%provides, $luser)
822 or die "FATAL $program_name: could not order packages";
823 }
824 #
825 # The build loop
826 #
827 my $prev_done = $done;
828 do {
829 $rebuild = 0;
830 $done = $prev_done;
831 for (my $i; $i < @{$run{todo}}; $i++) {
832 my ($dir, $srpm, $status) = @{$run{todo}[$i]};
833
834 # CM: Set argv[0] (in the C sense) to something we can easily spot and
835 # understand in process list
836 $0 = "Iurt: $run{distro_tag} $run{my_arch} $run{media} $srpm";
837
838 $status or next;
839 $done{$srpm} and next;
840 $done{$srpm} = 1;
841 check_version(\%run, $srpm, \%srpm_version) or next;
842 if ($run{debug}) { $run{debug}++ == 2 and exit() }
843 $done++;
844 plog('NOTIFY', "Build package $srpm [$done/$to_compile]");
845 # When rebuilding all the media, src.rpm can be removed from mirror before we work on them
846 unless (-f "$dir/$srpm") {
847 $cache->{failure}{$srpm} = 1;
848 $run{status}{$srpm} = 'missing';
849 dump_cache_par(\%run);
850 dump_status($local_spool, \%run);
851 next;
852 }
853 # FIXME unfortunately urpmi stalls quite often
854 my $retry = 0;
855
856 # current rpm is sometime segfaulting, and iurt is them blocked
857 # and cannot
858 #
859 # $cache->{failure}{$srpm} = 1;
860 # dump_cache(\%run);
861 retry:
862 $urpmi->clean_urpmi_process;
863
864 if (!$run{use_old_chroot}) {
865 (my $u_id, $chroot_tmp) = create_temp_chroot(\%run, $config,
866 $cache, $union_id, $chroot_tmp, $chroot_tar, $srpm) or next;
867 $union_id = $u_id;
868 }
869
870 if (!$urpmi->urpmi_command($chroot_tmp, $luser)) {
871 plog('DEBUG', "Creating chroot failed.\nCommand was: $chroot_tmp");
872 next;
873 };
874 $srpm =~ /(.*)-[^-]+-[^-]+\.src\.rpm$/ or next;
875 my ($maintainer, $cc);
876 if (!$run{warn}) {
877 ($maintainer) = get_maint(\%run, $srpm);
878 $cc = $maint{$srpm};#, maintainers\@mandriva.com";
879 chomp $maintainer;
880 if (!$maintainer || $maintainer eq 'NOT_FOUND') {
881 $maintainer = $cc;
882 #$cc = 'maintainers@mandriva.com'
883 }
884 }
885 #($maintainer, $cc) = ($config->{admin},'');
886
887 plog('DEBUG', "creating user $luser in chroot");
888 add_local_user($chroot_tmp, \%run, $config, $luser, $run{uid}) or next;
889
890 my $old_srpm = $srpm;
891 my ($ret, $srpm, $spec) = $urpmi->recreate_srpm(\%run, $config,
892 $chroot_tmp, $dir, $srpm, $luser, $retry);
893 if ($ret == -1) {
894 $retry = 1;
895 goto retry;
896 } elsif (!$ret) {
897 # CM: experimental: fail if we can't regenerate the srpm
898 # This should eliminate bouncers that block the input queue
899 #
900 $srpm = $old_srpm;
901 $cache->{failure}{$srpm} = 1;
902 $run{status}{$srpm} = 'recreate_srpm_failure';
903 dump_cache_par(\%run);
904 dump_status($local_spool, \%run);
905 next;
906 }
907
908 (my $log_dirname = $srpm) =~ s/.*:(.*)\.src.rpm/$1/;
909 my $log_dir = "$local_spool/log/$log_dirname/";
910
911 # only create the log dir for the new srpm
912 mkdir $log_dir;
913 -d $log_dir or die "FATAL: could not create $log_dir (check permissions and group ownerships)";
914
915 plog('INFO', "Install build dependencies");
916 my $path_srpm = "$chroot_tmp/home/$luser/rpm/SRPMS/";
917
918 # on x86_64 the rpm database is getting corrupted and sometimes
919 # rpm do not found anymore installed packages, retrying several
920 # time to be sure something is really broken
921
922 my $ok = $urpmi->install_packages($srpm, $chroot_tmp, $local_spool, \%pack_provide, 'install_deps', "[REBUILD] install of build dependencies of $srpm failed on $run{my_arch}", { maintainer => $maintainer }, "$path_srpm/$srpm");
923 if (!$ok) {
924 $run{status}{$srpm} ||= 'install_deps_failure';
925 next;
926 }
927
928 # try to workarround the rpm -qa db4 error(2) from dbcursor->c_get:
929 # No such file or directory
930 # system("sudo chroot $chroot_tmp rm -rf /var/lib/rpm/__db* &> /dev/null");
931 # system("$sudo chroot $chroot_tmp rpm --rebuilddb &> /dev/null");
932
933 perform_command("rpm --root $chroot_tmp -qa | sort",
934 \%run, $config, $cache,
935 logname => "rpm_qa",
936 hash => "rpm_qa_$srpm",
937 timeout => 60,
938 debug_mail => $run{debug},
939 log => $log_dir); # or next; As this failed quite often, do not stop
940 plog('NOTIFY', "Building $srpm");
941 my $command = "rpmbuild --rebuild $run{with_flags} /home/$luser/rpm/SRPMS/$srpm";
942 if ($run{stop}) {
943 $urpmi->install_packages('chroot', $chroot_tmp, $local_spool, \%pack_provide, 'configure', "[ADMIN] installation of urpmi and sudo failed in the chroot $run{my_arch}", { check => 1, maintainer => $config->{admin} }, 'urpmi', 'sudo');
944 add_sudoers(\%run, $chroot_tmp, $luser);
945 $command = "rpmbuild -b$run{stop} /home/$luser/rpm/SPECS/$spec";
946 }
947
948 my ($srpm_name) = $srpm =~ /(?:.*:)?(.*)-[^-]+-[^-]+\.src\.rpm$/;
949 my $icecream;
950 if ($run{icecream}) {
951 $icecream = "RPM_BUILD_NCPUS=$run{icecream}";
952 }
953
954 if (!perform_command(qq(chroot $chroot_tmp /bin/su - $luser -c "TMP=/home/$luser/tmp/ $icecream $command"),
955 \%run, $config, $cache,
956 use_iurt_root_command => 1,
957 mail => $maintainer,
958 error => "[REBUILD] $srpm from $run{distro_tag} does not build correctly on $run{my_arch}",
959 logname => "build",
960 hash => "build_$srpm",
961 timeout => $config->{build_timeout}{$srpm_name} ? $config->{build_timeout}{$srpm_name} : $config->{build_timeout}{default},
962 srpm => $srpm,
963 debug_mail => $run{debug},
964 cc => $cc,
965 log => $log_dir,
966 error_regexp => 'rror.*ailed|Bad exit status|RPM build error',
967 callback => sub {
968 my ($opt, $output) = @_;
969 if ($run{stop}) {
970 plog("dumping to a chrooted shell into $chroot_tmp (pid $$)");
971 # exec does not work because it seems stdin and out are shared between children
972 system($sudo, $config->{iurt_root_command}, '--chroot', $chroot_tmp, '/bin/su', '-', $luser, '-c', "$config->{prompt} bash");
973 exit();
974 }
975 plog('DEBUG', "calling callback for $opt->{hash}");
976 if ($run{unionfs_tmp} && $output =~ /no space left on device/i) {
977 plog('ERROR', "ERROR: running out of space to compile $srpm in unionfs mode, will recompile it in normal mode");
978 $cache->{no_unionfs}{$srpm} = 1;
979 return 1;
980 } elsif ($run{unionfs_tmp} && $output =~ m,$home,) {
981 plog('ERROR', "ERROR: seems like building $srpm needs to access /proc/self/exe, which is broken with unionfs, will try to recompile it in non unionfs mode");
982 $cache->{no_unionfs}{$srpm} = 1;
983 return 1;
984 } elsif ($output =~ /bin\/ld: cannot find -l(\S*)|configure.*error.* (?:-l([^\s]+)|([^\s]+) includes)/) {
985 my $missing = $1;
986 my @rpm = find_provides(\%run, \%pack_provide, $missing);
987 plog(5, "likely @rpm ($missing-devel) needed to rebuilt $srpm is not in build_requires");
988 if ($maintainer ne 'NOT_FOUND') {
989 $opt->{mail} = $maintainer;
990 #$opt->{mail} .= ", other_maint";
991 }
992 if (!$opt->{mail}) {
993 $opt->{mail} = "Maintainer not found <$config->{admin}>";
994 }
995 if (@rpm > 1) {
996 $opt->{error} = "[MISSING_BUILD_REQUIRES_TAG] one of @rpm ($missing-devel), needed to build $srpm, is not in buildrequires";
997 } elsif (@rpm == 1) {
998 $opt->{error} = "[MISSING_BUILD_REQUIRES_TAG] @rpm ($missing-devel), needed to build $srpm, is not in buildrequires";
999 } else {
1000 $opt->{error} = "[MISSING_BUILD_REQUIRES_TAG] $missing-devel, needed to build $srpm, is not in buildrequires";
1001 }
1002 $cache->{buildrequires}{$srpm}{$missing} = \@rpm;
1003 return;
1004 }
1005 1;
1006 },
1007 freq => 1)) {
1008
1009 # FIXME
1010 # The simple algo used here is :
1011 # try to compile it with unionfs, if it runs out of space,
1012 # compile it without the next time
1013 #
1014 # This could be improved in keeping this srpm name for future
1015 # version, but if we compile it on a new machine with more ram,
1016 # or if next version compiles just fine with unionfs, we will
1017 # loose the unionfs advantage.
1018 #
1019 # Maybe the right thing to do would be to first try to increase
1020 # the tmpfs size (more than 50 % of the physical RAM), but this
1021 # will lead to more swap usage, and slower compilation (and lost
1022 # of the unionfs plus). Or to keep the faulty package a unionfs
1023 # exception for some time, to save some more extra builds.
1024
1025 if (!glob "$chroot_tmp/home/$luser/rpm/RPMS/*/*.rpm") {
1026 if ($run{unionfs_tmp} && $cache->{no_unionfs}{$srpm}) {
1027 goto retry;
1028 }
1029 $cache->{failure}{$srpm} = 1;
1030 $run{status}{$srpm} = 'build_failure';
1031 # 20060615
1032 dump_cache_par(\%run);
1033 dump_status($local_spool, \%run);
1034 next;
1035 }
1036 }
1037
1038 # do some cleaning if the compilation is successful
1039 delete $cache->{needed}{$srpm} if defined $cache->{needed}{$srpm};
1040 delete $cache->{buildrequires}{$srpm} if defined $cache->{buildrequires}{$srpm};
1041 # FIXME It seems the glob is not correctly expanded any more, so listing the directory content to do so
1042 opendir my $binfh, "$chroot_tmp/home/$luser/rpm/RPMS/";
1043 my @packages;
1044 foreach my $bindir (readdir $binfh) {
1045 -d "$chroot_tmp/home/$luser/rpm/RPMS/$bindir" or next;
1046 opendir my $rpmfh, "$chroot_tmp/home/$luser/rpm/RPMS/$bindir";
1047 push @packages, map { "$chroot_tmp/home/$luser/rpm/RPMS/$bindir/$_" } grep { !/src\.rpm$/ && /\.rpm$/ } readdir $rpmfh;
1048 }
1049
1050 # 20060810 warly We should fail here, but rpm is currently
1051 # segfaulting when trying to install packages
1052
1053 if ($config->{check_binary_file}) {
1054 $urpmi->install_packages($srpm, $chroot_tmp, $local_spool, \%pack_provide, 'binary_test', "[REBUILD] binaries packages generated from $srpm do not install correctly", { maintainer => $maintainer } ,@packages) or next;
1055 } else {
1056 my $successfile = "$local_spool/log/$srpm/binary_test_$srpm-1.log";
1057 open my $f, ">$successfile";
1058 print $f "$srpm build ok";
1059 }
1060
1061 $run{status}{$srpm} = 'ok';
1062 delete $cache->{failure}{$srpm} if defined $cache->{failure}{$srpm};
1063 if ($run{debug}) {
1064 plog("debug mode, skip other packages");
1065 exit();
1066 } elsif ($run{group}) {
1067 # we should not move the package until they are all compiled
1068 plog("group mode, keep packages for local media ($srpm is done $done)");
1069 $run{done}{$srpm} = $done;
1070 $urpmi->add_to_local_media($chroot_tmp, $srpm, $luser);
1071 } else {
1072 # drop packages and logs if we only want failure logs
1073 if ($run{delete_on_success}) {
1074 system("rm -rf $local_spool/log/$srpm/");
1075 } else {
1076 plog('OK', "build successful, copying packages to $local_spool.");
1077
1078 system("cp $chroot_tmp/home/$luser/rpm/RPMS/*/*.rpm $local_spool &>/dev/null") and plog('ERR', "ERROR: could not copy rpm files from $chroot_tmp/home/$luser/rpm/RPMS/ to $local_spool ($!)");
1079 }
1080
1081 if ($run{copy_srpm}) {
1082 # replace the old srpm
1083 unlink "$local_spool/$old_srpm";
1084
1085 system("cp $chroot_tmp/home/$luser/rpm/SRPMS/$srpm $local_spool &>/dev/null") and plog('ERR', "ERROR: could not copy $srpm from $chroot_tmp/home/$luser/rpm/SRPMS/ to $local_spool ($!)");
1086 }
1087 process_queue($config, \%run, \@wrong_rpm, 1);
1088 }
1089 # dymp_cache each time so that concurrent process can get updated
1090 dump_cache_par(\%run) if $run{concurrent_run};
1091 }
1092 if ($run{group}) {
1093 for (my $i; $i < @{$run{todo}}; $i++) {
1094 my (undef, $srpm) = @{$run{todo}[$i]};
1095 if (!$run{done}{$srpm}) {
1096 $rebuild = $urpmi->order_packages($union_id, \%provides, $luser);
1097 last;
1098 }
1099 }
1100 if ($prev_done == $done) {
1101 $rebuild = 0;
1102 if ($done == @{$run{todo}}) {
1103 plog('OK', "all packages succesfully compiled, copying packages to $local_spool.");
1104 system("cp $chroot_tmp/home/$luser/rpm/RPMS/*/*.rpm $local_spool &>/dev/null") and plog('ERR', "ERROR: could not copy rpm files from $chroot_tmp/home/$luser/rpm/RPMS/ to $local_spool ($!)");
1105 if ($run{copy_srpm}) {
1106 system("cp $chroot_tmp/home/$luser/rpm/SRPMS/*.src.rpm $local_spool &>/dev/null") and plog('ERR', "ERROR: could not copy SRPMS from $chroot_tmp/home/$luser/rpm/SRPMS/ to $local_spool ($!)");
1107 }
1108 } else {
1109 plog('FAIL', "some packages could not be compiled.");
1110 }
1111 }
1112 }
1113 } while $rebuild;
1114
1115 my ($unionfs_dir) = $run{unionfs_dir} =~ m!(.*)/[^/]+/?!;
1116 if (!$run{debug} && !$run{use_old_chroot}) {
1117 if ($run{unionfs}) {
1118 clean_unionfs("$unionfs_dir/$run{user}", \%run, $run{run}, $union_id);
1119 } else {
1120 clean_chroot($chroot_tmp, $chroot_tar, \%run, $config, 1);
1121 }
1122 }
1123 plog("reprocess generated packages queue");
1124 process_queue($config, \%run, \@wrong_rpm);
1125
1126 dump_cache_par(\%run);
1127
1128 plog('FAIL', "ERROR: RPM with a wrong SRPM name") if @wrong_rpm;
1129 if (@wrong_rpm && open my $file, ">$local_spool/log/wrong_srpm_names.log") {
1130 foreach (@wrong_rpm) {
1131 print $file "$_->[1] -> $_->[0] (", $cache->{rpm_srpm}{$_->[1]}, ")\n";
1132 }
1133 }
1134
1135 dump_status($local_spool, \%run);
1136
1137 send_status_mail(\%run, $config, $cache) if $run{status_mail};
1138
1139 if ($config->{rsync_to} && !$run{no_rsync}) {
1140 # remove some old and very big log files not to saturate the server
1141 system(qq(find $local_spool/log/ -name "*.log" \\( -size +$config->{log_size_limit} -or -mtime +$config->{log_size_date} \\) -exec rm -f {} \\;));
1142 system('rsync', '--delete', '-alHPe', 'ssh -xc arcfour', "$local_spool/log/", "$config->{rsync_to}/$run{distro_tag}/$run{my_arch}/$run{media}/log/");
1143 }
1144
1145 # one last try to clean
1146 plog('DEBUG', "clean remaining unionfs");
1147 if ($run{unionfs} && !$run{use_old_chroot}) {
1148 remove_chroot(\%run, $unionfs_dir, \&clean_all_unionfs);
1149 }
1150 unlink "$run{pidfile_home}/$run{pidfile}" if $run{pidfile};
1151
1152 exit();
1153
1154
1155 #
1156 #
1157 #
1158
1159 sub check_needed {
1160 my ($srpm, $cache, $provides) = @_;
1161 if (!defined $cache->{needed}{$srpm} && !ref $cache->{needed}{$srpm}) { return 1 }
1162 my $ok = 1;
1163 # migrate old cache format
1164 my $ent = $cache->{needed}{$srpm};
1165 if (ref $ent eq 'ARRAY') {
1166 my $table = $ent;
1167 $cache->{needed}{$srpm} = {};
1168 foreach my $t (@$table) {
1169 my ($missing, $version, $maint) = @$t;
1170 $cache->{needed}{$srpm}{$missing} = {
1171 version => $version,
1172 maint => $maint
1173 };
1174 }
1175 $ent = $cache->{needed}{$srpm};
1176 }
1177 foreach my $name (keys %$ent) {
1178 my ($package, $version, $maint) = @{$ent->{$name}}{'package', 'version', 'maint'};
1179 # if packages does not exist anymore, it may have been rebuild, then try to recompute the build dependencies
1180 last if $package && !$provides->{$package};
1181 my $p_version = $provides->{$name};
1182 if ($p_version) {
1183 next if $version == $p_version;
1184 next if URPM::ranges_overlap($version, $p_version);
1185 }
1186 $ok = 0;
1187 if ($version) {
1188 $ent->{$name}{version} = $version;
1189 }
1190 my $v = $version;
1191 if ($package) {
1192 plog("ERROR: $srpm needs package $package which requires missing $name $v to be compiled.");
1193 } else {
1194 plog("ERROR: $srpm needs $name $v to be compiled.");
1195 }
1196 # try to recompile it once in a while
1197 last if $cache->{warning}{"install_deps_$srpm"}{$maint}++ % 72;
1198 return 1;
1199 }
1200 delete $cache->{needed}{$srpm} if $ok;
1201 $ok;
1202 }
1203
1204 sub process_queue {
1205 my ($config, $run, $wrong_rpm, $quiet) = @_;
1206 return if !$run->{upload} && $quiet;
1207 my $dir = "$config->{local_upload}/iurt/$run->{distro_tag}/$run->{my_arch}/$run->{media}/";
1208 opendir my $rpmdir, $dir or return;
1209 my $urpmi = $run->{urpmi};
1210 foreach my $rpm (readdir $rpmdir) {
1211 my ($rarch, $srpm) = $urpmi->update_srpm($dir, $rpm, $wrong_rpm);
1212 $rarch or next;
1213 plog($rpm);
1214 next if !$run->{upload};
1215 # recheck if the package has not been uploaded in the meantime
1216 my $rpms_dir = "$config->{repository}/$run->{distro}/$run->{my_arch}/media/$run->{media}/";
1217 if (! -f "$rpms_dir/$rpm") {
1218 my $err = system('/usr/bin/scp', "$dir/$rpm", $config->{upload} . "/$config->{extra_subdir}/RPMS/");
1219 # try to keep the opportunity to prevent disk full
1220 if ($err) {
1221 plog("ERROR: process_queue: cannot copy $dir/$rpm to ", $config->{upload}, "/$config->{extra_subdir}/RPMS/ ($!)");
1222 next;
1223 }
1224 }
1225 if ($run->{upload_source}) {
1226
1227 }
1228 unlink "$dir/$rpm";
1229 $cache->{queue}{$srpm} = 1;
1230 }
1231 closedir $rpmdir;
1232 }
1233
1234 sub check_version {
1235 my ($run, $srpm, $srpm_version) = @_;
1236 my ($srpm_name) = $srpm =~ /(.*)-[^-]+-[^-]+\.src\.rpm/;
1237 $run->{build_all} and return 1;
1238 if (URPM::ranges_overlap("= $srpm", ">= $srpm_version->{$srpm_name}")) {
1239 $srpm_version->{$srpm_name} = $srpm;
1240 return 1;
1241 }
1242 0;
1243 }
1244
1245 sub check_pid {
1246 my ($run, $local) = @_;
1247 my $hostname = `hostname`;
1248 chomp $hostname;
1249 my $pidfile = $run->{pidfile};
1250 my $lockfile = "$run->{pidfile_home}/$pidfile.$hostname.pid.lock";
1251 plog("trying to lock $lockfile");
1252 open my $lock, ">$lockfile";
1253 my $lock_ok;
1254 # lockf seems not to work, try to workarround, but this start to create lock on the lock for the lock of the file.
1255 my $status = 1; #File::lockf::lock($lock);
1256 if (!$status) {
1257 $lock_ok = 1;
1258 } else {
1259 plog("ERROR: could not lock pid file (status $status $!)");
1260 if (! -f "$lockfile.2") {
1261 plog("using $lockfile.2 as lock file");
1262 open my $lock2, ">$lockfile.2" or die "FATAL $program_name: could not open lock file $lockfile.2";
1263 print $lock2 $$;
1264 close $lock2;
1265 }
1266 }
1267 if (!$run->{concurrent_run} && !$local) {
1268 opendir my $dir, $run->{pidfile_home};
1269 foreach my $f (readdir $dir) {
1270 my ($pid_host) = $f =~ /$pidfile\.pid\.(.*)\.pid$/ or next;
1271 if ($pid_host ne $hostname) {
1272 my $pf = "$run->{pidfile_home}/$f";
1273 open my $test_PID, $pf;
1274 my $pid = <$test_PID>;
1275 my (@stat) = stat $pf;
1276 my $time = $stat[9];
1277 my $diff = time()-$time;
1278 my $msg = "$program_name: an other iurt is running for $run->{my_arch} on $pid_host, pid $pid, since $diff seconds";
1279 if ($diff < 36000) {
1280 plog("$msg\n");
1281 exit();
1282 } else {
1283 plog("$msg, ignoring it");
1284 }
1285 }
1286 }
1287 }
1288 $run->{pidfile} .= ".$hostname.pid";
1289 $pidfile = "$run->{pidfile_home}/$run->{pidfile}";
1290 if (-f $pidfile) {
1291 my (@stat) = stat $pidfile;
1292 open my $test_PID, $pidfile;
1293 my $pid = <$test_PID>;
1294 close $test_PID;
1295 if (!$pid) {
1296 plog("ERROR: invalid pidfile ($pid), should be <pid>");
1297 unlink $pidfile;
1298 }
1299 if ($pid && getpgrp $pid != -1) {
1300 my $time = $stat[9];
1301 my $state = `ps h -o state $pid`;
1302 chomp $state;
1303 if ($time < time()-36000 || $state eq 'Z') {
1304 plog("an other iurt pid $pid is running for a very long time or is zombie, killing it");
1305 my $i;
1306 while ($i < 5 && getpgrp $pid != -1) {
1307 kill_for_good($pid);
1308 $i++;
1309 sleep 1;
1310 }
1311 } else {
1312 plog("an other iurt is running for $run->{my_arch}, pid $pid, since ", time()-$time, " seconds");
1313 exit();
1314 }
1315 } else {
1316 plog("a previous iurt for $run->{my_arch} seems dead, cleaning.");
1317 unlink $pidfile;
1318 }
1319 }
1320 plog("setting $pidfile pid lock");
1321 open my $PID, ">$pidfile" or die "FATAL $program_name: could not open pidfile $pidfile for writing";
1322 print $PID $$;
1323 close $PID;
1324 if ($lock_ok) {
1325 File::lockf::ulock($lock);
1326 } else {
1327 unlink "$lockfile.2";
1328 }
1329 close $lock;
1330 unlink $lockfile;
1331 }
1332
1333 sub check_media {
1334 my ($run, $cache, $config, $srpm_version, $wrong_rpm, $provides, $pack_provide, $maint) = @_;
1335 # We could rely on only parsing the synthesis, hoping that they are correct, however this scan is very fast, so...
1336 if (!$run->{build_all}) {
1337 foreach my $subdir (@{$config->{all_media}{$run->{media}}}) {
1338 my $rpms_dir = "$config->{repository}/$run->{distro}/$run->{my_arch}/media/$run->{media}/$subdir/";
1339 plog("checking current packages in $rpms_dir");
1340 opendir my $rpmdir, $rpms_dir or die "Could not open $rpms_dir: $!";
1341 my $urpmi = $run->{urpmi};
1342 foreach my $rpm (readdir $rpmdir) {
1343 my ($rarch, $srpm) = $urpmi->update_srpm($rpms_dir, $rpm, $wrong_rpm);
1344 $rarch or next;
1345 $cache->{queue}{$srpm} = 1;
1346 $run{status}{$srpm} = 'ok';
1347 check_version($run, $srpm, $srpm_version);
1348 }
1349 closedir $rpmdir;
1350 }
1351 }
1352
1353 foreach my $m (keys %{$config->{all_media}}) {
1354 foreach my $subdir (@{$config->{all_media}{$m}}) {
1355 my $synthesis_file = "$config->{repository}/$run->{distro}/$run->{my_arch}/media/$m/$subdir/media_info/synthesis.hdlist.cz";
1356 if (-f $synthesis_file) {
1357 plog("Parsing $synthesis_file");
1358 if (open my $syn, "zcat $synthesis_file |") {
1359 my @prov;
1360 my $nb;
1361 local $_;
1362 while (<$syn>) {
1363 if (/^\@provides@(.*)/) {
1364 foreach my $p (split '@', $1) {
1365 if ($p =~ /([^[]+)(?:\[(.*)\])?/g) {
1366 push @prov, $1;
1367 $provides->{$1} = $2 || 1;
1368 }
1369 }
1370 } elsif (/\@info\@([^@]+)@/) {
1371 $nb++;
1372 my $p = $1;
1373 my ($name) = $p =~ /(.*)-[^-]+-[^-]+\./;
1374 $provides->{$p} = 1;
1375 foreach (@prov) {
1376 $pack_provide->{$_} = $name;
1377 }
1378 @prov = ();
1379 }
1380 }
1381 $nb < $config->{minimum_package_number} and die "FATAL $program_name: synthesis files seems corrupted, only $nb packages found.";
1382 } else {
1383 die "FATAL $program_name: Could not open $synthesis_file\n";
1384 }
1385 }
1386 }
1387 }
1388 #"
1389 my $nb;
1390 foreach my $subdir (@{$config->{all_media}{$run->{media}}}) {
1391 $nb += search_packages(0, $cache, $provides, $run, $maint, $srpm_version, "$config->{repository}/$run->{distro}/SRPMS/$run->{media}/$subdir/");
1392 }
1393 $nb;
1394 }
1395
1396 sub search_packages {
1397 my ($clean, $cache, $provides, $run, $_maint, $srpm_version, @dir) = @_;
1398 my ($to_compile, %rep);
1399 plog("iurt search_package: @dir");
1400 foreach my $dir (@dir) {
1401 plog("checking SRPMS dir $dir");
1402 opendir my $rpmdir, $dir or next;
1403 foreach my $srpm (readdir $rpmdir) {
1404 # this is for the output of the new svn system
1405 if ($srpm =~ /^\@\d+:(.*)/) {
1406 link "$dir/$srpm", "$dir/$1";
1407 # unlink "$dir/$srpm";
1408 $srpm = $1;
1409 }
1410 $srpm =~ /(.*)-[^-]+-[^-]+\.src\.rpm$/ or next;
1411 $run->{status}{$srpm} ||= 0;
1412 if ($config->{unwanted_packages} && $srpm =~ /$config->{unwanted_packages}/) { next }
1413 my $ok = 1;
1414 if (check_version($run, $srpm, $srpm_version)) {
1415 if (!$run->{ignore_failure} && defined $cache->{failure}{$srpm}) {
1416 $run->{status}{$srpm} = 'build_failure';
1417 next;
1418 }
1419 my $check_needed = check_needed($srpm, $cache, $provides);
1420 $run->{status}{$srpm} = 'missing_buildrequires' if !$check_needed;
1421 -f "$dir/$srpm" or next;
1422 if (!$cache->{queue}{$srpm} && $check_needed) {
1423 if (!check_arch("$dir/$srpm", $run{my_arch})) {
1424 $run->{status}{$srpm} = 'not_on_this_arch';
1425 next;
1426 }
1427 my $hdr = RPM4::Header->new("$dir/$srpm");
1428 my $changelog = $hdr->queryformat("%{CHANGELOGNAME}");
1429 my ($mail) = $changelog =~ /<(.*@.*)>/;
1430 $maint{$srpm} = $mail;
1431 print "$program_name: will try to compile $srpm\n";
1432 $to_compile++;
1433 push @{$run->{todo}}, [ $dir , $srpm, 1 ];
1434 }
1435 foreach my $arch (@{$config->{supported_arch}}) { #FIXME: (tv) this loop looks suspiciously broken
1436 $ok &&= $cache->{queue}{$srpm};
1437 }
1438 }
1439 if ($clean && ($rep{$srpm} || $ok)) {
1440 print "$program_name: cleaning $dir/$srpm\n";
1441 unlink "$dir/build/$srpm";
1442 unlink "$dir/$srpm";
1443 }
1444 $rep{$srpm} = 1;
1445 }
1446 closedir $rpmdir;
1447 }
1448 $to_compile;
1449 }
1450
1451 sub add_sudoers {
1452 my ($run, $chroot, $user) = @_;
1453 my $tmpfile = "/tmp/sudoers";
1454 my $file = "$chroot/etc/sudoers";
1455 my $f;
1456 if (!open $f, ">$tmpfile") {
1457 plog("ERROR: could not open $file ($!)");
1458 return 0;
1459 }
1460 print $f qq(Cmnd_Alias RPM=/bin/rpm,/usr/sbin/urpmi,/usr/sbin/urpme,/usr/sbin/urpmi.addmedia,/usr/sbin/urpmi.update,/usr/sbin/urpmi.removemedia
1461 root ALL=(ALL) ALL
1462 $user ALL=(ALL) NOPASSWD:RPM
1463 );
1464 close $f;
1465 chmod 0440, $tmpfile;
1466
1467 plog("adding sudo for /bin/rpm, /usr/sbin/urpmi and /usr/sbin/urpme");
1468 my $ret = sudo($run, $config, '--cp', $tmpfile, $file);
1469 unlink $tmpfile;
1470
1471 if (!$ret) {
1472 plog("ERROR: could not write $file ($!)");
1473 return 0;
1474 }
1475
1476 return -f $file;
1477 }
1478
1479 sub dump_status {
1480 my ($local_spool, $run) = @_;
1481 my $media = $run->{media} ? "$run->{media}." : "";
1482 if (open my $file, ">$local_spool/log/status.${media}log") {
1483 foreach my $srpm (sort keys %{$run->{status}}) {
1484 print $file "$srpm: ";
1485 if ($run{status}{$srpm}) {
1486 print $file $run->{status}{$srpm};
1487 } else {
1488 print $file "unknown";
1489 }
1490 print $file "\n";
1491 }
1492 }
1493 }
1494
1495 #
1496 # CM: FIXME: should notify in case of recreate_srpm_failure
1497 #
1498
1499 sub send_status_mail {
1500 my ($run, $config, $cache) = @_;
1501 my %output;
1502
1503 print "iurt compilation status\n";
1504
1505 foreach my $rpm (keys %{$run->{status}}) {
1506 next if $run->{status}{$rpm} =~ /ok|not_on_this_arch/;
1507
1508 if ($run->{status}{$rpm} eq 'missing_buildrequires') {
1509 foreach my $missing (keys %{$cache->{needed}{$rpm}}) {
1510 my $h = $cache->{needed}{$rpm}{$missing};
1511 my $maint = $h->{maint} || 'Other';
1512 my $package = $h->{package};
1513 if ($package) {
1514 push @{$output{missing}{$maint}{$package}{$missing}{$h->{version}}}, $rpm;
1515 } else {
1516 $output{missing}{$maint}{$rpm}{$missing}{$h->{version}} = 1;
1517 }
1518 }
1519 } elsif ($run->{status}{$rpm} eq 'build_failure') {
1520 my ($maint) = get_maint($run, $rpm);
1521 if ($cache->{buildrequires}{$rpm}) {
1522 push @{$output{buildrequires}{$maint}}, $rpm;
1523 } else {
1524 push @{$output{build}{$maint}}, $rpm;
1525 }
1526 } elsif (!$run->{status}{$rpm}) {
1527 # need to find something more usefull to do at that point
1528 next;
1529 }
1530 }
1531
1532 my $text = "*** Missing buildrequires tag in specfile ***\n";
1533 foreach my $maint (keys %{$output{buildrequires}}) {
1534 $text .= "\n$maint\n";
1535 foreach my $pack (keys %{$output{missing}{$maint}}) {
1536 foreach my $missing (keys %{$cache->{buildrequires}{$pack}}) {
1537 my $rpms = $cache->{buildrequires}{$pack}{$missing};
1538 if (@$rpms) {
1539 $text .= " $pack should have a buildrequires on @$rpms (for $missing-devel)\n";
1540 } else {
1541 $text .= " $pack should have a buildrequires for $missing-devel\n";
1542 }
1543 }
1544 }
1545 }
1546
1547 $text = "*** Missing dependencies ***\n";
1548 foreach my $maint (keys %{$output{missing}}) {
1549 $text .= "\n$maint\n";
1550 foreach my $pack (keys %{$output{missing}{$maint}}) {
1551 foreach my $missing (%{$output{missing}{$maint}{$pack}}) {
1552 my $h = $output{missing}{$maint}{$pack}{$missing};
1553 foreach my $version (keys %$h) {
1554 if (ref $h->{$version}) {
1555 $text .= " $pack should be recompile because\n $missing " . ($version ? "$version " : '') . "is not provided anymore\n";
1556 $text .= " to compile " . join("\n ", @{$h->{$version}}) . "\n";
1557 } else {
1558 $text .= " $pack needs $missing " . ($version ? "$version " : '') . "\n";
1559 }
1560 }
1561 }
1562 }
1563 }
1564 $text .= "\n*** Build failure ***\n";
1565 foreach my $maint (keys %{$output{build}}) {
1566 $text .= "\n$maint\n";
1567 foreach my $rpm (@{$output{build}{$maint}}) {
1568 $text .= " $rpm (see $config->{log_url}/$run{distro_tag}/$run{my_arch}/$run->{media}/log/$rpm/)\n";
1569 }
1570 }
1571 print "$text\n";
1572 sendmail($run->{status_mail}, '' , "Iurt report for $run->{my_arch}/$run->{media}", $text, "Iurt the rebuild bot <$config->{admin}>", 0, $config);
1573 }
1574
1575 sub find_provides {
1576 my ($_run, $pack_provide, $p) = @_;
1577 my @rpm;
1578 foreach my $provides (keys %{pack_provide}) {
1579 if ($provides =~ /$p/ && $provides =~ /devel/) {
1580 push @rpm, $pack_provide->{$provides};
1581 }
1582 }
1583 @rpm;
1584 }
1585
1586 sub check_sudo_access() {
1587 return 0 == system("$sudo -l -n $config->{iurt_root_command} &>/dev/null </dev/null");
1588 }
1589
1590 __END__
1591
1592 Discussion
1593
1594 20061222 Warly
1595 Group building
1596 For the group building, we need to order the source packages, the problem is that we do not
1597 really know what will be the provides of the resulting packages before building the.
1598 We could guess them by looking to older version, but that means that we need to have an access to
1599 the media deps files (synthesis should be enough).
1600 We can also perform a first pass of build to check which package build and then what are their
1601 provides. For the second pass, we will them be able to use the previously build packages to
1602 solve buildrequires.

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.30