1 # Copyright 1999-2011 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
5 from itertools import chain
7 from portage import _encodings, _unicode_decode, _unicode_encode
8 from portage.cache.mappings import slot_dict_class
9 from portage.const import EBUILD_PHASES
10 from portage.dep import Atom, check_required_use, use_reduce, \
11 paren_enclose, _slot_re, _slot_separator, _repo_separator
12 from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
13 from portage.exception import InvalidDependString
14 from portage.repository.config import _gen_valid_repo
15 from _emerge.Task import Task
17 if sys.hexversion >= 0x3000000:
23 __hash__ = Task.__hash__
24 __slots__ = ("built", "cpv", "depth",
25 "installed", "metadata", "onlydeps", "operation",
26 "root_config", "type_name",
27 "category", "counter", "cp", "cpv_split",
28 "inherited", "invalid", "iuse", "masks", "mtime",
29 "pf", "pv_split", "root", "slot", "slot_atom", "visible",) + \
30 ("_raw_metadata", "_use",)
33 "BUILD_TIME", "CHOST", "COUNTER", "DEPEND", "EAPI",
34 "INHERITED", "IUSE", "KEYWORDS",
35 "LICENSE", "PDEPEND", "PROVIDE", "RDEPEND",
36 "repository", "PROPERTIES", "RESTRICT", "SLOT", "USE",
37 "_mtime_", "DEFINED_PHASES", "REQUIRED_USE"]
39 _dep_keys = ('DEPEND', 'PDEPEND', 'RDEPEND',)
40 _use_conditional_misc_keys = ('LICENSE', 'PROPERTIES', 'RESTRICT')
42 def __init__(self, **kwargs):
43 Task.__init__(self, **kwargs)
44 # the SlotObject constructor assigns self.root_config from keyword args
45 # and is an instance of a '_emerge.RootConfig.RootConfig class
46 self.root = self.root_config.root
47 self._raw_metadata = _PackageMetadataWrapperBase(self.metadata)
48 self.metadata = _PackageMetadataWrapper(self, self._raw_metadata)
50 self.metadata['CHOST'] = self.root_config.settings.get('CHOST', '')
51 self.cp = portage.cpv_getkey(self.cpv)
53 if _slot_re.match(slot) is None:
54 self._invalid_metadata('SLOT.invalid',
55 "SLOT: invalid value: '%s'" % slot)
56 # Avoid an InvalidAtom exception when creating slot_atom.
57 # This package instance will be masked due to empty SLOT.
59 if (self.iuse.enabled or self.iuse.disabled) and \
60 not eapi_has_iuse_defaults(self.metadata["EAPI"]):
61 if not self.installed:
62 self._invalid_metadata('EAPI.incompatible',
63 "IUSE contains defaults, but EAPI doesn't allow them")
64 self.slot_atom = portage.dep.Atom("%s%s%s" % (self.cp, _slot_separator, slot))
65 self.category, self.pf = portage.catsplit(self.cpv)
66 self.cpv_split = portage.catpkgsplit(self.cpv)
67 self.pv_split = self.cpv_split[1:]
68 if self.inherited is None:
69 self.inherited = frozenset()
70 repo = _gen_valid_repo(self.metadata.get('repository', ''))
73 self.metadata['repository'] = repo
76 self.masks = self._masks()
77 self.visible = self._visible(self.masks)
78 if self.operation is None:
79 if self.onlydeps or self.installed:
80 self.operation = "nomerge"
82 self.operation = "merge"
84 def _validate_deps(self):
86 Validate deps. This does not trigger USE calculation since that
87 is expensive for ebuilds and therefore we want to avoid doing
88 in unnecessarily (like for masked packages).
90 eapi = self.metadata['EAPI']
92 dep_valid_flag = self.iuse.is_valid_flag
94 # Ignore EAPI.incompatible and conditionals missing
95 # from IUSE for installed packages since these issues
96 # aren't relevant now (re-evaluate when new EAPIs are
101 for k in self._dep_keys:
102 v = self.metadata.get(k)
106 use_reduce(v, eapi=dep_eapi, matchall=True,
107 is_valid_flag=dep_valid_flag, token_class=Atom)
108 except InvalidDependString as e:
109 self._metadata_exception(k, e)
112 v = self.metadata.get(k)
115 use_reduce(v, eapi=dep_eapi, matchall=True,
116 is_valid_flag=dep_valid_flag, token_class=Atom)
117 except InvalidDependString as e:
118 self._invalid_metadata("PROVIDE.syntax",
119 _unicode_decode("%s: %s") % (k, e))
121 for k in self._use_conditional_misc_keys:
122 v = self.metadata.get(k)
126 use_reduce(v, eapi=dep_eapi, matchall=True,
127 is_valid_flag=dep_valid_flag)
128 except InvalidDependString as e:
129 self._metadata_exception(k, e)
132 v = self.metadata.get(k)
134 if not eapi_has_required_use(eapi):
135 self._invalid_metadata('EAPI.incompatible',
136 "REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
139 check_required_use(v, (),
140 self.iuse.is_valid_flag)
141 except InvalidDependString as e:
142 # Force unicode format string for python-2.x safety,
143 # ensuring that PortageException.__unicode__() is used
145 self._invalid_metadata(k + ".syntax",
146 _unicode_decode("%s: %s") % (k, e))
149 v = self.metadata.get(k)
152 use_reduce(v, is_src_uri=True, eapi=eapi, matchall=True,
153 is_valid_flag=self.iuse.is_valid_flag)
154 except InvalidDependString as e:
155 if not self.installed:
156 self._metadata_exception(k, e)
159 return Package(built=self.built, cpv=self.cpv, depth=self.depth,
160 installed=self.installed, metadata=self._raw_metadata,
161 onlydeps=self.onlydeps, operation=self.operation,
162 root_config=self.root_config, type_name=self.type_name)
166 settings = self.root_config.settings
168 if self.invalid is not None:
169 masks['invalid'] = self.invalid
171 if not settings._accept_chost(self.cpv, self.metadata):
172 masks['CHOST'] = self.metadata['CHOST']
174 eapi = self.metadata["EAPI"]
175 if not portage.eapi_is_supported(eapi):
176 masks['EAPI.unsupported'] = eapi
177 if portage._eapi_is_deprecated(eapi):
178 masks['EAPI.deprecated'] = eapi
180 missing_keywords = settings._getMissingKeywords(
181 self.cpv, self.metadata)
183 masks['KEYWORDS'] = missing_keywords
186 missing_properties = settings._getMissingProperties(
187 self.cpv, self.metadata)
188 if missing_properties:
189 masks['PROPERTIES'] = missing_properties
190 except InvalidDependString:
191 # already recorded as 'invalid'
194 mask_atom = settings._getMaskAtom(self.cpv, self.metadata)
195 if mask_atom is not None:
196 masks['package.mask'] = mask_atom
198 system_mask = settings._getProfileMaskAtom(
199 self.cpv, self.metadata)
200 if system_mask is not None:
201 masks['profile.system'] = system_mask
204 missing_licenses = settings._getMissingLicenses(
205 self.cpv, self.metadata)
207 masks['LICENSE'] = missing_licenses
208 except InvalidDependString:
209 # already recorded as 'invalid'
217 def _visible(self, masks):
219 if masks is not None:
221 if 'EAPI.unsupported' in masks:
224 if 'invalid' in masks:
227 if not self.installed and ( \
228 'CHOST' in masks or \
229 'EAPI.deprecated' in masks or \
230 'KEYWORDS' in masks or \
231 'PROPERTIES' in masks):
234 if 'package.mask' in masks or \
235 'profile.system' in masks or \
241 def get_keyword_mask(self):
242 """returns None, 'missing', or 'unstable'."""
244 missing = self.root_config.settings._getRawMissingKeywords(
245 self.cpv, self.metadata)
253 global_accept_keywords = frozenset(
254 self.root_config.settings.get("ACCEPT_KEYWORDS", "").split())
256 for keyword in missing:
257 if keyword.lstrip("~") in global_accept_keywords:
262 def isHardMasked(self):
263 """returns a bool if the cpv is in the list of
264 expanded pmaskdict[cp] available ebuilds"""
265 pmask = self.root_config.settings._getRawMaskAtom(
266 self.cpv, self.metadata)
267 return pmask is not None
270 def _metadata_exception(self, k, e):
272 # For unicode safety with python-2.x we need to avoid
273 # using the string format operator with a non-unicode
274 # format string, since that will result in the
275 # PortageException.__str__() method being invoked,
276 # followed by unsafe decoding that may result in a
277 # UnicodeDecodeError. Therefore, use _unicode_decode()
278 # to ensure that format strings are unicode, so that
279 # PortageException.__unicode__() is used when necessary
281 if not self.installed:
282 categorized_error = False
284 for error in e.errors:
285 if getattr(error, 'category', None) is None:
287 categorized_error = True
288 self._invalid_metadata(error.category,
289 _unicode_decode("%s: %s") % (k, error))
291 if not categorized_error:
292 self._invalid_metadata(k + ".syntax",
293 _unicode_decode("%s: %s") % (k, e))
295 # For installed packages, show the path of the file
296 # containing the invalid metadata, since the user may
297 # want to fix the deps by hand.
298 vardb = self.root_config.trees['vartree'].dbapi
299 path = vardb.getpath(self.cpv, filename=k)
300 self._invalid_metadata(k + ".syntax",
301 _unicode_decode("%s: %s in '%s'") % (k, e, path))
303 def _invalid_metadata(self, msg_type, msg):
304 if self.invalid is None:
306 msgs = self.invalid.get(msg_type)
309 self.invalid[msg_type] = msgs
313 if self.operation == "merge":
314 if self.type_name == "binary":
315 cpv_color = "PKG_BINARY_MERGE"
317 cpv_color = "PKG_MERGE"
318 elif self.operation == "uninstall":
319 cpv_color = "PKG_UNINSTALL"
321 cpv_color = "PKG_NOMERGE"
324 % (portage.output.colorize(cpv_color, self.cpv + _repo_separator + self.repo) , self.type_name)
326 if self.type_name == "installed":
328 s += " in '%s'" % self.root
329 if self.operation == "uninstall":
330 s += " scheduled for uninstall"
332 if self.operation == "merge":
333 s += " scheduled for merge"
335 s += " to '%s'" % self.root
339 if sys.hexversion < 0x3000000:
341 __unicode__ = __str__
344 return _unicode_encode(self.__unicode__(),
345 encoding=_encodings['content'])
347 class _use_class(object):
349 __slots__ = ("enabled", "_force", "_pkg", "_mask")
351 def __init__(self, pkg, use_str):
355 self.enabled = frozenset(use_str.split())
357 # Use IUSE to validate USE settings for built packages,
358 # in case the package manager that built this package
359 # failed to do that for some reason (or in case of
361 missing_iuse = pkg.iuse.get_missing_iuse(self.enabled)
363 self.enabled = self.enabled.difference(missing_iuse)
365 def _init_force_mask(self):
366 pkgsettings = self._pkg._get_pkgsettings()
367 self._force = pkgsettings.useforce
368 self._mask = pkgsettings.usemask
372 if self._force is None:
373 self._init_force_mask()
378 if self._mask is None:
379 self._init_force_mask()
384 return self.metadata['repository']
387 def repo_priority(self):
388 repo_info = self.root_config.settings.repositories.prepos.get(self.repo)
389 if repo_info is None:
391 return repo_info.priority
395 if self._use is None:
396 self.metadata._init_use()
399 def _get_pkgsettings(self):
400 pkgsettings = self.root_config.trees[
401 'porttree'].dbapi.doebuild_settings
402 pkgsettings.setcpv(self)
407 __slots__ = ("__weakref__", "all", "enabled", "disabled",
408 "tokens") + ("_iuse_implicit_match",)
410 def __init__(self, tokens, iuse_implicit_match):
411 self.tokens = tuple(tokens)
412 self._iuse_implicit_match = iuse_implicit_match
419 enabled.append(x[1:])
421 disabled.append(x[1:])
424 self.enabled = frozenset(enabled)
425 self.disabled = frozenset(disabled)
426 self.all = frozenset(chain(enabled, disabled, other))
428 def is_valid_flag(self, flags):
430 @returns: True if all flags are valid USE values which may
431 be specified in USE dependencies, False otherwise.
433 if isinstance(flags, basestring):
437 if not flag in self.all and \
438 not self._iuse_implicit_match(flag):
442 def get_missing_iuse(self, flags):
444 @returns: A list of flags missing from IUSE.
446 if isinstance(flags, basestring):
450 if not flag in self.all and \
451 not self._iuse_implicit_match(flag):
452 missing_iuse.append(flag)
455 def _get_hash_key(self):
456 hash_key = getattr(self, "_hash_key", None)
458 # For installed (and binary) packages we don't care for the repo
459 # when it comes to hashing, because there can only be one cpv.
460 # So overwrite the repo_key with type_name.
461 repo_key = self.metadata.get('repository')
462 if self.type_name != 'ebuild':
463 repo_key = self.type_name
465 (self.type_name, self.root, self.cpv, self.operation, repo_key)
466 return self._hash_key
473 This is used to generate mtimedb resume mergelist entries, so we
474 limit it to 4 items for backward compatibility.
476 return iter(self._get_hash_key()[:4])
478 def __lt__(self, other):
479 if other.cp != self.cp:
481 if portage.pkgcmp(self.pv_split, other.pv_split) < 0:
485 def __le__(self, other):
486 if other.cp != self.cp:
488 if portage.pkgcmp(self.pv_split, other.pv_split) <= 0:
492 def __gt__(self, other):
493 if other.cp != self.cp:
495 if portage.pkgcmp(self.pv_split, other.pv_split) > 0:
499 def __ge__(self, other):
500 if other.cp != self.cp:
502 if portage.pkgcmp(self.pv_split, other.pv_split) >= 0:
506 _all_metadata_keys = set(x for x in portage.auxdbkeys \
507 if not x.startswith("UNUSED_"))
508 _all_metadata_keys.update(Package.metadata_keys)
509 _all_metadata_keys = frozenset(_all_metadata_keys)
511 _PackageMetadataWrapperBase = slot_dict_class(_all_metadata_keys)
513 class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
515 Detect metadata updates and synchronize Package attributes.
518 __slots__ = ("_pkg",)
519 _wrapped_keys = frozenset(
520 ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"])
521 _use_conditional_keys = frozenset(
522 ['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
524 def __init__(self, pkg, metadata):
525 _PackageMetadataWrapperBase.__init__(self)
528 # USE is lazy, but we want it to show up in self.keys().
529 _PackageMetadataWrapperBase.__setitem__(self, 'USE', '')
531 self.update(metadata)
535 use_str = self['USE']
536 self._pkg._use = self._pkg._use_class(
540 use_str = _PackageMetadataWrapperBase.__getitem__(self, 'USE')
543 calculated_use = False
545 use_str = self._pkg._get_pkgsettings()["PORTAGE_USE"]
546 calculated_use = True
547 _PackageMetadataWrapperBase.__setitem__(self, 'USE', use_str)
548 self._pkg._use = self._pkg._use_class(
550 # Initialize these now, since USE access has just triggered
551 # setcpv, and we want to cache the result of the force/mask
552 # calculations that were done.
554 self._pkg._use._init_force_mask()
558 def __getitem__(self, k):
559 v = _PackageMetadataWrapperBase.__getitem__(self, k)
560 if k in self._use_conditional_keys:
561 if self._pkg.root_config.settings.local_config and '?' in v:
563 v = paren_enclose(use_reduce(v, uselist=self._pkg.use.enabled, \
564 is_valid_flag=self._pkg.iuse.is_valid_flag))
565 except InvalidDependString:
566 # This error should already have been registered via
567 # self._pkg._invalid_metadata().
572 elif k == 'USE' and not self._pkg.built:
574 # This is lazy because it's expensive.
579 def __setitem__(self, k, v):
580 _PackageMetadataWrapperBase.__setitem__(self, k, v)
581 if k in self._wrapped_keys:
582 getattr(self, "_set_" + k.lower())(k, v)
584 def _set_inherited(self, k, v):
585 if isinstance(v, basestring):
586 v = frozenset(v.split())
587 self._pkg.inherited = v
589 def _set_iuse(self, k, v):
590 self._pkg.iuse = self._pkg._iuse(
591 v.split(), self._pkg.root_config.settings._iuse_implicit_match)
593 def _set_slot(self, k, v):
596 def _set_counter(self, k, v):
597 if isinstance(v, basestring):
602 self._pkg.counter = v
604 def _set_use(self, k, v):
605 # Force regeneration of _use attribute
606 self._pkg._use = None
607 # Use raw metadata to restore USE conditional values
608 # to unevaluated state
609 raw_metadata = self._pkg._raw_metadata
610 for x in self._use_conditional_keys:
612 self[x] = raw_metadata[x]
616 def _set__mtime_(self, k, v):
617 if isinstance(v, basestring):
625 def properties(self):
626 return self['PROPERTIES'].split()
630 return self['RESTRICT'].split()
633 def defined_phases(self):
635 Returns tokens from DEFINED_PHASES metadata if it is defined,
636 otherwise returns a tuple containing all possible phases. This
637 makes it easy to do containment checks to see if it's safe to
638 skip execution of a given phase.
640 s = self['DEFINED_PHASES']