1 |
Make LinkageMapELF safely discard NEEDED.ELF.2 data when possible, |
2 |
in a manner consistent with PROVIDES_EXCLUDE and REQUIRES_EXCLUDE. |
3 |
Achieve this by intersection with PROVIDES and REQUIRES, which is |
4 |
equivalent to evaluating PROVIDES_EXCLUDE and REQUIRES_EXCLUDE, |
5 |
but simpler to do. Do not apply PROVIDES_EXCLUDE for entries that |
6 |
have non-empty needed (after REQUIRES_EXCLUDE has been applied), |
7 |
since that will require a significant number of additional changes |
8 |
to LinkageMapELF. |
9 |
|
10 |
X-Gentoo-Bug: 565792 |
11 |
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=565792 |
12 |
--- |
13 |
[PATCH v2] fixes the PROVIDES_EXCLUDE code to check if the entry |
14 |
has the necessary data to construct an SonameAtom |
15 |
|
16 |
pym/portage/util/_dyn_libs/LinkageMapELF.py | 46 +++++++++++++++++++++++++---- |
17 |
pym/portage/util/_dyn_libs/NeededEntry.py | 24 +++++++++++++++ |
18 |
2 files changed, 65 insertions(+), 5 deletions(-) |
19 |
|
20 |
diff --git a/pym/portage/util/_dyn_libs/LinkageMapELF.py b/pym/portage/util/_dyn_libs/LinkageMapELF.py |
21 |
index 63e2213..466fb94 100644 |
22 |
--- a/pym/portage/util/_dyn_libs/LinkageMapELF.py |
23 |
+++ b/pym/portage/util/_dyn_libs/LinkageMapELF.py |
24 |
@@ -11,6 +11,8 @@ from portage import _os_merge |
25 |
from portage import _unicode_decode |
26 |
from portage import _unicode_encode |
27 |
from portage.cache.mappings import slot_dict_class |
28 |
+from portage.dep.soname.parse import parse_soname_deps |
29 |
+from portage.dep.soname.SonameAtom import SonameAtom |
30 |
from portage.exception import CommandNotFound, InvalidData |
31 |
from portage.localization import _ |
32 |
from portage.util import getlibpaths |
33 |
@@ -225,7 +227,7 @@ class LinkageMapELF(object): |
34 |
for line in grabfile(include_file): |
35 |
lines.append((None, include_file, line)) |
36 |
|
37 |
- aux_keys = [self._needed_aux_key] |
38 |
+ aux_keys = [self._needed_aux_key, 'PROVIDES', 'REQUIRES'] |
39 |
can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK) |
40 |
if can_lock: |
41 |
self._dbapi.lock() |
42 |
@@ -233,10 +235,26 @@ class LinkageMapELF(object): |
43 |
for cpv in self._dbapi.cpv_all(): |
44 |
if exclude_pkgs is not None and cpv in exclude_pkgs: |
45 |
continue |
46 |
+ metadata = dict(zip(aux_keys, self._dbapi.aux_get(cpv, aux_keys))) |
47 |
+ soname_deps = {} |
48 |
+ |
49 |
+ for k in ('PROVIDES', 'REQUIRES'): |
50 |
+ try: |
51 |
+ soname_deps[k] = frozenset(parse_soname_deps(metadata[k])) |
52 |
+ except InvalidData as e: |
53 |
+ soname_deps[k] = None |
54 |
+ location = self._dbapi.getpath(cpv, filename=k) |
55 |
+ writemsg_level(_("\nInvalid data in %s: %s\n\n") % |
56 |
+ (location, e), level=logging.ERROR, noiselevel=-1) |
57 |
+ |
58 |
+ provides = soname_deps['PROVIDES'] |
59 |
+ requires = soname_deps['REQUIRES'] |
60 |
+ |
61 |
needed_file = self._dbapi.getpath(cpv, |
62 |
filename=self._needed_aux_key) |
63 |
+ |
64 |
for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines(): |
65 |
- lines.append((cpv, needed_file, line)) |
66 |
+ lines.append((cpv, provides, requires, needed_file, line)) |
67 |
finally: |
68 |
if can_lock: |
69 |
self._dbapi.unlock() |
70 |
@@ -290,7 +308,8 @@ class LinkageMapELF(object): |
71 |
continue |
72 |
fields[1] = fields[1][root_len:] |
73 |
owner = plibs.pop(fields[1], None) |
74 |
- lines.append((owner, "scanelf", ";".join(fields))) |
75 |
+ lines.append((owner, None, None, |
76 |
+ "scanelf", ";".join(fields))) |
77 |
proc.wait() |
78 |
proc.stdout.close() |
79 |
|
80 |
@@ -302,13 +321,14 @@ class LinkageMapELF(object): |
81 |
# is important in order to prevent findConsumers from raising |
82 |
# an unwanted KeyError. |
83 |
for x, cpv in plibs.items(): |
84 |
- lines.append((cpv, "plibs", ";".join(['', x, '', '', '']))) |
85 |
+ lines.append((cpv, None, None, |
86 |
+ "plibs", ";".join(['', x, '', '', '']))) |
87 |
|
88 |
# Share identical frozenset instances when available, |
89 |
# in order to conserve memory. |
90 |
frozensets = {} |
91 |
|
92 |
- for owner, location, l in lines: |
93 |
+ for owner, provides, requires, location, l in lines: |
94 |
l = l.rstrip("\n") |
95 |
if not l: |
96 |
continue |
97 |
@@ -335,6 +355,22 @@ class LinkageMapELF(object): |
98 |
if arch is None: |
99 |
arch = _approx_multilib_categories.get( |
100 |
entry.arch, entry.arch) |
101 |
+ # initialize multilib_category for intersect_requires |
102 |
+ entry.multilib_category = arch |
103 |
+ |
104 |
+ if requires is not None: |
105 |
+ # Apply REQUIRES_EXCLUDE. |
106 |
+ entry = entry.intersect_requires(requires) |
107 |
+ |
108 |
+ if provides is not None: |
109 |
+ # Apply PROVIDES_EXCLUDE. Don't exclude entries with |
110 |
+ # non-empty entry.needed, since we want to ensure that |
111 |
+ # entry.needed is satisfied. TODO: Apply PROVIDES_EXCLUDE |
112 |
+ # to entries with non-empty entry.needed. |
113 |
+ if (not entry.needed and entry.soname and |
114 |
+ entry.multilib_category and SonameAtom( |
115 |
+ entry.multilib_category, entry.soname) not in provides): |
116 |
+ continue |
117 |
|
118 |
obj = entry.filename |
119 |
soname = entry.soname |
120 |
diff --git a/pym/portage/util/_dyn_libs/NeededEntry.py b/pym/portage/util/_dyn_libs/NeededEntry.py |
121 |
index c52cfce..824f94c 100644 |
122 |
--- a/pym/portage/util/_dyn_libs/NeededEntry.py |
123 |
+++ b/pym/portage/util/_dyn_libs/NeededEntry.py |
124 |
@@ -6,6 +6,7 @@ from __future__ import unicode_literals |
125 |
import sys |
126 |
|
127 |
from portage import _encodings, _unicode_encode |
128 |
+from portage.dep.soname.SonameAtom import SonameAtom |
129 |
from portage.exception import InvalidData |
130 |
from portage.localization import _ |
131 |
|
132 |
@@ -57,6 +58,29 @@ class NeededEntry(object): |
133 |
|
134 |
return obj |
135 |
|
136 |
+ def intersect_requires(self, requires): |
137 |
+ """ |
138 |
+ Return a new instance, filtering out data that does not intersect |
139 |
+ with the given requires data. This is a convenient way to account |
140 |
+ for REQUIRES_EXCLUDE, since the intersection operation will filter |
141 |
+ out anything that REQUIRES_EXCLUDE would exclude. |
142 |
+ |
143 |
+ @param requires: required soname atoms |
144 |
+ @type requires: frozenset |
145 |
+ """ |
146 |
+ obj = self.__class__() |
147 |
+ obj.arch = self.arch |
148 |
+ obj.filename = self.filename |
149 |
+ obj.multilib_category = self.multilib_category |
150 |
+ obj.soname = self.soname |
151 |
+ obj.runpaths = self.runpaths |
152 |
+ filtered_needed = [] |
153 |
+ for soname in self.needed: |
154 |
+ if SonameAtom(self.multilib_category, soname) in requires: |
155 |
+ filtered_needed.append(soname) |
156 |
+ obj.needed = tuple(filtered_needed) |
157 |
+ return obj |
158 |
+ |
159 |
def __str__(self): |
160 |
""" |
161 |
Format this entry for writing to a NEEDED.ELF.2 file. |
162 |
-- |
163 |
2.4.9 |