1 |
commit: ac3164b4c26124636e97d5c7d320d9e07f39a10a |
2 |
Author: André Erdmann <dywi <AT> mailerd <DOT> de> |
3 |
AuthorDate: Fri Mar 1 18:54:20 2013 +0000 |
4 |
Commit: André Erdmann <dywi <AT> mailerd <DOT> de> |
5 |
CommitDate: Fri Mar 1 18:54:20 2013 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=ac3164b4 |
7 |
|
8 |
packagerules/parser: use line number as priority |
9 |
|
10 |
This commit adds stable/reliable sorting for package rules (rule-,match- and |
11 |
action-blocks). The order of the rule entries will be exactly the same as in |
12 |
the rule file(s). |
13 |
|
14 |
--- |
15 |
roverlay/packagerules/abstract/acceptors.py | 2 +- |
16 |
roverlay/packagerules/abstract/rules.py | 2 +- |
17 |
roverlay/packagerules/parser/context/action.py | 6 ++- |
18 |
roverlay/packagerules/parser/context/match.py | 52 +++++++++++++++++------- |
19 |
roverlay/packagerules/parser/context/rule.py | 46 ++++++++++++++------- |
20 |
roverlay/packagerules/parser/text.py | 16 ++++--- |
21 |
6 files changed, 82 insertions(+), 42 deletions(-) |
22 |
|
23 |
diff --git a/roverlay/packagerules/abstract/acceptors.py b/roverlay/packagerules/abstract/acceptors.py |
24 |
index 4533f37..6698a10 100644 |
25 |
--- a/roverlay/packagerules/abstract/acceptors.py |
26 |
+++ b/roverlay/packagerules/abstract/acceptors.py |
27 |
@@ -122,9 +122,9 @@ class _AcceptorCompound ( Acceptor ): |
28 |
Raises: EmptyAcceptorError |
29 |
""" |
30 |
if len ( self._acceptors ) > 0: |
31 |
- self._acceptors = roverlay.util.priosort ( self._acceptors ) |
32 |
for acceptor in self._acceptors: |
33 |
acceptor.prepare() |
34 |
+ self._acceptors = roverlay.util.priosort ( self._acceptors ) |
35 |
else: |
36 |
raise EmptyAcceptorError() |
37 |
# --- end of prepare (...) --- |
38 |
|
39 |
diff --git a/roverlay/packagerules/abstract/rules.py b/roverlay/packagerules/abstract/rules.py |
40 |
index 80a7d62..af33bc7 100644 |
41 |
--- a/roverlay/packagerules/abstract/rules.py |
42 |
+++ b/roverlay/packagerules/abstract/rules.py |
43 |
@@ -196,9 +196,9 @@ class NestedPackageRule ( PackageRule ): |
44 |
Prepares this rule for usage. Has to be called after adding actions. |
45 |
""" |
46 |
super ( NestedPackageRule, self ).prepare() |
47 |
- self._rules = roverlay.util.priosort ( self._rules ) |
48 |
for rule in self._rules: |
49 |
rule.prepare() |
50 |
+ self._rules = roverlay.util.priosort ( self._rules ) |
51 |
# --- end of prepare (...) --- |
52 |
|
53 |
def apply_actions ( self, p_info ): |
54 |
|
55 |
diff --git a/roverlay/packagerules/parser/context/action.py b/roverlay/packagerules/parser/context/action.py |
56 |
index 91f97b6..ff5876c 100644 |
57 |
--- a/roverlay/packagerules/parser/context/action.py |
58 |
+++ b/roverlay/packagerules/parser/context/action.py |
59 |
@@ -41,11 +41,12 @@ class RuleActionContext ( |
60 |
self._actions = list() |
61 |
# --- end of __init__ (...) --- |
62 |
|
63 |
- def feed ( self, _str ): |
64 |
+ def feed ( self, _str, lino ): |
65 |
"""Feeds this action block with input. |
66 |
|
67 |
arguments: |
68 |
* _str -- |
69 |
+ * lino -- |
70 |
|
71 |
Raises: |
72 |
* InvalidContext |
73 |
@@ -72,7 +73,8 @@ class RuleActionContext ( |
74 |
self._actions.append ( |
75 |
self.namespace.get_object ( |
76 |
evar_cls, |
77 |
- roverlay.strutil.unquote ( argv [1] ) |
78 |
+ roverlay.strutil.unquote ( argv [1] ), |
79 |
+ lino |
80 |
) |
81 |
) |
82 |
else: |
83 |
|
84 |
diff --git a/roverlay/packagerules/parser/context/match.py b/roverlay/packagerules/parser/context/match.py |
85 |
index b6e2849..bd7f9ab 100644 |
86 |
--- a/roverlay/packagerules/parser/context/match.py |
87 |
+++ b/roverlay/packagerules/parser/context/match.py |
88 |
@@ -102,21 +102,41 @@ class RuleMatchContext ( |
89 |
), |
90 |
} |
91 |
|
92 |
- def __init__ ( self, namespace, level=0, bool_type=None ): |
93 |
+ def __init__ ( self, namespace, level=0, bool_type=None, priority=-1 ): |
94 |
+ """RuleMatchContext constructor. |
95 |
+ |
96 |
+ arguments: |
97 |
+ * namespace -- the rule parser's namespace |
98 |
+ * level -- the depth of this context |
99 |
+ * bool_type -- integer that sets the boolean type of this match |
100 |
+ context (see BOOL_* above, e.g. BOOL_AND) |
101 |
+ * priority -- priority of this match block (used for sorting) |
102 |
+ """ |
103 |
super ( RuleMatchContext, self ).__init__ ( |
104 |
namespace = namespace, |
105 |
level = level, |
106 |
) |
107 |
+ |
108 |
# match statements defined for this instance (nested ones, e.g. ORed, |
109 |
# are in self._nested) |
110 |
self._bool_type = ( |
111 |
bool_type if bool_type is not None else self.BOOL_AND |
112 |
) |
113 |
- self._matches = list() |
114 |
- self._active = True |
115 |
+ self.priority = priority |
116 |
+ self._matches = list() |
117 |
+ self._active = True |
118 |
# --- end of __init__ (...) --- |
119 |
|
120 |
- def _feed ( self, s, match_depth ): |
121 |
+ def _feed ( self, s, match_depth, lino ): |
122 |
+ """(Actually) feeds a match block with text input, either this one |
123 |
+ (if match_depth is self.level) or a nested one. |
124 |
+ |
125 |
+ arguments: |
126 |
+ * s -- preparsed input (a match statement), |
127 |
+ whitespace and match depth indicators removed |
128 |
+ * match_depth -- the depth of the match statement |
129 |
+ * lino -- line number |
130 |
+ """ |
131 |
assert match_depth >= self.level |
132 |
|
133 |
if not self._active: |
134 |
@@ -129,16 +149,16 @@ class RuleMatchContext ( |
135 |
s_low = s.lower() |
136 |
|
137 |
if s_low in self.KEYWORDS_AND: |
138 |
- self._new_nested ( bool_type=self.BOOL_AND ) |
139 |
+ self._new_nested ( bool_type=self.BOOL_AND, priority=lino ) |
140 |
|
141 |
elif s_low in self.KEYWORDS_OR: |
142 |
- self._new_nested ( bool_type=self.BOOL_OR ) |
143 |
+ self._new_nested ( bool_type=self.BOOL_OR, priority=lino ) |
144 |
|
145 |
elif s_low in self.KEYWORDS_XOR1: |
146 |
- self._new_nested ( bool_type=self.BOOL_XOR1 ) |
147 |
+ self._new_nested ( bool_type=self.BOOL_XOR1, priority=lino ) |
148 |
|
149 |
elif s_low in self.KEYWORDS_NOR: |
150 |
- self._new_nested ( bool_type=self.BOOL_NOR ) |
151 |
+ self._new_nested ( bool_type=self.BOOL_NOR, priority=lino ) |
152 |
|
153 |
else: |
154 |
if self._nested: |
155 |
@@ -159,7 +179,7 @@ class RuleMatchContext ( |
156 |
raise NoSuchMatchStatement ( s, "invalid arg count" ) |
157 |
|
158 |
elif argc == 3: |
159 |
- #if argc >= 3: |
160 |
+ #elif argc >= 3: |
161 |
# <keyword> <op> <arg> |
162 |
|
163 |
if argv [1] in self.OP_STRING_EXACT: |
164 |
@@ -194,7 +214,7 @@ class RuleMatchContext ( |
165 |
self._matches.append ( |
166 |
self.namespace.get_object ( |
167 |
op, |
168 |
- 100, |
169 |
+ lino, |
170 |
match_type [1], |
171 |
value |
172 |
) |
173 |
@@ -202,34 +222,36 @@ class RuleMatchContext ( |
174 |
|
175 |
else: |
176 |
try: |
177 |
- return self.get_nested()._feed ( s, match_depth ) |
178 |
+ return self.get_nested()._feed ( s, match_depth, lino ) |
179 |
except IndexError: |
180 |
raise MatchDepthError ( self.level, match_depth ) |
181 |
# --- end of _feed (...) --- |
182 |
|
183 |
def create ( self ): |
184 |
"""Creates and returns an acceptor for this match block.""" |
185 |
- acceptor = self._BOOL_MAP [self._bool_type] ( priority=100 ) |
186 |
+ |
187 |
+ acceptor = self._BOOL_MAP [self._bool_type] ( priority=self.priority ) |
188 |
|
189 |
for match in self._matches: |
190 |
acceptor.add_acceptor ( match ) |
191 |
|
192 |
for nested in self._nested: |
193 |
- acceptor.add_acceptor ( nested.create() ) |
194 |
+ acceptor.add_acceptor ( nested.create() ) |
195 |
|
196 |
return acceptor |
197 |
# --- end of create (...) --- |
198 |
|
199 |
- def feed ( self, _str ): |
200 |
+ def feed ( self, _str, lino ): |
201 |
"""Feeds a match block with input. |
202 |
|
203 |
arguments: |
204 |
* _str -- |
205 |
+ * lino -- |
206 |
""" |
207 |
# prepare _str for the actual _feed() function |
208 |
# * determine match depth |
209 |
s = _str.lstrip ( self.MATCH_DEPTH_CHARS ) |
210 |
- return self._feed ( s.lstrip(), len ( _str ) - len ( s ) ) |
211 |
+ return self._feed ( s.lstrip(), len ( _str ) - len ( s ), lino ) |
212 |
# --- end of feed (...) --- |
213 |
|
214 |
# --- end of RuleMatchContext --- |
215 |
|
216 |
diff --git a/roverlay/packagerules/parser/context/rule.py b/roverlay/packagerules/parser/context/rule.py |
217 |
index dd1a07b..f14faf6 100644 |
218 |
--- a/roverlay/packagerules/parser/context/rule.py |
219 |
+++ b/roverlay/packagerules/parser/context/rule.py |
220 |
@@ -42,17 +42,24 @@ class RuleContext ( base.NestableContext ): |
221 |
|
222 |
# -- end of CONTEXT_ -- |
223 |
|
224 |
- def __init__ ( self, namespace, level=0 ): |
225 |
+ def __init__ ( self, namespace, level=0, priority=-1 ): |
226 |
super ( RuleContext, self ).__init__ ( namespace, level ) |
227 |
|
228 |
self.context = self.CONTEXT_MAIN_MATCH |
229 |
- self._match_context = match.RuleMatchContext ( self.namespace ) |
230 |
+ self.priority = priority |
231 |
self._action_context = action.RuleActionContext ( self.namespace ) |
232 |
+ self._match_context = match.RuleMatchContext ( |
233 |
+ namespace = self.namespace, |
234 |
+ priority = priority |
235 |
+ ) |
236 |
# --- end of __init__ (...) --- |
237 |
|
238 |
- def begin_match ( self ): |
239 |
+ def begin_match ( self, lino ): |
240 |
"""Create/begin a match-block of a nested rule. |
241 |
|
242 |
+ arguments: |
243 |
+ * lino -- line number |
244 |
+ |
245 |
Raises: InvalidContext, |
246 |
match-blocks are only allowed within an action-block |
247 |
""" |
248 |
@@ -61,21 +68,24 @@ class RuleContext ( base.NestableContext ): |
249 |
|
250 |
if self.context & self.CONTEXT_MAIN_ACTION: |
251 |
# a nested rule (with depth = 1) |
252 |
- self._new_nested() |
253 |
+ self._new_nested ( priority=lino ) |
254 |
self.context = self.CONTEXT_SUB_MATCH |
255 |
elif self.context & self.CONTEXT_SUB_ACTION: |
256 |
# a nested rule inside a nested one (depth > 1) |
257 |
# => redirect to nested |
258 |
- self.get_nested().begin_match() |
259 |
+ self.get_nested().begin_match ( lino ) |
260 |
self.context = self.CONTEXT_SUB_MATCH |
261 |
else: |
262 |
# illegal |
263 |
raise self.InvalidContext() |
264 |
# --- end of begin_match (...) --- |
265 |
|
266 |
- def begin_action ( self ): |
267 |
+ def begin_action ( self, lino ): |
268 |
"""Create/begin an action block of a rule (nested or "self"). |
269 |
|
270 |
+ arguments: |
271 |
+ * lino -- line number |
272 |
+ |
273 |
Raises: InvalidContext, |
274 |
an action-block has to be preceeded by a match-block |
275 |
""" |
276 |
@@ -85,14 +95,14 @@ class RuleContext ( base.NestableContext ): |
277 |
elif self.context & self.CONTEXT_SUB_MATCH: |
278 |
# action-block of a nested rule |
279 |
# => redirect to nested |
280 |
- self.get_nested().begin_action() |
281 |
+ self.get_nested().begin_action ( lino ) |
282 |
self.context = self.CONTEXT_SUB_ACTION |
283 |
else: |
284 |
# illegal |
285 |
raise self.InvalidContext() |
286 |
# --- end of begin_action (...) --- |
287 |
|
288 |
- def end_of_rule ( self ): |
289 |
+ def end_of_rule ( self, lino ): |
290 |
"""Has to be called whenever an end-of-rule statement has been reached |
291 |
and ends a rule, either this one or a nested one (depending on the |
292 |
context). |
293 |
@@ -100,6 +110,9 @@ class RuleContext ( base.NestableContext ): |
294 |
Returns True if this rule has been ended, else False (end of a nested |
295 |
rule). |
296 |
|
297 |
+ arguments: |
298 |
+ * lino -- line number |
299 |
+ |
300 |
Raises: InvalidContext, |
301 |
rules can only be closed if within an action-block |
302 |
""" |
303 |
@@ -108,7 +121,7 @@ class RuleContext ( base.NestableContext ): |
304 |
self.context = self.CONTEXT_NONE |
305 |
return True |
306 |
elif self.context & self.CONTEXT_SUB_ACTION: |
307 |
- if self.get_nested().end_of_rule(): |
308 |
+ if self.get_nested().end_of_rule ( lino ): |
309 |
# end of child rule (depth=1) |
310 |
self.context = self.CONTEXT_MAIN_ACTION |
311 |
|
312 |
@@ -122,21 +135,22 @@ class RuleContext ( base.NestableContext ): |
313 |
raise self.InvalidContext() |
314 |
# --- end of end_of_rule (...) --- |
315 |
|
316 |
- def feed ( self, _str ): |
317 |
+ def feed ( self, _str, lino ): |
318 |
"""Feed this rule with input (text). |
319 |
|
320 |
arguments: |
321 |
* _str -- |
322 |
+ * lino -- line number |
323 |
|
324 |
Raises: InvalidContext if this rule does not accept input |
325 |
(if self.context is CONTEXT_NONE) |
326 |
""" |
327 |
if self.context & self.CONTEXT_MAIN_MATCH: |
328 |
- return self._match_context.feed ( _str ) |
329 |
+ return self._match_context.feed ( _str, lino ) |
330 |
elif self.context & self.CONTEXT_MAIN_ACTION: |
331 |
- return self._action_context.feed ( _str ) |
332 |
+ return self._action_context.feed ( _str, lino ) |
333 |
elif self.context & self.CONTEXT_SUB: |
334 |
- return self.get_nested().feed ( _str ) |
335 |
+ return self.get_nested().feed ( _str, lino ) |
336 |
else: |
337 |
raise self.InvalidContext() |
338 |
# --- end of feed (...) --- |
339 |
@@ -171,7 +185,7 @@ class RuleContext ( base.NestableContext ): |
340 |
"ignore action-block cannot contain nested rules." |
341 |
) |
342 |
else: |
343 |
- package_rule = rules.NestedPackageRule() |
344 |
+ package_rule = rules.NestedPackageRule ( priority=self.priority ) |
345 |
for nested in self._nested: |
346 |
package_rule.add_rule ( nested.create() ) |
347 |
|
348 |
@@ -180,11 +194,11 @@ class RuleContext ( base.NestableContext ): |
349 |
|
350 |
elif actions is None: |
351 |
# ignore rule |
352 |
- package_rule = rules.IgnorePackageRule() |
353 |
+ package_rule = rules.IgnorePackageRule ( priority=self.priority ) |
354 |
|
355 |
elif actions: |
356 |
# normal rule |
357 |
- package_rule = rules.PackageRule() |
358 |
+ package_rule = rules.PackageRule ( priority=self.priority ) |
359 |
|
360 |
for action in actions: |
361 |
package_rule.add_action ( action ) |
362 |
|
363 |
diff --git a/roverlay/packagerules/parser/text.py b/roverlay/packagerules/parser/text.py |
364 |
index 968729e..6badc58 100644 |
365 |
--- a/roverlay/packagerules/parser/text.py |
366 |
+++ b/roverlay/packagerules/parser/text.py |
367 |
@@ -11,7 +11,7 @@ class RuleParser ( object ): |
368 |
|
369 |
class NotParseable ( ValueError ): |
370 |
def __init__ ( self, line, lino ): |
371 |
- super ( NotParseable, self ).__init__ ( |
372 |
+ super ( RuleParser.NotParseable, self ).__init__ ( |
373 |
"in line {}: cannot parse '{}'.".format ( lino, line ) |
374 |
) |
375 |
# --- end of __init__ (...) --- |
376 |
@@ -56,22 +56,23 @@ class RuleParser ( object ): |
377 |
if len ( l ) > 0 and l[0] not in self.COMMENT_CHARS: |
378 |
if self._current_rule: |
379 |
if l in self.KEYWORDS_MATCH: |
380 |
- self._current_rule.begin_match() |
381 |
+ self._current_rule.begin_match ( lino ) |
382 |
elif l in self.KEYWORDS_ACTION: |
383 |
- self._current_rule.begin_action() |
384 |
+ self._current_rule.begin_action ( lino ) |
385 |
elif l in self.KEYWORDS_END: |
386 |
- if self._current_rule.end_of_rule(): |
387 |
+ if self._current_rule.end_of_rule ( lino ): |
388 |
# add rule to self._parsed_rules |
389 |
self._parsed_rules.append ( self._current_rule ) |
390 |
self._current_rule = None |
391 |
# else end of a nested rule, do nothing |
392 |
else: |
393 |
- self._current_rule.feed ( l ) |
394 |
+ self._current_rule.feed ( l, lino ) |
395 |
|
396 |
elif l in self.KEYWORDS_MATCH: |
397 |
self._current_rule = ( |
398 |
roverlay.packagerules.parser.context.rule.RuleContext ( |
399 |
- self.namespace |
400 |
+ self.namespace, |
401 |
+ priority=lino |
402 |
) |
403 |
) |
404 |
|
405 |
@@ -101,7 +102,8 @@ class RuleParser ( object ): |
406 |
|
407 |
with open ( rule_file, 'r' ) as FH: |
408 |
for lino, line in enumerate ( FH.readlines() ): |
409 |
- self._feed ( line.strip(), lino ) |
410 |
+ # ^lino := 0..(n-1), add +1 |
411 |
+ self._feed ( line.strip(), lino + 1 ) |
412 |
|
413 |
for rule in self._create(): |
414 |
self.add_rule ( rule ) |