from portage.cache.mappings import slot_dict_class
from portage.const import EBUILD_PHASES
from portage.dep import Atom, check_required_use, use_reduce, \
- paren_enclose, _slot_re, _slot_separator, _repo_separator
+ paren_enclose, _slot_separator, _repo_separator
from portage.versions import _pkg_str, _unknown_repo
-from portage.eapi import _get_eapi_attrs
+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):
"root_config", "type_name",
"category", "counter", "cp", "cpv_split",
"inherited", "iuse", "mtime",
- "pf", "root", "slot", "slot_atom", "version") + \
- ("_invalid", "_raw_metadata", "_masks", "_use", "_visible")
+ "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', 'PDEPEND', 'RDEPEND',)
+ _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
if not self.built:
self.metadata['CHOST'] = self.root_config.settings.get('CHOST', '')
eapi_attrs = _get_eapi_attrs(self.metadata["EAPI"])
- slot = self.slot
- if _slot_re.match(slot) is None:
+ 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'
- self.cpv = _pkg_str(self.cpv, slot=slot,
- repo=self.metadata.get('repository', ''))
+ "SLOT: invalid value: '%s'" % self.metadata["SLOT"])
+ self.cpv_split = self.cpv.cpv_split
+ self.category, self.pf = portage.catsplit(self.cpv)
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")
- self.slot_atom = portage.dep.Atom("%s%s%s" % (self.cp, _slot_separator, slot))
- self.category, self.pf = portage.catsplit(self.cpv)
- self.cpv_split = self.cpv.cpv_split
- self.version = self.cpv.version
if self.inherited is None:
self.inherited = frozenset()
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
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,
# So overwrite the repo_key with type_name.
repo_key = type_name
- return (type_name, root, cpv, operation, repo_key)
+ return (type_name, root, _unicode(cpv), operation, repo_key)
def _validate_deps(self):
"""
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:
- use_reduce(v, eapi=dep_eapi, matchall=True,
- is_valid_flag=dep_valid_flag, token_class=Atom)
+ 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)
k = 'REQUIRED_USE'
v = self.metadata.get(k)
- if v:
+ 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)
+ 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
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
_unicode_decode("%s: %s") % (k, error))
if not categorized_error:
- self._invalid_metadata(k + ".syntax",
+ self._invalid_metadata(qacat,
_unicode_decode("%s: %s") % (k, e))
else:
# For installed packages, show the path of the file
# want to fix the deps by hand.
vardb = self.root_config.trees['vartree'].dbapi
path = vardb.getpath(self.cpv, filename=k)
- self._invalid_metadata(k + ".syntax",
+ self._invalid_metadata(qacat,
_unicode_decode("%s: %s in '%s'") % (k, e, path))
def _invalid_metadata(self, msg_type, msg):
self._expand_hidden = None
self._force = None
self._mask = None
- self.enabled = frozenset(use_str.split())
+ 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
class _iuse(object):
- __slots__ = ("__weakref__", "all", "enabled", "disabled",
- "tokens") + ("_iuse_implicit_match",)
+ __slots__ = ("__weakref__", "_iuse_implicit_match", "_pkg", "alias_mapping",
+ "all", "all_aliases", "enabled", "disabled", "tokens")
- def __init__(self, tokens, iuse_implicit_match):
+ def __init__(self, pkg, tokens, iuse_implicit_match, aliases, eapi):
+ self._pkg = pkg
self.tokens = tuple(tokens)
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):
"""
flags = [flags]
for flag in flags:
- if not flag in self.all and \
+ if not flag in self.all and not flag in self.all_aliases and \
not self._iuse_implicit_match(flag):
return False
return True
flags = [flags]
missing_iuse = []
for flag in flags:
- if not flag in self.all and \
+ 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_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
__slots__ = ("_pkg",)
_wrapped_keys = frozenset(
- ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"])
+ ["COUNTER", "INHERITED", "USE", "_mtime_"])
_use_conditional_keys = frozenset(
['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
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_match)
-
- def _set_slot(self, k, v):
- self._pkg.slot = v
-
def _set_counter(self, k, v):
if isinstance(v, basestring):
try: