Gentoo Archives: gentoo-commits

From: "André Erdmann" <dywi@×××××××.de>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, ...
Date: Thu, 01 Aug 2013 12:45:01
Message-Id: 1375360359.703b273c1559be91ad2e7eeceff1b963e0f91e8a.dywi@gentoo
1 commit: 703b273c1559be91ad2e7eeceff1b963e0f91e8a
2 Author: André Erdmann <dywi <AT> mailerd <DOT> de>
3 AuthorDate: Thu Aug 1 12:32:39 2013 +0000
4 Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
5 CommitDate: Thu Aug 1 12:32:39 2013 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=703b273c
7
8 package rules, syntax: support else-action block
9
10 Package rules can now declare an ELSE: block (following the ACTION: block) whose
11 action statements are executed if the rule's MATCH: block did not match a
12 package.
13
14 "ELSE IF" statements are not supported, but can be realized by placing a nested
15 rule in the ELSE: block.
16
17 Other changes:
18 * "null"/"pass" action statement. A no-op statement (removed at rule "compile"
19 time) which can be used to improve readability (e.g. if a rule has no actions
20 in the ACTION: block)
21 * "do-not-process"/"ignore" is now available as action (in addition to the
22 hard-wired IgnorePackageRule class). The rule parser chooses the "correct"
23 implementation (which depends on the rule).
24 An "do-not-process if <matches...> else do-not-process" rule is forbidden.
25 (As "workaround", it can be achieved via "do-not-process if <always true
26 condition>.)
27 * minor fix in RuleActionContext.feed() concerning arg count
28 * the rule context (responsible for parsing a single rule) manipulates its
29 status bitmask (bitwise-AND/OR) now instead of setting it directly
30
31 ---
32 roverlay/packagerules/abstract/actions.py | 2 +
33 roverlay/packagerules/abstract/rules.py | 181 ++++++++++++++++---
34 roverlay/packagerules/acceptors/stringmatch.py | 6 +-
35 roverlay/packagerules/actions/evar.py | 2 +-
36 roverlay/packagerules/actions/ignore.py | 25 +++
37 roverlay/packagerules/actions/info.py | 4 +-
38 roverlay/packagerules/actions/trace.py | 4 +-
39 roverlay/packagerules/parser/context/action.py | 18 +-
40 roverlay/packagerules/parser/context/base.py | 2 +-
41 roverlay/packagerules/parser/context/rule.py | 233 +++++++++++++++++++------
42 roverlay/packagerules/parser/namespace.py | 9 +
43 roverlay/packagerules/parser/text.py | 18 +-
44 roverlay/packagerules/rules.py | 25 ++-
45 13 files changed, 419 insertions(+), 110 deletions(-)
46
47 diff --git a/roverlay/packagerules/abstract/actions.py b/roverlay/packagerules/abstract/actions.py
48 index f903398..608d20a 100644
49 --- a/roverlay/packagerules/abstract/actions.py
50 +++ b/roverlay/packagerules/abstract/actions.py
51 @@ -9,6 +9,8 @@ __all__ = [ 'PackageRuleAction', ]
52 class PackageRuleAction ( object ):
53 """PackageRuleActions manipulate PackageInfo instances."""
54
55 + INDENT = 3 * ' '
56 +
57 def __init__ ( self, priority=1000 ):
58 super ( PackageRuleAction, self ).__init__()
59 self.priority = priority
60
61 diff --git a/roverlay/packagerules/abstract/rules.py b/roverlay/packagerules/abstract/rules.py
62 index 02ce4df..98db68d 100644
63 --- a/roverlay/packagerules/abstract/rules.py
64 +++ b/roverlay/packagerules/abstract/rules.py
65 @@ -14,15 +14,16 @@ class IgnorePackageRule ( object ):
66
67 def __init__ ( self, priority=100 ):
68 super ( IgnorePackageRule, self ).__init__()
69 - self.priority = priority
70 - self._acceptor = None
71 - self.logger = None
72 + self.is_toplevel = False
73 + self.priority = priority
74 + self._acceptor = None
75 + self.logger = None
76 # --- end of __init__ (...) ---
77
78 - def _iter_rules ( self, with_self=True ):
79 + def _iter_all_rules ( self, with_self=True ):
80 if with_self:
81 yield self
82 - # --- end of _iter_rules (...) ---
83 + # --- end of _iter_all_rules (...) ---
84
85 def accepts ( self, p_info ):
86 """Returns True if this rule matches the given PackageInfo else False.
87 @@ -50,7 +51,7 @@ class IgnorePackageRule ( object ):
88 * logger --
89 """
90 self.logger = logger
91 - if hasattr ( self, '_acceptor' ):
92 + if self._acceptor:
93 self._acceptor.set_logger ( self.logger )
94 # --- end of set_logger (...) ---
95
96 @@ -63,11 +64,20 @@ class IgnorePackageRule ( object ):
97 return False
98 # --- end of apply_actions (...) ---
99
100 + def apply_alternative_actions ( self, p_info ):
101 + """Nop.
102 +
103 + arguments:
104 + * p_info --
105 + """
106 + return True
107 + # --- end of apply_alternative_actions (...) ---
108 +
109 def prepare ( self ):
110 """
111 Prepares this rule for usage. Has to be called after adding actions.
112 """
113 - if hasattr ( self, '_acceptor' ):
114 + if self._acceptor:
115 self._acceptor.prepare()
116 # --- end of prepare (...) ---
117
118 @@ -75,19 +85,51 @@ class IgnorePackageRule ( object ):
119 yield level * ' ' + 'ignore'
120 # --- end of _gen_action_str (...) ---
121
122 + def _gen_alt_action_str ( self, level ):
123 + raise NotImplementedError()
124 + # --- end of _gen_alt_action_str (...) ---
125 +
126 + def _gen_alt_rules_str ( self, level ):
127 + raise NotImplementedError()
128 + # --- end of _gen_alt_rules_str (...) ---
129 +
130 + def has_alternative_actions ( self ):
131 + return False
132 + # --- end of has_alternative_actions (...) ---
133 +
134 + def has_alternative_rules ( self ):
135 + return False
136 + # --- end of has_alternative_rules (...) ---
137 +
138 def gen_str ( self, level ):
139 - indent = level * ' '
140 + indent = level * ' '
141 + next_level = level + 1
142
143 yield ( indent + 'MATCH:' )
144 - for s in self._acceptor.gen_str ( level=( level + 1 ), match_level=0 ):
145 + for s in self._acceptor.gen_str ( level=next_level, match_level=0 ):
146 yield s
147
148 yield ( indent + 'ACTION:' )
149 - for s in self._gen_action_str ( level=( level + 1 ) ):
150 + for s in self._gen_action_str ( level=next_level ):
151 yield s
152
153 if hasattr ( self, '_gen_rules_str' ):
154 - for s in self._gen_rules_str ( level=( level + 1 ) ):
155 + for s in self._gen_rules_str ( level=next_level ):
156 + yield s
157 +
158 + have_alt = False
159 +
160 + if self.has_alternative_actions():
161 + yield ( indent + 'ELSE:' )
162 + have_alt = True
163 + for s in self._gen_alt_action_str ( level=next_level ):
164 + yield s
165 +
166 + if self.has_alternative_rules():
167 + if not have_alt:
168 + yield ( indent + 'ELSE:' )
169 + have_alt = True
170 + for s in self._gen_alt_rules_str ( level=next_level ):
171 yield s
172
173 yield ( indent + 'END;' )
174 @@ -109,15 +151,21 @@ class PackageRule ( IgnorePackageRule ):
175
176 def __init__ ( self, priority=1000 ):
177 super ( PackageRule, self ).__init__( priority )
178 - self._actions = list()
179 + self._actions = list()
180 + self._alt_actions = list()
181 # --- end of __init__ (...) ---
182
183 + def has_alternative_actions ( self ):
184 + return bool ( self._alt_actions )
185 + # --- end of has_alternative_actions (...) ---
186 +
187 def prepare ( self ):
188 """
189 Prepares this rule for usage. Has to be called after adding actions.
190 """
191 super ( PackageRule, self ).prepare()
192 - self._actions = roverlay.util.priosort ( self._actions )
193 + self._actions = roverlay.util.priosort ( self._actions )
194 + self._alt_actions = roverlay.util.priosort ( self._alt_actions )
195 # --- end of prepare (...) ---
196
197 def set_logger ( self, logger ):
198 @@ -127,9 +175,14 @@ class PackageRule ( IgnorePackageRule ):
199 * logger --
200 """
201 super ( PackageRule, self ).set_logger ( logger )
202 +
203 action_logger = self.logger.getChild ( 'Action' )
204 for action in self._actions:
205 action.set_logger ( action_logger )
206 +
207 + #action_logger = self.logger.getChild ( 'ElseAction' )
208 + for action in self._alt_actions:
209 + action.set_logger ( action_logger )
210 # --- end of set_logger (...) ---
211
212 def apply_actions ( self, p_info ):
213 @@ -148,6 +201,18 @@ class PackageRule ( IgnorePackageRule ):
214 return True
215 # --- end of apply_actions (...) ---
216
217 + def apply_alternative_actions ( self, p_info ):
218 + """Applies all 'alternative' actions to the given PackageInfo.
219 +
220 + arguments:
221 + * p_info --
222 + """
223 + for action in self._alt_actions:
224 + if action.apply_action ( p_info ) is False:
225 + return False
226 + return True
227 + # --- end of apply_alternative_actions (...) ---
228 +
229 def add_action ( self, action ):
230 """Adds an action to this rule.
231
232 @@ -157,12 +222,27 @@ class PackageRule ( IgnorePackageRule ):
233 self._actions.append ( action )
234 # --- end of add_action (...) ---
235
236 + def add_alternative_action ( self, action ):
237 + """Adds an 'alternative' action to this rule.
238 +
239 + arguments:
240 + * action --
241 + """
242 + self._alt_actions.append ( action )
243 + # --- end of add_alternative_action (...) ---
244 +
245 def _gen_action_str ( self, level ):
246 for x in self._actions:
247 for s in x.gen_str ( level=level ):
248 yield s
249 # --- end of _gen_action_str (...) ---
250
251 + def _gen_alt_action_str ( self, level ):
252 + for x in self._alt_actions:
253 + for s in x.gen_str ( level=level ):
254 + yield s
255 + # --- end of _gen_alt_action_str (...) ---
256 +
257 # --- end of PackageRule ---
258
259
260 @@ -171,23 +251,38 @@ class NestedPackageRule ( PackageRule ):
261
262 def __init__ ( self, priority=2000 ):
263 super ( NestedPackageRule, self ).__init__ ( priority )
264 - self._rules = list()
265 + self._rules = list()
266 + self._alt_rules = list()
267 # --- end of __init__ (...) ---
268
269 + def has_alternative_rules ( self ):
270 + return bool ( self._alt_rules )
271 + # --- end of has_alternative_rules (...) ---
272 +
273 def _gen_rules_str ( self, level ):
274 for rule in self._rules:
275 for s in rule.gen_str ( level ):
276 yield s
277 # --- end of _gen_rules_str (...) ---
278
279 - def _iter_rules ( self, with_self=True ):
280 + def _gen_alt_rules_str ( self, level ):
281 + for rule in self._alt_rules:
282 + for s in rule.gen_str ( level ):
283 + yield s
284 + # --- end of _gen_alt_rules_str (...) ---
285 +
286 + def _iter_all_rules ( self, with_self=True ):
287 if with_self:
288 yield self
289
290 for rule in self._rules:
291 - for nested_rule in rule._iter_rules ( with_self=True ):
292 + for nested_rule in rule._iter_all_rules ( with_self=True ):
293 + yield nested_rule
294 +
295 + for rule in self._alt_rules:
296 + for nested_rule in rule._iter_all_rules ( with_self=True ):
297 yield nested_rule
298 - # --- end of _iter_rules (...) ---
299 + # --- end of _iter_all_rules (...) ---
300
301 def set_logger ( self, logger ):
302 """Assigns a logger to this package rule and all actions.
303 @@ -196,13 +291,17 @@ class NestedPackageRule ( PackageRule ):
304 * logger --
305 """
306 super ( NestedPackageRule, self ).set_logger ( logger )
307 - if hasattr ( self, 'is_toplevel' ) and self.is_toplevel:
308 +
309 + if self.is_toplevel:
310 nested_logger = self.logger.getChild ( 'nested' )
311 - for nested_rule in self._rules:
312 - nested_rule.set_logger ( nested_logger )
313 else:
314 - for nested_rule in self._rules:
315 - nested_rule.set_logger ( self.logger )
316 + nested_logger = self.logger
317 +
318 + for nested_rule in self._rules:
319 + nested_rule.set_logger ( nested_logger )
320 +
321 + for nested_rule in self._alt_rules:
322 + nested_rule.set_logger ( nested_logger )
323 # --- end of set_logger (...) ---
324
325 def prepare ( self ):
326 @@ -212,7 +311,8 @@ class NestedPackageRule ( PackageRule ):
327 super ( NestedPackageRule, self ).prepare()
328 for rule in self._rules:
329 rule.prepare()
330 - self._rules = roverlay.util.priosort ( self._rules )
331 + self._rules = roverlay.util.priosort ( self._rules )
332 + self._alt_rules = roverlay.util.priosort ( self._alt_rules )
333 # --- end of prepare (...) ---
334
335 def apply_actions ( self, p_info ):
336 @@ -226,13 +326,37 @@ class NestedPackageRule ( PackageRule ):
337 """
338 if super ( NestedPackageRule, self ).apply_actions ( p_info ):
339 for rule in self._rules:
340 - if rule.accepts ( p_info ) and not rule.apply_actions ( p_info ):
341 + if rule.accepts ( p_info ):
342 + if not rule.apply_actions ( p_info ):
343 + return False
344 + elif not rule.apply_alternative_actions ( p_info ):
345 return False
346 return True
347 else:
348 return False
349 # --- end of apply_actions (...) ---
350
351 + def apply_alternative_actions ( self, p_info ):
352 + """Applies all 'alternative' actions to the given PackageInfo.
353 +
354 + arguments:
355 + * p_info --
356 + """
357 + if ( super (
358 + NestedPackageRule, self ).apply_alternative_actions ( p_info )
359 + ):
360 + for rule in self._alt_rules:
361 + if rule.accepts ( p_info ):
362 + if not rule.apply_actions ( p_info ):
363 + return False
364 + elif not rule.apply_alternative_actions ( p_info ):
365 + return False
366 +
367 + return True
368 + else:
369 + return False
370 + # --- end of apply_alternative_actions (...) ---
371 +
372 def add_rule ( self, rule ):
373 """Adds a rule.
374
375 @@ -242,4 +366,13 @@ class NestedPackageRule ( PackageRule ):
376 self._rules.append ( rule )
377 # --- end of add_rule (...) ---
378
379 + def add_alternative_rule ( self, rule ):
380 + """Adds an 'alternative' rule.
381 +
382 + arguments:
383 + * rule --
384 + """
385 + self._alt_rules.append ( rule )
386 + # --- end of add_alternative_rule (...) ---
387 +
388 # --- end of NestedPackageRule ---
389
390 diff --git a/roverlay/packagerules/acceptors/stringmatch.py b/roverlay/packagerules/acceptors/stringmatch.py
391 index f5da49f..b6007b6 100644
392 --- a/roverlay/packagerules/acceptors/stringmatch.py
393 +++ b/roverlay/packagerules/acceptors/stringmatch.py
394 @@ -103,8 +103,10 @@ class RegexAcceptor (
395 self.__class__.__name__
396 )
397 )
398 -
399 - self._regex = regex_compiled if regex_compiled else re.compile ( regex )
400 + elif regex_compiled:
401 + self._regex = regex_compiled
402 + else:
403 + self._regex = re.compile ( regex )
404 # --- end of __init__ (...) ---
405
406 def _matches ( self, value ):
407
408 diff --git a/roverlay/packagerules/actions/evar.py b/roverlay/packagerules/actions/evar.py
409 index c789219..17f46fe 100644
410 --- a/roverlay/packagerules/actions/evar.py
411 +++ b/roverlay/packagerules/actions/evar.py
412 @@ -46,7 +46,7 @@ class EvarAction ( roverlay.packagerules.abstract.actions.PackageRuleAction ):
413
414 def gen_str ( self, level ):
415 yield (
416 - level * ' ' + self._evar.name.lower()
417 + ( level * self.INDENT ) + self._evar.name.lower()
418 + ' "' + self._evar.value + '"'
419 )
420 # --- end of gen_str (...) ---
421
422 diff --git a/roverlay/packagerules/actions/ignore.py b/roverlay/packagerules/actions/ignore.py
423 new file mode 100644
424 index 0000000..5ee19f9
425 --- /dev/null
426 +++ b/roverlay/packagerules/actions/ignore.py
427 @@ -0,0 +1,25 @@
428 +# R overlay -- package rule actions, ignore package
429 +# -*- coding: utf-8 -*-
430 +# Copyright (C) 2013 André Erdmann <dywi@×××××××.de>
431 +# Distributed under the terms of the GNU General Public License;
432 +# either version 2 of the License, or (at your option) any later version.
433 +
434 +import roverlay.packagerules.abstract.actions
435 +
436 +__all__ = [ 'IgnoreAction', ]
437 +
438 +class IgnoreAction (
439 + roverlay.packagerules.abstract.actions.PackageRuleAction
440 +):
441 +
442 + KEYWORD = 'ignore'
443 +
444 + def apply_action ( self, p_info ):
445 + return False
446 + # --- end of apply_action (...) ---
447 +
448 + def gen_str ( self, level ):
449 + yield ( level * self.INDENT ) + self.KEYWORD
450 + # --- end of gen_str (...) ---
451 +
452 +# --- end of IgnoreAction ---
453
454 diff --git a/roverlay/packagerules/actions/info.py b/roverlay/packagerules/actions/info.py
455 index 538fdef..d9f1390 100644
456 --- a/roverlay/packagerules/actions/info.py
457 +++ b/roverlay/packagerules/actions/info.py
458 @@ -59,7 +59,7 @@ class InfoRenameAction (
459 # FIXME: that's not always correct!
460 # (could be solved by storing the original regex delimiter)
461 yield (
462 - level * ' ' + 'rename ' + self.key
463 + level * self.INDENT + 'rename ' + self.key
464 + ' s/' + self.regex.pattern + '/' + self.subst + '/' # + flags
465 )
466 # --- end of gen_str (...) ---
467 @@ -162,7 +162,7 @@ class InfoSetToAction (
468 # --- end of apply_action (...) ---
469
470 def gen_str ( self, level ):
471 - yield ( level * ' ' + 'set ' + self.key + ' ' + self.value )
472 + yield ( level * self.INDENT + 'set ' + self.key + ' ' + self.value )
473 # --- end of gen_str (...) ---
474
475 # --- end of InfoSetToAction ---
476
477 diff --git a/roverlay/packagerules/actions/trace.py b/roverlay/packagerules/actions/trace.py
478 index 669969a..c16f6c6 100644
479 --- a/roverlay/packagerules/actions/trace.py
480 +++ b/roverlay/packagerules/actions/trace.py
481 @@ -38,7 +38,7 @@ class TraceAction (
482 # --- end of apply_action (...) ---
483
484 def gen_str ( self, level ):
485 - yield ( level * ' ' ) + "trace " + str ( self._ident )
486 + yield ( level * self.INDENT ) + "trace " + str ( self._ident )
487 # --- end of gen_str (...) ---
488
489
490 @@ -57,5 +57,5 @@ class MarkAsModifiedAction (
491 # --- end of apply_action (...) ---
492
493 def gen_str ( self, level ):
494 - yield ( level * ' ' ) + "trace"
495 + yield ( level * self.INDENT ) + "trace"
496 # --- end of gen_str (...) ---
497
498 diff --git a/roverlay/packagerules/parser/context/action.py b/roverlay/packagerules/parser/context/action.py
499 index 22936cc..49ed7db 100644
500 --- a/roverlay/packagerules/parser/context/action.py
501 +++ b/roverlay/packagerules/parser/context/action.py
502 @@ -37,14 +37,16 @@ class RuleActionContext (
503 """RuleActionContext parses action-blocks."""
504
505 # keywords for the "ignore" action
506 - KEYWORDS_ACTION_IGNORE = frozenset ((
507 + KEYWORDS_ACTION_IGNORE = frozenset ({
508 'ignore',
509 'do-not-process'
510 - ))
511 + })
512
513 - KEYWORDS_ACTION_TRACE = frozenset ((
514 + KEYWORDS_ACTION_TRACE = frozenset ({
515 'trace',
516 - ))
517 + })
518 +
519 + KEYWORDS_NO_ACTION = frozenset ({ 'pass', 'null', })
520
521 # dict ( <keyword> => <evar class> )
522 # Dict of evar action keywords (with corresponding classes)
523 @@ -225,7 +227,9 @@ class RuleActionContext (
524 Raises:
525 * InvalidContext
526 """
527 - if _str in self.KEYWORDS_ACTION_IGNORE:
528 + if _str in self.KEYWORDS_NO_ACTION:
529 + pass
530 + elif _str in self.KEYWORDS_ACTION_IGNORE:
531 if not self._actions:
532 self._actions = None
533 else:
534 @@ -255,7 +259,9 @@ class RuleActionContext (
535 )
536 )
537
538 - elif self._add_as_info_action ( argv [0], argv [1], _str, lino ):
539 + elif len ( argv ) > 1 and (
540 + self._add_as_info_action ( argv [0], argv [1], _str, lino )
541 + ):
542 pass
543
544 else:
545
546 diff --git a/roverlay/packagerules/parser/context/base.py b/roverlay/packagerules/parser/context/base.py
547 index 1a09a79..9bd97b7 100644
548 --- a/roverlay/packagerules/parser/context/base.py
549 +++ b/roverlay/packagerules/parser/context/base.py
550 @@ -15,7 +15,7 @@ class BaseContext ( object ):
551 self.namespace = namespace
552 # --- end of __init__ (...) ---
553
554 - def feed ( self, _str ):
555 + def feed ( self, _str, lino ):
556 raise NotImplementedError()
557 # --- end of feed (...) ---
558
559
560 diff --git a/roverlay/packagerules/parser/context/rule.py b/roverlay/packagerules/parser/context/rule.py
561 index 2601d7e..0f6f342 100644
562 --- a/roverlay/packagerules/parser/context/rule.py
563 +++ b/roverlay/packagerules/parser/context/rule.py
564 @@ -4,11 +4,18 @@
565 # Distributed under the terms of the GNU General Public License;
566 # either version 2 of the License, or (at your option) any later version.
567
568 -from roverlay.packagerules.abstract import rules
569 +import roverlay.packagerules.abstract.rules
570 +from roverlay.packagerules.abstract.rules import \
571 + IgnorePackageRule, PackageRule, NestedPackageRule
572
573 -from . import base, match, action
574 +import roverlay.packagerules.parser.context.action
575 +import roverlay.packagerules.parser.context.base
576 +import roverlay.packagerules.parser.context.match
577
578 -class RuleContext ( base.NestableContext ):
579 +
580 +class RuleContext (
581 + roverlay.packagerules.parser.context.base.NestableContext
582 +):
583 """Class for creating rules from text input (feed(<>)) plus using a few
584 control flow functions (end_of_rule(), begin_match(), begin_action()).
585 """
586 @@ -29,28 +36,55 @@ class RuleContext ( base.NestableContext ):
587 #
588 # (use bitwise operators to check against these values)
589 #
590 - CONTEXT_NONE = 0 # == only
591 - CONTEXT_MAIN_MATCH = 1
592 - CONTEXT_MAIN_ACTION = 2
593 - CONTEXT_SUB_MATCH = 4
594 - CONTEXT_SUB_ACTION = 8
595 + CONTEXT_NONE = 0 # == only
596 + CONTEXT_MAIN_MATCH = 1
597 + CONTEXT_MAIN_ACTION = 2
598 + CONTEXT_MAIN_ALT_ACTION = 4
599 + CONTEXT_SUB_MATCH = 8
600 + CONTEXT_SUB_ACTION = 16
601 + # else-block is a non-propagating status
602 + #CONTEXT_SUB_ALT_ACTION
603 +
604 + CONTEXT_MATCH = CONTEXT_MAIN_MATCH | CONTEXT_SUB_MATCH
605 + CONTEXT_ACTION = CONTEXT_MAIN_ACTION | CONTEXT_SUB_ACTION
606 + CONTEXT_MAIN_ANY_ACTION = CONTEXT_MAIN_ALT_ACTION | CONTEXT_MAIN_ACTION
607 + CONTEXT_SUB = CONTEXT_SUB_MATCH | CONTEXT_SUB_ACTION
608 +
609 + CONTEXT_MAIN = (
610 + CONTEXT_MAIN_MATCH | CONTEXT_MAIN_ACTION | CONTEXT_MAIN_ALT_ACTION
611 + )
612
613 - CONTEXT_MATCH = CONTEXT_MAIN_MATCH | CONTEXT_SUB_MATCH
614 - CONTEXT_ACTION = CONTEXT_MAIN_ACTION | CONTEXT_SUB_ACTION
615 - CONTEXT_MAIN = CONTEXT_MAIN_MATCH | CONTEXT_MAIN_ACTION
616 - CONTEXT_SUB = CONTEXT_SUB_MATCH | CONTEXT_SUB_ACTION
617
618 # -- end of CONTEXT_ --
619
620 - def __init__ ( self, namespace, level=0, priority=-1 ):
621 + def __init__ ( self, namespace, level=0, priority=-1, mode=None ):
622 super ( RuleContext, self ).__init__ ( namespace, level )
623
624 - self.context = self.CONTEXT_MAIN_MATCH
625 - self.priority = priority
626 - self._action_context = action.RuleActionContext ( self.namespace )
627 - self._match_context = match.RuleMatchContext (
628 - namespace = self.namespace,
629 - priority = priority
630 + if mode is None:
631 + if level == 0:
632 + self.mode = self.CONTEXT_MAIN_ACTION
633 + else:
634 + raise Exception ( "mode has to be set if level is non-zero." )
635 + else:
636 + self.mode = mode
637 +
638 + self.context = self.CONTEXT_MAIN_MATCH
639 + self.priority = priority
640 + self._action_context = (
641 + roverlay.packagerules.parser.context.action.RuleActionContext (
642 + self.namespace
643 + )
644 + )
645 + self._alt_action_context = (
646 + roverlay.packagerules.parser.context.action.RuleActionContext (
647 + self.namespace
648 + )
649 + )
650 + self._match_context = (
651 + roverlay.packagerules.parser.context.match.RuleMatchContext (
652 + namespace = self.namespace,
653 + priority = priority
654 + )
655 )
656 # --- end of __init__ (...) ---
657
658 @@ -66,15 +100,22 @@ class RuleContext ( base.NestableContext ):
659 # nested rules are stored in self._nested (and not in
660 # self._action_context where they syntactically belong to)
661
662 - if self.context & self.CONTEXT_MAIN_ACTION:
663 - # a nested rule (with depth = 1)
664 - self._new_nested ( priority=lino )
665 - self.context = self.CONTEXT_SUB_MATCH
666 - elif self.context & self.CONTEXT_SUB_ACTION:
667 + if self.context & self.CONTEXT_SUB_ACTION:
668 # a nested rule inside a nested one (depth > 1)
669 # => redirect to nested
670 self.get_nested().begin_match ( lino )
671 - self.context = self.CONTEXT_SUB_MATCH
672 + self.context |= self.CONTEXT_SUB_MATCH
673 +
674 + elif self.context & self.CONTEXT_MAIN_ACTION:
675 + # a nested rule (with depth = 1)
676 + self._new_nested ( priority=lino, mode=self.CONTEXT_MAIN_ACTION )
677 + self.context |= self.CONTEXT_SUB_MATCH
678 +
679 + elif self.context & self.CONTEXT_MAIN_ALT_ACTION:
680 + # a new nested rule in the else block (with depth = 1)
681 + self._new_nested ( priority=lino, mode=self.CONTEXT_MAIN_ALT_ACTION )
682 + self.context |= self.CONTEXT_SUB_MATCH
683 +
684 else:
685 # illegal
686 raise self.InvalidContext()
687 @@ -87,21 +128,50 @@ class RuleContext ( base.NestableContext ):
688 * lino -- line number
689
690 Raises: InvalidContext,
691 - an action-block has to be preceeded by a match-block
692 + an action block has to be preceeded by a match block
693 """
694 - if self.context & self.CONTEXT_MAIN_MATCH:
695 - # begin of the main action-block
696 - self.context = self.CONTEXT_MAIN_ACTION
697 - elif self.context & self.CONTEXT_SUB_MATCH:
698 + if self.context & self.CONTEXT_SUB_MATCH:
699 # action-block of a nested rule
700 # => redirect to nested
701 self.get_nested().begin_action ( lino )
702 - self.context = self.CONTEXT_SUB_ACTION
703 + self.context &= ~self.CONTEXT_SUB_MATCH
704 + self.context |= self.CONTEXT_SUB_ACTION
705 +
706 + elif self.context & self.CONTEXT_MAIN_MATCH:
707 + # begin of the main action-block
708 + self.context &= ~self.CONTEXT_MAIN_MATCH
709 + self.context |= self.CONTEXT_MAIN_ACTION
710 +
711 else:
712 # illegal
713 raise self.InvalidContext()
714 # --- end of begin_action (...) ---
715
716 + def begin_alternative_action ( self, lino ):
717 + """Create/begin an else-action block of a rule (nested or "self").
718 +
719 + arguments:
720 + * lino -- line number
721 +
722 + Raises: InvalidContext,
723 + an else-action block has to be preceeded by an action block
724 + """
725 + if self.context & self.CONTEXT_SUB_ACTION:
726 + # else-action-block of a nested rule
727 + # => redirect to nested
728 + # no status change as else-blocks are handled non-recursively
729 + self.get_nested().begin_alternative_action ( lino )
730 +
731 + elif self.context & self.CONTEXT_MAIN_ACTION:
732 + # begin of the main else-action-block
733 + self.context &= ~self.CONTEXT_MAIN_ACTION
734 + self.context |= self.CONTEXT_MAIN_ALT_ACTION
735 +
736 + else:
737 + # illegal
738 + raise self.InvalidContext()
739 + # --- end of begin_alternative_action (...) ---
740 +
741 def end_of_rule ( self, lino ):
742 """Has to be called whenever an end-of-rule statement has been reached
743 and ends a rule, either this one or a nested one (depending on the
744 @@ -116,14 +186,10 @@ class RuleContext ( base.NestableContext ):
745 Raises: InvalidContext,
746 rules can only be closed if within an action-block
747 """
748 - if self.context & self.CONTEXT_MAIN_ACTION:
749 - # end of this rule
750 - self.context = self.CONTEXT_NONE
751 - return True
752 - elif self.context & self.CONTEXT_SUB_ACTION:
753 + if self.context & self.CONTEXT_SUB_ACTION:
754 if self.get_nested().end_of_rule ( lino ):
755 # end of child rule (depth=1)
756 - self.context = self.CONTEXT_MAIN_ACTION
757 + self.context &= ~self.CONTEXT_SUB_ACTION
758
759 # no-op, since self.context is already CONTEXT_SUB_ACTION
760 # else:
761 @@ -131,6 +197,17 @@ class RuleContext ( base.NestableContext ):
762 # self.context = self.CONTEXT_SUB_ACTION
763
764 return False
765 +
766 + elif self.context & self.CONTEXT_MAIN_ANY_ACTION:
767 + # end of this rule
768 + #self.context = self.CONTEXT_NONE
769 + self.context &= ~self.CONTEXT_MAIN_ANY_ACTION
770 + if self.context != self.CONTEXT_NONE:
771 + raise AssertionError (
772 + "broken context bit mask {:d}!".format ( self.context )
773 + )
774 + return True
775 +
776 else:
777 raise self.InvalidContext()
778 # --- end of end_of_rule (...) ---
779 @@ -145,12 +222,18 @@ class RuleContext ( base.NestableContext ):
780 Raises: InvalidContext if this rule does not accept input
781 (if self.context is CONTEXT_NONE)
782 """
783 - if self.context & self.CONTEXT_MAIN_MATCH:
784 + if self.context & self.CONTEXT_SUB:
785 + return self.get_nested().feed ( _str, lino )
786 +
787 + elif self.context & self.CONTEXT_MAIN_MATCH:
788 return self._match_context.feed ( _str, lino )
789 +
790 elif self.context & self.CONTEXT_MAIN_ACTION:
791 return self._action_context.feed ( _str, lino )
792 - elif self.context & self.CONTEXT_SUB:
793 - return self.get_nested().feed ( _str, lino )
794 +
795 + elif self.context & self.CONTEXT_MAIN_ALT_ACTION:
796 + return self._alt_action_context.feed ( _str, lino )
797 +
798 else:
799 raise self.InvalidContext()
800 # --- end of feed (...) ---
801 @@ -171,37 +254,71 @@ class RuleContext ( base.NestableContext ):
802 raise self.InvalidContext ( "end_of_rule not reached." )
803 # -- if;
804
805 - package_rule = None
806 - actions = self._action_context.create()
807 - acceptor = self._match_context.create()
808 + package_rule = None
809 + actions = self._action_context.create()
810 + alt_actions = self._alt_action_context.create()
811 + acceptor = self._match_context.create()
812 + ACTION_IGNORE = self.namespace.get_ignore_action()
813
814 if not acceptor:
815 raise Exception ( "empty match-block makes no sense." )
816
817 + elif actions is None and alt_actions is None:
818 + raise Exception ( "ignore-all rule makes no sense." )
819 +
820 elif len ( self._nested ) > 0:
821 # nested rule
822 + package_rule = NestedPackageRule ( priority=self.priority )
823 + for nested in self._nested:
824 + nested_rule = nested.create()
825 + if nested.mode == self.CONTEXT_MAIN_ACTION:
826 + package_rule.add_rule ( nested_rule )
827 + elif nested.mode == self.CONTEXT_MAIN_ALT_ACTION:
828 + package_rule.add_alternative_rule ( nested_rule )
829 + else:
830 + raise Exception ( "nested rule has invalid mode" )
831 +
832 if actions is None:
833 - raise Exception (
834 - "ignore action-block cannot contain nested rules."
835 - )
836 + package_rule.add_action ( ACTION_IGNORE )
837 else:
838 - package_rule = rules.NestedPackageRule ( priority=self.priority )
839 - for nested in self._nested:
840 - package_rule.add_rule ( nested.create() )
841 + for rule_action in actions:
842 + package_rule.add_action ( rule_action )
843
844 - for action in actions:
845 - package_rule.add_action ( action )
846 + if alt_actions is None:
847 + package_rule.add_alternative_action ( ACTION_IGNORE )
848 + else:
849 + for rule_action in alt_actions:
850 + package_rule.add_alternative_action ( rule_action )
851
852 elif actions is None:
853 - # ignore rule
854 - package_rule = rules.IgnorePackageRule ( priority=self.priority )
855 + if alt_actions:
856 + # ignore rule with else-action block
857 + package_rule = PackageRule ( priority=self.priority )
858 + package_rule.add_action ( ACTION_IGNORE )
859 +
860 + for rule_action in alt_actions:
861 + package_rule.add_alternative_action ( rule_action )
862 + else:
863 + # ignore rule
864 + package_rule = IgnorePackageRule ( priority=self.priority )
865 +
866 + elif alt_actions is None:
867 + # normal rule with else-ignore block
868 + package_rule = PackageRule ( priority=self.priority )
869 + package_rule.add_alternative_action ( ACTION_IGNORE )
870 +
871 + for rule_action in actions:
872 + package_rule.add_action ( rule_action )
873 +
874 + elif actions or alt_actions:
875 + # normal rule with action and/or else-action block
876 + package_rule = PackageRule ( priority=self.priority )
877
878 - elif actions:
879 - # normal rule
880 - package_rule = rules.PackageRule ( priority=self.priority )
881 + for rule_action in actions:
882 + package_rule.add_action ( rule_action )
883
884 - for action in actions:
885 - package_rule.add_action ( action )
886 + for rule_action in alt_actions:
887 + package_rule.add_alternative_action ( rule_action )
888
889 else:
890 raise Exception ( "empty action-block makes no sense." )
891
892 diff --git a/roverlay/packagerules/parser/namespace.py b/roverlay/packagerules/parser/namespace.py
893 index 6af8661..ab9b7d8 100644
894 --- a/roverlay/packagerules/parser/namespace.py
895 +++ b/roverlay/packagerules/parser/namespace.py
896 @@ -6,6 +6,8 @@
897
898 import roverlay.util
899
900 +import roverlay.packagerules.actions.ignore
901 +
902 DEBUG_GET_OBJECT = False
903
904 if DEBUG_GET_OBJECT:
905 @@ -36,8 +38,15 @@ class RuleNamespace ( object ):
906 # )
907 #
908 self._objects = dict()
909 + self._ignore_action = (
910 + roverlay.packagerules.actions.ignore.IgnoreAction()
911 + )
912 # --- end of __init__ (...) ---
913
914 + def get_ignore_action ( self ):
915 + return self._ignore_action
916 + # --- end of get_ignore_action (...) ---
917 +
918 def get_object ( self, cls, *args, **kwargs ):
919 """Returns the desired object.
920
921
922 diff --git a/roverlay/packagerules/parser/text.py b/roverlay/packagerules/parser/text.py
923 index 4060e95..87db0b0 100644
924 --- a/roverlay/packagerules/parser/text.py
925 +++ b/roverlay/packagerules/parser/text.py
926 @@ -20,17 +20,16 @@ class RuleParser ( object ):
927 # control flow statements
928 # all other keywords are defined in the respective context classes,
929 # namely RuleContext, RuleMatchContext and RuleActionContext
930 - KEYWORDS_MATCH = frozenset (( 'match:', 'MATCH:', ))
931 - KEYWORDS_ACTION = frozenset (( 'action:', 'ACTION:' ))
932 - KEYWORDS_END = frozenset (( 'end;', 'END;' ))
933 + KEYWORDS_MATCH = frozenset ({ 'match:', 'MATCH:', })
934 + KEYWORDS_ACTION = frozenset ({ 'action:', 'ACTION:' })
935 + KEYWORDS_ACTION_ELSE = frozenset ({ 'else:', 'ELSE:' })
936 + KEYWORDS_END = frozenset ({ 'end;', 'END;' })
937
938 - COMMENT_CHARS = frozenset ( "#;" )
939 + COMMENT_CHARS = frozenset ({ '#', ';' })
940
941 def _zap ( self ):
942 self.namespace.zap ( zap_object_db=False )
943 - # the rule block (RuleContext) that is currently active
944 self._current_rule = None
945 - # previous rule blocks
946 self._parsed_rules = list()
947 # --- end of _zap (...) ---
948
949 @@ -44,6 +43,11 @@ class RuleParser ( object ):
950 self.namespace = roverlay.packagerules.parser.namespace.RuleNamespace()
951 self.add_rule = add_rule_method
952 self._zap()
953 +
954 + # the rule block (RuleContext) that is currently active
955 + self._current_rule = None
956 + # previous rule blocks
957 + self._parsed_rules = None
958 # --- end of __init__ (...) ---
959
960 def _feed ( self, l, lino ):
961 @@ -59,6 +63,8 @@ class RuleParser ( object ):
962 self._current_rule.begin_match ( lino )
963 elif l in self.KEYWORDS_ACTION:
964 self._current_rule.begin_action ( lino )
965 + elif l in self.KEYWORDS_ACTION_ELSE:
966 + self._current_rule.begin_alternative_action ( lino )
967 elif l in self.KEYWORDS_END:
968 if self._current_rule.end_of_rule ( lino ):
969 # add rule to self._parsed_rules
970
971 diff --git a/roverlay/packagerules/rules.py b/roverlay/packagerules/rules.py
972 index 649343a..9ca91e5 100644
973 --- a/roverlay/packagerules/rules.py
974 +++ b/roverlay/packagerules/rules.py
975 @@ -45,7 +45,6 @@ class PackageRules ( roverlay.packagerules.abstract.rules.NestedPackageRule ):
976
977 def __init__ ( self ):
978 super ( PackageRules, self ).__init__ ( priority=-1 )
979 - del self._acceptor
980 self.logger = logging.getLogger ( self.__class__.__name__ )
981 self.is_toplevel = True
982 # --- end of __init__ (...) ---
983 @@ -69,17 +68,27 @@ class PackageRules ( roverlay.packagerules.abstract.rules.NestedPackageRule ):
984 return True
985 # --- end of accepts (...) ---
986
987 + def apply_alternative_actions ( self, p_info ):
988 + raise Exception ( "toplevel rule does not contain else-block actions." )
989 + # --- end of apply_alternative_actions (...) ---
990 +
991 + def add_alternative_action ( self, action ):
992 + raise Exception ( "toplevel rule does not accept else-block actions." )
993 + # --- end of add_alternative_action (...) ---
994 +
995 def add_trace_actions ( self ):
996 """Adds MarkAsModified actions to this rule and all nested ones.
997
998 - Meant for testing the package rule system."""
999 -
1000 + Meant for testing the package rule system.
1001 + """
1002 marker = roverlay.packagerules.actions.trace.MarkAsModifiedAction ( -1 )
1003 - for rule in filter (
1004 - lambda rule : hasattr ( rule, 'add_action' ),
1005 - self._iter_rules ( with_self=False )
1006 - ):
1007 - rule.add_action ( marker )
1008 +
1009 + for rule in self._iter_all_rules ( with_self=False ):
1010 + if hasattr ( rule, 'add_action' ):
1011 + rule.add_action ( marker )
1012 +
1013 + if hasattr ( rule, 'add_alternative_action' ):
1014 + rule.add_alternative_action ( marker )
1015
1016 self.prepare()
1017 # --- end of add_trace_actions (...) ---