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);
33 my $localrepo = $ENV{HOME} . "/public_html/smock/yum";
40 "distro=s" => \@distros,
43 "keepgoing" => \$keepgoing,
44 "localrepo=s" => \$localrepo,
46 "suffix=s" => \$suffix,
48 pod2usage (1) if $help;
49 pod2usage (-exitstatus => 0, -verbose => 2) if $man;
59 smock.pl --arch=i386 --arch=x86_64 --distro=fedora-10 list of SRPMs ...
63 This is a wrapper around I<mock> which lets you build a whole group of
64 mutually dependent SRPMs in one go.
66 The smock command will work out the correct order in which to build
67 the SRPMs, and makes the result of previous RPM builds available as
68 dependencies for later builds.
70 Smock also works incrementally. It won't rebuild RPMs which were
71 built already in a previous run, which means if a package fails to
72 build, you can just fix it and rerun the same smock command. (In the
73 unlikely case that you want to force smock to rebuild RPMs then you
74 must bump the release number or delete the binary RPM from the
77 B<NOTE:> Please read the README file first. You need to set up mock
78 and optionally a web server before you can use this command.
86 Specify the architecture(s) to build, eg. i386, x86_64. You can
87 list this option several times to build several architectures.
91 Don't run any commands, just print the packages in the correct
92 format for chain building. See:
93 L<http://fedoraproject.org/wiki/Koji/UsingKoji#Chained_builds>
97 Specify the distribution(s) to build, eg. fedora-9, fedora-10.
98 You can list this option several times to build several distributions.
102 Don't run any commands, just print the packages in the order
103 in which they must be built.
111 Don't exit if a package fails, but keep building.
113 Note that this isn't always safe because new packages may be built
114 against older packages, in the case where the older package couldn't
115 be rebuilt because of an error.
117 However, it is very useful.
121 Local repository. Defaults to C<$HOME/public_html/smock/yum>
125 Show this help using man.
129 Append a suffix to the mock configuration file in order to use
139 die "smock: specify one or more architectures using --arch=<arch>\n"
143 die "smock: specify one or more distros using --distro=<distro>\n"
147 die "smock: specify one or more SRPMs to build on the command line\n"
150 # Resolve the names, dependency list, etc. of the SRPMs that were
155 open PIPE, "$_[0] |" or die "$_[0]: $!";
165 open PIPE, "$_[0] |" or die "$_[0]: $!";
176 foreach my $srpm (@srpms) {
177 my $name = get_one_line "rpm -q --qf '%{name}' -p '$srpm'";
178 my $version = get_one_line "rpm -q --qf '%{version}' -p '$srpm'";
179 my $release = get_one_line "rpm -q --qf '%{release}' -p '$srpm'";
181 my @buildrequires = get_lines "rpm -q --requires -p '$srpm' |
182 grep -Eo '^[^[:space:]]+'";
184 #print "Filename: $srpm\n";
185 #print " name = $name\n";
186 #print " version = $version\n";
187 #print " release = $release\n";
188 #print " buildrequires = ", join (",", @buildrequires), "\n";
194 buildrequires => \@buildrequires,
199 # We don't care about buildrequires unless they refer to other
200 # packages that we are building. So filter them on this condition.
207 return 1 if $item eq $_;
214 my $dep = shift; # eg. dbus-devel
217 return $dep if is_member_of ($dep, @_);
219 $newdep =~ s/-\w+$//; # eg. dbus-devel -> dbus
220 last if $newdep eq $dep;
226 foreach my $name (keys %srpms) {
227 my @buildrequires = @{$srpms{$name}->{buildrequires}};
229 grep { $_ = dependency_in ($_, keys %srpms) } @buildrequires;
230 $srpms{$name}{buildrequires} = \@buildrequires;
233 # This function takes a list of package names and sorts them into the
234 # correct order for building, given the existing %srpms hash
235 # containing buildrequires. We use the external 'tsort' program.
241 my ($fh, $filename) = tempfile ();
243 foreach my $name (@names) {
244 my @buildrequires = @{$srpms{$name}->{buildrequires}};
245 foreach (@buildrequires) {
246 print $fh "$_ $name\n"
248 # Add a self->self dependency. This ensures that any
249 # packages which don't have or appear as a dependency of
250 # any other package still get built.
251 print $fh "$name $name\n"
255 get_lines "tsort $filename";
258 # Sort the initial list of package names.
260 my @names = sort keys %srpms;
261 my @buildorder = tsort (@names);
263 # With --chain flag we print the packages in groups for chain building.
269 print 'make chain-build CHAIN="';
271 foreach $name (@buildorder) {
272 my @br = @{$srpms{$name}->{buildrequires}};
274 # If a BR occurs within the current group, then start the next group.
277 if (exists $group{$_}) {
296 # With --dryrun flag we just print the packages in build order then exit.
299 foreach (@buildorder) {
306 # Now we can build each SRPM.
313 mkdir ($_, 0755) or die "mkdir $_: $!"
322 my_mkdir "$localrepo/$distro";
323 my_mkdir "$localrepo/$distro/src";
324 my_mkdir "$localrepo/$distro/src/SRPMS";
325 system ("cd $localrepo/$distro/src && rm -rf repodata && createrepo -q .") == 0
326 or die "createrepo failed: $?\n";
328 my_mkdir "$localrepo/$distro/$arch";
329 my_mkdir "$localrepo/$distro/$arch/RPMS";
330 my_mkdir "$localrepo/$distro/$arch/logs";
332 system ("cd $localrepo/$distro/$arch && rm -rf repodata && createrepo -q --exclude 'logs/*rpm' .") == 0
333 or die "createrepo failed: $?\n";
336 if (! -d "$localrepo/scratch") {
337 mkdir "$localrepo/scratch"
338 or die "mkdir $localrepo/scratch: $!\nIf you haven't set up a local repository yet, you must read the README file.\n";
341 system "rm -rf $localrepo/scratch/*";
345 # NB: Need to do the arch/distro in the outer loop to work
346 # around the caching bug in mock/yum.
347 foreach my $arch (@arches) {
348 foreach my $distro (@distros) {
349 foreach my $name (@buildorder) {
350 my $version = $srpms{$name}->{version};
351 my $release = $srpms{$name}->{release};
352 my $srpm_filename = $srpms{$name}->{filename};
354 $release =~ s/\.fc?\d+$//; # "1.fc9" -> "1"
356 # Does the built (binary) package exist already?
357 my $pattern = "$localrepo/$distro/$arch/RPMS/$name-$version-$release.*.rpm";
358 #print "pattern = $pattern\n";
359 my @binaries = glob $pattern;
363 # Rebuild the package.
364 print "*** building $name-$version-$release $arch $distro ***\n";
366 createrepo ($arch, $distro);
368 my $scratchdir = "$localrepo/scratch/$name-$distro-$arch";
371 if (system ("mock -r $distro-$arch$suffix --resultdir $scratchdir $srpm_filename") == 0) {
372 # Build was a success so move the final RPMs into the
373 # mock repo for next time.
374 system ("mv $scratchdir/*.src.rpm $localrepo/$distro/src/SRPMS") == 0 or die "mv";
375 system ("mv $scratchdir/*.rpm $localrepo/$distro/$arch/RPMS") == 0 or die "mv";
376 my_mkdir "$localrepo/$distro/$arch/logs/$name-$version-$release";
377 system ("mv $scratchdir/*.log $localrepo/$distro/$arch/logs/$name-$version-$release/") == 0 or die "mv";
378 system "rm -rf $scratchdir";
380 createrepo ($arch, $distro);
384 push @errors, "$name-$distro-$arch$suffix";
385 print STDERR "Build failed, return code $?\nLeaving the logs in $scratchdir\n";
386 exit 1 unless $keepgoing;
391 print "skipping $name-$version-$release $arch $distro\n";
398 print "\n\n\nBuild failed for the following packages:\n";
399 print " $_\n" foreach @errors;