1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
# Copyright: 2005 Gentoo Foundation
# Author(s): Jason Stubbs (jstubbs@gentoo.org), Brian Harring (ferringb@gentoo.org)
# License: GPL2
# $Header: /local/data/ulm/cvs/history/var/cvsroot/gentoo-src/portage/portage/ebuild/conditionals.py,v 1.4 2005/08/09 07:53:33 ferringb Exp $
# TODO: move exceptions elsewhere, bind them to a base exception for portage
import logging
from portage.restrictions.restrictionSet import RestrictionSet, OrRestrictionSet
from portage.util.strings import iter_tokens
from portage.package.conditionals import base as Conditional
def conditional_converter(node, payload):
if node[0] == "!":
return Conditional(node[1:], payload, negate=True)
return Conditional(node, payload)
class DepSet(RestrictionSet):
__slots__ = tuple(["has_conditionals", "conditional_class"] + list(RestrictionSet.__slots__))
def __init__(self, dep_str, element_func, operators={"||":OrRestrictionSet}, \
conditional_converter=conditional_converter, conditional_class=Conditional, empty=False):
"""dep_str is a dep style syntax, element_func is a callable returning the obj for each element, and
cleanse_string controls whether or translation of tabs/newlines is required"""
super(DepSet, self).__init__()
self.conditional_class = conditional_class
if empty: return
# anyone who uses this routine as fodder for pushing a rewrite in lisp I reserve the right to deliver an
# atomic wedgie upon.
# ~harring
conditionals, depsets, has_conditionals = [], [self], [False]
words = iter_tokens(dep_str)
try:
for k in words:
if k == ")":
# no elements == error. if closures don't map up, indexerror would be chucked from trying to pop the frame
# so that is addressed.
if len(depsets[-1].restrictions) == 0:
raise ParseError(dep_str)
elif conditionals[-1].endswith('?'):
depsets[-2].restrictions.append(conditional_converter(conditionals.pop(-1)[:-1], depsets[-1]))
else:
depsets[-2].restrictions.append(operators[conditionals.pop(-1)](depsets[-1]))
if not has_conditionals[-2]:
has_conditionals[-2] = has_conditionals[-1]
depsets[-1].has_conditionals = has_conditionals.pop(-1)
depsets.pop(-1)
elif k.endswith('?') or k in operators:
# use conditional or custom op. no tokens left == bad dep_str.
try: k2 = words.next()
except StopIteration: k2 = ''
if k2 != "(":
raise ParseError(dep_str)
# push another frame on
depsets.append(self.__class__(None, element_func, empty=True, conditional_converter=conditional_converter,
conditional_class=self.conditional_class))
conditionals.append(k)
if k.endswith("?"):
has_conditionals[-1] = True
has_conditionals.append(False)
else:
# node/element.
depsets[-1].restrictions.append(element_func(k))
except IndexError:
# [][-1] for a frame access, which means it was a parse error.
raise ParseError(dep_str)
# check if any closures required
if len(depsets) != 1:
raise ParseError(dep_str)
self.has_conditionals = has_conditionals[0]
def __str__(self): return ' '.join(map(str,self.restrictions))
def evaluate_depset(self, cond_dict):
"""passed in a depset, does lookups of the node in cond_dict.
no entry in cond_dict == conditional is off, else the bool value of the key's val in cond_dict"""
if not self.has_conditionals: return self
flat_deps = DepSet("", str)
stack = [self.restrictions]
while len(stack) != 0:
for node in stack[0]:
if isinstance(node, self.conditional_class):
if node.cond in cond_dict:
if not node.negate:
stack.append(node.restrictions)
elif node.negate:
stack.append(node.restrictions)
else:
flat_deps.restrictions.append(node)
stack.pop(0)
return flat_deps
class ParseError(Exception):
def __init__(self, s): self.dep_str = s
def __str__(self): return "%s is unparseable" % self.s
|