Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH v4] LinkageMapELF: account for {PROVIDES,REQUIRES}_EXCLUDE (bug 565792)
Date: Mon, 16 Nov 2015 01:34:14
Message-Id: 1447637630-18863-1-git-send-email-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH] LinkageMapELF: account for {PROVIDES,REQUIRES}_EXCLUDE (bug 565792) by Zac Medico
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

Replies