******** example:
variants name=tests:
- wait:
run = "wait"
variants:
- long:
time = short_time
- short: long
time = logn_time
- test2:
run = "test1"
variants name=virt_system:
- linux:
- windows_XP:
variants name=host_os:
- linux:
image = linux
- windows_XP:
image = windows
tests>wait.short:
shutdown = destroy
only host_os>linux
******** output:
dict 1: host_os>linux.virt_system>linux.tests>wait.long
dep = []
host_os = linux
image = linux
name = host_os>linux.virt_system>linux.tests>wait.long
run = wait
shortname = host_os>linux.virt_system>linux.tests>wait.long
tests = wait
time = short_time
virt_system = linux
dict 2: host_os>linux.virt_system>linux.tests>wait.short
dep = ['host_os>linux.virt_system>linux.tests>wait.long']
host_os = linux
image = linux
name = host_os>linux.virt_system>linux.tests>wait.short
run = wait
shortname = host_os>linux.virt_system>linux.tests>wait.short
shutdown = destroy
tests = wait
time = logn_time
virt_system = linux
dict 3: host_os>linux.virt_system>linux.tests>test2
dep = []
host_os = linux
image = linux
name = host_os>linux.virt_system>linux.tests>test2
run = test1
shortname = host_os>linux.virt_system>linux.tests>test2
tests = test2
virt_system = linux
dict 4: host_os>linux.virt_system>windows_XP.tests>wait.long
dep = []
host_os = linux
image = linux
name = host_os>linux.virt_system>windows_XP.tests>wait.long
run = wait
shortname = host_os>linux.virt_system>windows_XP.tests>wait.long
tests = wait
time = short_time
virt_system = windows_XP
dict 5: host_os>linux.virt_system>windows_XP.tests>wait.short
dep = ['host_os>linux.virt_system>windows_XP.tests>wait.long']
host_os = linux
image = linux
name = host_os>linux.virt_system>windows_XP.tests>wait.short
run = wait
shortname = host_os>linux.virt_system>windows_XP.tests>wait.short
shutdown = destroy
tests = wait
time = logn_time
virt_system = windows_XP
dict 6: host_os>linux.virt_system>windows_XP.tests>test2
dep = []
host_os = linux
image = linux
name = host_os>linux.virt_system>windows_XP.tests>test2
run = test1
shortname = host_os>linux.virt_system>windows_XP.tests>test2
tests = test2
virt_system = windows_XP
For filtering of named variants is used character ">" because there was
problem with conflict with = in expression key = value. The char ">"
could be changed to something better but it should be different from "="
for optimization of speed.
Additionally named variant adds keys to final dictionary in case of
example is it (virt_system = linux). It should reduce size of config file.
Keys defined in config and keys defined by named variants are in same
name space.
Signed-off-by: Jiří Župka <[email protected]>
---
virttest/cartesian_config.py | 138 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 124 insertions(+), 14 deletions(-)
diff --git a/virttest/cartesian_config.py b/virttest/cartesian_config.py
index ef91051..04ed2b5 100755
--- a/virttest/cartesian_config.py
+++ b/virttest/cartesian_config.py
@@ -145,6 +145,74 @@ class MissingIncludeError:
num_failed_cases = 5
+class Label(object):
+ __slots__ = ["name", "var_name", "long_name", "hash_val", "hash_var"]
+
+ def __init__(self, name, next_name=None):
+ if next_name is None:
+ self.name = name
+ self.var_name = None
+ else:
+ self.name = next_name
+ self.var_name = name
+
+ if self.var_name is None:
+ self.long_name = "%s" % (self.name)
+ else:
+ self.long_name = "%s>%s" % (self.var_name, self.name)
+
+ self.hash_val = self.hash_name()
+ self.hash_var = None
+ if self.var_name:
+ self.hash_var = self.hash_variant()
+
+
+ def __str__(self):
+ return self.long_name
+
+
+ def __repr__(self):
+ return self.long_name
+
+
+ def __eq__(self, o):
+ """
+ The comparison is asymmetric due to optimization.
+ """
+ if o.var_name:
+ if self.long_name == o.long_name:
+ return True
+ else:
+ if self.name == o.name:
+ return True
+ return False
+
+
+ def __ne__(self, o):
+ """
+ The comparison is asymmetric due to optimization.
+ """
+ if o.var_name:
+ if self.long_name != o.long_name:
+ return True
+ else:
+ if self.name != o.name:
+ return True
+ return False
+
+
+ def __hash__(self):
+ return self.hash_val
+
+
+ def hash_name(self):
+ return sum([i + 1 * ord(x) for i, x in enumerate(self.name)])
+
+
+ def hash_variant(self):
+ return sum([i + 1 * ord(x) for i, x in enumerate(str(self))])
+
+
class Node(object):
__slots__ = ["name", "dep", "content", "children", "labels",
"append_to_shortname", "failed_cases", "default"]
@@ -212,18 +280,19 @@ class Filter(object):
def __init__(self, s):
self.filter = []
for char in s:
- if not (char.isalnum() or char.isspace() or char in ".,_-"):
+ if not (char.isalnum() or char.isspace() or char in ".,_->"):
raise ParserError("Illegal characters in filter")
for word in s.replace(",", " ").split(): # OR
word = [block.split(".") for block in word.split("..")] # AND
- for word in s.replace(",", " ").split():
- word = [block.split(".") for block in word.split("..")]
- for block in word:
+ words = []
for block in word: # .
+ b = []
for elem in block:
if not elem:
raise ParserError("Syntax error")
- self.filter += [word]
+ b.append(Label(*elem.split(">")))
+ words.append(b)
+ self.filter += [words]
def match(self, ctx, ctx_set):
@@ -506,15 +575,16 @@ class Parser(object):
# node.dump(0)
# Update dep
for d in node.dep:
- dep = dep + [".".join(ctx + [d])]
+ dep = dep + [".".join([str(label) for label in ctx + [d]])]
# Update ctx
ctx = ctx + node.name
ctx_set = set(ctx)
labels = node.labels
# Get the current name
- name = ".".join(ctx)
+ name = ".".join([str(label) for label in ctx])
if node.name:
self._debug("checking out %r", name)
+
# Check previously failed filters
for i, failed_case in enumerate(node.failed_cases):
if not might_pass(*failed_case):
@@ -534,9 +604,11 @@ class Parser(object):
add_failed_case()
self._debug("Failed_cases %s", node.failed_cases)
return
+
# Update shortname
if node.append_to_shortname:
shortname = shortname + node.name
+
# Recurse into children
count = 0
for n in node.children:
@@ -546,7 +618,8 @@ class Parser(object):
# Reached leaf?
if not node.children:
self._debug(" reached leaf, returning it")
- d = {"name": name, "dep": dep, "shortname": ".".join(shortname)}
+ d = {"name": name, "dep": dep,
+ "shortname": ".".join([str(sn) for sn in shortname])}
for _, _, op in new_content:
op.apply_to_dict(d)
yield d
@@ -583,7 +656,7 @@ class Parser(object):
print s % args
- def _parse_variants(self, cr, node, prev_indent=-1):
+ def _parse_variants(self, cr, node, prev_indent=-1, var_name=None):
"""
Read and parse lines from a FileReader object until a line with an
indent level lower than or equal to prev_indent is encountered.
@@ -591,6 +664,7 @@ class Parser(object):
@param cr: A FileReader/StrReader object.
@param node: A node to operate on.
@param prev_indent: The indent level of the "parent" block.
+ @param var_name: Variants name
@return: A node object.
"""
node4 = Node()
@@ -620,9 +694,15 @@ class Parser(object):
node2.labels = node.labels
node3 = self._parse(cr, node2, prev_indent=indent)
- node3.name = name.lstrip("@").split(".")
- node3.dep = dep.replace(",", " ").split()
- node3.append_to_shortname = not name.startswith("@")
+ node3.name = [Label(var_name, n) for n in
name.lstrip("@").split(".")]
+ node3.dep = [Label(var_name, d) for d in dep.replace(",", "
").split()]
+
+ if var_name:
+ l = "%s = %s" % (var_name, name)
+ op_match = _ops_exp.search(l)
+ node3.content += [(cr.filename, linenum, Op(l, op_match))]
+
+ is_default = name.startswith("@")
node4.children += [node3]
node4.labels.update(node3.labels)
@@ -649,14 +729,44 @@ class Parser(object):
words = line.split(None, 1)
# Parse 'variants'
- if line == "variants:":
+ if line.startswith("variants"):
# 'variants' is not allowed inside a conditional block
if (isinstance(node, Condition) or
isinstance(node, NegativeCondition)):
raise ParserError("'variants' is not allowed inside a "
"conditional block",
None, cr.filename, linenum)
- node = self._parse_variants(cr, node, prev_indent=indent)
+ name = None
+ if not words[0] in ["variants", "variants:"]:
+ raise ParserError("Illegal characters in variants",
+ line, cr.filename, linenum)
+ if words[0] == "variants":
+ try:
+ name, _ = words[1].split(":") # split name and comment
+ except ValueError:
+ raise ParserError("Missing : in variants expression",
+ line, cr.filename, linenum)
+ for char in name:
+ if not (char.isalnum() or char.isspace() or
+ char in "._-=,"):
+ raise ParserError("Illegal characters in variants",
+ line, cr.filename, linenum)
+ var_name = None
+ if name:
+ block = name.split(",")
+ for b in block:
+ oper = b.split("=")
+ if oper[0] == "name":
+ if len(oper) == 1:
+ raise ParserError("Missing name of variants",
+ line, cr.filename, linenum)
+ var_name = oper[1].strip()
+ 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)
continue
# Parse 'include' statements
--
1.8.1.4
_______________________________________________
Virt-test-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/virt-test-devel