[virt-test][PATCH 6/7] virt: Adds possibility filter defaults variant from variants

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If default variant is not filtered by only or no filters then
only default variant is chosen. This behavior was used for optimizing
of speed of Cartesian config.
If variants don't have default variant then everything works as usual.
Default variant must be in variants with with_default exactly one times.
The default variant could be filtered by only, no filter. If default
variant is filtered from variants then variants works same as usual variants with
default variant.

For calling Cartesian config from command line is used option -d/--defaults:
   ../virttest/cartesian_config.py -d cfg/cc.cfg

For calling Cartesian config from python:
   c = Parser(args[0], defaults=options.defaults, debug=options.debug)

*********  example:
variants name=tests:
  - wait:
       run = "wait"
       variants:
         - long:
            time = short_time
         - short: long
            time = logn_time
  - test2:
       run = "test1"

variants name=virt_system, with_default:
  - @linux:
  - windows:

variants name=host_os, with_default:
  - linux:
       image = linux
       variants with_default:
            - ubuntu:
            - @fedora:
  - windows:
       image = windows
       variants:
            - @XP:
            - WIN7:

only host_os>windows

In this case is chosen from host_os variants windows variant.
host_os>windows was choosen because default variant linux was filtered.
Next step is select one variant from guest_os. There will be chosen only
default variant linux because not filtered and virt_system variant is
with with_default. There is no default variant in tests variants because
that all of tests will be chosen.

********  output:
dict    1:  host_os>windows.tests>wait.long
    dep = []
    host_os = windows
    image = windows
    name = host_os>windows.XP.virt_system>linux.tests>wait.long
    run = wait
    shortname = host_os>windows.tests>wait.long
    tests = wait
    time = short_time
    virt_system = linux
dict    2:  host_os>windows.tests>wait.short
    dep = ['host_os>windows.XP.virt_system>linux.tests>wait.long']
    host_os = windows
    image = windows
    name = host_os>windows.XP.virt_system>linux.tests>wait.short
    run = wait
    shortname = host_os>windows.tests>wait.short
    tests = wait
    time = logn_time
    virt_system = linux
dict    3:  host_os>windows.tests>test2
    dep = []
    host_os = windows
    image = windows
    name = host_os>windows.XP.virt_system>linux.tests>test2
    run = test1
    shortname = host_os>windows.tests>test2
    tests = test2
    virt_system = linux
dict    4:  host_os>windows.WIN7.tests>wait.long
    dep = []
    host_os = windows
    image = windows
    name = host_os>windows.WIN7.virt_system>linux.tests>wait.long
    run = wait
    shortname = host_os>windows.WIN7.tests>wait.long
    tests = wait
    time = short_time
    virt_system = linux
dict    5:  host_os>windows.WIN7.tests>wait.short
    dep = ['host_os>windows.WIN7.virt_system>linux.tests>wait.long']
    host_os = windows
    image = windows
    name = host_os>windows.WIN7.virt_system>linux.tests>wait.short
    run = wait
    shortname = host_os>windows.WIN7.tests>wait.short
    tests = wait
    time = logn_time
    virt_system = linux
dict    6:  host_os>windows.WIN7.tests>test2
    dep = []
    host_os = windows
    image = windows
    name = host_os>windows.WIN7.virt_system>linux.tests>test2
    run = test1
    shortname = host_os>windows.WIN7.tests>test2
    tests = test2
    virt_system = linux

Signed-off-by: Jiří Župka <jzupka@xxxxxxxxxx>
---
 virttest/cartesian_config.py | 82 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 68 insertions(+), 14 deletions(-)

diff --git a/virttest/cartesian_config.py b/virttest/cartesian_config.py
index 04ed2b5..6cd0e88 100755
--- a/virttest/cartesian_config.py
+++ b/virttest/cartesian_config.py
@@ -131,6 +131,10 @@ class ParserError:
             return "%s (%s:%s)" % (self.msg, self.filename, self.linenum)
 
 
+class MissingDefault:
+    pass
+
+
 class MissingIncludeError:
     def __init__(self, line, filename, linenum):
         self.line = line
@@ -225,6 +229,7 @@ class Node(object):
         self.labels = set()
         self.append_to_shortname = False
         self.failed_cases = collections.deque()
+        self.default = False
 
 
     def dump(self, indent, recurse=False):
@@ -407,14 +412,17 @@ class Parser(object):
 
     @see: https://github.com/autotest/autotest/wiki/KVMAutotest-CartesianConfigParametersIntro
     """
-    def __init__(self, filename=None, debug=False):
+    def __init__(self, filename=None, defaults=False, debug=False):
         """
         Initialize the parser and optionally parse a file.
 
         @param filename: Path of the file to parse.
