Adapt to mock-1.4.1-1.fc25
[Fedora-Rebuild.git] / lib / Fedora / Rebuild / Package.pm
blobd5cc4a696b0c08d1afa5864ea8b360dbec6de201
1 package Fedora::Rebuild::Package;
2 use strict;
3 use warnings;
4 use threads;
5 use threads::shared;
6 use Moose;
7 use File::Path::Tiny;
8 use File::Spec;
9 use Fedora::Rebuild::Package::StateLock;
10 use Fedora::Rebuild::RPM;
11 use Fedora::Rebuild::Mock;
12 use Data::Dumper;
13 use namespace::clean;
15 use version 0.77; our $VERSION = version->declare("v0.12.1");
17 has 'name' => (is => 'ro', isa => 'Str', required => 1);
18 # Build-time dependencies
19 has 'requires' => (is => 'rw', isa => 'HashRef', lazy_build => 1,
20 init_arg => undef);
21 # Run-time dependencies hashed by binary package ENVR.
22 has 'runrequires' => (is => 'rw', isa => 'HashRef', lazy_build => 1,
23 init_arg => undef);
24 # Run-time provides hashes by binary package ENVR.
25 has 'provides' => (is => 'rw', isa => 'HashRef', lazy_build => 1,
26 init_arg => undef);
27 has 'workdir' => (is => 'ro', isa => 'Str', required => 1);
28 # Git branch name
29 # "f14", "f15" etc. Use "rawhide" for latest one.
30 has 'dist' => (is => 'ro', isa => 'Str', required => 1);
31 # Fedpkg dist name identifier. This is required only if git branch name is not
32 # an offical one (e.g. a private branch).
33 # "f14", "f15" etc. Use "f18" for the latest one.
34 has 'pkgdist' => (is => 'ro', isa => 'Maybe[Str]', required => 0,
35 default => undef);
36 # Build target name
37 # "dist-f14", "dist-f15" etc. Use "rawhide" for latest one.
38 has 'target' => (is => 'ro', isa => 'Str', required => 1);
39 has 'message' => (is => 'ro', isa => 'Str', required => 1);
41 has 'packagedir' => (is => 'ro', isa => 'Str', lazy_build => 1,
42 init_arg => undef);
43 has 'repodir' => (is => 'ro', isa => 'Str', lazy_build => 1,
44 init_arg => undef);
45 has 'mockdir' => (is => 'ro', isa => 'Str', lazy_build => 1,
46 init_arg => undef);
47 has 'rpmdir' => (is => 'ro', isa => 'Str', lazy_build => 1,
48 init_arg => undef);
49 has 'requiresstore' => (is => 'ro', isa => 'Str', lazy_build => 1,
50 init_arg => undef);
51 has 'runrequiresstore' => (is => 'ro', isa => 'Str', lazy_build => 1,
52 init_arg => undef);
53 has 'providesstore' => (is => 'ro', isa => 'Str', lazy_build => 1,
54 init_arg => undef);
55 has 'taskstore' => (is => 'ro', isa => 'Str', lazy_build => 1,
56 init_arg => undef);
57 has 'branch' => (is => 'ro', isa => 'Str', lazy_build => 1,
58 init_arg => undef);
60 # Make object shared between threads.
61 # XXX: Not all attributes are shared automatically.
62 around 'new' => sub {
63 my $orig = shift;
64 my $class = shift;
65 return shared_clone($class->$orig(@_));
68 # Clean package locks bound to attributes
69 sub BUILD {
70 my $self = shift;
71 for my $state ('buildrequires', 'runrequires', 'provides') {
72 Fedora::Rebuild::Package::StateLock->new(package => $self,
73 state => $state)->mark_failed;
77 # BuildRequires. Shared.
78 # Initialize to empty hash. Call get_buildrequires() to populate.
79 sub _build_requires {
80 my $self = shift;
81 my $requires :shared = shared_clone({});
82 return $requires;
85 # Run-time Requires. Shared.
86 # Initialize to empty hash. Call get_runrequires() to populate.
87 sub _build_runrequires {
88 my $self = shift;
89 my $runrequires :shared = shared_clone({});
90 return $runrequires;
93 # Run-time provides. Shared.
94 # Initialize to empty hash. Call rebuild() or get_binaryprovides() to populate.
95 sub _build_provides {
96 my $self = shift;
97 my $provides :shared = shared_clone({});
98 return $provides;
101 sub _build_packagedir {
102 my $self = shift;
103 my $directory = File::Spec->catfile($self->workdir, $self->name);
104 if (! -d $directory) {
105 File::Path::Tiny::mk($directory) or
106 die "Could not create directory $directory: $!";
108 return $directory;
111 sub _build_repodir {
112 my $self = shift;
113 return File::Spec->catfile($self->packagedir, 'repository');
116 sub _build_mockdir {
117 my $self = shift;
118 return File::Spec->catfile($self->packagedir, 'mock');
121 sub _build_rpmdir {
122 my $self = shift;
123 return File::Spec->catfile($self->packagedir, 'RPMS');
126 sub _build_requiresstore {
127 my $self = shift;
128 return File::Spec->catfile($self->packagedir, 'buildrequires.store');
131 sub _build_runrequiresstore {
132 my $self = shift;
133 return File::Spec->catfile($self->packagedir, 'runrequires.store');
136 sub _build_providesstore {
137 my $self = shift;
138 return File::Spec->catfile($self->packagedir, 'provides.store');
141 sub _build_taskstore {
142 my $self = shift;
143 return File::Spec->catfile($self->packagedir, 'task.store');
146 sub _build_branch {
147 my $self = shift;
148 if ($self->dist eq 'rawhide') {
149 return 'master';
150 } else {
151 return $self->dist;
156 # Clones package repository and switch to proper branch if not yet done.
157 # First argument is anonymous clone boolean.
158 # Second argument is Fedora::Rebuild::Package::Config object.
159 # Return true on success.
160 sub clone {
161 my ($self, $anonymous, $build_config) = @_;
162 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
163 state => 'clone');
164 if ($lock->is_done) { return 1; }
166 # XXX: pyrpkg creates subdirectory named like package. The package name
167 # could clash with our file structure. Thus we need to clone into secure
168 # directory and move repository content to fixed name $self->repodir after
169 # that.
171 if (-d $self->repodir) { File::Path::Tiny::rm($self->repodir); }
172 my $tempdir = File::Spec->catfile($self->packagedir, 'tmp');
173 my $temprepodir = File::Spec->catfile($tempdir, $self->name);
174 if (-d $tempdir) { File::Path::Tiny::rm($tempdir); }
175 if (!File::Path::Tiny::mk($tempdir)) {
176 $lock->log("Could not create directory `" . $tempdir . "': $!\n");
177 return $lock->mark_failed;
180 if (!$lock->do($tempdir, $build_config->pyrpkg(), 'clone',
181 ($anonymous) ? '-a': (), $self->name)) {
182 $lock->log("Could not clone `" . $self->name . "' repository.\n");
183 return $lock->mark_failed;
186 if (!rename($temprepodir, $self->repodir)) {
187 $lock->log("Could not move `" . $temprepodir . "' content to to `" .
188 $self->repodir . "'.\n");
189 return $lock->mark_failed;
191 File::Path::Tiny::rm($tempdir);
193 if (!$lock->do($self->repodir, $build_config->pyrpkg(),
194 'switch-branch', $self->branch)) {
195 $lock->log("Could not switch `" . $self->name .
196 "' repository to branch `" . $self->branch . "'.\n");
197 return $lock->mark_failed;
200 return $lock->mark_done;
204 # Reset git repository and pull new changes.
205 # First argument is a state lock.
206 # XXX: The state is not marked as failed in case of error,
207 # Return true on success.
208 # Needs `clone'.
209 sub refreshgit {
210 my ($self, $lock) = @_;
211 if (!defined $lock) {
212 return 0;
215 # Reset git repository
216 if (!$lock->do($self->repodir, 'git', 'reset', '--hard',
217 'origin/' . $self->branch)) {
218 $lock->log("Could not reset git repository in `" . $self->repodir .
219 "'.\n");
220 return 0;
223 # Pull git repository
224 if (!$lock->do($self->repodir, 'git', 'pull')) {
225 $lock->log("Could not pull git repository in `" . $self->repodir .
226 "'.\n");
227 return 0;
230 return 1;
234 # Increase package revision with proper changelog entry. Do not commit nor
235 # push the changes.
236 # First argument is a state lock.
237 # XXX: The state is not marked as failed in case of error,
238 # Return true on success.
239 # Needs `clone'.
240 sub updatespec {
241 my ($self, $lock) = @_;
242 if (!defined $lock) {
243 return 0;
246 # Reset and pull git repository
247 if (!$self->refreshgit($lock)) {
248 return 0;
251 # Increase revision number
252 my $specfile = File::Spec->catfile($self->repodir, $self->name . '.spec');
253 if (!$lock->do(undef, 'rpmdev-bumpspec', '-c', $self->message, $specfile)) {
254 $lock->log("Could not increase revison number in `" . $specfile .
255 "' specfile.\n");
256 return 0;
259 return 1;
263 # Check if git repository is modifed (has uncommited changes).
264 # First arugument is a state lock.
265 # Second argument is a mode.
266 # Return -1 on an internal error.
267 # Return true if modifer, false otherwise.
268 # Needs `clone'.
269 sub gitismodified {
270 my ($self, $lock) = @_;
272 my $output;
273 if (!$lock->dooutput($self->repodir, \$output, 'git', 'status',
274 '--porcelain', '--untracked-files=no')) {
275 return -1;
277 if (defined $output and $output ne '') {
278 return 1;
281 return 0;
285 # Commit changes. And push them only if first argument is "koji".
286 # First arugument is a state lock.
287 # Second argument is a mode.
288 # Return true on success.
289 # Needs `clone'.
290 sub commitandpush {
291 my ($self, $lock, $mode) = @_;
293 # Commit changes
294 if (!$lock->do($self->repodir, 'git', 'commit', '-a',
295 '-m', $self->message)) {
296 $lock->log("Could not commit changes into git repository `" .
297 $self->repodir . "'.\n");
298 return 0;
301 if ($mode eq 'koji') {
302 # Push changes
303 if (!$lock->do($self->repodir, 'git', 'push')) {
304 $lock->log("Could not push changes from repository `" .
305 $self->repodir . "' to server.\n");
306 return 0;
308 } else {
309 $lock->log("Not pushing changes because of local build mode.\n");
312 return 1;
316 # Remove all state locks except `clone'.
317 # XXX: The state is not marked as failed in case of error.
318 # Returns true.
319 sub reset {
320 my ($self) = @_;
322 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
323 state => 'reset');
325 for my $state ('srpm', 'buildrequiresstore', 'edit', 'update',
326 'is_rebuildable', 'submitbuild', 'build', 'rpms', 'providesstore',
327 'runrequiresstore', 'rotate', 'buildrequires', 'runrequires',
328 'provides') {
329 $lock->log("Removing state lock $state\n");
331 if ($state eq 'rotate') {
332 $self->reset_rotate;
333 } else {
334 my $state_lock = Fedora::Rebuild::Package::StateLock->new(
335 package => $self, state => $state);
336 $state_lock->mark_failed;
337 $state_lock->remove_log;
340 $lock->log("States reset done.\n");
342 # The lock is for logging only
343 $lock->mark_failed;
344 return 1;
348 # Test if remote GIT repository HEAD differs from local clone. If the package
349 # has been changed in the remote repository, it will reset all package
350 # states up to (excluding) `clone'.
351 # Return false on failure, 1 for no change (repositories equals),
352 # 2 for detected change.
353 # Needs `clone'.
354 sub reset_remotly_updated {
355 my ($self) = @_;
357 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
358 state => 'checkremote');
360 if (!-d $self->repodir) {
361 $lock->log("Missing repository directory `" . $self->repodir . "\n");
362 return $lock->mark_failed;
365 # Expected output for "git show-ref origin/master"
366 # bb7f5790c2ef49087abe175e8b9560acce4ae15d refs/remotes/origin/master
367 my $local_id;
368 my $branch_name = $self->branch;
369 if (!$lock->dooutput($self->repodir, \$local_id, 'git', 'show-ref',
370 'origin/' . $self->branch)) {
371 $lock->log("Could not get HEAD of local origin branch.\n");
372 return $lock->mark_failed;
374 if (!defined $local_id or $local_id !~
375 s|\A(\S+)\s+refs/remotes/origin/\Q$branch_name\E\n\z|$1|) {
376 $lock->log("Could not parse local origin reference ID: `$local_id'\n");
377 return $lock->mark_failed;
380 # Expected output for "git ls-remote origin heads/master"
381 # 8d021a3956bbb1762ae52a04a5bc425a77c8a3ad refs/heads/master
382 # XXX: git ls-remote --heads ... handles master as a wildcard and returns
383 # entry for rc/master branch too.
384 my $remote_id;
385 if (!$lock->dooutput($self->repodir, \$remote_id, 'git', 'ls-remote',
386 'origin', 'heads/' . $self->branch)) {
387 $lock->log("Could not get HEAD of remote origin branch.\n");
388 return $lock->mark_failed;
390 if (!defined $remote_id or $remote_id !~
391 s|\A(\S+)\s+refs/heads/\Q$branch_name\E\n\z|$1|) {
392 $lock->log("Could not parse remote origin reference ID: `$remote_id'\n");
393 return $lock->mark_failed;
396 my $changed = $local_id ne $remote_id;
397 if ($changed) {
398 $lock->log("Remote repository has changed.\n");
399 $self->reset();
400 } else {
401 $lock->log("Remote repository has not changed.\n");
404 # The lock is for logging only
405 $lock->mark_failed;
407 if ($changed) {
408 return 2;
410 return 1;
414 # Builds SRPM. Return true on success.
415 # If first argument is true, recreate SRPM forcefully.
416 # Second argument is Fedora::Rebuild::Package::Config object.
417 # Third argument is Mock object to use instead of fresh one (value undef).
418 # (This is safe only in single-threaded run. This is limitation of mock.)
419 # Needs `clone'.
420 sub srpm {
421 my ($self, $force, $build_config, $mock) = @_;
422 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
423 state => 'srpm');
424 if ($force) { $lock->remove_lock; }
425 if ($lock->is_done) { return 1; }
427 # We need do the update spec now to get the same NEVRA as in rebuild. We do
428 # update without pushing to prevent from repetitive NEVRA bumps in case of
429 # failed builds.
430 if (!Fedora::Rebuild::Package::StateLock->new(package => $self,
431 state => 'update')->is_done) {
432 if (!$self->updatespec($lock)) {
433 $lock->log("Could not update spec file in order to create new " .
434 "SRPM for `" . $self->name . "' package.\n");
435 return $lock->mark_failed;
439 if ($build_config->mode() eq 'local') {
440 if (!$lock->do($self->repodir, $build_config->pyrpkg(),
441 (defined $self->pkgdist) ? ('--dist', $self->pkgdist) : (),
442 'srpm')) {
443 $lock->log("Could not build SRPM for `" . $self->name .
444 "' package locally.\n");
445 return $lock->mark_failed;
447 } elsif ($build_config->mode() eq 'koji' or
448 $build_config->mode() eq 'mock') {
449 # Prepare spec file and sources
450 my $specname = File::Spec->catfile($self->repodir,
451 $self->name . '.spec');
452 if (!$lock->do($self->repodir, $build_config->pyrpkg(),
453 (defined $self->pkgdist) ? ('--dist', $self->pkgdist) : (),
454 'sources')) {
455 $lock->log("Could not download sources for `" . $self->name .
456 "' package.\n");
457 return $lock->mark_failed;
460 # Build SRPM in mock
461 if (!replace_directory($lock, $self->mockdir)) {
462 return $lock->mark_failed;
464 my ($mock_config_dir, $mock_config_root);
465 eval {
466 if (!defined $mock) {
467 $mock = Fedora::Rebuild::Mock->new(
468 architecture => $build_config->architecture(),
469 repositories => $build_config->repositories(),
470 install_packages =>
471 $build_config->mock_install_packages(),
473 $mock->make_configuration;
475 $mock_config_dir = $mock->config_dir;
476 $mock_config_root = $mock->config_root;
478 if ($@) {
479 $lock->log("Could not configure mock: $@\n");
480 File::Path::Tiny::rm($mock_config_dir);
481 return $lock->mark_failed;
483 if ($mock->shared) {
484 # Mock stopped to pruning _topdir and accumulates built SRPMs now
485 # and die on final check for number of SRPM files.
486 # Let clean it manually.
487 if (!$lock->do(undef, 'mock', '--resultdir', $self->mockdir,
488 '--configdir', $mock_config_dir,
489 '--root', $mock_config_root,
490 '--no-clean', '--no-cleanup-after',
491 '--chroot',
492 q[find "$(rpm -E '%{_topdir}')" -mindepth 2 -maxdepth 2 -exec rm -r {} \;])) {
493 $lock->log("Could not prune _topdir for `" . $self->name .
494 "' in mock.\n");
495 return $lock->mark_failed;
498 if (!$lock->do(undef, 'mock', '--resultdir', $self->mockdir,
499 '--configdir', $mock_config_dir, '--root', $mock_config_root,
500 ($mock->shared) ? ('--no-clean', '--no-cleanup-after') : (),
501 '--buildsrpm',
502 '--spec', $specname, '--sources', $self->repodir)) {
503 $lock->log("Could not build SRPM for `" . $self->name .
504 "' in mock.\n");
505 if (!$mock->shared) {
506 File::Path::Tiny::rm($mock_config_dir);
508 return $lock->mark_failed;
510 if (!$mock->shared) {
511 File::Path::Tiny::rm($mock_config_dir);
514 # Move SRPM from mockdir to repodir
515 my @srpms = glob(File::Spec->catfile($self->mockdir, '*.src.rpm'));
516 if ($#srpms < 0) {
517 $lock->log("No SRPM package found under `" .
518 $self->mockdir . "'\n");
519 return $lock->mark_failed;
521 if ($#srpms > 0) {
522 $lock->log("More SRPM packages found under `" .
523 $self->mockdir . "'. This should not happen.\n");
524 return $lock->mark_failed;
526 if (!copy_files_into_directory($lock, $self->repodir, @srpms)) {
527 return $lock->mark_failed;
529 } else {
530 $lock->log("Could not build SRPM for `" . $self->name .
531 "' because of unknown building mode `" . $build_config->mode() .
532 "'.\n");
533 return $lock->mark_failed;
536 return $lock->mark_done;
539 # Get current package NEVRA from sources in repository.
540 # First argument is state lock where process of getting NEVRA including
541 # potential failure is logged.
542 # Second argument is Fedora::Rebuild::Package::Config object.
543 # XXX: The state is not marked as failed in case of error,
544 # Return NEVRA string or undef in case of error.
545 sub get_nevra_from_git {
546 my ($self, $lock, $build_config) = @_;
548 my $nevra;
549 if (!$lock->dooutput($self->repodir, \$nevra, $build_config->pyrpkg(),
550 (defined $self->pkgdist) ? ('--dist', $self->pkgdist) : (),
551 'verrel') ||
552 $nevra eq '') {
553 $lock->log("Could not get NEVRA from `" . $self->name .
554 "' git repository package.\n");
555 return undef;
557 chomp $nevra;
558 # Consider last line only becuase of bug in pyrpkg
559 # <https://bugzilla.redhat.com/show_bug.cgi?id=721389>.
560 my @lines = (split qr{$/}, $nevra);
561 $nevra = pop @lines;
562 return $nevra;
566 # Get current package SRPM name.
567 # If the SRPM file does not exist, it will be re-created.
568 # First argument is state lock where process of building SRPM including
569 # potential failure is logged.
570 # Second argument is Fedora::Rebuild::Package::Config object. If mode value is:
571 # "local" build SRPM locally using pyrpkg,
572 # "koji" or "mock" build SRPM using mock.
573 # Third argument is Mock object to use instead of fresh one (value undef).
574 # XXX: The state is not marked as failed in case of error,
575 # Return SRPM file name string or undef in case of error.
576 sub get_srpm_name {
577 my ($self, $lock, $build_config, $mock) = @_;
579 my $nevra = $self->get_nevra_from_git($lock, $build_config);
580 if (! defined $nevra) {
581 return undef;
584 my $srpmname = File::Spec->catfile($self->repodir, $nevra . '.src.rpm');
585 if (! -f $srpmname ) {
586 $lock->log("SRPM package `" . $srpmname . "' is missing, " .
587 "trying to create SRPM again...\n");
588 if (!$self->srpm(1, $build_config, $mock)
589 || ! -f $srpmname) {
590 $lock->log("`Could not recreate SRPM package '" . $srpmname .
591 "'.\n");
592 return undef;
595 return $srpmname;
598 # Remove a directory recursively, if it exists.
599 # First argument is the directory, second argument is lock to log errors into.
600 # Return true, false in case of error.
601 # XXX: This is not a method
602 sub remove_directory {
603 my ($lock, $directory) = @_;
604 if (!File::Path::Tiny::rm($directory)) {
605 $lock->log("Could not remove directory `" . $directory . "': $!\n");
606 return 0;
608 return 1;
611 # Create a directory. If it exists, it will remove it before.
612 # First argument is the directory, second argument is lock to log errors into.
613 # Return true, false in case of error.
614 # XXX: This is not a method
615 sub replace_directory {
616 my ($lock, $directory) = @_;
617 remove_directory($lock, $directory);
618 if (!File::Path::Tiny::mk($directory)) {
619 $lock->log("Could not create directory `" . $directory . "': $!\n");
620 return 0;
622 return 1;
625 # Copy files into existing directory.
626 # First argument lock for logggin,
627 # second argument is destinatinon directory,
628 # The last is list of files to be copied.
629 # Return true in sucesss, false in case of error.
630 # XXX: This is not a method
631 sub copy_files_into_directory {
632 my ($lock, $directory, @files) = @_;
633 for my $file (@files) {
634 use File::Copy;
635 if (!copy($file, $directory)) {
636 $lock->log("Could not copy `". $file . "' into `". $directory .
637 "'\n");
638 return 0;
640 $lock->log("`" . $file . "' copied into `" . $directory . "'\n");
642 return 1;
645 # Destile BuildRequires from local SRPM and serialize them into file.
646 # First argument is Fedora::Rebuild::Package::Config object. If mode member is:
647 # "local" build SRPM locally using pyrpkg,
648 # "koji" or "mock" build SRPM using mock.
649 # Second argument is Mock object to use instead of fresh one (value undef).
650 # Return true on success.
651 # Needs `srpm'.
652 # FIXME: does not work after cleaning clone or doing update.
653 sub storebuildrequires {
654 my ($self, $build_config, $mock) = @_;
655 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
656 state => 'buildrequiresstore');
657 if ($lock->is_done) { return 1; }
659 my $nevra = $self->get_nevra_from_git($lock, $build_config);
660 if (! defined $nevra) {
661 return $lock->mark_failed;
664 my $srpmname = File::Spec->catfile($self->repodir, $nevra . '.src.rpm');
665 if (! -f $srpmname ) {
666 $lock->log("SRPM package `" . $srpmname . "' is missing, " .
667 "trying to create SRPM again...\n");
668 if (!$self->srpm(1, $build_config, $mock) || ! -f $srpmname) {
669 $lock->log("`Could not recreate SRPM package '" . $srpmname .
670 "'.\n");
671 return $lock->mark_failed;
675 my $rpm = Fedora::Rebuild::RPM->new(name => $srpmname);
676 my ($requires, $envra) = $rpm->requires;
677 if (! defined $requires) {
678 $lock->log("Could not get requires of SRPM `" . $srpmname . "': ". $@
679 . "\n");
680 return $lock->mark_failed;
683 if (! $lock->nstorereference($requires, $self->requiresstore)) {
684 $lock->log("Could not store requires of SRPM `". $srpmname .
685 "' into `" . $self->requiresstore . "' file: $@\n");
686 return $lock->mark_failed;
689 $lock->log(Data::Dumper::Dumper($requires) . "\n");
690 return $lock->mark_done;
693 # Destile BuildRequires from local SRPM. Return true on success.
694 # Needs `buildrequiresstore'.
695 sub buildrequires {
696 my $self = shift;
697 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
698 state => 'buildrequires');
699 if ($lock->is_done) { return 1; }
701 my $requires = $lock->retrievereference($self->requiresstore);
702 if (! $requires) {
703 $lock->log("Could not load requires of `". $self->name .
704 "' package from `" . $self->requiresstore . "' file: $@\n");
705 return $lock->mark_failed;
707 $self->requires(shared_clone($requires));
709 $lock->log(Data::Dumper::Dumper($self->requires) . "\n");
710 return $lock->mark_done;
713 # Record verdict from dependency solver whether the package is rebuildable.
714 # This step is always redone.
715 sub log_is_rebuildable {
716 my ($self, $is_rebuildable, $message) = @_;
717 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
718 state => 'is_rebuildable');
719 $lock->remove_lock;
721 if (defined $message) {
722 $lock->log("Solver result for possibility of rebuilding SRPM for `" .
723 $self->name . "': $message\n");
725 if (! $is_rebuildable) {
726 $lock->log("According dependency solver, this package is not " .
727 "rebuildable now.\n");
728 return $lock->mark_failed;
731 $lock->log("According dependency solver, this package is " .
732 "rebuildable now.\n");
733 return $lock->mark_done;
736 # Get binary RPM packages for the source package.
737 # First argument is Fedora::Rebuild::Package::Config object. If mode member is:
738 # 'koji' download them from Koji,
739 # 'local' from local build,
740 # 'mock' from mock result directory.
741 # noarch packages are colletected automatically.
742 # Requires `clone'. Sould be called after `build'.
743 # Return true on success.
744 sub binaryrpm {
745 my ($self, $build_config) = @_;
746 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
747 state => 'rpms');
748 if ($lock->is_done) { return 1; }
750 if (!replace_directory($lock, $self->rpmdir)) {
751 return $lock->mark_failed;
754 my @archs = ($build_config->architecture(), 'noarch');
755 if ($build_config->mode eq 'koji') {
756 $lock->log("Getting binary RPM packages from Koji:\n");
758 my $nevra = $self->get_nevra_from_git($lock, $build_config);
759 if (! defined $nevra) {
760 return $lock->mark_failed;
763 # TODO: Get all archs, remove SRPM
764 if (!$lock->do($self->rpmdir, $build_config->koji(), 'download-build',
765 (map {'--arch=' . $_ } @archs), $nevra)) {
766 $lock->log("Could not get binary RPM packages for `" . $nevra .
767 "'\n");
768 return $lock->mark_failed;
770 } elsif ($build_config->mode() eq 'local') {
771 $lock->log("Getting binary RPM packages from local build:\n");
773 my @rpms = map { glob(File::Spec->catfile($self->repodir, $_,
774 '*.rpm')) } @archs;
775 if ($#rpms < 0) {
776 $lock->log("No binary RPM packages found under `" .
777 $self->repodir . "'\n");
778 return $lock->mark_failed;
781 if (!copy_files_into_directory($lock, $self->rpmdir, @rpms)) {
782 return $lock->mark_failed;
784 } elsif ($build_config->mode() eq 'mock') {
785 $lock->log("Getting binary RPM packages from mock build:\n");
787 my @rpms = map { glob(File::Spec->catfile($self->mockdir,
788 ('*.' . $_ . '.rpm'))) } @archs;
789 if ($#rpms < 0) {
790 $lock->log("No binary RPM packages found under `" .
791 $self->mockdir . "'\n");
792 return $lock->mark_failed;
795 if (!copy_files_into_directory($lock, $self->rpmdir, @rpms)) {
796 return $lock->mark_failed;
798 } else {
799 $lock->log("Could get binary RPM packages for `" . $self->name .
800 "' source package because of unknown building mode `" .
801 $build_config->mode() . "'\n");
802 return $lock->mark_failed;
805 return $lock->mark_done;
808 # Return list of binary RPM files relative to current working directory.
809 # XXX: Should be called after colleting the files from build process by
810 # binaryrpm().
811 sub listbinaryrpmfiles {
812 my $self = shift;
813 return (glob(File::Spec->catfile($self->rpmdir, '*.rpm')));
816 # Distill Requires from rebuilt binary packages and serialize them into file.
817 # Return true on success.
818 # Needs `rpms'.
819 sub storebinaryrequires {
820 my $self = shift;
821 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
822 state => 'runrequiresstore');
823 if ($lock->is_done) { return 1; }
825 my @rpms = glob(File::Spec->catfile($self->rpmdir, '*.rpm'));
826 if ($#rpms < 0) {
827 $lock->log("No binary RPM packages found in `" . $self->rpmdir
828 . "'\n");
829 return $lock->mark_failed;
832 my $allrequires = {};
833 for my $rpmname (@rpms) {
834 my $rpm = Fedora::Rebuild::RPM->new(name => $rpmname);
836 my ($requires, $envr) = $rpm->requires;
838 if (! defined $requires || ! defined $envr) {
839 $lock->log("Could not get run-time requires of RPM `" . $rpmname .
840 "': " . $@ ."\n");
841 return $lock->mark_failed;
843 $$allrequires{$envr} = $requires;
846 if (! $lock->nstorereference($allrequires, $self->runrequiresstore)) {
847 $lock->log("Could not store run-time requires of RPM `". $self->name .
848 "' into `" . $self->runrequiresstore . "' file: $@\n");
849 return $lock->mark_failed;
852 $lock->log(Data::Dumper::Dumper($allrequires));
853 return $lock->mark_done;
856 # Distill Provides from rebuilt binary packages and serialize them into file.
857 # Return true on success.
858 # Needs `rpms'.
859 sub storebinaryprovides {
860 my $self = shift;
861 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
862 state => 'providesstore');
863 if ($lock->is_done) { return 1; }
865 my @rpms = glob(File::Spec->catfile($self->rpmdir, '*.rpm'));
866 if ($#rpms < 0) {
867 $lock->log("No binary RPM packages found in `" . $self->rpmdir
868 . "'\n");
869 return $lock->mark_failed;
872 my $allprovides = {};
873 for my $rpmname (@rpms) {
874 my $rpm = Fedora::Rebuild::RPM->new(name => $rpmname);
876 my ($provides, $envr) = $rpm->provides;
878 if (! defined $provides || !defined $envr) {
879 $lock->log("Could not get provides of RPM `" . $rpmname . "': " .
880 $@ ."\n");
881 return $lock->mark_failed;
883 $$allprovides{$envr} = $provides;
886 if (! $lock->nstorereference($allprovides, $self->providesstore)) {
887 $lock->log("Could not store provides of RPM `". $self->name .
888 "' into `" . $self->providesstore . "' file: $@\n");
889 return $lock->mark_failed;
892 $lock->log(Data::Dumper::Dumper($allprovides));
893 return $lock->mark_done;
896 # Load run-time requires of already rebuilt binary packages from file.
897 # Return true on success.
898 # Needs `storebinaryrequires'.
899 sub loadbinaryrequires {
900 my $self = shift;
901 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
902 state => 'runrequires');
903 if ($lock->is_done) { return 1; }
905 my $runrequires = $lock->retrievereference($self->runrequiresstore);
906 if (! $runrequires) {
907 $lock->log("Could not load run-time requires of `". $self->name .
908 "' package from `" . $self->runrequiresstore . "' file: $@\n");
909 return $lock->mark_failed;
911 $self->runrequires(shared_clone($runrequires));
913 $lock->log(Data::Dumper::Dumper($self->runrequires));
914 return $lock->mark_done;
917 # Load provides of already rebuilt binary packages from file.
918 # Return true on success.
919 # Needs `storebinaryprovides'.
920 sub loadbinaryprovides {
921 my $self = shift;
922 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
923 state => 'provides');
924 if ($lock->is_done) { return 1; }
926 my $provides = $lock->retrievereference($self->providesstore);
927 if (! $provides) {
928 $lock->log("Could not load provides of `". $self->name .
929 "' package from `" . $self->providesstore . "' file: $@\n");
930 return $lock->mark_failed;
932 $self->provides(shared_clone($provides));
934 $lock->log(Data::Dumper::Dumper($self->provides));
935 return $lock->mark_done;
938 # Edit git repository by an external tool if not yet done. Does not increase
939 # package revisions.
940 # First argument is mode. Only in "koji" mode pushes the changes.
941 # Second argument is an external editor command. The command is expressed as
942 # an array reference. Its working directory will be the git repository
943 # directory. Its last argument will be the spec file name. The command can
944 # abort edition by non-zero exit code.
945 # Return true on success.
946 # Needs `clone'.
947 sub edit {
948 my ($self, $mode, $editor) = @_;
949 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
950 state => 'edit');
951 if ($lock->is_done) { return 1; }
953 if (ref $editor ne 'ARRAY') {
954 $lock->log("The editor argument (" . "$editor" .
955 ") is not an array reference.\n");
956 return $lock->mark_failed;
959 if (!@{$editor}) {
960 $lock->log("The editor command is an empty list.\n");
961 return $lock->mark_failed;
964 # Reset repository
965 if (!$self->refreshgit($lock)) {
966 return $lock->mark_failed;
969 # Execute external editor
970 if (!$lock->do($self->repodir, @{$editor}, $self->name . '.spec')) {
971 $lock->log("Could not edit spec file for `" . $self->name .
972 "' package.\n");
973 return $lock->mark_failed;
976 # Commit and push changes only if editor has changed anything
977 my $modified = $self->gitismodified($lock);
978 if (-1 == $modified) {
979 $lock->log("Could not check status of changes in git repository `" .
980 $self->repodir . "'.\n");
981 return $lock->mark_failed;
982 } elsif ($modified) {
983 $lock->log("Editor did changes." .
984 " They will be committed and possibly pushed.\n");
985 if (!$self->commitandpush($lock, $mode)) {
986 return $lock->mark_failed;
988 } else {
989 $lock->log("Editor did not change anything." .
990 " Nothing to commit and push.\n");
992 return $lock->mark_done;
996 # Increase package revision if not yet done. Commit change if first argument
997 # is "koji".
998 # Return true on success.
999 # Needs `clone'.
1000 sub update {
1001 my ($self, $mode) = @_;
1002 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
1003 state => 'update');
1004 if ($lock->is_done) { return 1; }
1006 # Update spec file
1007 if (!$self->updatespec($lock)) {
1008 $lock->log("Could not update spec file in order to create new " .
1009 "update for `" . $self->name . "' package.\n");
1010 return $lock->mark_failed;
1013 # Commit and push changes
1014 if (!$self->commitandpush($lock, $mode)) {
1015 return $lock->mark_failed;
1018 return $lock->mark_done;
1022 # Submit package for building into Koji and store task ID.
1023 # This is pointless in local build mode.
1024 # First argument is Fedora::Rebuild::Package::Config object.
1025 # Requires `clone'. Sould be called after `update'.
1026 # Return true on success.
1027 sub submitbuild {
1028 my ($self, $build_config) = @_;
1029 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
1030 state => 'submitbuild');
1031 if ($lock->is_done) { return 1; }
1033 # Get NEVRA of intended build
1034 my $nevra = $self->get_nevra_from_git($lock, $build_config);
1035 if (! defined $nevra) {
1036 return $lock->mark_failed;
1039 # Check the build is not already in Koji (e.g. by concurrent packager
1040 # or after this program restart) but do not conclude anything.
1041 my $buildinfo;
1042 if (!$lock->dooutput($self->repodir, \$buildinfo, $build_config->koji(),
1043 'buildinfo', $nevra)) {
1044 $lock->log("Could not ask Koji for `" . $nevra . "' status " .
1045 "before submitting new build.\n");
1046 return $lock->mark_failed;
1048 if ($buildinfo =~ /No such build/m) {
1049 $lock->log("Package not yet submitted for building as expected.\n");
1050 } else {
1051 # Get task ID of already building package
1052 if ($buildinfo =~ /Task:\s*(\d+)/m) {
1053 # TODO: We could compare task target and consider as submitted if
1054 # equaled to intended target.
1055 my $task_id = $1;
1056 $lock->log("Package `$nevra' already submitted as task " .
1057 "`$task_id'. Previous build failed or somebody builds the " .
1058 "package concurrently.\n");
1059 } else {
1060 $lock->log("Package `$nevra' already in Koji, but task ID " .
1061 "could not been determined.\n");
1063 $lock->log("Re-submitting the package.\n")
1066 # Submit into Koji
1067 my $task_id;
1068 if (!$lock->dooutput($self->repodir, \$task_id, $build_config->pyrpkg(),
1069 (defined $self->pkgdist) ? ('--dist', $self->pkgdist) : (),
1070 'build', '--nowait', '--target', $self->target)) {
1071 $lock->log("Could not submit `" . $nevra . "' into Koji.\n");
1072 return $lock->mark_failed;
1074 if (not $task_id =~ /Created task:\s*(\d+)/) {
1075 $lock->log("Could not parse Koji task ID for `$nevra' build\n");
1076 return $lock->mark_failed;
1078 $task_id = $1;
1080 # Store task ID
1081 if (! $lock->nstorereference(\$task_id, $self->taskstore)) {
1082 $lock->log("Could not store task ID `" . $task_id . "' of `" . $nevra .
1083 "' package into `" . $self->taskstore . "' file: $@\n");
1084 return $lock->mark_failed;
1085 } else {
1086 $lock->log("Task ID `" . $task_id . "' stored into `" .
1087 $self->taskstore . "' file sucessfully.\n");
1090 return $lock->mark_done;
1094 # First argument is Fedora::Rebuild::Package::Config module. If mode member is:
1095 # "koji" wait for package build in Koji,
1096 # "local" build locally using pyrpkg.
1097 # "mock" build locally using mock.
1098 # Second argument is Mock object to use instead of fresh one (value undef).
1099 # (This is safe only in single-threaded run. This is limitation of mock.)
1100 # Requires `clone'. Sould be called after `update' or `submitbuild'.
1101 # Third argument is Mock object to use instead of fresh one (value undef) for
1102 # building missing SRPMs.
1103 # Return true on success.
1104 sub build {
1105 my ($self, $build_config, $mock, $src_mock) = @_;
1106 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
1107 state => 'build');
1108 if ($lock->is_done) { return 1; }
1110 my $nevra = $self->get_nevra_from_git($lock, $build_config);
1111 if (! defined $nevra) {
1112 return $lock->mark_failed;
1115 if ($build_config->mode() eq 'local') {
1116 if (!$lock->do($self->repodir, $build_config->pyrpkg(),
1117 (defined $self->pkgdist) ? ('--dist', $self->pkgdist) : (),
1118 'local')) {
1119 $lock->log("Could not build `" . $nevra . "' locally.\n");
1120 return $lock->mark_failed;
1122 } elsif ($build_config->mode() eq 'koji') {
1123 # Retrieve task ID of submitted build
1124 my $task_id = $lock->retrievereference($self->taskstore);
1125 if (! $task_id) {
1126 $lock->log("Could not load task ID for `". $nevra .
1127 "' build from `" . $self->taskstore . "' file: $@\n");
1128 return $lock->mark_failed;
1130 $task_id = $$task_id;
1132 # Wait for build task result
1133 # TODO: How to recognize the process died for other reason
1134 # than build failure?
1135 if (!$lock->do($self->repodir, $build_config->koji(),
1136 'watch-task', $task_id)) {
1137 $lock->log("Could not get status of Koji task `" . $task_id .
1138 "' for `$nevra' build, or the task failed.\n");
1139 return $lock->mark_failed;
1141 } elsif ($build_config->mode() eq 'mock') {
1142 my $srpm_name = $self->get_srpm_name($lock, $build_config, $src_mock);
1143 if (! defined $srpm_name) {
1144 return $lock->mark_failed;
1146 if (!replace_directory($lock, $self->mockdir)) {
1147 return $lock->mark_failed;
1149 my ($mock_config_dir, $mock_config_root);
1150 eval {
1151 if (!defined $mock) {
1152 $mock = Fedora::Rebuild::Mock->new(
1153 architecture => $build_config->architecture(),
1154 repositories => $build_config->repositories(),
1155 install_packages => $build_config->mock_install_packages(),
1157 $mock->make_configuration;
1159 $mock_config_dir = $mock->config_dir;
1160 $mock_config_root = $mock->config_root;
1162 if ($@) {
1163 $lock->log("Could not configure mock: $@\n");
1164 File::Path::Tiny::rm($mock_config_dir);
1165 return $lock->mark_failed;
1167 my $success = $lock->do(undef, 'mock', '--resultdir', $self->mockdir,
1168 '--configdir', $mock_config_dir, '--root', $mock_config_root,
1169 '--rebuild', $srpm_name);
1170 if (defined $mock && !$mock->shared) {
1171 File::Path::Tiny::rm($mock_config_dir);
1173 if (!$success) {
1174 $lock->log("Could not build `" . $nevra . "' in mock.\n");
1175 return $lock->mark_failed;
1177 } else {
1178 $lock->log("Could not build `" . $nevra .
1179 "' because of unknown building mode `" . $build_config->mode() .
1180 "'.\n");
1181 return $lock->mark_failed;
1184 return $lock->mark_done;
1188 # Waits for build root rotation. Just built package will be available for
1189 # other packages at build time after returning from this fuction.
1190 # First argument is Fedora::Rebuild::Package::Config object.
1191 # If the mode is "koji", it will wait for the Koji rotation.
1192 # If the mode is "mock", it will create yum repository in directory with
1193 # binary packages.
1194 # If the mode is "local", this function is void.
1195 # Requires `update'. Sould be called after `build'.
1196 # Return true on success.
1197 sub dowaitforbuildroot {
1198 my ($self, $build_config) = @_;
1199 my $lock = Fedora::Rebuild::Package::StateLock->new(package => $self,
1200 state => 'rotate');
1201 if ($lock->is_done) { return 1; }
1203 my $nevra = $self->get_nevra_from_git($lock, $build_config);
1204 if (! defined $nevra) {
1205 return $lock->mark_failed;
1208 if ($build_config->mode() eq 'koji') {
1209 if (!$lock->do($self->repodir, $build_config->koji(), 'wait-repo',
1210 '--build=' . $nevra, '--target', $self->target)) {
1211 $lock->log("Koji does not contain `" . $nevra .
1212 "' package in build root for `" . $self->target .
1213 "' build target yet.\n");
1214 return $lock->mark_failed;
1216 } elsif ($build_config->mode() eq 'mock') {
1217 $lock->log("`" . $nevra .
1218 "' built in mock, creating yum repository...\n");
1219 if (!$lock->do($self->rpmdir, 'createrepo_c', '.')) {
1220 $lock->log("Could not create yum repository for `" . $nevra .
1221 "' package.\n");
1222 return $lock->mark_failed;
1224 $lock->log("`" . $nevra .
1225 "' yum repository created successfully.\n");
1226 } else {
1227 $lock->log("`" . $nevra .
1228 "' built locally, not waiting on Koji rotation.\n");
1231 return $lock->mark_done;
1235 # Reset 'rotate' state by removing directory with binary packages produced by
1236 # the package.
1237 # TODO: Untag package from koji?
1238 # Return true on success, otherwise false.
1239 sub reset_rotate {
1240 my ($self) = @_;
1242 my $lock = Fedora::Rebuild::Package::StateLock->new(
1243 package => $self, state => 'rotate');
1244 $lock->log("Reseting state...\n");
1245 if (!remove_directory($lock, $self->rpmdir)) {
1246 return $lock->mark_failed;
1248 $lock->mark_failed;
1249 $lock->remove_log;
1250 return 1;
1254 # Set hash of build-time dependencies (requires attribute).
1255 # First argument is Fedora::Rebuild::Package::Config object. If mode member is:
1256 # "local" build SRPM locally using pyrpkg,
1257 # "koji" or "mock" build SRPM using mock.
1258 # Second argument is anonymous clone boolean.
1259 # Third argument is Mock object to use instead of fresh one (value undef).
1260 # (This is safe only in single-threaded run. This is limitation of mock.)
1261 # Fourth argument is Mock object to use instead of fresh one (value undef).
1262 # Return undef in case of failure.
1263 sub get_buildrequires {
1264 my ($self, $build_config, $anonymous, $mock, $src_mock) = @_;
1265 my $ok;
1266 print "Getting BuildRequires for `" . $self->name . "'...\n";
1268 # Procede all steps, each must be re-doable
1269 $ok = $self->clone($anonymous, $build_config);
1270 $ok = $self->srpm(0, $build_config, $mock) if $ok;
1271 $ok = $self->storebuildrequires($build_config, $src_mock) if $ok;
1272 $ok = $self->buildrequires if $ok;
1274 if ($ok) {
1275 print "BuildRequires for `" . $self->name .
1276 "' package distilled successfully.\n";
1277 return 1;
1278 } else {
1279 print "Could not get BuildRequires for `" . $self->name .
1280 "' package.\n";
1281 return undef;
1285 # Set hash of run-time requires (Requires attribute).
1286 # Return true on success, undef in case of failure.
1287 # XXX: Requires `runrequiresstore'
1288 sub get_binaryrequires {
1289 my $self = shift;
1290 my $ok;
1291 print "Getting run-time requires for `" . $self->name . "'...\n";
1293 $ok = $self->storebinaryrequires;
1294 $ok = $self->loadbinaryrequires if $ok;
1296 if ($ok) {
1297 print "Run-time requires for `" . $self->name .
1298 "' package distilled successfully.\n";
1299 return 1;
1300 } else {
1301 print "Could not get run-time requires for `" . $self->name .
1302 "' package.\n";
1303 return undef;
1307 # Set hash of run-time provides (provides attribute).
1308 # Return true on success, undef in case of failure.
1309 # XXX: Requires `providesstore'
1310 sub get_binaryprovides {
1311 my $self = shift;
1312 my $ok;
1313 print "Getting binary provides for `" . $self->name . "'...\n";
1315 $ok = $self->storebinaryprovides;
1316 $ok = $self->loadbinaryprovides if $ok;
1318 if ($ok) {
1319 print "Provides for `" . $self->name .
1320 "' package distilled successfully.\n";
1321 return 1;
1322 } else {
1323 print "Could not get Provides for `" . $self->name . "' package.\n";
1324 return undef;
1328 # Set hash of run-time requires (Requires attribute) and provides
1329 # (provides attribute). Common wrapper for getbinaryrequires() and
1330 # getbinaryprovides().
1331 # Return true on success, undef in case of failure.
1332 # XXX: Requires `runrequiresstore' and `providesstore'
1333 sub get_binarydependencies {
1334 my $self = shift;
1335 my $ok;
1336 print "Getting binary dependencies for `" . $self->name . "'...\n";
1338 $ok = $self->get_binaryrequires;
1339 $ok = $self->get_binaryprovides if $ok;
1341 if ($ok) {
1342 print "Binary dependencies for `" . $self->name .
1343 "' package distilled successfully.\n";
1344 return 1;
1345 } else {
1346 print "Could not get binary dependencies for `" . $self->name .
1347 "' package.\n";
1348 return undef;
1352 # Edit a package. It clones it, edit it and push the changes.
1353 # Unchanged packages are not pushed, but still reported as successfully
1354 # processed.
1355 # First argument is Fedora::Rebuild::Package::Config object. mode member
1356 # defines build mode:
1357 # "koji" publish commit,
1358 # "local" without pushing commits to server,
1359 # Second argument is anonymous clone boolean.
1360 # Third argument is a program to execute as the editor as an array reference.
1361 sub cloneeditpush {
1362 my ($self, $build_config, $anonymous, $editor) = @_;
1363 my $ok;
1364 print "Editing `" . $self->name . "'...\n";
1366 # Proceed all steps, each must be re-doable
1367 $ok = $self->clone($anonymous, $build_config);
1368 $ok = $self->edit($build_config->mode(), $editor) if $ok;
1370 if ($ok) {
1371 print "`" . $self->name . "' edit finished successfully.\n";
1372 } else {
1373 print "`" . $self->name . "' edit failed.\n";
1375 return $ok;
1378 # Rebuild a package without waiting for propagation to next build root.
1379 # First argument is Fedora::Rebuild::Package::Config object. mode member
1380 # defines build mode:
1381 # "koji" publish commit and build in Koji,
1382 # "local" build locally without pushing commits to server,
1383 # "mock" build in mock without pushing commits to server.
1384 # Second argument is anonymous clone boolean.
1385 # Third argument is Mock object to use instead of fresh one (value undef).
1386 # (This is safe only in single-threaded run. This is limitation of mock.)
1387 sub rebuild {
1388 my ($self, $build_config, $anonymous, $mock) = @_;
1389 my $ok;
1390 print "Rebuilding `" . $self->name . "'...\n";
1392 # Proceed all steps, each must be re-doable
1393 $ok = $self->clone($anonymous, $build_config);
1394 $ok = $self->update($build_config->mode()) if $ok;
1395 $ok = $self->submitbuild($build_config)
1396 if ($ok and $build_config->mode() eq 'koji');
1397 $ok = $self->build($build_config, $mock) if $ok;
1398 $ok = $self->binaryrpm($build_config) if $ok;
1399 $ok = $self->get_binaryprovides if $ok;
1400 $ok = $self->get_binaryrequires if $ok;
1402 if ($ok) {
1403 print "`" . $self->name . "' rebuild finished successfully.\n";
1404 } else {
1405 print "`" . $self->name . "' rebuild failed.\n";
1407 return $ok;
1410 # Wait for the package propagated into new build root.
1411 # First argument is Fedora::Rebuild::Package::Config object.
1412 # If the mode is "koji", waits for Koji build root rotation,
1413 # Otherwise waits locally (no-op).
1414 # XXX: Requires `update', should be called after rebuilding package.
1415 sub waitforbuildroot {
1416 my ($self, $build_config) = @_;
1417 my $ok;
1418 print "Waiting for `" . $self->name . "' to get to build root...\n";
1420 $ok = $self->dowaitforbuildroot($build_config);
1422 if ($ok) {
1423 print "`" . $self->name . "' propagated successfully.\n";
1424 } else {
1425 print "`" . $self->name . "' propagation failed.\n";
1427 return $ok;