diff options
Diffstat (limited to 'presto-utils/gendeltarpms.py')
-rwxr-xr-x | presto-utils/gendeltarpms.py | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/presto-utils/gendeltarpms.py b/presto-utils/gendeltarpms.py new file mode 100755 index 0000000..7db9d4f --- /dev/null +++ b/presto-utils/gendeltarpms.py @@ -0,0 +1,324 @@ +#!/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 +import fnmatch, re +import rpmUtils.transaction, rpmUtils.miscutils +import commands +import string +import getopt +from dumpMetadata import byteranges +from packagelist import RpmItem, DrpmItem, PackageList + +import gzip +from zlib import error as zlibError +from gzip import write32u, FNAME + +DRPMWORTHKEEPINGTHRESH=0.5 +DEBUG=0 +__version__ = "0.2.0" + +def errorprint(stuff): + print >> sys.stderr, stuff + +def _(args): + """Stub function for translation""" + return args + +def usage(retval=1): + print _(""" + createdeltarpms [options] directory-of-packages directory-of-deltarpms + + Options: + -d, --dist-update <dir> = optional directory containing old distribution + to create an update from + -c, --count <number> = optional maximum number of deltarpms to create + per package. Default is maximum available + -n, --no-first = Don't create deltarpm against first rpm if number exceeds + count. Useful if you are running a continually-updated + distribution rather than one with set release cycles. + -q, --quiet = run quietly + -v, --verbose = run verbosely + -h, --help = show this help + -V, --version = output version + """) + + sys.exit(retval) + +def getDeltaNevr(filename): + """Get nevr for src rpm of a deltarpm. Return a tuple of (n, e, v, r)""" + def _getLength(in_data): + length = 0 + for val in in_data: + length = length * 256 + length += ord(val) + return length + + def _stringToVersion(strng): + i = strng.find(':') + if i != -1: + epoch = strng[:i] + else: + epoch = '0' + j = strng.find('-') + if j != -1: + if strng[i + 1:j] == '': + version = None + else: + version = strng[i + 1:j] + release = strng[j + 1:] + else: + if strng[i + 1:] == '': + version = None + else: + version = strng[i + 1:] + release = None + return (epoch, version, release) + + def _stringToNEVR(string): + i = string.rfind("-", 0, string.rfind("-")-1) + name = string[:i] + (epoch, ver, rel) = _stringToVersion(string[i+1:]) + return (name, epoch, ver, rel) + + (range_start, range_end) = byteranges(filename) + fd = open(filename, "r") + fd.seek(range_end) + try: + compobj = gzip.GzipFile("", "rb", 9, fd) + except: + raise zlibError("Data not stored in gzip format") + + if compobj.read(4)[:3] != "DLT": + raise Exception("Not a deltarpm") + + nevr_length = _getLength(compobj.read(4)) + nevr = compobj.read(nevr_length).strip("\x00") + oldnevr = _stringToNEVR(nevr) + compobj.close() + return oldnevr + + +def getFileList(path, ext, filelist): + """Return all files in path matching ext, store them in filelist, + recurse dirs. Returns a list object""" + + extlen = len(ext) + totalpath = os.path.normpath(path) + dir_list = os.listdir(totalpath) + + for d in dir_list: + if os.path.isdir(totalpath + '/' + d): + filelist = getFileList(os.path.join(totalpath, d), ext, filelist) + elif string.lower(d[-extlen:]) == '%s' % (ext): + filelist.append(os.path.join(totalpath, d)) + + return filelist + +def createPrestoRepo(base_dir, drpm_dir, dst_dir=None, DrpmsPerPackage=0, DoFirst=True): + ts = rpmUtils.transaction.initReadOnlyTransaction() + changed = False + + # Create list of .rpm files. + # We don't use "glob", so sub-directories are supported. + print 'Using base dir: %s' % base_dir + print 'Using destination dir: %s' % drpm_dir + + try: + rpm_files = getFileList(base_dir, ".rpm", []) + except OSError, e: + errorprint(_("Error: Unable to find directory %s: %s" % (base_dir, e))) + return False + if dst_dir != None: + try: + dst_rpm_files = getFileList(dst_dir, ".rpm", []) + except OSError, e: + errorprint(_("Error: Unable to find directory %s: %s" % (dst_dir, e))) + return False + try: + drpm_files = getFileList(drpm_dir, ".drpm", []) + except: + drpm_files = [] + if not len(rpm_files): + print ' Nothing found.' + return changed + + if dst_dir != None and not len(dst_rpm_files): + print ' No new rpms found.' + return changed + + # Check whether rel_dir exists, and if it doesn't, create it + if not os.access(drpm_dir, os.F_OK): + os.makedirs(drpm_dir, 0755) + elif not os.access(drpm_dir, os.W_OK): + print 'ERROR: Unable to write to %s' % drpm_dir + sys.exit(1) + + # Add all rpms to PackageList + rpm_list = PackageList(base_dir, drpm_dir, DRPMWORTHKEEPINGTHRESH, DEBUG) + for f in rpm_files: + try: + hdr = rpmUtils.miscutils.hdrFromPackage(ts, f) + except: + print "Unable to open %s" % f + else: + nm = hdr['name'] + "." + hdr['arch'] + e = hdr['epoch'] + if e is None: + e = "0" + + nevra = (hdr['name'], e, hdr['version'], hdr['release'], hdr['arch']) + rpm = RpmItem(nevra, f) + rpm_list.addRpm(rpm) + + # If we have a new distro, add its rpms with epoch bumped +5 + if dst_dir != None: + for f in dst_rpm_files: + try: + hdr = rpmUtils.miscutils.hdrFromPackage(ts, f) + except: + print "Unable to open %s" % f + else: + nm = hdr['name'] + "." + hdr['arch'] + e = hdr['epoch'] + if e is None: + e = "0" + e = str(int(e) + 5) + + nevra = (hdr['name'], e, hdr['version'], hdr['release'], hdr['arch']) + rpm = RpmItem(nevra, f) + rpm_list.addRpm(rpm) + + # Add all deltarpms to PackageList + for f in drpm_files: + try: + hdr = rpmUtils.miscutils.hdrFromPackage(ts, f) + except: + print "Unable to open %s" % f + else: + (sn, se, sv, sr) = getDeltaNevr(f) + + nm = hdr['name'] + "." + hdr['arch'] + e = hdr['epoch'] + if e is None: + e = "0" + + dst_nevra = (hdr['name'], e, hdr['version'], hdr['release'], hdr['arch']) + src_nevra = (sn, se, sv, sr, hdr['arch']) + drpm = DrpmItem(src_nevra, dst_nevra, f) + rpm_list.addDrpm(drpm) + + if DEBUG: + rpm_list.dump() + + # Build deltarpms + rpm_list.makeDeltaRpms(DrpmsPerPackage, DoFirst) + return True + +def parseArgs(args): + """ + Parse the command line args return a commands dict and directory. + Sanity check all the things being passed in. + """ + cmds = {} + cmds['quiet'] = 0 + cmds['verbose'] = 0 + cmds['dist-update'] = None + cmds['count'] = None + cmds['do-first'] = 1 + try: + gopts, argsleft = getopt.getopt(args, 'hqvVd:c:n', ['help', 'quiet', 'verbose', 'version', 'dist-update=', 'count=', 'no-first']) + except getopt.error, e: + errorprint(_('Options Error: %s.') % e) + usage() + + try: + for arg,a in gopts: + if arg in ['-h','--help']: + usage(retval=0) + elif arg in ['-V', '--version']: + print '%s' % __version__ + sys.exit(0) + except ValueError, e: + errorprint(_('Options Error: %s') % e) + usage() + + + # make sure our dir makes sense before we continue + if len(argsleft) > 2: + errorprint(_('Error: You may only specify one rpm directory and one deltarpm directory.')) + usage() + elif len(argsleft) == 0: + errorprint(_('Error: Must specify an rpm directory to index and a destination deltarpm directory.')) + usage() + else: + directories = argsleft + + try: + for arg,a in gopts: + if arg in ['-v', '--verbose']: + cmds['verbose'] = 1 + elif arg in ["-q", '--quiet']: + cmds['quiet'] = 1 + elif arg in ["-n", '--no-first']: + cmds['do-first'] = 0 + elif arg in ['-d', '--dist-update']: + if cmds['dist-update'] is not None: + errorprint(_('Error: Only one directory for distribution updates allowed.')) + usage() + else: + cmds['dist-update'] = a + elif arg in ['-c', '--count']: + if cmds['count'] is not None: + errorprint(_('Error: Only one count allowed.')) + usage() + else: + cmds['count'] = int(a) + + except ValueError, e: + errorprint(_('Options Error: %s') % e) + usage() + + rpm_directory = directories[0] + drpm_directory = directories[1] + + rpm_directory = os.path.normpath(rpm_directory) + drpm_directory = os.path.normpath(drpm_directory) + + # Fixup first directory + directories[0] = rpm_directory + directories[1] = drpm_directory + + # Set count + if cmds['count'] == None: + cmds['count'] = 0 + + return cmds, directories + +if __name__ == '__main__': + cmds, directories = parseArgs(sys.argv[1:]) + if cmds['dist-update'] != None: + if createPrestoRepo(cmds['dist-update'], directories[1], directories[0], cmds['count'], cmds['do-first']): + sys.exit(0) + else: + sys.exit(1) + else: + if createPrestoRepo(directories[0], directories[1], None, cmds['count'], cmds['do-first']): + sys.exit(0) + else: + sys.exit(1) + |