public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, ...
Date: Thu,  1 Aug 2013 12:44:54 +0000 (UTC)	[thread overview]
Message-ID: <1375360359.703b273c1559be91ad2e7eeceff1b963e0f91e8a.dywi@gentoo> (raw)

commit:     703b273c1559be91ad2e7eeceff1b963e0f91e8a
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Aug  1 12:32:39 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Aug  1 12:32:39 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=703b273c

package rules, syntax: support else-action block

Package rules can now declare an ELSE: block (following the ACTION: block) whose
action statements are executed if the rule's MATCH: block did not match a
package.

"ELSE IF" statements are not supported, but can be realized by placing a nested
rule in the ELSE: block.

Other changes:
* "null"/"pass" action statement. A no-op statement (removed at rule "compile"
  time) which can be used to improve readability (e.g. if a rule has no actions
  in the ACTION: block)
* "do-not-process"/"ignore" is now available as action (in addition to the
  hard-wired IgnorePackageRule class). The rule parser chooses the "correct"
  implementation (which depends on the rule).
  An "do-not-process if <matches...> else do-not-process" rule is forbidden.
  (As "workaround", it can be achieved via "do-not-process if <always true
  condition>.)
* minor fix in RuleActionContext.feed() concerning arg count
* the rule context (responsible for parsing a single rule) manipulates its
  status bitmask (bitwise-AND/OR) now instead of setting it directly

---
 roverlay/packagerules/abstract/actions.py      |   2 +
 roverlay/packagerules/abstract/rules.py        | 181 ++++++++++++++++---
 roverlay/packagerules/acceptors/stringmatch.py |   6 +-
 roverlay/packagerules/actions/evar.py          |   2 +-
 roverlay/packagerules/actions/ignore.py        |  25 +++
 roverlay/packagerules/actions/info.py          |   4 +-
 roverlay/packagerules/actions/trace.py         |   4 +-
 roverlay/packagerules/parser/context/action.py |  18 +-
 roverlay/packagerules/parser/context/base.py   |   2 +-
 roverlay/packagerules/parser/context/rule.py   | 233 +++++++++++++++++++------
 roverlay/packagerules/parser/namespace.py      |   9 +
 roverlay/packagerules/parser/text.py           |  18 +-
 roverlay/packagerules/rules.py                 |  25 ++-
 13 files changed, 419 insertions(+), 110 deletions(-)

diff --git a/roverlay/packagerules/abstract/actions.py b/roverlay/packagerules/abstract/actions.py
index f903398..608d20a 100644
--- a/roverlay/packagerules/abstract/actions.py
+++ b/roverlay/packagerules/abstract/actions.py
@@ -9,6 +9,8 @@ __all__ = [ 'PackageRuleAction', ]
 class PackageRuleAction ( object ):
    """PackageRuleActions manipulate PackageInfo instances."""
 
+   INDENT = 3 * ' '
+
    def __init__ ( self, priority=1000 ):
       super ( PackageRuleAction, self ).__init__()
       self.priority = priority

diff --git a/roverlay/packagerules/abstract/rules.py b/roverlay/packagerules/abstract/rules.py
index 02ce4df..98db68d 100644
--- a/roverlay/packagerules/abstract/rules.py
+++ b/roverlay/packagerules/abstract/rules.py
@@ -14,15 +14,16 @@ class IgnorePackageRule ( object ):
 
    def __init__ ( self, priority=100 ):
       super ( IgnorePackageRule, self ).__init__()
-      self.priority   = priority
-      self._acceptor  = None
-      self.logger     = None
+      self.is_toplevel = False
+      self.priority    = priority
+      self._acceptor   = None
+      self.logger      = None
    # --- end of __init__ (...) ---
 
-   def _iter_rules ( self, with_self=True ):
+   def _iter_all_rules ( self, with_self=True ):
       if with_self:
          yield self
-   # --- end of _iter_rules (...) ---
+   # --- end of _iter_all_rules (...) ---
 
    def accepts ( self, p_info ):
       """Returns True if this rule matches the given PackageInfo else False.
@@ -50,7 +51,7 @@ class IgnorePackageRule ( object ):
       * logger --
       """
       self.logger = logger
-      if hasattr ( self, '_acceptor' ):
+      if self._acceptor:
          self._acceptor.set_logger ( self.logger )
    # --- end of set_logger (...) ---
 
@@ -63,11 +64,20 @@ class IgnorePackageRule ( object ):
       return False
    # --- end of apply_actions (...) ---
 
+   def apply_alternative_actions ( self, p_info ):
+      """Nop.
+
+      arguments:
+      * p_info --
+      """
+      return True
+   # --- end of apply_alternative_actions (...) ---
+
    def prepare ( self ):
       """
       Prepares this rule for usage. Has to be called after adding actions.
       """
-      if hasattr ( self, '_acceptor' ):
+      if self._acceptor:
          self._acceptor.prepare()
    # --- end of prepare (...) ---
 
@@ -75,19 +85,51 @@ class IgnorePackageRule ( object ):
       yield level * '   ' + 'ignore'
    # --- end of _gen_action_str (...) ---
 
