diff options
-rw-r--r-- | man/make.conf.5 | 3 | ||||
-rw-r--r-- | pym/portage/const.py | 2 | ||||
-rw-r--r-- | pym/portage/package/ebuild/_config/features_set.py | 62 | ||||
-rw-r--r-- | pym/portage/package/ebuild/config.py | 16 |
4 files changed, 68 insertions, 15 deletions
diff --git a/man/make.conf.5 b/man/make.conf.5 index ee0f1c1e9..fb7ee85bb 100644 --- a/man/make.conf.5 +++ b/man/make.conf.5 @@ -469,6 +469,9 @@ If a file is not claimed by another package in the same slot and it is not protected by \fICONFIG_PROTECT\fR, unmerge it even if the modification time or checksum differs from the file that was originally installed. .TP +.B unknown\-features\-filter +Filter out any unknown values that the FEATURES variable contains. +.TP .B unknown\-features\-warn Warn if FEATURES contains one or more unknown values. .TP diff --git a/pym/portage/const.py b/pym/portage/const.py index 7edb1f19f..cf24fcc31 100644 --- a/pym/portage/const.py +++ b/pym/portage/const.py @@ -97,7 +97,7 @@ SUPPORTED_FEATURES = frozenset([ "selinux", "sesandbox", "severe", "sfperms", "sign", "skiprocheck", "split-elog", "split-log", "splitdebug", "strict", "stricter", "suidctl", "test", "test-fail-continue", - "unknown-features-warn", + "unknown-features-filter", "unknown-features-warn", "unmerge-logs", "unmerge-orphans", "userfetch", "userpriv", "usersandbox", "usersync", "webrsync-gpg"]) diff --git a/pym/portage/package/ebuild/_config/features_set.py b/pym/portage/package/ebuild/_config/features_set.py index 7ab148fc8..a39fb89dc 100644 --- a/pym/portage/package/ebuild/_config/features_set.py +++ b/pym/portage/package/ebuild/_config/features_set.py @@ -5,6 +5,13 @@ __all__ = ( 'features_set', ) +import logging + +from portage.const import SUPPORTED_FEATURES +from portage.localization import _ +from portage.output import colorize +from portage.util import writemsg_level + class features_set(object): """ Provides relevant set operations needed for access and modification of @@ -51,6 +58,15 @@ class features_set(object): if need_sync: self._sync_env_var() + def difference_update(self, values): + self._settings.modifying() + values = list(values) + self._settings._features_overrides.extend('-' + k for k in values) + remove_us = self._features.intersection(values) + if remove_us: + self._features.difference_update(values) + self._sync_env_var() + def remove(self, k): """ This never raises KeyError, since it records a permanent override @@ -65,3 +81,49 @@ class features_set(object): if k in self._features: self._features.remove(k) self._sync_env_var() + + def _validate(self): + """ + Implements unknown-features-warn and unknown-features-filter. + """ + if 'unknown-features-warn' in self._features: + unknown_features = \ + self._features.difference(SUPPORTED_FEATURES) + if unknown_features: + unknown_features = unknown_features.difference( + self._settings._unknown_features) + if unknown_features: + self._settings._unknown_features.update(unknown_features) + writemsg_level(colorize("BAD", + _("FEATURES variable contains unknown value(s): %s") % \ + ", ".join(sorted(unknown_features))) \ + + "\n", level=logging.WARNING, noiselevel=-1) + + if 'unknown-features-filter' in self._features: + unknown_features = \ + self._features.difference(SUPPORTED_FEATURES) + if unknown_features: + self.difference_update(unknown_features) + self._prune_overrides() + + def _prune_overrides(self): + """ + If there are lots of invalid package.env FEATURES settings + then unknown-features-filter can make _features_overrides + grow larger and larger, so prune it. This performs incremental + stacking with preservation of negative values since they need + to persist for future config.regenerate() calls. + """ + overrides_set = set(self._settings._features_overrides) + if len(overrides_set) < len(self._settings._features_overrides): + positive = set() + negative = set() + for x in self._settings._features_overrides: + if x[:1] == '-': + positive.discard(x[:1]) + negative.add(x[:1]) + else: + positive.add(x) + negative.discard(x) + self._settings._features_overrides[:] = \ + list(positive) + list(negative) diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py index ab042a235..847ac1ccb 100644 --- a/pym/portage/package/ebuild/config.py +++ b/pym/portage/package/ebuild/config.py @@ -27,7 +27,7 @@ from portage import bsd_chflags, \ from portage.const import CACHE_PATH, \ DEPCACHE_PATH, INCREMENTALS, MAKE_CONF_FILE, \ MODULES_FILE_PATH, PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, \ - PRIVATE_PATH, PROFILE_PATH, SUPPORTED_FEATURES, USER_CONFIG_PATH, \ + PRIVATE_PATH, PROFILE_PATH, USER_CONFIG_PATH, \ USER_VIRTUALS_FILE from portage.dbapi import dbapi from portage.dbapi.porttree import portdbapi @@ -1911,19 +1911,7 @@ class config(object): self.features = features_set(self) self.features._features.update(self.get('FEATURES', '').split()) self.features._sync_env_var() - - if 'unknown-features-warn' in self.features: - unknown_features = \ - self.features._features.difference(SUPPORTED_FEATURES) - if unknown_features: - unknown_features = \ - unknown_features.difference(self._unknown_features) - if unknown_features: - self._unknown_features.update(unknown_features) - writemsg_level(colorize("BAD", - _("FEATURES variable contains unknown value(s): %s") % \ - ", ".join(sorted(unknown_features))) \ - + "\n", noiselevel=-1) + self.features._validate() myflags.update(self.useforce) arch = self.configdict["defaults"].get("ARCH") |