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";
35 "distro=s" => \@distros,
36 "localrepo=s" => \$localrepo,
40 pod2usage (1) if $help;
41 pod2usage (-exitstatus => 0, -verbose => 2) if $man;
51 smock.pl --arch=i386 --arch=x86_64 --distro=fedora-10 list of SRPMs ...
55 This is a wrapper around I<mock> which lets you build a whole group of
56 mutually dependent SRPMs in one go.
58 The smock command will work out the correct order in which to build
59 the SRPMs, and makes the result of previous RPM builds available as
60 dependencies for later builds.
62 Smock also works incrementally. It won't rebuild RPMs which were
63 built already in a previous run, which means if a package fails to
64 build, you can just fix it and rerun the same smock command. (In the
65 unlikely case that you want to force smock to rebuild RPMs then you
66 must bump the release number or delete the binary RPM from the
69 B<NOTE:> Please read the README file first. You need to set up mock
70 and a web server before you can use this command.
78 Specify the architecture(s) to build, eg. i386, x86_64. You can
79 list this option several times to build several architectures.
83 Specify the distribution(s) to build, eg. fedora-9, fedora-10.
84 You can list this option several times to build several distributions.
88 Local repository. Defaults to C<$HOME/public_html/smock/yum>
97 die "smock: specify one or more architectures using --arch=<arch>\n"
101 die "smock: specify one or more distros using --distro=<distro>\n"
105 die "smock: specify one or more SRPMs to build on the command line\n"
108 # Resolve the names, dependency list, etc. of the SRPMs that were
113 open PIPE, "$_[0] |" or die "$_[0]: $!";
123 open PIPE, "$_[0] |" or die "$_[0]: $!";
134 foreach my $srpm (@srpms) {
135 my $name = get_one_line "rpm -q --qf '%{name}' -p '$srpm'";
136 my $version = get_one_line "rpm -q --qf '%{version}' -p '$srpm'";
137 my $release = get_one_line "rpm -q --qf '%{release}' -p '$srpm'";
139 my @buildrequires = get_lines "rpm -q --requires -p '$srpm' |
140 grep -Eo '^[^[:space:]]+'";
142 #print "Filename: $srpm\n";
143 #print " name = $name\n";
144 #print " version = $version\n";
145 #print " release = $release\n";
146 #print " buildrequires = ", join (",", @buildrequires), "\n";
152 buildrequires => \@buildrequires,
157 # We don't care about buildrequires unless they refer to other
158 # packages that we are building. So filter them on this condition.
165 return 1 if $item eq $_;
172 my $dep = shift; # eg. dbus-devel
175 return $dep if is_member_of ($dep, @_);
177 $newdep =~ s/-\w+$//; # eg. dbus-devel -> dbus
178 last if $newdep eq $dep;
184 my @names = sort keys %srpms;
185 foreach my $name (@names) {
186 my @buildrequires = @{$srpms{$name}->{buildrequires}};
187 @buildrequires = grep { $_ = dependency_in ($_, @names) } @buildrequires;
188 $srpms{$name}{buildrequires} = \@buildrequires;
191 # Now sort the SRPMs into the correct order for building
193 my ($fh, $filename) = tempfile ();
195 foreach my $name (@names) {
196 my @buildrequires = @{$srpms{$name}->{buildrequires}};
197 foreach (@buildrequires) {
198 print $fh "$_ $name\n"
203 my @buildorder = get_lines "tsort $filename";
205 #foreach (@buildorder) {
209 # Now we can build each SRPM.
216 mkdir ($_, 0755) or die "mkdir $_: $!"
225 my_mkdir "$localrepo/$distro";
226 my_mkdir "$localrepo/$distro/src";
227 my_mkdir "$localrepo/$distro/src/SRPMS";
228 system ("cd $localrepo/$distro/src && rm -rf repodata && createrepo -q .") == 0
229 or die "createrepo failed: $?\n";
231 my_mkdir "$localrepo/$distro/$arch";
232 my_mkdir "$localrepo/$distro/$arch/RPMS";
233 my_mkdir "$localrepo/$distro/$arch/logs";
235 system ("cd $localrepo/$distro/$arch && rm -rf repodata && createrepo -q --exclude 'logs/*rpm' .") == 0
236 or die "createrepo failed: $?\n";
239 if (! -d "$localrepo/scratch") {
240 mkdir "$localrepo/scratch"
241 or die "mkdir $localrepo/scratch: $!\nIf you haven't set up a local repository yet, you must read the README file.\n";
244 system "rm -f $localrepo/scratch/*";
246 # NB: Need to do the arch/distro in the outer loop to work
247 # around the caching bug in mock/yum.
248 foreach my $arch (@arches) {
249 foreach my $distro (@distros) {
250 foreach my $name (@buildorder) {
251 my $version = $srpms{$name}->{version};
252 my $release = $srpms{$name}->{release};
253 my $srpm_filename = $srpms{$name}->{filename};
255 $release =~ s/\.fc?\d+$//; # "1.fc9" -> "1"
257 # Does the built (binary) package exist already?
258 my $pattern = "$localrepo/$distro/$arch/RPMS/$name-$version-$release.*.rpm";
259 #print "pattern = $pattern\n";
260 my @binaries = glob $pattern;
264 # Rebuild the package.
265 print "*** building $name-$version-$release $arch $distro ***\n";
267 createrepo ($arch, $distro);
268 system ("mock -r $distro-$arch --resultdir $localrepo/scratch $srpm_filename") == 0
269 or die "Build failed, return code $?\nLeaving the logs in $localrepo/scratch\n";
271 # Build was a success so move the final RPMs into the
272 # mock repo for next time.
273 system ("mv $localrepo/scratch/*.src.rpm $localrepo/$distro/src/SRPMS") == 0 or die "mv";
274 system ("mv $localrepo/scratch/*.rpm $localrepo/$distro/$arch/RPMS") == 0 or die "mv";
275 my_mkdir "$localrepo/$distro/$arch/logs/$name-$version-$release";
276 system ("mv $localrepo/scratch/*.log $localrepo/$distro/$arch/logs/$name-$version-$release/") == 0 or die "mv";
278 createrepo ($arch, $distro);
282 print "skipping $name-$version-$release $arch $distro\n";