Bug #245362 - Use tuples of (device, inode) for all path comparisons inside
authorZac Medico <zmedico@gentoo.org>
Tue, 4 Nov 2008 07:40:34 +0000 (07:40 -0000)
committerZac Medico <zmedico@gentoo.org>
Tue, 4 Nov 2008 07:40:34 +0000 (07:40 -0000)
LinkageMap, so that they work regardless of path differences due to symlinked
directories. TODO: Fix other preserve-libs code, such as
dblink._preserve_libs(), to use this approach for path comparisons.

svn path=/main/trunk/; revision=11806

pym/portage/dbapi/vartree.py
pym/portage/util.py

index 0361bb3d96cda6af5773bc90ba2561d95af813ed..f88431ee0463d362cc1adea0aa29b39343b1e334 100644 (file)
@@ -149,8 +149,23 @@ class LinkageMap(object):
                self._root = self._dbapi.root
                self._libs = {}
                self._obj_properties = {}
-               self._defpath = set(getlibpaths(self._root))
                self._obj_key_cache = {}
+               self._defpath = set()
+               self._path_key_cache = {}
+
+       def _clear_cache(self):
+               self._libs.clear()
+               self._obj_properties.clear()
+               self._obj_key_cache.clear()
+               self._defpath.clear()
+               self._path_key_cache.clear()
+
+       def _path_key(self, path):
+               key = self._path_key_cache.get(path)
+               if key is None:
+                       key = self._ObjectKey(path, self._root)
+                       self._path_key_cache[path] = key
+               return key
 
        class _ObjectKey(object):
 
@@ -222,10 +237,12 @@ class LinkageMap(object):
 
        def rebuild(self, exclude_pkgs=None, include_file=None):
                root = self._root
-               self._defpath = set(getlibpaths(root))
-               libs = {}
-               obj_key_cache = {}
-               obj_properties = {}
+               self._clear_cache()
+               self._defpath.update(getlibpaths(self._root))
+               libs = self._libs
+               obj_key_cache = self._obj_key_cache
+               obj_properties = self._obj_properties
+
                lines = []
                for cpv in self._dbapi.cpv_all():
                        if exclude_pkgs is not None and cpv in exclude_pkgs:
@@ -259,8 +276,7 @@ class LinkageMap(object):
                        obj = fields[1]
                        obj_key = self._ObjectKey(obj, root)
                        soname = fields[2]
-                       path = set([
-                               normalize_path(os.path.join(self._root, x.lstrip(os.path.sep)))
+                       path = set([normalize_path(x) \
                                for x in filter(None, fields[3].replace(
                                "${ORIGIN}", os.path.dirname(obj)).replace(
                                "$ORIGIN", os.path.dirname(obj)).split(":"))])
@@ -281,10 +297,6 @@ class LinkageMap(object):
                        obj_properties.setdefault(obj_key, \
                                        (arch, needed, path, soname, set()))[4].add(obj)
 
-               self._libs = libs
-               self._obj_properties = obj_properties
-               self._obj_key_cache = obj_key_cache
-
        def listBrokenBinaries(self, debug=False):
                """
                Find binaries and their needed sonames, which have no providers.
@@ -530,7 +542,7 @@ class LinkageMap(object):
                                        raise KeyError("%s (%s) not in object list" % (obj_key, obj))
 
                arch, needed, path, _, _ = self._obj_properties[obj_key]
-               path = path.union(self._defpath)
+               path_keys = set(self._path_key(x) for x in path.union(self._defpath))
                for soname in needed:
                        rValue[soname] = set()
                        if soname not in self._libs or arch not in self._libs[soname]:
@@ -540,8 +552,7 @@ class LinkageMap(object):
                        for provider_key in self._libs[soname][arch]["providers"]:
                                providers = self._obj_properties[provider_key][4]
                                for provider in providers:
-                                       if os.path.join(self._root,
-                                               os.path.dirname(provider).lstrip(os.path.sep)) in path:
+                                       if self._path_key(os.path.dirname(provider)) in path_keys:
                                                rValue[soname].add(provider)
                return rValue
 
@@ -584,10 +595,6 @@ class LinkageMap(object):
                                if obj_key not in self._obj_properties:
                                        raise KeyError("%s (%s) not in object list" % (obj_key, obj))
 
-               # Determine the directory(ies) from the set of objects.
-               objs_dirs = set(os.path.join(self._root,
-                       os.path.dirname(x).lstrip(os.sep)) for x in objs)
-
                # If there is another version of this lib with the
                # same soname and the master link points to that
                # other version, this lib will be shadowed and won't
@@ -606,6 +613,10 @@ class LinkageMap(object):
                                        (master_st.st_dev, master_st.st_ino):
                                        return set()
 
+               # Determine the directory(ies) from the set of objects.
+               objs_dir_keys = set(self._path_key(os.path.dirname(x)) for x in objs)
+               defpath_keys = set(self._path_key(x) for x in self._defpath)
+
                arch, _, _, soname, _ = self._obj_properties[obj_key]
                if soname in self._libs and arch in self._libs[soname]:
                        # For each potential consumer, add it to rValue if an object from the
@@ -613,8 +624,8 @@ class LinkageMap(object):
                        for consumer_key in self._libs[soname][arch]["consumers"]:
                                _, _, path, _, consumer_objs = \
                                                self._obj_properties[consumer_key]
-                               path = path.union(self._defpath)
-                               if objs_dirs.intersection(path):
+                               path_keys = defpath_keys.union(self._path_key(x) for x in path)
+                               if objs_dir_keys.intersection(path_keys):
                                        rValue.update(consumer_objs)
                return rValue
 
index 481c15bbc268d6d15bb45c69ee484eb89d22757b..ab72140703f130bc9ac376f9e399a428a47f8a54 100644 (file)
@@ -1208,8 +1208,4 @@ def getlibpaths(root):
        rval.append("/usr/lib")
        rval.append("/lib")
 
-       rval = [normalize_path(os.path.join(root, x.lstrip(os.path.sep))) \
-               for x in rval if x]
-
-       return rval
-       
+       return [normalize_path(x) for x in rval if x]