| # Copyright 2010 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| __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 |
| config.features. The FEATURES variable is automatically synchronized |
| upon modification. |
| |
| Modifications result in a permanent override that will cause the change |
| to propagate to the incremental stacking mechanism in config.regenerate(). |
| This eliminates the need to call config.backup_changes() when FEATURES |
| is modified, since any overrides are guaranteed to persist despite calls |
| to config.reset(). |
| """ |
| |
| def __init__(self, settings): |
| self._settings = settings |
| self._features = set() |
| |
| def __contains__(self, k): |
| return k in self._features |
| |
| def __iter__(self): |
| return iter(self._features) |
| |
| def _sync_env_var(self): |
| self._settings['FEATURES'] = ' '.join(sorted(self._features)) |
| |
| def add(self, k): |
| self._settings.modifying() |
| self._settings._features_overrides.append(k) |
| if k not in self._features: |
| self._features.add(k) |
| self._sync_env_var() |
| |
| def update(self, values): |
| self._settings.modifying() |
| values = list(values) |
| self._settings._features_overrides.extend(values) |
| need_sync = False |
| for k in values: |
| if k in self._features: |
| continue |
| self._features.add(k) |
| need_sync = True |
| 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 |
| that will prevent the given flag from ever being added again by |
| incremental stacking in config.regenerate(). |
| """ |
| self.discard(k) |
| |
| def discard(self, k): |
| self._settings.modifying() |
| self._settings._features_overrides.append('-' + k) |
| 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) |
| 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('-' + x for x in negative) |