summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-10-07 22:41:24 -0400
committerColin Walters <walters@verbum.org>2010-10-07 22:41:24 -0400
commit7cb47c0a3b43536e55bd42a435cbc1454dc09ee3 (patch)
treef36c6f9eb9bc3f6d39ceefcde30b1409ae6c2ba1
parent4dbd6dbea57d79b0d2a06ec051d0ac160df1d414 (diff)
downloadrpmci-7cb47c0a3b43536e55bd42a435cbc1454dc09ee3.tar.gz
rpmci-7cb47c0a3b43536e55bd42a435cbc1454dc09ee3.tar.xz
rpmci-7cb47c0a3b43536e55bd42a435cbc1454dc09ee3.zip
mock-many-srpms: Import
-rw-r--r--mock-many-srpms308
1 files changed, 308 insertions, 0 deletions
diff --git a/mock-many-srpms b/mock-many-srpms
new file mode 100644
index 0000000..a1c4a94
--- /dev/null
+++ b/mock-many-srpms
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+
+# mock-many-srpms:
+# Build binary RPMS for the named source RPMs.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+# Written by Colin Walters <walters@verbum.org>
+# --auto-sort option derived from code by Seth Vidal <skvidal@fedoraproject.org>
+
+import getopt
+import os
+import sys
+import subprocess
+import tempfile
+import shutil
+from StringIO import StringIO
+
+def check_call_verbose(*args, **kwargs):
+ print "Running: %r %r" % (args[0], kwargs)
+ subprocess.check_call(*args, **kwargs)
+
+def popen_verbose(*args, **kwargs):
+ print "Running: %r" % (args[0], )
+ return subprocess.Popen(*args, **kwargs)
+
+def list_source_names_in_dir(dirpath):
+ """Return all source RPM names from directory (unsorted, may include duplicates)."""
+ files = os.listdir(dirpath)
+ sources = []
+ for f in files:
+ if not f.endswith('.src.rpm'):
+ continue
+ name = f.rsplit('-', 1)[0]
+ sources.append(name)
+ return sources
+
+def delete_old_rpms_in_dir(dirpath):
+ """Ensure there's only one version of each binary RPM in a directory."""
+ proc = popen_verbose(['repomanage', '-o', '.'], stdout=subprocess.PIPE,
+ stderr=sys.stderr,
+ cwd=dirpath)
+ output = proc.communicate()[0]
+ for line in output.split('\n'):
+ if line.endswith('.rpm') and os.path.exists(line):
+ os.unlink(line)
+
+def return_binary_pkgs_from_srpm(srpmfn):
+ import glob
+ import rpm
+ mydir = tempfile.mkdtemp()
+ binary_pkgs = []
+ rc = subprocess.Popen(['rpm2cpio', srpmfn],stdout=subprocess.PIPE)
+ cs = subprocess.Popen(['cpio', '--quiet', '-i', '*.spec'], cwd=mydir,
+ stdin=rc.stdout, stdout=subprocess.PIPE, stderr=open('/dev/null', 'w'))
+ output = cs.communicate()[0]
+ specs = glob.glob(mydir + '/*.spec')
+ if not specs:
+ return binary_pkgs
+ spkg = rpm.spec(specs[0])
+ for p in spkg.packages:
+ binary_pkgs.append(p.header['name'])
+ return binary_pkgs
+
+def sort_srpms_by_build_order(srpms):
+ """Input: list of file paths to source RPMs.
+Output: Sorted list."""
+ import yum
+ my = yum.YumBase()
+ my.preconf.init_plugins=False
+ my.setCacheDir()
+
+ build_reqs = {}
+ build_bin = {}
+ srpms_to_pkgs = {}
+
+ for i in srpms:
+ # generate the list of binpkgs the srpms create
+ build_bin[i] = return_binary_pkgs_from_srpm(i)
+
+ # generate the list of provides in the repos we know about from those binpkgs (if any)
+ p_names = []
+ for name in build_bin[i]:
+ providers = my.pkgSack.searchNevra(name=name)
+ if providers:
+ p_names.extend(providers[0].provides_names)
+ build_bin[i].extend(p_names)
+
+ # setup the build_reqs
+ build_reqs[i] = []
+
+ for i in srpms:
+ # go through each srpm and take its buildrequires and resolve them out to one of other
+ # srpms, if possible using the build_bin list we just generated
+ # toss out any pkg which doesn't map back - this only does requires NAMES - not versions
+ # so don't go getting picky about versioning here.
+ lp = yum.packages.YumLocalPackage(ts=my.ts, filename=i)
+ srpms_to_pkgs[i] = lp
+ for r in lp.requires_names:
+ for srpm in build_bin:
+ if r in build_bin[srpm]:
+ build_reqs[i].append(srpm)
+
+ # output the results in a format tsort(1) can cope with
+ (tmpfd, temppath) = tempfile.mkstemp()
+ tmpf = os.fdopen(tmpfd, 'w')
+ for (pkg,reqlist) in build_reqs.items():
+ for req in reqlist:
+ tmpf.write('%s %s' % (pkg, req))
+ tmpf.write('\n')
+ tmpf.close()
+
+ tsort_proc = subprocess.Popen(['tsort', temppath], stdout=subprocess.PIPE,
+ stderr=sys.stderr)
+ output_str = tsort_proc.communicate()[0]
+ output = StringIO(output_str)
+ output_str = None
+ tsort_proc.wait()
+ os.unlink(temppath)
+ result = []
+ # Reverse output order
+ for line in output:
+ result.insert(0, line.strip())
+ return result
+
+def main():
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], '', ['root=', 'resultdir=', 'logdir=', 'delete-old',
+ 'continue-on-fail', 'skip-have-build', 'save-temps',
+ 'auto-sort'])
+ except getopt.GetoptError, e:
+ print unicode(e)
+ print "Usage: mock-many-srpms --root=fedora-13-x86-64 --root=fedora-13-i386 --logdir=/path/to/logdir --resultdir=/path/to/repo rpm1 rpm2 ..."
+ sys.exit(1)
+
+ auto_sort = False
+ save_temps = False
+ continue_on_fail = False
+ skip_have_build = False
+ delete_old = False
+ resultdir = None
+ logdir = None
+ roots = []
+ for o, a in opts:
+ if o in ('--root', ):
+ roots.append(a)
+ elif o in ('--resultdir', ):
+ resultdir = a
+ elif o in ('--logdir', ):
+ logdir = a
+ elif o in ('--delete-old', ):
+ delete_old = True
+ elif o in ('--continue-on-fail'):
+ continue_on_fail = True
+ elif o in ('--skip-have-build'):
+ skip_have_build = True
+ elif o in ('--save-temps'):
+ save_temps = True
+ elif o in ('--auto-sort'):
+ auto_sort = True
+
+ if len(roots) == 0:
+ print "Must specify at least one --root"
+ sys.exit(1)
+ if logdir is None:
+ print "Must specify --logdir=/path/to/logs"
+ sys.exit(1)
+ if resultdir is None:
+ print "Must specify --resultdir=/path/to/repository"
+ sys.exit(1)
+
+ if len(args) == 0:
+ print "No source RPMS specified."
+ sys.exit(1)
+
+ for arg in args:
+ if not os.path.isfile(arg):
+ print "Couldn't find source RPM '%r'" % (arg, )
+
+ if auto_sort:
+ print "Auto-sorting by build order"
+ args = sort_srpms_by_build_order(args)
+ print "Determined build order: %r" % (args, )
+
+ if not os.path.exists(resultdir):
+ print "Creating initial empty repository in %r" % (resultdir, )
+ os.makedirs(resultdir)
+ check_call_verbose(['createrepo', '.'], cwd=resultdir)
+
+ if not os.path.isdir(logdir):
+ os.mkdir(logdir)
+
+ tmpdir = tempfile.mkdtemp()
+ tmp_mock_dir = os.path.join(tmpdir, 'mock')
+ os.mkdir(tmp_mock_dir)
+
+ for f in ('site-defaults.cfg', 'logging.ini'):
+ path = os.path.join('/etc', 'mock', f)
+ new_path = os.path.join(tmp_mock_dir, f)
+ shutil.copy2(path, new_path)
+ orig_stat = os.stat(path)
+ os.utime(new_path, (orig_stat.st_atime, orig_stat.st_mtime))
+
+ for root in roots:
+ orig_config_path = os.path.join('/etc', 'mock', root + '.cfg')
+ f_in = open(orig_config_path)
+ new_mockroot_path = os.path.join(tmp_mock_dir, root + '.cfg')
+ f_out = open(new_mockroot_path, 'w')
+ for line in f_in:
+ f_out.write(line)
+ f_in.close()
+ orig_stat = os.stat(orig_config_path)
+ os.utime(new_mockroot_path, (orig_stat.st_atime, orig_stat.st_mtime))
+ f_out.write('config_opts[\'yum.conf\'] += """[buildchain]\nname=buildchain\nbaseurl=file://%s\n"""' % (os.path.abspath(resultdir), ))
+ f_out.close()
+
+ if skip_have_build:
+ previous_successful_builds = list_source_names_in_dir(resultdir)
+ else:
+ previous_successful_builds = []
+
+ succeeded = []
+ skipped = []
+ failed = []
+ for srpm in args:
+ srpm_name = os.path.basename(srpm)
+ src_name = srpm_name.rsplit('-', 1)[0]
+
+ if src_name in previous_successful_builds:
+ print "Skipping %r due to previous successful build" % (srpm_name, )
+ skipped.append(srpm_name)
+ continue
+
+ mock_resultdir = os.path.join(logdir, srpm_name)
+ if not os.path.isdir(mock_resultdir):
+ os.makedirs(mock_resultdir)
+
+ current_failed = False
+ for root in roots:
+ try:
+ check_call_verbose(['mock', '--configdir=' + tmp_mock_dir, '-r', root,
+ '--resultdir=' + mock_resultdir, 'rebuild', srpm],
+ stdout=sys.stdout, stderr=sys.stderr)
+ except subprocess.CalledProcessError, e:
+ current_failed = True
+
+ if current_failed:
+ print "FAILED: %r" % (srpm_name, )
+ if continue_on_fail:
+ failed.append(srpm_name)
+ continue
+ else:
+ break
+
+ succeeded.append(srpm_name)
+ print "Successfully built %r" % (srpm_name, )
+ print "Updating repository in %r" % (resultdir, )
+ linkname = os.path.join(resultdir, srpm_name)
+ if not os.path.exists(linkname):
+ os.link(srpm, linkname)
+ for filename in os.listdir(mock_resultdir):
+ if not filename.endswith('.rpm'):
+ continue
+ src = os.path.join(mock_resultdir, filename)
+ linkname = os.path.join(resultdir, filename)
+ if os.path.exists(linkname):
+ continue
+ os.link(src, linkname)
+ check_call_verbose(['createrepo', '.'], cwd=resultdir)
+ if delete_old:
+ delete_old_rpms_in_dir(resultdir)
+
+ if save_temps:
+ print "Temporary files saved in %r" % (tmp_mock_dir, )
+ else:
+ shutil.rmtree(tmp_mock_dir)
+ if len(skipped) > 0:
+ print "The following builds were skipped due to a previous successful build:"
+ for v in skipped:
+ print " %r" % (v, )
+ if len(succeeded) > 0:
+ print "The following builds were successful:"
+ for v in succeeded:
+ print " %r" % (v, )
+ if len(failed) > 0:
+ print "The following builds failed:"
+ for v in failed:
+ print " %r" % (v, )
+ if len(failed) == 0:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()