incoming: dependency warnings

Bill Nottingham notting at redhat.com
Thu Jul 14 16:28:22 UTC 2005


Jeff Spaleta (jspaleta at gmail.com) 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
-------------- next part --------------
#!/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>"
	


More information about the Fedora-maintainers mailing list