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 v3] LinkageMapELF: account for {PROVIDES,REQUIRES}_EXCLUDE (bug 565792)
Date: Mon, 16 Nov 2015 00:17:01
Message-Id: 1447632998-19116-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 v3] fixes it to handle PROVIDES_EXCLUDE when entree.needed is
11 non-empty
12
13 pym/portage/util/_dyn_libs/LinkageMapELF.py | 44 +++++++++++++++++++++++++----
14 pym/portage/util/_dyn_libs/NeededEntry.py | 24 ++++++++++++++++
15 2 files changed, 62 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..310fd53 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 @@ -336,6 +356,18 @@ class LinkageMapELF(object):
95 arch = _approx_multilib_categories.get(
96 entry.arch, entry.arch)
97
98 + if requires is not None:
99 + # Apply REQUIRES_EXCLUDE.
100 + entry = entry.intersect_requires(requires)
101 +
102 + provides_soname = bool(entry.soname)
103 + if provides is not None:
104 + # Apply PROVIDES_EXCLUDE.
105 + if (entry.soname and
106 + entry.multilib_category and SonameAtom(
107 + entry.multilib_category, entry.soname) not in provides):
108 + provides_soname = False
109 +
110 obj = entry.filename
111 soname = entry.soname
112 expand = {"ORIGIN": os.path.dirname(entry.filename)}
113 @@ -369,7 +401,7 @@ class LinkageMapELF(object):
114 if arch_map is None:
115 arch_map = {}
116 libs[arch] = arch_map
117 - if soname:
118 + if provides_soname:
119 soname_map = arch_map.get(soname)
120 if soname_map is None:
121 soname_map = self._soname_map_class(
122 diff --git a/pym/portage/util/_dyn_libs/NeededEntry.py b/pym/portage/util/_dyn_libs/NeededEntry.py
123 index c52cfce..824f94c 100644
124 --- a/pym/portage/util/_dyn_libs/NeededEntry.py
125 +++ b/pym/portage/util/_dyn_libs/NeededEntry.py
126 @@ -6,6 +6,7 @@ from __future__ import unicode_literals
127 import sys
128
129 from portage import _encodings, _unicode_encode
130 +from portage.dep.soname.SonameAtom import SonameAtom
131 from portage.exception import InvalidData
132 from portage.localization import _
133
134 @@ -57,6 +58,29 @@ class NeededEntry(object):
135
136 return obj
137
138 + def intersect_requires(self, requires):
139 + """
140 + Return a new instance, filtering out data that does not intersect
141 + with the given requires data. This is a convenient way to account
142 + for REQUIRES_EXCLUDE, since the intersection operation will filter
143 + out anything that REQUIRES_EXCLUDE would exclude.
144 +
145 + @param requires: required soname atoms
146 + @type requires: frozenset
147 + """
148 + obj = self.__class__()
149 + obj.arch = self.arch
150 + obj.filename = self.filename
151 + obj.multilib_category = self.multilib_category
152 + obj.soname = self.soname
153 + obj.runpaths = self.runpaths
154 + filtered_needed = []
155 + for soname in self.needed:
156 + if SonameAtom(self.multilib_category, soname) in requires:
157 + filtered_needed.append(soname)
158 + obj.needed = tuple(filtered_needed)
159 + return obj
160 +
161 def __str__(self):
162 """
163 Format this entry for writing to a NEEDED.ELF.2 file.
164 --
165 2.4.9