extras-buildsys/utils/pushscript/repomd __init__.py, NONE, 1.1 mdErrors.py, NONE, 1.1 mdUtils.py, NONE, 1.1 packageObject.py, NONE, 1.1 packageSack.py, NONE, 1.1 repoMDObject.py, NONE, 1.1 test.py, NONE, 1.1
Michael Schwendt (mschwendt)
fedora-extras-commits at redhat.com
Sun Oct 15 12:30:46 UTC 2006
- Previous message (by thread): extras-buildsys/utils/pushscript README,1.3,1.4
- Next message (by thread): extras-buildsys/utils/pushscript/rpmUtils __init__.py, NONE, 1.1 arch.py, NONE, 1.1 miscutils.py, NONE, 1.1 oldUtils.py, NONE, 1.1 transaction.py, NONE, 1.1 updates.py, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Author: mschwendt
Update of /cvs/fedora/extras-buildsys/utils/pushscript/repomd
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv30805/repomd
Added Files:
__init__.py mdErrors.py mdUtils.py packageObject.py
packageSack.py repoMDObject.py test.py
Log Message:
Add the patched yum 2.6.1 here, so we remove the dependency on the
system-installed one.
--- NEW FILE __init__.py ---
--- NEW FILE mdErrors.py ---
#!/usr/bin/python -tt
# 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.
# Copyright 2003 Duke University
import exceptions
class RepoMDError(exceptions.Exception):
def __init__(self, args=None):
exceptions.Exception.__init__(self)
self.args = args
class PackageSackError(exceptions.Exception):
def __init__(self, args=None):
exceptions.Exception.__init__(self)
self.args = args
--- NEW FILE mdUtils.py ---
#!/usr/bin/python -tt
# 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.
# Copyright 2003 Duke University
import rpm
import types
def rpmOutToStr(arg):
if type(arg) != types.StringType:
# and arg is not None:
arg = str(arg)
return arg
def compareEVR((e1, v1, r1), (e2, v2, r2)):
# return 1: a is newer than b
# 0: a and b are the same version
# -1: b is newer than a
e1 = rpmOutToStr(e1)
v1 = rpmOutToStr(v1)
r1 = rpmOutToStr(r1)
e2 = rpmOutToStr(e2)
v2 = rpmOutToStr(v2)
r2 = rpmOutToStr(r2)
#print '%s, %s, %s vs %s, %s, %s' % (e1, v1, r1, e2, v2, r2)
rc = rpm.labelCompare((e1, v1, r1), (e2, v2, r2))
#print '%s, %s, %s vs %s, %s, %s = %s' % (e1, v1, r1, e2, v2, r2, rc)
return rc
def newestInList(pkgs):
# return the newest in the list of packages
ret = [ pkgs.pop() ]
newest = ret[0].returnEVR()
for pkg in pkgs:
rc = compareEVR(pkg.returnEVR(), newest)
if rc > 0:
ret = [ pkg ]
newest = pkg.returnEVR()
elif rc == 0:
ret.append(pkg)
return ret
###########
# Title: Remove duplicates from a sequence
# Submitter: Tim Peters
# From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
def unique(s):
"""Return a list of the elements in s, but without duplicates.
For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
unique("abcabc") some permutation of ["a", "b", "c"], and
unique(([1, 2], [2, 3], [1, 2])) some permutation of
[[2, 3], [1, 2]].
For best speed, all sequence elements should be hashable. Then
unique() will usually work in linear time.
If not possible, the sequence elements should enjoy a total
ordering, and if list(s).sort() doesn't raise TypeError it's
assumed that they do enjoy a total ordering. Then unique() will
usually work in O(N*log2(N)) time.
If that's not possible either, the sequence elements must support
equality-testing. Then unique() will usually work in quadratic
time.
"""
n = len(s)
if n == 0:
return []
# Try using a dict first, as that's the fastest and will usually
# work. If it doesn't work, it will usually fail quickly, so it
# usually doesn't cost much to *try* it. It requires that all the
# sequence elements be hashable, and support equality comparison.
u = {}
try:
for x in s:
u[x] = 1
except TypeError:
del u # move on to the next method
else:
return u.keys()
# We can't hash all the elements. Second fastest is to sort,
# which brings the equal elements together; then duplicates are
# easy to weed out in a single pass.
# NOTE: Python's list.sort() was designed to be efficient in the
# presence of many duplicate elements. This isn't true of all
# sort functions in all languages or libraries, so this approach
# is more effective in Python than it may be elsewhere.
try:
t = list(s)
t.sort()
except TypeError:
del t # move on to the next method
else:
assert n > 0
last = t[0]
lasti = i = 1
while i < n:
if t[i] != last:
t[lasti] = last = t[i]
lasti += 1
i += 1
return t[:lasti]
# Brute force is all that's left.
u = []
for x in s:
if x not in u:
u.append(x)
return u
--- NEW FILE packageObject.py ---
#!/usr/bin/python -tt
# 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.
# Copyright 2003 Duke University
import mdUtils
# consider making an XMLPackageObject
# BasePackageObject - with just methods and the init'd storage dicts
# XMLPackageobject will be used to build the rpmXMLPAckageObject - which is
# formatnode stuff for rpm.
class PackageObject:
"""Base Package Object - sets up the default storage dicts and the
most common returns"""
def __init__(self):
self.simple = {} # simple things, name, arch, e,v,r, size, etc
self.checksums = [] # (type, checksum, id(0,1)
def __str__(self):
return self.returnNevraPrintable()
def returnSimple(self, varname):
return self.simple[varname]
def simpleItems(self):
return self.simple.keys()
def returnID(self):
return self.returnSimple('id')
def returnPackageTuple(self):
return (self.returnSimple('name'), self.returnSimple('arch'),
self.returnSimple('epoch'),self.returnSimple('version'),
self.returnSimple('release'))
def returnNevraTuple(self):
return (self.returnSimple('name'), self.returnSimple('epoch'),
self.returnSimple('version'),self.returnSimple('release'),
self.returnSimple('arch'))
def returnNevraPrintable(self):
"""return printable string for the pkgname/object
name - epoch:ver-rel.arch"""
if self.returnSimple('epoch') == '0':
string = '%s - %s-%s.%s' % (self.returnSimple('name'),
self.returnSimple('version'),
self.returnSimple('release'),
self.returnSimple('arch'))
else:
string = '%s - %s:%s-%s.%s' % (self.returnSimple('name'),
self.returnSimple('epoch'),
self.returnSimple('version'),
self.returnSimple('release'),
self.returnSimple('arch'))
return string
def returnEVR(self):
"""returns a tuple of epoch, ver, rel"""
return (self.returnSimple('epoch'), self.returnSimple('version'), self.returnSimple('release'))
return
def returnChangelog(self):
"""return changelog entries"""
return self.changelog
class XMLPackageObject(PackageObject):
"""inherits from PackageObject, does the functions to parse an xml package format
file to pull packages in"""
def __init__(self):
PackageObject.__init__(self)
def parseVersion(self, node):
"""takes a version element, returns a tuple of (epoch, ver, rel)"""
epoch = node.GetAttribute('epoch')
ver = node.GetAttribute('ver')
rel = node.GetAttribute('rel')
return (epoch, ver, rel)
def parseChecksum(self, node):
"""takes a checksum element, returns a tuple of (type, checksum,
if it is the checksum to be used for the the package id)"""
csumtype = node.GetAttribute('type')
csumid = node.GetAttribute('pkgid')
if csumid is None or csumid.upper() == 'NO':
csumid = 0
elif csumid.upper() == 'YES':
csumid = 1
else:
#FIXME - raise an exception
print 'broken csumid - invalid document'
csumid = 0
node.Read()
csum = node.Value()
return (csumtype, csum, csumid)
def parseSize(self, node):
"""takes a size element, returns package,
installed and archive size"""
pkg = node.GetAttribute('package')
installed = node.GetAttribute('installed')
archive = node.GetAttribute('archive')
return pkg, installed, archive
def parseTime(self, node):
"""takes a time element, returns buildtime, filetime(mtime)"""
build = node.GetAttribute('build')
mtime = node.GetAttribute('file')
return build, mtime
def parseLocation(self, node):
"""takes a location element, returnsbase url path, relative path to package"""
base = node.GetAttribute('base')
relative = node.GetAttribute('href')
return base, relative
def parseSimple(self, node):
"""takes a simple unattributed CDATA element and returns its value"""
if node.IsEmptyElement():
return ''
node.Read() # get the next node
return node.Value()
def readPkgNode(self, reader):
"""primary package node reading and dumping"""
mydepth = reader.Depth()
ret = reader.Read()
while ret:
if reader.NodeType() == 14:
ret = reader.Read()
continue
if reader.NodeType() == 15 and reader.Depth() == mydepth:
return
if reader.NodeType() == 1:
if reader.Depth() == mydepth:
#print 'oh crap - we are outside - how did that happen??'
return
nodeName = reader.LocalName()
if nodeName in ['name', 'arch', 'summary', 'description',
'url', 'packager', 'buildtime', 'filetime']:
self.simple[nodeName] = self.parseSimple(reader)
elif nodeName == 'version':
(self.simple['epoch'], self.simple['version'],
self.simple['release']) = self.parseVersion(reader)
elif nodeName == 'size':
self.simple['packagesize'], self.simple['installedsize'], \
self.simple['archivesize'] = self.parseSize(reader)
elif nodeName == 'time':
self.simple['buildtime'], self.simple['filetime'], = \
self.parseTime(reader)
elif nodeName == 'location':
self.simple['basepath'], self.simple['relativepath'] = \
self.parseLocation(reader)
elif nodeName == 'checksum':
(sumtype, sumdata, sumid) = self.parseChecksum(reader)
self.checksums.append((sumtype, sumdata, sumid))
if sumid:
self.simple['id'] = sumdata
elif nodeName == 'format':
try:
self.readFormatNode(reader)
except AttributeError:
# FIXME - should raise an exception
print 'No method to handle format element'
else:
pass
# FIXME - should raise an exception
print 'unknown element in package: %s' % nodeName
ret = reader.Read()
continue
class RpmBase:
"""return functions and storage for rpm-specific data"""
def __init__(self):
self.prco = {}
self.prco['obsoletes'] = [] # (name, flag, (e,v,r))
self.prco['conflicts'] = [] # (name, flag, (e,v,r))
self.prco['requires'] = [] # (name, flag, (e,v,r))
self.prco['provides'] = [] # (name, flag, (e,v,r))
self.files = {}
self.files['file'] = []
self.files['dir'] = []
self.files['ghost'] = []
self.changelog = [] # (ctime, cname, ctext)
self.licenses = []
def returnPrco(self, prcotype):
"""return list of provides, requires, conflicts or obsoletes"""
if self.prco.has_key(prcotype):
return self.prco[prcotype]
else:
return []
def checkPrco(self, prcotype, prcotuple):
"""returns 1 or 0 if the pkg contains the requested tuple/tuple range"""
# get rid of simple cases - nothing
if not self.prco.has_key(prcotype):
return 0
# exact match
if prcotuple in self.prco[prcotype]:
return 1
else:
# make us look it up and compare
(reqn, reqf, (reqe, reqv ,reqr)) = prcotuple
if reqf is not None:
if self.inPrcoRange(prcotype, prcotuple):
return 1
else:
return 0
else:
for (n, f, (e, v, r)) in self.returnPrco(prcotype):
if reqn == n:
return 1
return 0
def inPrcoRange(self, prcotype, reqtuple):
"""returns true if the package has a the prco that satisfies
the reqtuple range, assume false.
Takes: prcotype, requested prco tuple"""
# we only ever get here if we have a versioned prco
# nameonly shouldn't ever raise it
(reqn, reqf, (reqe, reqv, reqr)) = reqtuple
# find the named entry in pkgobj, do the comparsion
for (n, f, (e, v, r)) in self.returnPrco(prcotype):
if reqn == n:
# found it
if f != 'EQ':
# isn't this odd, it's not 'EQ' - it really should be
# use the pkgobj's evr for the comparison
(e, v, r) = self.returnEVR()
# and you thought we were done having fun
# if the requested release is left out then we have
# to remove release from the package prco to make sure the match
# is a success - ie: if the request is EQ foo 1:3.0.0 and we have
# foo 1:3.0.0-15 then we have to drop the 15 so we can match
if reqr is None:
r = None
if reqe is None:
e = None
if reqv is None: # just for the record if ver is None then we're going to segfault
v = None
rc = mdUtils.compareEVR((e, v, r), (reqe, reqv, reqr))
if rc >= 1:
if reqf in ['GT', 'GE', 4, 12]:
return 1
if rc == 0:
if reqf in ['GE', 'LE', 'EQ', 8, 10, 12]:
return 1
if rc <= -1:
if reqf in ['LT', 'LE', 2, 10]:
return 1
return 0
def returnChangelog(self):
"""return changelog entries"""
return self.changelog
def returnFileEntries(self, ftype='file'):
"""return list of files based on type"""
if self.files.has_key(ftype):
return self.files[ftype]
else:
return []
def returnFileTypes(self):
"""return list of types of files in the package"""
return self.files.keys()
class RpmXMLPackageObject(XMLPackageObject, RpmBase):
"""used class - inherits from XMLPackageObject, which inherits from
Package Object also inherits from RpmBase for return functions"""
def __init__(self, node, repoid):
XMLPackageObject.__init__(self)
RpmBase.__init__(self)
self.simple['repoid'] = repoid
self.readPkgNode(node)
self.repoid = repoid
def dumpPkg(self):
fconv = { 'EQ':'=', 'LT':'<', 'LE':'<=',
'GT':'>', 'GE':'>='}
for item in self.simpleItems():
print '%s = %s' % (item, self.returnSimple(item))
for csum in self.checksums:
print csum
for thing in ['requires', 'provides', 'obsoletes', 'conflicts']:
if len(self.prco[thing]) > 0:
print '%s:' % thing
for (n,f,(e,v,r)) in self.prco[thing]:
if f is None:
print '\t%s ' % n
else:
print '\t',
print n,
print fconv[f],
print '%s:%s-%s' %(e,v,r)
print ''
def readFormatNode(self, reader):
"""reads the <format> element and hands off the elements to be
parsed elsewhere"""
mydepth = reader.Depth()
ret = reader.Read()
while ret:
if reader.NodeType() == 14:
ret = reader.Read()
continue
if reader.NodeType() == 15 and reader.Depth() == mydepth:
return
if reader.NodeType() == 1:
if reader.Depth() == mydepth:
#print 'oh crap - we are outside - how did that happen??'
return
nodeName = reader.LocalName()
if nodeName in ['vendor', 'group', 'buildhost', 'sourcerpm']:
self.simple[nodeName] = self.parseSimple(reader)
elif nodeName == 'license':
self.licenses.append(self.parseSimple(reader))
elif nodeName == 'header-range':
self.simple['hdrstart'], self.simple['hdrend'] = \
self.parseHdrRange(reader)
elif nodeName in ['obsoletes', 'provides', 'requires', 'conflicts']:
objlist = self.parsePrco(reader)
self.prco[nodeName].extend(objlist)
elif nodeName == 'file':
self.loadFileEntry(reader)
else:
# FIXME - should raise an exception
print 'unknown element in format: %s' % nodeName
#pass
ret = reader.Read()
continue
def parseHdrRange(self, node):
"""parse header-range, returns (start, end) tuple"""
start = node.GetAttribute('start')
end = node.GetAttribute('end')
return start, end
def parsePrco(self, reader):
"""parse a provides,requires,obsoletes,conflicts element"""
objlist = []
mydepth = reader.Depth()
ret = reader.Read()
while ret:
if reader.NodeType() == 14:
ret = reader.Read()
continue
if reader.NodeType() == 15 and reader.Depth() == mydepth:
return objlist
if reader.NodeType() == 1:
if reader.Depth() == mydepth:
#print 'oh crap - we are outside - how did that happen??'
return objlist
prcoName = reader.LocalName()
if prcoName == 'entry':
name = reader.GetAttribute('name')
flag = reader.GetAttribute('flags')
e = reader.GetAttribute('epoch')
v = reader.GetAttribute('ver')
r = reader.GetAttribute('rel')
pre = reader.GetAttribte('pre')
objlist.append((name, flag, (e, v, r), pre))
ret = reader.Read()
continue
return objlist
def loadFileEntry(self, node):
"""load a file/dir entry"""
ftype = node.GetAttribute('type')
node.Read() # content is file
file = node.Value()
if not ftype:
ftype = 'file'
if not self.files.has_key(ftype):
self.files[ftype] = []
#if file not in self.files[ftype]:
self.files[ftype].append(file)
return (ftype, file)
def loadChangeLogEntry(self, node):
"""load changelog data"""
time = node.GetAttribute('date')
author = node.GetAttribute('author')
node.Read()
content = node.Value()
self.changelog.append((time, author, content))
--- NEW FILE packageSack.py ---
#!/usr/bin/python -tt
# 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.
# Copyright 2003 Duke University
import libxml2
from mdErrors import PackageSackError
import mdUtils
class PackageSack:
"""represents sets (sacks) of Package Objects"""
def __init__(self):
self.nevra = {} #nevra[(Name, Epoch, Version, Release, Arch)] = []
self.obsoletes = {} #obs[obsoletename] = [pkg1, pkg2, pkg3]
#the package lists are packages that obsolete the key name
self.requires = {} #req[reqname] = [pkg1, pkg2, pkg3]
#the package lists are packages that require the key name
self.provides = {} #ditto of above but for provides
self.conflicts = {} #ditto of above but for conflicts
self.filenames = {} # duh
self.pkgsByRepo = {} #pkgsByRepo['repoid']= [pkg1, pkg2, pkg3]
self.pkgsByID = {} #pkgsById[pkgid] = [pkg1, pkg2] (should really only ever be one value but
#you might have repos with the same package in them
self.compatarchs = None # dict of compatible archs for addPackage
self.indexesBuilt = 0
def __len__(self):
return len(self.simplePkgList())
def __iter__(self):
if hasattr(self.returnPackages(), '__iter__'):
return self.returnPackages().__iter__()
else:
return iter(self.returnPackages())
def _checkIndexes(self, failure='error'):
"""check to see if the indexes are built, if not do what failure demands
either error out or build the indexes, default is to error out"""
if not self.indexesBuilt:
if failure == 'error':
raise PackageSackError, 'Indexes not yet built, cannot search'
elif failure == 'build':
self.buildIndexes()
def packagesByTuple(self, pkgtup):
"""return a list of package objects by (n,a,e,v,r) tuple"""
(n,a,e,v,r) = pkgtup
return self.searchNevra(name=n, arch=a, epoch=e, ver=v, rel=r)
def searchNevra(self, name=None, epoch=None, ver=None, rel=None, arch=None):
"""return list of pkgobjects matching the nevra requested"""
self._checkIndexes(failure='build')
if self.nevra.has_key((name, epoch, ver, rel, arch)):
return self.nevra[(name, epoch, ver, rel, arch)]
else:
return []
def searchID(self, pkgid):
"""return list of packages based on pkgid"""
self._checkIndexes(failure='build')
if self.pkgsByID.has_key(pkgid):
return self.pkgsByID[pkgid]
else:
return []
def searchRequires(self, name):
"""return list of package requiring the name (any evr and flag)"""
self._checkIndexes(failure='build')
if self.requires.has_key(name):
return self.requires[name]
else:
return []
def searchProvides(self, name):
"""return list of package providing the name (any evr and flag)"""
# FIXME - should this do a pkgobj.checkPrco((name, flag, (e,v,r,))??
# has to do a searchFiles and a searchProvides for things starting with /
self._checkIndexes(failure='build')
returnList = []
if name[0] == '/':
returnList.extend(self.searchFiles(name))
if self.provides.has_key(name):
returnList.extend(self.provides[name])
return returnList
def searchConflicts(self, name):
"""return list of package conflicting with the name (any evr and flag)"""
self._checkIndexes(failure='build')
if self.conflicts.has_key(name):
return self.conflicts[name]
else:
return []
def searchObsoletes(self, name):
"""return list of package obsoleting the name (any evr and flag)"""
self._checkIndexes(failure='build')
if self.obsoletes.has_key(name):
return self.obsoletes[name]
else:
return []
def returnObsoletes(self):
"""returns a dict of obsoletes dict[obsoleting pkgtuple] = [list of obs]"""
obs = {}
for po in self.returnPackages():
pkgtuple = po.returnPackageTuple()
if len(po.returnPrco('obsoletes')) == 0:
continue
if not obs.has_key(pkgtuple):
obs[pkgtuple] = po.returnPrco('obsoletes')
else:
obs[pkgtuple].extend(po.returnPrco('obsoletes'))
return obs
def searchFiles(self, file):
"""return list of packages by filename
FIXME - need to add regex match against keys in file list
"""
self._checkIndexes(failure='build')
if self.filenames.has_key(file):
return self.filenames[file]
else:
return []
def _addToDictAsList(self, dict, key, data):
if not dict.has_key(key):
dict[key] = []
#if data not in dict[key]: - if I enable this the whole world grinds to a halt
# need a faster way of looking for the object in any particular list
dict[key].append(data)
def _delFromListOfDict(self, dict, key, data):
if not dict.has_key(key):
dict[key] = []
try:
dict[key].remove(data)
except ValueError:
pass
if len(dict[key]) == 0: # if it's an empty list of the dict, then kill it
del dict[key]
def addPackage(self, obj):
"""add a pkgobject to the packageSack"""
repoid = obj.returnSimple('repoid')
(name, epoch, ver, rel, arch) = obj.returnNevraTuple()
if self.compatarchs:
if self.compatarchs.has_key(arch):
self._addToDictAsList(self.pkgsByRepo, repoid, obj)
else:
self._addToDictAsList(self.pkgsByRepo, repoid, obj)
def buildIndexes(self):
"""builds the useful indexes for searching/querying the packageSack
This should be called after all the necessary packages have been
added/deleted"""
# blank out the indexes
self.obsoletes = {}
self.requires = {}
self.provides = {}
self.conflicts = {}
self.filenames = {}
self.nevra = {}
self.pkgsByID = {}
for repoid in self.pkgsByRepo.keys():
for obj in self.pkgsByRepo[repoid]:
# store the things provided just on name, not the whole require+version
# this lets us reduce the set of pkgs to search when we're trying to depSolve
for (n, fl, (e,v,r)) in obj.returnPrco('obsoletes'):
self._addToDictAsList(self.obsoletes, n, obj)
for (n, fl, (e,v,r)) in obj.returnPrco('requires'):
self._addToDictAsList(self.requires, n, obj)
for (n, fl, (e,v,r)) in obj.returnPrco('provides'):
self._addToDictAsList(self.provides, n, obj)
for (n, fl, (e,v,r)) in obj.returnPrco('conflicts'):
self._addToDictAsList(self.conflicts, n, obj)
for ftype in obj.returnFileTypes():
for file in obj.returnFileEntries(ftype):
self._addToDictAsList(self.filenames, file, obj)
self._addToDictAsList(self.pkgsByID, obj.returnSimple('id'), obj)
(name, epoch, ver, rel, arch) = obj.returnNevraTuple()
self._addToDictAsList(self.nevra, (name, epoch, ver, rel, arch), obj)
self._addToDictAsList(self.nevra, (name, None, None, None, None), obj)
self.indexesBuilt = 1
def delPackage(self, obj):
"""delete a pkgobject"""
self._delFromListOfDict(self.pkgsByRepo, obj.returnSimple('repoid'), obj)
if self.indexesBuilt: # if we've built indexes, delete it b/c we've just deleted something
self.indexesBuilt = 0
def returnPackages(self, repoid=None):
"""return list of all packages, takes optional repoid"""
returnList = []
if repoid is None:
for repo in self.pkgsByRepo.keys():
returnList.extend(self.pkgsByRepo[repo])
else:
try:
returnList = self.pkgsByRepo[repoid]
except KeyError:
# nothing to return
pass
return returnList
def returnNewestByNameArch(self, naTup=None):
"""return list of newest packages based on name, arch matching
this means(in name.arch form): foo.i386 and foo.noarch are not
compared to each other for highest version only foo.i386 and
foo.i386 will be compared"""
highdict = {}
# If naTup is set, only iterate through packages that match that
# name
if (naTup):
where = self.nevra.get((naTup[0],None,None,None,None))
if (not where):
raise PackageSackError, 'No Package Matching %s.%s' % naTup
else:
where = self.returnPackages()
for pkg in where:
(n, e, v ,r, a) = pkg.returnNevraTuple()
if not highdict.has_key((n, a)):
highdict[(n, a)] = pkg
else:
pkg2 = highdict[(n, a)]
(e2, v2, r2) = pkg2.returnEVR()
rc = mdUtils.compareEVR((e,v,r), (e2, v2, r2))
if rc > 0:
highdict[(n, a)] = pkg
if naTup:
if highdict.has_key(naTup):
return highdict[naTup]
else:
raise PackageSackError, 'No Package Matching %s.%s' % naTup
return highdict.values()
def returnNewestByName(self, name=None):
"""return list of newest packages based on name matching
this means(in name.arch form): foo.i386 and foo.noarch will
be compared to each other for highest version"""
highdict = {}
for pkg in self.returnPackages():
(n, e, v ,r, a) = pkg.returnNevraTuple()
if not highdict.has_key(n):
highdict[n] = []
highdict[n].append(pkg)
else:
pkg2 = highdict[n][0]
(e2, v2, r2) = pkg2.returnEVR()
rc = mdUtils.compareEVR((e,v,r), (e2, v2, r2))
if rc > 0:
highdict[n] = [pkg]
elif rc == 0:
highdict[n].append(pkg)
if name:
if highdict.has_key(name):
return highdict[name]
else:
raise PackageSackError, 'No Package Matching %s' % name
return highdict.values()
def simplePkgList(self, repoid=None):
"""returns a list of pkg tuples (n, a, e, v, r) optionally from a single repoid"""
simplelist = []
for pkg in self.returnPackages(repoid):
simplelist.append(pkg.returnPackageTuple())
return simplelist
def printPackages(self):
for pkg in self.returnPackages():
print pkg.returnNevraPrintable()
def excludeArchs(self, archlist):
"""exclude incompatible arches. archlist is a list of compatible arches"""
for pkg in self.returnPackages():
if pkg.arch not in archlist:
self.delPackage(pkg)
# packageSack should be a base class
# two derived classes could be DBPackageSack and XMLPackageSack
# one for importing this data from the localdb
# another from XML metadata files
class XMLPackageSack(PackageSack):
"""Derived class from PackageSack to build list from XML metadata file.
Needs the Package Object Class passed to it for the Sack"""
def __init__(self, pkgObjectClass):
PackageSack.__init__(self)
self.repoStatus = {} #[repoid]= [primary, filelist, other] (so you can tell
#what things have been loaded or not - b/c w/o primary,
#filelist and other really can't be loaded
self.pkgObjectClass = pkgObjectClass
def addFile(self, repoid, file, callback=None):
"""takes a repository id and an xml file. It populates whatever it can,
if you try to populate with a filelist or other metadata file
before the primary metadata you'll not like the results"""
try:
reader = libxml2.newTextReaderFilename(file)
except libxml2.treeError:
raise PackageSackError, "Invalid or non-existent file: %s" % (file)
else:
reader.Read()
xmlfiletype=reader.Name() # - first node should be the type
if xmlfiletype == 'metadata':
if not self._checkRepoStatus(repoid, itemcheck='primary'):
self.loadPrimaryMD(reader, repoid, callback)
elif xmlfiletype == 'filelists':
if not self._checkRepoStatus(repoid, itemcheck='filelists'):
self.loadFileMD(reader, repoid, callback)
elif xmlfiletype == 'otherdata':
if not self._checkRepoStatus(repoid, itemcheck='other'):
self.loadOtherMD(reader, repoid, callback)
else:
print 'Error: other unknown root element %s' % xmlfiletype
def _checkRepoStatus(self, repoid, itemcheck='primary'):
"""return 1 if itemcheck is in repo"""
if self.repoStatus.has_key(repoid):
if itemcheck in self.repoStatus[repoid]:
return 1
return 0
def loadPrimaryMD(self, reader, repoid, callback=None):
"""load all the data from the primary metadata xml file"""
pkgcount = 9999 # big number
current = 1
if reader.HasAttributes():
pkgcount = int(reader.GetAttribute('packages'))
ret = reader.Read()
while ret:
if reader.NodeType() == 14:
ret = reader.Read()
continue
if reader.NodeType() == 1 and reader.Name() == 'package':
if reader.HasAttributes():
if reader.GetAttribute('type') == 'rpm':
current+=1
po = self.pkgObjectClass(reader, repoid)
self.addPackage(po)
if callback: callback(current, pkgcount, name=repoid)
ret = reader.Read()
continue
# update the repoStatus
if not self.repoStatus.has_key(repoid):
self.repoStatus[repoid] = []
if not 'primary' in self.repoStatus[repoid]:
self.repoStatus[repoid].append('primary')
def loadFileMD(self, reader, repoid, callback=None):
"""load all the filelist metadata from the file"""
pkgcount = 9999 # big number
current = 1
if reader.HasAttributes():
pkgcount = int(reader.GetAttribute('packages'))
ret = reader.Read()
while ret:
if reader.NodeType() == 14:
ret = reader.Read()
continue
if reader.NodeType() == 1 and reader.Name() == 'package':
if reader.HasAttributes():
pkgid = reader.GetAttribute('pkgid')
pkgs = self.searchID(pkgid)
pkgmatch = 0
mydepth = reader.Depth()
current+=1
for pkg in pkgs:
if pkg.returnSimple('repoid') == repoid: # check for matching repo
reader.Read()
pkgmatch+=1
while 1:
if reader.NodeType() == 15 and reader.Depth() == mydepth:
break
elif reader.NodeType() == 14:
ret = reader.Read()
continue
elif reader.NodeType() == 1:
if reader.LocalName() == 'file':
(ftype, file) = pkg.loadFileEntry(reader)
#self._addToDictAsList(self.filenames, file, pkg)
ret = reader.Read()
continue
if pkgmatch < 1:
# FIXME - raise a warning? Emit error? bitch? moan?
pass
ret = reader.Read()
if callback: callback(current, pkgcount, name=repoid) # give us some pretty output
continue
# update the repostatus
if not 'filelist' in self.repoStatus[repoid]:
self.repoStatus[repoid].append('filelist')
# we've just added file items - build up the indexes again
self.buildIndexes()
def loadOtherMD(self, reader, repoid, callback=None):
"""load the changelog, etc data from the other.xml file"""
pkgcount = 9999 # big number
current = 1
if reader.HasAttributes():
pkgcount = int(reader.GetAttribute('packages'))
ret = reader.Read()
while ret:
if reader.NodeType() == 14:
ret = reader.Read()
continue
if reader.NodeType() == 1 and reader.Name() == 'package':
current+=1
if reader.HasAttributes():
pkgid = reader.GetAttribute('pkgid')
pkgs = self.searchID(pkgid)
pkgmatch = 0
mydepth = reader.Depth()
#current+=1
for pkg in pkgs:
if pkg.returnSimple('repoid') == repoid: # check for matching repo
reader.Read()
pkgmatch+=1
while 1:
if reader.NodeType() == 15 and reader.Depth() == mydepth:
break
elif reader.NodeType() == 14:
ret = reader.Read()
continue
elif reader.NodeType() == 1:
if reader.LocalName() == 'changelog':
pkg.loadChangeLogEntry(reader)
ret = reader.Read()
continue
if pkgmatch < 1:
# FIXME - raise a warning? Emit error? bitch? moan?
pass
if callback: callback(current, pkgcount, name=repoid)
ret = reader.Read()
continue
if not 'other' in self.repoStatus[repoid]:
self.repoStatus[repoid].append('other')
# we've just added file items - build up the indexes again
self.buildIndexes()
class ListPackageSack(PackageSack):
"""Derived class from PackageSack to build new Sack from list of
pkgObjects - like one returned from self.returnNewestByNameArch()
or self.returnNewestByName()"""
def __init__(self, Objlist=None):
PackageSack.__init__(self)
if Objlist is not None:
self.addList(Objlist)
def addList(self, ObjList):
for pkgobj in ObjList:
self.addPackage(pkgobj)
--- NEW FILE repoMDObject.py ---
#!/usr/bin/python -tt
# 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.
# Copyright 2003 Duke University
import libxml2
from mdErrors import RepoMDError
class RepoMD:
"""represents the repomd xml file"""
def __init__(self, repoid, file):
"""takes a repoid and a filename for the repomd.xml"""
self.repoid = repoid
self.repoData = {}
try:
doc = libxml2.parseFile(file)
except libxml2.parserError:
raise RepoMDError, 'Error: could not parse file %s' % file
root = doc.getRootElement()
xmlfiletype = root.name
node = root.children
if xmlfiletype == 'repomd':
self.loadRepoMD(node)
else:
raise RepoMDError, 'Error: other unknown root element %s' % xmlfiletype
doc.freeDoc()
def _returnData(self, mdtype, request):
""" return the data from the repository Data"""
if self.repoData.has_key(mdtype):
ds = self.repoData[mdtype]
if ds.has_key(request):
return ds[request]
else:
raise RepoMDError, "Error: request %s not in %s data" % (request, mdtype)
else:
raise RepoMDError, "Error: odd MDtype requested: %s" % mdtype
def _storeRepoData(self, mdtype, dataname, data):
"""stores repository data
mdtype = primary, filelists, other, group
dataname = checksum, timestamp, basepath, relativepath
"""
if self.repoData.has_key(mdtype):
ds = self.repoData[mdtype]
if not ds.has_key(dataname):
ds[dataname] = data
else:
raise RepoMDError, "Warning: duplicate data of %s description inputted" % dataname
else:
raise RepoMDError, "Warning: odd mdtype being put in %s" % mdtype
def loadRepoDataNode(self, node):
"""loads a repository data node into the class"""
mdtype = node.prop('type') # get the 'type' property for the datanode
if not self.repoData.has_key(mdtype):
self.repoData[mdtype] = {}
datanode = node.children
while datanode is not None:
if datanode.type != 'element':
datanode = datanode.next
continue
if datanode.name == 'location':
base = datanode.prop('base')
relative = datanode.prop('href')
self._storeRepoData(mdtype, 'basepath', base)
self._storeRepoData(mdtype, 'relativepath', relative)
elif datanode.name == 'checksum':
csumType = datanode.prop('type')
csum = datanode.content
self._storeRepoData(mdtype, 'checksum', (csumType, csum))
elif datanode.name == 'timestamp':
timestamp = datanode.content
self._storeRepoData(mdtype, 'timestamp', timestamp)
datanode = datanode.next
continue
def loadRepoMD(self, node):
"""iterates through the data nodes and populates some simple data areas"""
while node is not None:
if node.type != 'element':
node = node.next
continue
if node.name == 'data':
self.loadRepoDataNode(node)
node = node.next
continue
def _checksum(self, mdtype):
"""returns a tuple of (checksum type, checksum) for the specified Metadata
file"""
return self._returnData(mdtype, 'checksum')
def _location(self, mdtype):
"""returns location to specified metadata file, (base, relative)"""
base = self._returnData(mdtype, 'basepath')
relative = self._returnData(mdtype, 'relativepath')
return (base, relative)
def _timestamp(self, mdtype):
"""returns timestamp for specified metadata file"""
return self._returnData(mdtype, 'timestamp')
def otherChecksum(self):
"""returns a tuple of (checksum type, checksum) for the other Metadata file"""
return self._checksum('other')
def otherLocation(self):
"""returns location to other metadata file, (base, relative)"""
return self._location('other')
def otherTimestamp(self):
"""returns timestamp for other metadata file"""
return self._timestamp('other')
def primaryChecksum(self):
"""returns a tuple of (checksum type, checksum) for the primary Metadata file"""
return self._checksum('primary')
def primaryLocation(self):
"""returns location to primary metadata file, (base, relative)"""
return self._location('primary')
def primaryTimestamp(self):
"""returns timestamp for primary metadata file"""
return self._timestamp('primary')
def filelistsChecksum(self):
"""returns a tuple of (checksum type, checksum) for the filelists Metadata file"""
return self._checksum('filelists')
def filelistsLocation(self):
"""returns location to filelists metadata file, (base, relative)"""
return self._location('filelists')
def filelistsTimestamp(self):
"""returns timestamp for filelists metadata file"""
return self._timestamp('filelists')
def groupChecksum(self):
"""returns a tuple of (checksum type, checksum) for the group Metadata file"""
return self._checksum('group')
def groupLocation(self):
"""returns location to group metadata file, (base, relative)"""
return self._location('group')
def groupTimestamp(self):
"""returns timestamp for group metadata file"""
return self._timestamp('group')
def fileTypes(self):
"""return list of metadata file types available"""
return self.repoData.keys()
--- NEW FILE test.py ---
#!/usr/bin/python -tt
# 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.
# Copyright 2003 Duke University
# classes for parsing the metadata files for the new metadata format
# used with python -i :)
import sys
import os
import time
import rpm
import packageSack
import packageObject
import repoMDObject
import mdUtils
import mdErrors
def process(current, total, name=None):
sys.stdout.write('\r' + ' ' * 80)
sys.stdout.write('\rNode %d of %d' % (current, total))
sys.stdout.flush()
if len(sys.argv) < 4:
print 'test.py: /path/to/repo /other/repo somepackagename'
sys.exit(1)
print time.time()
repos = sys.argv[1:3]
pkgSack = packageSack.XMLPackageSack(packageObject.RpmXMLPackageObject)
numid = 0
for repo in repos:
numid+=1
basepath = repo
repomdxmlfile = os.path.join(basepath, 'repodata/repomd.xml')
repoid = repo
try:
repodata = repoMDObject.RepoMD(repoid, repomdxmlfile)
except mdErrors.RepoMDError, e:
print >> sys.stderr, e
sys.exit(1)
(pbase, phref) = repodata.primaryLocation()
(fbase, fhref) = repodata.filelistsLocation()
(obase, ohref) = repodata.otherLocation()
processlist = [phref]
for file in processlist:
print time.time()
print 'importing %s from %s' % (file, repoid)
complete = basepath + '/' + file
try:
pkgSack.addFile(repoid, complete, process)
except mdErrors.PackageSackError, e:
print >> sys.stderr, e
sys.exit(1)
print ' '
print time.time()
for pkg in pkgSack.searchNevra(sys.argv[3]):
print pkg
for reqtup in pkg.returnPrco('requires'):
(reqn, reqf, (reqe,reqv,reqr)) = reqtup
# rpmlib deps should be handled on their own
if reqn[:6] == 'rpmlib':
continue
# kill self providers, too
if pkg.checkPrco('provides', reqtup):
continue
# get a list of all pkgs that match the reqn
providers = pkgSack.searchProvides(reqn)
if len(providers) == 0:
print 'unresolved: %s %s %s:%s-%s' % (reqn, reqf, reqe, reqv, reqr)
continue
if len(providers) == 1:
if reqf is None:
print '%s: %s from %s' % (reqn, providers[0], providers[0].returnSimple('relativepath'))
continue
# only one entry but we need to match out it out
if providers[0].checkPrco('provides', reqtup):
print '%s: %s from %s' % (reqn, providers[0], providers[0].returnSimple('relativepath'))
continue
output = '%s:' % reqn
for prov in providers:
if reqf is not None:
if prov.checkPrco('provides', reqtup):
output = output + '||' + prov.__str__()
else:
print '%s does not provide %s %s %s %s %s' % (prov, reqn, reqf, reqe, reqv, reqr)
else:
output = output + '||' + prov.__str__()
print output
print time.time()
- Previous message (by thread): extras-buildsys/utils/pushscript README,1.3,1.4
- Next message (by thread): extras-buildsys/utils/pushscript/rpmUtils __init__.py, NONE, 1.1 arch.py, NONE, 1.1 miscutils.py, NONE, 1.1 oldUtils.py, NONE, 1.1 transaction.py, NONE, 1.1 updates.py, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the fedora-extras-commits
mailing list