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] LinkageMapELF: account for {PROVIDES,REQUIRES}_EXCLUDE (bug 565792)
Date: Sun, 15 Nov 2015 09:02:28
Message-Id: 1447578098-13748-1-git-send-email-zmedico@gentoo.org
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 pym/portage/util/_dyn_libs/LinkageMapELF.py | 45 +++++++++++++++++++++++++----
14 pym/portage/util/_dyn_libs/NeededEntry.py | 24 +++++++++++++++
15 2 files changed, 64 insertions(+), 5 deletions(-)
16
17 diff --git a/pym/portage/util/_dyn_libs/LinkageMapELF.py b/pym/portage/util/_dyn_libs/LinkageMapELF.py
18 index 63e2213..24d03a5 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 @@ -335,6 +355,21 @@ class LinkageMapELF(object):
95 if arch is None:
96 arch = _approx_multilib_categories.get(
97 entry.arch, entry.arch)
98 + # initialize multilib_category for intersect_requires
99 + entry.multilib_category = arch
100 +
101 + if requires is not None:
102 + # Apply REQUIRES_EXCLUDE.
103 + entry = entry.intersect_requires(requires)
104 +
105 + if provides is not None:
106 + # Apply PROVIDES_EXCLUDE. Don't exclude entries with
107 + # non-empty entry.needed, since we want to ensure that
108 + # entry.needed is satisfied. TODO: Apply PROVIDES_EXCLUDE
109 + # to entries with non-empty entry.needed.
110 + if not entry.needed and SonameAtom(
111 + entry.multilib_category, entry.soname) not in provides:
112 + continue
113
114 obj = entry.filename
115 soname = entry.soname
116 diff --git a/pym/portage/util/_dyn_libs/NeededEntry.py b/pym/portage/util/_dyn_libs/NeededEntry.py
117 index c52cfce..824f94c 100644
118 --- a/pym/portage/util/_dyn_libs/NeededEntry.py
119 +++ b/pym/portage/util/_dyn_libs/NeededEntry.py
120 @@ -6,6 +6,7 @@ from __future__ import unicode_literals
121 import sys
122
123 from portage import _encodings, _unicode_encode
124 +from portage.dep.soname.SonameAtom import SonameAtom
125 from portage.exception import InvalidData
126 from portage.localization import _
127
128 @@ -57,6 +58,29 @@ class NeededEntry(object):
129
130 return obj
131
132 + def intersect_requires(self, requires):
133 + """
134 + Return a new instance, filtering out data that does not intersect
135 + with the given requires data. This is a convenient way to account
136 + for REQUIRES_EXCLUDE, since the intersection operation will filter
137 + out anything that REQUIRES_EXCLUDE would exclude.
138 +
139 + @param requires: required soname atoms
140 + @type requires: frozenset
141 + """
142 + obj = self.__class__()
143 + obj.arch = self.arch
144 + obj.filename = self.filename
145 + obj.multilib_category = self.multilib_category
146 + obj.soname = self.soname
147 + obj.runpaths = self.runpaths
148 + filtered_needed = []
149 + for soname in self.needed:
150 + if SonameAtom(self.multilib_category, soname) in requires:
151 + filtered_needed.append(soname)
152 + obj.needed = tuple(filtered_needed)
153 + return obj
154 +
155 def __str__(self):
156 """
157 Format this entry for writing to a NEEDED.ELF.2 file.
158 --
159 2.4.9

Replies