1 |
Author: zmedico |
2 |
Date: 2008-10-28 23:04:14 +0000 (Tue, 28 Oct 2008) |
3 |
New Revision: 11740 |
4 |
|
5 |
Modified: |
6 |
main/trunk/pym/portage/dbapi/vartree.py |
7 |
Log: |
8 |
Bug #238957 - When removing unneeded preserved libs inside dblink.unmerge(), |
9 |
use a digraph to properly track consumer relationships between preserved libs. |
10 |
This fixes cases where preserved libs failed to be removed due to being |
11 |
consumed by other preserved libs. |
12 |
|
13 |
|
14 |
Modified: main/trunk/pym/portage/dbapi/vartree.py |
15 |
=================================================================== |
16 |
--- main/trunk/pym/portage/dbapi/vartree.py 2008-10-28 21:22:22 UTC (rev 11739) |
17 |
+++ main/trunk/pym/portage/dbapi/vartree.py 2008-10-28 23:04:14 UTC (rev 11740) |
18 |
@@ -23,7 +23,7 @@ |
19 |
grabfile, grabdict, normalize_path, new_protect_filename, getlibpaths |
20 |
from portage.versions import pkgsplit, catpkgsplit, catsplit, best, pkgcmp |
21 |
|
22 |
-from portage import listdir, dep_expand, flatten, key_expand, \ |
23 |
+from portage import listdir, dep_expand, digraph, flatten, key_expand, \ |
24 |
doebuild_environment, doebuild, env_update, prepare_build_dirs, \ |
25 |
abssymlink, movefile, _movefile, bsd_chflags, cpv_getkey |
26 |
|
27 |
@@ -208,6 +208,16 @@ |
28 |
""" |
29 |
return isinstance(self._key, tuple) |
30 |
|
31 |
+ class _LibGraphNode(_ObjectKey): |
32 |
+ __slots__ = ("alt_paths",) |
33 |
+ |
34 |
+ def __init__(self, obj, root): |
35 |
+ LinkageMap._ObjectKey.__init__(self, obj, root) |
36 |
+ self.alt_paths = set() |
37 |
+ |
38 |
+ def __str__(self): |
39 |
+ return str(sorted(self.alt_paths)) |
40 |
+ |
41 |
def rebuild(self, include_file=None): |
42 |
root = self._root |
43 |
libs = {} |
44 |
@@ -1906,7 +1916,8 @@ |
45 |
writemsg("!!! FAILED prerm: %s\n" % retval, noiselevel=-1) |
46 |
|
47 |
self._unmerge_pkgfiles(pkgfiles, others_in_slot) |
48 |
- |
49 |
+ self._clear_contents_cache() |
50 |
+ |
51 |
# Remove the registration of preserved libs for this pkg instance |
52 |
plib_registry = self.vartree.dbapi.plib_registry |
53 |
plib_registry.unregister(self.mycpv, self.settings["SLOT"], |
54 |
@@ -1930,60 +1941,64 @@ |
55 |
self.vartree.dbapi.linkmap.rebuild() |
56 |
|
57 |
# remove preserved libraries that don't have any consumers left |
58 |
- # FIXME: this code is quite ugly and can likely be optimized in several ways |
59 |
+ # Since preserved libraries can be consumers of other preserved |
60 |
+ # libraries, use a graph to track consumer relationships. |
61 |
plib_dict = plib_registry.getPreservedLibs() |
62 |
- for cpv in plib_dict: |
63 |
- plib_dict[cpv].sort() |
64 |
- # for the loop below to work correctly, we need all |
65 |
- # symlinks to come before the actual files, such that |
66 |
- # the recorded symlinks (sonames) will be resolved into |
67 |
- # their real target before the object is found not to be |
68 |
- # in the reverse NEEDED map |
69 |
- def symlink_compare(x, y): |
70 |
- x = os.path.join(self.myroot, x.lstrip(os.path.sep)) |
71 |
- y = os.path.join(self.myroot, y.lstrip(os.path.sep)) |
72 |
- if os.path.islink(x): |
73 |
- if os.path.islink(y): |
74 |
- return 0 |
75 |
- else: |
76 |
- return -1 |
77 |
- elif os.path.islink(y): |
78 |
- return 1 |
79 |
+ lib_graph = digraph() |
80 |
+ preserved_nodes = set() |
81 |
+ root = self.myroot |
82 |
+ for plibs in plib_dict.itervalues(): |
83 |
+ for f in plibs: |
84 |
+ preserved_node = LinkageMap._LibGraphNode(f, root) |
85 |
+ if not preserved_node.file_exists(): |
86 |
+ continue |
87 |
+ existing_node = lib_graph.get(preserved_node) |
88 |
+ if existing_node is not None: |
89 |
+ preserved_node = existing_node |
90 |
else: |
91 |
- return 0 |
92 |
+ lib_graph.add(preserved_node, None) |
93 |
+ preserved_node.alt_paths.add(f) |
94 |
+ preserved_nodes.add(preserved_node) |
95 |
+ for c in self.vartree.dbapi.linkmap.findConsumers(f): |
96 |
+ if self.isowner(c, root): |
97 |
+ # TODO: Remove this case since it shouldn't be |
98 |
+ # necessary. This seems to be a false positive |
99 |
+ # returned from LinkageMap.findConsumers(). |
100 |
+ continue |
101 |
+ consumer_node = LinkageMap._LibGraphNode(c, root) |
102 |
+ if not consumer_node.file_exists(): |
103 |
+ continue |
104 |
+ # Note that consumers may also be providers. |
105 |
+ existing_node = lib_graph.get(consumer_node) |
106 |
+ if existing_node is not None: |
107 |
+ consumer_node = existing_node |
108 |
+ consumer_node.alt_paths.add(c) |
109 |
+ lib_graph.add(preserved_node, consumer_node) |
110 |
|
111 |
- plib_dict[cpv].sort(symlink_compare) |
112 |
- for f in plib_dict[cpv]: |
113 |
- f_abs = os.path.join(self.myroot, f.lstrip(os.path.sep)) |
114 |
- if not os.path.exists(f_abs): |
115 |
- continue |
116 |
- unlink_list = [] |
117 |
- consumers = self.vartree.dbapi.linkmap.findConsumers(f) |
118 |
- if not consumers: |
119 |
- unlink_list.append(f_abs) |
120 |
+ while not lib_graph.empty(): |
121 |
+ root_nodes = preserved_nodes.intersection(lib_graph.root_nodes()) |
122 |
+ if not root_nodes: |
123 |
+ break |
124 |
+ lib_graph.difference_update(root_nodes) |
125 |
+ unlink_list = set() |
126 |
+ for node in root_nodes: |
127 |
+ unlink_list.update(node.alt_paths) |
128 |
+ unlink_list = sorted(unlink_list) |
129 |
+ for obj in unlink_list: |
130 |
+ obj = os.path.join(root, obj.lstrip(os.sep)) |
131 |
+ if os.path.islink(obj): |
132 |
+ obj_type = "sym" |
133 |
else: |
134 |
- keep=False |
135 |
- for c in consumers: |
136 |
- c = os.path.join(self.myroot, |
137 |
- c.lstrip(os.path.sep)) |
138 |
- if c not in self.getcontents(): |
139 |
- keep=True |
140 |
- break |
141 |
- if not keep: |
142 |
- unlink_list.append(f_abs) |
143 |
- for obj in unlink_list: |
144 |
- try: |
145 |
- if os.path.islink(obj): |
146 |
- obj_type = "sym" |
147 |
- else: |
148 |
- obj_type = "obj" |
149 |
- os.unlink(obj) |
150 |
- showMessage("<<< !needed %s %s\n" % (obj_type, obj)) |
151 |
- except OSError, e: |
152 |
- if e.errno == errno.ENOENT: |
153 |
- pass |
154 |
- else: |
155 |
- raise e |
156 |
+ obj_type = "obj" |
157 |
+ try: |
158 |
+ os.unlink(obj) |
159 |
+ except OSError, e: |
160 |
+ if e.errno != errno.ENOENT: |
161 |
+ raise |
162 |
+ del e |
163 |
+ else: |
164 |
+ showMessage("<<< !needed %s %s\n" % (obj_type, obj)) |
165 |
+ |
166 |
plib_registry.pruneNonExisting() |
167 |
|
168 |
finally: |