summaryrefslogtreecommitdiffstats
path: root/presto-utils/gendeltarpms.py
diff options
context:
space:
mode:
Diffstat (limited to 'presto-utils/gendeltarpms.py')
-rwxr-xr-xpresto-utils/gendeltarpms.py324
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)
+