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";
37 "distro=s" => \@distros,
38 "localrepo=s" => \$localrepo,
44 pod2usage (1) if $help;
45 pod2usage (-exitstatus => 0, -verbose => 2) if $man;
55 smock.pl --arch=i386 --arch=x86_64 --distro=fedora-10 list of SRPMs ...
59 This is a wrapper around I<mock> which lets you build a whole group of
60 mutually dependent SRPMs in one go.
62 The smock command will work out the correct order in which to build
63 the SRPMs, and makes the result of previous RPM builds available as
64 dependencies for later builds.
66 Smock also works incrementally. It won't rebuild RPMs which were
67 built already in a previous run, which means if a package fails to
68 build, you can just fix it and rerun the same smock command. (In the
69 unlikely case that you want to force smock to rebuild RPMs then you
70 must bump the release number or delete the binary RPM from the
73 B<NOTE:> Please read the README file first. You need to set up mock
74 and a web server before you can use this command.
82 Specify the architecture(s) to build, eg. i386, x86_64. You can
83 list this option several times to build several architectures.
87 Specify the distribution(s) to build, eg. fedora-9, fedora-10.
88 You can list this option several times to build several distributions.
92 Local repository. Defaults to C<$HOME/public_html/smock/yum>
96 Don't run any commands, just print the packages in the order
97 in which they must be built.
101 Don't run any commands, just print the packages in the correct
102 format for chain building. See:
103 L<http://fedoraproject.org/wiki/Koji/UsingKoji#Chained_builds>
112 die "smock: specify one or more architectures using --arch=<arch>\n"
116 die "smock: specify one or more distros using --distro=<distro>\n"
120 die "smock: specify one or more SRPMs to build on the command line\n"
123 # Resolve the names, dependency list, etc. of the SRPMs that were
128 open PIPE, "$_[0] |" or die "$_[0]: $!";
138 open PIPE, "$_[0] |" or die "$_[0]: $!";
149 foreach my $srpm (@srpms) {
150 my $name = get_one_line "rpm -q --qf '%{name}' -p '$srpm'";
151 my $version = get_one_line "rpm -q --qf '%{version}' -p '$srpm'";
152 my $release = get_one_line "rpm -q --qf '%{release}' -p '$srpm'";
154 my @buildrequires = get_lines "rpm -q --requires -p '$srpm' |
155 grep -Eo '^[^[:space:]]+'";
157 #print "Filename: $srpm\n";
158 #print " name = $name\n";
159 #print " version = $version\n";
160 #print " release = $release\n";
161 #print " buildrequires = ", join (",", @buildrequires), "\n";
167 buildrequires => \@buildrequires,
172 # We don't care about buildrequires unless they refer to other
173 # packages that we are building. So filter them on this condition.
180 return 1 if $item eq $_;
187 my $dep = shift; # eg. dbus-devel
190 return $dep if is_member_of ($dep, @_);
192 $newdep =~ s/-\w+$//; # eg. dbus-devel -> dbus
193 last if $newdep eq $dep;
199 my @names = sort keys %srpms;
200 foreach my $name (@names) {
201 my @buildrequires = @{$srpms{$name}->{buildrequires}};
202 @buildrequires = grep { $_ = dependency_in ($_, @names) } @buildrequires;
203 $srpms{$name}{buildrequires} = \@buildrequires;
206 # Now sort the SRPMs into the correct order for building
208 my ($fh, $filename) = tempfile ();
210 foreach my $name (@names) {
211 my @buildrequires = @{$srpms{$name}->{buildrequires}};
212 foreach (@buildrequires) {
213 print $fh "$_ $name\n"
218 my @buildorder = get_lines "tsort $filename";
220 # With --chain flag we print the packages in groups for chain building.
226 print 'make chain-build CHAIN="';
228 foreach $name (@buildorder) {
229 my @br = @{$srpms{$name}->{buildrequires}};
231 # If a BR occurs within the current group, then start the next group.
234 if (exists $group{$_}) {
253 # With --dryrun flag we just print the packages in build order then exit.
256 foreach (@buildorder) {
263 # Now we can build each SRPM.
270 mkdir ($_, 0755) or die "mkdir $_: $!"
279 my_mkdir "$localrepo/$distro";
280 my_mkdir "$localrepo/$distro/src";
281 my_mkdir "$localrepo/$distro/src/SRPMS";
282 system ("cd $localrepo/$distro/src && rm -rf repodata && createrepo -q .") == 0
283 or die "createrepo failed: $?\n";
285 my_mkdir "$localrepo/$distro/$arch";
286 my_mkdir "$localrepo/$distro/$arch/RPMS";
287 my_mkdir "$localrepo/$distro/$arch/logs";
289 system ("cd $localrepo/$distro/$arch && rm -rf repodata && createrepo -q --exclude 'logs/*rpm' .") == 0
290 or die "createrepo failed: $?\n";
293 if (! -d "$localrepo/scratch") {
294 mkdir "$localrepo/scratch"
295 or die "mkdir $localrepo/scratch: $!\nIf you haven't set up a local repository yet, you must read the README file.\n";
298 system "rm -f $localrepo/scratch/*";
300 # NB: Need to do the arch/distro in the outer loop to work
301 # around the caching bug in mock/yum.
302 foreach my $arch (@arches) {
303 foreach my $distro (@distros) {
304 foreach my $name (@buildorder) {
305 my $version = $srpms{$name}->{version};
306 my $release = $srpms{$name}->{release};
307 my $srpm_filename = $srpms{$name}->{filename};
309 $release =~ s/\.fc?\d+$//; # "1.fc9" -> "1"
311 # Does the built (binary) package exist already?
312 my $pattern = "$localrepo/$distro/$arch/RPMS/$name-$version-$release.*.rpm";
313 #print "pattern = $pattern\n";
314 my @binaries = glob $pattern;
318 # Rebuild the package.
319 print "*** building $name-$version-$release $arch $distro ***\n";
321 createrepo ($arch, $distro);
322 system ("mock -r $distro-$arch --resultdir $localrepo/scratch $srpm_filename") == 0
323 or die "Build failed, return code $?\nLeaving the logs in $localrepo/scratch\n";
325 # Build was a success so move the final RPMs into the
326 # mock repo for next time.
327 system ("mv $localrepo/scratch/*.src.rpm $localrepo/$distro/src/SRPMS") == 0 or die "mv";
328 system ("mv $localrepo/scratch/*.rpm $localrepo/$distro/$arch/RPMS") == 0 or die "mv";
329 my_mkdir "$localrepo/$distro/$arch/logs/$name-$version-$release";
330 system ("mv $localrepo/scratch/*.log $localrepo/$distro/$arch/logs/$name-$version-$release/") == 0 or die "mv";
332 createrepo ($arch, $distro);
336 print "skipping $name-$version-$release $arch $distro\n";