#!/usr/bin/python ############################################################################### # purge-old-rpms.py 1.0 # # Purges old RPM packages from given directories. # # http://juliano.info/en/Projects/Purge_old_RPMs # ############################################################################### # Author: Juliano F. Ravasi < dev at juliano info > # # Version: 1.0 (Sep 8, 2007) # # Language: Python 2.5 # # License: GNU General Public License v3 # ############################################################################### ############################################################################### # Copyright (C) 2007 - Juliano F. Ravasi # ############################################################################### # # # 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 3 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, see . # # # ############################################################################### import sys, os, re from dircache import listdir from fnmatch import fnmatch from distutils import version from optparse import OptionParser rpm_re = re.compile('([\\w_.-]+?)-(\\d[\\w.]*)-(\\d[\\w.]*?)\\.([\\w_]+)\\.rpm'); ## "kernel-devel- 2.6.22.4 - 65.fc7 . i686 .rpm" ## |-----1----| |----2-----| |-----3-----| |---4---| def main(argv): parser = OptionParser(usage="Usage: %prog [options] directory...", version="%prog 1.0"); parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="make output verbose") parser.add_option("-n", "--dry-run", action="store_true", dest="dryrun", help="don't actually delete anything") (options, args) = parser.parse_args(argv[1:]) discard = [] for arg in args: path = os.path.realpath(arg) if not os.access(path, os.W_OK) and not options.dryrun: raise IOError("Write access denied to %s." % (path)) if options.verbose: print "Processing directory %s..." % (path) packages = {} files = listdir(path) for f in files: if not fnmatch(f, "*.rpm"): continue; m = rpm_re.match(f) if m: pfile = m.group(0) pname = m.group(1) pversion = m.group(2) prelease = m.group(3) parch = m.group(4) if not packages.has_key(pname): packages[pname] = [] packages[pname].append({ 'version': pversion, 'release': prelease, 'arch': parch, 'file': pfile}) else: print "File '%s' doesn't match regular expression." % f names = packages.keys() names.sort() for name in names: if options.verbose: print " Processing package '%s'..." % (name), ps = packages[name] if len(ps) < 2: if options.verbose: print "single version found, skipping." continue try: for p in ps: p['lver'] = version.StrictVersion(p['version']) except: for p in ps: p['lver'] = version.LooseVersion(p['version']) try: for p in ps: p['lrel'] = version.StrictVersion(p['release']) except: for p in ps: p['lrel'] = version.LooseVersion(p['release']) latest = None for p in ps: if not latest or p['lver'] > latest['lver'] or (p['lver'] == latest['lver'] and p['lrel'] > latest['lrel']): latest = p obsolete = [x for x in ps if x != latest] if options.verbose: print "latest: %s-%s" % (latest['version'], latest['release']) for ob in obsolete: print " ..obsolete:", ob['file'] discard += [path + os.path.sep + ob['file'] for ob in obsolete] if len(discard) > 0: print "Removing obsolete packages..." for fl in discard: print " Removing '%s'." % (fl) if not options.dryrun: os.unlink(fl) else: print "Nothing to remove." if __name__ == "__main__": main(sys.argv)