-# Copyright 1999-2010 Gentoo Foundation
+# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-import re
import sys
from itertools import chain
import portage
+from portage import _encodings, _unicode_decode, _unicode_encode
from portage.cache.mappings import slot_dict_class
-from portage.dep import isvalidatom, use_reduce, \
- paren_enclose, _slot_re
-from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
+from portage.const import EBUILD_PHASES
+from portage.dep import Atom, check_required_use, use_reduce, \
+ paren_enclose, _slot_separator, _repo_separator
+from portage.versions import _pkg_str, _unknown_repo
+from portage.eapi import _get_eapi_attrs, eapi_has_use_aliases
+from portage.exception import InvalidDependString
+from portage.localization import _
from _emerge.Task import Task
if sys.hexversion >= 0x3000000:
basestring = str
long = int
+ _unicode = str
+else:
+ _unicode = unicode
class Package(Task):
"installed", "metadata", "onlydeps", "operation",
"root_config", "type_name",
"category", "counter", "cp", "cpv_split",
- "inherited", "invalid", "iuse", "masks", "mtime",
- "pf", "pv_split", "root", "slot", "slot_atom", "visible",) + \
- ("_raw_metadata", "_use",)
+ "inherited", "iuse", "mtime",
+ "pf", "root", "slot", "sub_slot", "slot_atom", "version") + \
+ ("_invalid", "_raw_metadata", "_masks", "_use",
+ "_validated_atoms", "_visible")
metadata_keys = [
"BUILD_TIME", "CHOST", "COUNTER", "DEPEND", "EAPI",
- "INHERITED", "IUSE", "KEYWORDS",
+ "HDEPEND", "INHERITED", "IUSE", "KEYWORDS",
"LICENSE", "PDEPEND", "PROVIDE", "RDEPEND",
"repository", "PROPERTIES", "RESTRICT", "SLOT", "USE",
"_mtime_", "DEFINED_PHASES", "REQUIRED_USE"]
+ _dep_keys = ('DEPEND', 'HDEPEND', 'PDEPEND', 'RDEPEND')
+ _buildtime_keys = ('DEPEND', 'HDEPEND')
+ _runtime_keys = ('PDEPEND', 'RDEPEND')
+ _use_conditional_misc_keys = ('LICENSE', 'PROPERTIES', 'RESTRICT')
+ UNKNOWN_REPO = _unknown_repo
+
def __init__(self, **kwargs):
Task.__init__(self, **kwargs)
+ # the SlotObject constructor assigns self.root_config from keyword args
+ # and is an instance of a '_emerge.RootConfig.RootConfig class
self.root = self.root_config.root
self._raw_metadata = _PackageMetadataWrapperBase(self.metadata)
self.metadata = _PackageMetadataWrapper(self, self._raw_metadata)
if not self.built:
self.metadata['CHOST'] = self.root_config.settings.get('CHOST', '')
- self.cp = portage.cpv_getkey(self.cpv)
- slot = self.slot
- if _slot_re.match(slot) is None:
+ eapi_attrs = _get_eapi_attrs(self.metadata["EAPI"])
+ self.cpv = _pkg_str(self.cpv, metadata=self.metadata,
+ settings=self.root_config.settings)
+ if hasattr(self.cpv, 'slot_invalid'):
self._invalid_metadata('SLOT.invalid',
- "SLOT: invalid value: '%s'" % slot)
- # Avoid an InvalidAtom exception when creating slot_atom.
- # This package instance will be masked due to empty SLOT.
- slot = '0'
- if (self.iuse.enabled or self.iuse.disabled) and \
- not eapi_has_iuse_defaults(self.metadata["EAPI"]):
- self._invalid_metadata('IUSE.invalid',
- "IUSE contains defaults, but EAPI doesn't allow them")
- if self.metadata.get("REQUIRED_USE") and \
- not eapi_has_required_use(self.metadata["EAPI"]):
- self._invalid_metadata('REQUIRED_USE.invalid',
- "REQUIRED_USE set, but EAPI doesn't allow it")
- self.slot_atom = portage.dep.Atom("%s:%s" % (self.cp, slot))
+ "SLOT: invalid value: '%s'" % self.metadata["SLOT"])
+ self.cpv_split = self.cpv.cpv_split
self.category, self.pf = portage.catsplit(self.cpv)
- self.cpv_split = portage.catpkgsplit(self.cpv)
- self.pv_split = self.cpv_split[1:]
- self.masks = self._masks()
- self.visible = self._visible(self.masks)
+ self.cp = self.cpv.cp
+ self.version = self.cpv.version
+ self.slot = self.cpv.slot
+ self.sub_slot = self.cpv.sub_slot
+ self.slot_atom = Atom("%s%s%s" % (self.cp, _slot_separator, self.slot))
+ # sync metadata with validated repo (may be UNKNOWN_REPO)
+ self.metadata['repository'] = self.cpv.repo
+
+ if eapi_attrs.iuse_effective:
+ implicit_match = self.root_config.settings._iuse_effective_match
+ else:
+ implicit_match = self.root_config.settings._iuse_implicit_match
+ usealiases = self.root_config.settings._use_manager.getUseAliases(self)
+ self.iuse = self._iuse(self, self.metadata["IUSE"].split(), implicit_match,
+ usealiases, self.metadata["EAPI"])
+
+ if (self.iuse.enabled or self.iuse.disabled) and \
+ not eapi_attrs.iuse_defaults:
+ if not self.installed:
+ self._invalid_metadata('EAPI.incompatible',
+ "IUSE contains defaults, but EAPI doesn't allow them")
+ if self.inherited is None:
+ self.inherited = frozenset()
+
+ if self.operation is None:
+ if self.onlydeps or self.installed:
+ self.operation = "nomerge"
+ else:
+ self.operation = "merge"
+
+ self._hash_key = Package._gen_hash_key(cpv=self.cpv,
+ installed=self.installed, onlydeps=self.onlydeps,
+ operation=self.operation, repo_name=self.cpv.repo,
+ root_config=self.root_config,
+ type_name=self.type_name)
+ self._hash_value = hash(self._hash_key)
+
+ # For consistency with _pkg_str
+ @property
+ def _metadata(self):
+ return self.metadata
+
+ # These are calculated on-demand, so that they are calculated
+ # after FakeVartree applies its metadata tweaks.
+ @property
+ def invalid(self):
+ if self._invalid is None:
+ self._validate_deps()
+ if self._invalid is None:
+ self._invalid = False
+ return self._invalid
+
+ @property
+ def masks(self):
+ if self._masks is None:
+ self._masks = self._eval_masks()
+ return self._masks
+
+ @property
+ def visible(self):
+ if self._visible is None:
+ self._visible = self._eval_visiblity(self.masks)
+ return self._visible
+
+ @property
+ def validated_atoms(self):
+ """
+ Returns *all* validated atoms from the deps, regardless
+ of USE conditionals, with USE conditionals inside
+ atoms left unevaluated.
+ """
+ if self._validated_atoms is None:
+ self._validate_deps()
+ return self._validated_atoms
+
+ @property
+ def stable(self):
+ return self.cpv.stable
+
+ @classmethod
+ def _gen_hash_key(cls, cpv=None, installed=None, onlydeps=None,
+ operation=None, repo_name=None, root_config=None,
+ type_name=None, **kwargs):
+
+ if operation is None:
+ if installed or onlydeps:
+ operation = "nomerge"
+ else:
+ operation = "merge"
+
+ root = None
+ if root_config is not None:
+ root = root_config.root
+ else:
+ raise TypeError("root_config argument is required")
+
+ # For installed (and binary) packages we don't care for the repo
+ # when it comes to hashing, because there can only be one cpv.
+ # So overwrite the repo_key with type_name.
+ if type_name is None:
+ raise TypeError("type_name argument is required")
+ elif type_name == "ebuild":
+ if repo_name is None:
+ raise AssertionError(
+ "Package._gen_hash_key() " + \
+ "called without 'repo_name' argument")
+ repo_key = repo_name
+ else:
+ # For installed (and binary) packages we don't care for the repo
+ # when it comes to hashing, because there can only be one cpv.
+ # So overwrite the repo_key with type_name.
+ repo_key = type_name
+
+ return (type_name, root, _unicode(cpv), operation, repo_key)
+
+ def _validate_deps(self):
+ """
+ Validate deps. This does not trigger USE calculation since that
+ is expensive for ebuilds and therefore we want to avoid doing
+ in unnecessarily (like for masked packages).
+ """
+ eapi = self.metadata['EAPI']
+ dep_eapi = eapi
+ dep_valid_flag = self.iuse.is_valid_flag
+ if self.installed:
+ # Ignore EAPI.incompatible and conditionals missing
+ # from IUSE for installed packages since these issues
+ # aren't relevant now (re-evaluate when new EAPIs are
+ # deployed).
+ dep_eapi = None
+ dep_valid_flag = None
+
+ validated_atoms = []
+ for k in self._dep_keys:
+ v = self.metadata.get(k)
+ if not v:
+ continue
+ try:
+ atoms = use_reduce(v, eapi=dep_eapi,
+ matchall=True, is_valid_flag=dep_valid_flag,
+ token_class=Atom, flat=True)
+ except InvalidDependString as e:
+ self._metadata_exception(k, e)
+ else:
+ validated_atoms.extend(atoms)
+ if not self.built:
+ for atom in atoms:
+ if not isinstance(atom, Atom):
+ continue
+ if atom.slot_operator_built:
+ e = InvalidDependString(
+ _("Improper context for slot-operator "
+ "\"built\" atom syntax: %s") %
+ (atom.unevaluated_atom,))
+ self._metadata_exception(k, e)
+
+ self._validated_atoms = tuple(set(atom for atom in
+ validated_atoms if isinstance(atom, Atom)))
+
+ k = 'PROVIDE'
+ v = self.metadata.get(k)
+ if v:
+ try:
+ use_reduce(v, eapi=dep_eapi, matchall=True,
+ is_valid_flag=dep_valid_flag, token_class=Atom)
+ except InvalidDependString as e:
+ self._invalid_metadata("PROVIDE.syntax",
+ _unicode_decode("%s: %s") % (k, e))
+
+ for k in self._use_conditional_misc_keys:
+ v = self.metadata.get(k)
+ if not v:
+ continue
+ try:
+ use_reduce(v, eapi=dep_eapi, matchall=True,
+ is_valid_flag=dep_valid_flag)
+ except InvalidDependString as e:
+ self._metadata_exception(k, e)
+
+ k = 'REQUIRED_USE'
+ v = self.metadata.get(k)
+ if v and not self.built:
+ if not _get_eapi_attrs(eapi).required_use:
+ self._invalid_metadata('EAPI.incompatible',
+ "REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
+ else:
+ try:
+ check_required_use(v, (),
+ self.iuse.is_valid_flag, eapi=eapi)
+ except InvalidDependString as e:
+ # Force unicode format string for python-2.x safety,
+ # ensuring that PortageException.__unicode__() is used
+ # when necessary.
+ self._invalid_metadata(k + ".syntax",
+ _unicode_decode("%s: %s") % (k, e))
+
+ k = 'SRC_URI'
+ v = self.metadata.get(k)
+ if v:
+ try:
+ use_reduce(v, is_src_uri=True, eapi=eapi, matchall=True,
+ is_valid_flag=self.iuse.is_valid_flag)
+ except InvalidDependString as e:
+ if not self.installed:
+ self._metadata_exception(k, e)
def copy(self):
return Package(built=self.built, cpv=self.cpv, depth=self.depth,
onlydeps=self.onlydeps, operation=self.operation,
root_config=self.root_config, type_name=self.type_name)
- def _masks(self):
+ def _eval_masks(self):
masks = {}
settings = self.root_config.settings
- if self.invalid is not None:
+ if self.invalid is not False:
masks['invalid'] = self.invalid
if not settings._accept_chost(self.cpv, self.metadata):
self.cpv, self.metadata)
if missing_properties:
masks['PROPERTIES'] = missing_properties
- except portage.exception.InvalidDependString:
+ except InvalidDependString:
# already recorded as 'invalid'
pass
if mask_atom is not None:
masks['package.mask'] = mask_atom
- system_mask = settings._getProfileMaskAtom(
- self.cpv, self.metadata)
- if system_mask is not None:
- masks['profile.system'] = system_mask
-
try:
missing_licenses = settings._getMissingLicenses(
self.cpv, self.metadata)
if missing_licenses:
masks['LICENSE'] = missing_licenses
- except portage.exception.InvalidDependString:
+ except InvalidDependString:
# already recorded as 'invalid'
pass
if not masks:
- masks = None
+ masks = False
return masks
- def _visible(self, masks):
+ def _eval_visiblity(self, masks):
- if masks is not None:
+ if masks is not False:
if 'EAPI.unsupported' in masks:
return False
+ if 'invalid' in masks:
+ return False
+
if not self.installed and ( \
- 'invalid' in masks or \
'CHOST' in masks or \
'EAPI.deprecated' in masks or \
'KEYWORDS' in masks or \
return False
if 'package.mask' in masks or \
- 'profile.system' in masks or \
'LICENSE' in masks:
return False
return True
+ def get_keyword_mask(self):
+ """returns None, 'missing', or 'unstable'."""
+
+ missing = self.root_config.settings._getRawMissingKeywords(
+ self.cpv, self.metadata)
+
+ if not missing:
+ return None
+
+ if '**' in missing:
+ return 'missing'
+
+ global_accept_keywords = frozenset(
+ self.root_config.settings.get("ACCEPT_KEYWORDS", "").split())
+
+ for keyword in missing:
+ if keyword.lstrip("~") in global_accept_keywords:
+ return 'unstable'
+
+ return 'missing'
+
+ def isHardMasked(self):
+ """returns a bool if the cpv is in the list of
+ expanded pmaskdict[cp] available ebuilds"""
+ pmask = self.root_config.settings._getRawMaskAtom(
+ self.cpv, self.metadata)
+ return pmask is not None
+
+ def _metadata_exception(self, k, e):
+
+ if k.endswith('DEPEND'):
+ qacat = 'dependency.syntax'
+ else:
+ qacat = k + ".syntax"
+
+ # For unicode safety with python-2.x we need to avoid
+ # using the string format operator with a non-unicode
+ # format string, since that will result in the
+ # PortageException.__str__() method being invoked,
+ # followed by unsafe decoding that may result in a
+ # UnicodeDecodeError. Therefore, use _unicode_decode()
+ # to ensure that format strings are unicode, so that
+ # PortageException.__unicode__() is used when necessary
+ # in python-2.x.
+ if not self.installed:
+ categorized_error = False
+ if e.errors:
+ for error in e.errors:
+ if getattr(error, 'category', None) is None:
+ continue
+ categorized_error = True
+ self._invalid_metadata(error.category,
+ _unicode_decode("%s: %s") % (k, error))
+
+ if not categorized_error:
+ self._invalid_metadata(qacat,
+ _unicode_decode("%s: %s") % (k, e))
+ else:
+ # For installed packages, show the path of the file
+ # containing the invalid metadata, since the user may
+ # want to fix the deps by hand.
+ vardb = self.root_config.trees['vartree'].dbapi
+ path = vardb.getpath(self.cpv, filename=k)
+ self._invalid_metadata(qacat,
+ _unicode_decode("%s: %s in '%s'") % (k, e, path))
+
def _invalid_metadata(self, msg_type, msg):
- if self.invalid is None:
- self.invalid = {}
- msgs = self.invalid.get(msg_type)
+ if self._invalid is None:
+ self._invalid = {}
+ msgs = self._invalid.get(msg_type)
if msgs is None:
msgs = []
- self.invalid[msg_type] = msgs
+ self._invalid[msg_type] = msgs
msgs.append(msg)
def __str__(self):
- if self.operation is None:
- self.operation = "merge"
- if self.onlydeps or self.installed:
- self.operation = "nomerge"
-
if self.operation == "merge":
if self.type_name == "binary":
cpv_color = "PKG_BINARY_MERGE"
cpv_color = "PKG_NOMERGE"
s = "(%s, %s" \
- % (portage.output.colorize(cpv_color, self.cpv) , self.type_name)
+ % (portage.output.colorize(cpv_color, self.cpv + _repo_separator + self.repo) , self.type_name)
if self.type_name == "installed":
- if self.root != "/":
- s += " in '%s'" % self.root
+ if self.root_config.settings['ROOT'] != "/":
+ s += " in '%s'" % self.root_config.settings['ROOT']
if self.operation == "uninstall":
s += " scheduled for uninstall"
else:
if self.operation == "merge":
s += " scheduled for merge"
- if self.root != "/":
- s += " to '%s'" % self.root
+ if self.root_config.settings['ROOT'] != "/":
+ s += " to '%s'" % self.root_config.settings['ROOT']
s += ")"
return s
+ if sys.hexversion < 0x3000000:
+
+ __unicode__ = __str__
+
+ def __str__(self):
+ return _unicode_encode(self.__unicode__(),
+ encoding=_encodings['content'])
+
class _use_class(object):
- __slots__ = ("__weakref__", "enabled")
+ __slots__ = ("enabled", "_expand", "_expand_hidden",
+ "_force", "_pkg", "_mask")
+
+ # Share identical frozenset instances when available.
+ _frozensets = {}
+
+ def __init__(self, pkg, use_str):
+ self._pkg = pkg
+ self._expand = None
+ self._expand_hidden = None
+ self._force = None
+ self._mask = None
+ enabled_flags = use_str.split()
+ if eapi_has_use_aliases(pkg.metadata["EAPI"]):
+ for enabled_flag in enabled_flags:
+ enabled_flags.extend(pkg.iuse.alias_mapping.get(enabled_flag, []))
+ self.enabled = frozenset(enabled_flags)
+ if pkg.built:
+ # Use IUSE to validate USE settings for built packages,
+ # in case the package manager that built this package
+ # failed to do that for some reason (or in case of
+ # data corruption).
+ missing_iuse = pkg.iuse.get_missing_iuse(self.enabled)
+ if missing_iuse:
+ self.enabled = self.enabled.difference(missing_iuse)
+
+ def _init_force_mask(self):
+ pkgsettings = self._pkg._get_pkgsettings()
+ frozensets = self._frozensets
+ s = frozenset(
+ pkgsettings.get("USE_EXPAND", "").lower().split())
+ self._expand = frozensets.setdefault(s, s)
+ s = frozenset(
+ pkgsettings.get("USE_EXPAND_HIDDEN", "").lower().split())
+ self._expand_hidden = frozensets.setdefault(s, s)
+ s = pkgsettings.useforce
+ self._force = frozensets.setdefault(s, s)
+ s = pkgsettings.usemask
+ self._mask = frozensets.setdefault(s, s)
+
+ @property
+ def expand(self):
+ if self._expand is None:
+ self._init_force_mask()
+ return self._expand
+
+ @property
+ def expand_hidden(self):
+ if self._expand_hidden is None:
+ self._init_force_mask()
+ return self._expand_hidden
+
+ @property
+ def force(self):
+ if self._force is None:
+ self._init_force_mask()
+ return self._force
+
+ @property
+ def mask(self):
+ if self._mask is None:
+ self._init_force_mask()
+ return self._mask
+
+ @property
+ def repo(self):
+ return self.metadata['repository']
- def __init__(self, use):
- self.enabled = frozenset(use)
+ @property
+ def repo_priority(self):
+ repo_info = self.root_config.settings.repositories.prepos.get(self.repo)
+ if repo_info is None:
+ return None
+ return repo_info.priority
@property
def use(self):
if self._use is None:
- self._use = self._use_class(self.metadata['USE'].split())
+ self.metadata._init_use()
return self._use
+ def _get_pkgsettings(self):
+ pkgsettings = self.root_config.trees[
+ 'porttree'].dbapi.doebuild_settings
+ pkgsettings.setcpv(self)
+ return pkgsettings
+
class _iuse(object):
- __slots__ = ("__weakref__", "all", "enabled", "disabled",
- "tokens") + ("_iuse_implicit_regex",)
+ __slots__ = ("__weakref__", "_iuse_implicit_match", "_pkg", "alias_mapping",
+ "all", "all_aliases", "enabled", "disabled", "tokens")
- def __init__(self, tokens, iuse_implicit_regex):
+ def __init__(self, pkg, tokens, iuse_implicit_match, aliases, eapi):
+ self._pkg = pkg
self.tokens = tuple(tokens)
- self._iuse_implicit_regex = iuse_implicit_regex
+ self._iuse_implicit_match = iuse_implicit_match
enabled = []
disabled = []
other = []
+ enabled_aliases = []
+ disabled_aliases = []
+ other_aliases = []
+ aliases_supported = eapi_has_use_aliases(eapi)
+ self.alias_mapping = {}
for x in tokens:
prefix = x[:1]
if prefix == "+":
enabled.append(x[1:])
+ if aliases_supported:
+ self.alias_mapping[x[1:]] = aliases.get(x[1:], [])
+ enabled_aliases.extend(self.alias_mapping[x[1:]])
elif prefix == "-":
disabled.append(x[1:])
+ if aliases_supported:
+ self.alias_mapping[x[1:]] = aliases.get(x[1:], [])
+ disabled_aliases.extend(self.alias_mapping[x[1:]])
else:
other.append(x)
- self.enabled = frozenset(enabled)
- self.disabled = frozenset(disabled)
+ if aliases_supported:
+ self.alias_mapping[x] = aliases.get(x, [])
+ other_aliases.extend(self.alias_mapping[x])
+ self.enabled = frozenset(chain(enabled, enabled_aliases))
+ self.disabled = frozenset(chain(disabled, disabled_aliases))
self.all = frozenset(chain(enabled, disabled, other))
+ self.all_aliases = frozenset(chain(enabled_aliases, disabled_aliases, other_aliases))
def is_valid_flag(self, flags):
"""
- @returns: True if all flags are valid USE values which may
+ @return: True if all flags are valid USE values which may
be specified in USE dependencies, False otherwise.
"""
if isinstance(flags, basestring):
flags = [flags]
for flag in flags:
- if not flag in self.all and \
- self._iuse_implicit_regex.match(flag) is None:
+ if not flag in self.all and not flag in self.all_aliases and \
+ not self._iuse_implicit_match(flag):
return False
return True
-
+
def get_missing_iuse(self, flags):
"""
- @returns: A list of flags missing from IUSE.
+ @return: A list of flags missing from IUSE.
"""
if isinstance(flags, basestring):
flags = [flags]
missing_iuse = []
for flag in flags:
- if not flag in self.all and \
- self._iuse_implicit_regex.match(flag) is None:
+ if not flag in self.all and not flag in self.all_aliases and \
+ not self._iuse_implicit_match(flag):
missing_iuse.append(flag)
return missing_iuse
- def _get_hash_key(self):
- hash_key = getattr(self, "_hash_key", None)
- if hash_key is None:
- if self.operation is None:
- self.operation = "merge"
- if self.onlydeps or self.installed:
- self.operation = "nomerge"
- self._hash_key = \
- (self.type_name, self.root, self.cpv, self.operation)
- return self._hash_key
+ def get_real_flag(self, flag):
+ if flag in self.all:
+ return flag
+ elif flag in self.all_aliases:
+ for k, v in self.alias_mapping.items():
+ if flag in v:
+ return k
+ else:
+ raise ValueError("'%s' flag is not in IUSE and is not an alias of any flag in IUSE of '%s::%s'" %
+ (flag, self._pkg.cpv, self._pkg.repo))
+
+ def __len__(self):
+ return 4
+
+ def __iter__(self):
+ """
+ This is used to generate mtimedb resume mergelist entries, so we
+ limit it to 4 items for backward compatibility.
+ """
+ return iter(self._hash_key[:4])
def __lt__(self, other):
if other.cp != self.cp:
return False
- if portage.pkgcmp(self.pv_split, other.pv_split) < 0:
+ if portage.vercmp(self.version, other.version) < 0:
return True
return False
def __le__(self, other):
if other.cp != self.cp:
return False
- if portage.pkgcmp(self.pv_split, other.pv_split) <= 0:
+ if portage.vercmp(self.version, other.version) <= 0:
return True
return False
def __gt__(self, other):
if other.cp != self.cp:
return False
- if portage.pkgcmp(self.pv_split, other.pv_split) > 0:
+ if portage.vercmp(self.version, other.version) > 0:
return True
return False
def __ge__(self, other):
if other.cp != self.cp:
return False
- if portage.pkgcmp(self.pv_split, other.pv_split) >= 0:
+ if portage.vercmp(self.version, other.version) >= 0:
return True
return False
__slots__ = ("_pkg",)
_wrapped_keys = frozenset(
- ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"])
+ ["COUNTER", "INHERITED", "USE", "_mtime_"])
_use_conditional_keys = frozenset(
['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
self.update(metadata)
+ def _init_use(self):
+ if self._pkg.built:
+ use_str = self['USE']
+ self._pkg._use = self._pkg._use_class(
+ self._pkg, use_str)
+ else:
+ try:
+ use_str = _PackageMetadataWrapperBase.__getitem__(self, 'USE')
+ except KeyError:
+ use_str = None
+ calculated_use = False
+ if not use_str:
+ use_str = self._pkg._get_pkgsettings()["PORTAGE_USE"]
+ calculated_use = True
+ _PackageMetadataWrapperBase.__setitem__(self, 'USE', use_str)
+ self._pkg._use = self._pkg._use_class(
+ self._pkg, use_str)
+ # Initialize these now, since USE access has just triggered
+ # setcpv, and we want to cache the result of the force/mask
+ # calculations that were done.
+ if calculated_use:
+ self._pkg._use._init_force_mask()
+
+ return use_str
+
def __getitem__(self, k):
v = _PackageMetadataWrapperBase.__getitem__(self, k)
if k in self._use_conditional_keys:
if self._pkg.root_config.settings.local_config and '?' in v:
try:
- v = paren_enclose(use_reduce(v, uselist=self._pkg.use.enabled))
- except portage.exception.InvalidDependString:
+ v = paren_enclose(use_reduce(v, uselist=self._pkg.use.enabled, \
+ is_valid_flag=self._pkg.iuse.is_valid_flag))
+ except InvalidDependString:
# This error should already have been registered via
# self._pkg._invalid_metadata().
pass
elif k == 'USE' and not self._pkg.built:
if not v:
# This is lazy because it's expensive.
- pkgsettings = self._pkg.root_config.trees[
- 'porttree'].dbapi.doebuild_settings
- pkgsettings.setcpv(self._pkg)
- v = pkgsettings["PORTAGE_USE"]
- _PackageMetadataWrapperBase.__setitem__(self, 'USE', v)
+ v = self._init_use()
return v
_PackageMetadataWrapperBase.__setitem__(self, k, v)
if k in self._wrapped_keys:
getattr(self, "_set_" + k.lower())(k, v)
- elif k in self._use_conditional_keys:
- try:
- reduced = use_reduce(v, matchall=1, flat=True)
- except portage.exception.InvalidDependString as e:
- self._pkg._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))
- else:
- if reduced and k == 'PROVIDE':
- for x in reduced:
- if not isvalidatom(x):
- self._pkg._invalid_metadata(k + ".syntax",
- "%s: %s" % (k, x))
def _set_inherited(self, k, v):
if isinstance(v, basestring):
v = frozenset(v.split())
self._pkg.inherited = v
- def _set_iuse(self, k, v):
- self._pkg.iuse = self._pkg._iuse(
- v.split(), self._pkg.root_config.settings._iuse_implicit_re)
-
- def _set_slot(self, k, v):
- self._pkg.slot = v
-
def _set_counter(self, k, v):
if isinstance(v, basestring):
try:
@property
def defined_phases(self):
- return self['DEFINED_PHASES'].split()
+ """
+ Returns tokens from DEFINED_PHASES metadata if it is defined,
+ otherwise returns a tuple containing all possible phases. This
+ makes it easy to do containment checks to see if it's safe to
+ skip execution of a given phase.
+ """
+ s = self['DEFINED_PHASES']
+ if s:
+ return s.split()
+ return EBUILD_PHASES