1 |
In order to propagate information from dbapi to Package instance, |
2 |
it's useful for each _pkg_str instance to have a _db attribute |
3 |
which references the dbapi instance that instantiated it. Use a new |
4 |
dbapi._iuse_implicit_cnstr method to delegate implicit IUSE logic to |
5 |
the dbapi instance, in order to make the behavior customizable at the |
6 |
dbapi level for the purposes of bug 640318. This patch consists only |
7 |
of refactoring, with no behavioral changes. |
8 |
|
9 |
Bug: https://bugs.gentoo.org/640318 |
10 |
--- |
11 |
pym/_emerge/Package.py | 53 +++++++++--------------------- |
12 |
pym/_emerge/depgraph.py | 8 ++++- |
13 |
pym/_emerge/resolver/DbapiProvidesIndex.py | 3 +- |
14 |
pym/portage/dbapi/__init__.py | 44 +++++++++++++++++++++---- |
15 |
pym/portage/dbapi/bintree.py | 15 +++++---- |
16 |
pym/portage/dbapi/porttree.py | 4 +-- |
17 |
pym/portage/dbapi/vartree.py | 5 +-- |
18 |
pym/portage/dbapi/virtual.py | 4 +-- |
19 |
pym/portage/versions.py | 6 ++-- |
20 |
9 files changed, 81 insertions(+), 61 deletions(-) |
21 |
|
22 |
diff --git a/pym/_emerge/Package.py b/pym/_emerge/Package.py |
23 |
index 791a35612..a7ce00bc9 100644 |
24 |
--- a/pym/_emerge/Package.py |
25 |
+++ b/pym/_emerge/Package.py |
26 |
@@ -67,8 +67,19 @@ class Package(Task): |
27 |
if not self.built: |
28 |
self._metadata['CHOST'] = self.root_config.settings.get('CHOST', '') |
29 |
eapi_attrs = _get_eapi_attrs(self.eapi) |
30 |
+ |
31 |
+ try: |
32 |
+ db = self.cpv._db |
33 |
+ except AttributeError: |
34 |
+ if self.built: |
35 |
+ # For independence from the source ebuild repository and |
36 |
+ # profile implicit IUSE state, require the _db attribute |
37 |
+ # for built packages. |
38 |
+ raise |
39 |
+ db = self.root_config.trees['porttree'].dbapi |
40 |
+ |
41 |
self.cpv = _pkg_str(self.cpv, metadata=self._metadata, |
42 |
- settings=self.root_config.settings) |
43 |
+ settings=self.root_config.settings, db=db) |
44 |
if hasattr(self.cpv, 'slot_invalid'): |
45 |
self._invalid_metadata('SLOT.invalid', |
46 |
"SLOT: invalid value: '%s'" % self._metadata["SLOT"]) |
47 |
@@ -82,17 +93,10 @@ class Package(Task): |
48 |
# sync metadata with validated repo (may be UNKNOWN_REPO) |
49 |
self._metadata['repository'] = self.cpv.repo |
50 |
|
51 |
- if eapi_attrs.iuse_effective: |
52 |
- implicit_match = self.root_config.settings._iuse_effective_match |
53 |
- if self.built: |
54 |
- implicit_match = functools.partial( |
55 |
- self._built_iuse_effective_match, |
56 |
- implicit_match, frozenset(self._metadata['USE'].split())) |
57 |
- else: |
58 |
- implicit_match = self.root_config.settings._iuse_implicit_match |
59 |
+ implicit_match = db._iuse_implicit_cnstr(self.cpv, self._metadata) |
60 |
usealiases = self.root_config.settings._use_manager.getUseAliases(self) |
61 |
- self.iuse = self._iuse(self, self._metadata["IUSE"].split(), implicit_match, |
62 |
- usealiases, self.eapi) |
63 |
+ self.iuse = self._iuse(self, self._metadata["IUSE"].split(), |
64 |
+ implicit_match, usealiases, self.eapi) |
65 |
|
66 |
if (self.iuse.enabled or self.iuse.disabled) and \ |
67 |
not eapi_attrs.iuse_defaults: |
68 |
@@ -115,33 +119,6 @@ class Package(Task): |
69 |
type_name=self.type_name) |
70 |
self._hash_value = hash(self._hash_key) |
71 |
|
72 |
- @staticmethod |
73 |
- def _built_iuse_effective_match(prof_effective_match, built_use, flag): |
74 |
- """ |
75 |
- For built packages, it is desirable for the built USE setting to be |
76 |
- independent of the profile's current IUSE_IMPLICIT state, since the |
77 |
- profile's IUSE_IMPLICT setting may have diverged. Therefore, any |
78 |
- member of the built USE setting is considered to be a valid member of |
79 |
- IUSE_EFFECTIVE. Note that the binary package may be remote, so it's |
80 |
- only possible to rely on metadata that is available in the remote |
81 |
- Packages file, and the IUSE_IMPLICIT header in the Packages file is |
82 |
- vulnerable to mutation (see bug 640318). |
83 |
- |
84 |
- This function is only used for EAPIs that support IUSE_EFFECTIVE, |
85 |
- since built USE settings for earlier EAPIs may contain a large |
86 |
- number of irrelevant flags. |
87 |
- |
88 |
- @param prof_effective_match: function to match IUSE_EFFECTIVE |
89 |
- values for the current profile |
90 |
- @type prof_effective_match: callable |
91 |
- @param built_use: built USE setting |
92 |
- @type built_use: frozenset |
93 |
- @return: True if flag is a valid USE value which may |
94 |
- be specified in USE dependencies, False otherwise. |
95 |
- @rtype: bool |
96 |
- """ |
97 |
- return flag in built_use or prof_effective_match(flag) |
98 |
- |
99 |
@property |
100 |
def eapi(self): |
101 |
return self._metadata["EAPI"] |
102 |
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py |
103 |
index 963bf25f4..c435bc0b5 100644 |
104 |
--- a/pym/_emerge/depgraph.py |
105 |
+++ b/pym/_emerge/depgraph.py |
106 |
@@ -50,7 +50,7 @@ from portage.util.digraph import digraph |
107 |
from portage.util._async.TaskScheduler import TaskScheduler |
108 |
from portage.util._eventloop.EventLoop import EventLoop |
109 |
from portage.util._eventloop.global_event_loop import global_event_loop |
110 |
-from portage.versions import catpkgsplit |
111 |
+from portage.versions import _pkg_str, catpkgsplit |
112 |
|
113 |
from _emerge.AtomArg import AtomArg |
114 |
from _emerge.Blocker import Blocker |
115 |
@@ -6975,6 +6975,12 @@ class depgraph(object): |
116 |
except KeyError: |
117 |
raise portage.exception.PackageNotFound(cpv) |
118 |
|
119 |
+ # Ensure that this cpv is linked to the correct db, since the |
120 |
+ # caller might have passed in a cpv from a different db, in |
121 |
+ # order get an instance from this db with the same cpv. |
122 |
+ if getattr(cpv, '_db', None) is not db: |
123 |
+ cpv = _pkg_str(cpv, db=db) |
124 |
+ |
125 |
pkg = Package(built=(type_name != "ebuild"), cpv=cpv, |
126 |
installed=installed, metadata=metadata, onlydeps=onlydeps, |
127 |
root_config=root_config, type_name=type_name) |
128 |
diff --git a/pym/_emerge/resolver/DbapiProvidesIndex.py b/pym/_emerge/resolver/DbapiProvidesIndex.py |
129 |
index 59ae71941..1650edd4e 100644 |
130 |
--- a/pym/_emerge/resolver/DbapiProvidesIndex.py |
131 |
+++ b/pym/_emerge/resolver/DbapiProvidesIndex.py |
132 |
@@ -24,7 +24,8 @@ class DbapiProvidesIndex(object): |
133 |
_copy_attrs = ('aux_get', 'aux_update', 'categories', 'cpv_all', |
134 |
'cpv_exists', 'cp_all', 'cp_list', 'getfetchsizes', |
135 |
'settings', '_aux_cache_keys', '_clear_cache', |
136 |
- '_cpv_sort_ascending', '_pkg_str', '_pkg_str_aux_keys') |
137 |
+ '_cpv_sort_ascending', '_iuse_implicit_cnstr', '_pkg_str', |
138 |
+ '_pkg_str_aux_keys') |
139 |
|
140 |
def __init__(self, db): |
141 |
self._db = db |
142 |
diff --git a/pym/portage/dbapi/__init__.py b/pym/portage/dbapi/__init__.py |
143 |
index c1b5d967d..d320cc75f 100644 |
144 |
--- a/pym/portage/dbapi/__init__.py |
145 |
+++ b/pym/portage/dbapi/__init__.py |
146 |
@@ -166,7 +166,7 @@ class dbapi(object): |
147 |
metadata = dict(zip(self._pkg_str_aux_keys, |
148 |
self.aux_get(cpv, self._pkg_str_aux_keys, myrepo=repo))) |
149 |
|
150 |
- return _pkg_str(cpv, metadata=metadata, settings=self.settings) |
151 |
+ return _pkg_str(cpv, metadata=metadata, settings=self.settings, db=self) |
152 |
|
153 |
def _iter_match_repo(self, atom, cpv_iter): |
154 |
for cpv in cpv_iter: |
155 |
@@ -216,16 +216,48 @@ class dbapi(object): |
156 |
|
157 |
yield cpv |
158 |
|
159 |
- def _match_use(self, atom, pkg, metadata, ignore_profile=False): |
160 |
+ def _iuse_implicit_cnstr(self, pkg, metadata): |
161 |
+ """ |
162 |
+ Construct a callable that checks if a given USE flag should |
163 |
+ be considered to be a member of the implicit IUSE for the |
164 |
+ given package. |
165 |
+ |
166 |
+ @param pkg: package |
167 |
+ @type pkg: _pkg_str |
168 |
+ @param metadata: package metadata |
169 |
+ @type metadata: Mapping |
170 |
+ @return: a callable that accepts a single USE flag argument, |
171 |
+ and returns True only if the USE flag should be considered |
172 |
+ to be a member of the implicit IUSE for the given package. |
173 |
+ @rtype: callable |
174 |
+ """ |
175 |
eapi_attrs = _get_eapi_attrs(metadata["EAPI"]) |
176 |
if eapi_attrs.iuse_effective: |
177 |
iuse_implicit_match = self.settings._iuse_effective_match |
178 |
- if not self._use_mutable: |
179 |
- iuse_implicit_match = functools.partial( |
180 |
- Package._built_iuse_effective_match, |
181 |
- iuse_implicit_match, frozenset(metadata["USE"].split())) |
182 |
else: |
183 |
iuse_implicit_match = self.settings._iuse_implicit_match |
184 |
+ |
185 |
+ if not self._use_mutable and eapi_attrs.iuse_effective: |
186 |
+ # For built packages, it is desirable for the built USE setting to |
187 |
+ # be independent of the profile's current IUSE_IMPLICIT state, since |
188 |
+ # the profile's IUSE_IMPLICT setting may have diverged. Therefore, |
189 |
+ # any member of the built USE setting is considered to be a valid |
190 |
+ # member of IUSE_EFFECTIVE. Note that the binary package may be |
191 |
+ # remote, so it's only possible to rely on metadata that is available |
192 |
+ # in the remote Packages file, and the IUSE_IMPLICIT header in the |
193 |
+ # Packages file is vulnerable to mutation (see bug 640318). |
194 |
+ # |
195 |
+ # This behavior is only used for EAPIs that support IUSE_EFFECTIVE, |
196 |
+ # since built USE settings for earlier EAPIs may contain a large |
197 |
+ # number of irrelevant flags. |
198 |
+ prof_iuse = iuse_implicit_match |
199 |
+ enabled = frozenset(metadata["USE"].split()).__contains__ |
200 |
+ iuse_implicit_match = lambda flag: prof_iuse(flag) or enabled(flag) |
201 |
+ |
202 |
+ return iuse_implicit_match |
203 |
+ |
204 |
+ def _match_use(self, atom, pkg, metadata, ignore_profile=False): |
205 |
+ iuse_implicit_match = self._iuse_implicit_cnstr(pkg, metadata) |
206 |
usealiases = self.settings._use_manager.getUseAliases(pkg) |
207 |
iuse = Package._iuse(None, metadata["IUSE"].split(), iuse_implicit_match, usealiases, metadata["EAPI"]) |
208 |
|
209 |
diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py |
210 |
index fc48a6902..42d334d24 100644 |
211 |
--- a/pym/portage/dbapi/bintree.py |
212 |
+++ b/pym/portage/dbapi/bintree.py |
213 |
@@ -458,7 +458,7 @@ class binarytree(object): |
214 |
if v is not None: |
215 |
v = _unicode_decode(v) |
216 |
metadata[k] = " ".join(v.split()) |
217 |
- mynewcpv = _pkg_str(mynewcpv, metadata=metadata) |
218 |
+ mynewcpv = _pkg_str(mynewcpv, metadata=metadata, db=self.dbapi) |
219 |
new_path = self.getname(mynewcpv) |
220 |
self._pkg_paths[ |
221 |
self.dbapi._instance_key(mynewcpv)] = new_path[len(self.pkgdir)+1:] |
222 |
@@ -589,7 +589,7 @@ class binarytree(object): |
223 |
basename_index = {} |
224 |
for d in pkgindex.packages: |
225 |
cpv = _pkg_str(d["CPV"], metadata=d, |
226 |
- settings=self.settings) |
227 |
+ settings=self.settings, db=self.dbapi) |
228 |
d["CPV"] = cpv |
229 |
metadata[_instance_key(cpv)] = d |
230 |
path = d.get("PATH") |
231 |
@@ -755,8 +755,8 @@ class binarytree(object): |
232 |
pkg_metadata.pop("CATEGORY") |
233 |
pkg_metadata.pop("PF") |
234 |
mycpv = _pkg_str(mycpv, |
235 |
- metadata=self.dbapi._aux_cache_slot_dict( |
236 |
- pkg_metadata)) |
237 |
+ metadata=self.dbapi._aux_cache_slot_dict(pkg_metadata), |
238 |
+ db=self.dbapi) |
239 |
pkg_paths[_instance_key(mycpv)] = mypath |
240 |
self.dbapi.cpv_inject(mycpv) |
241 |
update_pkgindex = True |
242 |
@@ -1028,7 +1028,7 @@ class binarytree(object): |
243 |
remote_base_uri = pkgindex.header.get("URI", base_url) |
244 |
for d in pkgindex.packages: |
245 |
cpv = _pkg_str(d["CPV"], metadata=d, |
246 |
- settings=self.settings) |
247 |
+ settings=self.settings, db=self.dbapi) |
248 |
# Local package instances override remote instances |
249 |
# with the same instance_key. |
250 |
if self.dbapi.cpv_exists(cpv): |
251 |
@@ -1097,7 +1097,8 @@ class binarytree(object): |
252 |
if self._remotepkgs is not None: |
253 |
fetched = self._remotepkgs.pop(instance_key, None) |
254 |
|
255 |
- cpv = _pkg_str(cpv, metadata=metadata, settings=self.settings) |
256 |
+ cpv = _pkg_str(cpv, metadata=metadata, settings=self.settings, |
257 |
+ db=self.dbapi) |
258 |
|
259 |
# Reread the Packages index (in case it's been changed by another |
260 |
# process) and then updated it, all while holding a lock. |
261 |
@@ -1128,7 +1129,7 @@ class binarytree(object): |
262 |
build_id = self._parse_build_id(basename) |
263 |
metadata["BUILD_ID"] = _unicode(build_id) |
264 |
cpv = _pkg_str(cpv, metadata=metadata, |
265 |
- settings=self.settings) |
266 |
+ settings=self.settings, db=self.dbapi) |
267 |
binpkg = portage.xpak.tbz2(full_path) |
268 |
binary_data = binpkg.get_data() |
269 |
binary_data[b"BUILD_ID"] = _unicode_encode( |
270 |
diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py |
271 |
index 69e14dbcd..910e90e6f 100644 |
272 |
--- a/pym/portage/dbapi/porttree.py |
273 |
+++ b/pym/portage/dbapi/porttree.py |
274 |
@@ -945,7 +945,7 @@ class portdbapi(dbapi): |
275 |
writemsg(_("\nInvalid ebuild version: %s\n") % \ |
276 |
os.path.join(oroot, mycp, x), noiselevel=-1) |
277 |
continue |
278 |
- d[_pkg_str(mysplit[0]+"/"+pf)] = None |
279 |
+ d[_pkg_str(mysplit[0]+"/"+pf, db=self)] = None |
280 |
if invalid_category and d: |
281 |
writemsg(_("\n!!! '%s' has a category that is not listed in " \ |
282 |
"%setc/portage/categories\n") % \ |
283 |
@@ -1070,7 +1070,7 @@ class portdbapi(dbapi): |
284 |
|
285 |
try: |
286 |
pkg_str = _pkg_str(cpv, metadata=metadata, |
287 |
- settings=self.settings) |
288 |
+ settings=self.settings, db=self) |
289 |
except InvalidData: |
290 |
continue |
291 |
|
292 |
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py |
293 |
index a136c38f1..c274248e3 100644 |
294 |
--- a/pym/portage/dbapi/vartree.py |
295 |
+++ b/pym/portage/dbapi/vartree.py |
296 |
@@ -466,7 +466,8 @@ class vardbapi(dbapi): |
297 |
cpv = "%s/%s" % (mysplit[0], x) |
298 |
metadata = dict(zip(self._aux_cache_keys, |
299 |
self.aux_get(cpv, self._aux_cache_keys))) |
300 |
- returnme.append(_pkg_str(cpv, metadata=metadata)) |
301 |
+ returnme.append(_pkg_str(cpv, metadata=metadata, |
302 |
+ settings=self.settings, db=self)) |
303 |
self._cpv_sort_ascending(returnme) |
304 |
if use_cache: |
305 |
self.cpcache[mycp] = [mystat, returnme[:]] |
306 |
@@ -520,7 +521,7 @@ class vardbapi(dbapi): |
307 |
subpath = x + "/" + y |
308 |
# -MERGING- should never be a cpv, nor should files. |
309 |
try: |
310 |
- subpath = _pkg_str(subpath) |
311 |
+ subpath = _pkg_str(subpath, db=self) |
312 |
except InvalidData: |
313 |
self.invalidentry(self.getpath(subpath)) |
314 |
continue |
315 |
diff --git a/pym/portage/dbapi/virtual.py b/pym/portage/dbapi/virtual.py |
316 |
index f2e841fcd..3f7e6c221 100644 |
317 |
--- a/pym/portage/dbapi/virtual.py |
318 |
+++ b/pym/portage/dbapi/virtual.py |
319 |
@@ -151,10 +151,10 @@ class fakedbapi(dbapi): |
320 |
if mycp is None or \ |
321 |
(myslot is None and metadata is not None and metadata.get('SLOT')): |
322 |
if metadata is None: |
323 |
- mycpv = _pkg_str(mycpv) |
324 |
+ mycpv = _pkg_str(mycpv, db=self) |
325 |
else: |
326 |
mycpv = _pkg_str(mycpv, metadata=metadata, |
327 |
- settings=self.settings) |
328 |
+ settings=self.settings, db=self) |
329 |
|
330 |
mycp = mycpv.cp |
331 |
try: |
332 |
diff --git a/pym/portage/versions.py b/pym/portage/versions.py |
333 |
index 7b6a57673..0c21373cc 100644 |
334 |
--- a/pym/portage/versions.py |
335 |
+++ b/pym/portage/versions.py |
336 |
@@ -363,12 +363,12 @@ class _pkg_str(_unicode): |
337 |
|
338 |
def __new__(cls, cpv, metadata=None, settings=None, eapi=None, |
339 |
repo=None, slot=None, build_time=None, build_id=None, |
340 |
- file_size=None, mtime=None): |
341 |
+ file_size=None, mtime=None, db=None): |
342 |
return _unicode.__new__(cls, cpv) |
343 |
|
344 |
def __init__(self, cpv, metadata=None, settings=None, eapi=None, |
345 |
repo=None, slot=None, build_time=None, build_id=None, |
346 |
- file_size=None, mtime=None): |
347 |
+ file_size=None, mtime=None, db=None): |
348 |
if not isinstance(cpv, _unicode): |
349 |
# Avoid TypeError from _unicode.__init__ with PyPy. |
350 |
cpv = _unicode_decode(cpv) |
351 |
@@ -384,6 +384,8 @@ class _pkg_str(_unicode): |
352 |
mtime = metadata.get('_mtime_', mtime) |
353 |
if settings is not None: |
354 |
self.__dict__['_settings'] = settings |
355 |
+ if db is not None: |
356 |
+ self.__dict__['_db'] = db |
357 |
if eapi is not None: |
358 |
self.__dict__['eapi'] = eapi |
359 |
|
360 |
-- |
361 |
2.13.6 |