+   def _gen_alt_action_str ( self, level ):
+      raise NotImplementedError()
+   # --- end of _gen_alt_action_str (...) ---
+
+   def _gen_alt_rules_str ( self, level ):
+      raise NotImplementedError()
+   # --- end of _gen_alt_rules_str (...) ---
+
+   def has_alternative_actions ( self ):
+      return False
+   # --- end of has_alternative_actions (...) ---
+
+   def has_alternative_rules ( self ):
+      return False
+   # --- end of has_alternative_rules (...) ---
+
    def gen_str ( self, level ):
-      indent = level * '   '
+      indent     = level * '   '
+      next_level = level + 1
 
       yield ( indent + 'MATCH:' )
-      for s in self._acceptor.gen_str ( level=( level + 1 ), match_level=0 ):
+      for s in self._acceptor.gen_str ( level=next_level, match_level=0 ):
          yield s
 
       yield ( indent + 'ACTION:' )
-      for s in self._gen_action_str ( level=( level + 1 ) ):
+      for s in self._gen_action_str ( level=next_level ):
          yield s
 
       if hasattr ( self, '_gen_rules_str' ):
-         for s in self._gen_rules_str ( level=( level + 1 ) ):
+         for s in self._gen_rules_str ( level=next_level ):
+            yield s
+
+      have_alt = False
+
+      if self.has_alternative_actions():
+         yield ( indent + 'ELSE:' )
+         have_alt = True
+         for s in self._gen_alt_action_str ( level=next_level ):
+            yield s
+
+      if self.has_alternative_rules():
+         if not have_alt:
+            yield ( indent + 'ELSE:' )
+            have_alt = True
+         for s in self._gen_alt_rules_str ( level=next_level ):
             yield s
 
       yield ( indent + 'END;' )
@@ -109,15 +151,21 @@ class PackageRule ( IgnorePackageRule ):
 
    def __init__ ( self, priority=1000 ):
       super ( PackageRule, self ).__init__( priority )
-      self._actions = list()
+      self._actions     = list()
+      self._alt_actions = list()
    # --- end of __init__ (...) ---
 
+   def has_alternative_actions ( self ):
+      return bool ( self._alt_actions )
+   # --- end of has_alternative_actions (...) ---
+
    def prepare ( self ):
       """
       Prepares this rule for usage. Has to be called after adding actions.
       """
       super ( PackageRule, self ).prepare()
-      self._actions = roverlay.util.priosort ( self._actions )
+      self._actions     = roverlay.util.priosort ( self._actions )
+      self._alt_actions = roverlay.util.priosort ( self._alt_actions )
    # --- end of prepare (...) ---
 
    def set_logger ( self, logger ):
@@ -127,9 +175,14 @@ class PackageRule ( IgnorePackageRule ):
       * logger --
       """
       super ( PackageRule, self ).set_logger ( logger )
+
       action_logger = self.logger.getChild ( 'Action' )
       for action in self._actions:
          action.set_logger ( action_logger )
+
+      #action_logger = self.logger.getChild ( 'ElseAction' )
+      for action in self._alt_actions:
+         action.set_logger ( action_logger )
    # --- end of set_logger (...) ---
 
    def apply_actions ( self, p_info ):
@@ -148,6 +201,18 @@ class PackageRule ( IgnorePackageRule ):
       return True
    # --- end of apply_actions (...) ---
 
+   def apply_alternative_actions ( self, p_info ):
+      """Applies all 'alternative' actions to the given PackageInfo.
+
+      arguments:
+      * p_info --
+      """
+      for action in self._alt_actions:
+         if action.apply_action ( p_info ) is False:
+            return False
+      return True
+   # --- end of apply_alternative_actions (...) ---
+
    def add_action ( self, action ):
       """Adds an action to this rule.
 
@@ -157,12 +222,27 @@ class PackageRule ( IgnorePackageRule ):
       self._actions.append ( action )
    # --- end of add_action (...) ---
 
+   def add_alternative_action ( self, action ):
+      """Adds an 'alternative' action to this rule.
+
+      arguments:
+      * action --
+      """
+      self._alt_actions.append ( action )
+   # --- end of add_alternative_action (...) ---
+
    def _gen_action_str ( self, level ):
       for x in self._actions:
          for s in x.gen_str ( level=level ):
             yield s
    # --- end of _gen_action_str (...) ---
 
+   def _gen_alt_action_str ( self, level ):
+      for x in self._alt_actions:
+         for s in x.gen_str ( level=level ):
+            yield s
+   # --- end of _gen_alt_action_str (...) ---
+
 # --- end of PackageRule ---
 
 
@@ -171,23 +251,38 @@ class NestedPackageRule ( PackageRule ):
 
    def __init__ ( self, priority=2000 ):
       super ( NestedPackageRule, self ).__init__ ( priority )
-      self._rules = list()
+      self._rules     = list()
+      self._alt_rules = list()
    # --- end of __init__ (...) ---
 
