fedora-infrastructure/scripts/epel-repoclosure/rc-modified
2008-02-27 12:18:54 -06:00

282 lines
10 KiB
Python
Executable file

#!/usr/bin/python -t
# -*- mode: Python; indent-tabs-mode: nil; -*-
# 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.
# seth vidal 2005 (c) etc etc
# mschwendt: modified for Fedora Extras buildsys
#Read in the metadata of a series of repositories and check all the
# dependencies in all packages for resolution. Print out the list of
# packages with unresolved dependencies
import sys
import os
# For patched "yum" and "rpmUtils" (post 2.6.1 checkForObsolete support).
# Comment this to use system yum.
#sys.path.insert(0,'/srv/extras-push/work/buildsys-utils/pushscript')
import yum
import yum.Errors
from yum.misc import getCacheDir
from optparse import OptionParser
import rpmUtils.arch
from yum.constants import *
if yum.__version__ < '3.0': # TODO: check
from repomd.packageSack import ListPackageSack
else:
from yum.packageSack import ListPackageSack
def parseArgs():
usage = "usage: %s [-c <config file>] [-a <arch>] [-r <repoid>] [-r <repoid2>]" % sys.argv[0]
parser = OptionParser(usage=usage)
parser.add_option("-c", "--config", default='/etc/yum.conf',
help='config file to use (defaults to /etc/yum.conf)')
parser.add_option("-a", "--arch", default=None,
help='check as if running the specified arch (default: current arch)')
parser.add_option("-r", "--repoid", default=[], action='append',
help="specify repo ids to query, can be specified multiple times (default is all enabled)")
parser.add_option("-t", "--tempcache", default=False, action="store_true",
help="Use a temp dir for storing/accessing yum-cache")
parser.add_option("-d", "--cachedir", default='',
help="specify a custom directory for storing/accessing yum-cache")
parser.add_option("-q", "--quiet", default=0, action="store_true",
help="quiet (no output to stderr)")
parser.add_option("-n", "--newest", default=0, action="store_true",
help="check only the newest packages in the repos")
(opts, args) = parser.parse_args()
return (opts, args)
class RepoClosure(yum.YumBase):
def __init__(self, arch = None, config = "/etc/yum.conf"):
yum.YumBase.__init__(self)
self.arch = arch
if yum.__version__ < '3.0': # TODO: check
self.doConfigSetup(fn = config)
else:
self.doConfigSetup(fn = config, init_plugins = False)
if hasattr(self.repos, 'sqlite'):
self.repos.sqlite = False
self.repos._selectSackType()
def evrTupletoVer(self,tuple):
"""convert and evr tuple to a version string, return None if nothing
to convert"""
e, v,r = tuple
if v is None:
return None
val = ''
if e is not None:
val = '%s:%s' % (e, v)
if r is not None:
val = '%s-%s' % (val, r)
return val
def readMetadata(self):
self.doRepoSetup()
self.doSackSetup(rpmUtils.arch.getArchList(self.arch))
for repo in self.repos.listEnabled():
try: # TODO: when exactly did this change to "mdtype"?
self.repos.populateSack(which=[repo.id], mdtype='filelists')
except TypeError:
self.repos.populateSack(which=[repo.id], with='filelists')
def getBrokenDeps(self, newest=False):
unresolved = {}
resolved = {}
newpkgtuplist = []
if newest:
if yum.__version__ >= '2.9': # TODO: check
pkgs = self.pkgSack.returnNewestByName()
else:
pkgs = []
for l in self.pkgSack.returnNewestByName():
pkgs.extend(l)
newestpkgtuplist = ListPackageSack(pkgs).simplePkgList()
pkgs = self.pkgSack.returnNewestByNameArch()
else:
pkgs = self.pkgSack
self.numpkgs = len(pkgs)
mypkgSack = ListPackageSack(pkgs)
pkgtuplist = mypkgSack.simplePkgList()
# Support new checkForObsolete code in Yum (#190116)
# _if available_
# so we don't examine old _obsolete_ sub-packages.
import rpmUtils.updates
self.up = rpmUtils.updates.Updates([],pkgtuplist)
self.up.rawobsoletes = mypkgSack.returnObsoletes()
haveCheckForObsolete = hasattr(rpmUtils.updates.Updates,'checkForObsolete')
if not haveCheckForObsolete:
print 'WARNING: rpmUtils.updates.checkForObsolete missing!'
for pkg in pkgs:
thispkgobsdict = {}
if haveCheckForObsolete:
try:
thispkgobsdict = self.up.checkForObsolete([pkg.pkgtup])
if thispkgobsdict.has_key(pkg.pkgtup):
continue
except AttributeError:
pass
def isnotnewest(pkg):
# Handle noarch<->arch switches in package updates, so any
# old nevra returned by returnNewestByNameArch() are skipped.
# TODO: There must be a more elegant/convenient way.
if (pkg.pkgtup[1] == 'noarch'):
if (pkg.pkgtup not in newestpkgtuplist):
return True
else:
for p in self.pkgSack.returnNewestByName(pkg.pkgtup[0]):
if (p.pkgtup[1] == 'noarch') and (p.pkgtup in newestpkgtuplist):
return True
return False
for (req, flags, (reqe, reqv, reqr)) in pkg.returnPrco('requires'):
if req.startswith('rpmlib'): continue # ignore rpmlib deps
ver = self.evrTupletoVer((reqe, reqv, reqr))
if resolved.has_key((req,flags,ver)):
continue
try:
resolve_sack = self.whatProvides(req, flags, ver)
except yum.Errors.RepoError, e:
pass
if len(resolve_sack) < 1:
if newest and isnotnewest(pkg):
break
if not unresolved.has_key(pkg):
unresolved[pkg] = []
unresolved[pkg].append((req, flags, ver))
continue
kernelprovides = True # make a false assumption
# If all providers are "kernel*" packages, we allow old ones.
for (pn,pa,pe,pv,pr) in resolve_sack.simplePkgList():
kernelprovides &= pn.startswith('kernel')
if newest and not kernelprovides and not req.startswith('kernel'): # we allow old kernels
resolved_by_newest = False
for po in resolve_sack:# look through and make sure all our answers are newest-only
# 2nd stage handling of obsoletes. Only keep providers,
# which are not obsolete. If no provider is left, the
# dep is unresolved.
thispkgobsdict = {}
if haveCheckForObsolete:
try:
thispkgobsdict = self.up.checkForObsolete([po.pkgtup])
if thispkgobsdict.has_key(po.pkgtup):
continue
except AttributeError:
pass
if po.pkgtup in pkgtuplist:
resolved_by_newest = True
break
if resolved_by_newest:
resolved[(req,flags,ver)] = 1
else:
if newest and isnotnewest(pkg):
break
if not unresolved.has_key(pkg):
unresolved[pkg] = []
unresolved[pkg].append((req, flags, ver))
return unresolved
def log(self, value, msg):
pass
def main():
(opts, cruft) = parseArgs()
my = RepoClosure(arch = opts.arch, config = opts.config)
if opts.repoid:
for repo in my.repos.repos.values():
if repo.id not in opts.repoid:
repo.disable()
else:
repo.enable()
if os.geteuid() != 0 or opts.tempcache or opts.cachedir != '':
if opts.cachedir != '':
cachedir = opts.cachedir
else:
cachedir = getCacheDir()
if cachedir is None:
print "Error: Could not make cachedir, exiting"
sys.exit(50)
my.repos.setCacheDir(cachedir)
if not opts.quiet:
print 'Reading in repository metadata - please wait....'
try:
my.readMetadata()
except yum.Errors.RepoError, e:
print e
sys.exit(1)
if not opts.quiet:
print 'Checking Dependencies'
baddeps = my.getBrokenDeps(opts.newest)
num = my.numpkgs
repos = my.repos.listEnabled()
if not opts.quiet:
print 'Repos looked at: %s' % len(repos)
for repo in repos:
print ' %s' % repo
print 'Num Packages in Repos: %s' % num
pkgs = baddeps.keys()
def sortbyname(a,b):
return cmp(a.__str__(),b.__str__())
pkgs.sort(sortbyname)
for pkg in pkgs:
srcrpm = pkg.returnSimple('sourcerpm')
print 'source rpm: %s\npackage: %s from %s\n unresolved deps: ' % (srcrpm, pkg, pkg.repoid)
for (n, f, v) in baddeps[pkg]:
req = '%s' % n
if f:
flag = LETTERFLAGS[f]
req = '%s %s'% (req, flag)
if v:
req = '%s %s' % (req, v)
print ' %s' % req
print
if __name__ == "__main__":
main()