1 |
Author: zmedico |
2 |
Date: 2008-10-30 07:46:32 +0000 (Thu, 30 Oct 2008) |
3 |
New Revision: 11748 |
4 |
|
5 |
Modified: |
6 |
main/trunk/pym/portage/dbapi/vartree.py |
7 |
Log: |
8 |
Bug # 225429 - Try to remove unneeded preserved libs just before returning |
9 |
from dblink.treewalk(), after the library path has been updated. This is |
10 |
intended to remove unneeded preserved libs after a gcc upgrade. TODO: Figure |
11 |
out why libgomp.so.1 still isn't properly removed. |
12 |
|
13 |
|
14 |
Modified: main/trunk/pym/portage/dbapi/vartree.py |
15 |
=================================================================== |
16 |
--- main/trunk/pym/portage/dbapi/vartree.py 2008-10-30 03:37:55 UTC (rev 11747) |
17 |
+++ main/trunk/pym/portage/dbapi/vartree.py 2008-10-30 07:46:32 UTC (rev 11748) |
18 |
@@ -1953,118 +1953,21 @@ |
19 |
self.vartree.dbapi.linkmap.rebuild(exclude_pkgs=(self.mycpv,)) |
20 |
|
21 |
# remove preserved libraries that don't have any consumers left |
22 |
- # Since preserved libraries can be consumers of other preserved |
23 |
- # libraries, use a graph to track consumer relationships. |
24 |
- plib_dict = plib_registry.getPreservedLibs() |
25 |
- lib_graph = digraph() |
26 |
- preserved_nodes = set() |
27 |
- preserved_paths = set() |
28 |
- path_cpv_map = {} |
29 |
- path_node_map = {} |
30 |
- root = self.myroot |
31 |
- |
32 |
- def path_to_node(path): |
33 |
- node = path_node_map.get(path) |
34 |
- if node is None: |
35 |
- node = LinkageMap._LibGraphNode(path, root) |
36 |
- alt_path_node = lib_graph.get(node) |
37 |
- if alt_path_node is not None: |
38 |
- node = alt_path_node |
39 |
- node.alt_paths.add(path) |
40 |
- path_node_map[path] = node |
41 |
- return node |
42 |
- |
43 |
- linkmap = self.vartree.dbapi.linkmap |
44 |
- for cpv, plibs in plib_dict.iteritems(): |
45 |
- for f in plibs: |
46 |
- path_cpv_map[f] = cpv |
47 |
- preserved_node = path_to_node(f) |
48 |
- if not preserved_node.file_exists(): |
49 |
+ cpv_lib_map = self._find_unused_preserved_libs() |
50 |
+ if cpv_lib_map: |
51 |
+ self._remove_preserved_libs(cpv_lib_map) |
52 |
+ for cpv, removed in cpv_lib_map.iteritems(): |
53 |
+ if not self.vartree.dbapi.cpv_exists(cpv): |
54 |
+ for dblnk in others_in_slot: |
55 |
+ if dblnk.mycpv == cpv: |
56 |
+ # This one just got merged so it doesn't |
57 |
+ # register with cpv_exists() yet. |
58 |
+ self.vartree.dbapi.removeFromContents( |
59 |
+ dblnk, removed) |
60 |
+ break |
61 |
continue |
62 |
- lib_graph.add(preserved_node, None) |
63 |
- preserved_paths.add(f) |
64 |
- preserved_nodes.add(preserved_node) |
65 |
- for c in self.vartree.dbapi.linkmap.findConsumers(f): |
66 |
- consumer_node = path_to_node(c) |
67 |
- if not consumer_node.file_exists(): |
68 |
- continue |
69 |
- # Note that consumers may also be providers. |
70 |
- lib_graph.add(preserved_node, consumer_node) |
71 |
+ self.vartree.dbapi.removeFromContents(cpv, removed) |
72 |
|
73 |
- # Eliminate consumers having providers with the same soname as an |
74 |
- # installed library that is not preserved. This eliminates |
75 |
- # libraries that are erroneously preserved due to a move from one |
76 |
- # directory to another. |
77 |
- provider_cache = {} |
78 |
- for preserved_node in preserved_nodes: |
79 |
- soname = linkmap.getSoname(preserved_node) |
80 |
- for consumer_node in lib_graph.parent_nodes(preserved_node): |
81 |
- if consumer_node in preserved_nodes: |
82 |
- continue |
83 |
- providers = provider_cache.get(consumer_node) |
84 |
- if providers is None: |
85 |
- providers = linkmap.findProviders(consumer_node) |
86 |
- provider_cache[consumer_node] = providers |
87 |
- providers = providers.get(soname) |
88 |
- if providers is None: |
89 |
- continue |
90 |
- for provider in providers: |
91 |
- if provider in preserved_paths: |
92 |
- continue |
93 |
- provider_node = path_to_node(provider) |
94 |
- if not provider_node.file_exists(): |
95 |
- continue |
96 |
- if provider_node in preserved_nodes: |
97 |
- continue |
98 |
- # An alternative provider seems to be |
99 |
- # installed, so drop this edge. |
100 |
- lib_graph.remove_edge(preserved_node, consumer_node) |
101 |
- break |
102 |
- |
103 |
- removed_for_cpv = {} |
104 |
- while not lib_graph.empty(): |
105 |
- root_nodes = preserved_nodes.intersection(lib_graph.root_nodes()) |
106 |
- if not root_nodes: |
107 |
- break |
108 |
- lib_graph.difference_update(root_nodes) |
109 |
- unlink_list = set() |
110 |
- for node in root_nodes: |
111 |
- unlink_list.update(node.alt_paths) |
112 |
- unlink_list = sorted(unlink_list) |
113 |
- for obj in unlink_list: |
114 |
- cpv = path_cpv_map[obj] |
115 |
- removed = removed_for_cpv.get(cpv) |
116 |
- if removed is None: |
117 |
- removed = set() |
118 |
- removed_for_cpv[cpv] = removed |
119 |
- removed.add(obj) |
120 |
- obj = os.path.join(root, obj.lstrip(os.sep)) |
121 |
- if os.path.islink(obj): |
122 |
- obj_type = "sym" |
123 |
- else: |
124 |
- obj_type = "obj" |
125 |
- try: |
126 |
- os.unlink(obj) |
127 |
- except OSError, e: |
128 |
- if e.errno != errno.ENOENT: |
129 |
- raise |
130 |
- del e |
131 |
- else: |
132 |
- showMessage("<<< !needed %s %s\n" % (obj_type, obj)) |
133 |
- |
134 |
- for cpv, removed in removed_for_cpv.iteritems(): |
135 |
- if not self.vartree.dbapi.cpv_exists(cpv): |
136 |
- for dblnk in others_in_slot: |
137 |
- if dblnk.mycpv == cpv: |
138 |
- # This one just got merged so it doesn't |
139 |
- # register with cpv_exists() yet. |
140 |
- self.vartree.dbapi.removeFromContents(dblnk, removed) |
141 |
- break |
142 |
- continue |
143 |
- self.vartree.dbapi.removeFromContents(cpv, removed) |
144 |
- |
145 |
- plib_registry.pruneNonExisting() |
146 |
- |
147 |
finally: |
148 |
if builddir_lock: |
149 |
try: |
150 |
@@ -2636,8 +2539,143 @@ |
151 |
# keep track of the libs we preserved |
152 |
self.vartree.dbapi.plib_registry.register(self.mycpv, self.settings["SLOT"], counter, preserve_paths) |
153 |
|
154 |
- del preserve_paths |
155 |
- |
156 |
+ def _find_unused_preserved_libs(self): |
157 |
+ """ |
158 |
+ Find preserved libraries that don't have any consumers left. |
159 |
+ """ |
160 |
+ |
161 |
+ # Since preserved libraries can be consumers of other preserved |
162 |
+ # libraries, use a graph to track consumer relationships. |
163 |
+ plib_dict = self.vartree.dbapi.plib_registry.getPreservedLibs() |
164 |
+ lib_graph = digraph() |
165 |
+ preserved_nodes = set() |
166 |
+ preserved_paths = set() |
167 |
+ path_cpv_map = {} |
168 |
+ path_node_map = {} |
169 |
+ root = self.myroot |
170 |
+ |
171 |
+ def path_to_node(path): |
172 |
+ node = path_node_map.get(path) |
173 |
+ if node is None: |
174 |
+ node = LinkageMap._LibGraphNode(path, root) |
175 |
+ alt_path_node = lib_graph.get(node) |
176 |
+ if alt_path_node is not None: |
177 |
+ node = alt_path_node |
178 |
+ node.alt_paths.add(path) |
179 |
+ path_node_map[path] = node |
180 |
+ return node |
181 |
+ |
182 |
+ linkmap = self.vartree.dbapi.linkmap |
183 |
+ for cpv, plibs in plib_dict.iteritems(): |
184 |
+ for f in plibs: |
185 |
+ path_cpv_map[f] = cpv |
186 |
+ preserved_node = path_to_node(f) |
187 |
+ if not preserved_node.file_exists(): |
188 |
+ continue |
189 |
+ lib_graph.add(preserved_node, None) |
190 |
+ preserved_paths.add(f) |
191 |
+ preserved_nodes.add(preserved_node) |
192 |
+ for c in self.vartree.dbapi.linkmap.findConsumers(f): |
193 |
+ consumer_node = path_to_node(c) |
194 |
+ if not consumer_node.file_exists(): |
195 |
+ continue |
196 |
+ # Note that consumers may also be providers. |
197 |
+ lib_graph.add(preserved_node, consumer_node) |
198 |
+ |
199 |
+ # Eliminate consumers having providers with the same soname as an |
200 |
+ # installed library that is not preserved. This eliminates |
201 |
+ # libraries that are erroneously preserved due to a move from one |
202 |
+ # directory to another. |
203 |
+ provider_cache = {} |
204 |
+ for preserved_node in preserved_nodes: |
205 |
+ soname = linkmap.getSoname(preserved_node) |
206 |
+ for consumer_node in lib_graph.parent_nodes(preserved_node): |
207 |
+ if consumer_node in preserved_nodes: |
208 |
+ continue |
209 |
+ providers = provider_cache.get(consumer_node) |
210 |
+ if providers is None: |
211 |
+ providers = linkmap.findProviders(consumer_node) |
212 |
+ provider_cache[consumer_node] = providers |
213 |
+ providers = providers.get(soname) |
214 |
+ if providers is None: |
215 |
+ continue |
216 |
+ for provider in providers: |
217 |
+ if provider in preserved_paths: |
218 |
+ continue |
219 |
+ provider_node = path_to_node(provider) |
220 |
+ if not provider_node.file_exists(): |
221 |
+ continue |
222 |
+ if provider_node in preserved_nodes: |
223 |
+ continue |
224 |
+ # An alternative provider seems to be |
225 |
+ # installed, so drop this edge. |
226 |
+ lib_graph.remove_edge(preserved_node, consumer_node) |
227 |
+ break |
228 |
+ |
229 |
+ cpv_lib_map = {} |
230 |
+ while not lib_graph.empty(): |
231 |
+ root_nodes = preserved_nodes.intersection(lib_graph.root_nodes()) |
232 |
+ if not root_nodes: |
233 |
+ break |
234 |
+ lib_graph.difference_update(root_nodes) |
235 |
+ unlink_list = set() |
236 |
+ for node in root_nodes: |
237 |
+ unlink_list.update(node.alt_paths) |
238 |
+ unlink_list = sorted(unlink_list) |
239 |
+ for obj in unlink_list: |
240 |
+ cpv = path_cpv_map[obj] |
241 |
+ removed = cpv_lib_map.get(cpv) |
242 |
+ if removed is None: |
243 |
+ removed = set() |
244 |
+ cpv_lib_map[cpv] = removed |
245 |
+ removed.add(obj) |
246 |
+ |
247 |
+ return cpv_lib_map |
248 |
+ |
249 |
+ def _remove_preserved_libs(self, cpv_lib_map): |
250 |
+ """ |
251 |
+ Remove files returned from _find_unused_preserved_libs(). |
252 |
+ """ |
253 |
+ |
254 |
+ files_to_remove = set() |
255 |
+ for files in cpv_lib_map.itervalues(): |
256 |
+ files_to_remove.update(files) |
257 |
+ files_to_remove = sorted(files_to_remove) |
258 |
+ showMessage = self._display_merge |
259 |
+ root = self.myroot |
260 |
+ |
261 |
+ parent_dirs = set() |
262 |
+ for obj in files_to_remove: |
263 |
+ obj = os.path.join(root, obj.lstrip(os.sep)) |
264 |
+ parent_dirs.add(os.path.dirname(obj)) |
265 |
+ if os.path.islink(obj): |
266 |
+ obj_type = "sym" |
267 |
+ else: |
268 |
+ obj_type = "obj" |
269 |
+ try: |
270 |
+ os.unlink(obj) |
271 |
+ except OSError, e: |
272 |
+ if e.errno != errno.ENOENT: |
273 |
+ raise |
274 |
+ del e |
275 |
+ else: |
276 |
+ showMessage("<<< !needed %s %s\n" % (obj_type, obj)) |
277 |
+ |
278 |
+ # Remove empty parent directories if possible. |
279 |
+ while parent_dirs: |
280 |
+ x = parent_dirs.pop() |
281 |
+ while True: |
282 |
+ try: |
283 |
+ os.rmdir(x) |
284 |
+ except OSError: |
285 |
+ break |
286 |
+ prev = x |
287 |
+ x = os.path.dirname(x) |
288 |
+ if x == prev: |
289 |
+ break |
290 |
+ |
291 |
+ self.vartree.dbapi.plib_registry.pruneNonExisting() |
292 |
+ |
293 |
def _collision_protect(self, srcroot, destroot, mypkglist, mycontents): |
294 |
collision_ignore = set([normalize_path(myignore) for myignore in \ |
295 |
shlex.split(self.settings.get("COLLISION_IGNORE", ""))]) |
296 |
@@ -3289,6 +3327,17 @@ |
297 |
contents=contents, env=self.settings.environ(), |
298 |
writemsg_level=self._display_merge) |
299 |
|
300 |
+ # For gcc upgrades, preserved libs have to be removed after the |
301 |
+ # the library path has been updated. |
302 |
+ self.vartree.dbapi.linkmap.rebuild() |
303 |
+ cpv_lib_map = self._find_unused_preserved_libs() |
304 |
+ if cpv_lib_map: |
305 |
+ self._remove_preserved_libs(cpv_lib_map) |
306 |
+ for cpv, removed in cpv_lib_map.iteritems(): |
307 |
+ if not self.vartree.dbapi.cpv_exists(cpv): |
308 |
+ continue |
309 |
+ self.vartree.dbapi.removeFromContents(cpv, removed) |
310 |
+ |
311 |
return os.EX_OK |
312 |
|
313 |
def mergeme(self, srcroot, destroot, outfile, secondhand, stufftomerge, cfgfiledict, thismtime): |