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

Contents of /build_system/iurt/trunk/iurt

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:executable *
svn:keywords Date Author Rev

  ViewVC Help
Powered by ViewVC 1.1.30