Jeff Spaleta (jspaleta@xxxxxxxxx) said: > Is the script that generates that report open for review and patching? > 'someone' might be able to patch the script to produce a common block > of dep problems to bloat if this approach is worth attempting. I'd suspect the initial problem with coalescing them is that the deps can be different per-arch (64bit or not). Bill
#!/usr/bin/python import os from stat import * import sys import tempfile import pwd import re import string import glob import yum from yum.constants import * sys.path.append("/usr/bin/") import repoclosure arches = [] owners = {} deps = {} dbh = None cspec = None tmpdir = '/var/tmp' def generateConfig(theDir): for entry in os.listdir(theDir): try: if 'repodata' in os.listdir("%s/%s" % (theDir,entry)): arches.append(entry) except: pass try: (fd, conffile) = tempfile.mkstemp() except: conffile = tempfile.mktemp() fd = os.open(conffile,os.O_RDWR|os.O_CREAT) confheader = """ [main] cachedir=/var/cache/yum debuglevel=2 logfile=/var/log/yum.log pkgpolicy=newest distroverpkg=fedora-release reposdir=/dev/null """ os.write(fd,confheader) for arch in arches: repo = """ [development-%s] name=Fedora Core Development Tree - %s baseurl=file://%s/%s enabled=1 """ % (arch, arch, theDir, arch) os.write(fd,repo) os.close(fd) return conffile def libmunge(match): if match.groups()[1].isdigit(): return "%s%d" % (match.groups()[0],int(match.groups()[1])+1) else: return "%s%s" % (match.groups()[0],match.groups()[1]) def getCacheDir(): uid = os.geteuid() try: usertup = pwd.getpwuid(uid) username = usertup[0] except KeyError: return None # if it returns None then, well, it's bollocksed prefix = 'yum-%s-' % username dirpath = '%s/%s*' % (tmpdir, prefix) cachedirs = glob.glob(dirpath) for thisdir in cachedirs: # if one exists take the first one # check if it is: # 0. is a dir if not os.path.isdir(thisdir): continue stats = os.stat(thisdir) # 1. owned by the user if stats[4] != uid: continue # 2. 0700 if S_IMODE(stats[0]) != 448: continue # it made it through the gauntlet! return thisdir if 'mkdtemp' in dir(tempfile): cachedir = tempfile.mkdtemp(prefix=prefix, dir=tmpdir) else: tempfile.tempdir = tmpdir tempfile.template = prefix cachedir = tempfile.mktemp() try: os.mkdir(cachedir,0700) except: cachedir = None return cachedir def addOwner(list, pkg): if list.has_key(pkg): return True f = getOwner(pkg) if f: list[pkg] = f return True return False def getSrcPkg(pkg): srpm = pkg.returnSimple('sourcerpm') if not srpm: return None srcpkg = string.join(srpm.split('-')[:-2],'-') return srcpkg def printableReq(pkg, dep): (n, f, v) = dep req = '%s' % n if f: flag = LETTERFLAGS[f] req = '%s %s' % (req, flag) if v: req = '%s %s' % (req, v) return "%s requires %s" % (pkg, req,) def assignBlame(resolver, dep, guilty): # Given a dep, find potential responsible parties list = [] # The dep itself if addOwner(guilty, dep): list.append(dep) # Something that provides the dep try: sack = resolver.whatProvides(dep, None, None) for package in sack.returnPackages(): p = getSrcPkg(package) if addOwner(guilty, p): list.append(p) except yum.Errors.RepoError, e: pass # Libraries: check for variant in soname if re.match("lib*\.so\.[0-9]+",dep): new = re.sub("(lib.*\.so\.)([0-9])+",libmunge,1) try: sack = resolver.whatProvides(new, None, None) for package in sack.returnPackages(): p = getSrcPkg(package) if addOwner(guilty, p): list.append(p) except yum.Errors.RepoError, e: pass return list def generateSpam(pkgname, sendmail = True): package = deps[pkgname] guilty = owners[pkgname] conspirators = [] for s in package.keys(): subpackage = package[s] for arch in subpackage.keys(): brokendeps = subpackage[arch] for dep in brokendeps: for blame in dep[2]: party = owners[blame] if party != guilty and party not in conspirators: conspirators.append(party) foo = """ %s has broken dependencies in the development tree: """ % (pkgname,) for s in package.keys(): subpackage = package[s] for arch in subpackage.keys(): foo = foo + "On %s:\n" % (arch) brokendeps = subpackage[arch] for dep in brokendeps: foo = foo + "\t%s\n" % printableReq(dep[0],dep[1]) foo = foo + "Please resolve this as soon as possible.\n\n" command = '/bin/mail -s "Broken dependencies: %s" %s' % (pkgname, guilty) if conspirators: command = command + " -c %s" % (string.join(conspirators,","),) if sendmail: mailer = os.popen(command, 'w') mailer.write(foo) mailer.close() else: print """ To: %s Cc: %s Subject: Broken dependencies: %s """ % (guilty, string.join(conspirators,','), pkgname) print foo def doit(args): conffile = generateConfig(args[0]) mail = True if len(args) > 1: mail = False cachedir = getCacheDir() for arch in arches: if arch == 'i386': carch = 'i686' else: carch = arch repoid = 'development-%s' % (arch,) my = repoclosure.RepoClosure(config = conffile, arch = carch) for repo in my.repos.repos.values(): repo.cachedir = '%s/%s' % (cachedir,repo.id) repo.hdrdir = '%s/%s/headers' % (cachedir, repo.id) repo.pkgdir = '%s/%s/packages' % (cachedir, repo.id) if repo.id != repoid: repo.disable() else: repo.enable() my.readMetadata() baddeps = my.getBrokenDeps() pkgs = baddeps.keys() pkgs.sort() if len(pkgs) > 0: print "Broken deps for %s" % (arch,) print "----------------------------------------------------------" for pkg in pkgs: srcpkg = getSrcPkg(pkg) addOwner(owners, srcpkg) if not deps.has_key(srcpkg): deps[srcpkg] = {} pkgid = pkg.returnNevraPrintable() if not deps[srcpkg].has_key(pkgid): deps[srcpkg][pkgid] = {} broken = [] for (n, f, v) in baddeps[pkg]: print "\t%s" % printableReq(pkg, (n, f, v)) blamelist = assignBlame(my, n, owners) broken.append( (pkg, (n, f, v), blamelist) ) deps[srcpkg][pkgid][arch] = broken print "\n\n" pkglist = deps.keys() for pkg in pkglist: generateSpam(pkg, mail) os.unlink(conffile) if __name__ == '__main__': if len(sys.argv) > 1: doit(sys.argv[1:]) else: print "usage: spam-o-matic <directory>"