#!/usr/bin/python # # checkupdates.py -- Compares Red Hat tree to updates directory and lists # availible updates. # Copyright (C) 2002 Jack Neely # # 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 os import os.path import rpm import sys import getopt verbose = 0 def usage(): print "Usage:" + sys.argv[0] + "-v ver -r arch [listofrpms]" print " Required arguments:" print " -v, --ver [version of distro]" print " -r, --arch [architecture of distro]" print " -e, --tree [where the top of the tree is]" print " -u, --updates [path to update directory]" print print " Optional arguments:" print " -V, --verbose\tVerbose mode" print " -h, --help\t\tPrint this message" print sys.exit(1) def log(mess): global verbose if verbose: print mess def getHeader(filename): fd = os.open(filename, os.O_RDONLY) header, isSource = rpm.headerFromPackage(fd) os.close(fd) return (header, isSource) # sanity checks on the list list. Can preppend root to aid in # absolute path resolving. # Make damn sure this looks like an RPM.... def checkFiles(filelist, rt=""): files = [] for file in filelist: path = os.path.abspath(os.path.join(rt,file)) log(path) if not os.access(path, os.R_OK): print "Could not access %s" % file sys.exit(1) root, ext = os.path.splitext(path) if ext == ".rpm": files.append(path) return files # Returns a dict indexed by filename as given in the rpmlist list def getDictByFile(rpmlist): headers = {} for file in rpmlist: header, isSource = getHeader(file) if isSource: print "What are you thinking? %s is a source RPM!" % file sys.exit(1) headers[file] = header return headers # Returns a dict indexed by package name. # The dict contains a tuple of (header, filename) def getDictByName(rpmlist): headers = {} for file in rpmlist: header, isSource = getHeader(file) name = header[rpm.RPMTAG_NAME] arch = header[rpm.RPMTAG_ARCH] if isSource: print "What are you thinking? %s is a source RPM!" % file sys.exit(1) headers[(name,arch)] = (header, file) return headers # Do the header compares. Return a tuple of (newer_package_dict, missing_package_dict) def compareUpdates(headers, updateheaders): """We do the compares here and return a dict key'd on package name of packages that are newer then what is in the tree""" missing = {} newer = {} for k in updateheaders.keys(): package, arch = k log("Working on package " + package) h = updateheaders[k] if headers.has_key(k): ret = rpm.versionCompare(headers[k][0], h[0]) if ret == 1: print "Warning: Update for %s is older than package in install tree" % package log("Updated package %s is older. Not doing anyhting" % package) elif ret == 0: log("%s is the same as package in install tree." % package) elif ret == -1: log("%s in updates directory is newer. Will return in dict." % package) newer[k] = h else: log("%s is not present in install tree." % package) missing[k] = h log("Done comparing packages.") return (newer, missing) def main(): """This program will scan a directory of updates, such as the Red Hat updates directory on a Red Hat FTP mirror and print out all RPMS that have not been applied to the specified tree.""" args = sys.argv[1:] global verbose try: optlist, rpmlist = getopt.getopt(args, 'hVv:r:u:e:', ['help', 'verbose', 'ver=', 'arch=', 'updates=', 'tree=']) except getopt.error: usage() archarg=0 verarg=0 treearg=0 updatesarg=0 trees="/tmp/dumb" updates="/other/path" for o, a in optlist: if o in ("--help", "-h"): usage() if o in ("--verbose", "-V"): verbose = 1 if o in ("--ver", "-v"): version = a verarg = 1 if o in ("--arch", "-r"): arch = a archarg = 1 if o in ("--tree", "-e"): trees = a treearg = 1 if o in ("--updates", "-u"): updates = a updatesarg = 1 if archarg+verarg+treearg+updatesarg != 4: print "Not enough or bad arguments." usage() installtree = os.path.abspath(os.path.join(trees, version, arch, "RedHat/RPMS")) log("installtree = " + installtree) updates = os.path.abspath(updates) log("updates directory = " + updates) if not os.path.exists(installtree): print "ERROR: Where's your install tree again?" print "%s does not exist." % installtree sys.exit(1) if not os.path.exists(updates): print "ERROR: Where's your updates directory?" print "%s does not exist." % updates sys.exit(1) log("Checking Files...") installrpms = checkFiles(os.listdir(installtree), installtree) updaterpms = checkFiles(os.listdir(updates), updates) log("Getting RPM Headers...") installheaders = getDictByName(installrpms) updateheaders = getDictByName(updaterpms) new, missing = compareUpdates(installheaders, updateheaders) print "New Packages: " + str(new.keys()) print print "Missing Packages: " + str(missing.keys()) print "Done!" if __name__ == "__main__": main()