Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Unified Diff: client/tests/kvm/kvm_config.py

Issue 6551020: Merge remote branch 'autotest-upstream/master' into try-box1 (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/autotest.git@master
Patch Set: patch Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « client/tests/kvm/installer.py ('k') | client/tests/kvm/kvm_utils.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/tests/kvm/kvm_config.py
diff --git a/client/tests/kvm/kvm_config.py b/client/tests/kvm/kvm_config.py
index 807a20454626f87284f21c4da48e7dcc980f9be3..4dbb1d49b508643dc7935dbc6ed988f811725b6c 100755
--- a/client/tests/kvm/kvm_config.py
+++ b/client/tests/kvm/kvm_config.py
@@ -5,7 +5,7 @@ KVM test configuration file parser
@copyright: Red Hat 2008-2011
"""
-import re, os, sys, optparse, collections, string
+import re, os, sys, optparse, collections
# Filter syntax:
@@ -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
@@ -226,27 +249,18 @@ class Parser(object):
# filters first.
for t in content:
filename, linenum, obj = t
- if type(obj) is str:
+ 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,
@@ -330,7 +347,7 @@ class Parser(object):
self._debug(" reached leaf, returning it")
d = {"name": name, "dep": dep, "shortname": ".".join(shortname)}
for filename, linenum, op in new_content:
- op.apply_to_dict(d, ctx, ctx_set)
+ op.apply_to_dict(d)
yield d
# If this node did not produce any dicts, remember the failed filters
# of its descendants
@@ -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)
@@ -441,11 +459,10 @@ class Parser(object):
if len(words) < 2:
raise ParserError("Syntax error: missing parameter",
line, cr.filename, linenum)
- if not isinstance(cr, FileReader):
- raise ParserError("Cannot include because no file is "
- "currently open",
- line, cr.filename, linenum)
- filename = os.path.join(os.path.dirname(cr.filename), words[1])
+ filename = os.path.expanduser(words[1])
+ if isinstance(cr, FileReader) and not os.path.isabs(filename):
+ filename = os.path.join(os.path.dirname(cr.filename),
+ filename)
if not os.path.isfile(filename):
self._warn("%r (%s:%s): file doesn't exist or is not a "
"regular file", line, cr.filename, linenum)
@@ -471,28 +488,34 @@ class Parser(object):
node.content += [(cr.filename, linenum, f)]
continue
+ # Look for operators
+ op_match = _ops_exp.search(line)
+
# Parse conditional blocks
- if line.endswith(":"):
- try:
- cond = Condition(line)
- except ParserError, e:
- e.line = line
- e.filename = cr.filename
- e.linenum = linenum
- raise
- self._parse(cr, cond, prev_indent=indent)
- node.content += [(cr.filename, linenum, cond)]
- continue
+ if ":" in line:
+ index = line.index(":")
+ if not op_match or index < op_match.start():
+ index += 1
+ cr.set_next_line(line[index:], indent, linenum)
+ line = line[:index]
+ try:
+ if line.startswith("!"):
+ cond = NegativeCondition(line)
+ else:
+ cond = Condition(line)
+ except ParserError, e:
+ e.line = line
+ e.filename = cr.filename
+ e.linenum = linenum
+ raise
+ self._parse(cr, cond, prev_indent=indent)
+ node.content += [(cr.filename, linenum, cond)]
+ continue
# Parse regular operators
- try:
- op = Op(line)
- except ParserError, e:
- e.line = line
- e.filename = cr.filename
- e.linenum = linenum
- raise
- node.content += [(cr.filename, linenum, op)]
+ if not op_match:
+ raise ParserError("Syntax error", line, cr.filename, linenum)
+ node.content += [(cr.filename, linenum, Op(line, op_match))]
return node
@@ -557,26 +580,17 @@ _ops_exp = re.compile("|".join([op[0] for op in _ops.values()]))
class Op(object):
- def __init__(self, line):
- m = re.search(_ops_exp, line)
- if not m:
- raise ParserError("Syntax error: missing operator")
- left = line[:m.start()].strip()
+ def __init__(self, line, m):
+ self.func = _ops[m.group()][1]
+ self.key = line[:m.start()].strip()
value = line[m.end():].strip()
- if value and ((value[0] == '"' and value[-1] == '"') or
- (value[0] == "'" and value[-1] == "'")):
+ if value and (value[0] == value[-1] == '"' or
+ value[0] == value[-1] == "'"):
value = value[1:-1]
- filters_and_key = map(str.strip, left.split(":"))
- self.filters = [Filter(f) for f in filters_and_key[:-1]]
- self.key = filters_and_key[-1]
self.value = value
- self.func = _ops[m.group()][1]
- def apply_to_dict(self, d, ctx, ctx_set):
- for f in self.filters:
- if not f.match(ctx, ctx_set):
- return
+ def apply_to_dict(self, d):
self.func(d, self.key, self.value)
@@ -595,6 +609,7 @@ class StrReader(object):
self.filename = "<string>"
self._lines = []
self._line_index = 0
+ self._stored_line = None
for linenum, line in enumerate(s.splitlines()):
line = line.rstrip().expandtabs()
stripped_line = line.lstrip()
@@ -608,14 +623,17 @@ class StrReader(object):
def get_next_line(self, prev_indent):
"""
- Get the next non-empty, non-comment line in the string, whose
- indentation level is higher than prev_indent.
+ Get the next line in the current block.
@param prev_indent: The indentation level of the previous block.
@return: (line, indent, linenum), where indent is the line's
indentation level. If no line is available, (None, -1, -1) is
returned.
"""
+ if self._stored_line:
+ ret = self._stored_line
+ self._stored_line = None
+ return ret
if self._line_index >= len(self._lines):
return None, -1, -1
line, indent, linenum = self._lines[self._line_index]
@@ -625,6 +643,16 @@ class StrReader(object):
return line, indent, linenum
+ def set_next_line(self, line, indent, linenum):
+ """
+ Make the next call to get_next_line() return the given line instead of
+ the real next line.
+ """
+ line = line.strip()
+ if line:
+ self._stored_line = line, indent, linenum
+
+
class FileReader(StrReader):
"""
Preprocess an input file for easy reading.
@@ -640,7 +668,9 @@ class FileReader(StrReader):
if __name__ == "__main__":
- parser = optparse.OptionParser("usage: %prog [options] <filename>")
+ parser = optparse.OptionParser('usage: %prog [options] filename '
+ '[extra code] ...\n\nExample:\n\n '
+ '%prog tests.cfg "only my_set" "no qcow2"')
parser.add_option("-v", "--verbose", dest="debug", action="store_true",
help="include debug messages in console output")
parser.add_option("-f", "--fullname", dest="fullname", action="store_true",
@@ -653,6 +683,9 @@ if __name__ == "__main__":
parser.error("filename required")
c = Parser(args[0], debug=options.debug)
+ for s in args[1:]:
+ c.parse_string(s)
+
for i, d in enumerate(c.get_dicts()):
if options.fullname:
print "dict %4d: %s" % (i + 1, d["name"])
« no previous file with comments | « client/tests/kvm/installer.py ('k') | client/tests/kvm/kvm_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698