summaryrefslogtreecommitdiffstats
path: root/presto-utils/packagelist.py
diff options
context:
space:
mode:
Diffstat (limited to 'presto-utils/packagelist.py')
-rw-r--r--presto-utils/packagelist.py386
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
+