diff options
author | Colin Walters <walters@verbum.org> | 2010-10-07 22:41:24 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2010-10-07 22:41:24 -0400 |
commit | 7cb47c0a3b43536e55bd42a435cbc1454dc09ee3 (patch) | |
tree | f36c6f9eb9bc3f6d39ceefcde30b1409ae6c2ba1 | |
parent | 4dbd6dbea57d79b0d2a06ec051d0ac160df1d414 (diff) | |
download | rpmci-7cb47c0a3b43536e55bd42a435cbc1454dc09ee3.tar.gz rpmci-7cb47c0a3b43536e55bd42a435cbc1454dc09ee3.tar.xz rpmci-7cb47c0a3b43536e55bd42a435cbc1454dc09ee3.zip |
mock-many-srpms: Import
-rw-r--r-- | mock-many-srpms | 308 |
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() |