@@ -212,9 +212,10 @@ class LinkageMap(object):
@param obj: path to an existing file
@type obj: string (example: '/usr/bin/bar')
- @rtype: 2-tuple of longs or string
- @return: If obj exists, a 2-tuple of obj's inode and device from a stat
- call is returned. Otherwise, the obj is returned.
+ @rtype: 2-tuple of longs if obj exists. string if obj does not exist.
+ @return:
+ 1. 2-tuple of obj's inode and device from a stat call, if obj exists.
+ 2. string if obj does not exist.
"""
try:
@@ -225,12 +226,15 @@ class LinkageMap(object):
# from portage.output import teal
# writemsg(bold(red("Error in ")) + \
# bold(teal("_generateObjKey. Stat failed on %s" % obj)) + '\n')
+ # XXX do we need realpath?
return obj
def listBrokenBinaries(self, debug=False):
"""
Find binaries and their needed sonames, which have no providers.
+ @param debug: Boolean to enable debug output
+ @type debug: Boolean
@rtype: dict (example: {'/usr/bin/foo': set(['libbar.so'])})
@return: The return value is an object -> set-of-sonames mapping, where
object is a broken binary and the set consists of sonames needed by
@@ -240,7 +244,7 @@ class LinkageMap(object):
class LibraryCache(object):
"""
- Caches sonames and realpaths associated with paths.
+ Caches properties associated with paths.
The purpose of this class is to prevent multiple calls of
os.path.realpath and os.path.isfile on the same paths.
@@ -318,9 +322,12 @@ class LinkageMap(object):
validLibraries.add(cachedKey)
if debug and cachedKey not in \
set(map(self._obj_key_cache.get, libraries)):
+ # XXX This is most often due to soname symlinks not in
+ # a library's directory. We could catalog symlinks in
+ # LinkageMap to avoid checking for this edge case here.
print "Found provider outside of findProviders:", \
os.path.join(directory, soname), "->", \
- self._obj_properties[cachedKey][4]
+ self._obj_properties[cachedKey][4], libraries
# A valid library has been found, so there is no need to
# continue.
break
@@ -338,27 +345,11 @@ class LinkageMap(object):
# If no valid libraries have been found by this point, then
# there are no files named with the soname within obj's runpath,
# but if there are libraries (from the providers mapping), it is
- # likely that symlinks or the actual libraries are missing.
- # Thus possible symlinks and missing libraries are added to
- # rValue in order to emerge corrupt library packages.
+ # likely that soname symlinks or the actual libraries are
+ # missing or broken. Thus those libraries are added to rValue
+ # in order to emerge corrupt library packages.
for lib in libraries:
- cachedArch, cachedSoname, cachedKey, cachedExists = \
- cache.get(lib)
- if not cachedExists:
- # The library's package needs to be emerged to repair the
- # missing library.
- rValue.setdefault(lib, set()).add(soname)
- else:
- # A library providing the soname exists in the obj's
- # runpath, but no file named as the soname exists, so add
- # the path constructed from the lib's directory and the
- # soname to rValue to fix cases of vanishing (or modified)
- # symlinks. This path is not guaranteed to exist, but it
- # follows the symlink convention found in the majority of
- # packages.
- # XXX merge this into block above
- rValue.setdefault(os.path.join(os.path.dirname(lib), \
- soname), set()).add(soname)
+ rValue.setdefault(lib, set()).add(soname)
if debug:
if not os.path.isfile(lib):
print "Missing library:", lib
@@ -367,18 +358,9 @@ class LinkageMap(object):
os.path.join(os.path.dirname(lib), soname)
return rValue
- def listConsumers(self):
- rValue = {}
- if not self._libs:
- self.rebuild()
- # Iterate over all objects within LinkageMap.
- for obj_key in self._obj_properties:
- rValue.setdefault(obj_key, self.findConsumers(obj_key=obj_key))
- return rValue
-
def listProviders(self):
"""
- Find the providers for all objects in LinkageMap.
+ Find the providers for all object keys in LinkageMap.
@rtype: dict (example:
{(123L, 456L): {'libbar.so': set(['/lib/libbar.so.1.5'])}})
@@ -399,6 +381,17 @@ class LinkageMap(object):
return rValue
def isMasterLink(self, obj):
+ """
+ Determine whether an object is a master link.
+
+ @param obj: absolute path to an object
+ @type obj: string (example: '/usr/bin/foo')
+ @rtype: Boolean
+ @return:
+ 1. True if obj is a master link
+ 2. False if obj is not a master link
+
+ """
basename = os.path.basename(obj)
obj_key = self._generateObjKey(obj)
if obj_key not in self._obj_properties:
@@ -407,6 +400,15 @@ class LinkageMap(object):
return (len(basename) < len(soname))
def listLibraryObjects(self):
+ """
+ Return a list of library objects.
+
+ Known limitation: library objects lacking an soname are not included.
+
+ @rtype: list of strings
+ @return: list of paths to all providers
+
+ """
rValue = []
if not self._libs:
self.rebuild()
@@ -417,6 +419,15 @@ class LinkageMap(object):
return rValue
def getSoname(self, obj):
+ """
+ Return the soname associated with an object.
+
+ @param obj: absolute path to an object
+ @type obj: string (example: '/usr/bin/bar')
+ @rtype: string
+ @return: soname
+
+ """
if not self._libs:
self.rebuild()
if obj not in self._obj_key_cache:
@@ -431,12 +442,17 @@ class LinkageMap(object):
with both, the obj_key is ignored. If called with neither, KeyError is
raised as if an invalid obj was passed.
- @param obj:
- @type obj:
- @param obj_key:
- @type obj_key:
- @rtype:
- @return:
+ In some cases, not all valid libraries are returned. This may occur when
+ an soname symlink referencing a library is in and object's runpath while
+ the actual library is not.
+
+ @param obj: absolute path to an object
+ @type obj: string (example: '/usr/bin/bar')
+ @param obj_key: key from LinkageMap._generateObjKey
+ @type obj_key: 2-tuple of longs or string
+ @rtype: dict (example: {'libbar.so': set(['/lib/libbar.so.1.5'])})
+ @return: The return value is a soname -> set-of-library-paths, where
+ set-of-library-paths satisfy soname.
"""
rValue = {}
@@ -455,17 +471,12 @@ class LinkageMap(object):
arch, needed, path, soname, objs = self._obj_properties[obj_key]
path = path.union(self._defpath)
- # XXX test this
- # path = set(realpath(x) for x in path)
for x in needed:
rValue[x] = set()
if x not in self._libs or arch not in self._libs[x]:
continue
for y in self._libs[x][arch]["providers"]:
objs = self._obj_properties[y][4]
- # XXX x is an soname, so it should never start with os.sep, right?
- #if x[0] == os.sep and realpath(x) == realpath(y):
- # rValue[x].add(y)
for o in objs:
if os.path.dirname(o) in path:
rValue[x].add(o)
@@ -480,12 +491,17 @@ class LinkageMap(object):
with both, the obj_key is ignored. If called with neither, KeyError is
raised as if an invalid obj was passed.
- @param obj:
- @type obj:
- @param obj_key:
- @type obj_key:
- @rtype:
- @return:
+ In some cases, not all consumers are returned. This may occur when
+ an soname symlink referencing a library is in and object's runpath while
+ the actual library is not.
+
+ @param obj: absolute path to an object
+ @type obj: string (example: '/usr/bin/bar')
+ @param obj_key: key from LinkageMap._generateObjKey
+ @type obj_key: 2-tuple of longs or string
+ @rtype: set of strings (example: )
+ @return: The return value is a soname -> set-of-library-paths, where
+ set-of-library-paths satisfy soname.
"""
rValue = set()
@@ -532,19 +548,12 @@ class LinkageMap(object):
for consumer_key in self._libs[soname][arch]["consumers"]:
_, _, path, _, consumer_objs = \
self._obj_properties[consumer_key]
- # XXX test this
- #path = [realpath(y) for y in path+self._defpath]
path = path.union(self._defpath)
- # XXX x is an soname, so it should never start with os.sep,
- # right?
- #if soname[0] == os.sep and realpath(soname) == realpath(obj):
- # rValue.add(x)
- #if realpath(obj_dir) in path:
- # rValue.add(x)
for consumer_obj in consumer_objs:
for directory in objs_dirs:
if directory in path:
rValue.add(consumer_obj)
+
return rValue
class vardbapi(dbapi):
--- vartree.py.2.2_rc8 2008-08-17 21:11:41.000000000 -0500
-+++ pym/portage/dbapi/vartree.py 2008-08-17 21:39:11.000000000 -0500
++++ pym/portage/dbapi/vartree.py 2008-08-17 23:33:23.000000000 -0500
@@ -143,10 +143,12 @@
self._dbapi = vardbapi
self._libs = {}
obj_properties = {}
lines = []
for cpv in self._dbapi.cpv_all():
-@@ -176,26 +178,56 @@
+@@ -176,29 +178,63 @@
# insufficient field length
continue
arch = fields[0]
+ def _generateObjKey(self, obj):
+ """
+ Generate obj key for a given object.
-
-- def listBrokenBinaries(self):
++
+ @param obj: path to an existing file
+ @type obj: string (example: '/usr/bin/bar')
-+ @rtype: 2-tuple of longs or string
-+ @return: If obj exists, a 2-tuple of obj's inode and device from a stat
-+ call is returned. Otherwise, the obj is returned.
-+
++ @rtype: 2-tuple of longs if obj exists. string if obj does not exist.
++ @return:
++ 1. 2-tuple of obj's inode and device from a stat call, if obj exists.
++ 2. string if obj does not exist.
+
+- def listBrokenBinaries(self):
+ """
+ try:
+ return os.stat(obj)[1:3]
+# from portage.output import teal
+# writemsg(bold(red("Error in ")) + \
+# bold(teal("_generateObjKey. Stat failed on %s" % obj)) + '\n')
++ # XXX do we need realpath?
+ return obj
+
+ def listBrokenBinaries(self, debug=False):
"""
Find binaries and their needed sonames, which have no providers.
-@@ -218,55 +250,56 @@
++ @param debug: Boolean to enable debug output
++ @type debug: Boolean
+ @rtype: dict (example: {'/usr/bin/foo': set(['libbar.so'])})
+ @return: The return value is an object -> set-of-sonames mapping, where
+ object is a broken binary and the set consists of sonames needed by
+@@ -208,7 +244,7 @@
+ class LibraryCache(object):
+
+ """
+- Caches sonames and realpaths associated with paths.
++ Caches properties associated with paths.
+
+ The purpose of this class is to prevent multiple calls of
+ os.path.realpath and os.path.isfile on the same paths.
+@@ -218,55 +254,56 @@
def __init__(cache_self):
cache_self.cache = {}
validLibraries = set()
# It could be the case that the library to satisfy the soname is
# not in the obj's runpath, but a symlink to the library is (eg
-@@ -274,29 +307,34 @@
+@@ -274,67 +311,60 @@
# does not catalog symlinks, broken or missing symlinks may go
# unnoticed. As a result of these cases, check that a file with
# the same name as the soname exists in obj's runpath.
+ validLibraries.add(cachedKey)
+ if debug and cachedKey not in \
+ set(map(self._obj_key_cache.get, libraries)):
++ # XXX This is most often due to soname symlinks not in
++ # a library's directory. We could catalog symlinks in
++ # LinkageMap to avoid checking for this edge case here.
print "Found provider outside of findProviders:", \
- os.path.join(d, soname), "->", cachedRealpath
+ os.path.join(directory, soname), "->", \
-+ self._obj_properties[cachedKey][4]
++ self._obj_properties[cachedKey][4], libraries
# A valid library has been found, so there is no need to
# continue.
break
# If no valid libraries have been found by this point, then
# there are no files named with the soname within obj's runpath,
# but if there are libraries (from the providers mapping), it is
-@@ -304,7 +342,8 @@
- # Thus possible symlinks and missing libraries are added to
- # rValue in order to emerge corrupt library packages.
+- # likely that symlinks or the actual libraries are missing.
+- # Thus possible symlinks and missing libraries are added to
+- # rValue in order to emerge corrupt library packages.
++ # likely that soname symlinks or the actual libraries are
++ # missing or broken. Thus those libraries are added to rValue
++ # in order to emerge corrupt library packages.
for lib in libraries:
- cachedSoname, cachedRealpath, cachedExists = cache.get(lib)
-+ cachedArch, cachedSoname, cachedKey, cachedExists = \
-+ cache.get(lib)
- if not cachedExists:
- # The library's package needs to be emerged to repair the
- # missing library.
-@@ -317,24 +356,33 @@
- # symlinks. This path is not guaranteed to exist, but it
- # follows the symlink convention found in the majority of
- # packages.
-+ # XXX merge this into block above
- rValue.setdefault(os.path.join(os.path.dirname(lib), \
- soname), set()).add(soname)
+- if not cachedExists:
+- # The library's package needs to be emerged to repair the
+- # missing library.
+- rValue.setdefault(lib, set()).add(soname)
+- else:
+- # A library providing the soname exists in the obj's
+- # runpath, but no file named as the soname exists, so add
+- # the path constructed from the lib's directory and the
+- # soname to rValue to fix cases of vanishing (or modified)
+- # symlinks. This path is not guaranteed to exist, but it
+- # follows the symlink convention found in the majority of
+- # packages.
+- rValue.setdefault(os.path.join(os.path.dirname(lib), \
+- soname), set()).add(soname)
++ rValue.setdefault(lib, set()).add(soname)
if debug:
- if not cachedExists:
+ if not os.path.isfile(lib):
else:
print "Possibly missing symlink:", \
os.path.join(os.path.dirname(lib), soname)
-+ return rValue
-
-+ def listConsumers(self):
-+ rValue = {}
-+ if not self._libs:
-+ self.rebuild()
-+ # Iterate over all objects within LinkageMap.
-+ for obj_key in self._obj_properties:
-+ rValue.setdefault(obj_key, self.findConsumers(obj_key=obj_key))
+-
return rValue
def listProviders(self):
"""
- Find the providers for all binaries.
-+ Find the providers for all objects in LinkageMap.
++ Find the providers for all object keys in LinkageMap.
@rtype: dict (example:
- {'/usr/bin/foo': {'libbar.so': set(['/lib/libbar.so.1.5'])}})
providers is a mapping of soname -> set-of-library-paths returned
from the findProviders method.
-@@ -342,118 +390,163 @@
+@@ -342,118 +372,190 @@
rValue = {}
if not self._libs:
self.rebuild()
return rValue
def isMasterLink(self, obj):
++ """
++ Determine whether an object is a master link.
++
++ @param obj: absolute path to an object
++ @type obj: string (example: '/usr/bin/foo')
++ @rtype: Boolean
++ @return:
++ 1. True if obj is a master link
++ 2. False if obj is not a master link
++
++ """
basename = os.path.basename(obj)
- if obj not in self._obj_properties:
- obj = os.path.realpath(obj)
-
+
def listLibraryObjects(self):
++ """
++ Return a list of library objects.
++
++ Known limitation: library objects lacking an soname are not included.
++
++ @rtype: list of strings
++ @return: list of paths to all providers
++
++ """
rValue = []
if not self._libs:
self.rebuild()
return rValue
def getSoname(self, obj):
++ """
++ Return the soname associated with an object.
++
++ @param obj: absolute path to an object
++ @type obj: string (example: '/usr/bin/bar')
++ @rtype: string
++ @return: soname
++
++ """
if not self._libs:
self.rebuild()
- if obj not in self._obj_properties:
+ with both, the obj_key is ignored. If called with neither, KeyError is
+ raised as if an invalid obj was passed.
+
-+ @param obj:
-+ @type obj:
-+ @param obj_key:
-+ @type obj_key:
-+ @rtype:
-+ @return:
++ In some cases, not all valid libraries are returned. This may occur when
++ an soname symlink referencing a library is in and object's runpath while
++ the actual library is not.
++
++ @param obj: absolute path to an object
++ @type obj: string (example: '/usr/bin/bar')
++ @param obj_key: key from LinkageMap._generateObjKey
++ @type obj_key: 2-tuple of longs or string
++ @rtype: dict (example: {'libbar.so': set(['/lib/libbar.so.1.5'])})
++ @return: The return value is a soname -> set-of-library-paths, where
++ set-of-library-paths satisfy soname.
+
+ """
+ rValue = {}
- real_path = os.path.realpath(p)
- realpath_cache[p] = real_path
- return real_path
--
++ if obj is not None:
++ obj_key = self._obj_key_cache.get(obj)
++ if obj_key not in self._obj_properties:
++ obj_key = self._generateObjKey(obj)
++ if obj_key not in self._obj_properties:
++ raise KeyError("%s (%s) not in object list" % (obj_key, obj))
++ elif obj_key not in self._obj_properties:
++ raise KeyError("%s not in object list" % obj_key)
+
- rValue = {}
- if obj not in self._obj_properties:
- obj = realpath(obj)
- path = path[:]
- path.extend(self._defpath)
- path = set(realpath(x) for x in path)
-+ if obj is not None:
-+ obj_key = self._obj_key_cache.get(obj)
-+ if obj_key not in self._obj_properties:
-+ obj_key = self._generateObjKey(obj)
-+ if obj_key not in self._obj_properties:
-+ raise KeyError("%s (%s) not in object list" % (obj_key, obj))
-+ elif obj_key not in self._obj_properties:
-+ raise KeyError("%s not in object list" % obj_key)
-+
+ arch, needed, path, soname, objs = self._obj_properties[obj_key]
+ path = path.union(self._defpath)
-+ # XXX test this
-+ # path = set(realpath(x) for x in path)
for x in needed:
rValue[x] = set()
if x not in self._libs or arch not in self._libs[x]:
- elif realpath(os.path.dirname(y)) in path:
- rValue[x].add(y)
+ objs = self._obj_properties[y][4]
-+ # XXX x is an soname, so it should never start with os.sep, right?
-+ #if x[0] == os.sep and realpath(x) == realpath(y):
-+ # rValue[x].add(y)
+ for o in objs:
+ if os.path.dirname(o) in path:
+ rValue[x].add(o)
+ with both, the obj_key is ignored. If called with neither, KeyError is
+ raised as if an invalid obj was passed.
+
-+ @param obj:
-+ @type obj:
-+ @param obj_key:
-+ @type obj_key:
-+ @rtype:
-+ @return:
++ In some cases, not all consumers are returned. This may occur when
++ an soname symlink referencing a library is in and object's runpath while
++ the actual library is not.
++
++ @param obj: absolute path to an object
++ @type obj: string (example: '/usr/bin/bar')
++ @param obj_key: key from LinkageMap._generateObjKey
++ @type obj_key: 2-tuple of longs or string
++ @rtype: set of strings (example: )
++ @return: The return value is a soname -> set-of-library-paths, where
++ set-of-library-paths satisfy soname.
+
+ """
+ rValue = set()
- if (obj_st.st_dev, obj_st.st_ino) != \
- (master_st.st_dev, master_st.st_ino):
- return set()
--
-- rValue = set()
-- for soname in self._libs:
-- for arch in self._libs[soname]:
-- if obj in self._libs[soname][arch]["providers"]:
-- for x in self._libs[soname][arch]["consumers"]:
-- path = self._obj_properties[x][2]
-- path = [realpath(y) for y in path+self._defpath]
-- if soname[0] == os.sep and realpath(soname) == realpath(obj):
-- rValue.add(x)
-- elif realpath(obj_dir) in path:
-- rValue.add(x)
+ if obj is not None:
+ soname = self._obj_properties[obj_key][3]
+ obj_dir = os.path.dirname(obj)
+ for consumer_key in self._libs[soname][arch]["consumers"]:
+ _, _, path, _, consumer_objs = \
+ self._obj_properties[consumer_key]
-+ # XXX test this
-+ #path = [realpath(y) for y in path+self._defpath]
+ path = path.union(self._defpath)
-+ # XXX x is an soname, so it should never start with os.sep,
-+ # right?
-+ #if soname[0] == os.sep and realpath(soname) == realpath(obj):
-+ # rValue.add(x)
-+ #if realpath(obj_dir) in path:
-+ # rValue.add(x)
+ for consumer_obj in consumer_objs:
+ for directory in objs_dirs:
+ if directory in path:
+ rValue.add(consumer_obj)
+
+- rValue = set()
+- for soname in self._libs:
+- for arch in self._libs[soname]:
+- if obj in self._libs[soname][arch]["providers"]:
+- for x in self._libs[soname][arch]["consumers"]:
+- path = self._obj_properties[x][2]
+- path = [realpath(y) for y in path+self._defpath]
+- if soname[0] == os.sep and realpath(soname) == realpath(obj):
+- rValue.add(x)
+- elif realpath(obj_dir) in path:
+- rValue.add(x)
return rValue
-
+