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 <[email protected]>
---
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
_______________________________________________
Virt-test-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/virt-test-devel