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