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