1 # Copyright 1999-2010 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
6 from itertools import chain
8 from portage.cache.mappings import slot_dict_class
9 from portage.dep import isvalidatom, use_reduce, \
10 paren_enclose, _slot_re
11 from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
12 from _emerge.Task import Task
14 if sys.hexversion >= 0x3000000:
20 __hash__ = Task.__hash__
21 __slots__ = ("built", "cpv", "depth",
22 "installed", "metadata", "onlydeps", "operation",
23 "root_config", "type_name",
24 "category", "counter", "cp", "cpv_split",
25 "inherited", "invalid", "iuse", "masks", "mtime",
26 "pf", "pv_split", "root", "slot", "slot_atom", "visible",) + \
27 ("_raw_metadata", "_use",)
30 "BUILD_TIME", "CHOST", "COUNTER", "DEPEND", "EAPI",
31 "INHERITED", "IUSE", "KEYWORDS",
32 "LICENSE", "PDEPEND", "PROVIDE", "RDEPEND",
33 "repository", "PROPERTIES", "RESTRICT", "SLOT", "USE",
34 "_mtime_", "DEFINED_PHASES", "REQUIRED_USE"]
36 def __init__(self, **kwargs):
37 Task.__init__(self, **kwargs)
38 self.root = self.root_config.root
39 self._raw_metadata = _PackageMetadataWrapperBase(self.metadata)
40 self.metadata = _PackageMetadataWrapper(self, self._raw_metadata)
42 self.metadata['CHOST'] = self.root_config.settings.get('CHOST', '')
43 self.cp = portage.cpv_getkey(self.cpv)
45 if _slot_re.match(slot) is None:
46 self._invalid_metadata('SLOT.invalid',
47 "SLOT: invalid value: '%s'" % slot)
48 # Avoid an InvalidAtom exception when creating slot_atom.
49 # This package instance will be masked due to empty SLOT.
51 if (self.iuse.enabled or self.iuse.disabled) and \
52 not eapi_has_iuse_defaults(self.metadata["EAPI"]):
53 self._invalid_metadata('IUSE.invalid',
54 "IUSE contains defaults, but EAPI doesn't allow them")
55 if self.metadata.get("REQUIRED_USE") and \
56 not eapi_has_required_use(self.metadata["EAPI"]):
57 self._invalid_metadata('REQUIRED_USE.invalid',
58 "REQUIRED_USE set, but EAPI doesn't allow it")
59 self.slot_atom = portage.dep.Atom("%s:%s" % (self.cp, slot))
60 self.category, self.pf = portage.catsplit(self.cpv)
61 self.cpv_split = portage.catpkgsplit(self.cpv)
62 self.pv_split = self.cpv_split[1:]
63 self.masks = self._masks()
64 self.visible = self._visible(self.masks)
67 return Package(built=self.built, cpv=self.cpv, depth=self.depth,
68 installed=self.installed, metadata=self._raw_metadata,
69 onlydeps=self.onlydeps, operation=self.operation,
70 root_config=self.root_config, type_name=self.type_name)
74 settings = self.root_config.settings
76 if self.invalid is not None:
77 masks['invalid'] = self.invalid
79 if not settings._accept_chost(self.cpv, self.metadata):
80 masks['CHOST'] = self.metadata['CHOST']
82 eapi = self.metadata["EAPI"]
83 if not portage.eapi_is_supported(eapi):
84 masks['EAPI.unsupported'] = eapi
85 if portage._eapi_is_deprecated(eapi):
86 masks['EAPI.deprecated'] = eapi
88 missing_keywords = settings._getMissingKeywords(
89 self.cpv, self.metadata)
91 masks['KEYWORDS'] = missing_keywords
94 missing_properties = settings._getMissingProperties(
95 self.cpv, self.metadata)
96 if missing_properties:
97 masks['PROPERTIES'] = missing_properties
98 except portage.exception.InvalidDependString:
99 # already recorded as 'invalid'
102 mask_atom = settings._getMaskAtom(self.cpv, self.metadata)
103 if mask_atom is not None:
104 masks['package.mask'] = mask_atom
106 system_mask = settings._getProfileMaskAtom(
107 self.cpv, self.metadata)
108 if system_mask is not None:
109 masks['profile.system'] = system_mask
112 missing_licenses = settings._getMissingLicenses(
113 self.cpv, self.metadata)
115 masks['LICENSE'] = missing_licenses
116 except portage.exception.InvalidDependString:
117 # already recorded as 'invalid'
125 def _visible(self, masks):
127 if masks is not None:
129 if 'EAPI.unsupported' in masks:
132 if not self.installed and ( \
133 'invalid' in masks or \
134 'CHOST' in masks or \
135 'EAPI.deprecated' in masks or \
136 'KEYWORDS' in masks or \
137 'PROPERTIES' in masks):
140 if 'package.mask' in masks or \
141 'profile.system' in masks or \
147 def _invalid_metadata(self, msg_type, msg):
148 if self.invalid is None:
150 msgs = self.invalid.get(msg_type)
153 self.invalid[msg_type] = msgs
157 if self.operation is None:
158 self.operation = "merge"
159 if self.onlydeps or self.installed:
160 self.operation = "nomerge"
162 if self.operation == "merge":
163 if self.type_name == "binary":
164 cpv_color = "PKG_BINARY_MERGE"
166 cpv_color = "PKG_MERGE"
167 elif self.operation == "uninstall":
168 cpv_color = "PKG_UNINSTALL"
170 cpv_color = "PKG_NOMERGE"
173 % (portage.output.colorize(cpv_color, self.cpv) , self.type_name)
175 if self.type_name == "installed":
177 s += " in '%s'" % self.root
178 if self.operation == "uninstall":
179 s += " scheduled for uninstall"
181 if self.operation == "merge":
182 s += " scheduled for merge"
184 s += " to '%s'" % self.root
188 class _use_class(object):
190 __slots__ = ("__weakref__", "enabled")
192 def __init__(self, use):
193 self.enabled = frozenset(use)
197 if self._use is None:
198 self._use = self._use_class(self.metadata['USE'].split())
203 __slots__ = ("__weakref__", "all", "enabled", "disabled",
204 "tokens") + ("_iuse_implicit_regex",)
206 def __init__(self, tokens, iuse_implicit_regex):
207 self.tokens = tuple(tokens)
208 self._iuse_implicit_regex = iuse_implicit_regex
215 enabled.append(x[1:])
217 disabled.append(x[1:])
220 self.enabled = frozenset(enabled)
221 self.disabled = frozenset(disabled)
222 self.all = frozenset(chain(enabled, disabled, other))
224 def is_valid_flag(self, flags):
226 @returns: True if all flags are valid USE values which may
227 be specified in USE dependencies, False otherwise.
229 if isinstance(flags, basestring):
233 if not flag in self.all and \
234 self._iuse_implicit_regex.match(flag) is None:
238 def get_missing_iuse(self, flags):
240 @returns: A list of flags missing from IUSE.
242 if isinstance(flags, basestring):
246 if not flag in self.all and \
247 self._iuse_implicit_regex.match(flag) is None:
248 missing_iuse.append(flag)
251 def _get_hash_key(self):
252 hash_key = getattr(self, "_hash_key", None)
254 if self.operation is None:
255 self.operation = "merge"
256 if self.onlydeps or self.installed:
257 self.operation = "nomerge"
259 (self.type_name, self.root, self.cpv, self.operation)
260 return self._hash_key
262 def __lt__(self, other):
263 if other.cp != self.cp:
265 if portage.pkgcmp(self.pv_split, other.pv_split) < 0:
269 def __le__(self, other):
270 if other.cp != self.cp:
272 if portage.pkgcmp(self.pv_split, other.pv_split) <= 0:
276 def __gt__(self, other):
277 if other.cp != self.cp:
279 if portage.pkgcmp(self.pv_split, other.pv_split) > 0:
283 def __ge__(self, other):
284 if other.cp != self.cp:
286 if portage.pkgcmp(self.pv_split, other.pv_split) >= 0:
290 _all_metadata_keys = set(x for x in portage.auxdbkeys \
291 if not x.startswith("UNUSED_"))
292 _all_metadata_keys.update(Package.metadata_keys)
293 _all_metadata_keys = frozenset(_all_metadata_keys)
295 _PackageMetadataWrapperBase = slot_dict_class(_all_metadata_keys)
297 class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
299 Detect metadata updates and synchronize Package attributes.
302 __slots__ = ("_pkg",)
303 _wrapped_keys = frozenset(
304 ["COUNTER", "INHERITED", "IUSE", "SLOT", "USE", "_mtime_"])
305 _use_conditional_keys = frozenset(
306 ['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
308 def __init__(self, pkg, metadata):
309 _PackageMetadataWrapperBase.__init__(self)
312 # USE is lazy, but we want it to show up in self.keys().
313 _PackageMetadataWrapperBase.__setitem__(self, 'USE', '')
315 self.update(metadata)
317 def __getitem__(self, k):
318 v = _PackageMetadataWrapperBase.__getitem__(self, k)
319 if k in self._use_conditional_keys:
320 if self._pkg.root_config.settings.local_config and '?' in v:
322 v = paren_enclose(use_reduce(v, uselist=self._pkg.use.enabled, \
323 is_valid_flag=self._pkg.iuse.is_valid_flag))
324 except portage.exception.InvalidDependString:
325 # This error should already have been registered via
326 # self._pkg._invalid_metadata().
331 elif k == 'USE' and not self._pkg.built:
333 # This is lazy because it's expensive.
334 pkgsettings = self._pkg.root_config.trees[
335 'porttree'].dbapi.doebuild_settings
336 pkgsettings.setcpv(self._pkg)
337 v = pkgsettings["PORTAGE_USE"]
338 _PackageMetadataWrapperBase.__setitem__(self, 'USE', v)
342 def __setitem__(self, k, v):
343 _PackageMetadataWrapperBase.__setitem__(self, k, v)
344 if k in self._wrapped_keys:
345 getattr(self, "_set_" + k.lower())(k, v)
346 elif k in self._use_conditional_keys:
348 reduced = use_reduce(v, matchall=1, flat=True)
349 except portage.exception.InvalidDependString as e:
350 self._pkg._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))
352 if reduced and k == 'PROVIDE':
354 if not isvalidatom(x):
355 self._pkg._invalid_metadata(k + ".syntax",
358 def _set_inherited(self, k, v):
359 if isinstance(v, basestring):
360 v = frozenset(v.split())
361 self._pkg.inherited = v
363 def _set_iuse(self, k, v):
364 self._pkg.iuse = self._pkg._iuse(
365 v.split(), self._pkg.root_config.settings._iuse_implicit_re)
367 def _set_slot(self, k, v):
370 def _set_counter(self, k, v):
371 if isinstance(v, basestring):
376 self._pkg.counter = v
378 def _set_use(self, k, v):
379 # Force regeneration of _use attribute
380 self._pkg._use = None
381 # Use raw metadata to restore USE conditional values
382 # to unevaluated state
383 raw_metadata = self._pkg._raw_metadata
384 for x in self._use_conditional_keys:
386 self[x] = raw_metadata[x]
390 def _set__mtime_(self, k, v):
391 if isinstance(v, basestring):
399 def properties(self):
400 return self['PROPERTIES'].split()
404 return self['RESTRICT'].split()
407 def defined_phases(self):
408 return self['DEFINED_PHASES'].split()