summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/portage/__init__.py2568
-rw-r--r--pym/portage/package/__init__.py3
-rw-r--r--pym/portage/package/ebuild/__init__.py3
-rw-r--r--pym/portage/package/ebuild/config.py2607
4 files changed, 2615 insertions, 2566 deletions
diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py
index add0c008a..7e3143496 100644
--- a/pym/portage/__init__.py
+++ b/pym/portage/__init__.py
@@ -102,6 +102,8 @@ try:
'portage.mail',
'portage.output',
'portage.output:bold,colorize',
+ 'portage.package.ebuild.config:autouse,best_from_dict,' + \
+ 'check_config_instance,config',
'portage.process',
'portage.process:atexit_register,run_exitfuncs',
'portage.update:dep_transform,fixdbentries,grab_updates,' + \
@@ -512,18 +514,6 @@ def load_mod(name):
mod = getattr(mod, comp)
return mod
-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 getcwd():
"this fixes situations where the current directory doesn't exist"
try:
@@ -1008,2560 +998,6 @@ def ExtractKernelVersion(base_dir):
return (version,None)
-def autouse(myvartree, use_cache=1, mysettings=None):
- """
- autuse returns a list of USE variables auto-enabled to packages being installed
-
- @param myvartree: Instance of the vartree class (from /var/db/pkg...)
- @type myvartree: vartree
- @param use_cache: read values from cache
- @type use_cache: Boolean
- @param mysettings: Instance of config
- @type mysettings: config
- @rtype: string
- @returns: A string containing a list of USE variables that are enabled via use.defaults
- """
- if mysettings is None:
- global settings
- mysettings = settings
- if mysettings.profile_path is None:
- return ""
- myusevars=""
- usedefaults = mysettings.use_defs
- for myuse in usedefaults:
- dep_met = True
- for mydep in usedefaults[myuse]:
- if not myvartree.dep_match(mydep,use_cache=True):
- dep_met = False
- break
- if dep_met:
- myusevars += " "+myuse
- return myusevars
-
-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 _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 _local_repo_config(object):
- __slots__ = ('aliases', 'eclass_overrides', 'masters', 'name',)
- def __init__(self, name, repo_opts):
- self.name = name
-
- aliases = repo_opts.get('aliases')
- if aliases is not None:
- aliases = tuple(aliases.split())
- self.aliases = aliases
-
- eclass_overrides = repo_opts.get('eclass-overrides')
- if eclass_overrides is not None:
- eclass_overrides = tuple(eclass_overrides.split())
- self.eclass_overrides = eclass_overrides
-
- masters = repo_opts.get('masters')
- if masters is not None:
- masters = tuple(masters.split())
- self.masters = masters
-
-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.
- """
-
- _setcpv_aux_keys = ('DEFINED_PHASES', 'DEPEND', 'EAPI',
- 'INHERITED', 'IUSE', 'KEYWORDS', 'LICENSE', 'PDEPEND',
- 'PROPERTIES', 'PROVIDE', 'RDEPEND', 'SLOT',
- 'repository', 'RESTRICT', 'LICENSE',)
-
- _env_blacklist = [
- "A", "AA", "CATEGORY", "DEPEND", "DESCRIPTION", "EAPI",
- "EBUILD_PHASE", "ED", "EMERGE_FROM", "EPREFIX", "EROOT",
- "HOMEPAGE", "INHERITED", "IUSE",
- "KEYWORDS", "LICENSE", "PDEPEND", "PF", "PKGUSE",
- "PORTAGE_CONFIGROOT", "PORTAGE_IUSE",
- "PORTAGE_NONFATAL", "PORTAGE_REPO_NAME",
- "PORTAGE_USE", "PROPERTIES", "PROVIDE", "RDEPEND", "RESTRICT",
- "ROOT", "SLOT", "SRC_URI"
- ]
-
- _environ_whitelist = []
-
- # Whitelisted variables are always allowed to enter the ebuild
- # environment. Generally, this only includes special portage
- # variables. Ebuilds can unset variables that are not whitelisted
- # and rely on them remaining unset for future phases, without them
- # leaking back in from various locations (bug #189417). It's very
- # important to set our special BASH_ENV variable in the ebuild
- # environment in order to prevent sandbox from sourcing /etc/profile
- # in it's bashrc (causing major leakage).
- _environ_whitelist += [
- "ACCEPT_LICENSE", "BASH_ENV", "BUILD_PREFIX", "D",
- "DISTDIR", "DOC_SYMLINKS_DIR", "EAPI", "EBUILD",
- "EBUILD_EXIT_STATUS_FILE", "EBUILD_FORCE_TEST",
- "EBUILD_PHASE", "ECLASSDIR", "ECLASS_DEPTH", "ED",
- "EMERGE_FROM", "EPREFIX", "EROOT",
- "FEATURES", "FILESDIR", "HOME", "NOCOLOR", "PATH",
- "PKGDIR",
- "PKGUSE", "PKG_LOGDIR", "PKG_TMPDIR",
- "PORTAGE_ACTUAL_DISTDIR", "PORTAGE_ARCHLIST",
- "PORTAGE_BASHRC",
- "PORTAGE_BINPKG_FILE", "PORTAGE_BINPKG_TAR_OPTS",
- "PORTAGE_BINPKG_TMPFILE",
- "PORTAGE_BIN_PATH",
- "PORTAGE_BUILDDIR", "PORTAGE_COLORMAP",
- "PORTAGE_CONFIGROOT", "PORTAGE_DEBUG", "PORTAGE_DEPCACHEDIR",
- "PORTAGE_GID", "PORTAGE_INST_GID", "PORTAGE_INST_UID",
- "PORTAGE_IUSE",
- "PORTAGE_LOG_FILE", "PORTAGE_MASTER_PID",
- "PORTAGE_PYM_PATH", "PORTAGE_QUIET",
- "PORTAGE_REPO_NAME", "PORTAGE_RESTRICT",
- "PORTAGE_TMPDIR", "PORTAGE_UPDATE_ENV",
- "PORTAGE_VERBOSE", "PORTAGE_WORKDIR_MODE",
- "PORTDIR", "PORTDIR_OVERLAY", "PREROOTPATH", "PROFILE_PATHS",
- "ROOT", "ROOTPATH", "T", "TMP", "TMPDIR",
- "USE_EXPAND", "USE_ORDER", "WORKDIR",
- "XARGS",
- ]
-
- # user config variables
- _environ_whitelist += [
- "DOC_SYMLINKS_DIR", "INSTALL_MASK", "PKG_INSTALL_MASK"
- ]
-
- _environ_whitelist += [
- "A", "AA", "CATEGORY", "P", "PF", "PN", "PR", "PV", "PVR"
- ]
-
- # misc variables inherited from the calling environment
- _environ_whitelist += [
- "COLORTERM", "DISPLAY", "EDITOR", "LESS",
- "LESSOPEN", "LOGNAME", "LS_COLORS", "PAGER",
- "TERM", "TERMCAP", "USER",
- ]
-
- # tempdir settings
- _environ_whitelist += [
- "TMPDIR", "TEMP", "TMP",
- ]
-
- # localization settings
- _environ_whitelist += [
- "LANG", "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES",
- "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LC_PAPER",
- "LC_ALL",
- ]
-
- # other variables inherited from the calling environment
- _environ_whitelist += [
- "CVS_RSH", "ECHANGELOG_USER",
- "GPG_AGENT_INFO",
- "SSH_AGENT_PID", "SSH_AUTH_SOCK",
- "STY", "WINDOW", "XAUTHORITY",
- ]
-
- _environ_whitelist = frozenset(_environ_whitelist)
-
- _environ_whitelist_re = re.compile(r'^(CCACHE_|DISTCC_).*')
-
- # Filter selected variables in the config.environ() method so that
- # they don't needlessly propagate down into the ebuild environment.
- _environ_filter = []
-
- # Exclude anything that could be extremely long here (like SRC_URI)
- # since that could cause execve() calls to fail with E2BIG errors. For
- # example, see bug #262647.
- _environ_filter += [
- 'DEPEND', 'RDEPEND', 'PDEPEND', 'SRC_URI',
- ]
-
- # misc variables inherited from the calling environment
- _environ_filter += [
- "INFOPATH", "MANPATH", "USER",
- ]
-
- # variables that break bash
- _environ_filter += [
- "HISTFILE", "POSIXLY_CORRECT",
- ]
-
- # portage config variables and variables set directly by portage
- _environ_filter += [
- "ACCEPT_KEYWORDS", "ACCEPT_PROPERTIES", "AUTOCLEAN",
- "CLEAN_DELAY", "COLLISION_IGNORE", "CONFIG_PROTECT",
- "CONFIG_PROTECT_MASK", "EGENCACHE_DEFAULT_OPTS", "EMERGE_DEFAULT_OPTS",
- "EMERGE_LOG_DIR",
- "EMERGE_WARNING_DELAY", "FETCHCOMMAND", "FETCHCOMMAND_FTP",
- "FETCHCOMMAND_HTTP", "FETCHCOMMAND_SFTP",
- "GENTOO_MIRRORS", "NOCONFMEM", "O",
- "PORTAGE_BACKGROUND",
- "PORTAGE_BINHOST_CHUNKSIZE", "PORTAGE_CALLER",
- "PORTAGE_ELOG_CLASSES",
- "PORTAGE_ELOG_MAILFROM", "PORTAGE_ELOG_MAILSUBJECT",
- "PORTAGE_ELOG_MAILURI", "PORTAGE_ELOG_SYSTEM",
- "PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS", "PORTAGE_FETCH_RESUME_MIN_SIZE",
- "PORTAGE_GPG_DIR",
- "PORTAGE_GPG_KEY", "PORTAGE_IONICE_COMMAND",
- "PORTAGE_PACKAGE_EMPTY_ABORT",
- "PORTAGE_REPO_DUPLICATE_WARN",
- "PORTAGE_RO_DISTDIRS",
- "PORTAGE_RSYNC_EXTRA_OPTS", "PORTAGE_RSYNC_OPTS",
- "PORTAGE_RSYNC_RETRIES", "PORTAGE_USE", "PORT_LOGDIR",
- "QUICKPKG_DEFAULT_OPTS",
- "RESUMECOMMAND", "RESUMECOMMAND_HTTP", "RESUMECOMMAND_HTTP",
- "RESUMECOMMAND_SFTP", "SYNC", "USE_EXPAND_HIDDEN", "USE_ORDER",
- ]
-
- _environ_filter = frozenset(_environ_filter)
-
- _undef_lic_groups = set()
- _default_globals = (
- ('ACCEPT_LICENSE', '* -@EULA'),
- ('ACCEPT_PROPERTIES', '*'),
- )
-
- # To enhance usability, make some vars case insensitive
- # by forcing them to lower case.
- _case_insensitive_vars = ('AUTOCLEAN', 'NOCOLOR',)
-
- def __init__(self, clone=None, mycpv=None, config_profile_path=None,
- config_incrementals=None, config_root=None, target_root=None,
- local_config=True, env=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: __init__ override of $ROOT env variable.
- @type target_root: 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
- """
-
- # 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 = "_initializing_globals" in globals()
-
- self.already_in_regenerate = 0
-
- self.locked = 0
- self.mycpv = None
- self._setcpv_args_hash = None
- self.puse = []
- self.modifiedkeys = []
- self.uvlist = []
- self._accept_chost_re = None
- self._accept_license = None
- self._accept_license_str = None
- self._license_groups = {}
- self._accept_properties = None
-
- self.virtuals = {}
- self.virts_p = {}
- self.dirVirtuals = None
- self.v_count = 0
-
- # Virtuals obtained from the vartree
- self.treeVirtuals = {}
- # Virtuals by user specification. Includes negatives.
- self.userVirtuals = {}
- # Virtual negatives from user specifications.
- self.negVirtuals = {}
- # Virtuals added by the depgraph via self.setinst().
- self._depgraphVirtuals = {}
-
- self.user_profile_dir = None
- self.local_config = local_config
- self._local_repo_configs = None
- self._local_repo_conf_path = None
-
- if clone:
- # For immutable attributes, use shallow copy for
- # speed and memory conservation.
- 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.useforce_list = clone.useforce_list
- self.usemask_list = clone.usemask_list
-
- self.user_profile_dir = copy.deepcopy(clone.user_profile_dir)
- self.local_config = copy.deepcopy(clone.local_config)
- self._local_repo_configs = \
- copy.deepcopy(clone._local_repo_configs)
- self._local_repo_conf_path = \
- copy.deepcopy(clone._local_repo_conf_path)
- self.modules = copy.deepcopy(clone.modules)
- self.virtuals = copy.deepcopy(clone.virtuals)
- self.dirVirtuals = copy.deepcopy(clone.dirVirtuals)
- self.treeVirtuals = copy.deepcopy(clone.treeVirtuals)
- self.userVirtuals = copy.deepcopy(clone.userVirtuals)
- self.negVirtuals = copy.deepcopy(clone.negVirtuals)
- self._depgraphVirtuals = copy.deepcopy(clone._depgraphVirtuals)
-
- self.use_defs = copy.deepcopy(clone.use_defs)
- self.usemask = copy.deepcopy(clone.usemask)
- self.pusemask_list = copy.deepcopy(clone.pusemask_list)
- self.useforce = copy.deepcopy(clone.useforce)
- self.puseforce_list = copy.deepcopy(clone.puseforce_list)
- self.puse = copy.deepcopy(clone.puse)
- self.make_defaults_use = copy.deepcopy(clone.make_defaults_use)
- self.pkgprofileuse = copy.deepcopy(clone.pkgprofileuse)
- self.mycpv = copy.deepcopy(clone.mycpv)
- self._setcpv_args_hash = copy.deepcopy(clone._setcpv_args_hash)
-
- self.configdict = copy.deepcopy(clone.configdict)
- self.configlist = [
- self.configdict['env.d'],
- self.configdict['pkginternal'],
- self.configdict['globals'],
- self.configdict['defaults'],
- self.configdict['conf'],
- self.configdict['pkg'],
- self.configdict['auto'],
- 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.pusedict = copy.deepcopy(clone.pusedict)
- self.pkeywordsdict = copy.deepcopy(clone.pkeywordsdict)
- self._pkeywords_list = copy.deepcopy(clone._pkeywords_list)
- self.pmaskdict = copy.deepcopy(clone.pmaskdict)
- self.punmaskdict = copy.deepcopy(clone.punmaskdict)
- self.prevmaskdict = copy.deepcopy(clone.prevmaskdict)
- self.pprovideddict = copy.deepcopy(clone.pprovideddict)
- self.features = copy.deepcopy(clone.features)
-
- self._accept_license = copy.deepcopy(clone._accept_license)
- self._plicensedict = copy.deepcopy(clone._plicensedict)
- self._license_groups = copy.deepcopy(clone._license_groups)
- self._accept_properties = copy.deepcopy(clone._accept_properties)
- self._ppropertiesdict = copy.deepcopy(clone._ppropertiesdict)
- else:
-
- def check_var_directory(varname, var):
- if not os.path.isdir(var):
- writemsg(_("!!! Error: %s='%s' is not a directory. "
- "Please correct this.\n") % (varname, var),
- noiselevel=-1)
- raise portage.exception.DirectoryNotFound(var)
-
- if config_root is None:
- config_root = "/"
-
- config_root = normalize_path(os.path.abspath(
- config_root)).rstrip(os.path.sep) + os.path.sep
-
- check_var_directory("PORTAGE_CONFIGROOT", config_root)
-
- self.depcachedir = DEPCACHE_PATH
-
- if not config_profile_path:
- config_profile_path = \
- os.path.join(config_root, PROFILE_PATH)
- if os.path.isdir(config_profile_path):
- self.profile_path = config_profile_path
- else:
- self.profile_path = None
- else:
- self.profile_path = config_profile_path
-
- if config_incrementals is None:
- self.incrementals = portage.const.INCREMENTALS
- else:
- self.incrementals = config_incrementals
- if not isinstance(self.incrementals, tuple):
- self.incrementals = tuple(self.incrementals)
-
- self.module_priority = ("user", "default")
- self.modules = {}
- modules_loader = portage.env.loaders.KeyValuePairFileLoader(
- os.path.join(config_root, MODULES_FILE_PATH), None, None)
- modules_dict, modules_errors = modules_loader.load()
- self.modules["user"] = modules_dict
- if self.modules["user"] is None:
- self.modules["user"] = {}
- self.modules["default"] = {
- "portdbapi.metadbmodule": "portage.cache.metadata.database",
- "portdbapi.auxdbmodule": "portage.cache.flat_hash.database",
- }
-
- self.usemask=[]
- self.configlist=[]
-
- # back up our incremental variables:
- self.configdict={}
- self._use_expand_dict = {}
- # configlist will contain: [ env.d, globals, defaults, conf, pkg, auto, backupenv, env ]
- self.configlist.append({})
- self.configdict["env.d"] = self.configlist[-1]
-
- self.configlist.append({})
- self.configdict["pkginternal"] = self.configlist[-1]
-
- # The symlink might not exist or might not be a symlink.
- if self.profile_path is None:
- self.profiles = []
- else:
- self.profiles = []
- def addProfile(currentPath):
- parentsFile = os.path.join(currentPath, "parent")
- eapi_file = os.path.join(currentPath, "eapi")
- try:
- eapi = codecs.open(_unicode_encode(eapi_file,
- encoding=_encodings['fs'], errors='strict'),
- mode='r', encoding=_encodings['content'], errors='replace'
- ).readline().strip()
- except IOError:
- pass
- else:
- if not eapi_is_supported(eapi):
- raise portage.exception.ParseError(_(
- "Profile contains unsupported "
- "EAPI '%s': '%s'") % \
- (eapi, os.path.realpath(eapi_file),))
- if os.path.exists(parentsFile):
- parents = grabfile(parentsFile)
- if not parents:
- raise portage.exception.ParseError(
- _("Empty parent file: '%s'") % parentsFile)
- for parentPath in parents:
- parentPath = normalize_path(os.path.join(
- currentPath, parentPath))
- if os.path.exists(parentPath):
- addProfile(parentPath)
- else:
- raise portage.exception.ParseError(
- _("Parent '%s' not found: '%s'") % \
- (parentPath, parentsFile))
- self.profiles.append(currentPath)
- try:
- addProfile(os.path.realpath(self.profile_path))
- except portage.exception.ParseError as e:
- writemsg(_("!!! Unable to parse profile: '%s'\n") % \
- self.profile_path, noiselevel=-1)
- writemsg("!!! ParseError: %s\n" % str(e), noiselevel=-1)
- del e
- self.profiles = []
- if local_config and self.profiles:
- custom_prof = os.path.join(
- config_root, CUSTOM_PROFILE_PATH)
- if os.path.exists(custom_prof):
- self.user_profile_dir = custom_prof
- self.profiles.append(custom_prof)
- del custom_prof
-
- self.profiles = tuple(self.profiles)
- self.packages_list = [grabfile_package(os.path.join(x, "packages")) for x in self.profiles]
- self.packages = tuple(stack_lists(self.packages_list, incremental=1))
- del self.packages_list
- #self.packages = grab_stacked("packages", self.profiles, grabfile, incremental_lines=1)
-
- # revmaskdict
- self.prevmaskdict={}
- for x in self.packages:
- # Negative atoms are filtered by the above stack_lists() call.
- if not isinstance(x, dep.Atom):
- x = dep.Atom(x.lstrip('*'))
- self.prevmaskdict.setdefault(x.cp, []).append(x)
-
- self._pkeywords_list = []
- rawpkeywords = [grabdict_package(
- os.path.join(x, "package.keywords"), recursive=1) \
- for x in self.profiles]
- for pkeyworddict in rawpkeywords:
- cpdict = {}
- for k, v in pkeyworddict.items():
- cpdict.setdefault(k.cp, {})[k] = v
- self._pkeywords_list.append(cpdict)
-
- # get profile-masked use flags -- INCREMENTAL Child over parent
- self.usemask_list = tuple(
- tuple(grabfile(os.path.join(x, "use.mask"), recursive=1))
- for x in self.profiles)
- self.usemask = set(stack_lists(
- self.usemask_list, incremental=True))
- use_defs_lists = [grabdict(os.path.join(x, "use.defaults")) for x in self.profiles]
- self.use_defs = stack_dictlist(use_defs_lists, incremental=True)
- del use_defs_lists
-
- self.pusemask_list = []
- rawpusemask = [grabdict_package(os.path.join(x, "package.use.mask"),
- recursive=1) for x in self.profiles]
- for pusemaskdict in rawpusemask:
- cpdict = {}
- for k, v in pusemaskdict.items():
- cpdict.setdefault(k.cp, {})[k] = v
- self.pusemask_list.append(cpdict)
- del rawpusemask
-
- self.pkgprofileuse = []
- rawprofileuse = [grabdict_package(os.path.join(x, "package.use"),
- juststrings=True, recursive=1) for x in self.profiles]
- for rawpusedict in rawprofileuse:
- cpdict = {}
- for k, v in rawpusedict.items():
- cpdict.setdefault(k.cp, {})[k] = v
- self.pkgprofileuse.append(cpdict)
- del rawprofileuse
-
- self.useforce_list = tuple(
- tuple(grabfile(os.path.join(x, "use.force"), recursive=1))
- for x in self.profiles)
- self.useforce = set(stack_lists(
- self.useforce_list, incremental=True))
-
- self.puseforce_list = []
- rawpuseforce = [grabdict_package(
- os.path.join(x, "package.use.force"), recursive=1) \
- for x in self.profiles]
- for rawpusefdict in rawpuseforce:
- cpdict = {}
- for k, v in rawpusefdict.items():
- cpdict.setdefault(k.cp, {})[k] = v
- self.puseforce_list.append(cpdict)
- del rawpuseforce
-
- make_conf = getconfig(
- os.path.join(config_root, MAKE_CONF_FILE),
- tolerant=tolerant, allow_sourcing=True)
- if make_conf is None:
- make_conf = {}
-
- # Allow ROOT setting to come from make.conf if it's not overridden
- # by the constructor argument (from the calling environment).
- if target_root is None and "ROOT" in make_conf:
- target_root = make_conf["ROOT"]
- if not target_root.strip():
- target_root = None
- if target_root is None:
- target_root = "/"
-
- target_root = normalize_path(os.path.abspath(
- target_root)).rstrip(os.path.sep) + os.path.sep
-
- portage.util.ensure_dirs(target_root)
- check_var_directory("ROOT", target_root)
-
- # 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.
- expand_map = {}
-
- env_d = getconfig(os.path.join(target_root, "etc", "profile.env"),
- expand=expand_map)
- # env_d will be None if profile.env doesn't exist.
- if env_d:
- self.configdict["env.d"].update(env_d)
- expand_map.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"] = util.LazyItemsDict(self.backupenv)
-
- # make.globals should not be relative to config_root
- # because it only contains constants.
- for x in (portage.const.GLOBAL_CONFIG_PATH, "/etc"):
- self.mygcfg = getconfig(os.path.join(x, "make.globals"),
- expand=expand_map)
- if self.mygcfg:
- break
-
- if self.mygcfg is None:
- self.mygcfg = {}
-
- for k, v in self._default_globals:
- self.mygcfg.setdefault(k, v)
-
- self.configlist.append(self.mygcfg)
- self.configdict["globals"]=self.configlist[-1]
-
- self.make_defaults_use = []
- self.mygcfg = {}
- if self.profiles:
- mygcfg_dlists = [getconfig(os.path.join(x, "make.defaults"),
- expand=expand_map) for x in self.profiles]
-
- for cfg in mygcfg_dlists:
- if cfg:
- self.make_defaults_use.append(cfg.get("USE", ""))
- else:
- self.make_defaults_use.append("")
- self.mygcfg = stack_dicts(mygcfg_dlists,
- incrementals=portage.const.INCREMENTALS)
- if self.mygcfg is None:
- self.mygcfg = {}
- self.configlist.append(self.mygcfg)
- self.configdict["defaults"]=self.configlist[-1]
-
- self.mygcfg = getconfig(
- os.path.join(config_root, MAKE_CONF_FILE),
- tolerant=tolerant, allow_sourcing=True, expand=expand_map)
- if self.mygcfg is None:
- self.mygcfg = {}
-
- # Don't allow the user to override certain variables in make.conf
- profile_only_variables = self.configdict["defaults"].get(
- "PROFILE_ONLY_VARIABLES", "").split()
- for k in profile_only_variables:
- self.mygcfg.pop(k, None)
-
- self.configlist.append(self.mygcfg)
- self.configdict["conf"]=self.configlist[-1]
-
- self.configlist.append(util.LazyItemsDict())
- self.configdict["pkg"]=self.configlist[-1]
-
- #auto-use:
- self.configlist.append({})
- self.configdict["auto"]=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")
-
- # Prefix forward compatability, set EPREFIX to the empty string
- self["EPREFIX"] = ''
- self.backup_changes("EPREFIX")
- self["EROOT"] = target_root
- self.backup_changes("EROOT")
-
- self.pusedict = {}
- self.pkeywordsdict = {}
- self._plicensedict = {}
- self._ppropertiesdict = {}
- self.punmaskdict = {}
- abs_user_config = os.path.join(config_root, USER_CONFIG_PATH)
-
- # locations for "categories" and "arch.list" files
- locations = [os.path.join(self["PORTDIR"], "profiles")]
- pmask_locations = [os.path.join(self["PORTDIR"], "profiles")]
- pmask_locations.extend(self.profiles)
-
- """ repoman controls PORTDIR_OVERLAY via the environment, so no
- special cases are needed here."""
- overlay_profiles = []
- for ov in self["PORTDIR_OVERLAY"].split():
- ov = normalize_path(ov)
- profiles_dir = os.path.join(ov, "profiles")
- if os.path.isdir(profiles_dir):
- overlay_profiles.append(profiles_dir)
- locations += overlay_profiles
-
- pmask_locations.extend(overlay_profiles)
-
- if local_config:
- locations.append(abs_user_config)
- pmask_locations.append(abs_user_config)
- pusedict = grabdict_package(
- os.path.join(abs_user_config, "package.use"), recursive=1)
- for k, v in pusedict.items():
- self.pusedict.setdefault(k.cp, {})[k] = v
-
- #package.keywords
- pkgdict = grabdict_package(
- os.path.join(abs_user_config, "package.keywords"),
- recursive=1)
- for k, v in pkgdict.items():
- # default to ~arch if no specific keyword is given
- if not v:
- mykeywordlist = []
- if self.configdict["defaults"] and \
- "ACCEPT_KEYWORDS" in self.configdict["defaults"]:
- groups = self.configdict["defaults"]["ACCEPT_KEYWORDS"].split()
- else:
- groups = []
- for keyword in groups:
- if not keyword[0] in "~-":
- mykeywordlist.append("~"+keyword)
- v = mykeywordlist
- self.pkeywordsdict.setdefault(k.cp, {})[k] = v
-
- #package.license
- licdict = grabdict_package(os.path.join(
- abs_user_config, "package.license"), recursive=1)
- for k, v in licdict.items():
- cp = k.cp
- cp_dict = self._plicensedict.get(cp)
- if not cp_dict:
- cp_dict = {}
- self._plicensedict[cp] = cp_dict
- cp_dict[k] = self.expandLicenseTokens(v)
-
- #package.properties
- propdict = grabdict_package(os.path.join(
- abs_user_config, "package.properties"), recursive=1)
- for k, v in propdict.items():
- cp = k.cp
- cp_dict = self._ppropertiesdict.get(cp)
- if not cp_dict:
- cp_dict = {}
- self._ppropertiesdict[cp] = cp_dict
- cp_dict[k] = v
-
- self._local_repo_configs = {}
- self._local_repo_conf_path = \
- os.path.join(abs_user_config, 'repos.conf')
- try:
- from configparser import SafeConfigParser, ParsingError
- except ImportError:
- from ConfigParser import SafeConfigParser, ParsingError
- repo_conf_parser = SafeConfigParser()
- try:
- repo_conf_parser.readfp(
- codecs.open(
- _unicode_encode(self._local_repo_conf_path,
- encoding=_encodings['fs'], errors='strict'),
- mode='r', encoding=_encodings['content'], errors='replace')
- )
- except EnvironmentError as e:
- if e.errno != errno.ENOENT:
- raise
- del e
- except ParsingError as e:
- portage.util.writemsg_level(
- _("!!! Error parsing '%s': %s\n") % \
- (self._local_repo_conf_path, e),
- level=logging.ERROR, noiselevel=-1)
- del e
- else:
- repo_defaults = repo_conf_parser.defaults()
- if repo_defaults:
- self._local_repo_configs['DEFAULT'] = \
- _local_repo_config('DEFAULT', repo_defaults)
- for repo_name in repo_conf_parser.sections():
- repo_opts = repo_defaults.copy()
- for opt_name in repo_conf_parser.options(repo_name):
- repo_opts[opt_name] = \
- repo_conf_parser.get(repo_name, opt_name)
- self._local_repo_configs[repo_name] = \
- _local_repo_config(repo_name, repo_opts)
-
- #getting categories from an external file now
- categories = [grabfile(os.path.join(x, "categories")) for x in locations]
- category_re = dbapi.dbapi._category_re
- self.categories = tuple(sorted(
- x for x in stack_lists(categories, incremental=1)
- if category_re.match(x) is not None))
- del categories
-
- archlist = [grabfile(os.path.join(x, "arch.list")) for x in locations]
- archlist = stack_lists(archlist, incremental=1)
- self.configdict["conf"]["PORTAGE_ARCHLIST"] = " ".join(archlist)
-
- # package.mask and package.unmask
- pkgmasklines = []
- pkgunmasklines = []
- for x in pmask_locations:
- pkgmasklines.append(grabfile_package(
- os.path.join(x, "package.mask"), recursive=1))
- pkgunmasklines.append(grabfile_package(
- os.path.join(x, "package.unmask"), recursive=1))
- pkgmasklines = stack_lists(pkgmasklines, incremental=1)
- pkgunmasklines = stack_lists(pkgunmasklines, incremental=1)
-
- self.pmaskdict = {}
- for x in pkgmasklines:
- self.pmaskdict.setdefault(x.cp, []).append(x)
-
- for x in pkgunmasklines:
- self.punmaskdict.setdefault(x.cp, []).append(x)
-
- pkgprovidedlines = [grabfile(os.path.join(x, "package.provided"), recursive=1) for x in self.profiles]
- 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:
- cpv=catpkgsplit(x)
- if not x:
- continue
- mycatpkg = cpv_getkey(x)
- if mycatpkg in self.pprovideddict:
- self.pprovideddict[mycatpkg].append(x)
- else:
- self.pprovideddict[mycatpkg]=[x]
-
- # parse licensegroups
- license_groups = self._license_groups
- for x in locations:
- for k, v in grabdict(
- os.path.join(x, "license_groups")).items():
- license_groups.setdefault(k, []).extend(v)
-
- # 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:env.d"
-
- self["PORTAGE_GID"] = str(portage_gid)
- self.backup_changes("PORTAGE_GID")
-
- if self.get("PORTAGE_DEPCACHEDIR", None):
- self.depcachedir = self["PORTAGE_DEPCACHEDIR"]
- self["PORTAGE_DEPCACHEDIR"] = self.depcachedir
- self.backup_changes("PORTAGE_DEPCACHEDIR")
-
- overlays = self.get("PORTDIR_OVERLAY","").split()
- if overlays:
- new_ov = []
- for ov in overlays:
- ov = normalize_path(ov)
- if os.path.isdir(ov):
- new_ov.append(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")
-
- if "CBUILD" not in self and "CHOST" in self:
- self["CBUILD"] = self["CHOST"]
- self.backup_changes("CBUILD")
-
- self["PORTAGE_BIN_PATH"] = PORTAGE_BIN_PATH
- self.backup_changes("PORTAGE_BIN_PATH")
- self["PORTAGE_PYM_PATH"] = PORTAGE_PYM_PATH
- self.backup_changes("PORTAGE_PYM_PATH")
-
- for var in ("PORTAGE_INST_UID", "PORTAGE_INST_GID"):
- try:
- self[var] = str(int(self.get(var, "0")))
- except ValueError:
- writemsg(_("!!! %s='%s' is not a valid integer. "
- "Falling back to '0'.\n") % (var, self[var]),
- noiselevel=-1)
- self[var] = "0"
- self.backup_changes(var)
-
- # initialize self.features
- self.regenerate()
-
- if bsd_chflags:
- self.features.add('chflags')
-
- self["FEATURES"] = " ".join(sorted(self.features))
- self.backup_changes("FEATURES")
- global _glep_55_enabled, _validate_cache_for_unsupported_eapis
- if 'parse-eapi-ebuild-head' in self.features:
- _validate_cache_for_unsupported_eapis = False
- if 'parse-eapi-glep-55' in self.features:
- _validate_cache_for_unsupported_eapis = False
- _glep_55_enabled = True
-
- for k in self._case_insensitive_vars:
- if k in self:
- self[k] = self[k].lower()
- self.backup_changes(k)
-
- if mycpv:
- self.setcpv(mycpv)
-
- def _init_dirs(self):
- """
- Create a few directories that are critical to portage operation
- """
- if not os.access(self["ROOT"], 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["ROOT"], 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:
- portage.util.ensure_dirs(mydir, gid=gid, mode=mode, mask=modemask)
- except portage.exception.PortageException as e:
- writemsg(_("!!! Directory initialization failed: '%s'\n") % mydir,
- noiselevel=-1)
- writemsg("!!! %s\n" % str(e),
- noiselevel=-1)
-
- 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."""
- expanded_tokens = []
- for x in tokens:
- expanded_tokens.extend(self._expandLicenseToken(x, None))
- return expanded_tokens
-
- def _expandLicenseToken(self, token, traversed_groups):
- negate = False
- rValue = []
- if token.startswith("-"):
- negate = True
- license_name = token[1:]
- else:
- license_name = token
- if not license_name.startswith("@"):
- rValue.append(token)
- return rValue
- group_name = license_name[1:]
- if traversed_groups is None:
- traversed_groups = set()
- license_group = self._license_groups.get(group_name)
- if group_name in traversed_groups:
- writemsg(_("Circular license group reference"
- " detected in '%s'\n") % group_name, noiselevel=-1)
- rValue.append("@"+group_name)
- elif license_group:
- traversed_groups.add(group_name)
- for l in license_group:
- if l.startswith("-"):
- writemsg(_("Skipping invalid element %s"
- " in license group '%s'\n") % (l, group_name),
- noiselevel=-1)
- else:
- rValue.extend(self._expandLicenseToken(l, traversed_groups))
- else:
- if self._license_groups and \
- group_name not in self._undef_lic_groups:
- self._undef_lic_groups.add(group_name)
- writemsg(_("Undefined license group '%s'\n") % group_name,
- noiselevel=-1)
- rValue.append("@"+group_name)
- if negate:
- rValue = ["-" + token for token in rValue]
- return rValue
-
- 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)
-
- abs_profile_path = os.path.join(self["PORTAGE_CONFIGROOT"],
- PROFILE_PATH)
- if not self.profile_path or (not os.path.islink(abs_profile_path) and \
- not os.path.exists(os.path.join(abs_profile_path, "parent")) and \
- os.path.exists(os.path.join(self["PORTDIR"], "profiles"))):
- writemsg(_("\a\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 process.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 portage.process.fakeroot_capable:
- writemsg(_("!!! FEATURES=fakeroot is enabled, but the "
- "fakeroot binary is not installed.\n"), noiselevel=-1)
-
- def loadVirtuals(self,root):
- """Not currently used by portage."""
- writemsg("DEPRECATED: portage.config.loadVirtuals\n")
- self.getvirtuals(root)
-
- 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.startswith("cache."):
- best_mod = "portage." + best_mod
- try:
- mod = load_mod(best_mod)
- except ImportError:
- pass
- if mod is None:
- 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=1):
- """
- Restore environment from self.backupenv, call self.regenerate()
- @param keeping_pkg: Should we keep the set_cpv() data or delete it.
- @type keeping_pkg: Boolean
- @param use_cache: Should self.regenerate use the cache or not
- @type use_cache: Boolean
- @rype: None
- """
- self.modifying()
- self.configdict["env"].clear()
- self.configdict["env"].update(self.backupenv)
-
- self.modifiedkeys = []
- if not keeping_pkg:
- self.mycpv = None
- self.puse = ""
- self.configdict["pkg"].clear()
- self.configdict["pkginternal"].clear()
- self.configdict["defaults"]["USE"] = \
- " ".join(self.make_defaults_use)
- self.usemask = set(stack_lists(
- self.usemask_list, incremental=True))
- self.useforce = set(stack_lists(
- self.useforce_list, incremental=True))
- self.regenerate(use_cache=use_cache)
-
- 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'] = self._accept_license(use, settings)
- values['PORTAGE_RESTRICT'] = self._restrict(use, settings)
- return values
-
- def _accept_license(self, use, settings):
- """
- Generate a pruned version of ACCEPT_LICENSE, by intersection with
- LICENSE. This is required since otherwise ACCEPT_LICENSE might be
- too big (bigger than ARG_MAX), causing execve() calls to fail with
- E2BIG errors as in bug #262647.
- """
- try:
- licenses = set(flatten(
- dep.use_reduce(dep.paren_reduce(
- settings['LICENSE']),
- uselist=use)))
- except exception.InvalidDependString:
- licenses = set()
- licenses.discard('||')
- if settings._accept_license:
- acceptable_licenses = set()
- for x in settings._accept_license:
- if x == '*':
- acceptable_licenses.update(licenses)
- elif x == '-*':
- acceptable_licenses.clear()
- elif x[:1] == '-':
- acceptable_licenses.discard(x[1:])
- elif x in licenses:
- acceptable_licenses.add(x)
-
- licenses = acceptable_licenses
- return ' '.join(sorted(licenses))
-
- def _restrict(self, use, settings):
- try:
- restrict = set(flatten(
- dep.use_reduce(dep.paren_reduce(
- settings['RESTRICT']),
- uselist=use)))
- except exception.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, use, usemask, iuse_implicit,
- use_expand_split, use_expand_dict):
- 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.
- if has_wildcard:
- # ebuild.sh will see this and unset the variable so
- # that things like LINGUAS work properly
- value = '*'
- else:
- if has_iuse:
- 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=1, 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 use_cache: Enables caching
- @type use_cache: Boolean
- @param mydb: a dbapi instance that supports aux_get with the IUSE key.
- @type mydb: dbapi or derivative.
- @rtype: None
- """
-
- self.modifying()
-
- pkg = None
- built_use = None
- if not isinstance(mycpv, basestring):
- pkg = mycpv
- mycpv = pkg.cpv
- mydb = pkg.metadata
- 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")
-
- aux_keys = self._setcpv_aux_keys
-
- # Discard any existing metadata from the previous package, but
- # preserve things like USE_EXPAND values and PORTAGE_USE which
- # might be reused.
- for k in aux_keys:
- pkg_configdict.pop(k, None)
-
- pkg_configdict["CATEGORY"] = cat
- pkg_configdict["PF"] = pf
- 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:
- for k, v in zip(aux_keys, mydb.aux_get(self.mycpv, aux_keys)):
- pkg_configdict[k] = v
- repository = pkg_configdict.pop("repository", None)
- if repository is not None:
- pkg_configdict["PORTAGE_REPO_NAME"] = repository
- slot = pkg_configdict["SLOT"]
- iuse = pkg_configdict["IUSE"]
- if pkg is None:
- cpv_slot = "%s:%s" % (self.mycpv, slot)
- 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)
- if pkginternaluse != self.configdict["pkginternal"].get("USE", ""):
- self.configdict["pkginternal"]["USE"] = pkginternaluse
- has_changed = True
-
- defaults = []
- pos = 0
- for i, pkgprofileuse_dict in enumerate(self.pkgprofileuse):
- cpdict = pkgprofileuse_dict.get(cp)
- if cpdict:
- keys = list(cpdict)
- while keys:
- bestmatch = best_match_to_list(cpv_slot, keys)
- if bestmatch:
- keys.remove(bestmatch)
- defaults.insert(pos, cpdict[bestmatch])
- else:
- break
- del keys
- if self.make_defaults_use[i]:
- defaults.insert(pos, self.make_defaults_use[i])
- pos = len(defaults)
- defaults = " ".join(defaults)
- if defaults != self.configdict["defaults"].get("USE",""):
- self.configdict["defaults"]["USE"] = defaults
- has_changed = True
-
- useforce = self._getUseForce(cpv_slot)
- if useforce != self.useforce:
- self.useforce = useforce
- has_changed = True
-
- usemask = self._getUseMask(cpv_slot)
- if usemask != self.usemask:
- self.usemask = usemask
- has_changed = True
- oldpuse = self.puse
- self.puse = ""
- cpdict = self.pusedict.get(cp)
- if cpdict:
- keys = list(cpdict)
- while keys:
- self.pusekey = best_match_to_list(cpv_slot, keys)
- if self.pusekey:
- keys.remove(self.pusekey)
- self.puse = (" ".join(cpdict[self.pusekey])) + " " + self.puse
- else:
- break
- del keys
- 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 has_changed:
- self.reset(keeping_pkg=1,use_cache=use_cache)
-
- # 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.
- env_configdict = self.configdict['env']
- for k in pkg_configdict:
- if k != 'USE':
- 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 reset() has not been called, it's safe to return
- # early if IUSE has not changed.
- if not has_changed and previous_iuse == iuse:
- 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())
- iuse_implicit = self._get_implicit_iuse()
- iuse_implicit.update(x.lstrip("+-") for x in iuse.split())
-
- # PORTAGE_IUSE is not always needed so it's lazily evaluated.
- self.configdict["pkg"].addLazySingleton(
- "PORTAGE_IUSE", _lazy_iuse_regex, iuse_implicit)
-
- ebuild_force_test = 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 self.features:
- if "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:
- self.usemask.discard("test")
-
- # Allow _* flags from USE_EXPAND wildcards to pass through here.
- use.difference_update([x for x in use \
- if x not in iuse_implicit 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(use, self.usemask,
- iuse_implicit, use_expand_split, self._use_expand_dict)
-
- use_expand_iuses = {}
- for x in iuse_implicit:
- 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)
-
- # 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["pkg"]["PORTAGE_USE"] = \
- " ".join(sorted(x for x in use if x[-2:] != '_*'))
-
- def _get_implicit_iuse(self):
- """
- Some 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):
- cp = getattr(pkg, "cp", None)
- if cp is None:
- cp = cpv_getkey(dep.remove_slot(pkg))
- usemask = []
- pos = 0
- for i, pusemask_dict in enumerate(self.pusemask_list):
- cpdict = pusemask_dict.get(cp)
- if cpdict:
- keys = list(cpdict)
- while keys:
- best_match = best_match_to_list(pkg, keys)
- if best_match:
- keys.remove(best_match)
- usemask.insert(pos, cpdict[best_match])
- else:
- break
- del keys
- if self.usemask_list[i]:
- usemask.insert(pos, self.usemask_list[i])
- pos = len(usemask)
- return set(stack_lists(usemask, incremental=True))
-
- def _getUseForce(self, pkg):
- cp = getattr(pkg, "cp", None)
- if cp is None:
- cp = cpv_getkey(dep.remove_slot(pkg))
- useforce = []
- pos = 0
- for i, puseforce_dict in enumerate(self.puseforce_list):
- cpdict = puseforce_dict.get(cp)
- if cpdict:
- keys = list(cpdict)
- while keys:
- best_match = best_match_to_list(pkg, keys)
- if best_match:
- keys.remove(best_match)
- useforce.insert(pos, cpdict[best_match])
- else:
- break
- del keys
- if self.useforce_list[i]:
- useforce.insert(pos, self.useforce_list[i])
- pos = len(useforce)
- return set(stack_lists(useforce, incremental=True))
-
- 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: An matching atom string or None if one is not found.
- """
-
- cp = cpv_getkey(cpv)
- mask_atoms = self.pmaskdict.get(cp)
- if mask_atoms:
- pkg_list = ["%s:%s" % (cpv, metadata["SLOT"])]
- unmask_atoms = self.punmaskdict.get(cp)
- for x in mask_atoms:
- if not match_from_list(x, pkg_list):
- continue
- if unmask_atoms:
- for y in unmask_atoms:
- if match_from_list(y, pkg_list):
- return None
- return x
- return None
-
- 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: An matching profile atom string or None if one is not found.
- """
-
- cp = cpv_getkey(cpv)
- profile_atoms = self.prevmaskdict.get(cp)
- if profile_atoms:
- pkg_list = ["%s:%s" % (cpv, metadata["SLOT"])]
- for x in profile_atoms:
- if match_from_list(x, pkg_list):
- continue
- return x
- return None
-
- def _getKeywords(self, cpv, metadata):
- cp = cpv_getkey(cpv)
- pkg = "%s:%s" % (cpv, metadata["SLOT"])
- keywords = [[x for x in metadata["KEYWORDS"].split() if x != "-*"]]
- pos = len(keywords)
- for pkeywords_dict in self._pkeywords_list:
- cpdict = pkeywords_dict.get(cp)
- if cpdict:
- keys = list(cpdict)
- while keys:
- best_match = best_match_to_list(pkg, keys)
- if best_match:
- keys.remove(best_match)
- keywords.insert(pos, cpdict[best_match])
- else:
- break
- pos = len(keywords)
- return stack_lists(keywords, incremental=True)
-
- def _getMissingKeywords(self, cpv, metadata):
- """
- Take a package and return a list of any KEYWORDS that the user may
- 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 distiguish 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)
- egroups = self.configdict["backupenv"].get(
- "ACCEPT_KEYWORDS", "").split()
- mygroups = self._getKeywords(cpv, metadata)
- # Repoman may modify this attribute as necessary.
- pgroups = self["ACCEPT_KEYWORDS"].split()
- match=0
- cp = cpv_getkey(cpv)
- pkgdict = self.pkeywordsdict.get(cp)
- matches = False
- if pkgdict:
- cpv_slot_list = ["%s:%s" % (cpv, metadata["SLOT"])]
- for atom, pkgkeywords in pkgdict.items():
- if match_from_list(atom, cpv_slot_list):
- matches = True
- pgroups.extend(pkgkeywords)
- if matches or egroups:
- pgroups.extend(egroups)
- inc_pgroups = set()
- for x in pgroups:
- if x.startswith("-"):
- if x == "-*":
- inc_pgroups.clear()
- else:
- inc_pgroups.discard(x[1:])
- else:
- inc_pgroups.add(x)
- pgroups = inc_pgroups
- del inc_pgroups
- hasstable = False
- hastesting = False
- for gp in mygroups:
- if gp == "*" or (gp == "-*" and len(mygroups) == 1):
- writemsg(_("--- WARNING: Package '%(cpv)s' uses"
- " '%(keyword)s' keyword.\n") % {"cpv": cpv, "keyword": gp}, noiselevel=-1)
- if gp == "*":
- match = 1
- break
- elif gp in pgroups:
- match=1
- break
- elif gp.startswith("~"):
- hastesting = True
- elif not gp.startswith("-"):
- hasstable = True
- if not match and \
- ((hastesting and "~*" in pgroups) or \
- (hasstable and "*" in pgroups) or "**" in pgroups):
- match=1
- if match:
- missing = []
- else:
- if not mygroups:
- # If KEYWORDS is empty then we still have to return something
- # in order to distiguish from the case of "none missing".
- mygroups.append("**")
- missing = mygroups
- return missing
-
- def _getMissingLicenses(self, cpv, metadata):
- """
- Take a LICENSE string and return a list any licenses that the user may
- 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.
- """
- accept_license = self._accept_license
- cpdict = self._plicensedict.get(cpv_getkey(cpv), None)
- if cpdict:
- accept_license = list(self._accept_license)
- cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
- for atom in match_to_list(cpv_slot, list(cpdict)):
- accept_license.extend(cpdict[atom])
-
- licenses = set(flatten(dep.use_reduce(dep.paren_reduce(
- metadata["LICENSE"]), matchall=1)))
- licenses.discard('||')
-
- acceptable_licenses = set()
- for x in accept_license:
- if x == '*':
- acceptable_licenses.update(licenses)
- elif x == '-*':
- acceptable_licenses.clear()
- elif x[:1] == '-':
- acceptable_licenses.discard(x[1:])
- else:
- acceptable_licenses.add(x)
-
- license_str = metadata["LICENSE"]
- if "?" in license_str:
- use = metadata["USE"].split()
- else:
- use = []
-
- license_struct = portage.dep.use_reduce(
- portage.dep.paren_reduce(license_str), uselist=use)
- license_struct = portage.dep.dep_opconvert(license_struct)
- return self._getMaskedLicenses(license_struct, acceptable_licenses)
-
- def _getMaskedLicenses(self, license_struct, acceptable_licenses):
- if not license_struct:
- return []
- if license_struct[0] == "||":
- ret = []
- for element in license_struct[1:]:
- if isinstance(element, list):
- if element:
- ret.append(self._getMaskedLicenses(
- element, acceptable_licenses))
- if not ret[-1]:
- return []
- else:
- if element in acceptable_licenses:
- return []
- ret.append(element)
- # Return all masked licenses, since we don't know which combination
- # (if any) the user will decide to unmask.
- return flatten(ret)
-
- ret = []
- for element in license_struct:
- if isinstance(element, list):
- if element:
- ret.extend(self._getMaskedLicenses(element,
- acceptable_licenses))
- else:
- if element not in acceptable_licenses:
- ret.append(element)
- return ret
-
- def _getMissingProperties(self, cpv, metadata):
- """
- Take a PROPERTIES string and return a list of any properties the user may
- 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
- cpdict = self._ppropertiesdict.get(cpv_getkey(cpv), None)
- if cpdict:
- accept_properties = list(self._accept_properties)
- cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
- for atom in match_to_list(cpv_slot, list(cpdict)):
- accept_properties.extend(cpdict[atom])
-
- properties = set(flatten(dep.use_reduce(dep.paren_reduce(
- metadata["PROPERTIES"]), matchall=1)))
- properties.discard('||')
-
- 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)
-
- properties_str = metadata["PROPERTIES"]
- if "?" in properties_str:
- use = metadata["USE"].split()
- else:
- use = []
-
- properties_struct = portage.dep.use_reduce(
- portage.dep.paren_reduce(properties_str), uselist=use)
- properties_struct = portage.dep.dep_opconvert(properties_struct)
- return self._getMaskedProperties(properties_struct, acceptable_properties)
-
- def _getMaskedProperties(self, properties_struct, acceptable_properties):
- if not properties_struct:
- return []
- if properties_struct[0] == "||":
- ret = []
- for element in properties_struct[1:]:
- if isinstance(element, list):
- if element:
- ret.append(self._getMaskedProperties(
- element, acceptable_properties))
- if not ret[-1]:
- return []
- else:
- if element in acceptable_properties:
- return[]
- ret.append(element)
- # Return all masked properties, since we don't know which combination
- # (if any) the user will decide to unmask
- return flatten(ret)
-
- ret = []
- for element in properties_struct:
- if isinstance(element, list):
- if element:
- ret.extend(self._getMaskedProperties(element,
- acceptable_properties))
- else:
- if element not in acceptable_properties:
- ret.append(element)
- return ret
-
- 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()
- if len(self.virtuals) == 0:
- self.getvirtuals()
- # 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 = flatten(portage.dep.use_reduce(portage.dep.paren_reduce(provides), uselist=myuse.split()))
-
- modified = False
- cp = dep.Atom(cpv_getkey(mycpv))
- for virt in virts:
- try:
- virt = dep.Atom(virt).cp
- except exception.InvalidAtom:
- continue
- providers = self.virtuals.get(virt)
- if providers and cp in providers:
- continue
- providers = self._depgraphVirtuals.get(virt)
- if providers is None:
- providers = []
- self._depgraphVirtuals[virt] = providers
- if cp not in providers:
- providers.append(cp)
- modified = True
-
- if modified:
- self.virtuals = self.__getvirtuals_compile()
-
- def reload(self):
- """Reload things like /etc/profile.env that can change during runtime."""
- env_d_filename = os.path.join(self["ROOT"], "etc", "profile.env")
- self.configdict["env.d"].clear()
- env_d = getconfig(env_d_filename, expand=False)
- if env_d:
- # env_d will be None if profile.env doesn't exist.
- self.configdict["env.d"].update(env_d)
-
- def _prune_incremental(self, split):
- """
- Prune off any parts of an incremental variable that are
- made irrelevant by the latest occuring * or -*. This
- could be more aggressive but that might be confusing
- and the point is just to reduce noise a bit.
- """
- for i, x in enumerate(reversed(split)):
- if x == '*':
- split = split[-i-1:]
- break
- elif x == '-*':
- if i == 0:
- split = []
- else:
- split = split[-i:]
- break
- return split
-
- def regenerate(self,useonly=0,use_cache=1):
- """
- 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
- @param use_cache: Enable Caching (only for autouse)
- @type use_cache: Boolean
- @rtype: None
- """
-
- self.modifying()
- if self.already_in_regenerate:
- # XXX: THIS REALLY NEEDS TO GET FIXED. autouse() loops.
- writemsg("!!! Looping in regenerate.\n",1)
- return
- else:
- self.already_in_regenerate = 1
-
- if useonly:
- myincrementals=["USE"]
- else:
- myincrementals = self.incrementals
- myincrementals = set(myincrementals)
- # If self.features exists, it has already been stacked and may have
- # been mutated, so don't stack it again or else any mutations will be
- # reverted.
- if "FEATURES" in myincrementals and hasattr(self, "features"):
- myincrementals.remove("FEATURES")
-
- if "USE" in myincrementals:
- # Process USE last because it depends on USE_EXPAND which is also
- # an incremental!
- myincrementals.remove("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 = self._prune_incremental(mysplit)
- accept_license_str = ' '.join(mysplit)
- self.configlist[-1]['ACCEPT_LICENSE'] = accept_license_str
- if accept_license_str != self._accept_license_str:
- self._accept_license_str = accept_license_str
- self._accept_license = tuple(self.expandLicenseTokens(mysplit))
- else:
- # repoman will accept any license
- self._accept_license = ('*',)
-
- # 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 = self._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 = ('*',)
-
- for mykey in myincrementals:
-
- myflags=[]
- for curdb in mydbs:
- if mykey not in curdb:
- continue
- #variables are already expanded
- mysplit = curdb[mykey].split()
-
- 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 = []
- continue
-
- if x[0]=="+":
- # Not legal. People assume too much. Complain.
- writemsg(colorize("BAD",
- _("USE flags should not start with a '+': %s") % x) \
- + "\n", noiselevel=-1)
- x=x[1:]
- if not x:
- continue
-
- if (x[0]=="-"):
- if (x[1:] in myflags):
- # Unset/Remove it.
- del myflags[myflags.index(x[1:])]
- continue
-
- # We got here, so add it now.
- if x not in myflags:
- myflags.append(x)
-
- myflags.sort()
- #store setting in last element of configlist, the original environment:
- if myflags or mykey in self:
- self.configlist[-1][mykey] = " ".join(myflags)
- del myflags
-
- # Do the USE calculation last because it depends on USE_EXPAND.
- if "auto" in self["USE_ORDER"].split(":"):
- self.configdict["auto"]["USE"] = autouse(
- vartree(root=self["ROOT"], categories=self.categories,
- settings=self),
- use_cache=use_cache, mysettings=self)
- else:
- self.configdict["auto"]["USE"] = ""
-
- 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
-
- 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().
- myflags = set()
- for curdb in self.uvlist:
- 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] == "-":
- myflags.discard(x[1:])
- continue
-
- myflags.add(x)
-
- 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.clear()
- else:
- self.features = set()
- self.features.update(self.configlist[-1].get('FEATURES', '').split())
- self['FEATURES'] = ' '.join(sorted(self.features))
-
- 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))
-
- self.already_in_regenerate = 0
-
- def get_virts_p(self, myroot=None):
-
- if myroot is not None:
- warnings.warn("The 'myroot' parameter for " + \
- "portage.config.get_virts_p() is deprecated",
- DeprecationWarning, stacklevel=2)
-
- if self.virts_p:
- return self.virts_p
- virts = self.getvirtuals()
- if virts:
- for x in virts:
- vkeysplit = x.split("/")
- if vkeysplit[1] not in self.virts_p:
- self.virts_p[vkeysplit[1]] = virts[x]
- return self.virts_p
-
- def getvirtuals(self, myroot=None):
- """myroot is now ignored because, due to caching, it has always been
- broken for all but the first call."""
-
- if myroot is not None:
- warnings.warn("The 'myroot' parameter for " + \
- "portage.config.getvirtuals() is deprecated",
- DeprecationWarning, stacklevel=2)
-
- myroot = self["ROOT"]
- if self.virtuals:
- return self.virtuals
-
- virtuals_list = []
- for x in self.profiles:
- virtuals_file = os.path.join(x, "virtuals")
- virtuals_dict = grabdict(virtuals_file)
- atoms_dict = {}
- for k, v in virtuals_dict.items():
- try:
- virt_atom = portage.dep.Atom(k)
- except portage.exception.InvalidAtom:
- virt_atom = None
- else:
- if virt_atom.blocker or \
- str(virt_atom) != str(virt_atom.cp):
- virt_atom = None
- if virt_atom is None:
- writemsg(_("--- Invalid virtuals atom in %s: %s\n") % \
- (virtuals_file, k), noiselevel=-1)
- continue
- providers = []
- for atom in v:
- atom_orig = atom
- if atom[:1] == '-':
- # allow incrementals
- atom = atom[1:]
- try:
- atom = portage.dep.Atom(atom)
- except portage.exception.InvalidAtom:
- atom = None
- else:
- if atom.blocker:
- atom = None
- if atom is None:
- writemsg(_("--- Invalid atom in %s: %s\n") % \
- (virtuals_file, myatom), noiselevel=-1)
- else:
- if atom_orig == str(atom):
- # normal atom, so return as Atom instance
- providers.append(atom)
- else:
- # atom has special prefix, so return as string
- providers.append(atom_orig)
- if providers:
- atoms_dict[virt_atom] = providers
- if atoms_dict:
- virtuals_list.append(atoms_dict)
-
- self.dirVirtuals = stack_dictlist(virtuals_list, incremental=True)
- del virtuals_list
-
- for virt in self.dirVirtuals:
- # Preference for virtuals decreases from left to right.
- self.dirVirtuals[virt].reverse()
-
- # Repoman does not use user or tree virtuals.
- if self.local_config and not self.treeVirtuals:
- temp_vartree = vartree(myroot, None,
- categories=self.categories, settings=self)
- self._populate_treeVirtuals(temp_vartree)
-
- self.virtuals = self.__getvirtuals_compile()
- return self.virtuals
-
- def _populate_treeVirtuals(self, vartree):
- """Reduce the provides into a list by CP."""
- for provide, cpv_list in vartree.get_all_provides().items():
- try:
- provide = dep.Atom(provide)
- except exception.InvalidAtom:
- continue
- self.treeVirtuals[provide.cp] = \
- [dep.Atom(cpv_getkey(cpv)) for cpv in cpv_list]
-
- def __getvirtuals_compile(self):
- """Stack installed and profile virtuals. Preference for virtuals
- decreases from left to right.
- Order of preference:
- 1. installed and in profile
- 2. installed only
- 3. profile only
- """
-
- # Virtuals by profile+tree preferences.
- ptVirtuals = {}
-
- for virt, installed_list in self.treeVirtuals.items():
- profile_list = self.dirVirtuals.get(virt, None)
- if not profile_list:
- continue
- for cp in installed_list:
- if cp in profile_list:
- ptVirtuals.setdefault(virt, [])
- ptVirtuals[virt].append(cp)
-
- virtuals = stack_dictlist([ptVirtuals, self.treeVirtuals,
- self.dirVirtuals, self._depgraphVirtuals])
- return virtuals
-
- def __delitem__(self,mykey):
- self.modifying()
- for x in self.lookuplist:
- if x != None:
- if mykey in x:
- del x[mykey]
-
- def __getitem__(self,mykey):
- for d in self.lookuplist:
- if mykey in d:
- return d[mykey]
- return '' # for backward compat, don't raise KeyError
-
- def get(self, k, x=None):
- for d in self.lookuplist:
- if k in d:
- return d[k]
- return x
-
- def pop(self, key, *args):
- 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 has_key(self,mykey):
- warnings.warn("portage.config.has_key() is deprecated, "
- "use the in operator instead",
- DeprecationWarning, stacklevel=2)
- return mykey in self
-
- def __contains__(self, mykey):
- """Called to implement membership test operators (in and not in)."""
- for d in self.lookuplist:
- if mykey in d:
- return True
- return False
-
- 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()
- 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[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')
- phase = self.get('EBUILD_PHASE')
- filter_calling_env = False
- if phase not in ('clean', 'cleanrm', 'depend'):
- 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
- env_d = self.configdict["env.d"]
- 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.
- 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
-
- # 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 eapi not in ("0", "1", "2", "3", "3_pre2"):
- mydict.pop("AA", None)
-
- # Prefix variables are supported starting with EAPI 3.
- if phase == 'depend' or eapi in (None, "0", "1", "2"):
- mydict.pop("ED", None)
- mydict.pop("EPREFIX", None)
- mydict.pop("EROOT", None)
-
- if phase == 'depend':
- mydict.pop('FILESDIR', None)
-
- return mydict
-
- def thirdpartymirrors(self):
- if getattr(self, "_thirdpartymirrors", None) is None:
- profileroots = [os.path.join(self["PORTDIR"], "profiles")]
- for x in self["PORTDIR_OVERLAY"].split():
- profileroots.insert(0, os.path.join(x, "profiles"))
- thirdparty_lists = [grabdict(os.path.join(x, "thirdpartymirrors")) for x in profileroots]
- self._thirdpartymirrors = stack_dictlist(thirdparty_lists, incremental=True)
- return self._thirdpartymirrors
-
- def archlist(self):
- return flatten([[myarch, "~" + myarch] \
- for myarch in self["PORTAGE_ARCHLIST"].split()])
-
- 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
-
def _can_test_pty_eof():
"""
The _test_pty_eof() function seems to hang on most
diff --git a/pym/portage/package/__init__.py b/pym/portage/package/__init__.py
new file mode 100644
index 000000000..c802d70cc
--- /dev/null
+++ b/pym/portage/package/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
diff --git a/pym/portage/package/ebuild/__init__.py b/pym/portage/package/ebuild/__init__.py
new file mode 100644
index 000000000..c802d70cc
--- /dev/null
+++ b/pym/portage/package/ebuild/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py
new file mode 100644
index 000000000..ab7b7a2a5
--- /dev/null
+++ b/pym/portage/package/ebuild/config.py
@@ -0,0 +1,2607 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+__all__ = [
+ 'autouse', 'best_from_dict', 'check_config_instance', 'config',
+]
+
+import codecs
+import copy
+import errno
+import logging
+import re
+import sys
+import warnings
+
+try:
+ from configparser import SafeConfigParser, ParsingError
+except ImportError:
+ from ConfigParser import SafeConfigParser, ParsingError
+
+import portage
+from portage import bsd_chflags, eapi_is_supported, \
+ load_mod, os, selinux, _encodings, _unicode_encode, _unicode_decode
+from portage.const import CACHE_PATH, CUSTOM_PROFILE_PATH, \
+ DEPCACHE_PATH, GLOBAL_CONFIG_PATH, INCREMENTALS, MAKE_CONF_FILE, \
+ MODULES_FILE_PATH, PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, \
+ PRIVATE_PATH, PROFILE_PATH, USER_CONFIG_PATH, USER_VIRTUALS_FILE
+from portage.data import portage_gid
+from portage.dbapi import dbapi
+from portage.dbapi.porttree import portdbapi
+from portage.dbapi.vartree import vartree
+from portage.dep import Atom, best_match_to_list, dep_opconvert, \
+ flatten, isvalidatom, match_from_list, match_to_list, \
+ paren_reduce, remove_slot, use_reduce
+from portage.env.loaders import KeyValuePairFileLoader
+from portage.exception import DirectoryNotFound, InvalidAtom, \
+ InvalidDependString, ParseError, PortageException
+from portage.localization import _
+from portage.output import colorize
+from portage.process import fakeroot_capable, sandbox_capable
+from portage.util import ensure_dirs, getconfig, grabdict, \
+ grabdict_package, grabfile, grabfile_package, LazyItemsDict, \
+ normalize_path, stack_dictlist, stack_dicts, stack_lists, \
+ writemsg, writemsg_level
+from portage.versions import catpkgsplit, catsplit, cpv_getkey
+
+def autouse(myvartree, use_cache=1, mysettings=None):
+ """
+ autuse returns a list of USE variables auto-enabled to packages being installed
+
+ @param myvartree: Instance of the vartree class (from /var/db/pkg...)
+ @type myvartree: vartree
+ @param use_cache: read values from cache
+ @type use_cache: Boolean
+ @param mysettings: Instance of config
+ @type mysettings: config
+ @rtype: string
+ @returns: A string containing a list of USE variables that are enabled via use.defaults
+ """
+ if mysettings is None:
+ mysettings = portage.settings
+ if mysettings.profile_path is None:
+ return ""
+ myusevars=""
+ usedefaults = mysettings.use_defs
+ for myuse in usedefaults:
+ dep_met = True
+ for mydep in usedefaults[myuse]:
+ if not myvartree.dep_match(mydep,use_cache=True):
+ dep_met = False
+ break
+ if dep_met:
+ myusevars += " "+myuse
+ return myusevars
+
+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 _local_repo_config(object):
+ __slots__ = ('aliases', 'eclass_overrides', 'masters', 'name',)
+ def __init__(self, name, repo_opts):
+ self.name = name
+
+ aliases = repo_opts.get('aliases')
+ if aliases is not None:
+ aliases = tuple(aliases.split())
+ self.aliases = aliases
+
+ eclass_overrides = repo_opts.get('eclass-overrides')
+ if eclass_overrides is not None:
+ eclass_overrides = tuple(eclass_overrides.split())
+ self.eclass_overrides = eclass_overrides
+
+ masters = repo_opts.get('masters')
+ if masters is not None:
+ masters = tuple(masters.split())
+ self.masters = masters
+
+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.
+ """
+
+ _setcpv_aux_keys = ('DEFINED_PHASES', 'DEPEND', 'EAPI',
+ 'INHERITED', 'IUSE', 'KEYWORDS', 'LICENSE', 'PDEPEND',
+ 'PROPERTIES', 'PROVIDE', 'RDEPEND', 'SLOT',
+ 'repository', 'RESTRICT', 'LICENSE',)
+
+ _env_blacklist = [
+ "A", "AA", "CATEGORY", "DEPEND", "DESCRIPTION", "EAPI",
+ "EBUILD_PHASE", "ED", "EMERGE_FROM", "EPREFIX", "EROOT",
+ "HOMEPAGE", "INHERITED", "IUSE",
+ "KEYWORDS", "LICENSE", "PDEPEND", "PF", "PKGUSE",
+ "PORTAGE_CONFIGROOT", "PORTAGE_IUSE",
+ "PORTAGE_NONFATAL", "PORTAGE_REPO_NAME",
+ "PORTAGE_USE", "PROPERTIES", "PROVIDE", "RDEPEND", "RESTRICT",
+ "ROOT", "SLOT", "SRC_URI"
+ ]
+
+ _environ_whitelist = []
+
+ # Whitelisted variables are always allowed to enter the ebuild
+ # environment. Generally, this only includes special portage
+ # variables. Ebuilds can unset variables that are not whitelisted
+ # and rely on them remaining unset for future phases, without them
+ # leaking back in from various locations (bug #189417). It's very
+ # important to set our special BASH_ENV variable in the ebuild
+ # environment in order to prevent sandbox from sourcing /etc/profile
+ # in it's bashrc (causing major leakage).
+ _environ_whitelist += [
+ "ACCEPT_LICENSE", "BASH_ENV", "BUILD_PREFIX", "D",
+ "DISTDIR", "DOC_SYMLINKS_DIR", "EAPI", "EBUILD",
+ "EBUILD_EXIT_STATUS_FILE", "EBUILD_FORCE_TEST",
+ "EBUILD_PHASE", "ECLASSDIR", "ECLASS_DEPTH", "ED",
+ "EMERGE_FROM", "EPREFIX", "EROOT",
+ "FEATURES", "FILESDIR", "HOME", "NOCOLOR", "PATH",
+ "PKGDIR",
+ "PKGUSE", "PKG_LOGDIR", "PKG_TMPDIR",
+ "PORTAGE_ACTUAL_DISTDIR", "PORTAGE_ARCHLIST",
+ "PORTAGE_BASHRC",
+ "PORTAGE_BINPKG_FILE", "PORTAGE_BINPKG_TAR_OPTS",
+ "PORTAGE_BINPKG_TMPFILE",
+ "PORTAGE_BIN_PATH",
+ "PORTAGE_BUILDDIR", "PORTAGE_COLORMAP",
+ "PORTAGE_CONFIGROOT", "PORTAGE_DEBUG", "PORTAGE_DEPCACHEDIR",
+ "PORTAGE_GID", "PORTAGE_INST_GID", "PORTAGE_INST_UID",
+ "PORTAGE_IUSE",
+ "PORTAGE_LOG_FILE", "PORTAGE_MASTER_PID",
+ "PORTAGE_PYM_PATH", "PORTAGE_QUIET",
+ "PORTAGE_REPO_NAME", "PORTAGE_RESTRICT",
+ "PORTAGE_TMPDIR", "PORTAGE_UPDATE_ENV",
+ "PORTAGE_VERBOSE", "PORTAGE_WORKDIR_MODE",
+ "PORTDIR", "PORTDIR_OVERLAY", "PREROOTPATH", "PROFILE_PATHS",
+ "ROOT", "ROOTPATH", "T", "TMP", "TMPDIR",
+ "USE_EXPAND", "USE_ORDER", "WORKDIR",
+ "XARGS",
+ ]
+
+ # user config variables
+ _environ_whitelist += [
+ "DOC_SYMLINKS_DIR", "INSTALL_MASK", "PKG_INSTALL_MASK"
+ ]
+
+ _environ_whitelist += [
+ "A", "AA", "CATEGORY", "P", "PF", "PN", "PR", "PV", "PVR"
+ ]
+
+ # misc variables inherited from the calling environment
+ _environ_whitelist += [
+ "COLORTERM", "DISPLAY", "EDITOR", "LESS",
+ "LESSOPEN", "LOGNAME", "LS_COLORS", "PAGER",
+ "TERM", "TERMCAP", "USER",
+ ]
+
+ # tempdir settings
+ _environ_whitelist += [
+ "TMPDIR", "TEMP", "TMP",
+ ]
+
+ # localization settings
+ _environ_whitelist += [
+ "LANG", "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES",
+ "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LC_PAPER",
+ "LC_ALL",
+ ]
+
+ # other variables inherited from the calling environment
+ _environ_whitelist += [
+ "CVS_RSH", "ECHANGELOG_USER",
+ "GPG_AGENT_INFO",
+ "SSH_AGENT_PID", "SSH_AUTH_SOCK",
+ "STY", "WINDOW", "XAUTHORITY",
+ ]
+
+ _environ_whitelist = frozenset(_environ_whitelist)
+
+ _environ_whitelist_re = re.compile(r'^(CCACHE_|DISTCC_).*')
+
+ # Filter selected variables in the config.environ() method so that
+ # they don't needlessly propagate down into the ebuild environment.
+ _environ_filter = []
+
+ # Exclude anything that could be extremely long here (like SRC_URI)
+ # since that could cause execve() calls to fail with E2BIG errors. For
+ # example, see bug #262647.
+ _environ_filter += [
+ 'DEPEND', 'RDEPEND', 'PDEPEND', 'SRC_URI',
+ ]
+
+ # misc variables inherited from the calling environment
+ _environ_filter += [
+ "INFOPATH", "MANPATH", "USER",
+ ]
+
+ # variables that break bash
+ _environ_filter += [
+ "HISTFILE", "POSIXLY_CORRECT",
+ ]
+
+ # portage config variables and variables set directly by portage
+ _environ_filter += [
+ "ACCEPT_KEYWORDS", "ACCEPT_PROPERTIES", "AUTOCLEAN",
+ "CLEAN_DELAY", "COLLISION_IGNORE", "CONFIG_PROTECT",
+ "CONFIG_PROTECT_MASK", "EGENCACHE_DEFAULT_OPTS", "EMERGE_DEFAULT_OPTS",
+ "EMERGE_LOG_DIR",
+ "EMERGE_WARNING_DELAY", "FETCHCOMMAND", "FETCHCOMMAND_FTP",
+ "FETCHCOMMAND_HTTP", "FETCHCOMMAND_SFTP",
+ "GENTOO_MIRRORS", "NOCONFMEM", "O",
+ "PORTAGE_BACKGROUND",
+ "PORTAGE_BINHOST_CHUNKSIZE", "PORTAGE_CALLER",
+ "PORTAGE_ELOG_CLASSES",
+ "PORTAGE_ELOG_MAILFROM", "PORTAGE_ELOG_MAILSUBJECT",
+ "PORTAGE_ELOG_MAILURI", "PORTAGE_ELOG_SYSTEM",
+ "PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS", "PORTAGE_FETCH_RESUME_MIN_SIZE",
+ "PORTAGE_GPG_DIR",
+ "PORTAGE_GPG_KEY", "PORTAGE_IONICE_COMMAND",
+ "PORTAGE_PACKAGE_EMPTY_ABORT",
+ "PORTAGE_REPO_DUPLICATE_WARN",
+ "PORTAGE_RO_DISTDIRS",
+ "PORTAGE_RSYNC_EXTRA_OPTS", "PORTAGE_RSYNC_OPTS",
+ "PORTAGE_RSYNC_RETRIES", "PORTAGE_USE", "PORT_LOGDIR",
+ "QUICKPKG_DEFAULT_OPTS",
+ "RESUMECOMMAND", "RESUMECOMMAND_HTTP", "RESUMECOMMAND_HTTP",
+ "RESUMECOMMAND_SFTP", "SYNC", "USE_EXPAND_HIDDEN", "USE_ORDER",
+ ]
+
+ _environ_filter = frozenset(_environ_filter)
+
+ _undef_lic_groups = set()
+ _default_globals = (
+ ('ACCEPT_LICENSE', '* -@EULA'),
+ ('ACCEPT_PROPERTIES', '*'),
+ )
+
+ # To enhance usability, make some vars case insensitive
+ # by forcing them to lower case.
+ _case_insensitive_vars = ('AUTOCLEAN', 'NOCOLOR',)
+
+ def __init__(self, clone=None, mycpv=None, config_profile_path=None,
+ config_incrementals=None, config_root=None, target_root=None,
+ local_config=True, env=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: __init__ override of $ROOT env variable.
+ @type target_root: 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
+ """
+
+ # 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.already_in_regenerate = 0
+
+ self.locked = 0
+ self.mycpv = None
+ self._setcpv_args_hash = None
+ self.puse = []
+ self.modifiedkeys = []
+ self.uvlist = []
+ self._accept_chost_re = None
+ self._accept_license = None
+ self._accept_license_str = None
+ self._license_groups = {}
+ self._accept_properties = None
+
+ self.virtuals = {}
+ self.virts_p = {}
+ self.dirVirtuals = None
+ self.v_count = 0
+
+ # Virtuals obtained from the vartree
+ self.treeVirtuals = {}
+ # Virtuals by user specification. Includes negatives.
+ self.userVirtuals = {}
+ # Virtual negatives from user specifications.
+ self.negVirtuals = {}
+ # Virtuals added by the depgraph via self.setinst().
+ self._depgraphVirtuals = {}
+
+ self.user_profile_dir = None
+ self.local_config = local_config
+ self._local_repo_configs = None
+ self._local_repo_conf_path = None
+
+ if clone:
+ # For immutable attributes, use shallow copy for
+ # speed and memory conservation.
+ 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.useforce_list = clone.useforce_list
+ self.usemask_list = clone.usemask_list
+
+ self.user_profile_dir = copy.deepcopy(clone.user_profile_dir)
+ self.local_config = copy.deepcopy(clone.local_config)
+ self._local_repo_configs = \
+ copy.deepcopy(clone._local_repo_configs)
+ self._local_repo_conf_path = \
+ copy.deepcopy(clone._local_repo_conf_path)
+ self.modules = copy.deepcopy(clone.modules)
+ self.virtuals = copy.deepcopy(clone.virtuals)
+ self.dirVirtuals = copy.deepcopy(clone.dirVirtuals)
+ self.treeVirtuals = copy.deepcopy(clone.treeVirtuals)
+ self.userVirtuals = copy.deepcopy(clone.userVirtuals)
+ self.negVirtuals = copy.deepcopy(clone.negVirtuals)
+ self._depgraphVirtuals = copy.deepcopy(clone._depgraphVirtuals)
+
+ self.use_defs = copy.deepcopy(clone.use_defs)
+ self.usemask = copy.deepcopy(clone.usemask)
+ self.pusemask_list = copy.deepcopy(clone.pusemask_list)
+ self.useforce = copy.deepcopy(clone.useforce)
+ self.puseforce_list = copy.deepcopy(clone.puseforce_list)
+ self.puse = copy.deepcopy(clone.puse)
+ self.make_defaults_use = copy.deepcopy(clone.make_defaults_use)
+ self.pkgprofileuse = copy.deepcopy(clone.pkgprofileuse)
+ self.mycpv = copy.deepcopy(clone.mycpv)
+ self._setcpv_args_hash = copy.deepcopy(clone._setcpv_args_hash)
+
+ self.configdict = copy.deepcopy(clone.configdict)
+ self.configlist = [
+ self.configdict['env.d'],
+ self.configdict['pkginternal'],
+ self.configdict['globals'],
+ self.configdict['defaults'],
+ self.configdict['conf'],
+ self.configdict['pkg'],
+ self.configdict['auto'],
+ 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.pusedict = copy.deepcopy(clone.pusedict)
+ self.pkeywordsdict = copy.deepcopy(clone.pkeywordsdict)
+ self._pkeywords_list = copy.deepcopy(clone._pkeywords_list)
+ self.pmaskdict = copy.deepcopy(clone.pmaskdict)
+ self.punmaskdict = copy.deepcopy(clone.punmaskdict)
+ self.prevmaskdict = copy.deepcopy(clone.prevmaskdict)
+ self.pprovideddict = copy.deepcopy(clone.pprovideddict)
+ self.features = copy.deepcopy(clone.features)
+
+ self._accept_license = copy.deepcopy(clone._accept_license)
+ self._plicensedict = copy.deepcopy(clone._plicensedict)
+ self._license_groups = copy.deepcopy(clone._license_groups)
+ self._accept_properties = copy.deepcopy(clone._accept_properties)
+ self._ppropertiesdict = copy.deepcopy(clone._ppropertiesdict)
+ else:
+
+ def check_var_directory(varname, var):
+ if not os.path.isdir(var):
+ writemsg(_("!!! Error: %s='%s' is not a directory. "
+ "Please correct this.\n") % (varname, var),
+ noiselevel=-1)
+ raise DirectoryNotFound(var)
+
+ if config_root is None:
+ config_root = "/"
+
+ config_root = normalize_path(os.path.abspath(
+ config_root)).rstrip(os.path.sep) + os.path.sep
+
+ check_var_directory("PORTAGE_CONFIGROOT", config_root)
+
+ self.depcachedir = DEPCACHE_PATH
+
+ if not config_profile_path:
+ config_profile_path = \
+ os.path.join(config_root, PROFILE_PATH)
+ if os.path.isdir(config_profile_path):
+ self.profile_path = config_profile_path
+ else:
+ self.profile_path = None
+ else:
+ self.profile_path = config_profile_path
+
+ if config_incrementals is None:
+ self.incrementals = INCREMENTALS
+ else:
+ self.incrementals = config_incrementals
+ if not isinstance(self.incrementals, tuple):
+ self.incrementals = tuple(self.incrementals)
+
+ self.module_priority = ("user", "default")
+ self.modules = {}
+ modules_loader = KeyValuePairFileLoader(
+ os.path.join(config_root, MODULES_FILE_PATH), None, None)
+ modules_dict, modules_errors = modules_loader.load()
+ self.modules["user"] = modules_dict
+ if self.modules["user"] is None:
+ self.modules["user"] = {}
+ self.modules["default"] = {
+ "portdbapi.metadbmodule": "portage.cache.metadata.database",
+ "portdbapi.auxdbmodule": "portage.cache.flat_hash.database",
+ }
+
+ self.usemask=[]
+ self.configlist=[]
+
+ # back up our incremental variables:
+ self.configdict={}
+ self._use_expand_dict = {}
+ # configlist will contain: [ env.d, globals, defaults, conf, pkg, auto, backupenv, env ]
+ self.configlist.append({})
+ self.configdict["env.d"] = self.configlist[-1]
+
+ self.configlist.append({})
+ self.configdict["pkginternal"] = self.configlist[-1]
+
+ # The symlink might not exist or might not be a symlink.
+ if self.profile_path is None:
+ self.profiles = []
+ else:
+ self.profiles = []
+ def addProfile(currentPath):
+ parentsFile = os.path.join(currentPath, "parent")
+ eapi_file = os.path.join(currentPath, "eapi")
+ try:
+ eapi = codecs.open(_unicode_encode(eapi_file,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace'
+ ).readline().strip()
+ except IOError:
+ pass
+ else:
+ if not eapi_is_supported(eapi):
+ raise ParseError(_(
+ "Profile contains unsupported "
+ "EAPI '%s': '%s'") % \
+ (eapi, os.path.realpath(eapi_file),))
+ if os.path.exists(parentsFile):
+ parents = grabfile(parentsFile)
+ if not parents:
+ raise ParseError(
+ _("Empty parent file: '%s'") % parentsFile)
+ for parentPath in parents:
+ parentPath = normalize_path(os.path.join(
+ currentPath, parentPath))
+ if os.path.exists(parentPath):
+ addProfile(parentPath)
+ else:
+ raise ParseError(
+ _("Parent '%s' not found: '%s'") % \
+ (parentPath, parentsFile))
+ self.profiles.append(currentPath)
+ try:
+ addProfile(os.path.realpath(self.profile_path))
+ except ParseError as e:
+ writemsg(_("!!! Unable to parse profile: '%s'\n") % \
+ self.profile_path, noiselevel=-1)
+ writemsg("!!! ParseError: %s\n" % str(e), noiselevel=-1)
+ del e
+ self.profiles = []
+ if local_config and self.profiles:
+ custom_prof = os.path.join(
+ config_root, CUSTOM_PROFILE_PATH)
+ if os.path.exists(custom_prof):
+ self.user_profile_dir = custom_prof
+ self.profiles.append(custom_prof)
+ del custom_prof
+
+ self.profiles = tuple(self.profiles)
+ self.packages_list = [grabfile_package(os.path.join(x, "packages")) for x in self.profiles]
+ self.packages = tuple(stack_lists(self.packages_list, incremental=1))
+ del self.packages_list
+ #self.packages = grab_stacked("packages", self.profiles, grabfile, incremental_lines=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._pkeywords_list = []
+ rawpkeywords = [grabdict_package(
+ os.path.join(x, "package.keywords"), recursive=1) \
+ for x in self.profiles]
+ for pkeyworddict in rawpkeywords:
+ cpdict = {}
+ for k, v in pkeyworddict.items():
+ cpdict.setdefault(k.cp, {})[k] = v
+ self._pkeywords_list.append(cpdict)
+
+ # get profile-masked use flags -- INCREMENTAL Child over parent
+ self.usemask_list = tuple(
+ tuple(grabfile(os.path.join(x, "use.mask"), recursive=1))
+ for x in self.profiles)
+ self.usemask = set(stack_lists(
+ self.usemask_list, incremental=True))
+ use_defs_lists = [grabdict(os.path.join(x, "use.defaults")) for x in self.profiles]
+ self.use_defs = stack_dictlist(use_defs_lists, incremental=True)
+ del use_defs_lists
+
+ self.pusemask_list = []
+ rawpusemask = [grabdict_package(os.path.join(x, "package.use.mask"),
+ recursive=1) for x in self.profiles]
+ for pusemaskdict in rawpusemask:
+ cpdict = {}
+ for k, v in pusemaskdict.items():
+ cpdict.setdefault(k.cp, {})[k] = v
+ self.pusemask_list.append(cpdict)
+ del rawpusemask
+
+ self.pkgprofileuse = []
+ rawprofileuse = [grabdict_package(os.path.join(x, "package.use"),
+ juststrings=True, recursive=1) for x in self.profiles]
+ for rawpusedict in rawprofileuse:
+ cpdict = {}
+ for k, v in rawpusedict.items():
+ cpdict.setdefault(k.cp, {})[k] = v
+ self.pkgprofileuse.append(cpdict)
+ del rawprofileuse
+
+ self.useforce_list = tuple(
+ tuple(grabfile(os.path.join(x, "use.force"), recursive=1))
+ for x in self.profiles)
+ self.useforce = set(stack_lists(
+ self.useforce_list, incremental=True))
+
+ self.puseforce_list = []
+ rawpuseforce = [grabdict_package(
+ os.path.join(x, "package.use.force"), recursive=1) \
+ for x in self.profiles]
+ for rawpusefdict in rawpuseforce:
+ cpdict = {}
+ for k, v in rawpusefdict.items():
+ cpdict.setdefault(k.cp, {})[k] = v
+ self.puseforce_list.append(cpdict)
+ del rawpuseforce
+
+ make_conf = getconfig(
+ os.path.join(config_root, MAKE_CONF_FILE),
+ tolerant=tolerant, allow_sourcing=True)
+ if make_conf is None:
+ make_conf = {}
+
+ # Allow ROOT setting to come from make.conf if it's not overridden
+ # by the constructor argument (from the calling environment).
+ if target_root is None and "ROOT" in make_conf:
+ target_root = make_conf["ROOT"]
+ if not target_root.strip():
+ target_root = None
+ if target_root is None:
+ target_root = "/"
+
+ target_root = normalize_path(os.path.abspath(
+ target_root)).rstrip(os.path.sep) + os.path.sep
+
+ ensure_dirs(target_root)
+ check_var_directory("ROOT", target_root)
+
+ # 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.
+ expand_map = {}
+
+ env_d = getconfig(os.path.join(target_root, "etc", "profile.env"),
+ expand=expand_map)
+ # env_d will be None if profile.env doesn't exist.
+ if env_d:
+ self.configdict["env.d"].update(env_d)
+ expand_map.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)
+
+ # make.globals should not be relative to config_root
+ # because it only contains constants.
+ for x in (GLOBAL_CONFIG_PATH, "/etc"):
+ self.mygcfg = getconfig(os.path.join(x, "make.globals"),
+ expand=expand_map)
+ if self.mygcfg:
+ break
+
+ if self.mygcfg is None:
+ self.mygcfg = {}
+
+ for k, v in self._default_globals:
+ self.mygcfg.setdefault(k, v)
+
+ self.configlist.append(self.mygcfg)
+ self.configdict["globals"]=self.configlist[-1]
+
+ self.make_defaults_use = []
+ self.mygcfg = {}
+ if self.profiles:
+ mygcfg_dlists = [getconfig(os.path.join(x, "make.defaults"),
+ expand=expand_map) for x in self.profiles]
+
+ for cfg in mygcfg_dlists:
+ if cfg:
+ self.make_defaults_use.append(cfg.get("USE", ""))
+ else:
+ self.make_defaults_use.append("")
+ self.mygcfg = stack_dicts(mygcfg_dlists,
+ incrementals=INCREMENTALS)
+ if self.mygcfg is None:
+ self.mygcfg = {}
+ self.configlist.append(self.mygcfg)
+ self.configdict["defaults"]=self.configlist[-1]
+
+ self.mygcfg = getconfig(
+ os.path.join(config_root, MAKE_CONF_FILE),
+ tolerant=tolerant, allow_sourcing=True, expand=expand_map)
+ if self.mygcfg is None:
+ self.mygcfg = {}
+
+ # Don't allow the user to override certain variables in make.conf
+ profile_only_variables = self.configdict["defaults"].get(
+ "PROFILE_ONLY_VARIABLES", "").split()
+ for k in profile_only_variables:
+ self.mygcfg.pop(k, None)
+
+ self.configlist.append(self.mygcfg)
+ self.configdict["conf"]=self.configlist[-1]
+
+ self.configlist.append(LazyItemsDict())
+ self.configdict["pkg"]=self.configlist[-1]
+
+ #auto-use:
+ self.configlist.append({})
+ self.configdict["auto"]=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")
+
+ # Prefix forward compatability, set EPREFIX to the empty string
+ self["EPREFIX"] = ''
+ self.backup_changes("EPREFIX")
+ self["EROOT"] = target_root
+ self.backup_changes("EROOT")
+
+ self.pusedict = {}
+ self.pkeywordsdict = {}
+ self._plicensedict = {}
+ self._ppropertiesdict = {}
+ self.punmaskdict = {}
+ abs_user_config = os.path.join(config_root, USER_CONFIG_PATH)
+
+ # locations for "categories" and "arch.list" files
+ locations = [os.path.join(self["PORTDIR"], "profiles")]
+ pmask_locations = [os.path.join(self["PORTDIR"], "profiles")]
+ pmask_locations.extend(self.profiles)
+
+ """ repoman controls PORTDIR_OVERLAY via the environment, so no
+ special cases are needed here."""
+ overlay_profiles = []
+ for ov in self["PORTDIR_OVERLAY"].split():
+ ov = normalize_path(ov)
+ profiles_dir = os.path.join(ov, "profiles")
+ if os.path.isdir(profiles_dir):
+ overlay_profiles.append(profiles_dir)
+ locations += overlay_profiles
+
+ pmask_locations.extend(overlay_profiles)
+
+ if local_config:
+ locations.append(abs_user_config)
+ pmask_locations.append(abs_user_config)
+ pusedict = grabdict_package(
+ os.path.join(abs_user_config, "package.use"), recursive=1)
+ for k, v in pusedict.items():
+ self.pusedict.setdefault(k.cp, {})[k] = v
+
+ #package.keywords
+ pkgdict = grabdict_package(
+ os.path.join(abs_user_config, "package.keywords"),
+ recursive=1)
+ for k, v in pkgdict.items():
+ # default to ~arch if no specific keyword is given
+ if not v:
+ mykeywordlist = []
+ if self.configdict["defaults"] and \
+ "ACCEPT_KEYWORDS" in self.configdict["defaults"]:
+ groups = self.configdict["defaults"]["ACCEPT_KEYWORDS"].split()
+ else:
+ groups = []
+ for keyword in groups:
+ if not keyword[0] in "~-":
+ mykeywordlist.append("~"+keyword)
+ v = mykeywordlist
+ self.pkeywordsdict.setdefault(k.cp, {})[k] = v
+
+ #package.license
+ licdict = grabdict_package(os.path.join(
+ abs_user_config, "package.license"), recursive=1)
+ for k, v in licdict.items():
+ cp = k.cp
+ cp_dict = self._plicensedict.get(cp)
+ if not cp_dict:
+ cp_dict = {}
+ self._plicensedict[cp] = cp_dict
+ cp_dict[k] = self.expandLicenseTokens(v)
+
+ #package.properties
+ propdict = grabdict_package(os.path.join(
+ abs_user_config, "package.properties"), recursive=1)
+ for k, v in propdict.items():
+ cp = k.cp
+ cp_dict = self._ppropertiesdict.get(cp)
+ if not cp_dict:
+ cp_dict = {}
+ self._ppropertiesdict[cp] = cp_dict
+ cp_dict[k] = v
+
+ self._local_repo_configs = {}
+ self._local_repo_conf_path = \
+ os.path.join(abs_user_config, 'repos.conf')
+
+ repo_conf_parser = SafeConfigParser()
+ try:
+ repo_conf_parser.readfp(
+ codecs.open(
+ _unicode_encode(self._local_repo_conf_path,
+ encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['content'], errors='replace')
+ )
+ except EnvironmentError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ except ParsingError as e:
+ writemsg_level(
+ _("!!! Error parsing '%s': %s\n") % \
+ (self._local_repo_conf_path, e),
+ level=logging.ERROR, noiselevel=-1)
+ del e
+ else:
+ repo_defaults = repo_conf_parser.defaults()
+ if repo_defaults:
+ self._local_repo_configs['DEFAULT'] = \
+ _local_repo_config('DEFAULT', repo_defaults)
+ for repo_name in repo_conf_parser.sections():
+ repo_opts = repo_defaults.copy()
+ for opt_name in repo_conf_parser.options(repo_name):
+ repo_opts[opt_name] = \
+ repo_conf_parser.get(repo_name, opt_name)
+ self._local_repo_configs[repo_name] = \
+ _local_repo_config(repo_name, repo_opts)
+
+ #getting categories from an external file now
+ categories = [grabfile(os.path.join(x, "categories")) for x in locations]
+ category_re = dbapi._category_re
+ self.categories = tuple(sorted(
+ x for x in stack_lists(categories, incremental=1)
+ if category_re.match(x) is not None))
+ del categories
+
+ archlist = [grabfile(os.path.join(x, "arch.list")) for x in locations]
+ archlist = stack_lists(archlist, incremental=1)
+ self.configdict["conf"]["PORTAGE_ARCHLIST"] = " ".join(archlist)
+
+ # package.mask and package.unmask
+ pkgmasklines = []
+ pkgunmasklines = []
+ for x in pmask_locations:
+ pkgmasklines.append(grabfile_package(
+ os.path.join(x, "package.mask"), recursive=1))
+ pkgunmasklines.append(grabfile_package(
+ os.path.join(x, "package.unmask"), recursive=1))
+ pkgmasklines = stack_lists(pkgmasklines, incremental=1)
+ pkgunmasklines = stack_lists(pkgunmasklines, incremental=1)
+
+ self.pmaskdict = {}
+ for x in pkgmasklines:
+ self.pmaskdict.setdefault(x.cp, []).append(x)
+
+ for x in pkgunmasklines:
+ self.punmaskdict.setdefault(x.cp, []).append(x)
+
+ pkgprovidedlines = [grabfile(os.path.join(x, "package.provided"), recursive=1) for x in self.profiles]
+ 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]
+
+ # parse licensegroups
+ license_groups = self._license_groups
+ for x in locations:
+ for k, v in grabdict(
+ os.path.join(x, "license_groups")).items():
+ license_groups.setdefault(k, []).extend(v)
+
+ # 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:env.d"
+
+ self["PORTAGE_GID"] = str(portage_gid)
+ self.backup_changes("PORTAGE_GID")
+
+ if self.get("PORTAGE_DEPCACHEDIR", None):
+ self.depcachedir = self["PORTAGE_DEPCACHEDIR"]
+ self["PORTAGE_DEPCACHEDIR"] = self.depcachedir
+ self.backup_changes("PORTAGE_DEPCACHEDIR")
+
+ overlays = self.get("PORTDIR_OVERLAY","").split()
+ if overlays:
+ new_ov = []
+ for ov in overlays:
+ ov = normalize_path(ov)
+ if os.path.isdir(ov):
+ new_ov.append(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")
+
+ if "CBUILD" not in self and "CHOST" in self:
+ self["CBUILD"] = self["CHOST"]
+ self.backup_changes("CBUILD")
+
+ self["PORTAGE_BIN_PATH"] = PORTAGE_BIN_PATH
+ self.backup_changes("PORTAGE_BIN_PATH")
+ self["PORTAGE_PYM_PATH"] = PORTAGE_PYM_PATH
+ self.backup_changes("PORTAGE_PYM_PATH")
+
+ for var in ("PORTAGE_INST_UID", "PORTAGE_INST_GID"):
+ try:
+ self[var] = str(int(self.get(var, "0")))
+ except ValueError:
+ writemsg(_("!!! %s='%s' is not a valid integer. "
+ "Falling back to '0'.\n") % (var, self[var]),
+ noiselevel=-1)
+ self[var] = "0"
+ self.backup_changes(var)
+
+ # initialize self.features
+ self.regenerate()
+
+ if bsd_chflags:
+ self.features.add('chflags')
+
+ self["FEATURES"] = " ".join(sorted(self.features))
+ self.backup_changes("FEATURES")
+ global _glep_55_enabled, _validate_cache_for_unsupported_eapis
+ if 'parse-eapi-ebuild-head' in self.features:
+ _validate_cache_for_unsupported_eapis = False
+ if 'parse-eapi-glep-55' in self.features:
+ _validate_cache_for_unsupported_eapis = False
+ _glep_55_enabled = True
+
+ for k in self._case_insensitive_vars:
+ if k in self:
+ self[k] = self[k].lower()
+ self.backup_changes(k)
+
+ if mycpv:
+ self.setcpv(mycpv)
+
+ def _init_dirs(self):
+ """
+ Create a few directories that are critical to portage operation
+ """
+ if not os.access(self["ROOT"], 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["ROOT"], 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)
+
+ 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."""
+ expanded_tokens = []
+ for x in tokens:
+ expanded_tokens.extend(self._expandLicenseToken(x, None))
+ return expanded_tokens
+
+ def _expandLicenseToken(self, token, traversed_groups):
+ negate = False
+ rValue = []
+ if token.startswith("-"):
+ negate = True
+ license_name = token[1:]
+ else:
+ license_name = token
+ if not license_name.startswith("@"):
+ rValue.append(token)
+ return rValue
+ group_name = license_name[1:]
+ if traversed_groups is None:
+ traversed_groups = set()
+ license_group = self._license_groups.get(group_name)
+ if group_name in traversed_groups:
+ writemsg(_("Circular license group reference"
+ " detected in '%s'\n") % group_name, noiselevel=-1)
+ rValue.append("@"+group_name)
+ elif license_group:
+ traversed_groups.add(group_name)
+ for l in license_group:
+ if l.startswith("-"):
+ writemsg(_("Skipping invalid element %s"
+ " in license group '%s'\n") % (l, group_name),
+ noiselevel=-1)
+ else:
+ rValue.extend(self._expandLicenseToken(l, traversed_groups))
+ else:
+ if self._license_groups and \
+ group_name not in self._undef_lic_groups:
+ self._undef_lic_groups.add(group_name)
+ writemsg(_("Undefined license group '%s'\n") % group_name,
+ noiselevel=-1)
+ rValue.append("@"+group_name)
+ if negate:
+ rValue = ["-" + token for token in rValue]
+ return rValue
+
+ 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)
+
+ abs_profile_path = os.path.join(self["PORTAGE_CONFIGROOT"],
+ PROFILE_PATH)
+ if not self.profile_path or (not os.path.islink(abs_profile_path) and \
+ not os.path.exists(os.path.join(abs_profile_path, "parent")) and \
+ os.path.exists(os.path.join(self["PORTDIR"], "profiles"))):
+ writemsg(_("\a\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)
+
+ def loadVirtuals(self,root):
+ """Not currently used by portage."""
+ writemsg("DEPRECATED: portage.config.loadVirtuals\n")
+ self.getvirtuals(root)
+
+ 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.startswith("cache."):
+ best_mod = "portage." + best_mod
+ try:
+ mod = load_mod(best_mod)
+ except ImportError:
+ pass
+ if mod is None:
+ 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=1):
+ """
+ Restore environment from self.backupenv, call self.regenerate()
+ @param keeping_pkg: Should we keep the set_cpv() data or delete it.
+ @type keeping_pkg: Boolean
+ @param use_cache: Should self.regenerate use the cache or not
+ @type use_cache: Boolean
+ @rype: None
+ """
+ self.modifying()
+ self.configdict["env"].clear()
+ self.configdict["env"].update(self.backupenv)
+
+ self.modifiedkeys = []
+ if not keeping_pkg:
+ self.mycpv = None
+ self.puse = ""
+ self.configdict["pkg"].clear()
+ self.configdict["pkginternal"].clear()
+ self.configdict["defaults"]["USE"] = \
+ " ".join(self.make_defaults_use)
+ self.usemask = set(stack_lists(
+ self.usemask_list, incremental=True))
+ self.useforce = set(stack_lists(
+ self.useforce_list, incremental=True))
+ self.regenerate(use_cache=use_cache)
+
+ 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'] = self._accept_license(use, settings)
+ values['PORTAGE_RESTRICT'] = self._restrict(use, settings)
+ return values
+
+ def _accept_license(self, use, settings):
+ """
+ Generate a pruned version of ACCEPT_LICENSE, by intersection with
+ LICENSE. This is required since otherwise ACCEPT_LICENSE might be
+ too big (bigger than ARG_MAX), causing execve() calls to fail with
+ E2BIG errors as in bug #262647.
+ """
+ try:
+ licenses = set(flatten(
+ use_reduce(paren_reduce(
+ settings['LICENSE']),
+ uselist=use)))
+ except InvalidDependString:
+ licenses = set()
+ licenses.discard('||')
+ if settings._accept_license:
+ acceptable_licenses = set()
+ for x in settings._accept_license:
+ if x == '*':
+ acceptable_licenses.update(licenses)
+ elif x == '-*':
+ acceptable_licenses.clear()
+ elif x[:1] == '-':
+ acceptable_licenses.discard(x[1:])
+ elif x in licenses:
+ acceptable_licenses.add(x)
+
+ licenses = acceptable_licenses
+ return ' '.join(sorted(licenses))
+
+ def _restrict(self, use, settings):
+ try:
+ restrict = set(flatten(
+ use_reduce(paren_reduce(
+ settings['RESTRICT']),
+ uselist=use)))
+ 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, use, usemask, iuse_implicit,
+ use_expand_split, use_expand_dict):
+ 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.
+ if has_wildcard:
+ # ebuild.sh will see this and unset the variable so
+ # that things like LINGUAS work properly
+ value = '*'
+ else:
+ if has_iuse:
+ 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=1, 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 use_cache: Enables caching
+ @type use_cache: Boolean
+ @param mydb: a dbapi instance that supports aux_get with the IUSE key.
+ @type mydb: dbapi or derivative.
+ @rtype: None
+ """
+
+ self.modifying()
+
+ pkg = None
+ built_use = None
+ if not isinstance(mycpv, basestring):
+ pkg = mycpv
+ mycpv = pkg.cpv
+ mydb = pkg.metadata
+ 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")
+
+ aux_keys = self._setcpv_aux_keys
+
+ # Discard any existing metadata from the previous package, but
+ # preserve things like USE_EXPAND values and PORTAGE_USE which
+ # might be reused.
+ for k in aux_keys:
+ pkg_configdict.pop(k, None)
+
+ pkg_configdict["CATEGORY"] = cat
+ pkg_configdict["PF"] = pf
+ 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:
+ for k, v in zip(aux_keys, mydb.aux_get(self.mycpv, aux_keys)):
+ pkg_configdict[k] = v
+ repository = pkg_configdict.pop("repository", None)
+ if repository is not None:
+ pkg_configdict["PORTAGE_REPO_NAME"] = repository
+ slot = pkg_configdict["SLOT"]
+ iuse = pkg_configdict["IUSE"]
+ if pkg is None:
+ cpv_slot = "%s:%s" % (self.mycpv, slot)
+ 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)
+ if pkginternaluse != self.configdict["pkginternal"].get("USE", ""):
+ self.configdict["pkginternal"]["USE"] = pkginternaluse
+ has_changed = True
+
+ defaults = []
+ pos = 0
+ for i, pkgprofileuse_dict in enumerate(self.pkgprofileuse):
+ cpdict = pkgprofileuse_dict.get(cp)
+ if cpdict:
+ keys = list(cpdict)
+ while keys:
+ bestmatch = best_match_to_list(cpv_slot, keys)
+ if bestmatch:
+ keys.remove(bestmatch)
+ defaults.insert(pos, cpdict[bestmatch])
+ else:
+ break
+ del keys
+ if self.make_defaults_use[i]:
+ defaults.insert(pos, self.make_defaults_use[i])
+ pos = len(defaults)
+ defaults = " ".join(defaults)
+ if defaults != self.configdict["defaults"].get("USE",""):
+ self.configdict["defaults"]["USE"] = defaults
+ has_changed = True
+
+ useforce = self._getUseForce(cpv_slot)
+ if useforce != self.useforce:
+ self.useforce = useforce
+ has_changed = True
+
+ usemask = self._getUseMask(cpv_slot)
+ if usemask != self.usemask:
+ self.usemask = usemask
+ has_changed = True
+ oldpuse = self.puse
+ self.puse = ""
+ cpdict = self.pusedict.get(cp)
+ if cpdict:
+ keys = list(cpdict)
+ while keys:
+ self.pusekey = best_match_to_list(cpv_slot, keys)
+ if self.pusekey:
+ keys.remove(self.pusekey)
+ self.puse = (" ".join(cpdict[self.pusekey])) + " " + self.puse
+ else:
+ break
+ del keys
+ 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 has_changed:
+ self.reset(keeping_pkg=1,use_cache=use_cache)
+
+ # 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.
+ env_configdict = self.configdict['env']
+ for k in pkg_configdict:
+ if k != 'USE':
+ 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 reset() has not been called, it's safe to return
+ # early if IUSE has not changed.
+ if not has_changed and previous_iuse == iuse:
+ 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())
+ iuse_implicit = self._get_implicit_iuse()
+ iuse_implicit.update(x.lstrip("+-") for x in iuse.split())
+
+ # PORTAGE_IUSE is not always needed so it's lazily evaluated.
+ self.configdict["pkg"].addLazySingleton(
+ "PORTAGE_IUSE", _lazy_iuse_regex, iuse_implicit)
+
+ ebuild_force_test = 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 self.features:
+ if "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:
+ self.usemask.discard("test")
+
+ # Allow _* flags from USE_EXPAND wildcards to pass through here.
+ use.difference_update([x for x in use \
+ if x not in iuse_implicit 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(use, self.usemask,
+ iuse_implicit, use_expand_split, self._use_expand_dict)
+
+ use_expand_iuses = {}
+ for x in iuse_implicit:
+ 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)
+
+ # 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["pkg"]["PORTAGE_USE"] = \
+ " ".join(sorted(x for x in use if x[-2:] != '_*'))
+
+ def _get_implicit_iuse(self):
+ """
+ Some 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):
+ cp = getattr(pkg, "cp", None)
+ if cp is None:
+ cp = cpv_getkey(remove_slot(pkg))
+ usemask = []
+ pos = 0
+ for i, pusemask_dict in enumerate(self.pusemask_list):
+ cpdict = pusemask_dict.get(cp)
+ if cpdict:
+ keys = list(cpdict)
+ while keys:
+ best_match = best_match_to_list(pkg, keys)
+ if best_match:
+ keys.remove(best_match)
+ usemask.insert(pos, cpdict[best_match])
+ else:
+ break
+ del keys
+ if self.usemask_list[i]:
+ usemask.insert(pos, self.usemask_list[i])
+ pos = len(usemask)
+ return set(stack_lists(usemask, incremental=True))
+
+ def _getUseForce(self, pkg):
+ cp = getattr(pkg, "cp", None)
+ if cp is None:
+ cp = cpv_getkey(remove_slot(pkg))
+ useforce = []
+ pos = 0
+ for i, puseforce_dict in enumerate(self.puseforce_list):
+ cpdict = puseforce_dict.get(cp)
+ if cpdict:
+ keys = list(cpdict)
+ while keys:
+ best_match = best_match_to_list(pkg, keys)
+ if best_match:
+ keys.remove(best_match)
+ useforce.insert(pos, cpdict[best_match])
+ else:
+ break
+ del keys
+ if self.useforce_list[i]:
+ useforce.insert(pos, self.useforce_list[i])
+ pos = len(useforce)
+ return set(stack_lists(useforce, incremental=True))
+
+ 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: An matching atom string or None if one is not found.
+ """
+
+ cp = cpv_getkey(cpv)
+ mask_atoms = self.pmaskdict.get(cp)
+ if mask_atoms:
+ pkg_list = ["%s:%s" % (cpv, metadata["SLOT"])]
+ unmask_atoms = self.punmaskdict.get(cp)
+ for x in mask_atoms:
+ if not match_from_list(x, pkg_list):
+ continue
+ if unmask_atoms:
+ for y in unmask_atoms:
+ if match_from_list(y, pkg_list):
+ return None
+ return x
+ return None
+
+ 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: An matching profile atom string or None if one is not found.
+ """
+
+ cp = cpv_getkey(cpv)
+ profile_atoms = self.prevmaskdict.get(cp)
+ if profile_atoms:
+ pkg_list = ["%s:%s" % (cpv, metadata["SLOT"])]
+ for x in profile_atoms:
+ if match_from_list(x, pkg_list):
+ continue
+ return x
+ return None
+
+ def _getKeywords(self, cpv, metadata):
+ cp = cpv_getkey(cpv)
+ pkg = "%s:%s" % (cpv, metadata["SLOT"])
+ keywords = [[x for x in metadata["KEYWORDS"].split() if x != "-*"]]
+ pos = len(keywords)
+ for pkeywords_dict in self._pkeywords_list:
+ cpdict = pkeywords_dict.get(cp)
+ if cpdict:
+ keys = list(cpdict)
+ while keys:
+ best_match = best_match_to_list(pkg, keys)
+ if best_match:
+ keys.remove(best_match)
+ keywords.insert(pos, cpdict[best_match])
+ else:
+ break
+ pos = len(keywords)
+ return stack_lists(keywords, incremental=True)
+
+ def _getMissingKeywords(self, cpv, metadata):
+ """
+ Take a package and return a list of any KEYWORDS that the user may
+ 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 distiguish 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)
+ egroups = self.configdict["backupenv"].get(
+ "ACCEPT_KEYWORDS", "").split()
+ mygroups = self._getKeywords(cpv, metadata)
+ # Repoman may modify this attribute as necessary.
+ pgroups = self["ACCEPT_KEYWORDS"].split()
+ match=0
+ cp = cpv_getkey(cpv)
+ pkgdict = self.pkeywordsdict.get(cp)
+ matches = False
+ if pkgdict:
+ cpv_slot_list = ["%s:%s" % (cpv, metadata["SLOT"])]
+ for atom, pkgkeywords in pkgdict.items():
+ if match_from_list(atom, cpv_slot_list):
+ matches = True
+ pgroups.extend(pkgkeywords)
+ if matches or egroups:
+ pgroups.extend(egroups)
+ inc_pgroups = set()
+ for x in pgroups:
+ if x.startswith("-"):
+ if x == "-*":
+ inc_pgroups.clear()
+ else:
+ inc_pgroups.discard(x[1:])
+ else:
+ inc_pgroups.add(x)
+ pgroups = inc_pgroups
+ del inc_pgroups
+ hasstable = False
+ hastesting = False
+ for gp in mygroups:
+ if gp == "*" or (gp == "-*" and len(mygroups) == 1):
+ writemsg(_("--- WARNING: Package '%(cpv)s' uses"
+ " '%(keyword)s' keyword.\n") % {"cpv": cpv, "keyword": gp}, noiselevel=-1)
+ if gp == "*":
+ match = 1
+ break
+ elif gp in pgroups:
+ match=1
+ break
+ elif gp.startswith("~"):
+ hastesting = True
+ elif not gp.startswith("-"):
+ hasstable = True
+ if not match and \
+ ((hastesting and "~*" in pgroups) or \
+ (hasstable and "*" in pgroups) or "**" in pgroups):
+ match=1
+ if match:
+ missing = []
+ else:
+ if not mygroups:
+ # If KEYWORDS is empty then we still have to return something
+ # in order to distiguish from the case of "none missing".
+ mygroups.append("**")
+ missing = mygroups
+ return missing
+
+ def _getMissingLicenses(self, cpv, metadata):
+ """
+ Take a LICENSE string and return a list any licenses that the user may
+ 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.
+ """
+ accept_license = self._accept_license
+ cpdict = self._plicensedict.get(cpv_getkey(cpv), None)
+ if cpdict:
+ accept_license = list(self._accept_license)
+ cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
+ for atom in match_to_list(cpv_slot, list(cpdict)):
+ accept_license.extend(cpdict[atom])
+
+ licenses = set(flatten(use_reduce(paren_reduce(
+ metadata["LICENSE"]), matchall=1)))
+ licenses.discard('||')
+
+ acceptable_licenses = set()
+ for x in accept_license:
+ if x == '*':
+ acceptable_licenses.update(licenses)
+ elif x == '-*':
+ acceptable_licenses.clear()
+ elif x[:1] == '-':
+ acceptable_licenses.discard(x[1:])
+ else:
+ acceptable_licenses.add(x)
+
+ license_str = metadata["LICENSE"]
+ if "?" in license_str:
+ use = metadata["USE"].split()
+ else:
+ use = []
+
+ license_struct = use_reduce(
+ paren_reduce(license_str), uselist=use)
+ license_struct = dep_opconvert(license_struct)
+ return self._getMaskedLicenses(license_struct, acceptable_licenses)
+
+ def _getMaskedLicenses(self, license_struct, acceptable_licenses):
+ if not license_struct:
+ return []
+ if license_struct[0] == "||":
+ ret = []
+ for element in license_struct[1:]:
+ if isinstance(element, list):
+ if element:
+ ret.append(self._getMaskedLicenses(
+ element, acceptable_licenses))
+ if not ret[-1]:
+ return []
+ else:
+ if element in acceptable_licenses:
+ return []
+ ret.append(element)
+ # Return all masked licenses, since we don't know which combination
+ # (if any) the user will decide to unmask.
+ return flatten(ret)
+
+ ret = []
+ for element in license_struct:
+ if isinstance(element, list):
+ if element:
+ ret.extend(self._getMaskedLicenses(element,
+ acceptable_licenses))
+ else:
+ if element not in acceptable_licenses:
+ ret.append(element)
+ return ret
+
+ def _getMissingProperties(self, cpv, metadata):
+ """
+ Take a PROPERTIES string and return a list of any properties the user may
+ 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
+ cpdict = self._ppropertiesdict.get(cpv_getkey(cpv), None)
+ if cpdict:
+ accept_properties = list(self._accept_properties)
+ cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
+ for atom in match_to_list(cpv_slot, list(cpdict)):
+ accept_properties.extend(cpdict[atom])
+
+ properties = set(flatten(use_reduce(paren_reduce(
+ metadata["PROPERTIES"]), matchall=1)))
+ properties.discard('||')
+
+ 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)
+
+ properties_str = metadata["PROPERTIES"]
+ if "?" in properties_str:
+ use = metadata["USE"].split()
+ else:
+ use = []
+
+ properties_struct = use_reduce(
+ paren_reduce(properties_str), uselist=use)
+ properties_struct = dep_opconvert(properties_struct)
+ return self._getMaskedProperties(properties_struct, acceptable_properties)
+
+ def _getMaskedProperties(self, properties_struct, acceptable_properties):
+ if not properties_struct:
+ return []
+ if properties_struct[0] == "||":
+ ret = []
+ for element in properties_struct[1:]:
+ if isinstance(element, list):
+ if element:
+ ret.append(self._getMaskedProperties(
+ element, acceptable_properties))
+ if not ret[-1]:
+ return []
+ else:
+ if element in acceptable_properties:
+ return[]
+ ret.append(element)
+ # Return all masked properties, since we don't know which combination
+ # (if any) the user will decide to unmask
+ return flatten(ret)
+
+ ret = []
+ for element in properties_struct:
+ if isinstance(element, list):
+ if element:
+ ret.extend(self._getMaskedProperties(element,
+ acceptable_properties))
+ else:
+ if element not in acceptable_properties:
+ ret.append(element)
+ return ret
+
+ 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()
+ if len(self.virtuals) == 0:
+ self.getvirtuals()
+ # 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 = flatten(use_reduce(paren_reduce(provides), uselist=myuse.split()))
+
+ modified = False
+ cp = Atom(cpv_getkey(mycpv))
+ for virt in virts:
+ try:
+ virt = Atom(virt).cp
+ except InvalidAtom:
+ continue
+ providers = self.virtuals.get(virt)
+ if providers and cp in providers:
+ continue
+ providers = self._depgraphVirtuals.get(virt)
+ if providers is None:
+ providers = []
+ self._depgraphVirtuals[virt] = providers
+ if cp not in providers:
+ providers.append(cp)
+ modified = True
+
+ if modified:
+ self.virtuals = self.__getvirtuals_compile()
+
+ def reload(self):
+ """Reload things like /etc/profile.env that can change during runtime."""
+ env_d_filename = os.path.join(self["ROOT"], "etc", "profile.env")
+ self.configdict["env.d"].clear()
+ env_d = getconfig(env_d_filename, expand=False)
+ if env_d:
+ # env_d will be None if profile.env doesn't exist.
+ self.configdict["env.d"].update(env_d)
+
+ def _prune_incremental(self, split):
+ """
+ Prune off any parts of an incremental variable that are
+ made irrelevant by the latest occuring * or -*. This
+ could be more aggressive but that might be confusing
+ and the point is just to reduce noise a bit.
+ """
+ for i, x in enumerate(reversed(split)):
+ if x == '*':
+ split = split[-i-1:]
+ break
+ elif x == '-*':
+ if i == 0:
+ split = []
+ else:
+ split = split[-i:]
+ break
+ return split
+
+ def regenerate(self,useonly=0,use_cache=1):
+ """
+ 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
+ @param use_cache: Enable Caching (only for autouse)
+ @type use_cache: Boolean
+ @rtype: None
+ """
+
+ self.modifying()
+ if self.already_in_regenerate:
+ # XXX: THIS REALLY NEEDS TO GET FIXED. autouse() loops.
+ writemsg("!!! Looping in regenerate.\n",1)
+ return
+ else:
+ self.already_in_regenerate = 1
+
+ if useonly:
+ myincrementals=["USE"]
+ else:
+ myincrementals = self.incrementals
+ myincrementals = set(myincrementals)
+ # If self.features exists, it has already been stacked and may have
+ # been mutated, so don't stack it again or else any mutations will be
+ # reverted.
+ if "FEATURES" in myincrementals and hasattr(self, "features"):
+ myincrementals.remove("FEATURES")
+
+ if "USE" in myincrementals:
+ # Process USE last because it depends on USE_EXPAND which is also
+ # an incremental!
+ myincrementals.remove("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 = self._prune_incremental(mysplit)
+ accept_license_str = ' '.join(mysplit)
+ self.configlist[-1]['ACCEPT_LICENSE'] = accept_license_str
+ if accept_license_str != self._accept_license_str:
+ self._accept_license_str = accept_license_str
+ self._accept_license = tuple(self.expandLicenseTokens(mysplit))
+ else:
+ # repoman will accept any license
+ self._accept_license = ('*',)
+
+ # 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 = self._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 = ('*',)
+
+ for mykey in myincrementals:
+
+ myflags=[]
+ for curdb in mydbs:
+ if mykey not in curdb:
+ continue
+ #variables are already expanded
+ mysplit = curdb[mykey].split()
+
+ 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 = []
+ continue
+
+ if x[0]=="+":
+ # Not legal. People assume too much. Complain.
+ writemsg(colorize("BAD",
+ _("USE flags should not start with a '+': %s") % x) \
+ + "\n", noiselevel=-1)
+ x=x[1:]
+ if not x:
+ continue
+
+ if (x[0]=="-"):
+ if (x[1:] in myflags):
+ # Unset/Remove it.
+ del myflags[myflags.index(x[1:])]
+ continue
+
+ # We got here, so add it now.
+ if x not in myflags:
+ myflags.append(x)
+
+ myflags.sort()
+ #store setting in last element of configlist, the original environment:
+ if myflags or mykey in self:
+ self.configlist[-1][mykey] = " ".join(myflags)
+ del myflags
+
+ # Do the USE calculation last because it depends on USE_EXPAND.
+ if "auto" in self["USE_ORDER"].split(":"):
+ self.configdict["auto"]["USE"] = autouse(
+ vartree(root=self["ROOT"], categories=self.categories,
+ settings=self),
+ use_cache=use_cache, mysettings=self)
+ else:
+ self.configdict["auto"]["USE"] = ""
+
+ 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
+
+ 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().
+ myflags = set()
+ for curdb in self.uvlist:
+ 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] == "-":
+ myflags.discard(x[1:])
+ continue
+
+ myflags.add(x)
+
+ 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.clear()
+ else:
+ self.features = set()
+ self.features.update(self.configlist[-1].get('FEATURES', '').split())
+ self['FEATURES'] = ' '.join(sorted(self.features))
+
+ 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))
+
+ self.already_in_regenerate = 0
+
+ def get_virts_p(self, myroot=None):
+
+ if myroot is not None:
+ warnings.warn("The 'myroot' parameter for " + \
+ "portage.config.get_virts_p() is deprecated",
+ DeprecationWarning, stacklevel=2)
+
+ if self.virts_p:
+ return self.virts_p
+ virts = self.getvirtuals()
+ if virts:
+ for x in virts:
+ vkeysplit = x.split("/")
+ if vkeysplit[1] not in self.virts_p:
+ self.virts_p[vkeysplit[1]] = virts[x]
+ return self.virts_p
+
+ def getvirtuals(self, myroot=None):
+ """myroot is now ignored because, due to caching, it has always been
+ broken for all but the first call."""
+
+ if myroot is not None:
+ warnings.warn("The 'myroot' parameter for " + \
+ "portage.config.getvirtuals() is deprecated",
+ DeprecationWarning, stacklevel=2)
+
+ myroot = self["ROOT"]
+ if self.virtuals:
+ return self.virtuals
+
+ virtuals_list = []
+ for x in self.profiles:
+ virtuals_file = os.path.join(x, "virtuals")
+ virtuals_dict = grabdict(virtuals_file)
+ atoms_dict = {}
+ for k, v in virtuals_dict.items():
+ try:
+ virt_atom = Atom(k)
+ except InvalidAtom:
+ virt_atom = None
+ else:
+ if virt_atom.blocker or \
+ str(virt_atom) != str(virt_atom.cp):
+ virt_atom = None
+ if virt_atom is None:
+ writemsg(_("--- Invalid virtuals atom in %s: %s\n") % \
+ (virtuals_file, k), noiselevel=-1)
+ continue
+ providers = []
+ for atom in v:
+ atom_orig = atom
+ if atom[:1] == '-':
+ # allow incrementals
+ atom = atom[1:]
+ try:
+ atom = Atom(atom)
+ except InvalidAtom:
+ atom = None
+ else:
+ if atom.blocker:
+ atom = None
+ if atom is None:
+ writemsg(_("--- Invalid atom in %s: %s\n") % \
+ (virtuals_file, atom_orig), noiselevel=-1)
+ else:
+ if atom_orig == str(atom):
+ # normal atom, so return as Atom instance
+ providers.append(atom)
+ else:
+ # atom has special prefix, so return as string
+ providers.append(atom_orig)
+ if providers:
+ atoms_dict[virt_atom] = providers
+ if atoms_dict:
+ virtuals_list.append(atoms_dict)
+
+ self.dirVirtuals = stack_dictlist(virtuals_list, incremental=True)
+ del virtuals_list
+
+ for virt in self.dirVirtuals:
+ # Preference for virtuals decreases from left to right.
+ self.dirVirtuals[virt].reverse()
+
+ # Repoman does not use user or tree virtuals.
+ if self.local_config and not self.treeVirtuals:
+ temp_vartree = vartree(myroot, None,
+ categories=self.categories, settings=self)
+ self._populate_treeVirtuals(temp_vartree)
+
+ self.virtuals = self.__getvirtuals_compile()
+ return self.virtuals
+
+ def _populate_treeVirtuals(self, vartree):
+ """Reduce the provides into a list by CP."""
+ for provide, cpv_list in vartree.get_all_provides().items():
+ try:
+ provide = Atom(provide)
+ except InvalidAtom:
+ continue
+ self.treeVirtuals[provide.cp] = \
+ [Atom(cpv_getkey(cpv)) for cpv in cpv_list]
+
+ def __getvirtuals_compile(self):
+ """Stack installed and profile virtuals. Preference for virtuals
+ decreases from left to right.
+ Order of preference:
+ 1. installed and in profile
+ 2. installed only
+ 3. profile only
+ """
+
+ # Virtuals by profile+tree preferences.
+ ptVirtuals = {}
+
+ for virt, installed_list in self.treeVirtuals.items():
+ profile_list = self.dirVirtuals.get(virt, None)
+ if not profile_list:
+ continue
+ for cp in installed_list:
+ if cp in profile_list:
+ ptVirtuals.setdefault(virt, [])
+ ptVirtuals[virt].append(cp)
+
+ virtuals = stack_dictlist([ptVirtuals, self.treeVirtuals,
+ self.dirVirtuals, self._depgraphVirtuals])
+ return virtuals
+
+ def __delitem__(self,mykey):
+ self.modifying()
+ for x in self.lookuplist:
+ if x != None:
+ if mykey in x:
+ del x[mykey]
+
+ def __getitem__(self,mykey):
+ for d in self.lookuplist:
+ if mykey in d:
+ return d[mykey]
+ return '' # for backward compat, don't raise KeyError
+
+ def get(self, k, x=None):
+ for d in self.lookuplist:
+ if k in d:
+ return d[k]
+ return x
+
+ def pop(self, key, *args):
+ 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 has_key(self,mykey):
+ warnings.warn("portage.config.has_key() is deprecated, "
+ "use the in operator instead",
+ DeprecationWarning, stacklevel=2)
+ return mykey in self
+
+ def __contains__(self, mykey):
+ """Called to implement membership test operators (in and not in)."""
+ for d in self.lookuplist:
+ if mykey in d:
+ return True
+ return False
+
+ 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()
+ 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[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')
+ phase = self.get('EBUILD_PHASE')
+ filter_calling_env = False
+ if phase not in ('clean', 'cleanrm', 'depend'):
+ 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.
+ 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
+
+ # 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 eapi not in ("0", "1", "2", "3", "3_pre2"):
+ mydict.pop("AA", None)
+
+ # Prefix variables are supported starting with EAPI 3.
+ if phase == 'depend' or eapi in (None, "0", "1", "2"):
+ mydict.pop("ED", None)
+ mydict.pop("EPREFIX", None)
+ mydict.pop("EROOT", None)
+
+ if phase == 'depend':
+ mydict.pop('FILESDIR', None)
+
+ return mydict
+
+ def thirdpartymirrors(self):
+ if getattr(self, "_thirdpartymirrors", None) is None:
+ profileroots = [os.path.join(self["PORTDIR"], "profiles")]
+ for x in self["PORTDIR_OVERLAY"].split():
+ profileroots.insert(0, os.path.join(x, "profiles"))
+ thirdparty_lists = [grabdict(os.path.join(x, "thirdpartymirrors")) for x in profileroots]
+ self._thirdpartymirrors = stack_dictlist(thirdparty_lists, incremental=True)
+ return self._thirdpartymirrors
+
+ def archlist(self):
+ return flatten([[myarch, "~" + myarch] \
+ for myarch in self["PORTAGE_ARCHLIST"].split()])
+
+ 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