#!/usr/bin/python # yum-arch -- Creates YUM distribution databases # # 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 Library 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 sys import os import rpm import rpmUtils.oldUtils import rpmUtils.miscutils import rpm import string import types import getopt import fnmatch import logging sys.path.insert(1,'/usr/share/yum-cli') from i18n import _ log=logging.getLogger("yum-arch").log #serverStuff.log = log #rpmUtils.oldUtils.log = log #rpmUtils.oldUtils.errorlog = log ts = rpmUtils.oldUtils.Rpm_Ts_Work() rpmUtils.ts = ts rpmUtils.oldUtils.ts = ts ## From serverStuff.py def getfilelist(path, ext, list, usesymlinks): # get all the files matching the 3 letter extension that is ext in path, recursively # store them in append them to list # return list # ignore symlinks unless told otherwise try: dir_list = os.listdir(path) except OSError, e: log(0, 'Error accessing directory %s, %s' % (path, e)) sys.exit(1) for d in dir_list: if os.path.isdir(path + '/' + d): list = getfilelist(path + '/' + d, ext, list, usesymlinks) else: if string.lower(d[-4:]) == '%s' % (ext): if usesymlinks: newpath = os.path.normpath(path + '/' + d) list.append(newpath) else: if not os.path.islink( path + '/' + d): newpath = os.path.normpath(path + '/' + d) list.append(newpath) return(list) def Usage(): print _("""Usage: yum-arch [options] (path of dir where headers/ should/does live) options are: -d = check dependencies and conflicts in tree -v = more verbose output -vv = even more verbose output -n = don't generate headers -c = check pkgs with gpg and md5 checksums - cannot be used with -n -z = gzip compress the headers (default, deprecated as an option) -s = generate headers for source packages too -l = use symlinks as valid rpms when building headers -x, --exclude = wildcards to exclude from processing -q = make the display more quiet -h, --help = this screen""") sys.exit(1) def depchecktree(rpmlist): _ts = rpm.TransactionSet() _ts.closeDB() error=0 msgs=[] currpm=0 numrpms=len(rpmlist) log(1, "Checking dependencies") for rpmfn in rpmlist: currpm=currpm + 1 log(2, _("Checking deps %d/%d complete") %(currpm, numrpms)) hobj = rpmUtils.oldUtils.RPM_Work(rpmfn) if hobj.hdr == None: log(1, _("ignoring bad rpm: %s") % rpmfn) elif hobj.isSource(): log(2, _("ignoring srpm: %s") % rpmfn) else: _ts.addInstall(hobj.hdr, hobj.name(), 'i') log(3, _("adding %s") % hobj.name()) errors = _ts.check() if errors: print _('errors found') for ((name, version, release), (reqname, reqversion), \ flags, suggest, sense) in errors: if sense==rpm.RPMDEP_SENSE_REQUIRES: error=1 msgs.append(_("depcheck: package %s needs %s") % ( name, rpmUtils.miscutils.formatRequire(reqname, reqversion, flags))) elif sense==rpm.RPMDEP_SENSE_CONFLICTS: error=1 msgs.append(_("depcheck: package %s conflicts with %s") % (name, reqname)) print "" return (error,msgs) ## from pullheaders.py def argParse(args): """get arguments from command line, return a nice dict of cmds=args + left over args""" if len(args) == 0: Usage() cmds = {} cmds['checkdeps'] = 0 cmds['writehdrs'] = 1 cmds['rpmcheck'] = 0 cmds['compress'] = 1 cmds['usesymlinks'] = 0 cmds['dosrpms'] = 0 cmds['quiet'] = 0 cmds['loud'] = 0 cmds['exclude'] = [] try: gopts, args = getopt.getopt(args, 'vv:qdncszlhx:', ['help', 'exclude']) except getopt.error, e: log(0, _('Options Error: %s') % e) Usage() try: for arg,a in gopts: if arg in ['-h','--help']: Usage() elif arg == '-v': if cmds['loud'] == 1: log.threshold = 4 else: cmds['loud'] = 1 elif arg == '-d': cmds['checkdeps'] = 1 elif arg == '-n': cmds['writehdrs'] = 0 elif arg == '-c': cmds['rpmcheck'] = 1 elif arg == "-z": cmds['compress'] = 1 elif arg == "-l": cmds['usesymlinks'] = 1 elif arg == "-s": cmds['dosrpms'] = 1 elif arg == "-q": cmds['quiet'] = 1 log.threshold = 1 elif arg in ['-x', '--exclude']: cmds['exclude'].append(a) except ValueError, e: log(0, _('Options Error: %s') % e) Usage() if type(args) is types.ListType: if len(args) == 0: Usage() else: basedir = args[0] else: basedir = args return (cmds, basedir) def trimRpms(rpms, excludeGlobs): log(4, _('Pre-Trim Len: %d') % len(rpms)) badrpms = [] for file in rpms: for glob in excludeGlobs: if fnmatch.fnmatch(file, glob): log(4, _('excluded: %s') % file) if file not in badrpms: badrpms.append(file) for file in badrpms: if file in rpms: rpms.remove(file) log(4, _('Post-Trim Len: %d') % len(rpms)) return rpms def main(args): log(0, '\n\n\nTHIS PROGRAM IS DEPRECATED!') log(0, 'You should be generating xml metadata instead.') log(0, 'Please see http://linux.duke.edu/metadata\n\n\n') tempheaderdir = '.newheaders' tempheaderinfo = tempheaderdir + '/' + 'header.info' tempsrcheaderinfo = tempheaderdir + '/' + 'header.src.info' oldheaderdir = '.oldheaders' oldheaderinfo = oldheaderdir + '/' + 'header.info' oldsrcheaderinfo = oldheaderdir + '/' + 'header.src.info' headerdir = 'headers' headerinfo = headerdir + '/' + 'header.info' srcheaderinfo = headerdir + '/' + 'header.src.info' # parse our args (cmds, basedir) = argParse(args) # save where we are right now curdir = os.getcwd() # start the sanity/stupidity checks if not os.path.exists(basedir): print _("Directory of rpms must exist") Usage() if not os.path.isdir(basedir): print _("Directory of rpms must be a directory.") sys.exit(1) # change to the basedir to work from w/i the path - for relative url paths os.chdir(basedir) # get the list of rpms rpms=getfilelist('./', '.rpm', [], cmds['usesymlinks']) if len(cmds['exclude']) > 0: rpms = trimRpms(rpms, cmds['exclude']) # some quick checks - we know we don't have ANY rpms - so, umm what do we # do? - if we have a headers dir then maybe we already had some and its # a now-empty repo - well, lets clean it up # If nothing there, create an empty repository and make a warning. # kill the hdrs, kill the header.info - write an empty one if len(rpms) == 0: if not os.path.exists(headerdir): print >> sys.stderr, _('No rpms to work with and no header dir. Creating an empty repository.') os.makedirs(headerdir) hdrlist = getfilelist(headerdir, '.hdr', [], 0) removeCurrentHeaders(hdrlist) if cmds['dosrpms']: removeHeaderInfo(srcheaderinfo) srcheaderfd = open(srcheaderinfo, "w") srcheaderfd.close() removeHeaderInfo(headerinfo) headerfd = open(headerinfo, "w") headerfd.close() sys.exit(0) # depcheck if requested if cmds['checkdeps']: (error, msgs) = depchecktree(rpms) if error == 1: print _("Errors within the dir(s):\n %s") % basedir for msg in msgs: print _(" ") + msg sys.exit(1) else: print _("All dependencies resolved and no conflicts detected") if cmds['writehdrs']: # this should flow like this: # make sure the tempheaderdir is made, etc # check on the headerdir too # make the newheaders and header.info in tempheaderdir # mv the headers dir to .oldheaders # mv .newheaders to headers # clean out the old .hdrs # remove the .oldheaders/header.info # remove the .oldheaders dir # if the headerdir exists and its a file then we're in deep crap if not checkandMakeDir(headerdir): sys.exit(1) if not checkandMakeDir(tempheaderdir): sys.exit(1) # generate the new headers rpminfo = genhdrs(rpms, tempheaderdir, cmds) # Write header.info file if not cmds['quiet']: print _("\nWriting header.info file") headerfd = open(tempheaderinfo, "w") if cmds['dosrpms']: srcheaderfd = open(tempsrcheaderinfo, "w") for item in rpminfo.keys(): (name,epoch, ver, rel, arch, source) = item rpmloc = rpminfo[item] if source: info = "%s:%s-%s-%s.src=%s\n" % (epoch, name, ver, rel, rpmloc) srcheaderfd.write(info) else: info = "%s:%s-%s-%s.%s=%s\n" % (epoch, name, ver, rel, arch, rpmloc) headerfd.write(info) if cmds['dosrpms']: srcheaderfd.close() headerfd.close() try: os.rename(headerdir, oldheaderdir) except OSError, e: print _("Error moving %s to %s, fatal") % (headerdir, oldheaderdir) sys.exit(1) try: os.rename(tempheaderdir, headerdir) except OSError, e: print _("Error moving %s to %s, fatal") % (headerdir, oldheaderdir) # put the old dir back, don't leave everything broken print _("Putting back old headers") os.rename(oldheaderdir, headerdir) sys.exit(1) # looks for a list of .hdr files and the header.info file hdrlist = getfilelist(oldheaderdir, '.hdr', [], 0) removeCurrentHeaders(hdrlist) removeHeaderInfo(oldheaderinfo) removeHeaderInfo(oldsrcheaderinfo) os.rmdir(oldheaderdir) # take us home mr. data os.chdir(curdir) def checkandMakeDir(dir): """check out the dir and make it, if possible, return 1 if done, else return 0""" if os.path.exists(dir): if not os.path.isdir(dir): print _("%s is not a dir") % dir result = 0 else: if not os.access(dir, os.W_OK): print _("%s is not writable") % dir result = 0 else: result = 1 else: try: os.mkdir(dir) except OSError, e: print _('Error creating dir %s: %s') % (dir, e) result = 0 else: result = 1 return result def removeCurrentHeaders(hdrlist): """remove the headers before building the new ones""" for hdr in hdrlist: if os.path.exists(hdr): try: os.unlink(hdr) except OSError, e: print _('Cannot delete file %s') % hdr else: print _('Odd header %s suddenly disappeared') % hdr def removeHeaderInfo(headerinfo): """remove header.info file""" if os.path.exists(headerinfo): try: os.unlink(headerinfo) except OSError, e: print _('Cannot delete %s - check perms') % headerinfo def genhdrs(rpms,headerdir,cmds): """ Take a list of rpms, a place to put the headers and a config dictionary. outputs .hdr files and returns a dict containing all the header entries. """ rpminfo = {} numrpms = len(rpms) goodrpm = 0 currpm = 0 srpms = 0 for rpmfn in rpms: rpmname = os.path.basename(rpmfn) currpm=currpm + 1 percent = (currpm*100)/numrpms if not cmds['quiet']: if cmds['loud']: print _('Digesting rpm - %s - %d/%d') % (rpmname, currpm, numrpms) else: sys.stdout.write('\r' + ' ' * 80) sys.stdout.write("\rDigesting rpms %d %% complete: %s" % (percent, rpmname)) sys.stdout.flush() if cmds['rpmcheck']: log(2,_("\nChecking sig on %s") % rpmname) if rpmUtils.oldUtils.checkSig(rpmfn) > 0: log(0, _("\n\nProblem with gpg sig or md5sum on %s\n\n") % rpmfn) sys.exit(1) hobj = rpmUtils.oldUtils.RPM_Work(rpmfn) if hobj.hdr is None: log(1, _("\nignoring bad rpm: %s") % rpmfn) else: (name, epoch, ver, rel, arch) = hobj.nevra() if hobj.isSource(): if not cmds['dosrpms']: if cmds['loud']: print _("\nignoring srpm: %s") % rpmfn continue if epoch is None: epoch = '0' rpmloc = rpmfn rpmstat = os.stat(rpmfn) rpmmtime = rpmstat[-2] rpmatime = rpmstat[-3] rpmtup = (name, epoch, ver, rel, arch, hobj.isSource()) # do we already have this name.arch tuple in the dict? if rpminfo.has_key(rpmtup): log(2, _("\nAlready found tuple: %s %s:\n%s ") % (name, arch, rpmfn)) headerloc = hobj.writeHeader(headerdir, cmds['compress']) os.utime(headerloc, (rpmatime, rpmmtime)) if hobj.isSource(): srpms = srpms + 1 rpminfo[rpmtup]=rpmloc goodrpm = goodrpm + 1 if not cmds['quiet']: print _("\n Total: %d\n Used: %d\n Src: %d") %(numrpms, goodrpm, srpms) return rpminfo if __name__ == "__main__": main(sys.argv[1:])