+        @param defaults: If True adds only defaults variant from variants
+                         if there is some.
         @param debug: Whether to turn on debugging output.
         """
         self.node = Node()
+        self.defaults = defaults
         self.debug = debug
         if filename:
             self.parse_file(filename)
@@ -611,10 +619,18 @@ class Parser(object):
 
         # Recurse into children
         count = 0
-        for n in node.children:
-            for d in self.get_dicts(n, ctx, new_content, shortname, dep):
-                count += 1
-                yield d
+        if self.defaults:
+            for n in node.children:
+                for d in self.get_dicts(n, ctx, new_content, shortname, dep):
+                    count += 1
+                    yield d
+                if n.default and count:
+                    break
+        else:
+            for n in node.children:
+                for d in self.get_dicts(n, ctx, new_content, shortname, dep):
+                    count += 1
+                    yield d
         # Reached leaf?
         if not node.children:
             self._debug("    reached leaf, returning it")
@@ -656,7 +672,8 @@ class Parser(object):
         print s % args
 
 
-    def _parse_variants(self, cr, node, prev_indent=-1, var_name=None):
+    def _parse_variants(self, cr, node, prev_indent=-1, var_name=None,
+                        with_default=False):
         """
         Read and parse lines from a FileReader object until a line with an
         indent level lower than or equal to prev_indent is encountered.
@@ -665,8 +682,10 @@ class Parser(object):
         @param node: A node to operate on.
         @param prev_indent: The indent level of the "parent" block.
         @param var_name: Variants name
+        @param with_default: Variants take only default variant.
         @return: A node object.
         """
+        already_default = False
         node4 = Node()
 
         while True:
@@ -694,7 +713,9 @@ class Parser(object):
             node2.labels = node.labels
 
             node3 = self._parse(cr, node2, prev_indent=indent)
-            node3.name = [Label(var_name, n) for n in name.lstrip("@").split(".")]
+            is_default = name.startswith("@")
+            name = name.lstrip("@")
+            node3.name = [Label(var_name, n) for n in name.split(".")]
             node3.dep = [Label(var_name, d) for d in dep.replace(",", " ").split()]
 
             if var_name:
@@ -702,12 +723,33 @@ class Parser(object):
                 op_match = _ops_exp.search(l)
                 node3.content += [(cr.filename, linenum, Op(l, op_match))]
 
-            is_default = name.startswith("@")
-
-            node4.children += [node3]
+            node3.append_to_shortname = not is_default
+
+            if with_default and self.defaults:
+                """
+                Relevant only if defaults is True and
+                variants is with default.
+                """
+                if is_default:
+                    if not already_default:
+                        node3.default = True
+                        already_default = True
+                    else:
+                        raise MissingDefault
+                if node3.default:
+                    # Move default variant in front of rest of all variants.
+                    # Speed optimization.
+                    node4.children.insert(0, node3)
+                else:
+                    node4.children += [node3]
+            else:
+                node4.children += [node3]
             node4.labels.update(node3.labels)
             node4.labels.update(node3.name)
 
+        if with_default and not already_default:
+            raise MissingDefault
+
         return node4
 
 
@@ -751,6 +793,7 @@ class Parser(object):
                                 char in "._-=,"):
                             raise ParserError("Illegal characters in variants",
                                               line, cr.filename, linenum)
+                with_default = False
                 var_name = None
                 if name:
                     block = name.split(",")
@@ -761,12 +804,20 @@ class Parser(object):
                                 raise ParserError("Missing name of variants",
                                                   line, cr.filename, linenum)
                             var_name = oper[1].strip()
+                        elif "with_default" in oper[0]:
+                            with_default = True
                         else:
                             raise ParserError("Ilegal variants param",
                                                line, cr.filename, linenum)
-                node = self._parse_variants(cr, node, prev_indent=indent,
-                                            var_name=var_name)
-                                            var_name=name)
+                try:
+                    node = self._parse_variants(cr, node, prev_indent=indent,
+                                                var_name=var_name,
+                                                with_default=with_default)
+                except MissingDefault:
+                    raise ParserError("There must be exactly one default "
+                                      "variant in variants with param "
+                                      "with_default.",
+                                      line, cr.filename, linenum)
                 continue
 
             # Parse 'include' statements
@@ -1040,12 +1091,15 @@ if __name__ == "__main__":
                       help="show dict contents")
     parser.add_option("-r", "--repr", dest="repr_mode", action="store_true",
                       help="Output parsing results Python format")
+    parser.add_option("-d", "--defaults", dest="defaults", action="store_true",
+                      help="use only default variant of variants if there"
+                           " is some")
 
     options, args = parser.parse_args()
     if not args:
         parser.error("filename required")
 
-    c = Parser(args[0], debug=options.debug)
+    c = Parser(args[0], defaults=options.defaults, debug=options.debug)
     for s in args[1:]:
         c.parse_string(s)
 
-- 
1.8.1.4

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




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux