EAPI 5: Profile IUSE injection
authorZac Medico <zmedico@gentoo.org>
Wed, 29 Aug 2012 07:38:12 +0000 (00:38 -0700)
committerZac Medico <zmedico@gentoo.org>
Wed, 29 Aug 2012 07:38:12 +0000 (00:38 -0700)
See bug #176467 and the PMS patch:
http://git.overlays.gentoo.org/gitweb/?p=proj/pms.git;a=commit;h=d9040ab3482af5f790368bac5d053bf1cd760ba8

pym/_emerge/Package.py
pym/portage/const.py
pym/portage/dbapi/__init__.py
pym/portage/dbapi/_expand_new_virt.py
pym/portage/eapi.py
pym/portage/package/ebuild/config.py
pym/portage/package/ebuild/doebuild.py

index 0da374af40216d056dbd3f9eb3b4d297816da544..ce51a8b06ca1a48d1a0ac225c5d6c24473f90352 100644 (file)
@@ -64,6 +64,13 @@ class Package(Task):
                self.slot_abi = self.cpv.slot_abi
                # sync metadata with validated repo (may be UNKNOWN_REPO)
                self.metadata['repository'] = self.cpv.repo
+
+               if eapi_attrs.iuse_effective:
+                       implicit_match = self.root_config.settings._iuse_effective_match
+               else:
+                       implicit_match = self.root_config.settings._iuse_implicit_match
+               self.iuse = self._iuse(self.metadata["IUSE"].split(), implicit_match)
+
                if (self.iuse.enabled or self.iuse.disabled) and \
                        not eapi_attrs.iuse_defaults:
                        if not self.installed:
