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"
215 # Add a self->self dependency. This ensures that any
216 # packages which don't have or appear as a dependency of
217 # any other package still get built.
218 print $fh "$name $name\n"
222 my @buildorder = get_lines "tsort $filename";
224 # With --chain flag we print the packages in groups for chain building.
230 print 'make chain-build CHAIN="';
232 foreach $name (@buildorder) {
233 my @br = @{$srpms{$name}->{buildrequires}};
235 # If a BR occurs within the current group, then start the next group.
238 if (exists $group{$_}) {
257 # With --dryrun flag we just print the packages in build order then exit.
260 foreach (@buildorder) {
267 # Now we can build each SRPM.
274 mkdir ($_, 0755) or die "mkdir $_: $!"
283 my_mkdir "$localrepo/$distro";
284 my_mkdir "$localrepo/$distro/src";
285 my_mkdir "$localrepo/$distro/src/SRPMS";
286 system ("cd $localrepo/$distro/src && rm -rf repodata && createrepo -q .") == 0
287 or die "createrepo failed: $?\n";
289 my_mkdir "$localrepo/$distro/$arch";
290 my_mkdir "$localrepo/$distro/$arch/RPMS";
291 my_mkdir "$localrepo/$distro/$arch/logs";
293 system ("cd $localrepo/$distro/$arch && rm -rf repodata && createrepo -q --exclude 'logs/*rpm' .") == 0
294 or die "createrepo failed: $?\n";
297 if (! -d "$localrepo/scratch") {
298 mkdir "$localrepo/scratch"
299 or die "mkdir $localrepo/scratch: $!\nIf you haven't set up a local repository yet, you must read the README file.\n";
302 system "rm -f $localrepo/scratch/*";
304 # NB: Need to do the arch/distro in the outer loop to work
305 # around the caching bug in mock/yum.
306 foreach my $arch (@arches) {
307 foreach my $distro (@distros) {
308 foreach my $name (@buildorder) {
309 my $version = $srpms{$name}->{version};
310 my $release = $srpms{$name}->{release};
311 my $srpm_filename = $srpms{$name}->{filename};
313 $release =~ s/\.fc?\d+$//; # "1.fc9" -> "1"
315 # Does the built (binary) package exist already?
316 my $pattern = "$localrepo/$distro/$arch/RPMS/$name-$version-$release.*.rpm";
317 #print "pattern = $pattern\n";
318 my @binaries = glob $pattern;
322 # Rebuild the package.
323 print "*** building $name-$version-$release $arch $distro ***\n";
325 createrepo ($arch, $distro);
326 system ("mock -r $distro-$arch --resultdir $localrepo/scratch $srpm_filename") == 0
327 or die "Build failed, return code $?\nLeaving the logs in $localrepo/scratch\n";
329 # Build was a success so move the final RPMs into the
330 # mock repo for next time.
331 system ("mv $localrepo/scratch/*.src.rpm $localrepo/$distro/src/SRPMS") == 0 or die "mv";
332 system ("mv $localrepo/scratch/*.rpm $localrepo/$distro/$arch/RPMS") == 0 or die "mv";
333 my_mkdir "$localrepo/$distro/$arch/logs/$name-$version-$release";
334 system ("mv $localrepo/scratch/*.log $localrepo/$distro/$arch/logs/$name-$version-$release/") == 0 or die "mv";
336 createrepo ($arch, $distro);
340 print "skipping $name-$version-$release $arch $distro\n";