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. |