+   def has_alternative_rules ( self ):
+      return bool ( self._alt_rules )
+   # --- end of has_alternative_rules (...) ---
+
    def _gen_rules_str ( self, level ):
       for rule in self._rules:
          for s in rule.gen_str ( level ):
             yield s
    # --- end of _gen_rules_str (...) ---
 
-   def _iter_rules ( self, with_self=True ):
+   def _gen_alt_rules_str ( self, level ):
+      for rule in self._alt_rules:
+         for s in rule.gen_str ( level ):
+            yield s
+   # --- end of _gen_alt_rules_str (...) ---
+
+   def _iter_all_rules ( self, with_self=True ):
       if with_self:
          yield self
 
       for rule in self._rules:
-         for nested_rule in rule._iter_rules ( with_self=True ):
+         for nested_rule in rule._iter_all_rules ( with_self=True ):
+            yield nested_rule
+
+      for rule in self._alt_rules:
+         for nested_rule in rule._iter_all_rules ( with_self=True ):
             yield nested_rule
-   # --- end of _iter_rules (...) ---
+   # --- end of _iter_all_rules (...) ---
 
    def set_logger ( self, logger ):
       """Assigns a logger to this package rule and all actions.
@@ -196,13 +291,17 @@ class NestedPackageRule ( PackageRule ):
       * logger --
       """
       super ( NestedPackageRule, self ).set_logger ( logger )
-      if hasattr ( self, 'is_toplevel' ) and self.is_toplevel:
+
+      if self.is_toplevel:
          nested_logger = self.logger.getChild ( 'nested' )
-         for nested_rule in self._rules:
-            nested_rule.set_logger ( nested_logger )
       else:
-         for nested_rule in self._rules:
-            nested_rule.set_logger ( self.logger )
+         nested_logger = self.logger
+
+      for nested_rule in self._rules:
+         nested_rule.set_logger ( nested_logger )
+
+      for nested_rule in self._alt_rules:
+         nested_rule.set_logger ( nested_logger )
    # --- end of set_logger (...) ---
 
    def prepare ( self ):
@@ -212,7 +311,8 @@ class NestedPackageRule ( PackageRule ):
       super ( NestedPackageRule, self ).prepare()
       for rule in self._rules:
          rule.prepare()
-      self._rules = roverlay.util.priosort ( self._rules )
+      self._rules     = roverlay.util.priosort ( self._rules )
+      self._alt_rules = roverlay.util.priosort ( self._alt_rules )
    # --- end of prepare (...) ---
 
    def apply_actions ( self, p_info ):
@@ -226,13 +326,37 @@ class NestedPackageRule ( PackageRule ):
       """
       if super ( NestedPackageRule, self ).apply_actions ( p_info ):
          for rule in self._rules:
-            if rule.accepts ( p_info ) and not rule.apply_actions ( p_info ):
+            if rule.accepts ( p_info ):
+               if not rule.apply_actions ( p_info ):
+                  return False
+            elif not rule.apply_alternative_actions ( p_info ):
                return False
          return True
       else:
          return False
    # --- end of apply_actions (...) ---
 
+   def apply_alternative_actions ( self, p_info ):
+      """Applies all 'alternative' actions to the given PackageInfo.
+
+      arguments:
+      * p_info --
+      """
+      if ( super (
+         NestedPackageRule, self ).apply_alternative_actions ( p_info )
+      ):
+         for rule in self._alt_rules:
+            if rule.accepts ( p_info ):
+               if not rule.apply_actions ( p_info ):
+                  return False
+            elif not rule.apply_alternative_actions ( p_info ):
+               return False
+
+         return True
+      else:
+         return False
+   # --- end of apply_alternative_actions (...) ---
+
    def add_rule ( self, rule ):
       """Adds a rule.
 
@@ -242,4 +366,13 @@ class NestedPackageRule ( PackageRule ):
       self._rules.append ( rule )
    # --- end of add_rule (...) ---
 
+   def add_alternative_rule ( self, rule ):
+      """Adds an 'alternative' rule.
+
+      arguments:
+      * rule --
+      """
+      self._alt_rules.append ( rule )
+   # --- end of add_alternative_rule (...) ---
+
 # --- end of NestedPackageRule ---

diff --git a/roverlay/packagerules/acceptors/stringmatch.py b/roverlay/packagerules/acceptors/stringmatch.py
index f5da49f..b6007b6 100644
--- a/roverlay/packagerules/acceptors/stringmatch.py
+++ b/roverlay/packagerules/acceptors/stringmatch.py
@@ -103,8 +103,10 @@ class RegexAcceptor (
                self.__class__.__name__
             )
          )
-
-      self._regex = regex_compiled if regex_compiled else re.compile ( regex )
+      elif regex_compiled:
+         self._regex = regex_compiled
+      else:
+         self._regex = re.compile ( regex )
    # --- end of __init__ (...) ---
 
    def _matches ( self, value ):

