1 # Copyright 1999-2010 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._metadata_exception(k, e)
120 for k in self._use_conditional_misc_keys:
121 v = self.metadata.get(k)
125 use_reduce(v, eapi=dep_eapi, matchall=True,
126 is_valid_flag=dep_valid_flag)
127 except InvalidDependString as e:
128 self._metadata_exception(k, e)
131 v = self.metadata.get(k)
133 if not eapi_has_required_use(eapi):
134 self._invalid_metadata('EAPI.incompatible',
135 "REQUIRED_USE set, but EAPI='%s' doesn't allow it" % eapi)
138 check_required_use(v, (),
139 self.iuse.is_valid_flag)
140 except InvalidDependString as e:
141 # Force unicode format string for python-2.x safety,
142 # ensuring that PortageException.__unicode__() is used
144 self._invalid_metadata(k + ".syntax",
145 _unicode_decode("%s: %s") % (k, e))
148 v = self.metadata.get(k)
151 use_reduce(v, is_src_uri=True, eapi=eapi, matchall=True,
152 is_valid_flag=self.iuse.is_valid_flag)
153 except InvalidDependString as e:
154 if not self.installed:
155 self._metadata_exception(k, e)
158 return Package(built=self.built, cpv=self.cpv, depth=self.depth,
159 installed=self.installed, metadata=self._raw_metadata,
160 onlydeps=self.onlydeps, operation=self.operation,
161 root_config=self.root_config, type_name=self.type_name)
165 settings = self.root_config.settings
167 if self.invalid is not None:
168 masks['invalid'] = self.invalid
170 if not settings._accept_chost(self.cpv, self.metadata):
171 masks['CHOST'] = self.metadata['CHOST']
173 eapi = self.metadata["EAPI"]
174 if not portage.eapi_is_supported(eapi):
175 masks['EAPI.unsupported'] = eapi
176 if portage._eapi_is_deprecated(eapi):
177 masks['EAPI.deprecated'] = eapi
179 missing_keywords = settings._getMissingKeywords(
180 self.cpv, self.metadata)
182 masks['KEYWORDS'] = missing_keywords
185 missing_properties = settings._getMissingProperties(
186 self.cpv, self.metadata)
187 if missing_properties:
188 masks['PROPERTIES'] = missing_properties
189 except InvalidDependString:
190 # already recorded as 'invalid'
193 mask_atom = settings._getMaskAtom(self.cpv, self.metadata)
194 if mask_atom is not None:
195 masks['package.mask'] = mask_atom
197 system_mask = settings._getProfileMaskAtom(
198 self.cpv, self.metadata)
199 if system_mask is not None:
200 masks['profile.system'] = system_mask
203 missing_licenses = settings._getMissingLicenses(
204 self.cpv, self.metadata)
206 masks['LICENSE'] = missing_licenses
207 except InvalidDependString:
208 # already recorded as 'invalid'
216 def _visible(self, masks):
218 if masks is not None:
220 if 'EAPI.unsupported' in masks:
223 if 'invalid' in masks:
226 if not self.installed and ( \
227 'CHOST' in masks or \
228 'EAPI.deprecated' in masks or \
229 'KEYWORDS' in masks or \
230 'PROPERTIES' in masks):
233 if 'package.mask' in masks or \
234 'profile.system' in masks or \
240 def accepted_keyword(self):
241 """returns the keyword used from the ebuild's KEYWORDS string"""
243 keywords = set(self.metadata.get('KEYWORDS').split())
244 accept_keywords = set(self.root_config.settings['ACCEPT_KEYWORDS'].split())
245 used_keyword = list(set.intersection(keywords, accept_keywords))
246 if used_keyword and len(used_keyword) == 1:
247 used_keyword = used_keyword[0]
248 elif len(used_keyword) > 1:
249 # you can raise an error here if you prefer, remove it, or set the correct levels
250 writemsg_level( "_emerge.output.resolver.Display(), too many keywords recieved for pkg: %s, %s"
251 % (pkg.cpv, used_keyword))
252 used_keyword = used_keyword[0]
255 def isHardMasked(self):
256 """returns a bool if the cpv is in the list of
257 expanded pmaskdict[cp] availble ebuilds"""
258 pmask = self.root_config.settings._getRawMaskAtom(self.cpv, self.metadata)
259 print "pmask =", pmask
260 return pmask is not None
263 def _metadata_exception(self, k, e):
265 # For unicode safety with python-2.x we need to avoid
266 # using the string format operator with a non-unicode
267 # format string, since that will result in the
268 # PortageException.__str__() method being invoked,
269 # followed by unsafe decoding that may result in a
270 # UnicodeDecodeError. Therefore, use _unicode_decode()
271 # to ensure that format strings are unicode, so that
272 # PortageException.__unicode__() is used when necessary
274 if not self.installed:
275 categorized_error = False
277 for error in e.errors:
278 if getattr(error, 'category', None) is None:
280 categorized_error = True
281 self._invalid_metadata(error.category,
282 _unicode_decode("%s: %s") % (k, error))
284 if not categorized_error:
285 self._invalid_metadata(k + ".syntax",
286 _unicode_decode("%s: %s") % (k, e))
288 # For installed packages, show the path of the file
289 # containing the invalid metadata, since the user may
290 # want to fix the deps by hand.
291 vardb = self.root_config.trees['vartree'].dbapi
292 path = vardb.getpath(self.cpv, filename=k)
293 self._invalid_metadata(k + ".syntax",
294 _unicode_decode("%s: %s in '%s'") % (k, e, path))
296 def _invalid_metadata(self, msg_type, msg):
297 if self.invalid is None:
299 msgs = self.invalid.get(msg_type)
302 self.invalid[msg_type] = msgs
306 if self.operation == "merge":
307 if self.type_name == "binary":
308 cpv_color = "PKG_BINARY_MERGE"
310 cpv_color = "PKG_MERGE"
311 elif self.operation == "uninstall":
312 cpv_color = "PKG_UNINSTALL"
314 cpv_color = "PKG_NOMERGE"
317 % (portage.output.colorize(cpv_color, self.cpv + _repo_separator + self.repo) , self.type_name)
319 if self.type_name == "installed":
321 s += " in '%s'" % self.root
322 if self.operation == "uninstall":
323 s += " scheduled for uninstall"
325 if self.operation == "merge":
326 s += " scheduled for merge"
328 s += " to '%s'" % self.root
332 if sys.hexversion < 0x3000000:
334 __unicode__ = __str__
337 return _unicode_encode(self.__unicode__(),
338 encoding=_encodings['content'])
340 class _use_class(object):
342 __slots__ = ("enabled", "_force", "_pkg", "_mask")
344 def __init__(self, pkg, use_str):
348 self.enabled = frozenset(use_str.split())
350 # Use IUSE to validate USE settings for built packages,
351 # in case the package manager that built this package
352 # failed to do that for some reason (or in case of
354 missing_iuse = pkg.iuse.get_missing_iuse(self.enabled)
356 self.enabled = self.enabled.difference(missing_iuse)
358 def _init_force_mask(self):
359 pkgsettings = self._pkg._get_pkgsettings()
360 self._force = pkgsettings.useforce
361 self._mask = pkgsettings.usemask
365 if self._force is None:
366 self._init_force_mask()
371 if self._mask is None:
372 self._init_force_mask()
377 return self.metadata['repository']
380 def repo_priority(self):
381 repo_info = self.root_config.settings.repositories.prepos.get(self.repo)
382 if repo_info is None:
384 return repo_info.priority
388 if self._use is None:
389 self.metadata._init_use()
392 def _get_pkgsettings(self):
393 pkgsettings = self.root_config.trees[
394 'porttree'].dbapi.doebuild_settings
395 pkgsettings.setcpv(self)
400 __slots__ = ("__weakref__", "all", "enabled", "disabled",
401 "tokens") + ("_iuse_implicit_match",)
403 def __init__(self, tokens, iuse_implicit_match):
404 self.tokens = tuple(tokens)
405 self._iuse_implicit_match = iuse_implicit_match
412 enabled.append(x[1:])
414 disabled.append(x[1:])
417 self.enabled = frozenset(enabled)
418 self.disabled = frozenset(disabled)
419 self.all = frozenset(chain(enabled, disabled, other))
421 def is_valid_flag(self, flags):
423 @returns: True if all flags are valid USE values which may
424 be specified in USE dependencies, False otherwise.
426 if isinstance(flags, basestring):
430 if not flag in self.all and \
431 not self._iuse_implicit_match(flag):
435 def get_missing_iuse(self, flags):
437 @returns: A list of flags missing from IUSE.
439 if isinstance(flags, basestring):
443 if not flag in self.all and \
444 not self._iuse_implicit_match(flag):
445 missing_iuse.append(flag)
448 def _get_hash_key(self):
449 hash_key = getattr(self, "_hash_key", None)
451 # For installed (and binary) packages we don't care for the repo
452 # when it comes to hashing, because there can only be one cpv.
453 # So overwrite the repo_key with type_name.
454 repo_key = self.metadata.get('repository')
455 if self.type_name != 'ebuild':
456 repo_key = self.type_name
458 (self.type_name, self.root, self.cpv, self.operation, repo_key)
459 return self._hash_key
466 This is used to generate mtimedb resume mergelist entries, so we
467 limit it to 4 items for backward compatibility.
469 return iter(self._get_hash_key()[:4])
471 def __lt__(self, other):
472 if other.cp != self.cp:
474 if portage.pkgcmp(self.pv_split, other.pv_split) < 0:
478 def __le__(self, other):
479 if other.cp != self.cp:
481 if portage.pkgcmp(self.pv_split, other.pv_split) <= 0:
485 def __gt__(self, other):
486 if other.cp != self.cp:
488 if portage.pkgcmp(self.pv_split, other.pv_split) > 0:
492 def __ge__(self, other):
493 if other.cp != self.cp:
495 if portage.pkgcmp(self.pv_split, other.pv_split) >= 0:
499 _all_metadata_keys = set(x for x in portage.auxdbkeys \
500 if not x.startswith("UNUSED_"))
501 _all_metadata_keys.update(Package.metadata_keys)
502 _all_metadata_keys = frozenset(_all_metadata_keys)
504 _PackageMetadataWrapperBase = slot_dict_class(_all_metadata_keys)
506 class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
508 Detect metadata updates and synchronize Package attributes.
511 __slots__ = ("_pkg",)
512 _wrapped_keys = frozenset(
513 ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"])
514 _use_conditional_keys = frozenset(
515 ['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
517 def __init__(self, pkg, metadata):
518 _PackageMetadataWrapperBase.__init__(self)
521 # USE is lazy, but we want it to show up in self.keys().
522 _PackageMetadataWrapperBase.__setitem__(self, 'USE', '')
524 self.update(metadata)
528 use_str = self['USE']
529 self._pkg._use = self._pkg._use_class(
533 use_str = _PackageMetadataWrapperBase.__getitem__(self, 'USE')
536 calculated_use = False
538 use_str = self._pkg._get_pkgsettings()["PORTAGE_USE"]
539 calculated_use = True
540 _PackageMetadataWrapperBase.__setitem__(self, 'USE', use_str)
541 self._pkg._use = self._pkg._use_class(
543 # Initialize these now, since USE access has just triggered
544 # setcpv, and we want to cache the result of the force/mask
545 # calculations that were done.
547 self._pkg._use._init_force_mask()
551 def __getitem__(self, k):
552 v = _PackageMetadataWrapperBase.__getitem__(self, k)
553 if k in self._use_conditional_keys:
554 if self._pkg.root_config.settings.local_config and '?' in v:
556 v = paren_enclose(use_reduce(v, uselist=self._pkg.use.enabled, \
557 is_valid_flag=self._pkg.iuse.is_valid_flag))
558 except InvalidDependString:
559 # This error should already have been registered via
560 # self._pkg._invalid_metadata().
565 elif k == 'USE' and not self._pkg.built:
567 # This is lazy because it's expensive.
572 def __setitem__(self, k, v):
573 _PackageMetadataWrapperBase.__setitem__(self, k, v)
574 if k in self._wrapped_keys:
575 getattr(self, "_set_" + k.lower())(k, v)
577 def _set_inherited(self, k, v):
578 if isinstance(v, basestring):
579 v = frozenset(v.split())
580 self._pkg.inherited = v
582 def _set_iuse(self, k, v):
583 self._pkg.iuse = self._pkg._iuse(
584 v.split(), self._pkg.root_config.settings._iuse_implicit_match)
586 def _set_slot(self, k, v):
589 def _set_counter(self, k, v):
590 if isinstance(v, basestring):
595 self._pkg.counter = v
597 def _set_use(self, k, v):
598 # Force regeneration of _use attribute
599 self._pkg._use = None
600 # Use raw metadata to restore USE conditional values
601 # to unevaluated state
602 raw_metadata = self._pkg._raw_metadata
603 for x in self._use_conditional_keys:
605 self[x] = raw_metadata[x]
609 def _set__mtime_(self, k, v):
610 if isinstance(v, basestring):
618 def properties(self):
619 return self['PROPERTIES'].split()
623 return self['RESTRICT'].split()
626 def defined_phases(self):
628 Returns tokens from DEFINED_PHASES metadata if it is defined,
629 otherwise returns a tuple containing all possible phases. This
630 makes it easy to do containment checks to see if it's safe to
631 skip execution of a given phase.
633 s = self['DEFINED_PHASES']