4 # by Dan Berrange and Richard W.M. Jones.
5 # Copyright (C) 2008 Red Hat Inc.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 use File::Temp qw(tempfile);
29 my $localrepo = $ENV{HOME} . "/public_html/smock/yum";
38 "distro=s" => \@distros,
39 "localrepo=s" => \$localrepo,
41 "keepgoing" => \$keepgoing,
46 pod2usage (1) if $help;
47 pod2usage (-exitstatus => 0, -verbose => 2) if $man;
57 smock.pl --arch=i386 --arch=x86_64 --distro=fedora-10 list of SRPMs ...
61 This is a wrapper around I<mock> which lets you build a whole group of
62 mutually dependent SRPMs in one go.
64 The smock command will work out the correct order in which to build
65 the SRPMs, and makes the result of previous RPM builds available as
66 dependencies for later builds.
68 Smock also works incrementally. It won't rebuild RPMs which were
69 built already in a previous run, which means if a package fails to
70 build, you can just fix it and rerun the same smock command. (In the
71 unlikely case that you want to force smock to rebuild RPMs then you
72 must bump the release number or delete the binary RPM from the
75 B<NOTE:> Please read the README file first. You need to set up mock
76 and a web server before you can use this command.
84 Specify the architecture(s) to build, eg. i386, x86_64. You can
85 list this option several times to build several architectures.
89 Specify the distribution(s) to build, eg. fedora-9, fedora-10.
90 You can list this option several times to build several distributions.
94 Local repository. Defaults to C<$HOME/public_html/smock/yum>
98 Don't run any commands, just print the packages in the order
99 in which they must be built.
103 Don't exit if a package fails, but keep building.
105 Note that this isn't always safe because new packages may be built
106 against older packages, in the case where the older package couldn't
107 be rebuilt because of an error.
109 However, it is very useful.
113 Don't run any commands, just print the packages in the correct
114 format for chain building. See:
115 L<http://fedoraproject.org/wiki/Koji/UsingKoji#Chained_builds>
124 die "smock: specify one or more architectures using --arch=<arch>\n"
128 die "smock: specify one or more distros using --distro=<distro>\n"
132 die "smock: specify one or more SRPMs to build on the command line\n"
135 # Resolve the names, dependency list, etc. of the SRPMs that were
140 open PIPE, "$_[0] |" or die "$_[0]: $!";
150 open PIPE, "$_[0] |" or die "$_[0]: $!";
161 foreach my $srpm (@srpms) {
162 my $name = get_one_line "rpm -q --qf '%{name}' -p '$srpm'";
163 my $version = get_one_line "rpm -q --qf '%{version}' -p '$srpm'";
164 my $release = get_one_line "rpm -q --qf '%{release}' -p '$srpm'";
166 my @buildrequires = get_lines "rpm -q --requires -p '$srpm' |
167 grep -Eo '^[^[:space:]]+'";
169 #print "Filename: $srpm\n";
170 #print " name = $name\n";
171 #print " version = $version\n";
172 #print " release = $release\n";
173 #print " buildrequires = ", join (",", @buildrequires), "\n";
179 buildrequires => \@buildrequires,
184 # We don't care about buildrequires unless they refer to other
185 # packages that we are building. So filter them on this condition.
192 return 1 if $item eq $_;
199 my $dep = shift; # eg. dbus-devel
202 return $dep if is_member_of ($dep, @_);
204 $newdep =~ s/-\w+$//; # eg. dbus-devel -> dbus
205 last if $newdep eq $dep;
211 foreach my $name (keys %srpms) {
212 my @buildrequires = @{$srpms{$name}->{buildrequires}};
214 grep { $_ = dependency_in ($_, keys %srpms) } @buildrequires;
215 $srpms{$name}{buildrequires} = \@buildrequires;
218 # This function takes a list of package names and sorts them into the
219 # correct order for building, given the existing %srpms hash
220 # containing buildrequires. We use the external 'tsort' program.
226 my ($fh, $filename) = tempfile ();
228 foreach my $name (@names) {
229 my @buildrequires = @{$srpms{$name}->{buildrequires}};
230 foreach (@buildrequires) {
231 print $fh "$_ $name\n"
233 # Add a self->self dependency. This ensures that any
234 # packages which don't have or appear as a dependency of
235 # any other package still get built.
236 print $fh "$name $name\n"
240 get_lines "tsort $filename";
243 # Sort the initial list of package names.
245 my @names = sort keys %srpms;
246 my @buildorder = tsort (@names);
248 # With --chain flag we print the packages in groups for chain building.
254 print 'make chain-build CHAIN="';
256 foreach $name (@buildorder) {
257 my @br = @{$srpms{$name}->{buildrequires}};
259 # If a BR occurs within the current group, then start the next group.
262 if (exists $group{$_}) {
281 # With --dryrun flag we just print the packages in build order then exit.
284 foreach (@buildorder) {
291 # Now we can build each SRPM.
298 mkdir ($_, 0755) or die "mkdir $_: $!"
307 my_mkdir "$localrepo/$distro";
308 my_mkdir "$localrepo/$distro/src";
309 my_mkdir "$localrepo/$distro/src/SRPMS";
310 system ("cd $localrepo/$distro/src && rm -rf repodata && createrepo -q .") == 0
311 or die "createrepo failed: $?\n";
313 my_mkdir "$localrepo/$distro/$arch";
314 my_mkdir "$localrepo/$distro/$arch/RPMS";
315 my_mkdir "$localrepo/$distro/$arch/logs";
317 system ("cd $localrepo/$distro/$arch && rm -rf repodata && createrepo -q --exclude 'logs/*rpm' .") == 0
318 or die "createrepo failed: $?\n";
321 if (! -d "$localrepo/scratch") {
322 mkdir "$localrepo/scratch"
323 or die "mkdir $localrepo/scratch: $!\nIf you haven't set up a local repository yet, you must read the README file.\n";
326 system "rm -rf $localrepo/scratch/*";
330 # NB: Need to do the arch/distro in the outer loop to work
331 # around the caching bug in mock/yum.
332 foreach my $arch (@arches) {
333 foreach my $distro (@distros) {
334 foreach my $name (@buildorder) {
335 my $version = $srpms{$name}->{version};
336 my $release = $srpms{$name}->{release};
337 my $srpm_filename = $srpms{$name}->{filename};
339 $release =~ s/\.fc?\d+$//; # "1.fc9" -> "1"
341 # Does the built (binary) package exist already?
342 my $pattern = "$localrepo/$distro/$arch/RPMS/$name-$version-$release.*.rpm";
343 #print "pattern = $pattern\n";
344 my @binaries = glob $pattern;
348 # Rebuild the package.
349 print "*** building $name-$version-$release $arch $distro ***\n";
351 createrepo ($arch, $distro);
353 my $scratchdir = "$localrepo/scratch/$name-$distro-$arch";
356 if (system ("mock -r $distro-$arch --resultdir $scratchdir $srpm_filename") == 0) {
357 # Build was a success so move the final RPMs into the
358 # mock repo for next time.
359 system ("mv $scratchdir/*.src.rpm $localrepo/$distro/src/SRPMS") == 0 or die "mv";
360 system ("mv $scratchdir/*.rpm $localrepo/$distro/$arch/RPMS") == 0 or die "mv";
361 my_mkdir "$localrepo/$distro/$arch/logs/$name-$version-$release";
362 system ("mv $scratchdir/*.log $localrepo/$distro/$arch/logs/$name-$version-$release/") == 0 or die "mv";
363 system "rm -rf $scratchdir";
365 createrepo ($arch, $distro);
369 push @errors, "$name-$distro-$arch";
370 print STDERR "Build failed, return code $?\nLeaving the logs in $scratchdir\n";
371 exit 1 unless $keepgoing;
376 print "skipping $name-$version-$release $arch $distro\n";
383 print "\n\n\nBuild failed for the following packages:\n";
384 print " $_\n" foreach @errors;