If the filter starting a conditional block is preceded by '!', the condition is
negative.  For example:

!Fedora.14, RHEL.6.0:
    only qcow2

means "for everything except Fedora.14 and RHEL.6.0, allow only qcow2".

Signed-off-by: Michael Goldish <mgold...@redhat.com>
---
 client/tests/kvm/kvm_config.py |   59 +++++++++++++++++++++++++++-------------
 1 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/client/tests/kvm/kvm_config.py b/client/tests/kvm/kvm_config.py
index b6e089b..4dbb1d4 100755
--- a/client/tests/kvm/kvm_config.py
+++ b/client/tests/kvm/kvm_config.py
@@ -137,6 +137,14 @@ class NoOnlyFilter(Filter):
 
 
 class OnlyFilter(NoOnlyFilter):
+    def is_irrelevant(self, ctx, ctx_set, descendant_labels):
+        return self.match(ctx, ctx_set)
+
+
+    def requires_action(self, ctx, ctx_set, descendant_labels):
+        return not self.might_match(ctx, ctx_set, descendant_labels)
+
+
     def might_pass(self, failed_ctx, failed_ctx_set, ctx, ctx_set,
                    descendant_labels):
         for word in self.filter:
@@ -148,6 +156,14 @@ class OnlyFilter(NoOnlyFilter):
 
 
 class NoFilter(NoOnlyFilter):
+    def is_irrelevant(self, ctx, ctx_set, descendant_labels):
+        return not self.might_match(ctx, ctx_set, descendant_labels)
+
+
+    def requires_action(self, ctx, ctx_set, descendant_labels):
+        return self.match(ctx, ctx_set)
+
+
     def might_pass(self, failed_ctx, failed_ctx_set, ctx, ctx_set,
                    descendant_labels):
         for word in self.filter:
@@ -165,6 +181,13 @@ class Condition(NoFilter):
         self.content = []
 
 
+class NegativeCondition(OnlyFilter):
+    def __init__(self, line):
+        Filter.__init__(self, line.lstrip("!").rstrip(":"))
+        self.line = line
+        self.content = []
+
+
 class Parser(object):
     """
     Parse an input file or string that follows the KVM Test Config File format
@@ -229,24 +252,15 @@ class Parser(object):
                 if type(obj) is Op:
                     new_content.append(t)
                     continue
-                elif type(obj) is OnlyFilter:
-                    if not obj.might_match(ctx, ctx_set, labels):
-                        self._debug("    filter did not pass: %r (%s:%s)",
-                                    obj.line, filename, linenum)
-                        failed_filters.append(t)
-                        return False
-                    elif obj.match(ctx, ctx_set):
-                        continue
-                elif type(obj) is NoFilter:
-                    if obj.match(ctx, ctx_set):
+                # obj is an OnlyFilter/NoFilter/Condition/NegativeCondition
+                if obj.requires_action(ctx, ctx_set, labels):
+                    # This filter requires action now
+                    if type(obj) is OnlyFilter or type(obj) is NoFilter:
                         self._debug("    filter did not pass: %r (%s:%s)",
                                     obj.line, filename, linenum)
                         failed_filters.append(t)
                         return False
-                    elif not obj.might_match(ctx, ctx_set, labels):
-                        continue
-                elif type(obj) is Condition:
-                    if obj.match(ctx, ctx_set):
+                    else:
                         self._debug("    conditional block matches: %r 
(%s:%s)",
                                     obj.line, filename, linenum)
                         # Check and unpack the content inside this Condition
@@ -259,9 +273,12 @@ class Parser(object):
                             failed_filters.append(t)
                             return False
                         continue
-                    elif not obj.might_match(ctx, ctx_set, labels):
-                        continue
-                new_content.append(t)
+                elif obj.is_irrelevant(ctx, ctx_set, labels):
+                    # This filter is no longer relevant and can be removed
+                    continue
+                else:
+                    # Keep the filter and check it again later
+                    new_content.append(t)
             return True
 
         def might_pass(failed_ctx,
@@ -429,7 +446,8 @@ class Parser(object):
             # Parse 'variants'
             if line == "variants:":
                 # 'variants' is not allowed inside a conditional block
-                if isinstance(node, Condition):
+                if (isinstance(node, Condition) or
+                    isinstance(node, NegativeCondition)):
                     raise ParserError("'variants' is not allowed inside a "
                                       "conditional block",
                                       None, cr.filename, linenum)
@@ -481,7 +499,10 @@ class Parser(object):
                     cr.set_next_line(line[index:], indent, linenum)
                     line = line[:index]
                     try:
-                        cond = Condition(line)
+                        if line.startswith("!"):
+                            cond = NegativeCondition(line)
+                        else:
+                            cond = Condition(line)
                     except ParserError, e:
                         e.line = line
                         e.filename = cr.filename
-- 
1.7.3.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to