@@ -615,7 +622,7 @@ class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
 
        __slots__ = ("_pkg",)
        _wrapped_keys = frozenset(
-               ["COUNTER", "INHERITED", "IUSE", "USE", "_mtime_"])
+               ["COUNTER", "INHERITED", "USE", "_mtime_"])
        _use_conditional_keys = frozenset(
                ['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
 
@@ -684,10 +691,6 @@ class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
                        v = frozenset(v.split())
                self._pkg.inherited = v
 
-       def _set_iuse(self, k, v):
-               self._pkg.iuse = self._pkg._iuse(
-                       v.split(), self._pkg.root_config.settings._iuse_implicit_match)
-
        def _set_counter(self, k, v):
                if isinstance(v, basestring):
                        try:
index c2049f8718937d75c9a8bd8556f113d6793cdd40..6dffc5d06ea30c1a5973e9a5076c884da889dcff 100644 (file)
@@ -79,8 +79,10 @@ OS_HEADERS_PACKAGE_ATOM  = "virtual/os-headers"
 INCREMENTALS             = ("USE", "USE_EXPAND", "USE_EXPAND_HIDDEN",
                            "FEATURES", "ACCEPT_KEYWORDS",
                            "CONFIG_PROTECT_MASK", "CONFIG_PROTECT",
+                           "IUSE_IMPLICIT",
                            "PRELINK_PATH", "PRELINK_PATH_MASK",
-                           "PROFILE_ONLY_VARIABLES")
+                           "PROFILE_ONLY_VARIABLES",
+                           "USE_EXPAND_IMPLICIT", "USE_EXPAND_UNPREFIXED")
 EBUILD_PHASES            = ("pretend", "setup", "unpack", "prepare", "configure",
                            "compile", "test", "install",
                            "package", "preinst", "postinst","prerm", "postrm",
index 97b4255589375eadf48fed822657731e8bc5d66f..f326e68288217078addb5450866918c8a65db749 100644 (file)
@@ -16,6 +16,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
 
 from portage import os
 from portage import auxdbkeys
+from portage.eapi import _get_eapi_attrs
 from portage.exception import InvalidData
 from portage.localization import _
 
@@ -181,7 +182,7 @@ class dbapi(object):
                2) Check enabled/disabled flag states.
                """
 
-               aux_keys = ["IUSE", "KEYWORDS", "SLOT", "USE", "repository"]
+               aux_keys = ["EAPI", "IUSE", "KEYWORDS", "SLOT", "USE", "repository"]
                for cpv in cpv_iter:
                        try:
                                metadata = dict(zip(aux_keys,
@@ -195,7 +196,11 @@ class dbapi(object):
                        yield cpv
 
        def _match_use(self, atom, cpv, metadata):
-               iuse_implicit_match = self.settings._iuse_implicit_match
+               eapi_attrs = _get_eapi_attrs(metadata["EAPI"])
+               if eapi_attrs.iuse_effective:
+                       iuse_implicit_match = self.settings._iuse_effective_match
+               else:
+                       iuse_implicit_match = self.settings._iuse_implicit_match
                iuse = frozenset(x.lstrip('+-') for x in metadata["IUSE"].split())
 
                for x in atom.unevaluated_atom.use.required:
index d379b4c1dbaf9a471d05c3786def578fa20bd653..95b2c28cd45369a37ef155e406b81064c5976549 100644 (file)
@@ -1,8 +1,9 @@
-# Copyright 2011 Gentoo Foundation
+# Copyright 2011-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 import portage
 from portage.dep import Atom, _get_useflag_re
+from portage.eapi import _get_eapi_attrs
 
 def expand_new_virt(vardb, atom):
        """
@@ -44,6 +45,7 @@ def expand_new_virt(vardb, atom):
                        yield atom
                        continue
 
+               eapi_attrs = _get_eapi_attrs(eapi)
                # Validate IUSE and IUSE, for early detection of vardb corruption.
                useflag_re = _get_useflag_re(eapi)
                valid_iuse = []
@@ -54,7 +56,11 @@ def expand_new_virt(vardb, atom):
                                valid_iuse.append(x)
                valid_iuse = frozenset(valid_iuse)
 
-               iuse_implicit_match = vardb.settings._iuse_implicit_match
+               if eapi_attrs.iuse_effective:
+                       iuse_implicit_match = vardb.settings._iuse_effective_match
+               else:
+                       iuse_implicit_match = vardb.settings._iuse_implicit_match
+
                valid_use = []
                for x in use.split():
                        if x in valid_iuse or iuse_implicit_match(x):
index b701d02ab614d1f1476da3808d6a6554dff82a22..00ce2a512028819a30ce53a5f73f6e1c9a24891b 100644 (file)
@@ -8,6 +8,9 @@ from portage import eapi_is_supported
 def eapi_has_iuse_defaults(eapi):
        return eapi != "0"
 
+def eapi_has_iuse_effective(eapi):
+       return eapi not in ("0", "1", "2", "3", "4", "4-python", "4-slot-abi")
+
 def eapi_has_slot_deps(eapi):
        return eapi != "0"
 
@@ -72,7 +75,7 @@ def eapi_allows_dots_in_use_flags(eapi):
        return eapi in ("4-python",)
 
 _eapi_attrs = collections.namedtuple('_eapi_attrs',
-       'dots_in_PN dots_in_use_flags iuse_defaults '
+       'dots_in_PN dots_in_use_flags iuse_defaults iuse_effective '
        'repo_deps required_use required_use_at_most_one_of slot_abi slot_deps '
        'src_uri_arrows strong_blocks use_deps use_dep_defaults')
 
@@ -98,6 +101,7 @@ def _get_eapi_attrs(eapi):
                dots_in_PN = (eapi is None or eapi_allows_dots_in_PN(eapi)),
                dots_in_use_flags = (eapi is None or eapi_allows_dots_in_use_flags(eapi)),
                iuse_defaults = (eapi is None or eapi_has_iuse_defaults(eapi)),
+               iuse_effective = (eapi is not None and eapi_has_iuse_effective(eapi)),
                repo_deps = (eapi is None or eapi_has_repo_deps(eapi)),
                required_use = (eapi is None or eapi_has_required_use(eapi)),
                required_use_at_most_one_of = (eapi is None or eapi_has_required_use_at_most_one_of(eapi)),
index 871831fb67a382b822b469ba6445093473271d95..6a9ed08b897b27cb72a29a1508c3ee14552fd07e 100644 (file)
@@ -32,7 +32,7 @@ from portage.dbapi.porttree import portdbapi
 from portage.dbapi.vartree import vartree
 from portage.dep import Atom, isvalidatom, match_from_list, use_reduce, _repo_separator, _slot_separator
 from portage.eapi import eapi_exports_AA, eapi_exports_merge_type, \
-       eapi_supports_prefix, eapi_exports_replace_vars
+       eapi_supports_prefix, eapi_exports_replace_vars, _get_eapi_attrs
 from portage.env.loaders import KeyValuePairFileLoader
 from portage.exception import InvalidDependString, PortageException
 from portage.localization import _
@@ -215,6 +215,7 @@ class config(object):
                        self.profiles = clone.profiles
                        self.packages = clone.packages
                        self.repositories = clone.repositories
+                       self._iuse_effective = clone._iuse_effective
                        self._iuse_implicit_match = clone._iuse_implicit_match
                        self._non_user_variables = clone._non_user_variables
                        self._env_d_blacklist = clone._env_d_blacklist
@@ -793,6 +794,7 @@ class config(object):
                        if bsd_chflags:
                                self.features.add('chflags')
 
+                       self._iuse_effective = self._calc_iuse_effective()
                        self._iuse_implicit_match = _iuse_implicit_match_cache(self)
 
                        self._validate_commands()
@@ -1251,6 +1253,7 @@ class config(object):
                pkg_configdict["CATEGORY"] = cat
                pkg_configdict["PF"] = pf
                repository = None
+               eapi = None
                if mydb:
                        if not hasattr(mydb, "aux_get"):
                                for k in aux_keys:
@@ -1277,6 +1280,7 @@ class config(object):
                                        # Empty USE means this dbapi instance does not contain
                                        # built packages.
                                        built_use = None
+                       eapi = pkg_configdict['EAPI']
 
                        repository = pkg_configdict.pop("repository", None)
                        if repository is not None:
@@ -1295,6 +1299,9 @@ class config(object):
                                elif x.startswith("-"):
                                        pkginternaluse.append(x)
                        pkginternaluse = " ".join(pkginternaluse)
+
+               eapi_attrs = _get_eapi_attrs(eapi)
+
                if pkginternaluse != self.configdict["pkginternal"].get("USE", ""):
                        self.configdict["pkginternal"]["USE"] = pkginternaluse
                        has_changed = True
@@ -1434,9 +1441,17 @@ class config(object):
                use = set(self["USE"].split())
                if explicit_iuse is None:
                        explicit_iuse = frozenset(x.lstrip("+-") for x in iuse.split())
-               iuse_implicit_match = self._iuse_implicit_match
-               portage_iuse = self._get_implicit_iuse()
-               portage_iuse.update(explicit_iuse)
+
+               if eapi_attrs.iuse_effective:
+                       iuse_implicit_match = self._iuse_effective_match
+                       portage_iuse = set(self._iuse_effective)
+                       portage_iuse.update(explicit_iuse)
+                       self.configdict["pkg"]["IUSE_EFFECTIVE"] = \
+                               " ".join(sorted(portage_iuse))
+               else:
+                       iuse_implicit_match = self._iuse_implicit_match
+                       portage_iuse = self._get_implicit_iuse()
+                       portage_iuse.update(explicit_iuse)
 
                # PORTAGE_IUSE is not always needed so it's lazily evaluated.
                self.configdict["env"].addLazySingleton(
@@ -1501,6 +1516,14 @@ class config(object):
                        self.configdict['env'].addLazySingleton(k,
                                lazy_use_expand.__getitem__, k)
 
+               for k in self.get("USE_EXPAND_UNPREFIXED", "").split():
+                       var_split = self.get(k, '').split()
+                       var_split = [ x for x in var_split if x in use ]
+                       if var_split:
+                               self.configlist[-1][k] = ' '.join(var_split)
+                       elif k in self:
+                               self.configlist[-1][k] = ''
+
                # Filtered for the ebuild environment. Store this in a separate
                # attribute since we still want to be able to see global USE
                # settings for things like emerge --info.
@@ -1545,9 +1568,42 @@ class config(object):
                                        else:
                                                container[k] = v
 
+       def _iuse_effective_match(self, flag):
+               return flag in self._iuse_effective
+
+       def _calc_iuse_effective(self):
+               """
+               Beginning with EAPI 5, IUSE_EFFECTIVE is defined by PMS.
+               """
+               iuse_effective = []
+               iuse_effective.extend(self.get("IUSE_IMPLICIT", "").split())
+
+               # USE_EXPAND_IMPLICIT should contain things like ARCH, ELIBC,
+               # KERNEL, and USERLAND.
+               use_expand_implicit = frozenset(
+                       self.get("USE_EXPAND_IMPLICIT", "").split())
+
+               # USE_EXPAND_UNPREFIXED should contain at least ARCH, and
+               # USE_EXPAND_VALUES_ARCH should contain all valid ARCH flags.
+               for v in self.get("USE_EXPAND_UNPREFIXED", "").split():
+                       if v not in use_expand_implicit:
+                               continue
+                       iuse_effective.extend(
+                               self.get("USE_EXPAND_VALUES_" + v, "").split())
+
+               use_expand = frozenset(self.get("USE_EXPAND", "").split())
+               for v in use_expand_implicit:
+                       if v not in use_expand:
+                               continue
+                       lower_v = v.lower()
+                       for x in self.get("USE_EXPAND_VALUES_" + v, "").split():
+                               iuse_effective.append(lower_v + "_" + x)
+
+               return frozenset(iuse_effective)
+
        def _get_implicit_iuse(self):
                """
-               Some flags are considered to
+               Prior to EAPI 5, these flags are considered to
                be implicit members of IUSE:
                  * Flags derived from ARCH
                  * Flags derived from USE_EXPAND_HIDDEN variables
@@ -2005,6 +2061,8 @@ class config(object):
                        if v is not None:
                                use_expand_dict[k] = v
 
+               use_expand_unprefixed = self.get("USE_EXPAND_UNPREFIXED", "").split()
+
                # In order to best accomodate the long-standing practice of
                # setting default USE_EXPAND variables in the profile's
                # make.defaults, we translate these variables into their
@@ -2018,6 +2076,12 @@ class config(object):
                                        continue
                                use = cfg.get("USE", "")
                                expand_use = []
+
+                               for k in use_expand_unprefixed:
+                                       v = cfg.get(k)
+                                       if v is not None:
+                                               expand_use.extend(v.split())
+
                                for k in use_expand_dict:
                                        v = cfg.get(k)
                                        if v is None:
@@ -2055,6 +2119,17 @@ class config(object):
                        iuse = [x.lstrip("+-") for x in iuse.split()]
                myflags = set()
                for curdb in self.uvlist:
+
+                       for k in use_expand_unprefixed:
+                               v = curdb.get(k)
+                               if v is None:
+                                       continue
+                               for x in v.split():
+                                       if x[:1] == "-":
+                                               myflags.discard(x[1:])
+                                       else:
+                                               myflags.add(x)
+
                        cur_use_expand = [x for x in use_expand if x in curdb]
                        mysplit = curdb.get("USE", "").split()
                        if not mysplit and not cur_use_expand:
@@ -2171,6 +2246,14 @@ class config(object):
                                elif k in self:
                                        self.configlist[-1][k] = ''
 
+                       for k in use_expand_unprefixed:
+                               var_split = self.get(k, '').split()
+                               var_split = [ x for x in var_split if x in myflags ]
+                               if var_split:
+                                       self.configlist[-1][k] = ' '.join(var_split)
+                               elif k in self:
+                                       self.configlist[-1][k] = ''
+
        @property
        def virts_p(self):
                warnings.warn("portage config.virts_p attribute " + \
index 6e7e63c40b8dcff0cae6e2bea89e0c74d5a68f07..3ba8ebd6f8d11db809672fb3c55cd846b2b8d910 100644 (file)
@@ -1638,8 +1638,12 @@ def _post_src_install_write_metadata(settings):
 
        build_info_dir = os.path.join(settings['PORTAGE_BUILDDIR'], 'build-info')
 
-       for k in ('IUSE',):
-               v = settings.get(k)
+       metadata_keys = ['IUSE']
+       if eapi_attrs.iuse_effective:
+               metadata_keys.append('IUSE_EFFECTIVE')
+
+       for k in metadata_keys:
+               v = settings.configdict['pkg'].get(k)
                if v is not None:
                        write_atomic(os.path.join(build_info_dir, k), v + '\n')