| # Copyright 2010-2014 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| from __future__ import unicode_literals |
| |
| __all__ = [ |
| 'autouse', 'best_from_dict', 'check_config_instance', 'config', |
| ] |
| |
| import copy |
| from itertools import chain |
| import grp |
| import logging |
| import platform |
| import pwd |
| import re |
| import sys |
| import warnings |
| |
| from _emerge.Package import Package |
| import portage |
| portage.proxy.lazyimport.lazyimport(globals(), |
| 'portage.data:portage_gid', |
| 'portage.dbapi.vartree:vartree', |
| 'portage.package.ebuild.doebuild:_phase_func_map', |
| ) |
| from portage import bsd_chflags, \ |
| load_mod, os, selinux, _unicode_decode |
| from portage.const import CACHE_PATH, \ |
| DEPCACHE_PATH, INCREMENTALS, MAKE_CONF_FILE, \ |
| MODULES_FILE_PATH, PORTAGE_BASE_PATH, \ |
| PRIVATE_PATH, PROFILE_PATH, USER_CONFIG_PATH, \ |
| USER_VIRTUALS_FILE |
| from portage.dbapi import dbapi |
| from portage.dbapi.porttree import portdbapi |
| 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, _get_eapi_attrs |
| from portage.env.loaders import KeyValuePairFileLoader |
| from portage.exception import InvalidDependString, IsADirectory, \ |
| PortageException |
| from portage.localization import _ |
| from portage.output import colorize |
| from portage.process import fakeroot_capable, sandbox_capable |
| from portage.repository.config import load_repository_config |
| from portage.util import ensure_dirs, getconfig, grabdict, \ |
| grabdict_package, grabfile, grabfile_package, LazyItemsDict, \ |
| normalize_path, shlex_split, stack_dictlist, stack_dicts, stack_lists, \ |
| writemsg, writemsg_level, _eapi_cache |
| from portage.util._path import exists_raise_eaccess, isdir_raise_eaccess |
| from portage.versions import catpkgsplit, catsplit, cpv_getkey, _pkg_str |
| |
| from portage.package.ebuild._config import special_env_vars |
| from portage.package.ebuild._config.env_var_validation import validate_cmd_var |
| from portage.package.ebuild._config.features_set import features_set |
| from portage.package.ebuild._config.KeywordsManager import KeywordsManager |
| from portage.package.ebuild._config.LicenseManager import LicenseManager |
| from portage.package.ebuild._config.UseManager import UseManager |
| from portage.package.ebuild._config.LocationsManager import LocationsManager |
| from portage.package.ebuild._config.MaskManager import MaskManager |
| from portage.package.ebuild._config.VirtualsManager import VirtualsManager |
| from portage.package.ebuild._config.helper import ordered_by_atom_specificity, prune_incremental |
| from portage.package.ebuild._config.unpack_dependencies import load_unpack_dependencies_configuration |
| |
| if sys.hexversion >= 0x3000000: |
| # pylint: disable=W0622 |
| basestring = str |
| |
| _feature_flags_cache = {} |
| |
| def _get_feature_flags(eapi_attrs): |
| cache_key = (eapi_attrs.feature_flag_test, eapi_attrs.feature_flag_targetroot) |
| flags = _feature_flags_cache.get(cache_key) |
| if flags is not None: |
| return flags |
| |
| flags = [] |
| if eapi_attrs.feature_flag_test: |
| flags.append("test") |
| if eapi_attrs.feature_flag_targetroot: |
| flags.append("targetroot") |
| |
| flags = frozenset(flags) |
| _feature_flags_cache[cache_key] = flags |
| return flags |
| |
| def autouse(myvartree, use_cache=1, mysettings=None): |
| warnings.warn("portage.autouse() is deprecated", |
| DeprecationWarning, stacklevel=2) |
| return "" |
| |
| def check_config_instance(test): |
| if not isinstance(test, config): |
| raise TypeError("Invalid type for config object: %s (should be %s)" % (test.__class__, config)) |
| |
| def best_from_dict(key, top_dict, key_order, EmptyOnError=1, FullCopy=1, AllowEmpty=1): |
| for x in key_order: |
| if x in top_dict and key in top_dict[x]: |
| if FullCopy: |
| return copy.deepcopy(top_dict[x][key]) |
| else: |
| return top_dict[x][key] |
| if EmptyOnError: |
| return "" |
| else: |
| raise KeyError("Key not found in list; '%s'" % key) |
| |
| def _lazy_iuse_regex(iuse_implicit): |
| """ |
| The PORTAGE_IUSE value is lazily evaluated since re.escape() is slow |
| and the value is only used when an ebuild phase needs to be executed |
| (it's used only to generate QA notices). |
| """ |
| # Escape anything except ".*" which is supposed to pass through from |
| # _get_implicit_iuse(). |
| regex = sorted(re.escape(x) for x in iuse_implicit) |
| regex = "^(%s)$" % "|".join(regex) |
| regex = regex.replace("\\.\\*", ".*") |
| return regex |
| |
| class _iuse_implicit_match_cache(object): |
| |
| def __init__(self, settings): |
| self._iuse_implicit_re = re.compile("^(%s)$" % \ |
| "|".join(settings._get_implicit_iuse())) |
| self._cache = {} |
| |
| def __call__(self, flag): |
| """ |
| Returns True if the flag is matched, False otherwise. |
| """ |
| try: |
| return self._cache[flag] |
| except KeyError: |
| m = self._iuse_implicit_re.match(flag) is not None |
| self._cache[flag] = m |
| return m |
| |
| class config(object): |
| """ |
| This class encompasses the main portage configuration. Data is pulled from |
| ROOT/PORTDIR/profiles/, from ROOT/etc/make.profile incrementally through all |
| parent profiles as well as from ROOT/PORTAGE_CONFIGROOT/* for user specified |
| overrides. |
| |
| Generally if you need data like USE flags, FEATURES, environment variables, |
| virtuals ...etc you look in here. |
| """ |
| |
| _constant_keys = frozenset(['PORTAGE_BIN_PATH', 'PORTAGE_GID', |
| 'PORTAGE_PYM_PATH', 'PORTAGE_PYTHONPATH']) |
| |
| _setcpv_aux_keys = ('DEFINED_PHASES', 'DEPEND', 'EAPI', 'HDEPEND', |
| 'INHERITED', 'IUSE', 'REQUIRED_USE', 'KEYWORDS', 'LICENSE', 'PDEPEND', |
| 'PROPERTIES', 'PROVIDE', 'RDEPEND', 'SLOT', |
| 'repository', 'RESTRICT', 'LICENSE',) |
| |
| _module_aliases = { |
| "cache.metadata_overlay.database" : "portage.cache.flat_hash.database", |
| "portage.cache.metadata_overlay.database" : "portage.cache.flat_hash.database", |
| } |
| |
| _case_insensitive_vars = special_env_vars.case_insensitive_vars |
| _default_globals = special_env_vars.default_globals |
| _env_blacklist = special_env_vars.env_blacklist |
| _environ_filter = special_env_vars.environ_filter |
| _environ_whitelist = special_env_vars.environ_whitelist |
| _environ_whitelist_re = special_env_vars.environ_whitelist_re |
| _global_only_vars = special_env_vars.global_only_vars |
| |
| def __init__(self, clone=None, mycpv=None, config_profile_path=None, |
| config_incrementals=None, config_root=None, target_root=None, |
| eprefix=None, local_config=True, env=None, |
| _unmatched_removal=False, repositories=None): |
| """ |
| @param clone: If provided, init will use deepcopy to copy by value the instance. |
| @type clone: Instance of config class. |
| @param mycpv: CPV to load up (see setcpv), this is the same as calling init with mycpv=None |
| and then calling instance.setcpv(mycpv). |
| @type mycpv: String |
| @param config_profile_path: Configurable path to the profile (usually PROFILE_PATH from portage.const) |
| @type config_profile_path: String |
| @param config_incrementals: List of incremental variables |
| (defaults to portage.const.INCREMENTALS) |
| @type config_incrementals: List |
| @param config_root: path to read local config from (defaults to "/", see PORTAGE_CONFIGROOT) |
| @type config_root: String |
| @param target_root: the target root, which typically corresponds to the |
| value of the $ROOT env variable (default is /) |
| @type target_root: String |
| @param eprefix: set the EPREFIX variable (default is portage.const.EPREFIX) |
| @type eprefix: String |
| @param local_config: Enables loading of local config (/etc/portage); used most by repoman to |
| ignore local config (keywording and unmasking) |
| @type local_config: Boolean |
| @param env: The calling environment which is used to override settings. |
| Defaults to os.environ if unspecified. |
| @type env: dict |
| @param _unmatched_removal: Enabled by repoman when the |
| --unmatched-removal option is given. |
| @type _unmatched_removal: Boolean |
| @param repositories: Configuration of repositories. |
| Defaults to portage.repository.config.load_repository_config(). |
| @type repositories: Instance of portage.repository.config.RepoConfigLoader class. |
| """ |
| |
| # This is important when config is reloaded after emerge --sync. |
| _eapi_cache.clear() |
| |
| # When initializing the global portage.settings instance, avoid |
| # raising exceptions whenever possible since exceptions thrown |
| # from 'import portage' or 'import portage.exceptions' statements |
| # can practically render the api unusable for api consumers. |
| tolerant = hasattr(portage, '_initializing_globals') |
| self._tolerant = tolerant |
| self._unmatched_removal = _unmatched_removal |
| |
| self.locked = 0 |
| self.mycpv = None |
| self._setcpv_args_hash = None |
| self.puse = "" |
| self._penv = [] |
| self.modifiedkeys = [] |
| self.uvlist = [] |
| self._accept_chost_re = None |
| self._accept_properties = None |
| self._accept_restrict = None |
| self._features_overrides = [] |
| self._make_defaults = None |
| self._parent_stable = None |
| |
| # _unknown_features records unknown features that |
| # have triggered warning messages, and ensures that |
| # the same warning isn't shown twice. |
| self._unknown_features = set() |
| |
| self.local_config = local_config |
| |
| if clone: |
| # For immutable attributes, use shallow copy for |
| # speed and memory conservation. |
| self._tolerant = clone._tolerant |
| self._unmatched_removal = clone._unmatched_removal |
| self.categories = clone.categories |
| self.depcachedir = clone.depcachedir |
| self.incrementals = clone.incrementals |
| self.module_priority = clone.module_priority |
| self.profile_path = clone.profile_path |
| self.profiles = clone.profiles |
| self.packages = clone.packages |
| self.repositories = clone.repositories |
| self.unpack_dependencies = clone.unpack_dependencies |
| 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 |
| self._pbashrc = clone._pbashrc |
| self._repo_make_defaults = clone._repo_make_defaults |
| self.usemask = clone.usemask |
| self.useforce = clone.useforce |
| self.puse = clone.puse |
| self.user_profile_dir = clone.user_profile_dir |
| self.local_config = clone.local_config |
| self.make_defaults_use = clone.make_defaults_use |
| self.mycpv = clone.mycpv |
| self._setcpv_args_hash = clone._setcpv_args_hash |
| |
| # immutable attributes (internal policy ensures lack of mutation) |
| self._locations_manager = clone._locations_manager |
| self._use_manager = clone._use_manager |
| # force instantiation of lazy immutable objects when cloning, so |
| # that they're not instantiated more than once |
| self._keywords_manager_obj = clone._keywords_manager |
| self._mask_manager_obj = clone._mask_manager |
| |
| # shared mutable attributes |
| self._unknown_features = clone._unknown_features |
| |
| self.modules = copy.deepcopy(clone.modules) |
| self._penv = copy.deepcopy(clone._penv) |
| |
| self.configdict = copy.deepcopy(clone.configdict) |
| self.configlist = [ |
| self.configdict['env.d'], |
| self.configdict['repo'], |
| self.configdict['pkginternal'], |
| self.configdict['globals'], |
| self.configdict['defaults'], |
| self.configdict['conf'], |
| self.configdict['pkg'], |
| self.configdict['env'], |
| ] |
| self.lookuplist = self.configlist[:] |
| self.lookuplist.reverse() |
| self._use_expand_dict = copy.deepcopy(clone._use_expand_dict) |
| self.backupenv = self.configdict["backupenv"] |
| self.prevmaskdict = copy.deepcopy(clone.prevmaskdict) |
| self.pprovideddict = copy.deepcopy(clone.pprovideddict) |
| self.features = features_set(self) |
| self.features._features = copy.deepcopy(clone.features._features) |
| self._features_overrides = copy.deepcopy(clone._features_overrides) |
| |
| #Strictly speaking _license_manager is not immutable. Users need to ensure that |
| #extract_global_changes() is called right after __init__ (if at all). |
| #It also has the mutable member _undef_lic_groups. It is used to track |
| #undefined license groups, to not display an error message for the same |
| #group again and again. Because of this, it's useful to share it between |
| #all LicenseManager instances. |
| self._license_manager = clone._license_manager |
| |
| # force instantiation of lazy objects when cloning, so |
| # that they're not instantiated more than once |
| self._virtuals_manager_obj = copy.deepcopy(clone._virtuals_manager) |
| |
| self._accept_properties = copy.deepcopy(clone._accept_properties) |
| self._ppropertiesdict = copy.deepcopy(clone._ppropertiesdict) |
| self._accept_restrict = copy.deepcopy(clone._accept_restrict) |
| self._paccept_restrict = copy.deepcopy(clone._paccept_restrict) |
| self._penvdict = copy.deepcopy(clone._penvdict) |
| self._pbashrcdict = copy.deepcopy(clone._pbashrcdict) |
| self._expand_map = copy.deepcopy(clone._expand_map) |
| |
| else: |
| # lazily instantiated objects |
| self._keywords_manager_obj = None |
| self._mask_manager_obj = None |
| self._virtuals_manager_obj = None |
| |
| locations_manager = LocationsManager(config_root=config_root, |
| config_profile_path=config_profile_path, eprefix=eprefix, |
| local_config=local_config, target_root=target_root) |
| self._locations_manager = locations_manager |
| |
| eprefix = locations_manager.eprefix |
| config_root = locations_manager.config_root |
| abs_user_config = locations_manager.abs_user_config |
| make_conf_paths = [ |
| os.path.join(config_root, 'etc', 'make.conf'), |
| os.path.join(config_root, MAKE_CONF_FILE) |
| ] |
| try: |
| if os.path.samefile(*make_conf_paths): |
| make_conf_paths.pop() |
| except OSError: |
| pass |
| |
| make_conf_count = 0 |
| make_conf = {} |
| for x in make_conf_paths: |
| mygcfg = getconfig(x, |
| tolerant=tolerant, allow_sourcing=True, |
| expand=make_conf, recursive=True) |
| if mygcfg is not None: |
| make_conf.update(mygcfg) |
| make_conf_count += 1 |
| |
| if make_conf_count == 2: |
| writemsg("!!! %s\n" % |
| _("Found 2 make.conf files, using both '%s' and '%s'") % |
| tuple(make_conf_paths), noiselevel=-1) |
| |
| # Allow ROOT setting to come from make.conf if it's not overridden |
| # by the constructor argument (from the calling environment). |
| locations_manager.set_root_override(make_conf.get("ROOT")) |
| target_root = locations_manager.target_root |
| eroot = locations_manager.eroot |
| self.global_config_path = locations_manager.global_config_path |
| |
| # The expand_map is used for variable substitution |
| # in getconfig() calls, and the getconfig() calls |
| # update expand_map with the value of each variable |
| # assignment that occurs. Variable substitution occurs |
| # in the following order, which corresponds to the |
| # order of appearance in self.lookuplist: |
| # |
| # * env.d |
| # * make.globals |
| # * make.defaults |
| # * make.conf |
| # |
| # Notably absent is "env", since we want to avoid any |
| # interaction with the calling environment that might |
| # lead to unexpected results. |
| |
| env_d = getconfig(os.path.join(eroot, "etc", "profile.env"), |
| tolerant=tolerant, expand=False) or {} |
| expand_map = env_d.copy() |
| self._expand_map = expand_map |
| |
| # Allow make.globals to set default paths relative to ${EPREFIX}. |
| expand_map["EPREFIX"] = eprefix |
| |
| if portage._not_installed: |
| make_globals_path = os.path.join(PORTAGE_BASE_PATH, "cnf", "make.globals") |
| else: |
| make_globals_path = os.path.join(self.global_config_path, "make.globals") |
| old_make_globals = os.path.join(config_root, "etc", "make.globals") |
| if os.path.isfile(old_make_globals) and \ |
| not os.path.samefile(make_globals_path, old_make_globals): |
| # Don't warn if they refer to the same path, since |
| # that can be used for backward compatibility with |
| # old software. |
| writemsg("!!! %s\n" % |
| _("Found obsolete make.globals file: " |
| "'%s', (using '%s' instead)") % |
| (old_make_globals, make_globals_path), |
| noiselevel=-1) |
| |
| make_globals = getconfig(make_globals_path, |
| tolerant=tolerant, expand=expand_map) |
| if make_globals is None: |
| make_globals = {} |
| |
| for k, v in self._default_globals.items(): |
| make_globals.setdefault(k, v) |
| |
| if config_incrementals is None: |
| self.incrementals = INCREMENTALS |
| else: |
| self.incrementals = config_incrementals |
| if not isinstance(self.incrementals, frozenset): |
| self.incrementals = frozenset(self.incrementals) |
| |
| self.module_priority = ("user", "default") |
| self.modules = {} |
| modules_file = os.path.join(config_root, MODULES_FILE_PATH) |
| modules_loader = KeyValuePairFileLoader(modules_file, None, None) |
| modules_dict, modules_errors = modules_loader.load() |
| self.modules["user"] = modules_dict |
| if self.modules["user"] is None: |
| self.modules["user"] = {} |
| user_auxdbmodule = \ |
| self.modules["user"].get("portdbapi.auxdbmodule") |
| if user_auxdbmodule is not None and \ |
| user_auxdbmodule in self._module_aliases: |
| warnings.warn("'%s' is deprecated: %s" % |
| (user_auxdbmodule, modules_file)) |
| |
| self.modules["default"] = { |
| "portdbapi.auxdbmodule": "portage.cache.flat_hash.database", |
| } |
| |
| self.configlist=[] |
| |
| # back up our incremental variables: |
| self.configdict={} |
| self._use_expand_dict = {} |
| # configlist will contain: [ env.d, globals, defaults, conf, pkg, backupenv, env ] |
| self.configlist.append({}) |
| self.configdict["env.d"] = self.configlist[-1] |
| |
| self.configlist.append({}) |
| self.configdict["repo"] = self.configlist[-1] |
| |
| self.configlist.append({}) |
| self.configdict["pkginternal"] = self.configlist[-1] |
| |
| # env_d will be None if profile.env doesn't exist. |
| if env_d: |
| self.configdict["env.d"].update(env_d) |
| |
| # backupenv is used for calculating incremental variables. |
| if env is None: |
| env = os.environ |
| |
| # Avoid potential UnicodeDecodeError exceptions later. |
| env_unicode = dict((_unicode_decode(k), _unicode_decode(v)) |
| for k, v in env.items()) |
| |
| self.backupenv = env_unicode |
| |
| if env_d: |
| # Remove duplicate values so they don't override updated |
| # profile.env values later (profile.env is reloaded in each |
| # call to self.regenerate). |
| for k, v in env_d.items(): |
| try: |
| if self.backupenv[k] == v: |
| del self.backupenv[k] |
| except KeyError: |
| pass |
| del k, v |
| |
| self.configdict["env"] = LazyItemsDict(self.backupenv) |
| |
| self.configlist.append(make_globals) |
| self.configdict["globals"]=self.configlist[-1] |
| |
| self.make_defaults_use = [] |
| |
| #Loading Repositories |
| self["PORTAGE_CONFIGROOT"] = config_root |
| self["ROOT"] = target_root |
| self["EPREFIX"] = eprefix |
| self["EROOT"] = eroot |
| known_repos = [] |
| portdir = "" |
| portdir_overlay = "" |
| portdir_sync = None |
| for confs in [make_globals, make_conf, self.configdict["env"]]: |
| v = confs.get("PORTDIR") |
| if v is not None: |
| portdir = v |
| known_repos.append(v) |
| v = confs.get("PORTDIR_OVERLAY") |
| if v is not None: |
| portdir_overlay = v |
| known_repos.extend(shlex_split(v)) |
| v = confs.get("SYNC") |
| if v is not None: |
| portdir_sync = v |
| |
| known_repos = frozenset(known_repos) |
| self["PORTDIR"] = portdir |
| self["PORTDIR_OVERLAY"] = portdir_overlay |
| if portdir_sync: |
| self["SYNC"] = portdir_sync |
| self.lookuplist = [self.configdict["env"]] |
| if repositories is None: |
| self.repositories = load_repository_config(self) |
| else: |
| self.repositories = repositories |
| |
| self['PORTAGE_REPOSITORIES'] = self.repositories.config_string() |
| self.backup_changes('PORTAGE_REPOSITORIES') |
| |
| #filling PORTDIR and PORTDIR_OVERLAY variable for compatibility |
| main_repo = self.repositories.mainRepo() |
| if main_repo is not None: |
| self["PORTDIR"] = main_repo.user_location |
| self.backup_changes("PORTDIR") |
| expand_map["PORTDIR"] = self["PORTDIR"] |
| |
| # repoman controls PORTDIR_OVERLAY via the environment, so no |
| # special cases are needed here. |
| portdir_overlay = list(self.repositories.repoUserLocationList()) |
| if portdir_overlay and portdir_overlay[0] == self["PORTDIR"]: |
| portdir_overlay = portdir_overlay[1:] |
| |
| new_ov = [] |
| if portdir_overlay: |
| for ov in portdir_overlay: |
| ov = normalize_path(ov) |
| if isdir_raise_eaccess(ov) or portage._sync_mode: |
| new_ov.append(portage._shell_quote(ov)) |
| else: |
| writemsg(_("!!! Invalid PORTDIR_OVERLAY" |
| " (not a dir): '%s'\n") % ov, noiselevel=-1) |
| |
| self["PORTDIR_OVERLAY"] = " ".join(new_ov) |
| self.backup_changes("PORTDIR_OVERLAY") |
| expand_map["PORTDIR_OVERLAY"] = self["PORTDIR_OVERLAY"] |
| |
| locations_manager.set_port_dirs(self["PORTDIR"], self["PORTDIR_OVERLAY"]) |
| locations_manager.load_profiles(self.repositories, known_repos) |
| |
| profiles_complex = locations_manager.profiles_complex |
| self.profiles = locations_manager.profiles |
| self.profile_path = locations_manager.profile_path |
| self.user_profile_dir = locations_manager.user_profile_dir |
| |
| try: |
| packages_list = [grabfile_package(os.path.join(x, "packages"), |
| verify_eapi=True) for x in self.profiles] |
| except IOError as e: |
| if e.errno == IsADirectory.errno: |
| raise IsADirectory(os.path.join(self.profile_path, |
| "packages")) |
| |
| self.packages = tuple(stack_lists(packages_list, incremental=1)) |
| |
| # revmaskdict |
| self.prevmaskdict={} |
| for x in self.packages: |
| # Negative atoms are filtered by the above stack_lists() call. |
| if not isinstance(x, Atom): |
| x = Atom(x.lstrip('*')) |
| self.prevmaskdict.setdefault(x.cp, []).append(x) |
| |
| self.unpack_dependencies = load_unpack_dependencies_configuration(self.repositories) |
| |
| mygcfg = {} |
| if profiles_complex: |
| mygcfg_dlists = [getconfig(os.path.join(x.location, "make.defaults"), |
| tolerant=tolerant, expand=expand_map, recursive=x.portage1_directories) |
| for x in profiles_complex] |
| self._make_defaults = mygcfg_dlists |
| mygcfg = stack_dicts(mygcfg_dlists, |
| incrementals=self.incrementals) |
| if mygcfg is None: |
| mygcfg = {} |
| self.configlist.append(mygcfg) |
| self.configdict["defaults"]=self.configlist[-1] |
| |
| mygcfg = {} |
| for x in make_conf_paths: |
| mygcfg.update(getconfig(x, |
| tolerant=tolerant, allow_sourcing=True, |
| expand=expand_map, recursive=True) or {}) |
| |
| # Don't allow the user to override certain variables in make.conf |
| profile_only_variables = self.configdict["defaults"].get( |
| "PROFILE_ONLY_VARIABLES", "").split() |
| profile_only_variables = stack_lists([profile_only_variables]) |
| non_user_variables = set() |
| non_user_variables.update(profile_only_variables) |
| non_user_variables.update(self._env_blacklist) |
| non_user_variables.update(self._global_only_vars) |
| non_user_variables = frozenset(non_user_variables) |
| self._non_user_variables = non_user_variables |
| |
| self._env_d_blacklist = frozenset(chain( |
| profile_only_variables, |
| self._env_blacklist, |
| )) |
| env_d = self.configdict["env.d"] |
| for k in self._env_d_blacklist: |
| env_d.pop(k, None) |
| |
| for k in profile_only_variables: |
| mygcfg.pop(k, None) |
| |
| self.configlist.append(mygcfg) |
| self.configdict["conf"]=self.configlist[-1] |
| |
| self.configlist.append(LazyItemsDict()) |
| self.configdict["pkg"]=self.configlist[-1] |
| |
| self.configdict["backupenv"] = self.backupenv |
| |
| # Don't allow the user to override certain variables in the env |
| for k in profile_only_variables: |
| self.backupenv.pop(k, None) |
| |
| self.configlist.append(self.configdict["env"]) |
| |
| # make lookuplist for loading package.* |
| self.lookuplist=self.configlist[:] |
| self.lookuplist.reverse() |
| |
| # Blacklist vars that could interfere with portage internals. |
| for blacklisted in self._env_blacklist: |
| for cfg in self.lookuplist: |
| cfg.pop(blacklisted, None) |
| self.backupenv.pop(blacklisted, None) |
| del blacklisted, cfg |
| |
| self["PORTAGE_CONFIGROOT"] = config_root |
| self.backup_changes("PORTAGE_CONFIGROOT") |
| self["ROOT"] = target_root |
| self.backup_changes("ROOT") |
| self["EPREFIX"] = eprefix |
| self.backup_changes("EPREFIX") |
| self["EROOT"] = eroot |
| self.backup_changes("EROOT") |
| |
| # The prefix of the running portage instance is used in the |
| # ebuild environment to implement the --host-root option for |
| # best_version and has_version. |
| self["PORTAGE_OVERRIDE_EPREFIX"] = portage.const.EPREFIX |
| self.backup_changes("PORTAGE_OVERRIDE_EPREFIX") |
| |
| self._ppropertiesdict = portage.dep.ExtendedAtomDict(dict) |
| self._paccept_restrict = portage.dep.ExtendedAtomDict(dict) |
| self._penvdict = portage.dep.ExtendedAtomDict(dict) |
| self._pbashrcdict = {} |
| self._pbashrc = () |
| |
| self._repo_make_defaults = {} |
| for repo in self.repositories.repos_with_profiles(): |
| d = getconfig(os.path.join(repo.location, "profiles", "make.defaults"), |
| tolerant=tolerant, expand=self.configdict["globals"].copy(), recursive=repo.portage1_profiles) or {} |
| if d: |
| for k in chain(self._env_blacklist, |
| profile_only_variables, self._global_only_vars): |
| d.pop(k, None) |
| self._repo_make_defaults[repo.name] = d |
| |
| #Read all USE related files from profiles and optionally from user config. |
| self._use_manager = UseManager(self.repositories, profiles_complex, |
| abs_user_config, self._isStable, user_config=local_config) |
| #Initialize all USE related variables we track ourselves. |
| self.usemask = self._use_manager.getUseMask() |
| self.useforce = self._use_manager.getUseForce() |
| self.configdict["conf"]["USE"] = \ |
| self._use_manager.extract_global_USE_changes( \ |
| self.configdict["conf"].get("USE", "")) |
| |
| #Read license_groups and optionally license_groups and package.license from user config |
| self._license_manager = LicenseManager(locations_manager.profile_locations, \ |
| abs_user_config, user_config=local_config) |
| #Extract '*/*' entries from package.license |
| self.configdict["conf"]["ACCEPT_LICENSE"] = \ |
| self._license_manager.extract_global_changes( \ |
| self.configdict["conf"].get("ACCEPT_LICENSE", "")) |
| |
| if local_config: |
| #package.properties |
| propdict = grabdict_package(os.path.join( |
| abs_user_config, "package.properties"), recursive=1, allow_wildcard=True, \ |
| allow_repo=True, verify_eapi=False) |
| v = propdict.pop("*/*", None) |
| if v is not None: |
| if "ACCEPT_PROPERTIES" in self.configdict["conf"]: |
| self.configdict["conf"]["ACCEPT_PROPERTIES"] += " " + " ".join(v) |
| else: |
| self.configdict["conf"]["ACCEPT_PROPERTIES"] = " ".join(v) |
| for k, v in propdict.items(): |
| self._ppropertiesdict.setdefault(k.cp, {})[k] = v |
| |
| # package.accept_restrict |
| d = grabdict_package(os.path.join( |
| abs_user_config, "package.accept_restrict"), |
| recursive=True, allow_wildcard=True, |
| allow_repo=True, verify_eapi=False) |
| v = d.pop("*/*", None) |
| if v is not None: |
| if "ACCEPT_RESTRICT" in self.configdict["conf"]: |
| self.configdict["conf"]["ACCEPT_RESTRICT"] += " " + " ".join(v) |
| else: |
| self.configdict["conf"]["ACCEPT_RESTRICT"] = " ".join(v) |
| for k, v in d.items(): |
| self._paccept_restrict.setdefault(k.cp, {})[k] = v |
| |
| #package.env |
| penvdict = grabdict_package(os.path.join( |
| abs_user_config, "package.env"), recursive=1, allow_wildcard=True, \ |
| allow_repo=True, verify_eapi=False) |
| v = penvdict.pop("*/*", None) |
| if v is not None: |
| global_wildcard_conf = {} |
| self._grab_pkg_env(v, global_wildcard_conf) |
| incrementals = self.incrementals |
| conf_configdict = self.configdict["conf"] |
| for k, v in global_wildcard_conf.items(): |
| if k in incrementals: |
| if k in conf_configdict: |
| conf_configdict[k] = \ |
| conf_configdict[k] + " " + v |
| else: |
| conf_configdict[k] = v |
| else: |
| conf_configdict[k] = v |
| expand_map[k] = v |
| |
| for k, v in penvdict.items(): |
| self._penvdict.setdefault(k.cp, {})[k] = v |
| |
| # package.bashrc |
| for profile in profiles_complex: |
| if not 'profile-bashrcs' in profile.profile_formats: |
| continue |
| self._pbashrcdict[profile] = \ |
| portage.dep.ExtendedAtomDict(dict) |
| bashrc = grabdict_package(os.path.join(profile.location, |
| "package.bashrc"), recursive=1, allow_wildcard=True, |
| allow_repo=True, verify_eapi=False) |
| if not bashrc: |
| continue |
| |
| for k, v in bashrc.items(): |
| envfiles = [os.path.join(profile.location, |
| "bashrc", |
| envname) for envname in v] |
| self._pbashrcdict[profile].setdefault(k.cp, {})\ |
| .setdefault(k, []).extend(envfiles) |
| |
| #getting categories from an external file now |
| self.categories = [grabfile(os.path.join(x, "categories")) \ |
| for x in locations_manager.profile_and_user_locations] |
| category_re = dbapi._category_re |
| # categories used to be a tuple, but now we use a frozenset |
| # for hashed category validation in pordbapi.cp_list() |
| self.categories = frozenset( |
| x for x in stack_lists(self.categories, incremental=1) |
| if category_re.match(x) is not None) |
| |
| archlist = [grabfile(os.path.join(x, "arch.list")) \ |
| for x in locations_manager.profile_and_user_locations] |
| archlist = stack_lists(archlist, incremental=1) |
| self.configdict["conf"]["PORTAGE_ARCHLIST"] = " ".join(archlist) |
| |
| pkgprovidedlines = [grabfile( |
| os.path.join(x.location, "package.provided"), |
| recursive=x.portage1_directories) |
| for x in profiles_complex] |
| pkgprovidedlines = stack_lists(pkgprovidedlines, incremental=1) |
| has_invalid_data = False |
| for x in range(len(pkgprovidedlines)-1, -1, -1): |
| myline = pkgprovidedlines[x] |
| if not isvalidatom("=" + myline): |
| writemsg(_("Invalid package name in package.provided: %s\n") % \ |
| myline, noiselevel=-1) |
| has_invalid_data = True |
| del pkgprovidedlines[x] |
| continue |
| cpvr = catpkgsplit(pkgprovidedlines[x]) |
| if not cpvr or cpvr[0] == "null": |
| writemsg(_("Invalid package name in package.provided: ")+pkgprovidedlines[x]+"\n", |
| noiselevel=-1) |
| has_invalid_data = True |
| del pkgprovidedlines[x] |
| continue |
| if cpvr[0] == "virtual": |
| writemsg(_("Virtual package in package.provided: %s\n") % \ |
| myline, noiselevel=-1) |
| has_invalid_data = True |
| del pkgprovidedlines[x] |
| continue |
| if has_invalid_data: |
| writemsg(_("See portage(5) for correct package.provided usage.\n"), |
| noiselevel=-1) |
| self.pprovideddict = {} |
| for x in pkgprovidedlines: |
| x_split = catpkgsplit(x) |
| if x_split is None: |
| continue |
| mycatpkg = cpv_getkey(x) |
| if mycatpkg in self.pprovideddict: |
| self.pprovideddict[mycatpkg].append(x) |
| else: |
| self.pprovideddict[mycatpkg]=[x] |
| |
| # reasonable defaults; this is important as without USE_ORDER, |
| # USE will always be "" (nothing set)! |
| if "USE_ORDER" not in self: |
| self.backupenv["USE_ORDER"] = "env:pkg:conf:defaults:pkginternal:repo:env.d" |
| |
| self.depcachedir = DEPCACHE_PATH |
| if portage.const.EPREFIX: |
| self.depcachedir = os.path.join(portage.const.EPREFIX, |
| DEPCACHE_PATH.lstrip(os.sep)) |
| |
| if self.get("PORTAGE_DEPCACHEDIR", None): |
| self.depcachedir = self["PORTAGE_DEPCACHEDIR"] |
| self["PORTAGE_DEPCACHEDIR"] = self.depcachedir |
| self.backup_changes("PORTAGE_DEPCACHEDIR") |
| |
| if "CBUILD" not in self and "CHOST" in self: |
| self["CBUILD"] = self["CHOST"] |
| self.backup_changes("CBUILD") |
| |
| if "USERLAND" not in self: |
| # Set default USERLAND so that our test cases can assume that |
| # it's always set. This allows isolated-functions.sh to avoid |
| # calling uname -s when sourced. |
| system = platform.system() |
| if system is not None and \ |
| (system.endswith("BSD") or system == "DragonFly"): |
| self["USERLAND"] = "BSD" |
| else: |
| self["USERLAND"] = "GNU" |
| self.backup_changes("USERLAND") |
| |
| default_inst_ids = { |
| "PORTAGE_INST_GID": "0", |
| "PORTAGE_INST_UID": "0", |
| } |
| |
| if eprefix: |
| # For prefix environments, default to the UID and GID of |
| # the top-level EROOT directory. |
| try: |
| eroot_st = os.stat(eroot) |
| except OSError: |
| pass |
| else: |
| default_inst_ids["PORTAGE_INST_GID"] = str(eroot_st.st_gid) |
| default_inst_ids["PORTAGE_INST_UID"] = str(eroot_st.st_uid) |
| |
| if "PORTAGE_USERNAME" not in self: |
| try: |
| pwd_struct = pwd.getpwuid(eroot_st.st_uid) |
| except KeyError: |
| pass |
| else: |
| self["PORTAGE_USERNAME"] = pwd_struct.pw_name |
| self.backup_changes("PORTAGE_USERNAME") |
| |
| if "PORTAGE_GRPNAME" not in self: |
| try: |
| grp_struct = grp.getgrgid(eroot_st.st_gid) |
| except KeyError: |
| pass |
| else: |
| self["PORTAGE_GRPNAME"] = grp_struct.gr_name |
| self.backup_changes("PORTAGE_GRPNAME") |
| |
| for var, default_val in default_inst_ids.items(): |
| try: |
| self[var] = str(int(self.get(var, default_val))) |
| except ValueError: |
| writemsg(_("!!! %s='%s' is not a valid integer. " |
| "Falling back to %s.\n") % (var, self[var], default_val), |
| noiselevel=-1) |
| self[var] = default_val |
| self.backup_changes(var) |
| |
| if portage._internal_caller: |
| self["PORTAGE_INTERNAL_CALLER"] = "1" |
| self.backup_changes("PORTAGE_INTERNAL_CALLER") |
| |
| # initialize self.features |
| self.regenerate() |
| |
| 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() |
| |
| for k in self._case_insensitive_vars: |
| if k in self: |
| self[k] = self[k].lower() |
| self.backup_changes(k) |
| |
| # The first constructed config object initializes these modules, |
| # and subsequent calls to the _init() functions have no effect. |
| portage.output._init(config_root=self['PORTAGE_CONFIGROOT']) |
| portage.data._init(self) |
| |
| if mycpv: |
| self.setcpv(mycpv) |
| |
| @property |
| def mygcfg(self): |
| warnings.warn("portage.config.mygcfg is deprecated", stacklevel=3) |
| return {} |
| |
| def _validate_commands(self): |
| for k in special_env_vars.validate_commands: |
| v = self.get(k) |
| if v is not None: |
| valid, v_split = validate_cmd_var(v) |
| |
| if not valid: |
| if v_split: |
| writemsg_level(_("%s setting is invalid: '%s'\n") % \ |
| (k, v), level=logging.ERROR, noiselevel=-1) |
| |
| # before deleting the invalid setting, backup |
| # the default value if available |
| v = self.configdict['globals'].get(k) |
| if v is not None: |
| default_valid, v_split = validate_cmd_var(v) |
| if not default_valid: |
| if v_split: |
| writemsg_level( |
| _("%s setting from make.globals" + \ |
| " is invalid: '%s'\n") % \ |
| (k, v), level=logging.ERROR, noiselevel=-1) |
| # make.globals seems corrupt, so try for |
| # a hardcoded default instead |
| v = self._default_globals.get(k) |
| |
| # delete all settings for this key, |
| # including the invalid one |
| del self[k] |
| self.backupenv.pop(k, None) |
| if v: |
| # restore validated default |
| self.configdict['globals'][k] = v |
| |
| def _init_dirs(self): |
| """ |
| Create a few directories that are critical to portage operation |
| """ |
| if not os.access(self["EROOT"], os.W_OK): |
| return |
| |
| # gid, mode, mask, preserve_perms |
| dir_mode_map = { |
| "tmp" : ( -1, 0o1777, 0, True), |
| "var/tmp" : ( -1, 0o1777, 0, True), |
| PRIVATE_PATH : (portage_gid, 0o2750, 0o2, False), |
| CACHE_PATH : (portage_gid, 0o755, 0o2, False) |
| } |
| |
| for mypath, (gid, mode, modemask, preserve_perms) \ |
| in dir_mode_map.items(): |
| mydir = os.path.join(self["EROOT"], mypath) |
| if preserve_perms and os.path.isdir(mydir): |
| # Only adjust permissions on some directories if |
| # they don't exist yet. This gives freedom to the |
| # user to adjust permissions to suit their taste. |
| continue |
| try: |
| ensure_dirs(mydir, gid=gid, mode=mode, mask=modemask) |
| except PortageException as e: |
| writemsg(_("!!! Directory initialization failed: '%s'\n") % mydir, |
| noiselevel=-1) |
| writemsg("!!! %s\n" % str(e), |
| noiselevel=-1) |
| |
| @property |
| def _keywords_manager(self): |
| if self._keywords_manager_obj is None: |
| self._keywords_manager_obj = KeywordsManager( |
| self._locations_manager.profiles_complex, |
| self._locations_manager.abs_user_config, |
| self.local_config, |
| global_accept_keywords=self.configdict["defaults"].get("ACCEPT_KEYWORDS", "")) |
| return self._keywords_manager_obj |
| |
| @property |
| def _mask_manager(self): |
| if self._mask_manager_obj is None: |
| self._mask_manager_obj = MaskManager(self.repositories, |
| self._locations_manager.profiles_complex, |
| self._locations_manager.abs_user_config, |
| user_config=self.local_config, |
| strict_umatched_removal=self._unmatched_removal) |
| return self._mask_manager_obj |
| |
| @property |
| def _virtuals_manager(self): |
| if self._virtuals_manager_obj is None: |
| self._virtuals_manager_obj = VirtualsManager(self.profiles) |
| return self._virtuals_manager_obj |
| |
| @property |
| def pkeywordsdict(self): |
| result = self._keywords_manager.pkeywordsdict.copy() |
| for k, v in result.items(): |
| result[k] = v.copy() |
| return result |
| |
| @property |
| def pmaskdict(self): |
| return self._mask_manager._pmaskdict.copy() |
| |
| @property |
| def punmaskdict(self): |
| return self._mask_manager._punmaskdict.copy() |
| |
| def expandLicenseTokens(self, tokens): |
| """ Take a token from ACCEPT_LICENSE or package.license and expand it |
| if it's a group token (indicated by @) or just return it if it's not a |
| group. If a group is negated then negate all group elements.""" |
| return self._license_manager.expandLicenseTokens(tokens) |
| |
| def validate(self): |
| """Validate miscellaneous settings and display warnings if necessary. |
| (This code was previously in the global scope of portage.py)""" |
| |
| groups = self["ACCEPT_KEYWORDS"].split() |
| archlist = self.archlist() |
| if not archlist: |
| writemsg(_("--- 'profiles/arch.list' is empty or " |
| "not available. Empty portage tree?\n"), noiselevel=1) |
| else: |
| for group in groups: |
| if group not in archlist and \ |
| not (group.startswith("-") and group[1:] in archlist) and \ |
| group not in ("*", "~*", "**"): |
| writemsg(_("!!! INVALID ACCEPT_KEYWORDS: %s\n") % str(group), |
| noiselevel=-1) |
| |
| profile_broken = False |
| |
| if not self.profile_path: |
| profile_broken = True |
| else: |
| # If any one of these files exists, then |
| # the profile is considered valid. |
| for x in ("make.defaults", "parent", |
| "packages", "use.force", "use.mask"): |
| if exists_raise_eaccess(os.path.join(self.profile_path, x)): |
| break |
| else: |
| profile_broken = True |
| |
| if profile_broken and not portage._sync_mode: |
| abs_profile_path = None |
| for x in (PROFILE_PATH, 'etc/make.profile'): |
| x = os.path.join(self["PORTAGE_CONFIGROOT"], x) |
| try: |
| os.lstat(x) |
| except OSError: |
| pass |
| else: |
| abs_profile_path = x |
| break |
| |
| if abs_profile_path is None: |
| abs_profile_path = os.path.join(self["PORTAGE_CONFIGROOT"], |
| PROFILE_PATH) |
| |
| writemsg(_("\n\n!!! %s is not a symlink and will probably prevent most merges.\n") % abs_profile_path, |
| noiselevel=-1) |
| writemsg(_("!!! It should point into a profile within %s/profiles/\n") % self["PORTDIR"]) |
| writemsg(_("!!! (You can safely ignore this message when syncing. It's harmless.)\n\n\n")) |
| |
| abs_user_virtuals = os.path.join(self["PORTAGE_CONFIGROOT"], |
| USER_VIRTUALS_FILE) |
| if os.path.exists(abs_user_virtuals): |
| writemsg("\n!!! /etc/portage/virtuals is deprecated in favor of\n") |
| writemsg("!!! /etc/portage/profile/virtuals. Please move it to\n") |
| writemsg("!!! this new location.\n\n") |
| |
| if not sandbox_capable and \ |
| ("sandbox" in self.features or "usersandbox" in self.features): |
| if self.profile_path is not None and \ |
| os.path.realpath(self.profile_path) == \ |
| os.path.realpath(os.path.join( |
| self["PORTAGE_CONFIGROOT"], PROFILE_PATH)): |
| # Don't show this warning when running repoman and the |
| # sandbox feature came from a profile that doesn't belong |
| # to the user. |
| writemsg(colorize("BAD", _("!!! Problem with sandbox" |
| " binary. Disabling...\n\n")), noiselevel=-1) |
| |
| if "fakeroot" in self.features and \ |
| not fakeroot_capable: |
| writemsg(_("!!! FEATURES=fakeroot is enabled, but the " |
| "fakeroot binary is not installed.\n"), noiselevel=-1) |
| |
| if os.getuid() == 0 and not hasattr(os, "setgroups"): |
| warning_shown = False |
| |
| if "userpriv" in self.features: |
| writemsg(_("!!! FEATURES=userpriv is enabled, but " |
| "os.setgroups is not available.\n"), noiselevel=-1) |
| warning_shown = True |
| |
| if "userfetch" in self.features: |
| writemsg(_("!!! FEATURES=userfetch is enabled, but " |
| "os.setgroups is not available.\n"), noiselevel=-1) |
| warning_shown = True |
| |
| if warning_shown and platform.python_implementation() == 'PyPy': |
| writemsg(_("!!! See https://bugs.pypy.org/issue833 for details.\n"), |
| noiselevel=-1) |
| |
| def load_best_module(self,property_string): |
| best_mod = best_from_dict(property_string,self.modules,self.module_priority) |
| mod = None |
| try: |
| mod = load_mod(best_mod) |
| except ImportError: |
| if best_mod in self._module_aliases: |
| mod = load_mod(self._module_aliases[best_mod]) |
| elif not best_mod.startswith("cache."): |
| raise |
| else: |
| best_mod = "portage." + best_mod |
| try: |
| mod = load_mod(best_mod) |
| except ImportError: |
| raise |
| return mod |
| |
| def lock(self): |
| self.locked = 1 |
| |
| def unlock(self): |
| self.locked = 0 |
| |
| def modifying(self): |
| if self.locked: |
| raise Exception(_("Configuration is locked.")) |
| |
| def backup_changes(self,key=None): |
| self.modifying() |
| if key and key in self.configdict["env"]: |
| self.backupenv[key] = copy.deepcopy(self.configdict["env"][key]) |
| else: |
| raise KeyError(_("No such key defined in environment: %s") % key) |
| |
| def reset(self, keeping_pkg=0, use_cache=None): |
| """ |
| Restore environment from self.backupenv, call self.regenerate() |
| @param keeping_pkg: Should we keep the setcpv() data or delete it. |
| @type keeping_pkg: Boolean |
| @rype: None |
| """ |
| |
| if use_cache is not None: |
| warnings.warn("The use_cache parameter for config.reset() is deprecated and without effect.", |
| DeprecationWarning, stacklevel=2) |
| |
| self.modifying() |
| self.configdict["env"].clear() |
| self.configdict["env"].update(self.backupenv) |
| |
| self.modifiedkeys = [] |
| if not keeping_pkg: |
| self.mycpv = None |
| self._setcpv_args_hash = None |
| self.puse = "" |
| del self._penv[:] |
| self.configdict["pkg"].clear() |
| self.configdict["pkginternal"].clear() |
| self.configdict["repo"].clear() |
| self.configdict["defaults"]["USE"] = \ |
| " ".join(self.make_defaults_use) |
| self.usemask = self._use_manager.getUseMask() |
| self.useforce = self._use_manager.getUseForce() |
| self.regenerate() |
| |
| class _lazy_vars(object): |
| |
| __slots__ = ('built_use', 'settings', 'values') |
| |
| def __init__(self, built_use, settings): |
| self.built_use = built_use |
| self.settings = settings |
| self.values = None |
| |
| def __getitem__(self, k): |
| if self.values is None: |
| self.values = self._init_values() |
| return self.values[k] |
| |
| def _init_values(self): |
| values = {} |
| settings = self.settings |
| use = self.built_use |
| if use is None: |
| use = frozenset(settings['PORTAGE_USE'].split()) |
| |
| values['ACCEPT_LICENSE'] = settings._license_manager.get_prunned_accept_license( \ |
| settings.mycpv, use, settings['LICENSE'], settings['SLOT'], settings.get('PORTAGE_REPO_NAME')) |
| values['PORTAGE_RESTRICT'] = self._restrict(use, settings) |
| return values |
| |
| def _restrict(self, use, settings): |
| try: |
| restrict = set(use_reduce(settings['RESTRICT'], uselist=use, flat=True)) |
| except InvalidDependString: |
| restrict = set() |
| return ' '.join(sorted(restrict)) |
| |
| class _lazy_use_expand(object): |
| """ |
| Lazily evaluate USE_EXPAND variables since they are only needed when |
| an ebuild shell is spawned. Variables values are made consistent with |
| the previously calculated USE settings. |
| """ |
| |
| def __init__(self, settings, unfiltered_use, |
| use, usemask, iuse_implicit, |
| use_expand_split, use_expand_dict): |
| self._settings = settings |
| self._unfiltered_use = unfiltered_use |
| self._use = use |
| self._usemask = usemask |
| self._iuse_implicit = iuse_implicit |
| self._use_expand_split = use_expand_split |
| self._use_expand_dict = use_expand_dict |
| |
| def __getitem__(self, key): |
| prefix = key.lower() + '_' |
| prefix_len = len(prefix) |
| expand_flags = set( x[prefix_len:] for x in self._use \ |
| if x[:prefix_len] == prefix ) |
| var_split = self._use_expand_dict.get(key, '').split() |
| # Preserve the order of var_split because it can matter for things |
| # like LINGUAS. |
| var_split = [ x for x in var_split if x in expand_flags ] |
| var_split.extend(expand_flags.difference(var_split)) |
| has_wildcard = '*' in expand_flags |
| if has_wildcard: |
| var_split = [ x for x in var_split if x != "*" ] |
| has_iuse = set() |
| for x in self._iuse_implicit: |
| if x[:prefix_len] == prefix: |
| has_iuse.add(x[prefix_len:]) |
| if has_wildcard: |
| # * means to enable everything in IUSE that's not masked |
| if has_iuse: |
| usemask = self._usemask |
| for suffix in has_iuse: |
| x = prefix + suffix |
| if x not in usemask: |
| if suffix not in expand_flags: |
| var_split.append(suffix) |
| else: |
| # If there is a wildcard and no matching flags in IUSE then |
| # LINGUAS should be unset so that all .mo files are |
| # installed. |
| var_split = [] |
| # Make the flags unique and filter them according to IUSE. |
| # Also, continue to preserve order for things like LINGUAS |
| # and filter any duplicates that variable may contain. |
| filtered_var_split = [] |
| remaining = has_iuse.intersection(var_split) |
| for x in var_split: |
| if x in remaining: |
| remaining.remove(x) |
| filtered_var_split.append(x) |
| var_split = filtered_var_split |
| |
| if var_split: |
| value = ' '.join(var_split) |
| else: |
| # Don't export empty USE_EXPAND vars unless the user config |
| # exports them as empty. This is required for vars such as |
| # LINGUAS, where unset and empty have different meanings. |
| # The special '*' token is understood by ebuild.sh, which |
| # will unset the variable so that things like LINGUAS work |
| # properly (see bug #459350). |
| if has_wildcard: |
| value = '*' |
| else: |
| if has_iuse: |
| already_set = False |
| # Skip the first 'env' configdict, in order to |
| # avoid infinite recursion here, since that dict's |
| # __getitem__ calls the current __getitem__. |
| for d in self._settings.lookuplist[1:]: |
| if key in d: |
| already_set = True |
| break |
| |
| if not already_set: |
| for x in self._unfiltered_use: |
| if x[:prefix_len] == prefix: |
| already_set = True |
| break |
| |
| if already_set: |
| value = '' |
| else: |
| value = '*' |
| else: |
| # It's not in IUSE, so just allow the variable content |
| # to pass through if it is defined somewhere. This |
| # allows packages that support LINGUAS but don't |
| # declare it in IUSE to use the variable outside of the |
| # USE_EXPAND context. |
| value = None |
| |
| return value |
| |
| def setcpv(self, mycpv, use_cache=None, mydb=None): |
| """ |
| Load a particular CPV into the config, this lets us see the |
| Default USE flags for a particular ebuild as well as the USE |
| flags from package.use. |
| |
| @param mycpv: A cpv to load |
| @type mycpv: string |
| @param mydb: a dbapi instance that supports aux_get with the IUSE key. |
| @type mydb: dbapi or derivative. |
| @rtype: None |
| """ |
| |
| if use_cache is not None: |
| warnings.warn("The use_cache parameter for config.setcpv() is deprecated and without effect.", |
| DeprecationWarning, stacklevel=2) |
| |
| self.modifying() |
| |
| pkg = None |
| built_use = None |
| explicit_iuse = None |
| if not isinstance(mycpv, basestring): |
| pkg = mycpv |
| mycpv = pkg.cpv |
| mydb = pkg._metadata |
| explicit_iuse = pkg.iuse.all |
| args_hash = (mycpv, id(pkg)) |
| if pkg.built: |
| built_use = pkg.use.enabled |
| else: |
| args_hash = (mycpv, id(mydb)) |
| |
| if args_hash == self._setcpv_args_hash: |
| return |
| self._setcpv_args_hash = args_hash |
| |
| has_changed = False |
| self.mycpv = mycpv |
| cat, pf = catsplit(mycpv) |
| cp = cpv_getkey(mycpv) |
| cpv_slot = self.mycpv |
| pkginternaluse = "" |
| iuse = "" |
| pkg_configdict = self.configdict["pkg"] |
| previous_iuse = pkg_configdict.get("IUSE") |
| previous_iuse_effective = pkg_configdict.get("IUSE_EFFECTIVE") |
| previous_features = pkg_configdict.get("FEATURES") |
| |
| aux_keys = self._setcpv_aux_keys |
| |
| # Discard any existing metadata and package.env settings from |
| # the previous package instance. |
| pkg_configdict.clear() |
| |
| 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: |
| if k in mydb: |
| # Make these lazy, since __getitem__ triggers |
| # evaluation of USE conditionals which can't |
| # occur until PORTAGE_USE is calculated below. |
| pkg_configdict.addLazySingleton(k, |
| mydb.__getitem__, k) |
| else: |
| # When calling dbapi.aux_get(), grab USE for built/installed |
| # packages since we want to save it PORTAGE_BUILT_USE for |
| # evaluating conditional USE deps in atoms passed via IPC to |
| # helpers like has_version and best_version. |
| aux_keys = set(aux_keys) |
| if hasattr(mydb, '_aux_cache_keys'): |
| aux_keys = aux_keys.intersection(mydb._aux_cache_keys) |
| aux_keys.add('USE') |
| aux_keys = list(aux_keys) |
| for k, v in zip(aux_keys, mydb.aux_get(self.mycpv, aux_keys)): |
| pkg_configdict[k] = v |
| built_use = frozenset(pkg_configdict.pop('USE').split()) |
| if not built_use: |
| # 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: |
| pkg_configdict["PORTAGE_REPO_NAME"] = repository |
| iuse = pkg_configdict["IUSE"] |
| if pkg is None: |
| self.mycpv = _pkg_str(self.mycpv, metadata=pkg_configdict, |
| settings=self) |
| cpv_slot = self.mycpv |
| else: |
| cpv_slot = pkg |
| pkginternaluse = [] |
| for x in iuse.split(): |
| if x.startswith("+"): |
| pkginternaluse.append(x[1:]) |
| 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 |
| |
| repo_env = [] |
| if repository and repository != Package.UNKNOWN_REPO: |
| repos = [] |
| try: |
| repos.extend(repo.name for repo in |
| self.repositories[repository].masters) |
| except KeyError: |
| pass |
| repos.append(repository) |
| for repo in repos: |
| d = self._repo_make_defaults.get(repo) |
| if d is None: |
| d = {} |
| else: |
| # make a copy, since we might modify it with |
| # package.use settings |
| d = d.copy() |
| cpdict = self._use_manager._repo_puse_dict.get(repo, {}).get(cp) |
| if cpdict: |
| repo_puse = ordered_by_atom_specificity(cpdict, cpv_slot) |
| if repo_puse: |
| for x in repo_puse: |
| d["USE"] = d.get("USE", "") + " " + " ".join(x) |
| if d: |
| repo_env.append(d) |
| |
| if repo_env or self.configdict["repo"]: |
| self.configdict["repo"].clear() |
| self.configdict["repo"].update(stack_dicts(repo_env, |
| incrementals=self.incrementals)) |
| has_changed = True |
| |
| defaults = [] |
| for i, pkgprofileuse_dict in enumerate(self._use_manager._pkgprofileuse): |
| if self.make_defaults_use[i]: |
| defaults.append(self.make_defaults_use[i]) |
| cpdict = pkgprofileuse_dict.get(cp) |
| if cpdict: |
| pkg_defaults = ordered_by_atom_specificity(cpdict, cpv_slot) |
| if pkg_defaults: |
| defaults.extend(pkg_defaults) |
| defaults = " ".join(defaults) |
| if defaults != self.configdict["defaults"].get("USE",""): |
| self.configdict["defaults"]["USE"] = defaults |
| has_changed = True |
| |
| useforce = self._use_manager.getUseForce(cpv_slot) |
| if useforce != self.useforce: |
| self.useforce = useforce |
| has_changed = True |
| |
| usemask = self._use_manager.getUseMask(cpv_slot) |
| if usemask != self.usemask: |
| self.usemask = usemask |
| has_changed = True |
| |
| oldpuse = self.puse |
| self.puse = self._use_manager.getPUSE(cpv_slot) |
| if oldpuse != self.puse: |
| has_changed = True |
| self.configdict["pkg"]["PKGUSE"] = self.puse[:] # For saving to PUSE file |
| self.configdict["pkg"]["USE"] = self.puse[:] # this gets appended to USE |
| |
| if previous_features: |
| # The package from the previous setcpv call had package.env |
| # settings which modified FEATURES. Therefore, trigger a |
| # regenerate() call in order to ensure that self.features |
| # is accurate. |
| has_changed = True |
| |
| self._penv = [] |
| cpdict = self._penvdict.get(cp) |
| if cpdict: |
| penv_matches = ordered_by_atom_specificity(cpdict, cpv_slot) |
| if penv_matches: |
| for x in penv_matches: |
| self._penv.extend(x) |
| |
| bashrc_files = [] |
| |
| for profile in self._locations_manager.profiles_complex: |
| profile_bashrc = os.path.join(profile.location, |
| 'profile.bashrc') |
| if os.path.exists(profile_bashrc): |
| bashrc_files.append(profile_bashrc) |
| if profile in self._pbashrcdict: |
| cpdict = self._pbashrcdict[profile].get(cp) |
| if cpdict: |
| bashrc_matches = \ |
| ordered_by_atom_specificity(cpdict, cpv_slot) |
| for x in bashrc_matches: |
| bashrc_files.extend(x) |
| |
| self._pbashrc = tuple(bashrc_files) |
| |
| protected_pkg_keys = set(pkg_configdict) |
| protected_pkg_keys.discard('USE') |
| |
| # If there are _any_ package.env settings for this package |
| # then it automatically triggers config.reset(), in order |
| # to account for possible incremental interaction between |
| # package.use, package.env, and overrides from the calling |
| # environment (configdict['env']). |
| if self._penv: |
| has_changed = True |
| # USE is special because package.use settings override |
| # it. Discard any package.use settings here and they'll |
| # be added back later. |
| pkg_configdict.pop('USE', None) |
| self._grab_pkg_env(self._penv, pkg_configdict, |
| protected_keys=protected_pkg_keys) |
| |
| # Now add package.use settings, which override USE from |
| # package.env |
| if self.puse: |
| if 'USE' in pkg_configdict: |
| pkg_configdict['USE'] = \ |
| pkg_configdict['USE'] + " " + self.puse |
| else: |
| pkg_configdict['USE'] = self.puse |
| |
| if has_changed: |
| self.reset(keeping_pkg=1) |
| |
| env_configdict = self.configdict['env'] |
| |
| # Ensure that "pkg" values are always preferred over "env" values. |
| # This must occur _after_ the above reset() call, since reset() |
| # copies values from self.backupenv. |
| for k in protected_pkg_keys: |
| env_configdict.pop(k, None) |
| |
| lazy_vars = self._lazy_vars(built_use, self) |
| env_configdict.addLazySingleton('ACCEPT_LICENSE', |
| lazy_vars.__getitem__, 'ACCEPT_LICENSE') |
| env_configdict.addLazySingleton('PORTAGE_RESTRICT', |
| lazy_vars.__getitem__, 'PORTAGE_RESTRICT') |
| |
| if built_use is not None: |
| pkg_configdict['PORTAGE_BUILT_USE'] = ' '.join(built_use) |
| |
| # If reset() has not been called, it's safe to return |
| # early if IUSE has not changed. |
| if not has_changed and previous_iuse == iuse and \ |
| (previous_iuse_effective is not None == eapi_attrs.iuse_effective): |
| return |
| |
| # Filter out USE flags that aren't part of IUSE. This has to |
| # be done for every setcpv() call since practically every |
| # package has different IUSE. |
| use = set(self["USE"].split()) |
| unfiltered_use = frozenset(use) |
| if explicit_iuse is None: |
| explicit_iuse = frozenset(x.lstrip("+-") for x in iuse.split()) |
| |
| 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( |
| "PORTAGE_IUSE", _lazy_iuse_regex, portage_iuse) |
| |
| if pkg is None: |
| raw_restrict = pkg_configdict.get("RESTRICT") |
| else: |
| raw_restrict = pkg._raw_metadata["RESTRICT"] |
| |
| restrict_test = False |
| if raw_restrict: |
| try: |
| if built_use is not None: |
| restrict = use_reduce(raw_restrict, |
| uselist=built_use, flat=True) |
| else: |
| # Use matchnone=True to ignore USE conditional parts |
| # of RESTRICT, since we want to know whether to mask |
| # the "test" flag _before_ we know the USE values |
| # that would be needed to evaluate the USE |
| # conditionals (see bug #273272). |
| restrict = use_reduce(raw_restrict, |
| matchnone=True, flat=True) |
| except PortageException: |
| pass |
| else: |
| restrict_test = "test" in restrict |
| |
| ebuild_force_test = not restrict_test and \ |
| self.get("EBUILD_FORCE_TEST") == "1" |
| |
| if ebuild_force_test and \ |
| not hasattr(self, "_ebuild_force_test_msg_shown"): |
| self._ebuild_force_test_msg_shown = True |
| writemsg(_("Forcing test.\n"), noiselevel=-1) |
| |
| if "test" in explicit_iuse or iuse_implicit_match("test"): |
| if "test" not in self.features: |
| use.discard("test") |
| elif restrict_test or \ |
| ("test" in self.usemask and not ebuild_force_test): |
| # "test" is in IUSE and USE=test is masked, so execution |
| # of src_test() probably is not reliable. Therefore, |
| # temporarily disable FEATURES=test just for this package. |
| self["FEATURES"] = " ".join(x for x in self.features \ |
| if x != "test") |
| use.discard("test") |
| else: |
| use.add("test") |
| if ebuild_force_test and "test" in self.usemask: |
| self.usemask = \ |
| frozenset(x for x in self.usemask if x != "test") |
| |
| if eapi_attrs.feature_flag_targetroot and \ |
| ("targetroot" in explicit_iuse or iuse_implicit_match("targetroot")): |
| if self["ROOT"] != "/": |
| use.add("targetroot") |
| else: |
| use.discard("targetroot") |
| |
| # Allow _* flags from USE_EXPAND wildcards to pass through here. |
| use.difference_update([x for x in use \ |
| if (x not in explicit_iuse and \ |
| not iuse_implicit_match(x)) and x[-2:] != '_*']) |
| |
| # Use the calculated USE flags to regenerate the USE_EXPAND flags so |
| # that they are consistent. For optimal performance, use slice |
| # comparison instead of startswith(). |
| use_expand_split = set(x.lower() for \ |
| x in self.get('USE_EXPAND', '').split()) |
| lazy_use_expand = self._lazy_use_expand( |
| self, unfiltered_use, use, self.usemask, |
| portage_iuse, use_expand_split, self._use_expand_dict) |
| |
| use_expand_iuses = {} |
| for x in portage_iuse: |
| x_split = x.split('_') |
| if len(x_split) == 1: |
| continue |
| for i in range(len(x_split) - 1): |
| k = '_'.join(x_split[:i+1]) |
| if k in use_expand_split: |
| v = use_expand_iuses.get(k) |
| if v is None: |
| v = set() |
| use_expand_iuses[k] = v |
| v.add(x) |
| break |
| |
| # If it's not in IUSE, variable content is allowed |
| # to pass through if it is defined somewhere. This |
| # allows packages that support LINGUAS but don't |
| # declare it in IUSE to use the variable outside of the |
| # USE_EXPAND context. |
| for k, use_expand_iuse in use_expand_iuses.items(): |
| if k + '_*' in use: |
| use.update( x for x in use_expand_iuse if x not in usemask ) |
| k = k.upper() |
| 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. |
| |
| self.configdict["env"]["PORTAGE_USE"] = \ |
| " ".join(sorted(x for x in use if x[-2:] != '_*')) |
| |
| # Clear the eapi cache here rather than in the constructor, since |
| # setcpv triggers lazy instantiation of things like _use_manager. |
| _eapi_cache.clear() |
| |
| def _grab_pkg_env(self, penv, container, protected_keys=None): |
| if protected_keys is None: |
| protected_keys = () |
| abs_user_config = os.path.join( |
| self['PORTAGE_CONFIGROOT'], USER_CONFIG_PATH) |
| non_user_variables = self._non_user_variables |
| # Make a copy since we don't want per-package settings |
| # to pollute the global expand_map. |
| expand_map = self._expand_map.copy() |
| incrementals = self.incrementals |
| for envname in penv: |
| penvfile = os.path.join(abs_user_config, "env", envname) |
| penvconfig = getconfig(penvfile, tolerant=self._tolerant, |
| allow_sourcing=True, expand=expand_map) |
| if penvconfig is None: |
| writemsg("!!! %s references non-existent file: %s\n" % \ |
| (os.path.join(abs_user_config, 'package.env'), penvfile), |
| noiselevel=-1) |
| else: |
| for k, v in penvconfig.items(): |
| if k in protected_keys or \ |
| k in non_user_variables: |
| writemsg("!!! Illegal variable " + \ |
| "'%s' assigned in '%s'\n" % \ |
| (k, penvfile), noiselevel=-1) |
| elif k in incrementals: |
| if k in container: |
| container[k] = container[k] + " " + v |
| else: |
| container[k] = v |
| 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): |
| """ |
| 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 |
| * Masked flags, such as those from {,package}use.mask |
| * Forced flags, such as those from {,package}use.force |
| * build and bootstrap flags used by bootstrap.sh |
| """ |
| iuse_implicit = set() |
| # Flags derived from ARCH. |
| arch = self.configdict["defaults"].get("ARCH") |
| if arch: |
| iuse_implicit.add(arch) |
| iuse_implicit.update(self.get("PORTAGE_ARCHLIST", "").split()) |
| |
| # Flags derived from USE_EXPAND_HIDDEN variables |
| # such as ELIBC, KERNEL, and USERLAND. |
| use_expand_hidden = self.get("USE_EXPAND_HIDDEN", "").split() |
| for x in use_expand_hidden: |
| iuse_implicit.add(x.lower() + "_.*") |
| |
| # Flags that have been masked or forced. |
| iuse_implicit.update(self.usemask) |
| iuse_implicit.update(self.useforce) |
| |
| # build and bootstrap flags used by bootstrap.sh |
| iuse_implicit.add("build") |
| iuse_implicit.add("bootstrap") |
| |
| # Controlled by FEATURES=test. Make this implicit, so handling |
| # of FEATURES=test is consistent regardless of explicit IUSE. |
| # Users may use use.mask/package.use.mask to control |
| # FEATURES=test for all ebuilds, regardless of explicit IUSE. |
| iuse_implicit.add("test") |
| |
| return iuse_implicit |
| |
| def _getUseMask(self, pkg, stable=None): |
| return self._use_manager.getUseMask(pkg, stable=stable) |
| |
| def _getUseForce(self, pkg, stable=None): |
| return self._use_manager.getUseForce(pkg, stable=stable) |
| |
| def _getMaskAtom(self, cpv, metadata): |
| """ |
| Take a package and return a matching package.mask atom, or None if no |
| such atom exists or it has been cancelled by package.unmask. PROVIDE |
| is not checked, so atoms will not be found for old-style virtuals. |
| |
| @param cpv: The package name |
| @type cpv: String |
| @param metadata: A dictionary of raw package metadata |
| @type metadata: dict |
| @rtype: String |
| @return: A matching atom string or None if one is not found. |
| """ |
| return self._mask_manager.getMaskAtom(cpv, metadata["SLOT"], metadata.get('repository')) |
| |
| def _getRawMaskAtom(self, cpv, metadata): |
| """ |
| Take a package and return a matching package.mask atom, or None if no |
| such atom exists or it has been cancelled by package.unmask. PROVIDE |
| is not checked, so atoms will not be found for old-style virtuals. |
| |
| @param cpv: The package name |
| @type cpv: String |
| @param metadata: A dictionary of raw package metadata |
| @type metadata: dict |
| @rtype: String |
| @return: A matching atom string or None if one is not found. |
| """ |
| return self._mask_manager.getRawMaskAtom(cpv, metadata["SLOT"], metadata.get('repository')) |
| |
| |
| def _getProfileMaskAtom(self, cpv, metadata): |
| """ |
| Take a package and return a matching profile atom, or None if no |
| such atom exists. Note that a profile atom may or may not have a "*" |
| prefix. PROVIDE is not checked, so atoms will not be found for |
| old-style virtuals. |
| |
| @param cpv: The package name |
| @type cpv: String |
| @param metadata: A dictionary of raw package metadata |
| @type metadata: dict |
| @rtype: String |
| @return: A matching profile atom string or None if one is not found. |
| """ |
| |
| warnings.warn("The config._getProfileMaskAtom() method is deprecated.", |
| DeprecationWarning, stacklevel=2) |
| |
| cp = cpv_getkey(cpv) |
| profile_atoms = self.prevmaskdict.get(cp) |
| if profile_atoms: |
| pkg = "".join((cpv, _slot_separator, metadata["SLOT"])) |
| repo = metadata.get("repository") |
| if repo and repo != Package.UNKNOWN_REPO: |
| pkg = "".join((pkg, _repo_separator, repo)) |
| pkg_list = [pkg] |
| for x in profile_atoms: |
| if match_from_list(x, pkg_list): |
| continue |
| return x |
| return None |
| |
| def _isStable(self, pkg): |
| return self._keywords_manager.isStable(pkg, |
| self.get("ACCEPT_KEYWORDS", ""), |
| self.configdict["backupenv"].get("ACCEPT_KEYWORDS", "")) |
| |
| def _getKeywords(self, cpv, metadata): |
| return self._keywords_manager.getKeywords(cpv, metadata["SLOT"], \ |
| metadata.get("KEYWORDS", ""), metadata.get("repository")) |
| |
| def _getMissingKeywords(self, cpv, metadata): |
| """ |
| Take a package and return a list of any KEYWORDS that the user may |
| need to accept for the given package. If the KEYWORDS are empty |
| and the the ** keyword has not been accepted, the returned list will |
| contain ** alone (in order to distinguish from the case of "none |
| missing"). |
| |
| @param cpv: The package name (for package.keywords support) |
| @type cpv: String |
| @param metadata: A dictionary of raw package metadata |
| @type metadata: dict |
| @rtype: List |
| @return: A list of KEYWORDS that have not been accepted. |
| """ |
| |
| # Hack: Need to check the env directly here as otherwise stacking |
| # doesn't work properly as negative values are lost in the config |
| # object (bug #139600) |
| backuped_accept_keywords = self.configdict["backupenv"].get("ACCEPT_KEYWORDS", "") |
| global_accept_keywords = self["ACCEPT_KEYWORDS"] |
| |
| return self._keywords_manager.getMissingKeywords(cpv, metadata["SLOT"], \ |
| metadata.get("KEYWORDS", ""), metadata.get('repository'), \ |
| global_accept_keywords, backuped_accept_keywords) |
| |
| def _getRawMissingKeywords(self, cpv, metadata): |
| """ |
| Take a package and return a list of any KEYWORDS that the user may |
| need to accept for the given package. If the KEYWORDS are empty, |
| the returned list will contain ** alone (in order to distinguish |
| from the case of "none missing"). This DOES NOT apply any user config |
| package.accept_keywords acceptance. |
| |
| @param cpv: The package name (for package.keywords support) |
| @type cpv: String |
| @param metadata: A dictionary of raw package metadata |
| @type metadata: dict |
| @rtype: List |
| @return: lists of KEYWORDS that have not been accepted |
| and the keywords it looked for. |
| """ |
| return self._keywords_manager.getRawMissingKeywords(cpv, metadata["SLOT"], \ |
| metadata.get("KEYWORDS", ""), metadata.get('repository'), \ |
| self.get("ACCEPT_KEYWORDS", "")) |
| |
| def _getPKeywords(self, cpv, metadata): |
| global_accept_keywords = self.get("ACCEPT_KEYWORDS", "") |
| |
| return self._keywords_manager.getPKeywords(cpv, metadata["SLOT"], \ |
| metadata.get('repository'), global_accept_keywords) |
| |
| def _getMissingLicenses(self, cpv, metadata): |
| """ |
| Take a LICENSE string and return a list of any licenses that the user |
| may need to accept for the given package. The returned list will not |
| contain any licenses that have already been accepted. This method |
| can throw an InvalidDependString exception. |
| |
| @param cpv: The package name (for package.license support) |
| @type cpv: String |
| @param metadata: A dictionary of raw package metadata |
| @type metadata: dict |
| @rtype: List |
| @return: A list of licenses that have not been accepted. |
| """ |
| return self._license_manager.getMissingLicenses( \ |
| cpv, metadata["USE"], metadata["LICENSE"], metadata["SLOT"], metadata.get('repository')) |
| |
| def _getMissingProperties(self, cpv, metadata): |
| """ |
| Take a PROPERTIES string and return a list of any properties the user |
| may need to accept for the given package. The returned list will not |
| contain any properties that have already been accepted. This method |
| can throw an InvalidDependString exception. |
| |
| @param cpv: The package name (for package.properties support) |
| @type cpv: String |
| @param metadata: A dictionary of raw package metadata |
| @type metadata: dict |
| @rtype: List |
| @return: A list of properties that have not been accepted. |
| """ |
| accept_properties = self._accept_properties |
| try: |
| cpv.slot |
| except AttributeError: |
| cpv = _pkg_str(cpv, metadata=metadata, settings=self) |
| cp = cpv_getkey(cpv) |
| cpdict = self._ppropertiesdict.get(cp) |
| if cpdict: |
| pproperties_list = ordered_by_atom_specificity(cpdict, cpv) |
| if pproperties_list: |
| accept_properties = list(self._accept_properties) |
| for x in pproperties_list: |
| accept_properties.extend(x) |
| |
| properties_str = metadata.get("PROPERTIES", "") |
| properties = set(use_reduce(properties_str, matchall=1, flat=True)) |
| |
| acceptable_properties = set() |
| for x in accept_properties: |
| if x == '*': |
| acceptable_properties.update(properties) |
| elif x == '-*': |
| acceptable_properties.clear() |
| elif x[:1] == '-': |
| acceptable_properties.discard(x[1:]) |
| else: |
| acceptable_properties.add(x) |
| |
| if "?" in properties_str: |
| use = metadata["USE"].split() |
| else: |
| use = [] |
| |
| return [x for x in use_reduce(properties_str, uselist=use, flat=True) |
| if x not in acceptable_properties] |
| |
| def _getMissingRestrict(self, cpv, metadata): |
| """ |
| Take a RESTRICT string and return a list of any tokens the user |
| may need to accept for the given package. The returned list will not |
| contain any tokens that have already been accepted. This method |
| can throw an InvalidDependString exception. |
| |
| @param cpv: The package name (for package.accept_restrict support) |
| @type cpv: String |
| @param metadata: A dictionary of raw package metadata |
| @type metadata: dict |
| @rtype: List |
| @return: A list of tokens that have not been accepted. |
| """ |
| accept_restrict = self._accept_restrict |
| try: |
| cpv.slot |
| except AttributeError: |
| cpv = _pkg_str(cpv, metadata=metadata, settings=self) |
| cp = cpv_getkey(cpv) |
| cpdict = self._paccept_restrict.get(cp) |
| if cpdict: |
| paccept_restrict_list = ordered_by_atom_specificity(cpdict, cpv) |
| if paccept_restrict_list: |
| accept_restrict = list(self._accept_restrict) |
| for x in paccept_restrict_list: |
| accept_restrict.extend(x) |
| |
| restrict_str = metadata.get("RESTRICT", "") |
| all_restricts = set(use_reduce(restrict_str, matchall=1, flat=True)) |
| |
| acceptable_restricts = set() |
| for x in accept_restrict: |
| if x == '*': |
| acceptable_restricts.update(all_restricts) |
| elif x == '-*': |
| acceptable_restricts.clear() |
| elif x[:1] == '-': |
| acceptable_restricts.discard(x[1:]) |
| else: |
| acceptable_restricts.add(x) |
| |
| if "?" in restrict_str: |
| use = metadata["USE"].split() |
| else: |
| use = [] |
| |
| return [x for x in use_reduce(restrict_str, uselist=use, flat=True) |
| if x not in acceptable_restricts] |
| |
| def _accept_chost(self, cpv, metadata): |
| """ |
| @return True if pkg CHOST is accepted, False otherwise. |
| """ |
| if self._accept_chost_re is None: |
| accept_chost = self.get("ACCEPT_CHOSTS", "").split() |
| if not accept_chost: |
| chost = self.get("CHOST") |
| if chost: |
| accept_chost.append(chost) |
| if not accept_chost: |
| self._accept_chost_re = re.compile(".*") |
| elif len(accept_chost) == 1: |
| try: |
| self._accept_chost_re = re.compile(r'^%s$' % accept_chost[0]) |
| except re.error as e: |
| writemsg(_("!!! Invalid ACCEPT_CHOSTS value: '%s': %s\n") % \ |
| (accept_chost[0], e), noiselevel=-1) |
| self._accept_chost_re = re.compile("^$") |
| else: |
| try: |
| self._accept_chost_re = re.compile( |
| r'^(%s)$' % "|".join(accept_chost)) |
| except re.error as e: |
| writemsg(_("!!! Invalid ACCEPT_CHOSTS value: '%s': %s\n") % \ |
| (" ".join(accept_chost), e), noiselevel=-1) |
| self._accept_chost_re = re.compile("^$") |
| |
| pkg_chost = metadata.get('CHOST', '') |
| return not pkg_chost or \ |
| self._accept_chost_re.match(pkg_chost) is not None |
| |
| def setinst(self, mycpv, mydbapi): |
| """This updates the preferences for old-style virtuals, |
| affecting the behavior of dep_expand() and dep_check() |
| calls. It can change dbapi.match() behavior since that |
| calls dep_expand(). However, dbapi instances have |
| internal match caches that are not invalidated when |
| preferences are updated here. This can potentially |
| lead to some inconsistency (relevant to bug #1343).""" |
| self.modifying() |
| |
| # Grab the virtuals this package provides and add them into the tree virtuals. |
| if not hasattr(mydbapi, "aux_get"): |
| provides = mydbapi["PROVIDE"] |
| else: |
| provides = mydbapi.aux_get(mycpv, ["PROVIDE"])[0] |
| if not provides: |
| return |
| if isinstance(mydbapi, portdbapi): |
| self.setcpv(mycpv, mydb=mydbapi) |
| myuse = self["PORTAGE_USE"] |
| elif not hasattr(mydbapi, "aux_get"): |
| myuse = mydbapi["USE"] |
| else: |
| myuse = mydbapi.aux_get(mycpv, ["USE"])[0] |
| virts = use_reduce(provides, uselist=myuse.split(), flat=True) |
| |
| # Ensure that we don't trigger the _treeVirtuals |
| # assertion in VirtualsManager._compile_virtuals(). |
| self.getvirtuals() |
| self._virtuals_manager.add_depgraph_virtuals(mycpv, virts) |
| |
| def reload(self): |
| """Reload things like /etc/profile.env that can change during runtime.""" |
| env_d_filename = os.path.join(self["EROOT"], "etc", "profile.env") |
| self.configdict["env.d"].clear() |
| env_d = getconfig(env_d_filename, |
| tolerant=self._tolerant, expand=False) |
| if env_d: |
| # env_d will be None if profile.env doesn't exist. |
| for k in self._env_d_blacklist: |
| env_d.pop(k, None) |
| self.configdict["env.d"].update(env_d) |
| |
| def regenerate(self, useonly=0, use_cache=None): |
| """ |
| Regenerate settings |
| This involves regenerating valid USE flags, re-expanding USE_EXPAND flags |
| re-stacking USE flags (-flag and -*), as well as any other INCREMENTAL |
| variables. This also updates the env.d configdict; useful in case an ebuild |
| changes the environment. |
| |
| If FEATURES has already stacked, it is not stacked twice. |
| |
| @param useonly: Only regenerate USE flags (not any other incrementals) |
| @type useonly: Boolean |
| @rtype: None |
| """ |
| |
| if use_cache is not None: |
| warnings.warn("The use_cache parameter for config.regenerate() is deprecated and without effect.", |
| DeprecationWarning, stacklevel=2) |
| |
| self.modifying() |
| |
| if useonly: |
| myincrementals=["USE"] |
| else: |
| myincrementals = self.incrementals |
| myincrementals = set(myincrementals) |
| |
| # Process USE last because it depends on USE_EXPAND which is also |
| # an incremental! |
| myincrementals.discard("USE") |
| |
| mydbs = self.configlist[:-1] |
| mydbs.append(self.backupenv) |
| |
| # ACCEPT_LICENSE is a lazily evaluated incremental, so that * can be |
| # used to match all licenses without every having to explicitly expand |
| # it to all licenses. |
| if self.local_config: |
| mysplit = [] |
| for curdb in mydbs: |
| mysplit.extend(curdb.get('ACCEPT_LICENSE', '').split()) |
| mysplit = prune_incremental(mysplit) |
| accept_license_str = ' '.join(mysplit) |
| self.configlist[-1]['ACCEPT_LICENSE'] = accept_license_str |
| self._license_manager.set_accept_license_str(accept_license_str) |
| else: |
| # repoman will accept any license |
| self._license_manager.set_accept_license_str("*") |
| |
| # ACCEPT_PROPERTIES works like ACCEPT_LICENSE, without groups |
| if self.local_config: |
| mysplit = [] |
| for curdb in mydbs: |
| mysplit.extend(curdb.get('ACCEPT_PROPERTIES', '').split()) |
| mysplit = prune_incremental(mysplit) |
| self.configlist[-1]['ACCEPT_PROPERTIES'] = ' '.join(mysplit) |
| if tuple(mysplit) != self._accept_properties: |
| self._accept_properties = tuple(mysplit) |
| else: |
| # repoman will accept any property |
| self._accept_properties = ('*',) |
| |
| if self.local_config: |
| mysplit = [] |
| for curdb in mydbs: |
| mysplit.extend(curdb.get('ACCEPT_RESTRICT', '').split()) |
| mysplit = prune_incremental(mysplit) |
| self.configlist[-1]['ACCEPT_RESTRICT'] = ' '.join(mysplit) |
| if tuple(mysplit) != self._accept_restrict: |
| self._accept_restrict = tuple(mysplit) |
| else: |
| # repoman will accept any property |
| self._accept_restrict = ('*',) |
| |
| increment_lists = {} |
| for k in myincrementals: |
| incremental_list = [] |
| increment_lists[k] = incremental_list |
| for curdb in mydbs: |
| v = curdb.get(k) |
| if v is not None: |
| incremental_list.append(v.split()) |
| |
| if 'FEATURES' in increment_lists: |
| increment_lists['FEATURES'].append(self._features_overrides) |
| |
| myflags = set() |
| for mykey, incremental_list in increment_lists.items(): |
| |
| myflags.clear() |
| for mysplit in incremental_list: |
| |
| for x in mysplit: |
| if x=="-*": |
| # "-*" is a special "minus" var that means "unset all settings". |
| # so USE="-* gnome" will have *just* gnome enabled. |
| myflags.clear() |
| continue |
| |
| if x[0]=="+": |
| # Not legal. People assume too much. Complain. |
| writemsg(colorize("BAD", |
| _("%s values should not start with a '+': %s") % (mykey,x)) \ |
| + "\n", noiselevel=-1) |
| x=x[1:] |
| if not x: |
| continue |
| |
| if (x[0]=="-"): |
| myflags.discard(x[1:]) |
| continue |
| |
| # We got here, so add it now. |
| myflags.add(x) |
| |
| #store setting in last element of configlist, the original environment: |
| if myflags or mykey in self: |
| self.configlist[-1][mykey] = " ".join(sorted(myflags)) |
| |
| # Do the USE calculation last because it depends on USE_EXPAND. |
| use_expand = self.get("USE_EXPAND", "").split() |
| use_expand_dict = self._use_expand_dict |
| use_expand_dict.clear() |
| for k in use_expand: |
| v = self.get(k) |
| 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 |
| # equivalent USE flags so that useful incremental behavior |
| # is enabled (for sub-profiles). |
| configdict_defaults = self.configdict['defaults'] |
| if self._make_defaults is not None: |
| for i, cfg in enumerate(self._make_defaults): |
| if not cfg: |
| self.make_defaults_use.append("") |
| 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: |
| continue |
| prefix = k.lower() + '_' |
| for x in v.split(): |
| if x[:1] == '-': |
| expand_use.append('-' + prefix + x[1:]) |
| else: |
| expand_use.append(prefix + x) |
| |
| if expand_use: |
| expand_use.append(use) |
| use = ' '.join(expand_use) |
| self.make_defaults_use.append(use) |
| self.make_defaults_use = tuple(self.make_defaults_use) |
| # Preserve both positive and negative flags here, since |
| # negative flags may later interact with other flags pulled |
| # in via USE_ORDER. |
| configdict_defaults['USE'] = ' '.join( |
| filter(None, self.make_defaults_use)) |
| # Set to None so this code only runs once. |
| self._make_defaults = None |
| |
| if not self.uvlist: |
| for x in self["USE_ORDER"].split(":"): |
| if x in self.configdict: |
| self.uvlist.append(self.configdict[x]) |
| self.uvlist.reverse() |
| |
| # For optimal performance, use slice |
| # comparison instead of startswith(). |
| iuse = self.configdict["pkg"].get("IUSE") |
| if iuse is not None: |
| 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: |
| continue |
| for x in mysplit: |
| if x == "-*": |
| myflags.clear() |
| continue |
| |
| if x[0] == "+": |
| writemsg(colorize("BAD", _("USE flags should not start " |
| "with a '+': %s\n") % x), noiselevel=-1) |
| x = x[1:] |
| if not x: |
| continue |
| |
| if x[0] == "-": |
| if x[-2:] == '_*': |
| prefix = x[1:-1] |
| prefix_len = len(prefix) |
| myflags.difference_update( |
| [y for y in myflags if \ |
| y[:prefix_len] == prefix]) |
| myflags.discard(x[1:]) |
| continue |
| |
| if iuse is not None and x[-2:] == '_*': |
| # Expand wildcards here, so that cases like |
| # USE="linguas_* -linguas_en_US" work correctly. |
| prefix = x[:-1] |
| prefix_len = len(prefix) |
| has_iuse = False |
| for y in iuse: |
| if y[:prefix_len] == prefix: |
| has_iuse = True |
| myflags.add(y) |
| if not has_iuse: |
| # There are no matching IUSE, so allow the |
| # wildcard to pass through. This allows |
| # linguas_* to trigger unset LINGUAS in |
| # cases when no linguas_ flags are in IUSE. |
| myflags.add(x) |
| else: |
| myflags.add(x) |
| |
| if curdb is configdict_defaults: |
| # USE_EXPAND flags from make.defaults are handled |
| # earlier, in order to provide useful incremental |
| # behavior (for sub-profiles). |
| continue |
| |
| for var in cur_use_expand: |
| var_lower = var.lower() |
| is_not_incremental = var not in myincrementals |
| if is_not_incremental: |
| prefix = var_lower + "_" |
| prefix_len = len(prefix) |
| for x in list(myflags): |
| if x[:prefix_len] == prefix: |
| myflags.remove(x) |
| for x in curdb[var].split(): |
| if x[0] == "+": |
| if is_not_incremental: |
| writemsg(colorize("BAD", _("Invalid '+' " |
| "operator in non-incremental variable " |
| "'%s': '%s'\n") % (var, x)), noiselevel=-1) |
| continue |
| else: |
| writemsg(colorize("BAD", _("Invalid '+' " |
| "operator in incremental variable " |
| "'%s': '%s'\n") % (var, x)), noiselevel=-1) |
| x = x[1:] |
| if x[0] == "-": |
| if is_not_incremental: |
| writemsg(colorize("BAD", _("Invalid '-' " |
| "operator in non-incremental variable " |
| "'%s': '%s'\n") % (var, x)), noiselevel=-1) |
| continue |
| myflags.discard(var_lower + "_" + x[1:]) |
| continue |
| myflags.add(var_lower + "_" + x) |
| |
| if hasattr(self, "features"): |
| self.features._features.clear() |
| else: |
| self.features = features_set(self) |
| self.features._features.update(self.get('FEATURES', '').split()) |
| self.features._sync_env_var() |
| self.features._validate() |
| |
| myflags.update(self.useforce) |
| arch = self.configdict["defaults"].get("ARCH") |
| if arch: |
| myflags.add(arch) |
| |
| myflags.difference_update(self.usemask) |
| self.configlist[-1]["USE"]= " ".join(sorted(myflags)) |
| |
| if self.mycpv is None: |
| # Generate global USE_EXPAND variables settings that are |
| # consistent with USE, for display by emerge --info. For |
| # package instances, these are instead generated via |
| # setcpv(). |
| for k in use_expand: |
| prefix = k.lower() + '_' |
| prefix_len = len(prefix) |
| expand_flags = set( x[prefix_len:] for x in myflags \ |
| if x[:prefix_len] == prefix ) |
| var_split = use_expand_dict.get(k, '').split() |
| var_split = [ x for x in var_split if x in expand_flags ] |
| var_split.extend(sorted(expand_flags.difference(var_split))) |
| if var_split: |
| self.configlist[-1][k] = ' '.join(var_split) |
| 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 " + \ |
| "is deprecated, use config.get_virts_p()", |
| DeprecationWarning, stacklevel=2) |
| return self.get_virts_p() |
| |
| @property |
| def virtuals(self): |
| warnings.warn("portage config.virtuals attribute " + \ |
| "is deprecated, use config.getvirtuals()", |
| DeprecationWarning, stacklevel=2) |
| return self.getvirtuals() |
| |
| def get_virts_p(self): |
| # Ensure that we don't trigger the _treeVirtuals |
| # assertion in VirtualsManager._compile_virtuals(). |
| self.getvirtuals() |
| return self._virtuals_manager.get_virts_p() |
| |
| def getvirtuals(self): |
| if self._virtuals_manager._treeVirtuals is None: |
| #Hack around the fact that VirtualsManager needs a vartree |
| #and vartree needs a config instance. |
| #This code should be part of VirtualsManager.getvirtuals(). |
| if self.local_config: |
| temp_vartree = vartree(settings=self) |
| self._virtuals_manager._populate_treeVirtuals(temp_vartree) |
| else: |
| self._virtuals_manager._treeVirtuals = {} |
| |
| return self._virtuals_manager.getvirtuals() |
| |
| def _populate_treeVirtuals_if_needed(self, vartree): |
| """Reduce the provides into a list by CP.""" |
| if self._virtuals_manager._treeVirtuals is None: |
| if self.local_config: |
| self._virtuals_manager._populate_treeVirtuals(vartree) |
| else: |
| self._virtuals_manager._treeVirtuals = {} |
| |
| def __delitem__(self,mykey): |
| self.pop(mykey) |
| |
| def __getitem__(self, key): |
| try: |
| return self._getitem(key) |
| except KeyError: |
| return '' # for backward compat, don't raise KeyError |
| |
| def _getitem(self, mykey): |
| |
| if mykey in self._constant_keys: |
| # These two point to temporary values when |
| # portage plans to update itself. |
| if mykey == "PORTAGE_BIN_PATH": |
| return portage._bin_path |
| elif mykey == "PORTAGE_PYM_PATH": |
| return portage._pym_path |
| |
| elif mykey == "PORTAGE_PYTHONPATH": |
| value = [x for x in \ |
| self.backupenv.get("PYTHONPATH", "").split(":") if x] |
| need_pym_path = True |
| if value: |
| try: |
| need_pym_path = not os.path.samefile(value[0], |
| portage._pym_path) |
| except OSError: |
| pass |
| if need_pym_path: |
| value.insert(0, portage._pym_path) |
| return ":".join(value) |
| |
| elif mykey == "PORTAGE_GID": |
| return "%s" % portage_gid |
| |
| for d in self.lookuplist: |
| try: |
| return d[mykey] |
| except KeyError: |
| pass |
| |
| raise KeyError(mykey) |
| |
| def get(self, k, x=None): |
| try: |
| return self._getitem(k) |
| except KeyError: |
| return x |
| |
| def pop(self, key, *args): |
| self.modifying() |
| if len(args) > 1: |
| raise TypeError( |
| "pop expected at most 2 arguments, got " + \ |
| repr(1 + len(args))) |
| v = self |
| for d in reversed(self.lookuplist): |
| v = d.pop(key, v) |
| if v is self: |
| if args: |
| return args[0] |
| raise KeyError(key) |
| return v |
| |
| def __contains__(self, mykey): |
| """Called to implement membership test operators (in and not in).""" |
| try: |
| self._getitem(mykey) |
| except KeyError: |
| return False |
| else: |
| return True |
| |
| def setdefault(self, k, x=None): |
| v = self.get(k) |
| if v is not None: |
| return v |
| else: |
| self[k] = x |
| return x |
| |
| def keys(self): |
| return list(self) |
| |
| def __iter__(self): |
| keys = set() |
| keys.update(self._constant_keys) |
| for d in self.lookuplist: |
| keys.update(d) |
| return iter(keys) |
| |
| def iterkeys(self): |
| return iter(self) |
| |
| def iteritems(self): |
| for k in self: |
| yield (k, self._getitem(k)) |
| |
| def items(self): |
| return list(self.iteritems()) |
| |
| def __setitem__(self,mykey,myvalue): |
| "set a value; will be thrown away at reset() time" |
| if not isinstance(myvalue, basestring): |
| raise ValueError("Invalid type being used as a value: '%s': '%s'" % (str(mykey),str(myvalue))) |
| |
| # Avoid potential UnicodeDecodeError exceptions later. |
| mykey = _unicode_decode(mykey) |
| myvalue = _unicode_decode(myvalue) |
| |
| self.modifying() |
| self.modifiedkeys.append(mykey) |
| self.configdict["env"][mykey]=myvalue |
| |
| def environ(self): |
| "return our locally-maintained environment" |
| mydict={} |
| environ_filter = self._environ_filter |
| |
| eapi = self.get('EAPI') |
| eapi_attrs = _get_eapi_attrs(eapi) |
| phase = self.get('EBUILD_PHASE') |
| filter_calling_env = False |
| if self.mycpv is not None and \ |
| phase not in ('clean', 'cleanrm', 'depend', 'fetch'): |
| temp_dir = self.get('T') |
| if temp_dir is not None and \ |
| os.path.exists(os.path.join(temp_dir, 'environment')): |
| filter_calling_env = True |
| |
| environ_whitelist = self._environ_whitelist |
| for x in self: |
| if x in environ_filter: |
| continue |
| myvalue = self[x] |
| if not isinstance(myvalue, basestring): |
| writemsg(_("!!! Non-string value in config: %s=%s\n") % \ |
| (x, myvalue), noiselevel=-1) |
| continue |
| if filter_calling_env and \ |
| x not in environ_whitelist and \ |
| not self._environ_whitelist_re.match(x): |
| # Do not allow anything to leak into the ebuild |
| # environment unless it is explicitly whitelisted. |
| # This ensures that variables unset by the ebuild |
| # remain unset (bug #189417). |
| continue |
| mydict[x] = myvalue |
| if "HOME" not in mydict and "BUILD_PREFIX" in mydict: |
| writemsg("*** HOME not set. Setting to "+mydict["BUILD_PREFIX"]+"\n") |
| mydict["HOME"]=mydict["BUILD_PREFIX"][:] |
| |
| if filter_calling_env: |
| if phase: |
| whitelist = [] |
| if "rpm" == phase: |
| whitelist.append("RPMDIR") |
| for k in whitelist: |
| v = self.get(k) |
| if v is not None: |
| mydict[k] = v |
| |
| # At some point we may want to stop exporting FEATURES to the ebuild |
| # environment, in order to prevent ebuilds from abusing it. In |
| # preparation for that, export it as PORTAGE_FEATURES so that bashrc |
| # users will be able to migrate any FEATURES conditional code to |
| # use this alternative variable. |
| mydict["PORTAGE_FEATURES"] = self["FEATURES"] |
| |
| # Filtered by IUSE and implicit IUSE. |
| mydict["USE"] = self.get("PORTAGE_USE", "") |
| |
| # Don't export AA to the ebuild environment in EAPIs that forbid it |
| if not eapi_exports_AA(eapi): |
| mydict.pop("AA", None) |
| |
| if not eapi_exports_merge_type(eapi): |
| mydict.pop("MERGE_TYPE", None) |
| |
| # Prefix variables are supported beginning with EAPI 3, or when |
| # force-prefix is in FEATURES, since older EAPIs would otherwise be |
| # useless with prefix configurations. This brings compatibility with |
| # the prefix branch of portage, which also supports EPREFIX for all |
| # EAPIs (for obvious reasons). |
| if phase == 'depend' or \ |
| ('force-prefix' not in self.features and |
| eapi is not None and not eapi_supports_prefix(eapi)): |
| mydict.pop("ED", None) |
| mydict.pop("EPREFIX", None) |
| mydict.pop("EROOT", None) |
| |
| if phase == 'depend': |
| mydict.pop('FILESDIR', None) |
| |
| if phase not in ("pretend", "setup", "preinst", "postinst") or \ |
| not eapi_exports_replace_vars(eapi): |
| mydict.pop("REPLACING_VERSIONS", None) |
| |
| if phase not in ("prerm", "postrm") or \ |
| not eapi_exports_replace_vars(eapi): |
| mydict.pop("REPLACED_BY_VERSION", None) |
| |
| if phase is not None and eapi_attrs.exports_EBUILD_PHASE_FUNC: |
| phase_func = _phase_func_map.get(phase) |
| if phase_func is not None: |
| mydict["EBUILD_PHASE_FUNC"] = phase_func |
| |
| return mydict |
| |
| def thirdpartymirrors(self): |
| if getattr(self, "_thirdpartymirrors", None) is None: |
| thirdparty_lists = [] |
| for repo_name in reversed(self.repositories.prepos_order): |
| thirdparty_lists.append(grabdict(os.path.join( |
| self.repositories[repo_name].location, |
| "profiles", "thirdpartymirrors"))) |
| self._thirdpartymirrors = stack_dictlist(thirdparty_lists, incremental=True) |
| return self._thirdpartymirrors |
| |
| def archlist(self): |
| _archlist = [] |
| for myarch in self["PORTAGE_ARCHLIST"].split(): |
| _archlist.append(myarch) |
| _archlist.append("~" + myarch) |
| return _archlist |
| |
| def selinux_enabled(self): |
| if getattr(self, "_selinux_enabled", None) is None: |
| self._selinux_enabled = 0 |
| if "selinux" in self["USE"].split(): |
| if selinux: |
| if selinux.is_selinux_enabled() == 1: |
| self._selinux_enabled = 1 |
| else: |
| self._selinux_enabled = 0 |
| else: |
| writemsg(_("!!! SELinux module not found. Please verify that it was installed.\n"), |
| noiselevel=-1) |
| self._selinux_enabled = 0 |
| |
| return self._selinux_enabled |
| |
| if sys.hexversion >= 0x3000000: |
| keys = __iter__ |
| items = iteritems |