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