Since profile IUSE_IMPLICIT settings may diverge from those
that a binary package was built with, consider members of
built USE settings to be members of IUSE_EFFECTIVE. Only do
this for EAPIs that support IUSE_EFFECTIVE, since built USE
settings for earlier EAPIs may contain a large number of
irrelevant flags.

Note that the binary package may be remote, so it's only
possible to rely on metadata that is available in the remote
Packages file, and the IUSE_IMPLICIT header in the Packages
file is vulnerable to mutation.

Bug: https://bugs.gentoo.org/640318
---
 pym/_emerge/Package.py                    | 32 +++++++++++++++++++++++++++++++
 pym/portage/dbapi/__init__.py             |  5 +++++
 pym/portage/package/ebuild/config.py      |  6 ++++++
 pym/portage/tests/dbapi/test_fakedbapi.py | 20 +++++++++++++++++++
 4 files changed, 63 insertions(+)

diff --git a/pym/_emerge/Package.py b/pym/_emerge/Package.py
index 2c1a116ea..e1943175d 100644
--- a/pym/_emerge/Package.py
+++ b/pym/_emerge/Package.py
@@ -3,6 +3,7 @@
 
 from __future__ import unicode_literals
 
+import functools
 import sys
 from itertools import chain
 import warnings
@@ -82,6 +83,10 @@ class Package(Task):
 
                if eapi_attrs.iuse_effective:
                        implicit_match = 
self.root_config.settings._iuse_effective_match
+                       if self.built:
+                               implicit_match = functools.partial(
+                                       self._built_iuse_effective_match,
+                                       implicit_match, 
frozenset(self._metadata['USE'].split()))
                else:
                        implicit_match = 
self.root_config.settings._iuse_implicit_match
                usealiases = 
self.root_config.settings._use_manager.getUseAliases(self)
@@ -109,6 +114,33 @@ class Package(Task):
                        type_name=self.type_name)
                self._hash_value = hash(self._hash_key)
 
+       @staticmethod
+       def _built_iuse_effective_match(prof_effective_match, built_use, flag):
+               """
+               For built packages, it is desirable for the built USE setting 
to be
+               independent of the profile's current IUSE_IMPLICIT state, since 
the
+               profile's IUSE_IMPLICT setting may have diverged. Therefore, any
+               member the built USE is setting considered to be a valid member 
of
+               IUSE_EFFECTIVE. Note that the binary package may be remote, so 
it's
+               only possible to rely on metadata that is available in the 
remote
+               Packages file, and the IUSE_IMPLICIT header in the Packages 
file is
+               vulnerable to mutation (see bug 640318).
+
+               This function is only used for EAPIs that support 
IUSE_EFFECTIVE,
+               since built USE settings for earlier EAPIs may contain a large
+               number of irrelevant flags.
+
+               @param prof_effective_match: function to match IUSE_EFFECTIVE
+                       values for the current profile
+               @type prof_effective_match: callable
+               @param built_use: built USE setting
+               @type built_use: frozenset
+               @return: True if flag is a valid USE value which may
+                       be specified in USE dependencies, False otherwise.
+               @rtype: bool
+               """
+               return flag in built_use or prof_effective_match(flag)
+
        @property
        def eapi(self):
                return self._metadata["EAPI"]
diff --git a/pym/portage/dbapi/__init__.py b/pym/portage/dbapi/__init__.py
index 95053840d..2574b63df 100644
--- a/pym/portage/dbapi/__init__.py
+++ b/pym/portage/dbapi/__init__.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
 
 __all__ = ["dbapi"]
 
+import functools
 import re
 
 import portage
@@ -219,6 +220,10 @@ class dbapi(object):
                eapi_attrs = _get_eapi_attrs(metadata["EAPI"])
                if eapi_attrs.iuse_effective:
                        iuse_implicit_match = 
self.settings._iuse_effective_match
+                       if not self._use_mutable:
+                               iuse_implicit_match = functools.partial(
+                                       Package._built_iuse_effective_match,
+                                       iuse_implicit_match, 
frozenset(metadata["USE"].split()))
                else:
                        iuse_implicit_match = self.settings._iuse_implicit_match
                usealiases = self.settings._use_manager.getUseAliases(pkg)
diff --git a/pym/portage/package/ebuild/config.py 
b/pym/portage/package/ebuild/config.py
index cd2b009aa..d0225a311 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -1693,6 +1693,12 @@ class config(object):
                        iuse_implicit_match = self._iuse_effective_match
                        portage_iuse = set(self._iuse_effective)
                        portage_iuse.update(explicit_iuse)
+                       if built_use is not None:
+                               # When the binary package was built, the 
profile may have
+                               # had different IUSE_IMPLICIT settings, so any 
member of
+                               # the built USE setting is considered to be a 
member of
+                               # IUSE_EFFECTIVE (see bug 640318).
+                               portage_iuse.update(built_use)
                        self.configdict["pkg"]["IUSE_EFFECTIVE"] = \
                                " ".join(sorted(portage_iuse))
                else:
diff --git a/pym/portage/tests/dbapi/test_fakedbapi.py 
b/pym/portage/tests/dbapi/test_fakedbapi.py
index e4f5dd771..19ea9cd00 100644
--- a/pym/portage/tests/dbapi/test_fakedbapi.py
+++ b/pym/portage/tests/dbapi/test_fakedbapi.py
@@ -14,6 +14,20 @@ class TestFakedbapi(TestCase):
 
        def testFakedbapi(self):
                packages = (
+                       ("app-misc/foo-1", {
+                               "EAPI"         : "2", # does not support 
IUSE_EFFECTIVE
+                               "IUSE"         : "",
+                               "repository"   : "gentoo",
+                               "SLOT"         : "1",
+                               "USE"          : "missing-iuse",
+                       }),
+                       ("app-misc/foo-2", {
+                               "EAPI"         : "5", # supports IUSE_EFFECTIVE
+                               "IUSE"         : "",
+                               "repository"   : "gentoo",
+                               "SLOT"         : "2",
+                               "USE"          : "missing-iuse",
+                       }),
                        ("sys-apps/portage-2.1.10", {
                                "EAPI"         : "2",
                                "IUSE"         : "ipc doc",
@@ -29,6 +43,12 @@ class TestFakedbapi(TestCase):
                )
 
                match_tests = (
+                       # The missing-iuse match is only intended to work for 
binary
+                       # packages with EAPIs that support IUSE_EFFECTIVE (bug 
640318).
+                       ("app-misc/foo[missing-iuse]",    ["app-misc/foo-2"]),
+                       ("app-misc/foo[-missing-iuse]",   []),
+                       ("app-misc/foo",                  ["app-misc/foo-1", 
"app-misc/foo-2"]),
+
                        ("sys-apps/portage:0[ipc]",             
["sys-apps/portage-2.1.10"]),
                        ("sys-apps/portage:0[-ipc]",            []),
                        ("sys-apps/portage:0[doc]",             []),
-- 
2.13.6


Reply via email to