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')
41 UNKNOWN_REPO = "__unknown__"
43 def __init__(self, **kwargs):
44 Task.__init__(self, **kwargs)
45 # the SlotObject constructor assigns self.root_config from keyword args
46 # and is an instance of a '_emerge.RootConfig.RootConfig class
47 self.root = self.root_config.root
48 self._raw_metadata = _PackageMetadataWrapperBase(self.metadata)
49 self.metadata = _PackageMetadataWrapper(self, self._raw_metadata)
51 self.metadata['CHOST'] = self.root_config.settings.get('CHOST', '')
52 self.cp = portage.cpv_getkey(self.cpv)
54 if _slot_re.match(slot) is None:
55 self._invalid_metadata('SLOT.invalid',
56 "SLOT: invalid value: '%s'" % slot)
57 # Avoid an InvalidAtom exception when creating slot_atom.
58 # This package instance will be masked due to empty SLOT.
60 if (self.iuse.enabled or self.iuse.disabled) and \
61 not eapi_has_iuse_defaults(self.metadata["EAPI"]):
62 if not self.installed:
63 self._invalid_metadata('EAPI.incompatible',
64 "IUSE contains defaults, but EAPI doesn't allow them")
65 self.slot_atom = portage.dep.Atom("%s%s%s" % (self.cp, _slot_separator, slot))
66 self.category, self.pf = portage.catsplit(self.cpv)
67 self.cpv_split = portage.catpkgsplit(self.cpv)
68 self.pv_split = self.cpv_split[1:]
69 if self.inherited is None:
70 self.inherited = frozenset()
71 repo = _gen_valid_repo(self.metadata.get('repository', ''))
73 repo = self.UNKNOWN_REPO
74 self.metadata['repository'] = repo
77 self.masks = self._masks()
78 self.visible = self._visible(self.masks)
79 if self.operation is None:
80 if self.onlydeps or self.installed:
81 self.operation = "nomerge"
83 self.operation = "merge"
85 self._hash_key = Package._gen_hash_key(cpv=self.cpv,
86 installed=self.installed, onlydeps=self.onlydeps,
87 operation=self.operation, repo_name=repo,
88 root_config=self.root_config,
89 type_name=self.type_name)
90 self._hash_value = hash(self._hash_key)
93 def _gen_hash_key(cls, cpv=None, installed=None, onlydeps=None,
94 operation=None, repo_name=None, root_config=None,
95 type_name=None, **kwargs):
98 if installed or onlydeps:
104 if root_config is not None:
105 root = root_config.root
107 raise TypeError("root_config argument is required")
109 # For installed (and binary) packages we don't care for the repo
110 # when it comes to hashing, because there can only be one cpv.
111 # So overwrite the repo_key with type_name.
112 if type_name is None:
113 raise TypeError("type_name argument is required")
114 elif type_name == "ebuild":
115 if repo_name is None:
116 raise AssertionError(
117 "Package._gen_hash_key() " + \
118 "called without 'repo_name' argument")
121 # For installed (and binary) packages we don't care for the repo
122 # when it comes to hashing, because there can only be one cpv.
123 # So overwrite the repo_key with type_name.
126 return (type_name, root, cpv, operation, repo_key)
128 def _validate_deps(self):
130 Validate deps. This does not trigger USE calculation since that
131 is expensive for ebuilds and therefore we want to avoid doing
132 in unnecessarily (like for masked packages).
134 eapi = self.metadata['EAPI']
136 dep_valid_flag = self.iuse.is_valid_flag
138 # Ignore EAPI.incompatible and conditionals missing
139 # from IUSE for installed packages since these issues
140 # aren't relevant now (re-evaluate when new EAPIs are
143 dep_valid_flag = None
145 for k in self._dep_keys:
146 v = self.metadata.get(k)
150 use_reduce(v, eapi=dep_eapi, matchall=True,
151 is_valid_flag=dep_valid_flag, token_class=Atom)
152 except InvalidDependString as e:
153 self._metadata_exception(k, e)
156 v = self.metadata.get(k)
159 use_reduce(v, eapi=dep_eapi, matchall=True,
160 is_valid_flag=dep_valid_flag, token_class=Atom)
161 except InvalidDependString as e:
162 self._invalid_metadata("PROVIDE.syntax",
163 _unicode_decode("%s: %s") % (k, e))
165 for k in self._use_conditional_misc_keys:
166 v = self.metadata.get(k)
170 use_reduce(v, eapi=dep_eapi, matchall=True,
171 is_valid_flag=dep_valid_flag)
172 except InvalidDependString as e:
173 self._metadata_exception(k, e)
176 v = self.metadata.get(k)
178 if not eapi_has_required_use(eapi):
179 self._invalid_metadata('EAPI.incompatible',
180 "REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
183 check_required_use(v, (),
184 self.iuse.is_valid_flag)
185 except InvalidDependString as e:
186 # Force unicode format string for python-2.x safety,
187 # ensuring that PortageException.__unicode__() is used
189 self._invalid_metadata(k + ".syntax",
190 _unicode_decode("%s: %s") % (k, e))
193 v = self.metadata.get(k)
196 use_reduce(v, is_src_uri=True, eapi=eapi, matchall=True,
197 is_valid_flag=self.iuse.is_valid_flag)
198 except InvalidDependString as e:
199 if not self.installed:
200 self._metadata_exception(k, e)
203 return Package(built=self.built, cpv=self.cpv, depth=self.depth,
204 installed=self.installed, metadata=self._raw_metadata,
205 onlydeps=self.onlydeps, operation=self.operation,
206 root_config=self.root_config, type_name=self.type_name)
210 settings = self.root_config.settings
212 if self.invalid is not None:
213 masks['invalid'] = self.invalid
215 if not settings._accept_chost(self.cpv, self.metadata):
216 masks['CHOST'] = self.metadata['CHOST']
218 eapi = self.metadata["EAPI"]
219 if not portage.eapi_is_supported(eapi):
220 masks['EAPI.unsupported'] = eapi
221 if portage._eapi_is_deprecated(eapi):
222 masks['EAPI.deprecated'] = eapi
224 missing_keywords = settings._getMissingKeywords(
225 self.cpv, self.metadata)
227 masks['KEYWORDS'] = missing_keywords
230 missing_properties = settings._getMissingProperties(
231 self.cpv, self.metadata)
232 if missing_properties:
233 masks['PROPERTIES'] = missing_properties
234 except InvalidDependString:
235 # already recorded as 'invalid'
238 mask_atom = settings._getMaskAtom(self.cpv, self.metadata)
239 if mask_atom is not None:
240 masks['package.mask'] = mask_atom
242 system_mask = settings._getProfileMaskAtom(
243 self.cpv, self.metadata)
244 if system_mask is not None:
245 masks['profile.system'] = system_mask
248 missing_licenses = settings._getMissingLicenses(
249 self.cpv, self.metadata)
251 masks['LICENSE'] = missing_licenses
252 except InvalidDependString:
253 # already recorded as 'invalid'
261 def _visible(self, masks):
263 if masks is not None:
265 if 'EAPI.unsupported' in masks:
268 if 'invalid' in masks:
271 if not self.installed and ( \
272 'CHOST' in masks or \
273 'EAPI.deprecated' in masks or \
274 'KEYWORDS' in masks or \
275 'PROPERTIES' in masks):
278 if 'package.mask' in masks or \
279 'profile.system' in masks or \
285 def get_keyword_mask(self):
286 """returns None, 'missing', or 'unstable'."""
288 missing = self.root_config.settings._getRawMissingKeywords(
289 self.cpv, self.metadata)
297 global_accept_keywords = frozenset(
298 self.root_config.settings.get("ACCEPT_KEYWORDS", "").split())
300 for keyword in missing:
301 if keyword.lstrip("~") in global_accept_keywords:
306 def isHardMasked(self):
307 """returns a bool if the cpv is in the list of
308 expanded pmaskdict[cp] available ebuilds"""
309 pmask = self.root_config.settings._getRawMaskAtom(
310 self.cpv, self.metadata)
311 return pmask is not None
313 def _metadata_exception(self, k, e):
315 # For unicode safety with python-2.x we need to avoid
316 # using the string format operator with a non-unicode
317 # format string, since that will result in the
318 # PortageException.__str__() method being invoked,
319 # followed by unsafe decoding that may result in a
320 # UnicodeDecodeError. Therefore, use _unicode_decode()
321 # to ensure that format strings are unicode, so that
322 # PortageException.__unicode__() is used when necessary
324 if not self.installed:
325 categorized_error = False
327 for error in e.errors:
328 if getattr(error, 'category', None) is None:
330 categorized_error = True
331 self._invalid_metadata(error.category,
332 _unicode_decode("%s: %s") % (k, error))
334 if not categorized_error:
335 self._invalid_metadata(k + ".syntax",
336 _unicode_decode("%s: %s") % (k, e))
338 # For installed packages, show the path of the file
339 # containing the invalid metadata, since the user may
340 # want to fix the deps by hand.
341 vardb = self.root_config.trees['vartree'].dbapi
342 path = vardb.getpath(self.cpv, filename=k)
343 self._invalid_metadata(k + ".syntax",
344 _unicode_decode("%s: %s in '%s'") % (k, e, path))
346 def _invalid_metadata(self, msg_type, msg):
347 if self.invalid is None:
349 msgs = self.invalid.get(msg_type)
352 self.invalid[msg_type] = msgs
356 if self.operation == "merge":
357 if self.type_name == "binary":
358 cpv_color = "PKG_BINARY_MERGE"
360 cpv_color = "PKG_MERGE"
361 elif self.operation == "uninstall":
362 cpv_color = "PKG_UNINSTALL"
364 cpv_color = "PKG_NOMERGE"
367 % (portage.output.colorize(cpv_color, self.cpv + _repo_separator + self.repo) , self.type_name)
369 if self.type_name == "installed":
371 s += " in '%s'" % self.root
372 if self.operation == "uninstall":
373 s += " scheduled for uninstall"
375 if self.operation == "merge":
376 s += " scheduled for merge"
378 s += " to '%s'" % self.root
382 if sys.hexversion < 0x3000000:
384 __unicode__ = __str__
387 return _unicode_encode(self.__unicode__(),
388 encoding=_encodings['content'])
390 class _use_class(object):
392 __slots__ = ("enabled", "_force", "_pkg", "_mask")
394 def __init__(self, pkg, use_str):
398 self.enabled = frozenset(use_str.split())
400 # Use IUSE to validate USE settings for built packages,
401 # in case the package manager that built this package
402 # failed to do that for some reason (or in case of
404 missing_iuse = pkg.iuse.get_missing_iuse(self.enabled)
406 self.enabled = self.enabled.difference(missing_iuse)
408 def _init_force_mask(self):
409 pkgsettings = self._pkg._get_pkgsettings()
410 self._force = pkgsettings.useforce
411 self._mask = pkgsettings.usemask
415 if self._force is None:
416 self._init_force_mask()
421 if self._mask is None:
422 self._init_force_mask()
427 return self.metadata['repository']
430 def repo_priority(self):
431 repo_info = self.root_config.settings.repositories.prepos.get(self.repo)
432 if repo_info is None:
434 return repo_info.priority
438 if self._use is None:
439 self.metadata._init_use()
442 def _get_pkgsettings(self):
443 pkgsettings = self.root_config.trees[
444 'porttree'].dbapi.doebuild_settings
445 pkgsettings.setcpv(self)
450 __slots__ = ("__weakref__", "all", "enabled", "disabled",
451 "tokens") + ("_iuse_implicit_match",)
453 def __init__(self, tokens, iuse_implicit_match):
454 self.tokens = tuple(tokens)
455 self._iuse_implicit_match = iuse_implicit_match
462 enabled.append(x[1:])
464 disabled.append(x[1:])
467 self.enabled = frozenset(enabled)
468 self.disabled = frozenset(disabled)
469 self.all = frozenset(chain(enabled, disabled, other))
471 def is_valid_flag(self, flags):
473 @returns: True if all flags are valid USE values which may
474 be specified in USE dependencies, False otherwise.
476 if isinstance(flags, basestring):
480 if not flag in self.all and \
481 not self._iuse_implicit_match(flag):
485 def get_missing_iuse(self, flags):
487 @returns: A list of flags missing from IUSE.
489 if isinstance(flags, basestring):
493 if not flag in self.all and \
494 not self._iuse_implicit_match(flag):
495 missing_iuse.append(flag)
503 This is used to generate mtimedb resume mergelist entries, so we
504 limit it to 4 items for backward compatibility.
506 return iter(self._hash_key[:4])
508 def __lt__(self, other):
509 if other.cp != self.cp:
511 if portage.pkgcmp(self.pv_split, other.pv_split) < 0:
515 def __le__(self, other):
516 if other.cp != self.cp:
518 if portage.pkgcmp(self.pv_split, other.pv_split) <= 0:
522 def __gt__(self, other):
523 if other.cp != self.cp:
525 if portage.pkgcmp(self.pv_split, other.pv_split) > 0:
529 def __ge__(self, other):
530 if other.cp != self.cp:
532 if portage.pkgcmp(self.pv_split, other.pv_split) >= 0:
536 _all_metadata_keys = set(x for x in portage.auxdbkeys \
537 if not x.startswith("UNUSED_"))
538 _all_metadata_keys.update(Package.metadata_keys)
539 _all_metadata_keys = frozenset(_all_metadata_keys)
541 _PackageMetadataWrapperBase = slot_dict_class(_all_metadata_keys)
543 class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
545 Detect metadata updates and synchronize Package attributes.
548 __slots__ = ("_pkg",)
549 _wrapped_keys = frozenset(
550 ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"])
551 _use_conditional_keys = frozenset(
552 ['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
554 def __init__(self, pkg, metadata):
555 _PackageMetadataWrapperBase.__init__(self)
558 # USE is lazy, but we want it to show up in self.keys().
559 _PackageMetadataWrapperBase.__setitem__(self, 'USE', '')
561 self.update(metadata)
565 use_str = self['USE']
566 self._pkg._use = self._pkg._use_class(
570 use_str = _PackageMetadataWrapperBase.__getitem__(self, 'USE')
573 calculated_use = False
575 use_str = self._pkg._get_pkgsettings()["PORTAGE_USE"]
576 calculated_use = True
577 _PackageMetadataWrapperBase.__setitem__(self, 'USE', use_str)
578 self._pkg._use = self._pkg._use_class(
580 # Initialize these now, since USE access has just triggered
581 # setcpv, and we want to cache the result of the force/mask
582 # calculations that were done.
584 self._pkg._use._init_force_mask()
588 def __getitem__(self, k):
589 v = _PackageMetadataWrapperBase.__getitem__(self, k)
590 if k in self._use_conditional_keys:
591 if self._pkg.root_config.settings.local_config and '?' in v:
593 v = paren_enclose(use_reduce(v, uselist=self._pkg.use.enabled, \
594 is_valid_flag=self._pkg.iuse.is_valid_flag))
595 except InvalidDependString:
596 # This error should already have been registered via
597 # self._pkg._invalid_metadata().
602 elif k == 'USE' and not self._pkg.built:
604 # This is lazy because it's expensive.
609 def __setitem__(self, k, v):
610 _PackageMetadataWrapperBase.__setitem__(self, k, v)
611 if k in self._wrapped_keys:
612 getattr(self, "_set_" + k.lower())(k, v)
614 def _set_inherited(self, k, v):
615 if isinstance(v, basestring):
616 v = frozenset(v.split())
617 self._pkg.inherited = v
619 def _set_iuse(self, k, v):
620 self._pkg.iuse = self._pkg._iuse(
621 v.split(), self._pkg.root_config.settings._iuse_implicit_match)
623 def _set_slot(self, k, v):
626 def _set_counter(self, k, v):
627 if isinstance(v, basestring):
632 self._pkg.counter = v
634 def _set_use(self, k, v):
635 # Force regeneration of _use attribute
636 self._pkg._use = None
637 # Use raw metadata to restore USE conditional values
638 # to unevaluated state
639 raw_metadata = self._pkg._raw_metadata
640 for x in self._use_conditional_keys:
642 self[x] = raw_metadata[x]
646 def _set__mtime_(self, k, v):
647 if isinstance(v, basestring):
655 def properties(self):
656 return self['PROPERTIES'].split()
660 return self['RESTRICT'].split()
663 def defined_phases(self):
665 Returns tokens from DEFINED_PHASES metadata if it is defined,
666 otherwise returns a tuple containing all possible phases. This
667 makes it easy to do containment checks to see if it's safe to
668 skip execution of a given phase.
670 s = self['DEFINED_PHASES']