From patchwork Fri Mar 29 17:14:09 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jiri Zupka X-Patchwork-Id: 2366231 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id F072C40B29 for ; Fri, 29 Mar 2013 17:14:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756173Ab3C2ROb (ORCPT ); Fri, 29 Mar 2013 13:14:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57277 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756013Ab3C2ROa (ORCPT ); Fri, 29 Mar 2013 13:14:30 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r2THETYZ020070 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 29 Mar 2013 13:14:29 -0400 Received: from jzupka-pc.local.com (vpn1-6-43.ams2.redhat.com [10.36.6.43]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r2THEDM3032179; Fri, 29 Mar 2013 13:14:27 -0400 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C5=BDupka?= To: virt-test-devel@redhat.com, kvm@vger.kernel.org, kvm-autotest@redhat.com, lmr@redhat.com, ldoktor@redhat.com, jzupka@redhat.com, ehabkost@redhat.com, pbonzini@redhat.com Subject: [virt-test][PATCH 6/7] virt: Adds possibility filter defaults variant from variants Date: Fri, 29 Mar 2013 18:14:09 +0100 Message-Id: <1364577250-2637-7-git-send-email-jzupka@redhat.com> In-Reply-To: <1364577250-2637-1-git-send-email-jzupka@redhat.com> References: <1364577250-2637-1-git-send-email-jzupka@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org 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 --- 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)