#!/usr/bin/python # # 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 Library 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. # # Copyright 2005 Dan Williams and Red Hat, Inc. import os, sys import time import rpmUtils import commands import shutil import string class RebuildException(Exception): pass class EnqueueException(Exception): pass def first_is_newer(evr1, evr2): rc = rpmUtils.miscutils.compareEVR(evr1, evr2) if rc == 0: # same return True elif rc > 0: return True elif rc < 0: return False def find_newest_srpms(path): """ Build up a list of the most recent SRPMs in a directory """ srpm_dict = {} for root, dirs, files in os.walk(path): for f in files: # match the files to what list they should be in if not f.endswith('.src.rpm'): continue fullfile = os.path.join(root, f) ts = rpmUtils.transaction.initReadOnlyTransaction() hdr = rpmUtils.miscutils.hdrFromPackage(ts, fullfile) name = hdr['name'] ver_dict = { 'name': name, 'evr': (hdr['epoch'], hdr['version'], hdr['release']), 'file': fullfile } if not srpm_dict.has_key(name): srpm_dict[name] = ver_dict else: if first_is_newer(ver_dict['evr'], srpm_dict[name]['evr']): srpm_dict[name] = ver_dict del hdr del ts files_dict = {} for name in srpm_dict.keys(): files_dict[name] = srpm_dict[name]['file'] del srpm_dict return files_dict def rebuild_srpm(name, f, user=None): ts = rpmUtils.transaction.initReadOnlyTransaction() hdr = rpmUtils.miscutils.hdrFromPackage(ts, f) chlog_ver = "%s-%s.1" % (hdr['version'], hdr['release']) del ts del hdr # Create a temp dir temp_dir = os.path.join("/tmp", "rebuild", name) if not os.path.exists(temp_dir): os.makedirs(temp_dir) # install the srpm in the temp dir src_root = os.path.join(temp_dir, "usr", "src", "redhat") if not os.path.exists(src_root): os.makedirs(src_root) cmd = "/bin/rpm -ihv --root %s %s" % (temp_dir, f) (s, o) = commands.getstatusoutput(cmd) if s != 0: raise RebuildException("Could not install srpm %s: %s" % (f, o)) # find the specfile spec_dir = os.path.join(src_root, "SPECS") files = os.listdir(spec_dir) specfile = None for spec in files: if spec.endswith(".spec"): specfile = os.path.join(spec_dir, spec) break if not specfile: raise RebuildException("Could not locate specfile in %s." % spec_dir) src = open(specfile) specfile_new = specfile+".new" dst = open(specfile_new, "w") found = False changelog = False for line in src: if line.startswith("Release:"): line = string.strip(line) + ".1\n" found = True if line.startswith("%changelog"): changelog = True elif changelog and user: # Add a changelog entry for the rebuild t = time.strftime("%a %b %e %Y") entry = "* %s %s - %s\n- Rebuild\n\n" % (t, user, chlog_ver) dst.write(entry) changelog = False dst.write(line) dst.close() src.close() if not found: raise RebuildException("Couldn't find Release line in specfile %s." % specfile) os.rename(specfile_new, specfile) # rebuild the srpm cmd = '/usr/bin/rpmbuild -bs --nodeps --define "_sourcedir %s/usr/src/redhat/SOURCES" ' \ ' --define "_srcrpmdir %s" %s' % (temp_dir, temp_dir, specfile) (s, o) = commands.getstatusoutput(cmd) if s != 0: raise RebuildException("Could not rebuild srpm %s: %s" % (f, o)) new_srpm = None for line in o.split("\n"): if line.startswith("Wrote:"): line.replace("\n", "") (garbage, path) = line.split(':') new_srpm = path.strip() break if not new_srpm: raise RebuildException("Could not find rebuilt SRPM for %s." % specfile) # return the file's path return (new_srpm, temp_dir) def enqueue_new_srpm(rebuilt_srpm, target): cmd = "/usr/bin/plague-client build %s %s" % (rebuilt_srpm, target) (s, o) = commands.getstatusoutput(cmd) if s != 0: raise EnqueueException("Enqueue command '%s' failed: '\n%s'" % (cmd, o)) def usage(program): print "%s [changelog user]" % program print "" if __name__ == '__main__': if len(sys.argv) < 4: usage(sys.argv[0]) sys.exit(1) search_dir = os.path.abspath(sys.argv[1]) if not os.path.exists(search_dir) or not os.access(search_dir, os.R_OK): print "Could not access %s" % search_dir sys.exit(1) target = sys.argv[2] user = None if len(sys.argv) > 3: user = sys.argv[3] # Build up a list of all SRPMs in the specified directory files = find_newest_srpms(search_dir) temp_dirs = [] # Rebuild and enqueue the packages names = files.keys() names.sort() for name in names: f = files[name] try: (rebuilt_srpm, temp_dir_path) = rebuild_srpm(name, f, user) except RebuildException, e: shutil.rmtree(temp_dir_path, ignore_errors=True) print "RE: %s (%s)" % (f, e) continue try: enqueue_new_srpm(rebuilt_srpm, target) except EnqueueException, e: shutil.rmtree(temp_dir_path, ignore_errors=True) print "EE: %s (%s)" % (rebuilt_srpm, e) continue temp_dirs.append(temp_dir_path) print "OK: %s" % rebuilt_srpm print "Sleeping before cleanup..." time.sleep(30) for path in temp_dirs: shutil.rmtree(path, ignore_errors=True) print "All done." sys.exit(0)