diff options
author | Jonathan Dieter <jdieter@gmail.com> | 2007-03-21 16:21:23 +0200 |
---|---|---|
committer | Jonathan Dieter <jdieter@gmail.com> | 2007-03-21 16:21:23 +0200 |
commit | afbedc06abf48f63ba8aee113103a0b360ed1c63 (patch) | |
tree | 7468431a27860afd19f1ca1356b9b862104f3972 /makerepo/createprestorepo.py | |
parent | eee8adadcd4fc3c0d7deea4a8ada73b4278c61f4 (diff) | |
download | presto-afbedc06abf48f63ba8aee113103a0b360ed1c63.tar.gz presto-afbedc06abf48f63ba8aee113103a0b360ed1c63.tar.xz presto-afbedc06abf48f63ba8aee113103a0b360ed1c63.zip |
Massive rewrite of whole system. Now uses yum-like XML data so we don't waste time on 404 messages.
Signed-off-by: Jonathan Dieter <jdieter@gmail.com>
Diffstat (limited to 'makerepo/createprestorepo.py')
-rwxr-xr-x | makerepo/createprestorepo.py | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/makerepo/createprestorepo.py b/makerepo/createprestorepo.py new file mode 100755 index 0000000..0fee5b4 --- /dev/null +++ b/makerepo/createprestorepo.py @@ -0,0 +1,308 @@ +#!/usr/bin/python -t +# -*- mode: Python; indent-tabs-mode: nil; -*- +# +# 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 + +import errno, os, sys, gzip +import fnmatch, re +import rpmUtils.transaction, rpmUtils.miscutils +import commands, libxml2 +import dumpMetadata +from dumpMetadata import _gzipOpen, getChecksum +#### import Utils + +DEBUG = False +#### Utils.setdebug(DEBUG) + +SUFFIX='drpm' +DRPMWORTHKEEPINGTHRESH=0.5 +DEBUG=0 +REPODATA="repodata" +REPOFILE="presto.xml" +REPOMDFILE="prestomd.xml" +SUM_TYPE="sha" + +def XML_start_newrpm(node, (f, n, e, v, r, a), srcdir_len): + newrpm_node = node.newChild(None, "package", None) + newrpm_node.newProp("type", "rpm") + newrpm_node.newChild(None, "name", n) + newrpm_node.newChild(None, "arch", str(a)) + version = newrpm_node.newChild(None, "version", None) + version.newProp("epoch", str(e)) + version.newProp("ver", str(v)) + version.newProp("rel", str(r)) + deltas = newrpm_node.newChild(None, "deltas", None) + return deltas + +def XML_oldrpm(newrpm_node, drpm_file, oldrpm, newrpm, sequence, size): + (f, n, e, v, r, a) = oldrpm + (nf, nn, ne, nv, nr, na) = newrpm + oldrpm_node = newrpm_node.newChild(None, "oldrpm", None) + checksum = getChecksum(SUM_TYPE, drpm_file) + if n != nn: + oldrpm_node.newChild(None, "name", n) + if a != na: + oldrpm_node.newChild(None, "arch", str(a)) + version = oldrpm_node.newChild(None, "version", None) + if e != ne: + version.newProp("epoch", str(e)) + if v != nv: + version.newProp("ver", str(v)) + version.newProp("rel", str(r)) + oldrpm_node.newChild(None, "drpm_filename", drpm_file) + oldrpm_node.newChild(None, "size", str(size)) + oldrpm_node.newChild(None, "sequence", str(sequence)) + cs_node = oldrpm_node.newChild(None, "checksum", str(checksum)) + cs_node.newProp("type", SUM_TYPE) + +def startXML(): + basedoc = libxml2.newDoc("1.0") + baseroot = basedoc.newChild(None, "metadata", None) + basens = baseroot.newNs('http://linux.duke.edu/metadata/common', None) + formatns = baseroot.newNs('http://linux.duke.edu/metadata/rpm', 'rpm') + baseroot.setNs(basens) + return (basedoc, baseroot) + +def endXML(xmldoc, filename, srcdir, compressed=True): + if compressed: + outfile = _gzipOpen("%s%s/%s.gz" % (srcdir, REPODATA, filename), "w") + output = xmldoc.serialize('UTF-8', 1) + outfile.write(output) + outfile.close() + else: + xmldoc.saveFormatFileEnc("%s%s/%s" % (srcdir, REPODATA, filename), 'UTF-8', 1) + xmldoc.freeDoc() + +def repoXML(srcdir): + """generate the repomd.xml file that stores the info on the other files""" + repodoc = libxml2.newDoc("1.0") + reporoot = repodoc.newChild(None, "repomd", None) + repons = reporoot.newNs('http://linux.duke.edu/metadata/repo', None) + reporoot.setNs(repons) + repofilepath = "%s%s/%s" % (srcdir, REPODATA, REPOMDFILE) + filename = "%s%s/%s.gz" % (srcdir, REPODATA, REPOFILE) + filetype = "deltas" + zfo = _gzipOpen(filename, "rb") + uncsum = getChecksum(SUM_TYPE, zfo) + zfo.close() + csum = getChecksum(SUM_TYPE, filename) + timestamp = os.stat(filename)[8] + data = reporoot.newChild(None, 'data', None) + data.newProp('type', filetype) + location = data.newChild(None, 'location', None) + location.newProp('href', "%s/%s.gz" % (REPODATA, REPOFILE)) + checksum = data.newChild(None, 'checksum', csum) + checksum.newProp('type', SUM_TYPE) + timestamp = data.newChild(None, 'timestamp', str(timestamp)) + unchecksum = data.newChild(None, 'open-checksum', uncsum) + unchecksum.newProp('type', SUM_TYPE) + endXML(repodoc, REPOMDFILE, srcdir, False) + +def genDeltaRPM(ts, newrpm, oldrpm, is_new_package, srcdir, dstdir, locroot): + (f1,n1,e1,v1,r1,a1) = newrpm + (f2,n2,e2,v2,r2,a2) = oldrpm + hdr = rpmUtils.miscutils.hdrFromPackage(ts,f1) + arch = hdr['arch'] + v12 = "_".join([v1,v2]) + r12 = "_".join([r1,r2]) + deltaRPMName= '%s/%s.%s.%s' % (dstdir, "-".join([n1,v12,r12]), a1, SUFFIX) + if DEBUG: + print "DEBUG " + deltaCommand + # If the drpm doesn't exists, make it, else skip it + if os.path.exists("%s%s" % (srcdir, deltaRPMName)): + dsize = os.path.getsize("%s%s" % (srcdir, deltaRPMName)) + if e1 == e2: + print 'Using pre-generated delta rpm for %s.%s - %s.%s => %s.%s' % (n1, a1, v2, r2, v1, r1) + else: + print 'Using pre-generated delta rpm for %s.%s - %s:%s.%s => %s:%s.%s' % (n1, a1, e2, v2, r2, e1, v1, r1) + # Get checksum + seqfile = open("%s%s.seq" % (srcdir, deltaRPMName), "r") + sequence = seqfile.read()[:-1] + sequence = sequence[sequence.rfind("-")+1:] + seqfile.close() + if is_new_package: + locroot = XML_start_newrpm(locroot, newrpm, len(srcdir)) + is_new_package = False + XML_oldrpm(locroot, deltaRPMName, oldrpm, newrpm, sequence, dsize) + if DEBUG: + print "DEBUG skipping %s" % (deltaRPMName) + elif os.path.exists("%s%s.dontdelta" % (srcdir, deltaRPMName)) or os.path.getsize(f1) > 70000000: + pass + else: + deltaCommand = 'makedeltarpm -s %s%s.seq %s %s %s%s' % (srcdir, deltaRPMName, f2, f1, srcdir, deltaRPMName) + (code, out) = commands.getstatusoutput(deltaCommand) + if code: + #raise Exception("genDeltaRPM: exitcode was %s - Reported Error: %s" % (code, out)) + print "Error genDeltaRPM for %s: exitcode was %s - Reported Error: %s" % (n1, code, out) + + # Get size + dsize = os.path.getsize("%s%s" % (srcdir, deltaRPMName)) + + # Get checksum + seqfile = open("%s%s.seq" % (srcdir, deltaRPMName), "r") + sequence = seqfile.read()[:-1] + sequence = sequence[sequence.rfind("-")+1:] + seqfile.close() + + # Check whether or not we should keep the drpm + if not drpmIsWorthKeeping(deltaRPMName, f1, srcdir): + if DEBUG: + print 'deleting %s' % (deltaRPMName) + try: + os.unlink("%s%s" % (srcdir, deltaRPMName)) + except Exception, e: + print "Error deleting deltarpm %s" % (deltaRPMName), str(e) + try: + os.unlink("%s%s.seq" % (srcdir, deltaRPMName)) + except Exception, e: + print "Error deleting checksum %s.seq" % (deltaRPMName), str(e) + f = open("%s%s.dontdelta" % (srcdir, deltaRPMName), "w") + f.close() + 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) + + if is_new_package: + locroot = XML_start_newrpm(locroot, newrpm, len(srcdir)) + is_new_package = False + XML_oldrpm(locroot, deltaRPMName, oldrpm, newrpm, sequence, dsize) + return (is_new_package, locroot) + +def drpmIsWorthKeeping(deltaRPMName, newrpm, srcdir): + newsize = os.path.getsize(newrpm) + drpmsize = os.path.getsize("%s%s" % (srcdir, deltaRPMName)) + # Delete the drpm if it's too large + if drpmsize > DRPMWORTHKEEPINGTHRESH * newsize: + return False + return True + +def createPrestoRepo(srcdir, dstdir): + ts = rpmUtils.transaction.initReadOnlyTransaction() + changed = False + + # Create list of .rpm files. + # We don't use "glob", so sub-directories are supported. + print 'Using source dir: %s' % srcdir + print 'Using destination dir: %s' % dstdir + if dstdir[-1] == "/": + dstdir = dstdir[:-1] + srcfiles = [] + for root, dirs, files in os.walk(srcdir): + for f in fnmatch.filter(files,'*.rpm'): + srcfiles.append(os.path.join(root,f)) + if not len(srcfiles): + print ' Nothing found.' + return changed + assert srcfiles[0].startswith(srcdir) + + # Check whether dstdir exists, and if it doesn't, create it + if not os.access(dstdir, os.F_OK): + os.makedirs(dstdir, 0755) + elif not os.access(dstdir, os.W_OK): + print 'ERROR: Unable to write to %s' % dstdir + sys.exit(1) + + # Check whether REPODATA exists, and if it doesn't, create it + if not os.access("%s%s" % (srcdir, REPODATA), os.F_OK): + os.makedirs("%s%s" % (srcdir, REPODATA), 0755) + elif not os.access(dstdir, os.W_OK): + print 'ERROR: Unable to write to %s' % REPODATA + sys.exit(1) + + # Create XML document +# xmldoc = libxml2.newDoc("1.0") +# xmlroot = xmldoc + (xmldoc, xmlroot) = startXML() + + # Create map: rpm %name -> list of tuples (filename,name,e,v,r) + newestsrcrpms = {} + for f in srcfiles: + hdr = rpmUtils.miscutils.hdrFromPackage(ts, f) + nm = hdr['name'] + "." + hdr['arch'] + n = hdr['name'] + a = hdr['arch'] + v = hdr['version'] + r = hdr['release'] + e = hdr['epoch'] + if e is None: + e = 0 + newestsrcrpms.setdefault(nm,[]) + newestsrcrpms[nm].append((f,n,e,v,r,a)) + + # Now purge old src.rpm unless their %name matches a white-list pattern. + for l in newestsrcrpms.itervalues(): + x = len(l) + + if x > 1: + def sortByEVR(fnevr1, fnevr2): + (f1,n1,e1,v1,r1,a1) = fnevr1 + (f2,n2,e2,v2,r2,a2) = fnevr2 + 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 + + l.sort(sortByEVR) # highest first in list + + # Generate delta rpm + is_new_package = True + locroot = xmlroot + for rpm in l[1:]: + (is_new_package, locroot) = genDeltaRPM(ts, l[0], rpm, is_new_package, srcdir, dstdir, locroot) + + if not len(srcfiles): + print 'WARNING: No .rpms left. Stopping here.' + return changed + + # Write out end of deltas.xml file + endXML(xmldoc, REPOFILE, srcdir, True) + repoXML(srcdir) + + # Examine binary repository directories and remove everything which + # is missing its corresponding src.rpm. + return changed + + +def main(bin_rpm_path, delta_rpm_path): + assert rpmUtils.miscutils.compareEVR((1,2,3),(1,2,0)) > 0 + assert rpmUtils.miscutils.compareEVR((0,1,2),(0,1,2)) == 0 + assert rpmUtils.miscutils.compareEVR((1,2,3),(4,0,99)) < 0 + + return createPrestoRepo(bin_rpm_path, delta_rpm_path) + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print 'Usage: %s <bin_rpm_dir> <delta_rpm_dir> \n' % os.path.basename(sys.argv[0]) + sys.exit(errno.EINVAL) + bin_rpm_path = sys.argv[1] + delta_rpm_path = sys.argv[2] + + #### cfg = Utils.load_config_module(sys.argv[1]) + + #### Utils.signer_gid_check(cfg.signersgid) + #### os.umask(cfg.signersumask) + + #### for dist in sys.argv[2:]: + #### if not cfg.archdict.has_key(dist): + #### print "No distribution release named '%s' found" % dist + #### sys.exit(errno.EINVAL) + main(bin_rpm_path, delta_rpm_path) + sys.exit(0) |