diff --git a/roverlay/packagerules/actions/evar.py b/roverlay/packagerules/actions/evar.py
index c789219..17f46fe 100644
--- a/roverlay/packagerules/actions/evar.py
+++ b/roverlay/packagerules/actions/evar.py
@@ -46,7 +46,7 @@ class EvarAction ( roverlay.packagerules.abstract.actions.PackageRuleAction ):
 
    def gen_str ( self, level ):
       yield (
-         level * '   ' + self._evar.name.lower()
+         ( level * self.INDENT ) + self._evar.name.lower()
          + ' "' + self._evar.value + '"'
       )
    # --- end of gen_str (...) ---

diff --git a/roverlay/packagerules/actions/ignore.py b/roverlay/packagerules/actions/ignore.py
new file mode 100644
index 0000000..5ee19f9
--- /dev/null
+++ b/roverlay/packagerules/actions/ignore.py
@@ -0,0 +1,25 @@
+# R overlay -- package rule actions, ignore package
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import roverlay.packagerules.abstract.actions
+
+__all__ = [ 'IgnoreAction', ]
+
+class IgnoreAction (
+   roverlay.packagerules.abstract.actions.PackageRuleAction
+):
+
+   KEYWORD = 'ignore'
+
+   def apply_action ( self, p_info ):
+      return False
+   # --- end of apply_action (...) ---
+
+   def gen_str ( self, level ):
+      yield ( level * self.INDENT ) + self.KEYWORD
+   # --- end of gen_str (...) ---
+
+# --- end of IgnoreAction ---

