1 # Copyright 1999-2009 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
7 from itertools import chain
9 from portage.cache.mappings import slot_dict_class
10 from portage.dep import isvalidatom, paren_reduce, use_reduce, \
11 paren_normalize, paren_enclose, _slot_re
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",) + \
30 "BUILD_TIME", "CHOST", "COUNTER", "DEPEND", "EAPI",
31 "INHERITED", "IUSE", "KEYWORDS",
32 "LICENSE", "PDEPEND", "PROVIDE", "RDEPEND",
33 "repository", "PROPERTIES", "RESTRICT", "SLOT", "USE", "_mtime_"]
35 def __init__(self, **kwargs):
36 Task.__init__(self, **kwargs)
37 self.root = self.root_config.root
38 self.metadata = _PackageMetadataWrapper(self, self.metadata)
40 self.metadata['CHOST'] = self.root_config.settings.get('CHOST', '')
41 self.cp = portage.cpv_getkey(self.cpv)
43 if _slot_re.match(slot) is None:
44 self._invalid_metadata('SLOT.invalid',
45 "SLOT: invalid value: '%s'" % slot)
46 # Avoid an InvalidAtom exception when creating slot_atom.
47 # This package instance will be masked due to empty SLOT.
49 self.slot_atom = portage.dep.Atom("%s:%s" % (self.cp, slot))
50 self.category, self.pf = portage.catsplit(self.cpv)
51 self.cpv_split = portage.catpkgsplit(self.cpv)
52 self.pv_split = self.cpv_split[1:]
53 self.masks = self._masks()
54 self.visible = self._visible(self.masks)
58 settings = self.root_config.settings
60 if self.invalid is not None:
61 masks['invalid'] = self.invalid
63 if not settings._accept_chost(self.cpv, self.metadata):
64 masks['CHOST'] = self.metadata['CHOST']
66 eapi = self.metadata["EAPI"]
67 if not portage.eapi_is_supported(eapi):
68 masks['EAPI.unsupported'] = eapi
69 if portage._eapi_is_deprecated(eapi):
70 masks['EAPI.deprecated'] = eapi
72 missing_keywords = settings._getMissingKeywords(
73 self.cpv, self.metadata)
75 masks['KEYWORDS'] = missing_keywords
78 missing_properties = settings._getMissingProperties(
79 self.cpv, self.metadata)
80 if missing_properties:
81 masks['PROPERTIES'] = missing_properties
82 except portage.exception.InvalidDependString:
83 # already recorded as 'invalid'
86 mask_atom = settings._getMaskAtom(self.cpv, self.metadata)
87 if mask_atom is not None:
88 masks['package.mask'] = mask_atom
90 system_mask = settings._getProfileMaskAtom(
91 self.cpv, self.metadata)
92 if system_mask is not None:
93 masks['profile.system'] = system_mask
96 missing_licenses = settings._getMissingLicenses(
97 self.cpv, self.metadata)
99 masks['LICENSE'] = missing_licenses
100 except portage.exception.InvalidDependString:
101 # already recorded as 'invalid'
109 def _visible(self, masks):
111 if masks is not None:
113 if 'EAPI.unsupported' in masks:
116 if not self.installed and ( \
117 'invalid' in masks or \
118 'CHOST' in masks or \
119 'EAPI.deprecated' in masks or \
120 'KEYWORDS' in masks or \
121 'PROPERTIES' in masks):
124 if 'package.mask' in masks or \
125 'profile.system' in masks or \
131 def _invalid_metadata(self, msg_type, msg):
132 if self.invalid is None:
134 msgs = self.invalid.get(msg_type)
137 self.invalid[msg_type] = msgs
140 class _use_class(object):
142 __slots__ = ("__weakref__", "enabled")
144 def __init__(self, use):
145 self.enabled = frozenset(use)
149 if self._use is None:
150 self._use = self._use_class(self.metadata['USE'].split())
155 __slots__ = ("__weakref__", "all", "enabled", "disabled",
156 "iuse_implicit", "tokens") + \
159 def __init__(self, tokens, iuse_implicit):
160 self.tokens = tuple(tokens)
161 self.iuse_implicit = iuse_implicit
168 enabled.append(x[1:])
170 disabled.append(x[1:])
173 self.enabled = frozenset(enabled)
174 self.disabled = frozenset(disabled)
175 self.all = frozenset(chain(enabled, disabled, other))
180 @returns: A regular expression that matches valid USE values which
181 may be specified in USE dependencies.
185 except AttributeError:
186 # Escape anything except ".*" which is supposed
187 # to pass through from _get_implicit_iuse()
188 regex = (re.escape(x) for x in \
189 chain(self.all, self.iuse_implicit))
190 regex = "^(%s)$" % "|".join(regex)
191 regex = re.compile(regex.replace("\\.\\*", ".*"))
195 def _get_hash_key(self):
196 hash_key = getattr(self, "_hash_key", None)
198 if self.operation is None:
199 self.operation = "merge"
200 if self.onlydeps or self.installed:
201 self.operation = "nomerge"
203 (self.type_name, self.root, self.cpv, self.operation)
204 return self._hash_key
206 def __lt__(self, other):
207 if other.cp != self.cp:
209 if portage.pkgcmp(self.pv_split, other.pv_split) < 0:
213 def __le__(self, other):
214 if other.cp != self.cp:
216 if portage.pkgcmp(self.pv_split, other.pv_split) <= 0:
220 def __gt__(self, other):
221 if other.cp != self.cp:
223 if portage.pkgcmp(self.pv_split, other.pv_split) > 0:
227 def __ge__(self, other):
228 if other.cp != self.cp:
230 if portage.pkgcmp(self.pv_split, other.pv_split) >= 0:
234 _all_metadata_keys = set(x for x in portage.auxdbkeys \
235 if not x.startswith("UNUSED_"))
236 _all_metadata_keys.update(Package.metadata_keys)
237 _all_metadata_keys = frozenset(_all_metadata_keys)
239 _PackageMetadataWrapperBase = slot_dict_class(_all_metadata_keys)
241 class _PackageMetadataWrapper(_PackageMetadataWrapperBase):
243 Detect metadata updates and synchronize Package attributes.
246 __slots__ = ("_pkg",)
247 _wrapped_keys = frozenset(
248 ["COUNTER", "INHERITED", "IUSE", "SLOT", "_mtime_"])
249 _use_conditional_keys = frozenset(
250 ['LICENSE', 'PROPERTIES', 'PROVIDE', 'RESTRICT',])
252 def __init__(self, pkg, metadata):
253 _PackageMetadataWrapperBase.__init__(self)
256 # USE is lazy, but we want it to show up in self.keys().
259 self.update(metadata)
261 def __getitem__(self, k):
262 v = _PackageMetadataWrapperBase.__getitem__(self, k)
263 if k in self._use_conditional_keys:
264 if self._pkg.root_config.settings.local_config and '?' in v:
266 v = paren_enclose(paren_normalize(use_reduce(
267 paren_reduce(v), uselist=self._pkg.use.enabled)))
268 except portage.exception.InvalidDependString:
269 # This error should already have been registered via
270 # self._pkg._invalid_metadata().
275 elif k == 'USE' and not self._pkg.built:
277 # This is lazy because it's expensive.
278 pkgsettings = self._pkg.root_config.trees[
279 'porttree'].dbapi.doebuild_settings
280 pkgsettings.setcpv(self._pkg)
281 v = pkgsettings["PORTAGE_USE"]
286 def __setitem__(self, k, v):
287 _PackageMetadataWrapperBase.__setitem__(self, k, v)
288 if k in self._wrapped_keys:
289 getattr(self, "_set_" + k.lower())(k, v)
290 elif k in self._use_conditional_keys:
292 reduced = use_reduce(paren_reduce(v), matchall=1)
293 except portage.exception.InvalidDependString as e:
294 self._pkg._invalid_metadata(k + ".syntax", "%s: %s" % (k, e))
296 if reduced and k == 'PROVIDE':
297 for x in portage.flatten(reduced):
298 if not isvalidatom(x):
299 self._pkg._invalid_metadata(k + ".syntax",
302 def _set_inherited(self, k, v):
303 if isinstance(v, basestring):
304 v = frozenset(v.split())
305 self._pkg.inherited = v
307 def _set_iuse(self, k, v):
308 self._pkg.iuse = self._pkg._iuse(
309 v.split(), self._pkg.root_config.iuse_implicit)
311 def _set_slot(self, k, v):
314 def _set_counter(self, k, v):
315 if isinstance(v, basestring):
320 self._pkg.counter = v
322 def _set__mtime_(self, k, v):
323 if isinstance(v, basestring):
331 def properties(self):
332 return self['PROPERTIES'].split()
336 return self['RESTRICT'].split()