1 |
Author: zmedico |
2 |
Date: 2010-02-25 20:48:08 +0000 (Thu, 25 Feb 2010) |
3 |
New Revision: 15461 |
4 |
|
5 |
Added: |
6 |
main/trunk/pym/portage/dep/ |
7 |
main/trunk/pym/portage/dep/__init__.py |
8 |
Removed: |
9 |
main/trunk/pym/portage/dep.py |
10 |
Log: |
11 |
Move dep.py to dep/__init__.py, for splitting into smaller files. |
12 |
|
13 |
|
14 |
Copied: main/trunk/pym/portage/dep/__init__.py (from rev 15457, main/trunk/pym/portage/dep.py) |
15 |
=================================================================== |
16 |
--- main/trunk/pym/portage/dep/__init__.py (rev 0) |
17 |
+++ main/trunk/pym/portage/dep/__init__.py 2010-02-25 20:48:08 UTC (rev 15461) |
18 |
@@ -0,0 +1,1203 @@ |
19 |
+# deps.py -- Portage dependency resolution functions |
20 |
+# Copyright 2003-2004 Gentoo Foundation |
21 |
+# Distributed under the terms of the GNU General Public License v2 |
22 |
+# $Id$ |
23 |
+ |
24 |
+__all__ = [ |
25 |
+ 'Atom', 'best_match_to_list', 'cpvequal', |
26 |
+ 'dep_getcpv', 'dep_getkey', 'dep_getslot', |
27 |
+ 'dep_getusedeps', 'dep_opconvert', 'flatten', |
28 |
+ 'get_operator', 'isjustname', 'isspecific', |
29 |
+ 'isvalidatom', 'match_from_list', 'match_to_list', |
30 |
+ 'paren_enclose', 'paren_normalize', 'paren_reduce', |
31 |
+ 'remove_slot', 'strip_empty', 'use_reduce' |
32 |
+] |
33 |
+ |
34 |
+# DEPEND SYNTAX: |
35 |
+# |
36 |
+# 'use?' only affects the immediately following word! |
37 |
+# Nesting is the only legal way to form multiple '[!]use?' requirements. |
38 |
+# |
39 |
+# Where: 'a' and 'b' are use flags, and 'z' is a depend atom. |
40 |
+# |
41 |
+# "a? z" -- If 'a' in [use], then b is valid. |
42 |
+# "a? ( z )" -- Syntax with parenthesis. |
43 |
+# "a? b? z" -- Deprecated. |
44 |
+# "a? ( b? z )" -- Valid |
45 |
+# "a? ( b? ( z ) ) -- Valid |
46 |
+# |
47 |
+ |
48 |
+import re, sys |
49 |
+import warnings |
50 |
+from itertools import chain |
51 |
+import portage.exception |
52 |
+from portage.exception import InvalidData, InvalidAtom |
53 |
+from portage.localization import _ |
54 |
+from portage.versions import catpkgsplit, catsplit, \ |
55 |
+ pkgcmp, pkgsplit, ververify, _cp, _cpv |
56 |
+import portage.cache.mappings |
57 |
+ |
58 |
+if sys.hexversion >= 0x3000000: |
59 |
+ basestring = str |
60 |
+ |
61 |
+def cpvequal(cpv1, cpv2): |
62 |
+ """ |
63 |
+ |
64 |
+ @param cpv1: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1" |
65 |
+ @type cpv1: String |
66 |
+ @param cpv2: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1" |
67 |
+ @type cpv2: String |
68 |
+ @rtype: Boolean |
69 |
+ @returns: |
70 |
+ 1. True if cpv1 = cpv2 |
71 |
+ 2. False Otherwise |
72 |
+ 3. Throws PortageException if cpv1 or cpv2 is not a CPV |
73 |
+ |
74 |
+ Example Usage: |
75 |
+ >>> from portage.dep import cpvequal |
76 |
+ >>> cpvequal("sys-apps/portage-2.1","sys-apps/portage-2.1") |
77 |
+ >>> True |
78 |
+ |
79 |
+ """ |
80 |
+ |
81 |
+ split1 = catpkgsplit(cpv1) |
82 |
+ split2 = catpkgsplit(cpv2) |
83 |
+ |
84 |
+ if not split1 or not split2: |
85 |
+ raise portage.exception.PortageException(_("Invalid data '%s, %s', parameter was not a CPV") % (cpv1, cpv2)) |
86 |
+ |
87 |
+ if split1[0] != split2[0]: |
88 |
+ return False |
89 |
+ |
90 |
+ return (pkgcmp(split1[1:], split2[1:]) == 0) |
91 |
+ |
92 |
+def strip_empty(myarr): |
93 |
+ """ |
94 |
+ Strip all empty elements from an array |
95 |
+ |
96 |
+ @param myarr: The list of elements |
97 |
+ @type myarr: List |
98 |
+ @rtype: Array |
99 |
+ @return: The array with empty elements removed |
100 |
+ """ |
101 |
+ return [x for x in myarr if x] |
102 |
+ |
103 |
+_paren_whitespace_re = re.compile(r'\S(\(|\))|(\(|\))\S') |
104 |
+ |
105 |
+def paren_reduce(mystr,tokenize=1): |
106 |
+ """ |
107 |
+ Take a string and convert all paren enclosed entities into sublists, optionally |
108 |
+ futher splitting the list elements by spaces. |
109 |
+ |
110 |
+ Example usage: |
111 |
+ >>> paren_reduce('foobar foo ( bar baz )',1) |
112 |
+ ['foobar', 'foo', ['bar', 'baz']] |
113 |
+ >>> paren_reduce('foobar foo ( bar baz )',0) |
114 |
+ ['foobar foo ', [' bar baz ']] |
115 |
+ |
116 |
+ @param mystr: The string to reduce |
117 |
+ @type mystr: String |
118 |
+ @param tokenize: Split on spaces to produces further list breakdown |
119 |
+ @type tokenize: Integer |
120 |
+ @rtype: Array |
121 |
+ @return: The reduced string in an array |
122 |
+ """ |
123 |
+ global _dep_check_strict, _paren_whitespace_re |
124 |
+ if _dep_check_strict: |
125 |
+ m = _paren_whitespace_re.search(mystr) |
126 |
+ if m is not None: |
127 |
+ raise portage.exception.InvalidDependString( |
128 |
+ _("missing space by parenthesis: '%s'") % m.group(0)) |
129 |
+ mylist = [] |
130 |
+ while mystr: |
131 |
+ left_paren = mystr.find("(") |
132 |
+ has_left_paren = left_paren != -1 |
133 |
+ right_paren = mystr.find(")") |
134 |
+ has_right_paren = right_paren != -1 |
135 |
+ if not has_left_paren and not has_right_paren: |
136 |
+ freesec = mystr |
137 |
+ subsec = None |
138 |
+ tail = "" |
139 |
+ elif mystr[0] == ")": |
140 |
+ return [mylist,mystr[1:]] |
141 |
+ elif has_left_paren and not has_right_paren: |
142 |
+ raise portage.exception.InvalidDependString( |
143 |
+ _("missing right parenthesis: '%s'") % mystr) |
144 |
+ elif has_left_paren and left_paren < right_paren: |
145 |
+ freesec,subsec = mystr.split("(",1) |
146 |
+ sublist = paren_reduce(subsec, tokenize=tokenize) |
147 |
+ if len(sublist) != 2: |
148 |
+ raise portage.exception.InvalidDependString( |
149 |
+ _("malformed syntax: '%s'") % mystr) |
150 |
+ subsec, tail = sublist |
151 |
+ else: |
152 |
+ subsec,tail = mystr.split(")",1) |
153 |
+ if tokenize: |
154 |
+ subsec = strip_empty(subsec.split(" ")) |
155 |
+ return [mylist+subsec,tail] |
156 |
+ return mylist+[subsec],tail |
157 |
+ if not isinstance(tail, basestring): |
158 |
+ raise portage.exception.InvalidDependString( |
159 |
+ _("malformed syntax: '%s'") % mystr) |
160 |
+ mystr = tail |
161 |
+ if freesec: |
162 |
+ if tokenize: |
163 |
+ mylist = mylist + strip_empty(freesec.split(" ")) |
164 |
+ else: |
165 |
+ mylist = mylist + [freesec] |
166 |
+ if subsec is not None: |
167 |
+ mylist = mylist + [subsec] |
168 |
+ return mylist |
169 |
+ |
170 |
+class paren_normalize(list): |
171 |
+ """Take a dependency structure as returned by paren_reduce or use_reduce |
172 |
+ and generate an equivalent structure that has no redundant lists.""" |
173 |
+ def __init__(self, src): |
174 |
+ list.__init__(self) |
175 |
+ self._zap_parens(src, self) |
176 |
+ |
177 |
+ def _zap_parens(self, src, dest, disjunction=False): |
178 |
+ if not src: |
179 |
+ return dest |
180 |
+ i = iter(src) |
181 |
+ for x in i: |
182 |
+ if isinstance(x, basestring): |
183 |
+ if x == '||': |
184 |
+ x = self._zap_parens(next(i), [], disjunction=True) |
185 |
+ if len(x) == 1: |
186 |
+ dest.append(x[0]) |
187 |
+ else: |
188 |
+ dest.append("||") |
189 |
+ dest.append(x) |
190 |
+ elif x.endswith("?"): |
191 |
+ dest.append(x) |
192 |
+ dest.append(self._zap_parens(next(i), [])) |
193 |
+ else: |
194 |
+ dest.append(x) |
195 |
+ else: |
196 |
+ if disjunction: |
197 |
+ x = self._zap_parens(x, []) |
198 |
+ if len(x) == 1: |
199 |
+ dest.append(x[0]) |
200 |
+ else: |
201 |
+ dest.append(x) |
202 |
+ else: |
203 |
+ self._zap_parens(x, dest) |
204 |
+ return dest |
205 |
+ |
206 |
+def paren_enclose(mylist): |
207 |
+ """ |
208 |
+ Convert a list to a string with sublists enclosed with parens. |
209 |
+ |
210 |
+ Example usage: |
211 |
+ >>> test = ['foobar','foo',['bar','baz']] |
212 |
+ >>> paren_enclose(test) |
213 |
+ 'foobar foo ( bar baz )' |
214 |
+ |
215 |
+ @param mylist: The list |
216 |
+ @type mylist: List |
217 |
+ @rtype: String |
218 |
+ @return: The paren enclosed string |
219 |
+ """ |
220 |
+ mystrparts = [] |
221 |
+ for x in mylist: |
222 |
+ if isinstance(x, list): |
223 |
+ mystrparts.append("( "+paren_enclose(x)+" )") |
224 |
+ else: |
225 |
+ mystrparts.append(x) |
226 |
+ return " ".join(mystrparts) |
227 |
+ |
228 |
+# This is just for use by emerge so that it can enable a backward compatibility |
229 |
+# mode in order to gracefully deal with installed packages that have invalid |
230 |
+# atoms or dep syntax. For backward compatibility with api consumers, strict |
231 |
+# behavior will be explicitly enabled as necessary. |
232 |
+_dep_check_strict = False |
233 |
+ |
234 |
+def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]): |
235 |
+ """ |
236 |
+ Takes a paren_reduce'd array and reduces the use? conditionals out |
237 |
+ leaving an array with subarrays |
238 |
+ |
239 |
+ @param deparray: paren_reduce'd list of deps |
240 |
+ @type deparray: List |
241 |
+ @param uselist: List of use flags |
242 |
+ @type uselist: List |
243 |
+ @param masklist: List of masked flags |
244 |
+ @type masklist: List |
245 |
+ @param matchall: Resolve all conditional deps unconditionally. Used by repoman |
246 |
+ @type matchall: Integer |
247 |
+ @rtype: List |
248 |
+ @return: The use reduced depend array |
249 |
+ """ |
250 |
+ # Quick validity checks |
251 |
+ for x, y in enumerate(deparray): |
252 |
+ if y == '||': |
253 |
+ if len(deparray) - 1 == x or not isinstance(deparray[x+1], list): |
254 |
+ raise portage.exception.InvalidDependString(_('%(dep)s missing atom list in "%(deparray)s"') % {"dep": deparray[x], "deparray": paren_enclose(deparray)}) |
255 |
+ if deparray and deparray[-1] and deparray[-1][-1] == "?": |
256 |
+ raise portage.exception.InvalidDependString(_('Conditional without target in "%s"') % paren_enclose(deparray)) |
257 |
+ |
258 |
+ global _dep_check_strict |
259 |
+ |
260 |
+ mydeparray = deparray[:] |
261 |
+ rlist = [] |
262 |
+ while mydeparray: |
263 |
+ head = mydeparray.pop(0) |
264 |
+ |
265 |
+ if not isinstance(head, basestring): |
266 |
+ additions = use_reduce(head, uselist, masklist, matchall, excludeall) |
267 |
+ if additions: |
268 |
+ rlist.append(additions) |
269 |
+ elif rlist and rlist[-1] == "||": |
270 |
+ #XXX: Currently some DEPEND strings have || lists without default atoms. |
271 |
+ # raise portage.exception.InvalidDependString("No default atom(s) in \""+paren_enclose(deparray)+"\"") |
272 |
+ rlist.append([]) |
273 |
+ |
274 |
+ else: |
275 |
+ if head[-1:] == "?": # Use reduce next group on fail. |
276 |
+ # Pull any other use conditions and the following atom or list into a separate array |
277 |
+ newdeparray = [head] |
278 |
+ while isinstance(newdeparray[-1], basestring) and \ |
279 |
+ newdeparray[-1][-1:] == "?": |
280 |
+ if mydeparray: |
281 |
+ newdeparray.append(mydeparray.pop(0)) |
282 |
+ else: |
283 |
+ raise ValueError(_("Conditional with no target.")) |
284 |
+ |
285 |
+ # Deprecation checks |
286 |
+ warned = 0 |
287 |
+ if len(newdeparray[-1]) == 0: |
288 |
+ sys.stderr.write(_("Note: Empty target in string. (Deprecated)\n")) |
289 |
+ warned = 1 |
290 |
+ if len(newdeparray) != 2: |
291 |
+ sys.stderr.write(_("Note: Nested use flags without parenthesis (Deprecated)\n")) |
292 |
+ warned = 1 |
293 |
+ if warned: |
294 |
+ sys.stderr.write(" --> "+" ".join(map(str,[head]+newdeparray))+"\n") |
295 |
+ |
296 |
+ # Check that each flag matches |
297 |
+ ismatch = True |
298 |
+ missing_flag = False |
299 |
+ for head in newdeparray[:-1]: |
300 |
+ head = head[:-1] |
301 |
+ if not head: |
302 |
+ missing_flag = True |
303 |
+ break |
304 |
+ if head.startswith("!"): |
305 |
+ head_key = head[1:] |
306 |
+ if not head_key: |
307 |
+ missing_flag = True |
308 |
+ break |
309 |
+ if not matchall and head_key in uselist or \ |
310 |
+ head_key in excludeall: |
311 |
+ ismatch = False |
312 |
+ break |
313 |
+ elif head not in masklist: |
314 |
+ if not matchall and head not in uselist: |
315 |
+ ismatch = False |
316 |
+ break |
317 |
+ else: |
318 |
+ ismatch = False |
319 |
+ if missing_flag: |
320 |
+ raise portage.exception.InvalidDependString( |
321 |
+ _('Conditional without flag: "') + \ |
322 |
+ paren_enclose([head+"?", newdeparray[-1]])+"\"") |
323 |
+ |
324 |
+ # If they all match, process the target |
325 |
+ if ismatch: |
326 |
+ target = newdeparray[-1] |
327 |
+ if isinstance(target, list): |
328 |
+ additions = use_reduce(target, uselist, masklist, matchall, excludeall) |
329 |
+ if additions: |
330 |
+ rlist.append(additions) |
331 |
+ elif not _dep_check_strict: |
332 |
+ # The old deprecated behavior. |
333 |
+ rlist.append(target) |
334 |
+ else: |
335 |
+ raise portage.exception.InvalidDependString( |
336 |
+ _("Conditional without parenthesis: '%s?'") % head) |
337 |
+ |
338 |
+ else: |
339 |
+ rlist += [head] |
340 |
+ |
341 |
+ return rlist |
342 |
+ |
343 |
+def dep_opconvert(deplist): |
344 |
+ """ |
345 |
+ Iterate recursively through a list of deps, if the |
346 |
+ dep is a '||' or '&&' operator, combine it with the |
347 |
+ list of deps that follows.. |
348 |
+ |
349 |
+ Example usage: |
350 |
+ >>> test = ["blah", "||", ["foo", "bar", "baz"]] |
351 |
+ >>> dep_opconvert(test) |
352 |
+ ['blah', ['||', 'foo', 'bar', 'baz']] |
353 |
+ |
354 |
+ @param deplist: A list of deps to format |
355 |
+ @type mydep: List |
356 |
+ @rtype: List |
357 |
+ @return: |
358 |
+ The new list with the new ordering |
359 |
+ """ |
360 |
+ |
361 |
+ retlist = [] |
362 |
+ x = 0 |
363 |
+ while x != len(deplist): |
364 |
+ if isinstance(deplist[x], list): |
365 |
+ retlist.append(dep_opconvert(deplist[x])) |
366 |
+ elif deplist[x] == "||" or deplist[x] == "&&": |
367 |
+ retlist.append([deplist[x]] + dep_opconvert(deplist[x+1])) |
368 |
+ x += 1 |
369 |
+ else: |
370 |
+ retlist.append(deplist[x]) |
371 |
+ x += 1 |
372 |
+ return retlist |
373 |
+ |
374 |
+def flatten(mylist): |
375 |
+ """ |
376 |
+ Recursively traverse nested lists and return a single list containing |
377 |
+ all non-list elements that are found. |
378 |
+ |
379 |
+ Example usage: |
380 |
+ >>> flatten([1, [2, 3, [4]]]) |
381 |
+ [1, 2, 3, 4] |
382 |
+ |
383 |
+ @param mylist: A list containing nested lists and non-list elements. |
384 |
+ @type mylist: List |
385 |
+ @rtype: List |
386 |
+ @return: A single list containing only non-list elements. |
387 |
+ """ |
388 |
+ newlist = [] |
389 |
+ for x in mylist: |
390 |
+ if isinstance(x, list): |
391 |
+ newlist.extend(flatten(x)) |
392 |
+ else: |
393 |
+ newlist.append(x) |
394 |
+ return newlist |
395 |
+ |
396 |
+class _use_dep(object): |
397 |
+ |
398 |
+ __slots__ = ("__weakref__", "conditional", |
399 |
+ "disabled", "enabled", "tokens", "required") |
400 |
+ |
401 |
+ _conditionals_class = portage.cache.mappings.slot_dict_class( |
402 |
+ ("disabled", "enabled", "equal", "not_equal"), prefix="") |
403 |
+ |
404 |
+ _valid_use_re = re.compile(r'^[^-?!=][^?!=]*$') |
405 |
+ |
406 |
+ def __init__(self, use): |
407 |
+ enabled_flags = [] |
408 |
+ disabled_flags = [] |
409 |
+ conditional = self._conditionals_class() |
410 |
+ for k in conditional.allowed_keys: |
411 |
+ conditional[k] = [] |
412 |
+ |
413 |
+ for x in use: |
414 |
+ last_char = x[-1:] |
415 |
+ first_char = x[:1] |
416 |
+ |
417 |
+ if "?" == last_char: |
418 |
+ if "!" == first_char: |
419 |
+ conditional.disabled.append( |
420 |
+ self._validate_flag(x, x[1:-1])) |
421 |
+ else: |
422 |
+ conditional.enabled.append( |
423 |
+ self._validate_flag(x, x[:-1])) |
424 |
+ |
425 |
+ elif "=" == last_char: |
426 |
+ if "!" == first_char: |
427 |
+ conditional.not_equal.append( |
428 |
+ self._validate_flag(x, x[1:-1])) |
429 |
+ else: |
430 |
+ conditional.equal.append( |
431 |
+ self._validate_flag(x, x[:-1])) |
432 |
+ |
433 |
+ else: |
434 |
+ if "-" == first_char: |
435 |
+ disabled_flags.append(self._validate_flag(x, x[1:])) |
436 |
+ else: |
437 |
+ enabled_flags.append(self._validate_flag(x, x)) |
438 |
+ |
439 |
+ self.tokens = use |
440 |
+ if not isinstance(self.tokens, tuple): |
441 |
+ self.tokens = tuple(self.tokens) |
442 |
+ |
443 |
+ self.required = frozenset(chain( |
444 |
+ enabled_flags, |
445 |
+ disabled_flags, |
446 |
+ *conditional.values() |
447 |
+ )) |
448 |
+ |
449 |
+ self.enabled = frozenset(enabled_flags) |
450 |
+ self.disabled = frozenset(disabled_flags) |
451 |
+ self.conditional = None |
452 |
+ |
453 |
+ for v in conditional.values(): |
454 |
+ if v: |
455 |
+ for k, v in conditional.items(): |
456 |
+ conditional[k] = frozenset(v) |
457 |
+ self.conditional = conditional |
458 |
+ break |
459 |
+ |
460 |
+ def _validate_flag(self, token, flag): |
461 |
+ if self._valid_use_re.match(flag) is None: |
462 |
+ raise InvalidAtom(_("Invalid use dep: '%s'") % (token,)) |
463 |
+ return flag |
464 |
+ |
465 |
+ def __bool__(self): |
466 |
+ return bool(self.tokens) |
467 |
+ |
468 |
+ if sys.hexversion < 0x3000000: |
469 |
+ __nonzero__ = __bool__ |
470 |
+ |
471 |
+ def __str__(self): |
472 |
+ if not self.tokens: |
473 |
+ return "" |
474 |
+ return "[%s]" % (",".join(self.tokens),) |
475 |
+ |
476 |
+ def __repr__(self): |
477 |
+ return "portage.dep._use_dep(%s)" % repr(self.tokens) |
478 |
+ |
479 |
+ def evaluate_conditionals(self, use): |
480 |
+ """ |
481 |
+ Create a new instance with conditionals evaluated. |
482 |
+ |
483 |
+ Conditional evaluation behavior: |
484 |
+ |
485 |
+ parent state conditional result |
486 |
+ |
487 |
+ x x? x |
488 |
+ -x x? |
489 |
+ x !x? |
490 |
+ -x !x? -x |
491 |
+ |
492 |
+ x x= x |
493 |
+ -x x= -x |
494 |
+ x !x= -x |
495 |
+ -x !x= x |
496 |
+ |
497 |
+ Conditional syntax examples: |
498 |
+ |
499 |
+ Compact Form Equivalent Expanded Form |
500 |
+ |
501 |
+ foo[bar?] bar? ( foo[bar] ) !bar? ( foo ) |
502 |
+ foo[!bar?] bar? ( foo ) !bar? ( foo[-bar] ) |
503 |
+ foo[bar=] bar? ( foo[bar] ) !bar? ( foo[-bar] ) |
504 |
+ foo[!bar=] bar? ( foo[-bar] ) !bar? ( foo[bar] ) |
505 |
+ |
506 |
+ """ |
507 |
+ tokens = [] |
508 |
+ |
509 |
+ conditional = self.conditional |
510 |
+ tokens.extend(self.enabled) |
511 |
+ tokens.extend("-" + x for x in self.disabled) |
512 |
+ tokens.extend(x for x in conditional.enabled if x in use) |
513 |
+ tokens.extend("-" + x for x in conditional.disabled if x not in use) |
514 |
+ |
515 |
+ tokens.extend(x for x in conditional.equal if x in use) |
516 |
+ tokens.extend("-" + x for x in conditional.equal if x not in use) |
517 |
+ tokens.extend("-" + x for x in conditional.not_equal if x in use) |
518 |
+ tokens.extend(x for x in conditional.not_equal if x not in use) |
519 |
+ |
520 |
+ return _use_dep(tokens) |
521 |
+ |
522 |
+ def _eval_qa_conditionals(self, use_mask, use_force): |
523 |
+ """ |
524 |
+ For repoman, evaluate all possible combinations within the constraints |
525 |
+ of the given use.force and use.mask settings. The result may seem |
526 |
+ ambiguous in the sense that the same flag can be in both the enabled |
527 |
+ and disabled sets, but this is useful within the context of how its |
528 |
+ intended to be used by repoman. It is assumed that the caller has |
529 |
+ already ensured that there is no intersection between the given |
530 |
+ use_mask and use_force sets when necessary. |
531 |
+ """ |
532 |
+ tokens = [] |
533 |
+ |
534 |
+ conditional = self.conditional |
535 |
+ tokens.extend(self.enabled) |
536 |
+ tokens.extend("-" + x for x in self.disabled) |
537 |
+ tokens.extend(x for x in conditional.enabled if x not in use_mask) |
538 |
+ tokens.extend("-" + x for x in conditional.disabled if x not in use_force) |
539 |
+ |
540 |
+ tokens.extend(x for x in conditional.equal if x not in use_mask) |
541 |
+ tokens.extend("-" + x for x in conditional.equal if x not in use_force) |
542 |
+ tokens.extend("-" + x for x in conditional.not_equal if x not in use_mask) |
543 |
+ tokens.extend(x for x in conditional.not_equal if x not in use_force) |
544 |
+ |
545 |
+ return _use_dep(tokens) |
546 |
+ |
547 |
+if sys.hexversion < 0x3000000: |
548 |
+ _atom_base = unicode |
549 |
+else: |
550 |
+ _atom_base = str |
551 |
+ |
552 |
+class Atom(_atom_base): |
553 |
+ |
554 |
+ """ |
555 |
+ For compatibility with existing atom string manipulation code, this |
556 |
+ class emulates most of the str methods that are useful with atoms. |
557 |
+ """ |
558 |
+ |
559 |
+ class _blocker(object): |
560 |
+ __slots__ = ("overlap",) |
561 |
+ |
562 |
+ class _overlap(object): |
563 |
+ __slots__ = ("forbid",) |
564 |
+ |
565 |
+ def __init__(self, forbid=False): |
566 |
+ self.forbid = forbid |
567 |
+ |
568 |
+ def __init__(self, forbid_overlap=False): |
569 |
+ self.overlap = self._overlap(forbid=forbid_overlap) |
570 |
+ |
571 |
+ def __init__(self, s): |
572 |
+ if isinstance(s, Atom): |
573 |
+ # This is an efficiency assertion, to ensure that the Atom |
574 |
+ # constructor is not called redundantly. |
575 |
+ raise TypeError(_("Expected %s, got %s") % \ |
576 |
+ (_atom_base, type(s))) |
577 |
+ |
578 |
+ _atom_base.__init__(s) |
579 |
+ |
580 |
+ if "!" == s[:1]: |
581 |
+ blocker = self._blocker(forbid_overlap=("!" == s[1:2])) |
582 |
+ if blocker.overlap.forbid: |
583 |
+ s = s[2:] |
584 |
+ else: |
585 |
+ s = s[1:] |
586 |
+ else: |
587 |
+ blocker = False |
588 |
+ self.__dict__['blocker'] = blocker |
589 |
+ m = _atom_re.match(s) |
590 |
+ if m is None: |
591 |
+ raise InvalidAtom(self) |
592 |
+ |
593 |
+ if m.group('op') is not None: |
594 |
+ base = _atom_re.groupindex['op'] |
595 |
+ op = m.group(base + 1) |
596 |
+ cpv = m.group(base + 2) |
597 |
+ cp = m.group(base + 3) |
598 |
+ if m.group(base + 4) is not None: |
599 |
+ raise InvalidAtom(self) |
600 |
+ elif m.group('star') is not None: |
601 |
+ base = _atom_re.groupindex['star'] |
602 |
+ op = '=*' |
603 |
+ cpv = m.group(base + 1) |
604 |
+ cp = m.group(base + 2) |
605 |
+ if m.group(base + 3) is not None: |
606 |
+ raise InvalidAtom(self) |
607 |
+ elif m.group('simple') is not None: |
608 |
+ op = None |
609 |
+ cpv = cp = m.group(_atom_re.groupindex['simple'] + 1) |
610 |
+ if m.group(_atom_re.groupindex['simple'] + 2) is not None: |
611 |
+ raise InvalidAtom(self) |
612 |
+ else: |
613 |
+ raise AssertionError(_("required group not found in atom: '%s'") % self) |
614 |
+ self.__dict__['cp'] = cp |
615 |
+ self.__dict__['cpv'] = cpv |
616 |
+ self.__dict__['slot'] = m.group(_atom_re.groups - 1) |
617 |
+ self.__dict__['operator'] = op |
618 |
+ |
619 |
+ use_str = m.group(_atom_re.groups) |
620 |
+ if use_str is not None: |
621 |
+ use = _use_dep(dep_getusedeps(s)) |
622 |
+ without_use = Atom(m.group('without_use')) |
623 |
+ else: |
624 |
+ use = None |
625 |
+ without_use = self |
626 |
+ |
627 |
+ self.__dict__['use'] = use |
628 |
+ self.__dict__['without_use'] = without_use |
629 |
+ |
630 |
+ def __setattr__(self, name, value): |
631 |
+ raise AttributeError("Atom instances are immutable", |
632 |
+ self.__class__, name, value) |
633 |
+ |
634 |
+ def intersects(self, other): |
635 |
+ """ |
636 |
+ Atoms with different cpv, operator or use attributes cause this method |
637 |
+ to return False even though there may actually be some intersection. |
638 |
+ TODO: Detect more forms of intersection. |
639 |
+ @param other: The package atom to match |
640 |
+ @type other: Atom |
641 |
+ @rtype: Boolean |
642 |
+ @return: True if this atom and the other atom intersect, |
643 |
+ False otherwise. |
644 |
+ """ |
645 |
+ if not isinstance(other, Atom): |
646 |
+ raise TypeError("expected %s, got %s" % \ |
647 |
+ (Atom, type(other))) |
648 |
+ |
649 |
+ if self == other: |
650 |
+ return True |
651 |
+ |
652 |
+ if self.cp != other.cp or \ |
653 |
+ self.use != other.use or \ |
654 |
+ self.operator != other.operator or \ |
655 |
+ self.cpv != other.cpv: |
656 |
+ return False |
657 |
+ |
658 |
+ if self.slot is None or \ |
659 |
+ other.slot is None or \ |
660 |
+ self.slot == other.slot: |
661 |
+ return True |
662 |
+ |
663 |
+ return False |
664 |
+ |
665 |
+ def evaluate_conditionals(self, use): |
666 |
+ """ |
667 |
+ Create an atom instance with any USE conditionals evaluated. |
668 |
+ @param use: The set of enabled USE flags |
669 |
+ @type use: set |
670 |
+ @rtype: Atom |
671 |
+ @return: an atom instance with any USE conditionals evaluated |
672 |
+ """ |
673 |
+ if not (self.use and self.use.conditional): |
674 |
+ return self |
675 |
+ atom = remove_slot(self) |
676 |
+ if self.slot: |
677 |
+ atom += ":%s" % self.slot |
678 |
+ atom += str(self.use.evaluate_conditionals(use)) |
679 |
+ return Atom(atom) |
680 |
+ |
681 |
+ def __copy__(self): |
682 |
+ """Immutable, so returns self.""" |
683 |
+ return self |
684 |
+ |
685 |
+ def __deepcopy__(self, memo=None): |
686 |
+ """Immutable, so returns self.""" |
687 |
+ memo[id(self)] = self |
688 |
+ return self |
689 |
+ |
690 |
+def get_operator(mydep): |
691 |
+ """ |
692 |
+ Return the operator used in a depstring. |
693 |
+ |
694 |
+ Example usage: |
695 |
+ >>> from portage.dep import * |
696 |
+ >>> get_operator(">=test-1.0") |
697 |
+ '>=' |
698 |
+ |
699 |
+ @param mydep: The dep string to check |
700 |
+ @type mydep: String |
701 |
+ @rtype: String |
702 |
+ @return: The operator. One of: |
703 |
+ '~', '=', '>', '<', '=*', '>=', or '<=' |
704 |
+ """ |
705 |
+ if isinstance(mydep, Atom): |
706 |
+ return mydep.operator |
707 |
+ try: |
708 |
+ return Atom(mydep).operator |
709 |
+ except InvalidAtom: |
710 |
+ pass |
711 |
+ |
712 |
+ # Fall back to legacy code for backward compatibility. |
713 |
+ warnings.warn(_("%s is deprecated, use %s instead") % \ |
714 |
+ ('portage.dep.get_operator()', 'portage.dep.Atom.operator'), |
715 |
+ DeprecationWarning) |
716 |
+ operator = None |
717 |
+ if mydep: |
718 |
+ mydep = remove_slot(mydep) |
719 |
+ if not mydep: |
720 |
+ return None |
721 |
+ if mydep[0] == "~": |
722 |
+ operator = "~" |
723 |
+ elif mydep[0] == "=": |
724 |
+ if mydep[-1] == "*": |
725 |
+ operator = "=*" |
726 |
+ else: |
727 |
+ operator = "=" |
728 |
+ elif mydep[0] in "><": |
729 |
+ if len(mydep) > 1 and mydep[1] == "=": |
730 |
+ operator = mydep[0:2] |
731 |
+ else: |
732 |
+ operator = mydep[0] |
733 |
+ else: |
734 |
+ operator = None |
735 |
+ |
736 |
+ return operator |
737 |
+ |
738 |
+def dep_getcpv(mydep): |
739 |
+ """ |
740 |
+ Return the category-package-version with any operators/slot specifications stripped off |
741 |
+ |
742 |
+ Example usage: |
743 |
+ >>> dep_getcpv('>=media-libs/test-3.0') |
744 |
+ 'media-libs/test-3.0' |
745 |
+ |
746 |
+ @param mydep: The depstring |
747 |
+ @type mydep: String |
748 |
+ @rtype: String |
749 |
+ @return: The depstring with the operator removed |
750 |
+ """ |
751 |
+ if isinstance(mydep, Atom): |
752 |
+ return mydep.cpv |
753 |
+ try: |
754 |
+ return Atom(mydep).cpv |
755 |
+ except InvalidAtom: |
756 |
+ pass |
757 |
+ |
758 |
+ # Fall back to legacy code for backward compatibility. |
759 |
+ warnings.warn(_("%s is deprecated, use %s instead") % \ |
760 |
+ ('portage.dep.dep_getcpv()', 'portage.dep.Atom.cpv'), |
761 |
+ DeprecationWarning, stacklevel=2) |
762 |
+ mydep_orig = mydep |
763 |
+ if mydep: |
764 |
+ mydep = remove_slot(mydep) |
765 |
+ if mydep and mydep[0] == "*": |
766 |
+ mydep = mydep[1:] |
767 |
+ if mydep and mydep[-1] == "*": |
768 |
+ mydep = mydep[:-1] |
769 |
+ if mydep and mydep[0] == "!": |
770 |
+ if mydep[1:2] == "!": |
771 |
+ mydep = mydep[2:] |
772 |
+ else: |
773 |
+ mydep = mydep[1:] |
774 |
+ if mydep[:2] in [">=", "<="]: |
775 |
+ mydep = mydep[2:] |
776 |
+ elif mydep[:1] in "=<>~": |
777 |
+ mydep = mydep[1:] |
778 |
+ return mydep |
779 |
+ |
780 |
+def dep_getslot(mydep): |
781 |
+ """ |
782 |
+ Retrieve the slot on a depend. |
783 |
+ |
784 |
+ Example usage: |
785 |
+ >>> dep_getslot('app-misc/test:3') |
786 |
+ '3' |
787 |
+ |
788 |
+ @param mydep: The depstring to retrieve the slot of |
789 |
+ @type mydep: String |
790 |
+ @rtype: String |
791 |
+ @return: The slot |
792 |
+ """ |
793 |
+ slot = getattr(mydep, "slot", False) |
794 |
+ if slot is not False: |
795 |
+ return slot |
796 |
+ colon = mydep.find(":") |
797 |
+ if colon != -1: |
798 |
+ bracket = mydep.find("[", colon) |
799 |
+ if bracket == -1: |
800 |
+ return mydep[colon+1:] |
801 |
+ else: |
802 |
+ return mydep[colon+1:bracket] |
803 |
+ return None |
804 |
+ |
805 |
+def remove_slot(mydep): |
806 |
+ """ |
807 |
+ Removes dep components from the right side of an atom: |
808 |
+ * slot |
809 |
+ * use |
810 |
+ * repo |
811 |
+ """ |
812 |
+ colon = mydep.find(":") |
813 |
+ if colon != -1: |
814 |
+ mydep = mydep[:colon] |
815 |
+ else: |
816 |
+ bracket = mydep.find("[") |
817 |
+ if bracket != -1: |
818 |
+ mydep = mydep[:bracket] |
819 |
+ return mydep |
820 |
+ |
821 |
+def dep_getusedeps( depend ): |
822 |
+ """ |
823 |
+ Pull a listing of USE Dependencies out of a dep atom. |
824 |
+ |
825 |
+ Example usage: |
826 |
+ >>> dep_getusedeps('app-misc/test:3[foo,-bar]') |
827 |
+ ('foo', '-bar') |
828 |
+ |
829 |
+ @param depend: The depstring to process |
830 |
+ @type depend: String |
831 |
+ @rtype: List |
832 |
+ @return: List of use flags ( or [] if no flags exist ) |
833 |
+ """ |
834 |
+ use_list = [] |
835 |
+ open_bracket = depend.find('[') |
836 |
+ # -1 = failure (think c++ string::npos) |
837 |
+ comma_separated = False |
838 |
+ bracket_count = 0 |
839 |
+ while( open_bracket != -1 ): |
840 |
+ bracket_count += 1 |
841 |
+ if bracket_count > 1: |
842 |
+ raise InvalidAtom(_("USE Dependency with more " |
843 |
+ "than one set of brackets: %s") % (depend,)) |
844 |
+ close_bracket = depend.find(']', open_bracket ) |
845 |
+ if close_bracket == -1: |
846 |
+ raise InvalidAtom(_("USE Dependency with no closing bracket: %s") % depend ) |
847 |
+ use = depend[open_bracket + 1: close_bracket] |
848 |
+ # foo[1:1] may return '' instead of None, we don't want '' in the result |
849 |
+ if not use: |
850 |
+ raise InvalidAtom(_("USE Dependency with " |
851 |
+ "no use flag ([]): %s") % depend ) |
852 |
+ if not comma_separated: |
853 |
+ comma_separated = "," in use |
854 |
+ |
855 |
+ if comma_separated and bracket_count > 1: |
856 |
+ raise InvalidAtom(_("USE Dependency contains a mixture of " |
857 |
+ "comma and bracket separators: %s") % depend ) |
858 |
+ |
859 |
+ if comma_separated: |
860 |
+ for x in use.split(","): |
861 |
+ if x: |
862 |
+ use_list.append(x) |
863 |
+ else: |
864 |
+ raise InvalidAtom(_("USE Dependency with no use " |
865 |
+ "flag next to comma: %s") % depend ) |
866 |
+ else: |
867 |
+ use_list.append(use) |
868 |
+ |
869 |
+ # Find next use flag |
870 |
+ open_bracket = depend.find( '[', open_bracket+1 ) |
871 |
+ return tuple(use_list) |
872 |
+ |
873 |
+# \w is [a-zA-Z0-9_] |
874 |
+ |
875 |
+# 2.1.3 A slot name may contain any of the characters [A-Za-z0-9+_.-]. |
876 |
+# It must not begin with a hyphen or a dot. |
877 |
+_slot = r'([\w+][\w+.-]*)' |
878 |
+_slot_re = re.compile('^' + _slot + '$', re.VERBOSE) |
879 |
+ |
880 |
+_use = r'\[.*\]' |
881 |
+_op = r'([=~]|[><]=?)' |
882 |
+ |
883 |
+_atom_re = re.compile('^(?P<without_use>(?:' + |
884 |
+ '(?P<op>' + _op + _cpv + ')|' + |
885 |
+ '(?P<star>=' + _cpv + r'\*)|' + |
886 |
+ '(?P<simple>' + _cp + '))(:' + _slot + ')?)(' + _use + ')?$', re.VERBOSE) |
887 |
+ |
888 |
+def isvalidatom(atom, allow_blockers=False): |
889 |
+ """ |
890 |
+ Check to see if a depend atom is valid |
891 |
+ |
892 |
+ Example usage: |
893 |
+ >>> isvalidatom('media-libs/test-3.0') |
894 |
+ False |
895 |
+ >>> isvalidatom('>=media-libs/test-3.0') |
896 |
+ True |
897 |
+ |
898 |
+ @param atom: The depend atom to check against |
899 |
+ @type atom: String or Atom |
900 |
+ @rtype: Boolean |
901 |
+ @return: One of the following: |
902 |
+ 1) False if the atom is invalid |
903 |
+ 2) True if the atom is valid |
904 |
+ """ |
905 |
+ try: |
906 |
+ if not isinstance(atom, Atom): |
907 |
+ atom = Atom(atom) |
908 |
+ if not allow_blockers and atom.blocker: |
909 |
+ return False |
910 |
+ return True |
911 |
+ except InvalidAtom: |
912 |
+ return False |
913 |
+ |
914 |
+def isjustname(mypkg): |
915 |
+ """ |
916 |
+ Checks to see if the atom is only the package name (no version parts). |
917 |
+ |
918 |
+ Example usage: |
919 |
+ >>> isjustname('=media-libs/test-3.0') |
920 |
+ False |
921 |
+ >>> isjustname('media-libs/test') |
922 |
+ True |
923 |
+ |
924 |
+ @param mypkg: The package atom to check |
925 |
+ @param mypkg: String or Atom |
926 |
+ @rtype: Integer |
927 |
+ @return: One of the following: |
928 |
+ 1) False if the package string is not just the package name |
929 |
+ 2) True if it is |
930 |
+ """ |
931 |
+ try: |
932 |
+ if not isinstance(mypkg, Atom): |
933 |
+ mypkg = Atom(mypkg) |
934 |
+ return mypkg == mypkg.cp |
935 |
+ except InvalidAtom: |
936 |
+ pass |
937 |
+ |
938 |
+ for x in mypkg.split('-')[-2:]: |
939 |
+ if ververify(x): |
940 |
+ return False |
941 |
+ return True |
942 |
+ |
943 |
+def isspecific(mypkg): |
944 |
+ """ |
945 |
+ Checks to see if a package is in =category/package-version or |
946 |
+ package-version format. |
947 |
+ |
948 |
+ Example usage: |
949 |
+ >>> isspecific('media-libs/test') |
950 |
+ False |
951 |
+ >>> isspecific('=media-libs/test-3.0') |
952 |
+ True |
953 |
+ |
954 |
+ @param mypkg: The package depstring to check against |
955 |
+ @type mypkg: String |
956 |
+ @rtype: Boolean |
957 |
+ @return: One of the following: |
958 |
+ 1) False if the package string is not specific |
959 |
+ 2) True if it is |
960 |
+ """ |
961 |
+ try: |
962 |
+ if not isinstance(mypkg, Atom): |
963 |
+ mypkg = Atom(mypkg) |
964 |
+ return mypkg != mypkg.cp |
965 |
+ except InvalidAtom: |
966 |
+ pass |
967 |
+ |
968 |
+ # Fall back to legacy code for backward compatibility. |
969 |
+ return not isjustname(mypkg) |
970 |
+ |
971 |
+def dep_getkey(mydep): |
972 |
+ """ |
973 |
+ Return the category/package-name of a depstring. |
974 |
+ |
975 |
+ Example usage: |
976 |
+ >>> dep_getkey('=media-libs/test-3.0') |
977 |
+ 'media-libs/test' |
978 |
+ |
979 |
+ @param mydep: The depstring to retrieve the category/package-name of |
980 |
+ @type mydep: String |
981 |
+ @rtype: String |
982 |
+ @return: The package category/package-name |
983 |
+ """ |
984 |
+ if isinstance(mydep, Atom): |
985 |
+ return mydep.cp |
986 |
+ try: |
987 |
+ return Atom(mydep).cp |
988 |
+ except InvalidAtom: |
989 |
+ try: |
990 |
+ atom = Atom('=' + mydep) |
991 |
+ except InvalidAtom: |
992 |
+ pass |
993 |
+ else: |
994 |
+ warnings.warn(_("invalid input to %s: '%s', use %s instead") % \ |
995 |
+ ('portage.dep.dep_getkey()', mydep, 'portage.cpv_getkey()'), |
996 |
+ DeprecationWarning, stacklevel=2) |
997 |
+ return atom.cp |
998 |
+ |
999 |
+ # Fall back to legacy code for backward compatibility. |
1000 |
+ warnings.warn(_("%s is deprecated, use %s instead") % \ |
1001 |
+ ('portage.dep.dep_getkey()', 'portage.dep.Atom.cp'), |
1002 |
+ DeprecationWarning, stacklevel=2) |
1003 |
+ mydep = dep_getcpv(mydep) |
1004 |
+ if mydep and isspecific(mydep): |
1005 |
+ mysplit = catpkgsplit(mydep) |
1006 |
+ if not mysplit: |
1007 |
+ return mydep |
1008 |
+ return mysplit[0] + "/" + mysplit[1] |
1009 |
+ else: |
1010 |
+ return mydep |
1011 |
+ |
1012 |
+def match_to_list(mypkg, mylist): |
1013 |
+ """ |
1014 |
+ Searches list for entries that matches the package. |
1015 |
+ |
1016 |
+ @param mypkg: The package atom to match |
1017 |
+ @type mypkg: String |
1018 |
+ @param mylist: The list of package atoms to compare against |
1019 |
+ @param mylist: List |
1020 |
+ @rtype: List |
1021 |
+ @return: A unique list of package atoms that match the given package atom |
1022 |
+ """ |
1023 |
+ return [ x for x in set(mylist) if match_from_list(x, [mypkg]) ] |
1024 |
+ |
1025 |
+def best_match_to_list(mypkg, mylist): |
1026 |
+ """ |
1027 |
+ Returns the most specific entry that matches the package given. |
1028 |
+ |
1029 |
+ @param mypkg: The package atom to check |
1030 |
+ @type mypkg: String |
1031 |
+ @param mylist: The list of package atoms to check against |
1032 |
+ @type mylist: List |
1033 |
+ @rtype: String |
1034 |
+ @return: The package atom which best matches given the following ordering: |
1035 |
+ - =cpv 6 |
1036 |
+ - ~cpv 5 |
1037 |
+ - =cpv* 4 |
1038 |
+ - cp:slot 3 |
1039 |
+ - >cpv 2 |
1040 |
+ - <cpv 2 |
1041 |
+ - >=cpv 2 |
1042 |
+ - <=cpv 2 |
1043 |
+ - cp 1 |
1044 |
+ """ |
1045 |
+ operator_values = {'=':6, '~':5, '=*':4, |
1046 |
+ '>':2, '<':2, '>=':2, '<=':2, None:1} |
1047 |
+ maxvalue = 0 |
1048 |
+ bestm = None |
1049 |
+ for x in match_to_list(mypkg, mylist): |
1050 |
+ if dep_getslot(x) is not None: |
1051 |
+ if maxvalue < 3: |
1052 |
+ maxvalue = 3 |
1053 |
+ bestm = x |
1054 |
+ op_val = operator_values[x.operator] |
1055 |
+ if op_val > maxvalue: |
1056 |
+ maxvalue = op_val |
1057 |
+ bestm = x |
1058 |
+ return bestm |
1059 |
+ |
1060 |
+def match_from_list(mydep, candidate_list): |
1061 |
+ """ |
1062 |
+ Searches list for entries that matches the package. |
1063 |
+ |
1064 |
+ @param mydep: The package atom to match |
1065 |
+ @type mydep: String |
1066 |
+ @param candidate_list: The list of package atoms to compare against |
1067 |
+ @param candidate_list: List |
1068 |
+ @rtype: List |
1069 |
+ @return: A list of package atoms that match the given package atom |
1070 |
+ """ |
1071 |
+ |
1072 |
+ if not candidate_list: |
1073 |
+ return [] |
1074 |
+ |
1075 |
+ from portage.util import writemsg |
1076 |
+ if "!" == mydep[:1]: |
1077 |
+ mydep = mydep[1:] |
1078 |
+ if not isinstance(mydep, Atom): |
1079 |
+ mydep = Atom(mydep) |
1080 |
+ |
1081 |
+ mycpv = mydep.cpv |
1082 |
+ mycpv_cps = catpkgsplit(mycpv) # Can be None if not specific |
1083 |
+ slot = mydep.slot |
1084 |
+ |
1085 |
+ if not mycpv_cps: |
1086 |
+ cat, pkg = catsplit(mycpv) |
1087 |
+ ver = None |
1088 |
+ rev = None |
1089 |
+ else: |
1090 |
+ cat, pkg, ver, rev = mycpv_cps |
1091 |
+ if mydep == mycpv: |
1092 |
+ raise KeyError(_("Specific key requires an operator" |
1093 |
+ " (%s) (try adding an '=')") % (mydep)) |
1094 |
+ |
1095 |
+ if ver and rev: |
1096 |
+ operator = mydep.operator |
1097 |
+ if not operator: |
1098 |
+ writemsg(_("!!! Invalid atom: %s\n") % mydep, noiselevel=-1) |
1099 |
+ return [] |
1100 |
+ else: |
1101 |
+ operator = None |
1102 |
+ |
1103 |
+ mylist = [] |
1104 |
+ |
1105 |
+ if operator is None: |
1106 |
+ for x in candidate_list: |
1107 |
+ cp = getattr(x, "cp", None) |
1108 |
+ if cp is None: |
1109 |
+ mysplit = catpkgsplit(remove_slot(x)) |
1110 |
+ if mysplit is not None: |
1111 |
+ cp = mysplit[0] + '/' + mysplit[1] |
1112 |
+ if cp != mycpv: |
1113 |
+ continue |
1114 |
+ mylist.append(x) |
1115 |
+ |
1116 |
+ elif operator == "=": # Exact match |
1117 |
+ for x in candidate_list: |
1118 |
+ xcpv = getattr(x, "cpv", None) |
1119 |
+ if xcpv is None: |
1120 |
+ xcpv = remove_slot(x) |
1121 |
+ if not cpvequal(xcpv, mycpv): |
1122 |
+ continue |
1123 |
+ mylist.append(x) |
1124 |
+ |
1125 |
+ elif operator == "=*": # glob match |
1126 |
+ # XXX: Nasty special casing for leading zeros |
1127 |
+ # Required as =* is a literal prefix match, so can't |
1128 |
+ # use vercmp |
1129 |
+ mysplit = catpkgsplit(mycpv) |
1130 |
+ myver = mysplit[2].lstrip("0") |
1131 |
+ if not myver or not myver[0].isdigit(): |
1132 |
+ myver = "0"+myver |
1133 |
+ mycpv = mysplit[0]+"/"+mysplit[1]+"-"+myver |
1134 |
+ for x in candidate_list: |
1135 |
+ xs = getattr(x, "cpv_split", None) |
1136 |
+ if xs is None: |
1137 |
+ xs = catpkgsplit(remove_slot(x)) |
1138 |
+ myver = xs[2].lstrip("0") |
1139 |
+ if not myver or not myver[0].isdigit(): |
1140 |
+ myver = "0"+myver |
1141 |
+ xcpv = xs[0]+"/"+xs[1]+"-"+myver |
1142 |
+ if xcpv.startswith(mycpv): |
1143 |
+ mylist.append(x) |
1144 |
+ |
1145 |
+ elif operator == "~": # version, any revision, match |
1146 |
+ for x in candidate_list: |
1147 |
+ xs = getattr(x, "cpv_split", None) |
1148 |
+ if xs is None: |
1149 |
+ xs = catpkgsplit(remove_slot(x)) |
1150 |
+ if xs is None: |
1151 |
+ raise InvalidData(x) |
1152 |
+ if not cpvequal(xs[0]+"/"+xs[1]+"-"+xs[2], mycpv_cps[0]+"/"+mycpv_cps[1]+"-"+mycpv_cps[2]): |
1153 |
+ continue |
1154 |
+ if xs[2] != ver: |
1155 |
+ continue |
1156 |
+ mylist.append(x) |
1157 |
+ |
1158 |
+ elif operator in [">", ">=", "<", "<="]: |
1159 |
+ mysplit = ["%s/%s" % (cat, pkg), ver, rev] |
1160 |
+ for x in candidate_list: |
1161 |
+ xs = getattr(x, "cpv_split", None) |
1162 |
+ if xs is None: |
1163 |
+ xs = catpkgsplit(remove_slot(x)) |
1164 |
+ xcat, xpkg, xver, xrev = xs |
1165 |
+ xs = ["%s/%s" % (xcat, xpkg), xver, xrev] |
1166 |
+ try: |
1167 |
+ result = pkgcmp(xs, mysplit) |
1168 |
+ except ValueError: # pkgcmp may return ValueError during int() conversion |
1169 |
+ writemsg(_("\nInvalid package name: %s\n") % x, noiselevel=-1) |
1170 |
+ raise |
1171 |
+ if result is None: |
1172 |
+ continue |
1173 |
+ elif operator == ">": |
1174 |
+ if result > 0: |
1175 |
+ mylist.append(x) |
1176 |
+ elif operator == ">=": |
1177 |
+ if result >= 0: |
1178 |
+ mylist.append(x) |
1179 |
+ elif operator == "<": |
1180 |
+ if result < 0: |
1181 |
+ mylist.append(x) |
1182 |
+ elif operator == "<=": |
1183 |
+ if result <= 0: |
1184 |
+ mylist.append(x) |
1185 |
+ else: |
1186 |
+ raise KeyError(_("Unknown operator: %s") % mydep) |
1187 |
+ else: |
1188 |
+ raise KeyError(_("Unknown operator: %s") % mydep) |
1189 |
+ |
1190 |
+ if slot is not None: |
1191 |
+ candidate_list = mylist |
1192 |
+ mylist = [] |
1193 |
+ for x in candidate_list: |
1194 |
+ xslot = getattr(x, "slot", False) |
1195 |
+ if xslot is False: |
1196 |
+ xslot = dep_getslot(x) |
1197 |
+ if xslot is not None and xslot != slot: |
1198 |
+ continue |
1199 |
+ mylist.append(x) |
1200 |
+ |
1201 |
+ if mydep.use: |
1202 |
+ candidate_list = mylist |
1203 |
+ mylist = [] |
1204 |
+ for x in candidate_list: |
1205 |
+ use = getattr(x, "use", None) |
1206 |
+ if use is not None: |
1207 |
+ regex = x.iuse.regex |
1208 |
+ missing_iuse = False |
1209 |
+ for y in mydep.use.required: |
1210 |
+ if regex.match(y) is None: |
1211 |
+ missing_iuse = True |
1212 |
+ break |
1213 |
+ if missing_iuse: |
1214 |
+ continue |
1215 |
+ if mydep.use.enabled.difference(use.enabled): |
1216 |
+ continue |
1217 |
+ if mydep.use.disabled.intersection(use.enabled): |
1218 |
+ continue |
1219 |
+ mylist.append(x) |
1220 |
+ |
1221 |
+ return mylist |
1222 |
|
1223 |
Deleted: main/trunk/pym/portage/dep.py |
1224 |
=================================================================== |
1225 |
--- main/trunk/pym/portage/dep.py 2010-02-25 20:42:04 UTC (rev 15460) |
1226 |
+++ main/trunk/pym/portage/dep.py 2010-02-25 20:48:08 UTC (rev 15461) |
1227 |
@@ -1,1203 +0,0 @@ |
1228 |
-# deps.py -- Portage dependency resolution functions |
1229 |
-# Copyright 2003-2004 Gentoo Foundation |
1230 |
-# Distributed under the terms of the GNU General Public License v2 |
1231 |
-# $Id$ |
1232 |
- |
1233 |
-__all__ = [ |
1234 |
- 'Atom', 'best_match_to_list', 'cpvequal', |
1235 |
- 'dep_getcpv', 'dep_getkey', 'dep_getslot', |
1236 |
- 'dep_getusedeps', 'dep_opconvert', 'flatten', |
1237 |
- 'get_operator', 'isjustname', 'isspecific', |
1238 |
- 'isvalidatom', 'match_from_list', 'match_to_list', |
1239 |
- 'paren_enclose', 'paren_normalize', 'paren_reduce', |
1240 |
- 'remove_slot', 'strip_empty', 'use_reduce' |
1241 |
-] |
1242 |
- |
1243 |
-# DEPEND SYNTAX: |
1244 |
-# |
1245 |
-# 'use?' only affects the immediately following word! |
1246 |
-# Nesting is the only legal way to form multiple '[!]use?' requirements. |
1247 |
-# |
1248 |
-# Where: 'a' and 'b' are use flags, and 'z' is a depend atom. |
1249 |
-# |
1250 |
-# "a? z" -- If 'a' in [use], then b is valid. |
1251 |
-# "a? ( z )" -- Syntax with parenthesis. |
1252 |
-# "a? b? z" -- Deprecated. |
1253 |
-# "a? ( b? z )" -- Valid |
1254 |
-# "a? ( b? ( z ) ) -- Valid |
1255 |
-# |
1256 |
- |
1257 |
-import re, sys |
1258 |
-import warnings |
1259 |
-from itertools import chain |
1260 |
-import portage.exception |
1261 |
-from portage.exception import InvalidData, InvalidAtom |
1262 |
-from portage.localization import _ |
1263 |
-from portage.versions import catpkgsplit, catsplit, \ |
1264 |
- pkgcmp, pkgsplit, ververify, _cp, _cpv |
1265 |
-import portage.cache.mappings |
1266 |
- |
1267 |
-if sys.hexversion >= 0x3000000: |
1268 |
- basestring = str |
1269 |
- |
1270 |
-def cpvequal(cpv1, cpv2): |
1271 |
- """ |
1272 |
- |
1273 |
- @param cpv1: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1" |
1274 |
- @type cpv1: String |
1275 |
- @param cpv2: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1" |
1276 |
- @type cpv2: String |
1277 |
- @rtype: Boolean |
1278 |
- @returns: |
1279 |
- 1. True if cpv1 = cpv2 |
1280 |
- 2. False Otherwise |
1281 |
- 3. Throws PortageException if cpv1 or cpv2 is not a CPV |
1282 |
- |
1283 |
- Example Usage: |
1284 |
- >>> from portage.dep import cpvequal |
1285 |
- >>> cpvequal("sys-apps/portage-2.1","sys-apps/portage-2.1") |
1286 |
- >>> True |
1287 |
- |
1288 |
- """ |
1289 |
- |
1290 |
- split1 = catpkgsplit(cpv1) |
1291 |
- split2 = catpkgsplit(cpv2) |
1292 |
- |
1293 |
- if not split1 or not split2: |
1294 |
- raise portage.exception.PortageException(_("Invalid data '%s, %s', parameter was not a CPV") % (cpv1, cpv2)) |
1295 |
- |
1296 |
- if split1[0] != split2[0]: |
1297 |
- return False |
1298 |
- |
1299 |
- return (pkgcmp(split1[1:], split2[1:]) == 0) |
1300 |
- |
1301 |
-def strip_empty(myarr): |
1302 |
- """ |
1303 |
- Strip all empty elements from an array |
1304 |
- |
1305 |
- @param myarr: The list of elements |
1306 |
- @type myarr: List |
1307 |
- @rtype: Array |
1308 |
- @return: The array with empty elements removed |
1309 |
- """ |
1310 |
- return [x for x in myarr if x] |
1311 |
- |
1312 |
-_paren_whitespace_re = re.compile(r'\S(\(|\))|(\(|\))\S') |
1313 |
- |
1314 |
-def paren_reduce(mystr,tokenize=1): |
1315 |
- """ |
1316 |
- Take a string and convert all paren enclosed entities into sublists, optionally |
1317 |
- futher splitting the list elements by spaces. |
1318 |
- |
1319 |
- Example usage: |
1320 |
- >>> paren_reduce('foobar foo ( bar baz )',1) |
1321 |
- ['foobar', 'foo', ['bar', 'baz']] |
1322 |
- >>> paren_reduce('foobar foo ( bar baz )',0) |
1323 |
- ['foobar foo ', [' bar baz ']] |
1324 |
- |
1325 |
- @param mystr: The string to reduce |
1326 |
- @type mystr: String |
1327 |
- @param tokenize: Split on spaces to produces further list breakdown |
1328 |
- @type tokenize: Integer |
1329 |
- @rtype: Array |
1330 |
- @return: The reduced string in an array |
1331 |
- """ |
1332 |
- global _dep_check_strict, _paren_whitespace_re |
1333 |
- if _dep_check_strict: |
1334 |
- m = _paren_whitespace_re.search(mystr) |
1335 |
- if m is not None: |
1336 |
- raise portage.exception.InvalidDependString( |
1337 |
- _("missing space by parenthesis: '%s'") % m.group(0)) |
1338 |
- mylist = [] |
1339 |
- while mystr: |
1340 |
- left_paren = mystr.find("(") |
1341 |
- has_left_paren = left_paren != -1 |
1342 |
- right_paren = mystr.find(")") |
1343 |
- has_right_paren = right_paren != -1 |
1344 |
- if not has_left_paren and not has_right_paren: |
1345 |
- freesec = mystr |
1346 |
- subsec = None |
1347 |
- tail = "" |
1348 |
- elif mystr[0] == ")": |
1349 |
- return [mylist,mystr[1:]] |
1350 |
- elif has_left_paren and not has_right_paren: |
1351 |
- raise portage.exception.InvalidDependString( |
1352 |
- _("missing right parenthesis: '%s'") % mystr) |
1353 |
- elif has_left_paren and left_paren < right_paren: |
1354 |
- freesec,subsec = mystr.split("(",1) |
1355 |
- sublist = paren_reduce(subsec, tokenize=tokenize) |
1356 |
- if len(sublist) != 2: |
1357 |
- raise portage.exception.InvalidDependString( |
1358 |
- _("malformed syntax: '%s'") % mystr) |
1359 |
- subsec, tail = sublist |
1360 |
- else: |
1361 |
- subsec,tail = mystr.split(")",1) |
1362 |
- if tokenize: |
1363 |
- subsec = strip_empty(subsec.split(" ")) |
1364 |
- return [mylist+subsec,tail] |
1365 |
- return mylist+[subsec],tail |
1366 |
- if not isinstance(tail, basestring): |
1367 |
- raise portage.exception.InvalidDependString( |
1368 |
- _("malformed syntax: '%s'") % mystr) |
1369 |
- mystr = tail |
1370 |
- if freesec: |
1371 |
- if tokenize: |
1372 |
- mylist = mylist + strip_empty(freesec.split(" ")) |
1373 |
- else: |
1374 |
- mylist = mylist + [freesec] |
1375 |
- if subsec is not None: |
1376 |
- mylist = mylist + [subsec] |
1377 |
- return mylist |
1378 |
- |
1379 |
-class paren_normalize(list): |
1380 |
- """Take a dependency structure as returned by paren_reduce or use_reduce |
1381 |
- and generate an equivalent structure that has no redundant lists.""" |
1382 |
- def __init__(self, src): |
1383 |
- list.__init__(self) |
1384 |
- self._zap_parens(src, self) |
1385 |
- |
1386 |
- def _zap_parens(self, src, dest, disjunction=False): |
1387 |
- if not src: |
1388 |
- return dest |
1389 |
- i = iter(src) |
1390 |
- for x in i: |
1391 |
- if isinstance(x, basestring): |
1392 |
- if x == '||': |
1393 |
- x = self._zap_parens(next(i), [], disjunction=True) |
1394 |
- if len(x) == 1: |
1395 |
- dest.append(x[0]) |
1396 |
- else: |
1397 |
- dest.append("||") |
1398 |
- dest.append(x) |
1399 |
- elif x.endswith("?"): |
1400 |
- dest.append(x) |
1401 |
- dest.append(self._zap_parens(next(i), [])) |
1402 |
- else: |
1403 |
- dest.append(x) |
1404 |
- else: |
1405 |
- if disjunction: |
1406 |
- x = self._zap_parens(x, []) |
1407 |
- if len(x) == 1: |
1408 |
- dest.append(x[0]) |
1409 |
- else: |
1410 |
- dest.append(x) |
1411 |
- else: |
1412 |
- self._zap_parens(x, dest) |
1413 |
- return dest |
1414 |
- |
1415 |
-def paren_enclose(mylist): |
1416 |
- """ |
1417 |
- Convert a list to a string with sublists enclosed with parens. |
1418 |
- |
1419 |
- Example usage: |
1420 |
- >>> test = ['foobar','foo',['bar','baz']] |
1421 |
- >>> paren_enclose(test) |
1422 |
- 'foobar foo ( bar baz )' |
1423 |
- |
1424 |
- @param mylist: The list |
1425 |
- @type mylist: List |
1426 |
- @rtype: String |
1427 |
- @return: The paren enclosed string |
1428 |
- """ |
1429 |
- mystrparts = [] |
1430 |
- for x in mylist: |
1431 |
- if isinstance(x, list): |
1432 |
- mystrparts.append("( "+paren_enclose(x)+" )") |
1433 |
- else: |
1434 |
- mystrparts.append(x) |
1435 |
- return " ".join(mystrparts) |
1436 |
- |
1437 |
-# This is just for use by emerge so that it can enable a backward compatibility |
1438 |
-# mode in order to gracefully deal with installed packages that have invalid |
1439 |
-# atoms or dep syntax. For backward compatibility with api consumers, strict |
1440 |
-# behavior will be explicitly enabled as necessary. |
1441 |
-_dep_check_strict = False |
1442 |
- |
1443 |
-def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]): |
1444 |
- """ |
1445 |
- Takes a paren_reduce'd array and reduces the use? conditionals out |
1446 |
- leaving an array with subarrays |
1447 |
- |
1448 |
- @param deparray: paren_reduce'd list of deps |
1449 |
- @type deparray: List |
1450 |
- @param uselist: List of use flags |
1451 |
- @type uselist: List |
1452 |
- @param masklist: List of masked flags |
1453 |
- @type masklist: List |
1454 |
- @param matchall: Resolve all conditional deps unconditionally. Used by repoman |
1455 |
- @type matchall: Integer |
1456 |
- @rtype: List |
1457 |
- @return: The use reduced depend array |
1458 |
- """ |
1459 |
- # Quick validity checks |
1460 |
- for x, y in enumerate(deparray): |
1461 |
- if y == '||': |
1462 |
- if len(deparray) - 1 == x or not isinstance(deparray[x+1], list): |
1463 |
- raise portage.exception.InvalidDependString(_('%(dep)s missing atom list in "%(deparray)s"') % {"dep": deparray[x], "deparray": paren_enclose(deparray)}) |
1464 |
- if deparray and deparray[-1] and deparray[-1][-1] == "?": |
1465 |
- raise portage.exception.InvalidDependString(_('Conditional without target in "%s"') % paren_enclose(deparray)) |
1466 |
- |
1467 |
- global _dep_check_strict |
1468 |
- |
1469 |
- mydeparray = deparray[:] |
1470 |
- rlist = [] |
1471 |
- while mydeparray: |
1472 |
- head = mydeparray.pop(0) |
1473 |
- |
1474 |
- if not isinstance(head, basestring): |
1475 |
- additions = use_reduce(head, uselist, masklist, matchall, excludeall) |
1476 |
- if additions: |
1477 |
- rlist.append(additions) |
1478 |
- elif rlist and rlist[-1] == "||": |
1479 |
- #XXX: Currently some DEPEND strings have || lists without default atoms. |
1480 |
- # raise portage.exception.InvalidDependString("No default atom(s) in \""+paren_enclose(deparray)+"\"") |
1481 |
- rlist.append([]) |
1482 |
- |
1483 |
- else: |
1484 |
- if head[-1:] == "?": # Use reduce next group on fail. |
1485 |
- # Pull any other use conditions and the following atom or list into a separate array |
1486 |
- newdeparray = [head] |
1487 |
- while isinstance(newdeparray[-1], basestring) and \ |
1488 |
- newdeparray[-1][-1:] == "?": |
1489 |
- if mydeparray: |
1490 |
- newdeparray.append(mydeparray.pop(0)) |
1491 |
- else: |
1492 |
- raise ValueError(_("Conditional with no target.")) |
1493 |
- |
1494 |
- # Deprecation checks |
1495 |
- warned = 0 |
1496 |
- if len(newdeparray[-1]) == 0: |
1497 |
- sys.stderr.write(_("Note: Empty target in string. (Deprecated)\n")) |
1498 |
- warned = 1 |
1499 |
- if len(newdeparray) != 2: |
1500 |
- sys.stderr.write(_("Note: Nested use flags without parenthesis (Deprecated)\n")) |
1501 |
- warned = 1 |
1502 |
- if warned: |
1503 |
- sys.stderr.write(" --> "+" ".join(map(str,[head]+newdeparray))+"\n") |
1504 |
- |
1505 |
- # Check that each flag matches |
1506 |
- ismatch = True |
1507 |
- missing_flag = False |
1508 |
- for head in newdeparray[:-1]: |
1509 |
- head = head[:-1] |
1510 |
- if not head: |
1511 |
- missing_flag = True |
1512 |
- break |
1513 |
- if head.startswith("!"): |
1514 |
- head_key = head[1:] |
1515 |
- if not head_key: |
1516 |
- missing_flag = True |
1517 |
- break |
1518 |
- if not matchall and head_key in uselist or \ |
1519 |
- head_key in excludeall: |
1520 |
- ismatch = False |
1521 |
- break |
1522 |
- elif head not in masklist: |
1523 |
- if not matchall and head not in uselist: |
1524 |
- ismatch = False |
1525 |
- break |
1526 |
- else: |
1527 |
- ismatch = False |
1528 |
- if missing_flag: |
1529 |
- raise portage.exception.InvalidDependString( |
1530 |
- _('Conditional without flag: "') + \ |
1531 |
- paren_enclose([head+"?", newdeparray[-1]])+"\"") |
1532 |
- |
1533 |
- # If they all match, process the target |
1534 |
- if ismatch: |
1535 |
- target = newdeparray[-1] |
1536 |
- if isinstance(target, list): |
1537 |
- additions = use_reduce(target, uselist, masklist, matchall, excludeall) |
1538 |
- if additions: |
1539 |
- rlist.append(additions) |
1540 |
- elif not _dep_check_strict: |
1541 |
- # The old deprecated behavior. |
1542 |
- rlist.append(target) |
1543 |
- else: |
1544 |
- raise portage.exception.InvalidDependString( |
1545 |
- _("Conditional without parenthesis: '%s?'") % head) |
1546 |
- |
1547 |
- else: |
1548 |
- rlist += [head] |
1549 |
- |
1550 |
- return rlist |
1551 |
- |
1552 |
-def dep_opconvert(deplist): |
1553 |
- """ |
1554 |
- Iterate recursively through a list of deps, if the |
1555 |
- dep is a '||' or '&&' operator, combine it with the |
1556 |
- list of deps that follows.. |
1557 |
- |
1558 |
- Example usage: |
1559 |
- >>> test = ["blah", "||", ["foo", "bar", "baz"]] |
1560 |
- >>> dep_opconvert(test) |
1561 |
- ['blah', ['||', 'foo', 'bar', 'baz']] |
1562 |
- |
1563 |
- @param deplist: A list of deps to format |
1564 |
- @type mydep: List |
1565 |
- @rtype: List |
1566 |
- @return: |
1567 |
- The new list with the new ordering |
1568 |
- """ |
1569 |
- |
1570 |
- retlist = [] |
1571 |
- x = 0 |
1572 |
- while x != len(deplist): |
1573 |
- if isinstance(deplist[x], list): |
1574 |
- retlist.append(dep_opconvert(deplist[x])) |
1575 |
- elif deplist[x] == "||" or deplist[x] == "&&": |
1576 |
- retlist.append([deplist[x]] + dep_opconvert(deplist[x+1])) |
1577 |
- x += 1 |
1578 |
- else: |
1579 |
- retlist.append(deplist[x]) |
1580 |
- x += 1 |
1581 |
- return retlist |
1582 |
- |
1583 |
-def flatten(mylist): |
1584 |
- """ |
1585 |
- Recursively traverse nested lists and return a single list containing |
1586 |
- all non-list elements that are found. |
1587 |
- |
1588 |
- Example usage: |
1589 |
- >>> flatten([1, [2, 3, [4]]]) |
1590 |
- [1, 2, 3, 4] |
1591 |
- |
1592 |
- @param mylist: A list containing nested lists and non-list elements. |
1593 |
- @type mylist: List |
1594 |
- @rtype: List |
1595 |
- @return: A single list containing only non-list elements. |
1596 |
- """ |
1597 |
- newlist = [] |
1598 |
- for x in mylist: |
1599 |
- if isinstance(x, list): |
1600 |
- newlist.extend(flatten(x)) |
1601 |
- else: |
1602 |
- newlist.append(x) |
1603 |
- return newlist |
1604 |
- |
1605 |
-class _use_dep(object): |
1606 |
- |
1607 |
- __slots__ = ("__weakref__", "conditional", |
1608 |
- "disabled", "enabled", "tokens", "required") |
1609 |
- |
1610 |
- _conditionals_class = portage.cache.mappings.slot_dict_class( |
1611 |
- ("disabled", "enabled", "equal", "not_equal"), prefix="") |
1612 |
- |
1613 |
- _valid_use_re = re.compile(r'^[^-?!=][^?!=]*$') |
1614 |
- |
1615 |
- def __init__(self, use): |
1616 |
- enabled_flags = [] |
1617 |
- disabled_flags = [] |
1618 |
- conditional = self._conditionals_class() |
1619 |
- for k in conditional.allowed_keys: |
1620 |
- conditional[k] = [] |
1621 |
- |
1622 |
- for x in use: |
1623 |
- last_char = x[-1:] |
1624 |
- first_char = x[:1] |
1625 |
- |
1626 |
- if "?" == last_char: |
1627 |
- if "!" == first_char: |
1628 |
- conditional.disabled.append( |
1629 |
- self._validate_flag(x, x[1:-1])) |
1630 |
- else: |
1631 |
- conditional.enabled.append( |
1632 |
- self._validate_flag(x, x[:-1])) |
1633 |
- |
1634 |
- elif "=" == last_char: |
1635 |
- if "!" == first_char: |
1636 |
- conditional.not_equal.append( |
1637 |
- self._validate_flag(x, x[1:-1])) |
1638 |
- else: |
1639 |
- conditional.equal.append( |
1640 |
- self._validate_flag(x, x[:-1])) |
1641 |
- |
1642 |
- else: |
1643 |
- if "-" == first_char: |
1644 |
- disabled_flags.append(self._validate_flag(x, x[1:])) |
1645 |
- else: |
1646 |
- enabled_flags.append(self._validate_flag(x, x)) |
1647 |
- |
1648 |
- self.tokens = use |
1649 |
- if not isinstance(self.tokens, tuple): |
1650 |
- self.tokens = tuple(self.tokens) |
1651 |
- |
1652 |
- self.required = frozenset(chain( |
1653 |
- enabled_flags, |
1654 |
- disabled_flags, |
1655 |
- *conditional.values() |
1656 |
- )) |
1657 |
- |
1658 |
- self.enabled = frozenset(enabled_flags) |
1659 |
- self.disabled = frozenset(disabled_flags) |
1660 |
- self.conditional = None |
1661 |
- |
1662 |
- for v in conditional.values(): |
1663 |
- if v: |
1664 |
- for k, v in conditional.items(): |
1665 |
- conditional[k] = frozenset(v) |
1666 |
- self.conditional = conditional |
1667 |
- break |
1668 |
- |
1669 |
- def _validate_flag(self, token, flag): |
1670 |
- if self._valid_use_re.match(flag) is None: |
1671 |
- raise InvalidAtom(_("Invalid use dep: '%s'") % (token,)) |
1672 |
- return flag |
1673 |
- |
1674 |
- def __bool__(self): |
1675 |
- return bool(self.tokens) |
1676 |
- |
1677 |
- if sys.hexversion < 0x3000000: |
1678 |
- __nonzero__ = __bool__ |
1679 |
- |
1680 |
- def __str__(self): |
1681 |
- if not self.tokens: |
1682 |
- return "" |
1683 |
- return "[%s]" % (",".join(self.tokens),) |
1684 |
- |
1685 |
- def __repr__(self): |
1686 |
- return "portage.dep._use_dep(%s)" % repr(self.tokens) |
1687 |
- |
1688 |
- def evaluate_conditionals(self, use): |
1689 |
- """ |
1690 |
- Create a new instance with conditionals evaluated. |
1691 |
- |
1692 |
- Conditional evaluation behavior: |
1693 |
- |
1694 |
- parent state conditional result |
1695 |
- |
1696 |
- x x? x |
1697 |
- -x x? |
1698 |
- x !x? |
1699 |
- -x !x? -x |
1700 |
- |
1701 |
- x x= x |
1702 |
- -x x= -x |
1703 |
- x !x= -x |
1704 |
- -x !x= x |
1705 |
- |
1706 |
- Conditional syntax examples: |
1707 |
- |
1708 |
- Compact Form Equivalent Expanded Form |
1709 |
- |
1710 |
- foo[bar?] bar? ( foo[bar] ) !bar? ( foo ) |
1711 |
- foo[!bar?] bar? ( foo ) !bar? ( foo[-bar] ) |
1712 |
- foo[bar=] bar? ( foo[bar] ) !bar? ( foo[-bar] ) |
1713 |
- foo[!bar=] bar? ( foo[-bar] ) !bar? ( foo[bar] ) |
1714 |
- |
1715 |
- """ |
1716 |
- tokens = [] |
1717 |
- |
1718 |
- conditional = self.conditional |
1719 |
- tokens.extend(self.enabled) |
1720 |
- tokens.extend("-" + x for x in self.disabled) |
1721 |
- tokens.extend(x for x in conditional.enabled if x in use) |
1722 |
- tokens.extend("-" + x for x in conditional.disabled if x not in use) |
1723 |
- |
1724 |
- tokens.extend(x for x in conditional.equal if x in use) |
1725 |
- tokens.extend("-" + x for x in conditional.equal if x not in use) |
1726 |
- tokens.extend("-" + x for x in conditional.not_equal if x in use) |
1727 |
- tokens.extend(x for x in conditional.not_equal if x not in use) |
1728 |
- |
1729 |
- return _use_dep(tokens) |
1730 |
- |
1731 |
- def _eval_qa_conditionals(self, use_mask, use_force): |
1732 |
- """ |
1733 |
- For repoman, evaluate all possible combinations within the constraints |
1734 |
- of the given use.force and use.mask settings. The result may seem |
1735 |
- ambiguous in the sense that the same flag can be in both the enabled |
1736 |
- and disabled sets, but this is useful within the context of how its |
1737 |
- intended to be used by repoman. It is assumed that the caller has |
1738 |
- already ensured that there is no intersection between the given |
1739 |
- use_mask and use_force sets when necessary. |
1740 |
- """ |
1741 |
- tokens = [] |
1742 |
- |
1743 |
- conditional = self.conditional |
1744 |
- tokens.extend(self.enabled) |
1745 |
- tokens.extend("-" + x for x in self.disabled) |
1746 |
- tokens.extend(x for x in conditional.enabled if x not in use_mask) |
1747 |
- tokens.extend("-" + x for x in conditional.disabled if x not in use_force) |
1748 |
- |
1749 |
- tokens.extend(x for x in conditional.equal if x not in use_mask) |
1750 |
- tokens.extend("-" + x for x in conditional.equal if x not in use_force) |
1751 |
- tokens.extend("-" + x for x in conditional.not_equal if x not in use_mask) |
1752 |
- tokens.extend(x for x in conditional.not_equal if x not in use_force) |
1753 |
- |
1754 |
- return _use_dep(tokens) |
1755 |
- |
1756 |
-if sys.hexversion < 0x3000000: |
1757 |
- _atom_base = unicode |
1758 |
-else: |
1759 |
- _atom_base = str |
1760 |
- |
1761 |
-class Atom(_atom_base): |
1762 |
- |
1763 |
- """ |
1764 |
- For compatibility with existing atom string manipulation code, this |
1765 |
- class emulates most of the str methods that are useful with atoms. |
1766 |
- """ |
1767 |
- |
1768 |
- class _blocker(object): |
1769 |
- __slots__ = ("overlap",) |
1770 |
- |
1771 |
- class _overlap(object): |
1772 |
- __slots__ = ("forbid",) |
1773 |
- |
1774 |
- def __init__(self, forbid=False): |
1775 |
- self.forbid = forbid |
1776 |
- |
1777 |
- def __init__(self, forbid_overlap=False): |
1778 |
- self.overlap = self._overlap(forbid=forbid_overlap) |
1779 |
- |
1780 |
- def __init__(self, s): |
1781 |
- if isinstance(s, Atom): |
1782 |
- # This is an efficiency assertion, to ensure that the Atom |
1783 |
- # constructor is not called redundantly. |
1784 |
- raise TypeError(_("Expected %s, got %s") % \ |
1785 |
- (_atom_base, type(s))) |
1786 |
- |
1787 |
- _atom_base.__init__(s) |
1788 |
- |
1789 |
- if "!" == s[:1]: |
1790 |
- blocker = self._blocker(forbid_overlap=("!" == s[1:2])) |
1791 |
- if blocker.overlap.forbid: |
1792 |
- s = s[2:] |
1793 |
- else: |
1794 |
- s = s[1:] |
1795 |
- else: |
1796 |
- blocker = False |
1797 |
- self.__dict__['blocker'] = blocker |
1798 |
- m = _atom_re.match(s) |
1799 |
- if m is None: |
1800 |
- raise InvalidAtom(self) |
1801 |
- |
1802 |
- if m.group('op') is not None: |
1803 |
- base = _atom_re.groupindex['op'] |
1804 |
- op = m.group(base + 1) |
1805 |
- cpv = m.group(base + 2) |
1806 |
- cp = m.group(base + 3) |
1807 |
- if m.group(base + 4) is not None: |
1808 |
- raise InvalidAtom(self) |
1809 |
- elif m.group('star') is not None: |
1810 |
- base = _atom_re.groupindex['star'] |
1811 |
- op = '=*' |
1812 |
- cpv = m.group(base + 1) |
1813 |
- cp = m.group(base + 2) |
1814 |
- if m.group(base + 3) is not None: |
1815 |
- raise InvalidAtom(self) |
1816 |
- elif m.group('simple') is not None: |
1817 |
- op = None |
1818 |
- cpv = cp = m.group(_atom_re.groupindex['simple'] + 1) |
1819 |
- if m.group(_atom_re.groupindex['simple'] + 2) is not None: |
1820 |
- raise InvalidAtom(self) |
1821 |
- else: |
1822 |
- raise AssertionError(_("required group not found in atom: '%s'") % self) |
1823 |
- self.__dict__['cp'] = cp |
1824 |
- self.__dict__['cpv'] = cpv |
1825 |
- self.__dict__['slot'] = m.group(_atom_re.groups - 1) |
1826 |
- self.__dict__['operator'] = op |
1827 |
- |
1828 |
- use_str = m.group(_atom_re.groups) |
1829 |
- if use_str is not None: |
1830 |
- use = _use_dep(dep_getusedeps(s)) |
1831 |
- without_use = Atom(m.group('without_use')) |
1832 |
- else: |
1833 |
- use = None |
1834 |
- without_use = self |
1835 |
- |
1836 |
- self.__dict__['use'] = use |
1837 |
- self.__dict__['without_use'] = without_use |
1838 |
- |
1839 |
- def __setattr__(self, name, value): |
1840 |
- raise AttributeError("Atom instances are immutable", |
1841 |
- self.__class__, name, value) |
1842 |
- |
1843 |
- def intersects(self, other): |
1844 |
- """ |
1845 |
- Atoms with different cpv, operator or use attributes cause this method |
1846 |
- to return False even though there may actually be some intersection. |
1847 |
- TODO: Detect more forms of intersection. |
1848 |
- @param other: The package atom to match |
1849 |
- @type other: Atom |
1850 |
- @rtype: Boolean |
1851 |
- @return: True if this atom and the other atom intersect, |
1852 |
- False otherwise. |
1853 |
- """ |
1854 |
- if not isinstance(other, Atom): |
1855 |
- raise TypeError("expected %s, got %s" % \ |
1856 |
- (Atom, type(other))) |
1857 |
- |
1858 |
- if self == other: |
1859 |
- return True |
1860 |
- |
1861 |
- if self.cp != other.cp or \ |
1862 |
- self.use != other.use or \ |
1863 |
- self.operator != other.operator or \ |
1864 |
- self.cpv != other.cpv: |
1865 |
- return False |
1866 |
- |
1867 |
- if self.slot is None or \ |
1868 |
- other.slot is None or \ |
1869 |
- self.slot == other.slot: |
1870 |
- return True |
1871 |
- |
1872 |
- return False |
1873 |
- |
1874 |
- def evaluate_conditionals(self, use): |
1875 |
- """ |
1876 |
- Create an atom instance with any USE conditionals evaluated. |
1877 |
- @param use: The set of enabled USE flags |
1878 |
- @type use: set |
1879 |
- @rtype: Atom |
1880 |
- @return: an atom instance with any USE conditionals evaluated |
1881 |
- """ |
1882 |
- if not (self.use and self.use.conditional): |
1883 |
- return self |
1884 |
- atom = remove_slot(self) |
1885 |
- if self.slot: |
1886 |
- atom += ":%s" % self.slot |
1887 |
- atom += str(self.use.evaluate_conditionals(use)) |
1888 |
- return Atom(atom) |
1889 |
- |
1890 |
- def __copy__(self): |
1891 |
- """Immutable, so returns self.""" |
1892 |
- return self |
1893 |
- |
1894 |
- def __deepcopy__(self, memo=None): |
1895 |
- """Immutable, so returns self.""" |
1896 |
- memo[id(self)] = self |
1897 |
- return self |
1898 |
- |
1899 |
-def get_operator(mydep): |
1900 |
- """ |
1901 |
- Return the operator used in a depstring. |
1902 |
- |
1903 |
- Example usage: |
1904 |
- >>> from portage.dep import * |
1905 |
- >>> get_operator(">=test-1.0") |
1906 |
- '>=' |
1907 |
- |
1908 |
- @param mydep: The dep string to check |
1909 |
- @type mydep: String |
1910 |
- @rtype: String |
1911 |
- @return: The operator. One of: |
1912 |
- '~', '=', '>', '<', '=*', '>=', or '<=' |
1913 |
- """ |
1914 |
- if isinstance(mydep, Atom): |
1915 |
- return mydep.operator |
1916 |
- try: |
1917 |
- return Atom(mydep).operator |
1918 |
- except InvalidAtom: |
1919 |
- pass |
1920 |
- |
1921 |
- # Fall back to legacy code for backward compatibility. |
1922 |
- warnings.warn(_("%s is deprecated, use %s instead") % \ |
1923 |
- ('portage.dep.get_operator()', 'portage.dep.Atom.operator'), |
1924 |
- DeprecationWarning) |
1925 |
- operator = None |
1926 |
- if mydep: |
1927 |
- mydep = remove_slot(mydep) |
1928 |
- if not mydep: |
1929 |
- return None |
1930 |
- if mydep[0] == "~": |
1931 |
- operator = "~" |
1932 |
- elif mydep[0] == "=": |
1933 |
- if mydep[-1] == "*": |
1934 |
- operator = "=*" |
1935 |
- else: |
1936 |
- operator = "=" |
1937 |
- elif mydep[0] in "><": |
1938 |
- if len(mydep) > 1 and mydep[1] == "=": |
1939 |
- operator = mydep[0:2] |
1940 |
- else: |
1941 |
- operator = mydep[0] |
1942 |
- else: |
1943 |
- operator = None |
1944 |
- |
1945 |
- return operator |
1946 |
- |
1947 |
-def dep_getcpv(mydep): |
1948 |
- """ |
1949 |
- Return the category-package-version with any operators/slot specifications stripped off |
1950 |
- |
1951 |
- Example usage: |
1952 |
- >>> dep_getcpv('>=media-libs/test-3.0') |
1953 |
- 'media-libs/test-3.0' |
1954 |
- |
1955 |
- @param mydep: The depstring |
1956 |
- @type mydep: String |
1957 |
- @rtype: String |
1958 |
- @return: The depstring with the operator removed |
1959 |
- """ |
1960 |
- if isinstance(mydep, Atom): |
1961 |
- return mydep.cpv |
1962 |
- try: |
1963 |
- return Atom(mydep).cpv |
1964 |
- except InvalidAtom: |
1965 |
- pass |
1966 |
- |
1967 |
- # Fall back to legacy code for backward compatibility. |
1968 |
- warnings.warn(_("%s is deprecated, use %s instead") % \ |
1969 |
- ('portage.dep.dep_getcpv()', 'portage.dep.Atom.cpv'), |
1970 |
- DeprecationWarning, stacklevel=2) |
1971 |
- mydep_orig = mydep |
1972 |
- if mydep: |
1973 |
- mydep = remove_slot(mydep) |
1974 |
- if mydep and mydep[0] == "*": |
1975 |
- mydep = mydep[1:] |
1976 |
- if mydep and mydep[-1] == "*": |
1977 |
- mydep = mydep[:-1] |
1978 |
- if mydep and mydep[0] == "!": |
1979 |
- if mydep[1:2] == "!": |
1980 |
- mydep = mydep[2:] |
1981 |
- else: |
1982 |
- mydep = mydep[1:] |
1983 |
- if mydep[:2] in [">=", "<="]: |
1984 |
- mydep = mydep[2:] |
1985 |
- elif mydep[:1] in "=<>~": |
1986 |
- mydep = mydep[1:] |
1987 |
- return mydep |
1988 |
- |
1989 |
-def dep_getslot(mydep): |
1990 |
- """ |
1991 |
- Retrieve the slot on a depend. |
1992 |
- |
1993 |
- Example usage: |
1994 |
- >>> dep_getslot('app-misc/test:3') |
1995 |
- '3' |
1996 |
- |
1997 |
- @param mydep: The depstring to retrieve the slot of |
1998 |
- @type mydep: String |
1999 |
- @rtype: String |
2000 |
- @return: The slot |
2001 |
- """ |
2002 |
- slot = getattr(mydep, "slot", False) |
2003 |
- if slot is not False: |
2004 |
- return slot |
2005 |
- colon = mydep.find(":") |
2006 |
- if colon != -1: |
2007 |
- bracket = mydep.find("[", colon) |
2008 |
- if bracket == -1: |
2009 |
- return mydep[colon+1:] |
2010 |
- else: |
2011 |
- return mydep[colon+1:bracket] |
2012 |
- return None |
2013 |
- |
2014 |
-def remove_slot(mydep): |
2015 |
- """ |
2016 |
- Removes dep components from the right side of an atom: |
2017 |
- * slot |
2018 |
- * use |
2019 |
- * repo |
2020 |
- """ |
2021 |
- colon = mydep.find(":") |
2022 |
- if colon != -1: |
2023 |
- mydep = mydep[:colon] |
2024 |
- else: |
2025 |
- bracket = mydep.find("[") |
2026 |
- if bracket != -1: |
2027 |
- mydep = mydep[:bracket] |
2028 |
- return mydep |
2029 |
- |
2030 |
-def dep_getusedeps( depend ): |
2031 |
- """ |
2032 |
- Pull a listing of USE Dependencies out of a dep atom. |
2033 |
- |
2034 |
- Example usage: |
2035 |
- >>> dep_getusedeps('app-misc/test:3[foo,-bar]') |
2036 |
- ('foo', '-bar') |
2037 |
- |
2038 |
- @param depend: The depstring to process |
2039 |
- @type depend: String |
2040 |
- @rtype: List |
2041 |
- @return: List of use flags ( or [] if no flags exist ) |
2042 |
- """ |
2043 |
- use_list = [] |
2044 |
- open_bracket = depend.find('[') |
2045 |
- # -1 = failure (think c++ string::npos) |
2046 |
- comma_separated = False |
2047 |
- bracket_count = 0 |
2048 |
- while( open_bracket != -1 ): |
2049 |
- bracket_count += 1 |
2050 |
- if bracket_count > 1: |
2051 |
- raise InvalidAtom(_("USE Dependency with more " |
2052 |
- "than one set of brackets: %s") % (depend,)) |
2053 |
- close_bracket = depend.find(']', open_bracket ) |
2054 |
- if close_bracket == -1: |
2055 |
- raise InvalidAtom(_("USE Dependency with no closing bracket: %s") % depend ) |
2056 |
- use = depend[open_bracket + 1: close_bracket] |
2057 |
- # foo[1:1] may return '' instead of None, we don't want '' in the result |
2058 |
- if not use: |
2059 |
- raise InvalidAtom(_("USE Dependency with " |
2060 |
- "no use flag ([]): %s") % depend ) |
2061 |
- if not comma_separated: |
2062 |
- comma_separated = "," in use |
2063 |
- |
2064 |
- if comma_separated and bracket_count > 1: |
2065 |
- raise InvalidAtom(_("USE Dependency contains a mixture of " |
2066 |
- "comma and bracket separators: %s") % depend ) |
2067 |
- |
2068 |
- if comma_separated: |
2069 |
- for x in use.split(","): |
2070 |
- if x: |
2071 |
- use_list.append(x) |
2072 |
- else: |
2073 |
- raise InvalidAtom(_("USE Dependency with no use " |
2074 |
- "flag next to comma: %s") % depend ) |
2075 |
- else: |
2076 |
- use_list.append(use) |
2077 |
- |
2078 |
- # Find next use flag |
2079 |
- open_bracket = depend.find( '[', open_bracket+1 ) |
2080 |
- return tuple(use_list) |
2081 |
- |
2082 |
-# \w is [a-zA-Z0-9_] |
2083 |
- |
2084 |
-# 2.1.3 A slot name may contain any of the characters [A-Za-z0-9+_.-]. |
2085 |
-# It must not begin with a hyphen or a dot. |
2086 |
-_slot = r'([\w+][\w+.-]*)' |
2087 |
-_slot_re = re.compile('^' + _slot + '$', re.VERBOSE) |
2088 |
- |
2089 |
-_use = r'\[.*\]' |
2090 |
-_op = r'([=~]|[><]=?)' |
2091 |
- |
2092 |
-_atom_re = re.compile('^(?P<without_use>(?:' + |
2093 |
- '(?P<op>' + _op + _cpv + ')|' + |
2094 |
- '(?P<star>=' + _cpv + r'\*)|' + |
2095 |
- '(?P<simple>' + _cp + '))(:' + _slot + ')?)(' + _use + ')?$', re.VERBOSE) |
2096 |
- |
2097 |
-def isvalidatom(atom, allow_blockers=False): |
2098 |
- """ |
2099 |
- Check to see if a depend atom is valid |
2100 |
- |
2101 |
- Example usage: |
2102 |
- >>> isvalidatom('media-libs/test-3.0') |
2103 |
- False |
2104 |
- >>> isvalidatom('>=media-libs/test-3.0') |
2105 |
- True |
2106 |
- |
2107 |
- @param atom: The depend atom to check against |
2108 |
- @type atom: String or Atom |
2109 |
- @rtype: Boolean |
2110 |
- @return: One of the following: |
2111 |
- 1) False if the atom is invalid |
2112 |
- 2) True if the atom is valid |
2113 |
- """ |
2114 |
- try: |
2115 |
- if not isinstance(atom, Atom): |
2116 |
- atom = Atom(atom) |
2117 |
- if not allow_blockers and atom.blocker: |
2118 |
- return False |
2119 |
- return True |
2120 |
- except InvalidAtom: |
2121 |
- return False |
2122 |
- |
2123 |
-def isjustname(mypkg): |
2124 |
- """ |
2125 |
- Checks to see if the atom is only the package name (no version parts). |
2126 |
- |
2127 |
- Example usage: |
2128 |
- >>> isjustname('=media-libs/test-3.0') |
2129 |
- False |
2130 |
- >>> isjustname('media-libs/test') |
2131 |
- True |
2132 |
- |
2133 |
- @param mypkg: The package atom to check |
2134 |
- @param mypkg: String or Atom |
2135 |
- @rtype: Integer |
2136 |
- @return: One of the following: |
2137 |
- 1) False if the package string is not just the package name |
2138 |
- 2) True if it is |
2139 |
- """ |
2140 |
- try: |
2141 |
- if not isinstance(mypkg, Atom): |
2142 |
- mypkg = Atom(mypkg) |
2143 |
- return mypkg == mypkg.cp |
2144 |
- except InvalidAtom: |
2145 |
- pass |
2146 |
- |
2147 |
- for x in mypkg.split('-')[-2:]: |
2148 |
- if ververify(x): |
2149 |
- return False |
2150 |
- return True |
2151 |
- |
2152 |
-def isspecific(mypkg): |
2153 |
- """ |
2154 |
- Checks to see if a package is in =category/package-version or |
2155 |
- package-version format. |
2156 |
- |
2157 |
- Example usage: |
2158 |
- >>> isspecific('media-libs/test') |
2159 |
- False |
2160 |
- >>> isspecific('=media-libs/test-3.0') |
2161 |
- True |
2162 |
- |
2163 |
- @param mypkg: The package depstring to check against |
2164 |
- @type mypkg: String |
2165 |
- @rtype: Boolean |
2166 |
- @return: One of the following: |
2167 |
- 1) False if the package string is not specific |
2168 |
- 2) True if it is |
2169 |
- """ |
2170 |
- try: |
2171 |
- if not isinstance(mypkg, Atom): |
2172 |
- mypkg = Atom(mypkg) |
2173 |
- return mypkg != mypkg.cp |
2174 |
- except InvalidAtom: |
2175 |
- pass |
2176 |
- |
2177 |
- # Fall back to legacy code for backward compatibility. |
2178 |
- return not isjustname(mypkg) |
2179 |
- |
2180 |
-def dep_getkey(mydep): |
2181 |
- """ |
2182 |
- Return the category/package-name of a depstring. |
2183 |
- |
2184 |
- Example usage: |
2185 |
- >>> dep_getkey('=media-libs/test-3.0') |
2186 |
- 'media-libs/test' |
2187 |
- |
2188 |
- @param mydep: The depstring to retrieve the category/package-name of |
2189 |
- @type mydep: String |
2190 |
- @rtype: String |
2191 |
- @return: The package category/package-name |
2192 |
- """ |
2193 |
- if isinstance(mydep, Atom): |
2194 |
- return mydep.cp |
2195 |
- try: |
2196 |
- return Atom(mydep).cp |
2197 |
- except InvalidAtom: |
2198 |
- try: |
2199 |
- atom = Atom('=' + mydep) |
2200 |
- except InvalidAtom: |
2201 |
- pass |
2202 |
- else: |
2203 |
- warnings.warn(_("invalid input to %s: '%s', use %s instead") % \ |
2204 |
- ('portage.dep.dep_getkey()', mydep, 'portage.cpv_getkey()'), |
2205 |
- DeprecationWarning, stacklevel=2) |
2206 |
- return atom.cp |
2207 |
- |
2208 |
- # Fall back to legacy code for backward compatibility. |
2209 |
- warnings.warn(_("%s is deprecated, use %s instead") % \ |
2210 |
- ('portage.dep.dep_getkey()', 'portage.dep.Atom.cp'), |
2211 |
- DeprecationWarning, stacklevel=2) |
2212 |
- mydep = dep_getcpv(mydep) |
2213 |
- if mydep and isspecific(mydep): |
2214 |
- mysplit = catpkgsplit(mydep) |
2215 |
- if not mysplit: |
2216 |
- return mydep |
2217 |
- return mysplit[0] + "/" + mysplit[1] |
2218 |
- else: |
2219 |
- return mydep |
2220 |
- |
2221 |
-def match_to_list(mypkg, mylist): |
2222 |
- """ |
2223 |
- Searches list for entries that matches the package. |
2224 |
- |
2225 |
- @param mypkg: The package atom to match |
2226 |
- @type mypkg: String |
2227 |
- @param mylist: The list of package atoms to compare against |
2228 |
- @param mylist: List |
2229 |
- @rtype: List |
2230 |
- @return: A unique list of package atoms that match the given package atom |
2231 |
- """ |
2232 |
- return [ x for x in set(mylist) if match_from_list(x, [mypkg]) ] |
2233 |
- |
2234 |
-def best_match_to_list(mypkg, mylist): |
2235 |
- """ |
2236 |
- Returns the most specific entry that matches the package given. |
2237 |
- |
2238 |
- @param mypkg: The package atom to check |
2239 |
- @type mypkg: String |
2240 |
- @param mylist: The list of package atoms to check against |
2241 |
- @type mylist: List |
2242 |
- @rtype: String |
2243 |
- @return: The package atom which best matches given the following ordering: |
2244 |
- - =cpv 6 |
2245 |
- - ~cpv 5 |
2246 |
- - =cpv* 4 |
2247 |
- - cp:slot 3 |
2248 |
- - >cpv 2 |
2249 |
- - <cpv 2 |
2250 |
- - >=cpv 2 |
2251 |
- - <=cpv 2 |
2252 |
- - cp 1 |
2253 |
- """ |
2254 |
- operator_values = {'=':6, '~':5, '=*':4, |
2255 |
- '>':2, '<':2, '>=':2, '<=':2, None:1} |
2256 |
- maxvalue = 0 |
2257 |
- bestm = None |
2258 |
- for x in match_to_list(mypkg, mylist): |
2259 |
- if dep_getslot(x) is not None: |
2260 |
- if maxvalue < 3: |
2261 |
- maxvalue = 3 |
2262 |
- bestm = x |
2263 |
- op_val = operator_values[x.operator] |
2264 |
- if op_val > maxvalue: |
2265 |
- maxvalue = op_val |
2266 |
- bestm = x |
2267 |
- return bestm |
2268 |
- |
2269 |
-def match_from_list(mydep, candidate_list): |
2270 |
- """ |
2271 |
- Searches list for entries that matches the package. |
2272 |
- |
2273 |
- @param mydep: The package atom to match |
2274 |
- @type mydep: String |
2275 |
- @param candidate_list: The list of package atoms to compare against |
2276 |
- @param candidate_list: List |
2277 |
- @rtype: List |
2278 |
- @return: A list of package atoms that match the given package atom |
2279 |
- """ |
2280 |
- |
2281 |
- if not candidate_list: |
2282 |
- return [] |
2283 |
- |
2284 |
- from portage.util import writemsg |
2285 |
- if "!" == mydep[:1]: |
2286 |
- mydep = mydep[1:] |
2287 |
- if not isinstance(mydep, Atom): |
2288 |
- mydep = Atom(mydep) |
2289 |
- |
2290 |
- mycpv = mydep.cpv |
2291 |
- mycpv_cps = catpkgsplit(mycpv) # Can be None if not specific |
2292 |
- slot = mydep.slot |
2293 |
- |
2294 |
- if not mycpv_cps: |
2295 |
- cat, pkg = catsplit(mycpv) |
2296 |
- ver = None |
2297 |
- rev = None |
2298 |
- else: |
2299 |
- cat, pkg, ver, rev = mycpv_cps |
2300 |
- if mydep == mycpv: |
2301 |
- raise KeyError(_("Specific key requires an operator" |
2302 |
- " (%s) (try adding an '=')") % (mydep)) |
2303 |
- |
2304 |
- if ver and rev: |
2305 |
- operator = mydep.operator |
2306 |
- if not operator: |
2307 |
- writemsg(_("!!! Invalid atom: %s\n") % mydep, noiselevel=-1) |
2308 |
- return [] |
2309 |
- else: |
2310 |
- operator = None |
2311 |
- |
2312 |
- mylist = [] |
2313 |
- |
2314 |
- if operator is None: |
2315 |
- for x in candidate_list: |
2316 |
- cp = getattr(x, "cp", None) |
2317 |
- if cp is None: |
2318 |
- mysplit = catpkgsplit(remove_slot(x)) |
2319 |
- if mysplit is not None: |
2320 |
- cp = mysplit[0] + '/' + mysplit[1] |
2321 |
- if cp != mycpv: |
2322 |
- continue |
2323 |
- mylist.append(x) |
2324 |
- |
2325 |
- elif operator == "=": # Exact match |
2326 |
- for x in candidate_list: |
2327 |
- xcpv = getattr(x, "cpv", None) |
2328 |
- if xcpv is None: |
2329 |
- xcpv = remove_slot(x) |
2330 |
- if not cpvequal(xcpv, mycpv): |
2331 |
- continue |
2332 |
- mylist.append(x) |
2333 |
- |
2334 |
- elif operator == "=*": # glob match |
2335 |
- # XXX: Nasty special casing for leading zeros |
2336 |
- # Required as =* is a literal prefix match, so can't |
2337 |
- # use vercmp |
2338 |
- mysplit = catpkgsplit(mycpv) |
2339 |
- myver = mysplit[2].lstrip("0") |
2340 |
- if not myver or not myver[0].isdigit(): |
2341 |
- myver = "0"+myver |
2342 |
- mycpv = mysplit[0]+"/"+mysplit[1]+"-"+myver |
2343 |
- for x in candidate_list: |
2344 |
- xs = getattr(x, "cpv_split", None) |
2345 |
- if xs is None: |
2346 |
- xs = catpkgsplit(remove_slot(x)) |
2347 |
- myver = xs[2].lstrip("0") |
2348 |
- if not myver or not myver[0].isdigit(): |
2349 |
- myver = "0"+myver |
2350 |
- xcpv = xs[0]+"/"+xs[1]+"-"+myver |
2351 |
- if xcpv.startswith(mycpv): |
2352 |
- mylist.append(x) |
2353 |
- |
2354 |
- elif operator == "~": # version, any revision, match |
2355 |
- for x in candidate_list: |
2356 |
- xs = getattr(x, "cpv_split", None) |
2357 |
- if xs is None: |
2358 |
- xs = catpkgsplit(remove_slot(x)) |
2359 |
- if xs is None: |
2360 |
- raise InvalidData(x) |
2361 |
- if not cpvequal(xs[0]+"/"+xs[1]+"-"+xs[2], mycpv_cps[0]+"/"+mycpv_cps[1]+"-"+mycpv_cps[2]): |
2362 |
- continue |
2363 |
- if xs[2] != ver: |
2364 |
- continue |
2365 |
- mylist.append(x) |
2366 |
- |
2367 |
- elif operator in [">", ">=", "<", "<="]: |
2368 |
- mysplit = ["%s/%s" % (cat, pkg), ver, rev] |
2369 |
- for x in candidate_list: |
2370 |
- xs = getattr(x, "cpv_split", None) |
2371 |
- if xs is None: |
2372 |
- xs = catpkgsplit(remove_slot(x)) |
2373 |
- xcat, xpkg, xver, xrev = xs |
2374 |
- xs = ["%s/%s" % (xcat, xpkg), xver, xrev] |
2375 |
- try: |
2376 |
- result = pkgcmp(xs, mysplit) |
2377 |
- except ValueError: # pkgcmp may return ValueError during int() conversion |
2378 |
- writemsg(_("\nInvalid package name: %s\n") % x, noiselevel=-1) |
2379 |
- raise |
2380 |
- if result is None: |
2381 |
- continue |
2382 |
- elif operator == ">": |
2383 |
- if result > 0: |
2384 |
- mylist.append(x) |
2385 |
- elif operator == ">=": |
2386 |
- if result >= 0: |
2387 |
- mylist.append(x) |
2388 |
- elif operator == "<": |
2389 |
- if result < 0: |
2390 |
- mylist.append(x) |
2391 |
- elif operator == "<=": |
2392 |
- if result <= 0: |
2393 |
- mylist.append(x) |
2394 |
- else: |
2395 |
- raise KeyError(_("Unknown operator: %s") % mydep) |
2396 |
- else: |
2397 |
- raise KeyError(_("Unknown operator: %s") % mydep) |
2398 |
- |
2399 |
- if slot is not None: |
2400 |
- candidate_list = mylist |
2401 |
- mylist = [] |
2402 |
- for x in candidate_list: |
2403 |
- xslot = getattr(x, "slot", False) |
2404 |
- if xslot is False: |
2405 |
- xslot = dep_getslot(x) |
2406 |
- if xslot is not None and xslot != slot: |
2407 |
- continue |
2408 |
- mylist.append(x) |
2409 |
- |
2410 |
- if mydep.use: |
2411 |
- candidate_list = mylist |
2412 |
- mylist = [] |
2413 |
- for x in candidate_list: |
2414 |
- use = getattr(x, "use", None) |
2415 |
- if use is not None: |
2416 |
- regex = x.iuse.regex |
2417 |
- missing_iuse = False |
2418 |
- for y in mydep.use.required: |
2419 |
- if regex.match(y) is None: |
2420 |
- missing_iuse = True |
2421 |
- break |
2422 |
- if missing_iuse: |
2423 |
- continue |
2424 |
- if mydep.use.enabled.difference(use.enabled): |
2425 |
- continue |
2426 |
- if mydep.use.disabled.intersection(use.enabled): |
2427 |
- continue |
2428 |
- mylist.append(x) |
2429 |
- |
2430 |
- return mylist |