diff options
Diffstat (limited to 'presto-utils/packagelist.py')
-rw-r--r-- | presto-utils/packagelist.py | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/presto-utils/packagelist.py b/presto-utils/packagelist.py new file mode 100644 index 0000000..e9019f9 --- /dev/null +++ b/presto-utils/packagelist.py @@ -0,0 +1,386 @@ +# 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 +# Copyright (c) 2007 Jonathan Dieter + +import rpmUtils.miscutils +import os +import commands + +class RpmItem: + def __init__(self, nevra, f): + (self.name, self.epoch, self.version, self.release, self.arch) = nevra + self.epoch = str(self.epoch) + self.filename = f + + def getNevra(self): + return (self.name, self.epoch, self.version, self.release, self.arch) + + def __eq__(self, b): + if b == None: + return False + try: + # An RpmItem is equal to another RpmItem if the nevra's are equal + if self.getNevra() == b.getNevra(): + return True + else: + return False + except: + # An RpmItem is equal to a DrpmItem if the nevra is equal to the drpm's destination nevra + if self.getNevra() == b.getDstNevra(): + return True + else: + return False + +class DrpmItem: + def __init__(self, src_nevra, dst_nevra, f): + (self.src_name, self.src_epoch, self.src_version, self.src_release, self.src_arch) = src_nevra + (self.dst_name, self.dst_epoch, self.dst_version, self.dst_release, self.dst_arch) = dst_nevra + self.src_epoch = str(self.src_epoch) + self.dst_epoch = str(self.dst_epoch) + self.filename = f + + def exists(self): + return self.filename != None + + def getSrcNevra(self): + return (self.src_name, self.src_epoch, self.src_version, self.src_release, self.src_arch) + + def getDstNevra(self): + return (self.dst_name, self.dst_epoch, self.dst_version, self.dst_release, self.dst_arch) + + def getSrcDstNevra(self): + return [self.getSrcNevra(), self.getDstNevra()] + + def __eq__(self, b): + if b == None: + return False + try: + # A DrpmItem is equal to another DrpmItem if both source and destination nevra's are equal + if self.getSrcDstNevra() == b.getSrcDstNevra(): + return True + else: + return False + except: + # A DrpmItem is equal to an RpmItem if the destination nevra is equal to the rpm's nevra + if self.getDstNevra() == b.getNevra(): + return True + else: + return False + + +class PackageList: + def __init__(self, base_dir, drpm_dir, threshold, debug): + self.base_dir = base_dir + self.drpm_dir = drpm_dir + self.threshold = threshold + self.debug = debug + self.rpm_list = {} + self.sorted = False + + def addRpm(self, rpm): + """Add RpmItem to PackageList""" + self.sorted = False + rpm_key = "%s.%s" % (rpm.name, rpm.arch) + self.rpm_list.setdefault(rpm_key, {}) + self.rpm_list[rpm_key].setdefault("rpms", []) + found = False + for found_rpm in self.rpm_list[rpm_key]["rpms"]: + if rpm == found_rpm: + found = True + break + if not found: + self.rpm_list[rpm_key]["rpms"].append(rpm) + + def addDrpm(self, drpm): + """Add DrpmItem to PackageList""" + self.sorted = False + rpm_key = "%s.%s" % (drpm.src_name, drpm.src_arch) + self.rpm_list.setdefault(rpm_key, {}) + self.rpm_list[rpm_key].setdefault("drpms", []) + found = False + for found_drpm in self.rpm_list[rpm_key]["drpms"]: + if drpm == found_drpm: + found = True + break + if not found: + self.rpm_list[rpm_key]["drpms"].append(drpm) + + def sort(self): + """Sort all rpms and deltarpms in reverse order. This is necessary before running any + methods that try to work with rpms and deltarpms""" + self.sorted = True + for rpm_type in self.rpm_list.values(): + for key in rpm_type.keys(): + if key == "rpms" and len(rpm_type["rpms"]) > 1: + def sortByEVR(rpm1, rpm2): + (n1,e1,v1,r1,a1) = rpm1.getNevra() + (n2,e2,v2,r2,a2) = rpm2.getNevra() + rc = rpmUtils.miscutils.compareEVR((e1,v1,r1),(e2,v2,r2)) + if rc == 0: + return 0 + if rc > 0: + return -1 + if rc < 0: + return 1 + rpm_type["rpms"].sort(sortByEVR) # highest first in list + elif key == "drpms" and len(rpm_type["drpms"]) > 1: + def sortByEVR(drpm1, drpm2, src=False): + if src: + (n1,e1,v1,r1,a1) = drpm1.getSrcNevra() + (n2,e2,v2,r2,a2) = drpm2.getSrcNevra() + else: + (n1,e1,v1,r1,a1) = drpm1.getDstNevra() + (n2,e2,v2,r2,a2) = drpm2.getDstNevra() + rc = rpmUtils.miscutils.compareEVR((e1,v1,r1),(e2,v2,r2)) + if rc == 0: + if src: + return 0 + else: + return sortByEVR(drpm1, drpm2, True) + if rc > 0: + return -1 + if rc < 0: + return 1 + rpm_type["drpms"].sort(sortByEVR) # highest first in list + + def dump(self): + """Dump list of all packages and their rpms and deltarpms""" + if not self.sorted: + self.sort() + temp_list = [] + for x in self.rpm_list.keys(): + temp_list.append(x) + temp_list.sort() + for x in temp_list: + print x + if self.rpm_list[x].has_key("rpms"): + print " RPMS:" + for rpm in self.rpm_list[x]["rpms"]: + print " %s:%s-%s" % (rpm.epoch, rpm.version, rpm.release) + if self.rpm_list[x].has_key("drpms"): + print " DRPMS:" + for drpm in self.rpm_list[x]["drpms"]: + print " %s:%s-%s => %s:%s-%s" % (drpm.src_epoch, drpm.src_version, drpm.src_release, drpm.dst_epoch, drpm.dst_version, drpm.dst_release) + + def __doWork(self, nevra1, nevra2, f1, deltaCommand): + (n1,e1,v1,r1,a1) = nevra1 + (n2,e2,v2,r2,a2) = nevra2 + + deltaRPMName = os.path.join(self.drpm_dir, '%s-%s-%s_%s-%s.%s.drpm' % (n1, v2, r2, v1, r1, a1)) + deltaCommand += deltaRPMName + if self.debug: + print deltaCommand + + if os.path.exists("%s.dontdelta" % deltaRPMName): + f = open("%s.dontdelta" % deltaRPMName, "r") + drpmsize = f.readline()[:-1] + drpmsize = int(drpmsize) + if not self.__drpmIsWorthKeeping(drpmsize, f1): + return False + else: + if self.debug: + print "Original drpm is now worth creating...deleting %s%s.dontdelta" % (self.base_dir, deltaRPMName) + try: + os.unlink("%s.dontdelta" % deltaRPMName) + except Exception, e: + print "Error deleting %s.dontdelta" % os.path.basename(deltaRPMName), str(e) + + (code, out) = commands.getstatusoutput(deltaCommand) + if code: + print "Error genDeltaRPM for %s: exitcode was %s - Reported Error: %s" % (n1, code, out) + return False + else: + # Check whether or not we should keep the drpm + drpmsize = os.path.getsize(deltaRPMName) + if not self.__drpmIsWorthKeeping(drpmsize, f1): + if self.debug: + print 'deleting %s' % (deltaRPMName) + f = open("%s.dontdelta" % deltaRPMName, "w") + f.write("%i\n" % os.path.getsize(deltaRPMName)) + f.close() + try: + os.unlink(deltaRPMName) + except Exception, e: + print "Error deleting deltarpm %s" % os.path.basename(deltaRPMName), str(e) + return False + else: + if e1 == e2: + print 'Generated delta rpm for %s.%s - %s-%s => %s-%s' % (n1, a1, v2, r2, v1, r1) + else: + print 'Generated delta rpm for %s.%s - %s:%s-%s => %s:%s-%s' % (n1, a1, e2, v2, r2, e1, v1, r1) + drpm = DrpmItem(nevra2, nevra1, deltaRPMName) + self.addDrpm(drpm) + self.sort() + if self.debug: + self.dump() + return True + + def __combineDeltaRpm(self, combine_list, dstrpm): + nevra1 = combine_list[-1].getDstNevra() + nevra2 = combine_list[0].getSrcNevra() + f1 = dstrpm.filename + + deltaCommand = 'combinedeltarpm ' + for drpm in combine_list: + deltaCommand += "%s " % drpm.filename + + return self.__doWork(nevra1, nevra2, f1, deltaCommand) + + + def __buildDeltaRpm(self, srcrpm, dstrpm): + nevra1 = dstrpm.getNevra() + nevra2 = srcrpm.getNevra() + + f1 = dstrpm.filename + f2 = srcrpm.filename + deltaCommand = 'makedeltarpm %s %s ' % (f2, f1) + + return self.__doWork(nevra1, nevra2, f1, deltaCommand) + + def __makeDeltaRpm(self, src_nevra, dstrpm, package): + foundSrc = False + foundDst = False + tempQueue = [] + if package.has_key("drpms"): + for drpm in package["drpms"]: + if drpm.getDstNevra() == dstrpm.getNevra() and drpm.getSrcNevra() == src_nevra: + return True + if drpm.getSrcNevra() == src_nevra: + for item in tempQueue: + if drpm.getDstNevra() == item.getSrcNevra(): + combine_list = [drpm, item] + return self.__combineDeltaRpm(combine_list, dstrpm) + elif drpm.getDstNevra() == dstrpm.getNevra(): + tempQueue.append(drpm) + + for rpm in package["rpms"]: + if rpm.getNevra() == src_nevra: + return self.__buildDeltaRpm(rpm, dstrpm) + + print "Found nothing!" + return False + + + def makeDeltaRpms(self, DrpmsPerPackage=0, DoFirst=True, OnlyLastPackage=True): + """Create deltarpms for packages. + Attributes: + OnlyLastPackage (Boolean): Only create deltarpms to point to last destination package + DrpmsPerPackage (Int): Number of deltarpms to make for each package (0 = all possible) + DoFirst (Boolean): Create deltarpm for first source package""" + if not self.sorted: + self.sort() + temp_list = [] + for x in self.rpm_list.keys(): + temp_list.append(x) + temp_list.sort() + if self.debug: + print "Building drpms" + for rpm_name in temp_list: + package = self.rpm_list[rpm_name] + if not package.has_key("rpms") or len(package["rpms"]) == 0: + if self.debug: + print "No rpms for %s: Doing nothing" % rpm_name + continue + + if (not package.has_key("drpms") or len(package["drpms"]) == 0) and len(package["rpms"]) == 1: + if self.debug: + print "Only one rpm available for %s: Doing nothing" % rpm_name + continue + + build_list = [] + + for rpm in package["rpms"]: + if [rpm.getNevra(), 1] not in build_list: + build_list.append([rpm.getNevra(), 1]) + + if package.has_key("drpms"): + for drpm in package["drpms"]: + if [drpm.getSrcNevra(), 1] not in build_list and [drpm.getSrcNevra(), 0] not in build_list: + build_list.append([drpm.getSrcNevra(), 0]) + if [drpm.getDstNevra(), 1] not in build_list and [drpm.getDstNevra(), 0] not in build_list: + build_list.append([drpm.getDstNevra(), 0]) + + def sortByEVR(rpm1, rpm2): + (n1,e1,v1,r1,a1) = rpm1[0] + (n2,e2,v2,r2,a2) = rpm2[0] + rc = rpmUtils.miscutils.compareEVR((e1,v1,r1),(e2,v2,r2)) + if rc == 0: + return 0 + if rc > 0: + return -1 + if rc < 0: + return 1 + build_list.sort(sortByEVR) + + if OnlyLastPackage: + if build_list[0][1] != 1: + continue + + rpm = None + for x in package["rpms"]: + if x.getNevra() == build_list[0][0]: + rpm = x + break + if rpm == None: + continue + + newpkg_list = [rpm] + else: + newpkg_list = [] + for build in build_list[:-1]: + if build[1] != 1: + continue + + rpm = None + for x in package["rpms"]: + if x.getNevra() == build[0]: + rpm = x + break + if rpm == None: + continue + + newpkg_list.append(rpm) + + for newpkg in newpkg_list: + start = False + count = 0 + do_last = True + for build in build_list[:-1]: + if start: + self.__makeDeltaRpm(build[0], newpkg, package) + if not self.sorted: + self.sort() + count += 1 + if DrpmsPerPackage != 0: + if count >= DrpmsPerPackage and not DoFirst: + do_last = False + break + elif count >= DrpmsPerPackage - 1 and DoFirst: + break + if build[0] == newpkg.getNevra(): + start = True + + if DoFirst == 1 and start and do_last: + self.__makeDeltaRpm(build_list[-1][0], newpkg, package) + if not self.sorted: + self.sort() + return + + def __drpmIsWorthKeeping(self, drpmsize, newrpm): + newsize = os.path.getsize(newrpm) + # Delete the drpm if it's too large + if drpmsize > self.threshold * newsize: + return False + return True + |