diff --git a/roverlay/packagerules/actions/info.py b/roverlay/packagerules/actions/info.py
index 538fdef..d9f1390 100644
--- a/roverlay/packagerules/actions/info.py
+++ b/roverlay/packagerules/actions/info.py
@@ -59,7 +59,7 @@ class InfoRenameAction (
       # FIXME: that's not always correct!
       # (could be solved by storing the original regex delimiter)
       yield (
-         level * '   ' + 'rename ' + self.key
+         level * self.INDENT + 'rename ' + self.key
          + ' s/' + self.regex.pattern + '/' + self.subst + '/' # + flags
       )
    # --- end of gen_str (...) ---
@@ -162,7 +162,7 @@ class InfoSetToAction (
    # --- end of apply_action (...) ---
 
    def gen_str ( self, level ):
-      yield ( level * '   ' + 'set ' + self.key + ' ' + self.value )
+      yield ( level * self.INDENT + 'set ' + self.key + ' ' + self.value )
    # --- end of gen_str (...) ---
 
 # --- end of InfoSetToAction ---

diff --git a/roverlay/packagerules/actions/trace.py b/roverlay/packagerules/actions/trace.py
index 669969a..c16f6c6 100644
--- a/roverlay/packagerules/actions/trace.py
+++ b/roverlay/packagerules/actions/trace.py
@@ -38,7 +38,7 @@ class TraceAction (
    # --- end of apply_action (...) ---
 
    def gen_str ( self, level ):
-      yield ( level * '   ' ) + "trace " + str ( self._ident )
+      yield ( level * self.INDENT ) + "trace " + str ( self._ident )
    # --- end of gen_str (...) ---
 
 
@@ -57,5 +57,5 @@ class MarkAsModifiedAction (
    # --- end of apply_action (...) ---
 
    def gen_str ( self, level ):
-      yield ( level * '   ' ) + "trace"
+      yield ( level * self.INDENT ) + "trace"
    # --- end of gen_str (...) ---

diff --git a/roverlay/packagerules/parser/context/action.py b/roverlay/packagerules/parser/context/action.py
index 22936cc..49ed7db 100644
--- a/roverlay/packagerules/parser/context/action.py
+++ b/roverlay/packagerules/parser/context/action.py
@@ -37,14 +37,16 @@ class RuleActionContext (
    """RuleActionContext parses action-blocks."""
 
    # keywords for the "ignore" action
-   KEYWORDS_ACTION_IGNORE = frozenset ((
+   KEYWORDS_ACTION_IGNORE = frozenset ({
       'ignore',
       'do-not-process'
-   ))
+   })
 
-   KEYWORDS_ACTION_TRACE = frozenset ((
+   KEYWORDS_ACTION_TRACE = frozenset ({
       'trace',
-   ))
+   })
+
+   KEYWORDS_NO_ACTION = frozenset ({ 'pass', 'null', })
 
    # dict ( <keyword> => <evar class> )
    # Dict of evar action keywords (with corresponding classes)
@@ -225,7 +227,9 @@ class RuleActionContext (
       Raises:
       * InvalidContext
       """
-      if _str in self.KEYWORDS_ACTION_IGNORE:
+      if _str in self.KEYWORDS_NO_ACTION:
+         pass
+      elif _str in self.KEYWORDS_ACTION_IGNORE:
          if not self._actions:
             self._actions = None
          else:
@@ -255,7 +259,9 @@ class RuleActionContext (
                   )
                )
 
-         elif self._add_as_info_action ( argv [0], argv [1], _str, lino ):
+         elif len ( argv ) > 1 and (
+            self._add_as_info_action ( argv [0], argv [1], _str, lino )
+         ):
             pass
 
          else:

diff --git a/roverlay/packagerules/parser/context/base.py b/roverlay/packagerules/parser/context/base.py
index 1a09a79..9bd97b7 100644
--- a/roverlay/packagerules/parser/context/base.py
+++ b/roverlay/packagerules/parser/context/base.py
@@ -15,7 +15,7 @@ class BaseContext ( object ):
       self.namespace = namespace
    # --- end of __init__ (...) ---
 
-   def feed ( self, _str ):
+   def feed ( self, _str, lino ):
       raise NotImplementedError()
    # --- end of feed (...) ---
 

diff --git a/roverlay/packagerules/parser/context/rule.py b/roverlay/packagerules/parser/context/rule.py
index 2601d7e..0f6f342 100644
--- a/roverlay/packagerules/parser/context/rule.py
+++ b/roverlay/packagerules/parser/context/rule.py
@@ -4,11 +4,18 @@
 # Distributed under the terms of the GNU General Public License;
 # either version 2 of the License, or (at your option) any later version.
 
-from roverlay.packagerules.abstract import rules
+import roverlay.packagerules.abstract.rules
+from roverlay.packagerules.abstract.rules import \
+   IgnorePackageRule, PackageRule, NestedPackageRule
 
-from . import base, match, action
+import roverlay.packagerules.parser.context.action
+import roverlay.packagerules.parser.context.base
+import roverlay.packagerules.parser.context.match
 
-class RuleContext ( base.NestableContext ):
+
+class RuleContext (
+   roverlay.packagerules.parser.context.base.NestableContext
+):
    """Class for creating rules from text input (feed(<>)) plus using a few
    control flow functions (end_of_rule(), begin_match(), begin_action()).
    """
@@ -29,28 +36,55 @@ class RuleContext ( base.NestableContext ):
    #
    # (use bitwise operators to check against these values)
    #
-   CONTEXT_NONE        = 0 # == only
-   CONTEXT_MAIN_MATCH  = 1
-   CONTEXT_MAIN_ACTION = 2
-   CONTEXT_SUB_MATCH   = 4
-   CONTEXT_SUB_ACTION  = 8
+   CONTEXT_NONE            = 0 # == only
+   CONTEXT_MAIN_MATCH      = 1
+   CONTEXT_MAIN_ACTION     = 2
+   CONTEXT_MAIN_ALT_ACTION = 4
+   CONTEXT_SUB_MATCH       = 8
+   CONTEXT_SUB_ACTION      = 16
+   # else-block is a non-propagating status
+   #CONTEXT_SUB_ALT_ACTION
+
+   CONTEXT_MATCH           = CONTEXT_MAIN_MATCH      | CONTEXT_SUB_MATCH
+   CONTEXT_ACTION          = CONTEXT_MAIN_ACTION     | CONTEXT_SUB_ACTION
+   CONTEXT_MAIN_ANY_ACTION = CONTEXT_MAIN_ALT_ACTION | CONTEXT_MAIN_ACTION
+   CONTEXT_SUB             = CONTEXT_SUB_MATCH       | CONTEXT_SUB_ACTION
+
+   CONTEXT_MAIN = (
+      CONTEXT_MAIN_MATCH | CONTEXT_MAIN_ACTION | CONTEXT_MAIN_ALT_ACTION
+   )
 
-   CONTEXT_MATCH  = CONTEXT_MAIN_MATCH  | CONTEXT_SUB_MATCH
-   CONTEXT_ACTION = CONTEXT_MAIN_ACTION | CONTEXT_SUB_ACTION
-   CONTEXT_MAIN   = CONTEXT_MAIN_MATCH  | CONTEXT_MAIN_ACTION
-   CONTEXT_SUB    = CONTEXT_SUB_MATCH   | CONTEXT_SUB_ACTION
 
    # -- end of CONTEXT_ --
 
-   def __init__ ( self, namespace, level=0, priority=-1 ):
+   def __init__ ( self, namespace, level=0, priority=-1, mode=None ):
       super ( RuleContext, self ).__init__ ( namespace, level )
 
-      self.context         = self.CONTEXT_MAIN_MATCH
-      self.priority        = priority
-      self._action_context = action.RuleActionContext ( self.namespace )
-      self._match_context  = match.RuleMatchContext (
-         namespace = self.namespace,
-         priority  = priority
+      if mode is None:
+         if level == 0:
+            self.mode = self.CONTEXT_MAIN_ACTION
+         else:
+            raise Exception ( "mode has to be set if level is non-zero." )
+      else:
+         self.mode = mode
+
+      self.context             = self.CONTEXT_MAIN_MATCH
+      self.priority            = priority
+      self._action_context     = (
+         roverlay.packagerules.parser.context.action.RuleActionContext (
+            self.namespace
+         )
+      )
+      self._alt_action_context = (
+         roverlay.packagerules.parser.context.action.RuleActionContext (
+            self.namespace
+         )
+      )
+      self._match_context      = (
+         roverlay.packagerules.parser.context.match.RuleMatchContext (
+            namespace = self.namespace,
+            priority  = priority
+         )
       )
    # --- end of __init__ (...) ---
 
@@ -66,15 +100,22 @@ class RuleContext ( base.NestableContext ):
       # nested rules are stored in self._nested (and not in
       # self._action_context where they syntactically belong to)
 
-      if self.context & self.CONTEXT_MAIN_ACTION:
-         # a nested rule (with depth = 1)
-         self._new_nested ( priority=lino )
-         self.context = self.CONTEXT_SUB_MATCH
-      elif self.context & self.CONTEXT_SUB_ACTION:
+      if self.context & self.CONTEXT_SUB_ACTION:
          # a nested rule inside a nested one (depth > 1)
          # => redirect to nested
          self.get_nested().begin_match ( lino )
-         self.context = self.CONTEXT_SUB_MATCH
+         self.context |= self.CONTEXT_SUB_MATCH
+
+      elif self.context & self.CONTEXT_MAIN_ACTION:
+         # a nested rule (with depth = 1)
+         self._new_nested ( priority=lino, mode=self.CONTEXT_MAIN_ACTION )
+         self.context |= self.CONTEXT_SUB_MATCH
+
+      elif self.context & self.CONTEXT_MAIN_ALT_ACTION:
+         # a new nested rule in the else block (with depth = 1)
+         self._new_nested ( priority=lino, mode=self.CONTEXT_MAIN_ALT_ACTION )
+         self.context |= self.CONTEXT_SUB_MATCH
+
       else:
          # illegal
          raise self.InvalidContext()
@@ -87,21 +128,50 @@ class RuleContext ( base.NestableContext ):
       * lino -- line number
 
       Raises: InvalidContext,
-               an action-block has to be preceeded by a match-block
+               an action block has to be preceeded by a match block
       """
-      if self.context & self.CONTEXT_MAIN_MATCH:
-         # begin of the main action-block
-         self.context = self.CONTEXT_MAIN_ACTION
-      elif self.context & self.CONTEXT_SUB_MATCH:
+      if self.context & self.CONTEXT_SUB_MATCH:
          # action-block of a nested rule
          # => redirect to nested
          self.get_nested().begin_action ( lino )
-         self.context = self.CONTEXT_SUB_ACTION
+         self.context &= ~self.CONTEXT_SUB_MATCH
+         self.context |= self.CONTEXT_SUB_ACTION
+
+      elif self.context & self.CONTEXT_MAIN_MATCH:
+         # begin of the main action-block
+         self.context &= ~self.CONTEXT_MAIN_MATCH
+         self.context |= self.CONTEXT_MAIN_ACTION
+
       else:
          # illegal
          raise self.InvalidContext()
    # --- end of begin_action (...) ---
 
+   def begin_alternative_action ( self, lino ):
+      """Create/begin an else-action block of a rule (nested or "self").
+
+      arguments:
+      * lino -- line number
+
+      Raises: InvalidContext,
+               an else-action block has to be preceeded by an action block
+      """
+      if self.context & self.CONTEXT_SUB_ACTION:
+         # else-action-block of a nested rule
+         #  => redirect to nested
+         #  no status change as else-blocks are handled non-recursively
+         self.get_nested().begin_alternative_action ( lino )
+
+      elif self.context & self.CONTEXT_MAIN_ACTION:
+         # begin of the main else-action-block
+         self.context &= ~self.CONTEXT_MAIN_ACTION
+         self.context |= self.CONTEXT_MAIN_ALT_ACTION
+
+      else:
+         # illegal
+         raise self.InvalidContext()
+   # --- end of begin_alternative_action (...) ---
+
    def end_of_rule ( self, lino ):
       """Has to be called whenever an end-of-rule statement has been reached
       and ends a rule, either this one or a nested one (depending on the
@@ -116,14 +186,10 @@ class RuleContext ( base.NestableContext ):
       Raises: InvalidContext,
                rules can only be closed if within an action-block
       """
-      if self.context & self.CONTEXT_MAIN_ACTION:
-         # end of this rule
-         self.context = self.CONTEXT_NONE
-         return True
-      elif self.context & self.CONTEXT_SUB_ACTION:
+      if self.context & self.CONTEXT_SUB_ACTION:
          if self.get_nested().end_of_rule ( lino ):
             # end of child rule (depth=1)
-            self.context = self.CONTEXT_MAIN_ACTION
+            self.context &= ~self.CONTEXT_SUB_ACTION
 
 # no-op, since self.context is already CONTEXT_SUB_ACTION
 #         else:
@@ -131,6 +197,17 @@ class RuleContext ( base.NestableContext ):
 #            self.context = self.CONTEXT_SUB_ACTION
 
          return False
+
+      elif self.context & self.CONTEXT_MAIN_ANY_ACTION:
+         # end of this rule
+         #self.context = self.CONTEXT_NONE
+         self.context &= ~self.CONTEXT_MAIN_ANY_ACTION
+         if self.context != self.CONTEXT_NONE:
+            raise AssertionError (
+               "broken context bit mask {:d}!".format ( self.context )
+            )
+         return True
+
       else:
          raise self.InvalidContext()
    # --- end of end_of_rule (...) ---
@@ -145,12 +222,18 @@ class RuleContext ( base.NestableContext ):
       Raises: InvalidContext if this rule does not accept input
               (if self.context is CONTEXT_NONE)
       """
-      if self.context & self.CONTEXT_MAIN_MATCH:
+      if self.context & self.CONTEXT_SUB:
+         return self.get_nested().feed ( _str, lino )
+
+      elif self.context & self.CONTEXT_MAIN_MATCH:
          return self._match_context.feed ( _str, lino )
+
       elif self.context & self.CONTEXT_MAIN_ACTION:
          return self._action_context.feed ( _str, lino )
-      elif self.context & self.CONTEXT_SUB:
-         return self.get_nested().feed ( _str, lino )
+
+      elif self.context & self.CONTEXT_MAIN_ALT_ACTION:
+         return self._alt_action_context.feed ( _str, lino )
+
       else:
          raise self.InvalidContext()
    # --- end of feed (...) ---
@@ -171,37 +254,71 @@ class RuleContext ( base.NestableContext ):
          raise self.InvalidContext ( "end_of_rule not reached." )
       # -- if;
 
-      package_rule = None
-      actions      = self._action_context.create()
-      acceptor     = self._match_context.create()
+      package_rule  = None
+      actions       = self._action_context.create()
+      alt_actions   = self._alt_action_context.create()
+      acceptor      = self._match_context.create()
+      ACTION_IGNORE = self.namespace.get_ignore_action()
 
       if not acceptor:
          raise Exception ( "empty match-block makes no sense." )
 
+      elif actions is None and alt_actions is None:
+         raise Exception ( "ignore-all rule makes no sense." )
+
       elif len ( self._nested ) > 0:
          # nested rule
+         package_rule = NestedPackageRule ( priority=self.priority )
+         for nested in self._nested:
+            nested_rule = nested.create()
+            if nested.mode == self.CONTEXT_MAIN_ACTION:
+               package_rule.add_rule ( nested_rule )
+            elif nested.mode == self.CONTEXT_MAIN_ALT_ACTION:
+               package_rule.add_alternative_rule ( nested_rule )
+            else:
+               raise Exception ( "nested rule has invalid mode" )
+
          if actions is None:
-            raise Exception (
-               "ignore action-block cannot contain nested rules."
-            )
+            package_rule.add_action ( ACTION_IGNORE )
          else:
-            package_rule = rules.NestedPackageRule ( priority=self.priority )
-            for nested in self._nested:
-               package_rule.add_rule ( nested.create() )
+            for rule_action in actions:
+               package_rule.add_action ( rule_action )
 
-            for action in actions:
-               package_rule.add_action ( action )
+         if alt_actions is None:
+            package_rule.add_alternative_action ( ACTION_IGNORE )
+         else:
+            for rule_action in alt_actions:
+               package_rule.add_alternative_action ( rule_action )
 
       elif actions is None:
-         # ignore rule
-         package_rule = rules.IgnorePackageRule ( priority=self.priority )
+         if alt_actions:
+            # ignore rule with else-action block
+            package_rule = PackageRule ( priority=self.priority )
+            package_rule.add_action ( ACTION_IGNORE )
+
+            for rule_action in alt_actions:
+               package_rule.add_alternative_action ( rule_action )
+         else:
+            # ignore rule
+            package_rule = IgnorePackageRule ( priority=self.priority )
+
+      elif alt_actions is None:
+         # normal rule with else-ignore block
+         package_rule = PackageRule ( priority=self.priority )
+         package_rule.add_alternative_action ( ACTION_IGNORE )
+
+         for rule_action in actions:
+            package_rule.add_action ( rule_action )
+
+      elif actions or alt_actions:
+         # normal rule with action and/or else-action block
+         package_rule = PackageRule ( priority=self.priority )
 
-      elif actions:
-         # normal rule
-         package_rule = rules.PackageRule ( priority=self.priority )
+         for rule_action in actions:
+            package_rule.add_action ( rule_action )
 
-         for action in actions:
-            package_rule.add_action ( action )
+         for rule_action in alt_actions:
+            package_rule.add_alternative_action ( rule_action )
 
       else:
          raise Exception ( "empty action-block makes no sense." )

diff --git a/roverlay/packagerules/parser/namespace.py b/roverlay/packagerules/parser/namespace.py
index 6af8661..ab9b7d8 100644
--- a/roverlay/packagerules/parser/namespace.py
+++ b/roverlay/packagerules/parser/namespace.py
@@ -6,6 +6,8 @@
 
 import roverlay.util
 
+import roverlay.packagerules.actions.ignore
+
 DEBUG_GET_OBJECT = False
 
 if DEBUG_GET_OBJECT:
@@ -36,8 +38,15 @@ class RuleNamespace ( object ):
       #  )
       #
       self._objects = dict()
+      self._ignore_action = (
+         roverlay.packagerules.actions.ignore.IgnoreAction()
+      )
    # --- end of __init__ (...) ---
 
+   def get_ignore_action ( self ):
+      return self._ignore_action
+   # --- end of get_ignore_action (...) ---
+
    def get_object ( self, cls, *args, **kwargs ):
       """Returns the desired object.
 

diff --git a/roverlay/packagerules/parser/text.py b/roverlay/packagerules/parser/text.py
index 4060e95..87db0b0 100644
--- a/roverlay/packagerules/parser/text.py
+++ b/roverlay/packagerules/parser/text.py
@@ -20,17 +20,16 @@ class RuleParser ( object ):
    # control flow statements
    #  all other keywords are defined in the respective context classes,
    #  namely RuleContext, RuleMatchContext and RuleActionContext
-   KEYWORDS_MATCH  = frozenset (( 'match:', 'MATCH:', ))
-   KEYWORDS_ACTION = frozenset (( 'action:', 'ACTION:' ))
-   KEYWORDS_END    = frozenset (( 'end;', 'END;' ))
+   KEYWORDS_MATCH       = frozenset ({ 'match:', 'MATCH:', })
+   KEYWORDS_ACTION      = frozenset ({ 'action:', 'ACTION:' })
+   KEYWORDS_ACTION_ELSE = frozenset ({ 'else:', 'ELSE:' })
+   KEYWORDS_END         = frozenset ({ 'end;', 'END;' })
 
-   COMMENT_CHARS   = frozenset ( "#;" )
+   COMMENT_CHARS        = frozenset ({ '#', ';' })
 
    def _zap ( self ):
       self.namespace.zap ( zap_object_db=False )
-      # the rule block (RuleContext) that is currently active
       self._current_rule = None
-      # previous rule blocks
       self._parsed_rules = list()
    # --- end of _zap (...) ---
 
@@ -44,6 +43,11 @@ class RuleParser ( object ):
       self.namespace = roverlay.packagerules.parser.namespace.RuleNamespace()
       self.add_rule = add_rule_method
       self._zap()
+
+      # the rule block (RuleContext) that is currently active
+      self._current_rule = None
+      # previous rule blocks
+      self._parsed_rules = None
    # --- end of __init__ (...) ---
 
    def _feed ( self, l, lino ):
@@ -59,6 +63,8 @@ class RuleParser ( object ):
                self._current_rule.begin_match ( lino )
             elif l in self.KEYWORDS_ACTION:
                self._current_rule.begin_action ( lino )
+            elif l in self.KEYWORDS_ACTION_ELSE:
+               self._current_rule.begin_alternative_action ( lino )
             elif l in self.KEYWORDS_END:
                if self._current_rule.end_of_rule ( lino ):
                   # add rule to self._parsed_rules

diff --git a/roverlay/packagerules/rules.py b/roverlay/packagerules/rules.py
index 649343a..9ca91e5 100644
--- a/roverlay/packagerules/rules.py
+++ b/roverlay/packagerules/rules.py
@@ -45,7 +45,6 @@ class PackageRules ( roverlay.packagerules.abstract.rules.NestedPackageRule ):
 
    def __init__ ( self ):
       super ( PackageRules, self ).__init__ ( priority=-1 )
-      del self._acceptor
       self.logger = logging.getLogger ( self.__class__.__name__ )
       self.is_toplevel = True
    # --- end of __init__ (...) ---
@@ -69,17 +68,27 @@ class PackageRules ( roverlay.packagerules.abstract.rules.NestedPackageRule ):
       return True
    # --- end of accepts (...) ---
 
+   def apply_alternative_actions ( self, p_info ):
+      raise Exception ( "toplevel rule does not contain else-block actions." )
+   # --- end of apply_alternative_actions (...) ---
+
+   def add_alternative_action ( self, action ):
+      raise Exception ( "toplevel rule does not accept else-block actions." )
+   # --- end of add_alternative_action (...) ---
+
    def add_trace_actions ( self ):
       """Adds MarkAsModified actions to this rule and all nested ones.
 
-      Meant for testing the package rule system."""
-
+      Meant for testing the package rule system.
+      """
       marker = roverlay.packagerules.actions.trace.MarkAsModifiedAction ( -1 )
-      for rule in filter (
-         lambda rule : hasattr ( rule, 'add_action' ),
-         self._iter_rules ( with_self=False )
-      ):
-         rule.add_action ( marker )
+
+      for rule in self._iter_all_rules ( with_self=False ):
+         if hasattr ( rule, 'add_action' ):
+            rule.add_action ( marker )
+
+         if hasattr ( rule, 'add_alternative_action' ):
+            rule.add_alternative_action ( marker )
 
       self.prepare()
    # --- end of add_trace_actions (...) ---


             reply	other threads:[~2013-08-01 12:45 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-01 12:44 André Erdmann [this message]
  -- strict thread matches above, loose matches on Subject: below --
2013-06-13 16:34 [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, André Erdmann
2013-03-01 19:00 André Erdmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1375360359.703b273c1559be91ad2e7eeceff1b963e0f91e8a.dywi@gentoo \
    --to=dywi@mailerd.de \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox