From f442fd93949cb0c082e537d512c2c22754061622 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Mon, 20 Jun 2016 11:21:24 -0500 Subject: [PATCH 01/17] Broaden acceptable toolchain spec; improved incorrect toolchain error --- tools/memap.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/memap.py b/tools/memap.py index b465cb44f3c..057bd9b0d79 100644 --- a/tools/memap.py +++ b/tools/memap.py @@ -477,6 +477,15 @@ def parse(self, mapfile, toolchain): return True + toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "IAR"] + @staticmethod + def parse_toolchain(string) : + newstring = string.upper().replace("-","_") + if newstring not in MemapParser.toolchains: + raise (argparse.ArgumentTypeError("{} is not a supported toolchain. Supported toolchains are {}".format(string, ", ".join(MemapParser.toolchains)))) + else: + return newstring + def main(): version = '0.3.10' @@ -486,8 +495,8 @@ def main(): parser.add_argument('file', help='memory map file') - parser.add_argument('-t', '--toolchain', dest='toolchain', help='select a toolchain used to build the memory map file (ARM, GCC_ARM, IAR)',\ - required=True) + parser.add_argument('-t', '--toolchain', dest='toolchain', help='select a toolchain used to build the memory map file (%s)' % ", ".join(MemapParser.toolchains),\ + required=True, type=MemapParser.parse_toolchain) parser.add_argument('-o', '--output', help='output file name', required=False) @@ -510,7 +519,6 @@ def main(): # Parse and decode a map file if args.file and args.toolchain: if memap.parse(args.file, args.toolchain) is False: - print "Unknown toolchain for memory statistics %s" % args.toolchain sys.exit(0) # default export format is table From ee8a02c6ab10b6407d162f9d472c67dc1199070f Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Mon, 20 Jun 2016 11:41:23 -0500 Subject: [PATCH 02/17] Generalize export format flag input --- tools/memap.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tools/memap.py b/tools/memap.py index 057bd9b0d79..833e33da05b 100644 --- a/tools/memap.py +++ b/tools/memap.py @@ -486,6 +486,15 @@ def parse_toolchain(string) : else: return newstring + export_formats = ["json", "csv-ci", "table"] + @staticmethod + def parse_export_format(string): + newstring = string.lower().replace("_","-") + if newstring not in MemapParser.export_formats: + raise (argparse.ArgumentTypeError("{} is not a supported export format. Supported export formats are {}".format(string, ", ".join(MemapParser.export_formats)))) + else : + return newstring + def main(): version = '0.3.10' @@ -500,8 +509,8 @@ def main(): parser.add_argument('-o', '--output', help='output file name', required=False) - parser.add_argument('-e', '--export', dest='export', required=False,\ - help="export format (examples: 'json', 'csv-ci', 'table': default)") + parser.add_argument('-e', '--export', dest='export', required=False, default='table', type=MemapParser.parse_export_format,\ + help="export format (examples: %s: default)" % ", ".join(MemapParser.export_formats)) parser.add_argument('-v', '--version', action='version', version=version) @@ -521,10 +530,6 @@ def main(): if memap.parse(args.file, args.toolchain) is False: sys.exit(0) - # default export format is table - if not args.export: - args.export = 'table' - # Write output in file if args.output != None: memap.generate_output(args.export, args.output) From 52a7f64d6730fd9c076ab690f797611a5ae4f964 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Mon, 20 Jun 2016 18:04:28 -0500 Subject: [PATCH 03/17] Generalize parsing types --- tools/memap.py | 27 +++++++-------------------- tools/utils.py | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/tools/memap.py b/tools/memap.py index 833e33da05b..faaf308f538 100644 --- a/tools/memap.py +++ b/tools/memap.py @@ -10,6 +10,7 @@ import csv import json import argparse +from utils import argparse_uppercase_type, argparse_lowercase_hyphen_type from prettytable import PrettyTable debug = False @@ -336,6 +337,8 @@ def search_objects(self, path, toolchain): else: self.object_to_module.update({object_name:module_name}) + export_formats = ["json", "csv-ci", "table"] + def generate_output(self, export_format, file_output=None): """ Generates summary of memory map data @@ -451,6 +454,8 @@ def generate_output(self, export_format, file_output=None): return True + toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "IAR"] + def parse(self, mapfile, toolchain): """ Parse and decode map file depending on the toolchain @@ -477,24 +482,6 @@ def parse(self, mapfile, toolchain): return True - toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "IAR"] - @staticmethod - def parse_toolchain(string) : - newstring = string.upper().replace("-","_") - if newstring not in MemapParser.toolchains: - raise (argparse.ArgumentTypeError("{} is not a supported toolchain. Supported toolchains are {}".format(string, ", ".join(MemapParser.toolchains)))) - else: - return newstring - - export_formats = ["json", "csv-ci", "table"] - @staticmethod - def parse_export_format(string): - newstring = string.lower().replace("_","-") - if newstring not in MemapParser.export_formats: - raise (argparse.ArgumentTypeError("{} is not a supported export format. Supported export formats are {}".format(string, ", ".join(MemapParser.export_formats)))) - else : - return newstring - def main(): version = '0.3.10' @@ -505,11 +492,11 @@ def main(): parser.add_argument('file', help='memory map file') parser.add_argument('-t', '--toolchain', dest='toolchain', help='select a toolchain used to build the memory map file (%s)' % ", ".join(MemapParser.toolchains),\ - required=True, type=MemapParser.parse_toolchain) + required=True, type=argparse_uppercase_type(MemapParser.toolchains, "toolchain")) parser.add_argument('-o', '--output', help='output file name', required=False) - parser.add_argument('-e', '--export', dest='export', required=False, default='table', type=MemapParser.parse_export_format,\ + parser.add_argument('-e', '--export', dest='export', required=False, default='table', type=argparse_lowercase_hyphen_type(MemapParser.export_formats,'export format'),\ help="export format (examples: %s: default)" % ", ".join(MemapParser.export_formats)) parser.add_argument('-v', '--version', action='version', version=version) diff --git a/tools/utils.py b/tools/utils.py index 55752b8750d..c2ae4bd156d 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -17,6 +17,7 @@ import sys import inspect import os +import argparse from os import listdir, remove, makedirs from shutil import copyfile from os.path import isdir, join, exists, split, relpath, splitext @@ -196,3 +197,23 @@ def dict_to_ascii(input): def json_file_to_dict(fname): with open(fname, "rt") as f: return dict_to_ascii(json.load(f, object_pairs_hook=OrderedDict)) + +# Wowza, double closure +def argparse_list_type(casedness, prefer_hyphen=False) : + def middle(list, type_name): + def parse_type(string): + if prefer_hyphen: newstring = casedness(string).replace("_","-") + else: newstring = casedness(string).replace("-","_") + if string in list: + return string + elif string not in list and newstring in list: + raise argparse.ArgumentTypeError("{0} is not a supported {1}. Did you mean {2}?".format(string, type_name, newstring)) + else: + raise argparse.ArgumentTypeError("{0} is not a supported {1}. Supported {1}s are {2}.".format(string, type_name, ", ".join(list))) + return parse_type + return middle + +argparse_uppercase_type = argparse_list_type(str.upper, False) +argparse_lowercase_type = argparse_list_type(str.lower, False) +argparse_uppercase_hyphen_type = argparse_list_type(str.upper, True) +argparse_lowercase_hyphen_type = argparse_list_type(str.lower, True) From 43e036d6e127bdc382eba4645d300a7a2546f061 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Tue, 21 Jun 2016 10:43:12 -0500 Subject: [PATCH 04/17] Move to argparse from optparse --- tools/build.py | 44 +++++++++++++------------- tools/detect_targets.py | 8 ++--- tools/get_config.py | 8 ++--- tools/make.py | 68 ++++++++++++++++++++--------------------- tools/options.py | 26 +++++++++------- tools/test.py | 31 ++++++++++--------- 6 files changed, 95 insertions(+), 90 deletions(-) diff --git a/tools/build.py b/tools/build.py index e47cd6a411f..e021f6ff2b0 100644 --- a/tools/build.py +++ b/tools/build.py @@ -42,115 +42,115 @@ # Parse Options parser = get_default_options_parser() - parser.add_option("--source", dest="source_dir", + parser.add_argument("--source", dest="source_dir", default=None, help="The source (input) directory", action="append") - parser.add_option("--build", dest="build_dir", + parser.add_argument("--build", dest="build_dir", default=None, help="The build (output) directory") - parser.add_option("--no-archive", dest="no_archive", action="store_true", + parser.add_argument("--no-archive", dest="no_archive", action="store_true", default=False, help="Do not produce archive (.ar) file, but rather .o") # Extra libraries - parser.add_option("-r", "--rtos", + parser.add_argument("-r", "--rtos", action="store_true", dest="rtos", default=False, help="Compile the rtos") - parser.add_option("--rpc", + parser.add_argument("--rpc", action="store_true", dest="rpc", default=False, help="Compile the rpc library") - parser.add_option("-e", "--eth", + parser.add_argument("-e", "--eth", action="store_true", dest="eth", default=False, help="Compile the ethernet library") - parser.add_option("-U", "--usb_host", + parser.add_argument("-U", "--usb_host", action="store_true", dest="usb_host", default=False, help="Compile the USB Host library") - parser.add_option("-u", "--usb", + parser.add_argument("-u", "--usb", action="store_true", dest="usb", default=False, help="Compile the USB Device library") - parser.add_option("-d", "--dsp", + parser.add_argument("-d", "--dsp", action="store_true", dest="dsp", default=False, help="Compile the DSP library") - parser.add_option("-F", "--fat", + parser.add_argument("-F", "--fat", action="store_true", dest="fat", default=False, help="Compile FS and SD card file system library") - parser.add_option("-b", "--ublox", + parser.add_argument("-b", "--ublox", action="store_true", dest="ublox", default=False, help="Compile the u-blox library") - parser.add_option("", "--cpputest", + parser.add_argument( "--cpputest", action="store_true", dest="cpputest_lib", default=False, help="Compiles 'cpputest' unit test library (library should be on the same directory level as mbed repository)") - parser.add_option("-D", "", + parser.add_argument("-D", action="append", dest="macros", help="Add a macro definition") - parser.add_option("-S", "--supported-toolchains", + parser.add_argument("-S", "--supported-toolchains", action="store_true", dest="supported_toolchains", default=False, help="Displays supported matrix of MCUs and toolchains") - parser.add_option('-f', '--filter', + parser.add_argument('-f', '--filter', dest='general_filter_regex', default=None, help='For some commands you can use filter to filter out results') - parser.add_option("", "--cppcheck", + parser.add_argument("--cppcheck", action="store_true", dest="cppcheck_validation", default=False, help="Forces 'cppcheck' static code analysis") - parser.add_option("-j", "--jobs", type="int", dest="jobs", + parser.add_argument("-j", "--jobs", type=int, dest="jobs", default=0, help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)") - parser.add_option("-N", "--artifact-name", dest="artifact_name", + parser.add_argument("-N", "--artifact-name", dest="artifact_name", default=None, help="The built project's name") - parser.add_option("-v", "--verbose", + parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Verbose diagnostic output") - parser.add_option("--silent", + parser.add_argument("--silent", action="store_true", dest="silent", default=False, help="Silent diagnostic output (no copy, compile notification)") - parser.add_option("-x", "--extra-verbose-notifications", + parser.add_argument("-x", "--extra-verbose-notifications", action="store_true", dest="extra_verbose_notify", default=False, help="Makes compiler more verbose, CI friendly.") - (options, args) = parser.parse_args() + options = parser.parse_args() # Only prints matrix of supported toolchains if options.supported_toolchains: diff --git a/tools/detect_targets.py b/tools/detect_targets.py index 1cf288dede6..dd7be0ab916 100644 --- a/tools/detect_targets.py +++ b/tools/detect_targets.py @@ -42,24 +42,24 @@ # Parse Options parser = get_default_options_parser() - parser.add_option("-S", "--supported-toolchains", + parser.add_argument("-S", "--supported-toolchains", action="store_true", dest="supported_toolchains", default=False, help="Displays supported matrix of targets and toolchains") - parser.add_option('-f', '--filter', + parser.add_argument('-f', '--filter', dest='general_filter_regex', default=None, help='Filter targets') - parser.add_option("-v", "--verbose", + parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Verbose diagnostic output") - (options, args) = parser.parse_args() + options = parser.parse_args() # Only prints matrix of supported toolchains if options.supported_toolchains: diff --git a/tools/get_config.py b/tools/get_config.py index 9d9e7dc5fa2..0a57426bd7c 100644 --- a/tools/get_config.py +++ b/tools/get_config.py @@ -36,14 +36,14 @@ if __name__ == '__main__': # Parse Options parser = get_default_options_parser(add_clean=False, add_options=False) - parser.add_option("--source", dest="source_dir", + parser.add_argument("--source", dest="source_dir", default=None, help="The source (input) directory", action="append") - parser.add_option("--prefix", dest="prefix", action="append", + parser.add_argument("--prefix", dest="prefix", action="append", default=None, help="Restrict listing to parameters that have this prefix") - parser.add_option("-v", "--verbose", action="store_true", dest="verbose", + parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Verbose diagnostic output") - (options, args) = parser.parse_args() + options = parser.parse_args() for path in options.source_dir : if not isdir(path) : diff --git a/tools/make.py b/tools/make.py index 7bc749985e2..b895ad496df 100644 --- a/tools/make.py +++ b/tools/make.py @@ -50,133 +50,133 @@ if __name__ == '__main__': # Parse Options parser = get_default_options_parser() - parser.add_option("-p", - type="int", + parser.add_argument("-p", + type=int, dest="program", help="The index of the desired test program: [0-%d]" % (len(TESTS)-1)) - parser.add_option("-n", + parser.add_argument("-n", dest="program_name", help="The name of the desired test program") - parser.add_option("-j", "--jobs", - type="int", + parser.add_argument("-j", "--jobs", + type=int, dest="jobs", default=0, help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)") - parser.add_option("-v", "--verbose", + parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Verbose diagnostic output") - parser.add_option("--silent", + parser.add_argument("--silent", action="store_true", dest="silent", default=False, help="Silent diagnostic output (no copy, compile notification)") - parser.add_option("-D", "", + parser.add_argument("-D", action="append", dest="macros", help="Add a macro definition") - parser.add_option("-S", "--supported-toolchains", + parser.add_argument("-S", "--supported-toolchains", action="store_true", dest="supported_toolchains", default=False, help="Displays supported matrix of MCUs and toolchains") - parser.add_option('-f', '--filter', + parser.add_argument('-f', '--filter', dest='general_filter_regex', default=None, help='For some commands you can use filter to filter out results') # Local run - parser.add_option("--automated", action="store_true", dest="automated", + parser.add_argument("--automated", action="store_true", dest="automated", default=False, help="Automated test") - parser.add_option("--host", dest="host_test", + parser.add_argument("--host", dest="host_test", default=None, help="Host test") - parser.add_option("--extra", dest="extra", + parser.add_argument("--extra", dest="extra", default=None, help="Extra files") - parser.add_option("--peripherals", dest="peripherals", + parser.add_argument("--peripherals", dest="peripherals", default=None, help="Required peripherals") - parser.add_option("--dep", dest="dependencies", + parser.add_argument("--dep", dest="dependencies", default=None, help="Dependencies") - parser.add_option("--source", dest="source_dir", + parser.add_argument("--source", dest="source_dir", default=None, help="The source (input) directory", action="append") - parser.add_option("--duration", type="int", dest="duration", + parser.add_argument("--duration", type=int, dest="duration", default=None, help="Duration of the test") - parser.add_option("--build", dest="build_dir", + parser.add_argument("--build", dest="build_dir", default=None, help="The build (output) directory") - parser.add_option("-N", "--artifact-name", dest="artifact_name", + parser.add_argument("-N", "--artifact-name", dest="artifact_name", default=None, help="The built project's name") - parser.add_option("-d", "--disk", dest="disk", + parser.add_argument("-d", "--disk", dest="disk", default=None, help="The mbed disk") - parser.add_option("-s", "--serial", dest="serial", + parser.add_argument("-s", "--serial", dest="serial", default=None, help="The mbed serial port") - parser.add_option("-b", "--baud", type="int", dest="baud", + parser.add_argument("-b", "--baud", type=int, dest="baud", default=None, help="The mbed serial baud rate") - parser.add_option("-L", "--list-tests", action="store_true", dest="list_tests", + parser.add_argument("-L", "--list-tests", action="store_true", dest="list_tests", default=False, help="List available tests in order and exit") # Ideally, all the tests with a single "main" thread can be run with, or # without the rtos, eth, usb_host, usb, dsp, fat, ublox - parser.add_option("--rtos", + parser.add_argument("--rtos", action="store_true", dest="rtos", default=False, help="Link with RTOS library") - parser.add_option("--rpc", + parser.add_argument("--rpc", action="store_true", dest="rpc", default=False, help="Link with RPC library") - parser.add_option("--eth", + parser.add_argument("--eth", action="store_true", dest="eth", default=False, help="Link with Ethernet library") - parser.add_option("--usb_host", + parser.add_argument("--usb_host", action="store_true", dest="usb_host", default=False, help="Link with USB Host library") - parser.add_option("--usb", + parser.add_argument("--usb", action="store_true", dest="usb", default=False, help="Link with USB Device library") - parser.add_option("--dsp", + parser.add_argument("--dsp", action="store_true", dest="dsp", default=False, help="Link with DSP library") - parser.add_option("--fat", + parser.add_argument("--fat", action="store_true", dest="fat", default=False, help="Link with FS ad SD card file system library") - parser.add_option("--ublox", + parser.add_argument("--ublox", action="store_true", dest="ublox", default=False, help="Link with U-Blox library") - parser.add_option("--testlib", + parser.add_argument("--testlib", action="store_true", dest="testlib", default=False, help="Link with mbed test library") # Specify a different linker script - parser.add_option("-l", "--linker", dest="linker_script", + parser.add_argument("-l", "--linker", dest="linker_script", default=None, help="use the specified linker script") - (options, args) = parser.parse_args() + options = parser.parse_args() # Only prints matrix of supported toolchains if options.supported_toolchains: diff --git a/tools/options.py b/tools/options.py index 250e8e19484..d4e338b90dc 100644 --- a/tools/options.py +++ b/tools/options.py @@ -14,33 +14,37 @@ See the License for the specific language governing permissions and limitations under the License. """ -from optparse import OptionParser +from argparse import ArgumentParser from tools.toolchains import TOOLCHAINS from tools.targets import TARGET_NAMES +from utils import argparse_uppercase_type, argparse_lowercase_hyphen_type def get_default_options_parser(add_clean=True, add_options=True): - parser = OptionParser() + parser = ArgumentParser() targetnames = TARGET_NAMES targetnames.sort() toolchainlist = list(TOOLCHAINS) toolchainlist.sort() - parser.add_option("-m", "--mcu", - help="build for the given MCU (%s)" % ', '.join(targetnames), - metavar="MCU") + parser.add_argument("-m", "--mcu", + help="build for the given MCU (%s)" % ', '.join(targetnames), + metavar="MCU", + type=argparse_uppercase_type(targetnames, "MCU")) - parser.add_option("-t", "--tool", - help="build using the given TOOLCHAIN (%s)" % ', '.join(toolchainlist), - metavar="TOOLCHAIN") + parser.add_argument("-t", "--tool", + help="build using the given TOOLCHAIN (%s)" % ', '.join(toolchainlist), + metavar="TOOLCHAIN", + type=argparse_uppercase_type(toolchainlist, "toolchain")) if add_clean: - parser.add_option("-c", "--clean", action="store_true", default=False, + parser.add_argument("-c", "--clean", action="store_true", default=False, help="clean the build directory") if add_options: - parser.add_option("-o", "--options", action="append", - help='Add a build option ("save-asm": save the asm generated by the compiler, "debug-info": generate debugging information, "analyze": run Goanna static code analyzer")') + parser.add_argument("-o", "--options", action="append", + help='Add a build argument ("save-asm": save the asm generated by the compiler, "debug-info": generate debugging information, "analyze": run Goanna static code analyzer")', + type=argparse_lowercase_hyphen_type(['save-asm', 'debug-info', 'analyze'], "build option")) return parser diff --git a/tools/test.py b/tools/test.py index bdc9bb9c9dd..3231a4da29f 100644 --- a/tools/test.py +++ b/tools/test.py @@ -32,60 +32,61 @@ from tools.targets import TARGET_MAP from tools.utils import mkdir, ToolException, NotSupportedException from tools.test_exporters import ReportExporter, ResultExporterType +from utils import argparse_lowercase_type if __name__ == '__main__': try: # Parse Options parser = get_default_options_parser() - parser.add_option("-D", "", + parser.add_argument("-D", "", action="append", dest="macros", help="Add a macro definition") - parser.add_option("-j", "--jobs", - type="int", + parser.add_argument("-j", "--jobs", + type=int, dest="jobs", default=0, help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)") - parser.add_option("--source", dest="source_dir", + parser.add_argument("--source", dest="source_dir", default=None, help="The source (input) directory (for sources other than tests). Defaults to current directory.", action="append") - parser.add_option("--build", dest="build_dir", + parser.add_argument("--build", dest="build_dir", default=None, help="The build (output) directory") - parser.add_option("-l", "--list", action="store_true", dest="list", + parser.add_argument("-l", "--list", action="store_true", dest="list", default=False, help="List (recursively) available tests in order and exit") - parser.add_option("-p", "--paths", dest="paths", + parser.add_argument("-p", "--paths", dest="paths", default=None, help="Limit the tests to those within the specified comma separated list of paths") format_choices = ["list", "json"] format_default_choice = "list" format_help = "Change the format in which tests are listed. Choices include: %s. Default: %s" % (", ".join(format_choices), format_default_choice) - parser.add_option("-f", "--format", type="choice", dest="format", - choices=format_choices, default=format_default_choice, help=format_help) + parser.add_argument("-f", "--format", type=argparse_lowercase_type(format_coices,"format"), dest="format", + default=format_default_choice, help=format_help) - parser.add_option("--continue-on-build-fail", action="store_true", dest="continue_on_build_fail", + parser.add_argument("--continue-on-build-fail", action="store_true", dest="continue_on_build_fail", default=None, help="Continue trying to build all tests if a build failure occurs") - parser.add_option("-n", "--names", dest="names", + parser.add_argument("-n", "--names", dest="names", default=None, help="Limit the tests to a comma separated list of names") - parser.add_option("--test-spec", dest="test_spec", + parser.add_argument("--test-spec", dest="test_spec", default=None, help="Destination path for a test spec file that can be used by the Greentea automated test tool") - parser.add_option("--build-report-junit", dest="build_report_junit", + parser.add_argument("--build-report-junit", dest="build_report_junit", default=None, help="Destination path for a build report in the JUnit xml format") - parser.add_option("-v", "--verbose", + parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Verbose diagnostic output") - (options, args) = parser.parse_args() + options = parser.parse_args() # Filter tests by path if specified if options.paths: From b98c8c1c333711c534d1d44bad7d2d83443a9494 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Tue, 21 Jun 2016 10:55:01 -0500 Subject: [PATCH 05/17] Generalize all appropriate arguments and check for file existance --- tools/build.py | 13 +++--------- tools/get_config.py | 11 ++++------ tools/make.py | 52 +++++++++++++++++++++------------------------ tools/test.py | 17 +++++++++------ tools/utils.py | 4 ++++ 5 files changed, 45 insertions(+), 52 deletions(-) diff --git a/tools/build.py b/tools/build.py index e021f6ff2b0..691129dcc99 100644 --- a/tools/build.py +++ b/tools/build.py @@ -35,6 +35,7 @@ from tools.build_api import static_analysis_scan, static_analysis_scan_lib, static_analysis_scan_library from tools.build_api import print_build_results from tools.settings import CPPCHECK_CMD, CPPCHECK_MSG_FORMAT +from utils import argparse_filestring_type if __name__ == '__main__': start = time() @@ -42,10 +43,10 @@ # Parse Options parser = get_default_options_parser() - parser.add_argument("--source", dest="source_dir", + parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type, default=None, help="The source (input) directory", action="append") - parser.add_argument("--build", dest="build_dir", + parser.add_argument("--build", dest="build_dir", type=argparse_filestring_type, default=None, help="The build (output) directory") parser.add_argument("--no-archive", dest="no_archive", action="store_true", @@ -160,10 +161,6 @@ # Get target list if options.mcu: mcu_list = (options.mcu).split(",") - for mcu in mcu_list: - if mcu not in TARGET_NAMES: - print "Given MCU '%s' not into the supported list:\n%s" % (mcu, TARGET_NAMES) - sys.exit(1) targets = mcu_list else: targets = TARGET_NAMES @@ -171,10 +168,6 @@ # Get toolchains list if options.tool: toolchain_list = (options.tool).split(",") - for tc in toolchain_list: - if tc not in TOOLCHAINS: - print "Given toolchain '%s' not into the supported list:\n%s" % (tc, TOOLCHAINS) - sys.exit(1) toolchains = toolchain_list else: toolchains = TOOLCHAINS diff --git a/tools/get_config.py b/tools/get_config.py index 0a57426bd7c..8efb30293f6 100644 --- a/tools/get_config.py +++ b/tools/get_config.py @@ -28,6 +28,7 @@ from tools.options import get_default_options_parser from tools.build_api import get_config from config import Config +from utils import argparse_filestring_type try: import tools.private_settings as ps except: @@ -36,19 +37,15 @@ if __name__ == '__main__': # Parse Options parser = get_default_options_parser(add_clean=False, add_options=False) - parser.add_argument("--source", dest="source_dir", - default=None, help="The source (input) directory", action="append") + parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type, + default=[], help="The source (input) directory", action="append") parser.add_argument("--prefix", dest="prefix", action="append", - default=None, help="Restrict listing to parameters that have this prefix") + default=[], help="Restrict listing to parameters that have this prefix") parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Verbose diagnostic output") options = parser.parse_args() - for path in options.source_dir : - if not isdir(path) : - args_error(parser, "[ERROR] you passed \"{}\" to --source, which does not exist". - format(path)) # Target if options.mcu is None : args_error(parser, "[ERROR] You should specify an MCU") diff --git a/tools/make.py b/tools/make.py index b895ad496df..431384168a9 100644 --- a/tools/make.py +++ b/tools/make.py @@ -42,21 +42,38 @@ from tools.options import get_default_options_parser from tools.build_api import build_project from tools.build_api import mcu_toolchain_matrix +from utils import argparse_filestring_type +from argparse import ArgumentTypeError try: import tools.private_settings as ps except: ps = object() +def test_known(string): + i = int(string) + if i >= 0 and i < len(TESTS) : return i + else : raise ArgumentTypeError("{0} does not index a test".format(i)) + +def test_name_known(string): + nlist = string.split(',') + for test_id in nlist: + if test_id not in TEST_MAP.keys(): + raise ArgumentTypeError("Program with name '%s' not found"% test_id) + + return [TEST_MAP[n].n for n in nlist] + if __name__ == '__main__': # Parse Options parser = get_default_options_parser() - parser.add_argument("-p", - type=int, + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("-p", + type=test_known, dest="program", help="The index of the desired test program: [0-%d]" % (len(TESTS)-1)) - parser.add_argument("-n", - dest="program_name", + group.add_argument("-n", + type=test_name_known, + dest="program", help="The name of the desired test program") parser.add_argument("-j", "--jobs", @@ -104,7 +121,7 @@ default=None, help="Required peripherals") parser.add_argument("--dep", dest="dependencies", default=None, help="Dependencies") - parser.add_argument("--source", dest="source_dir", + parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type, default=None, help="The source (input) directory", action="append") parser.add_argument("--duration", type=int, dest="duration", default=None, help="Duration of the test") @@ -174,6 +191,7 @@ # Specify a different linker script parser.add_argument("-l", "--linker", dest="linker_script", + type=argparse_filestring_type, default=None, help="use the specified linker script") options = parser.parse_args() @@ -183,12 +201,6 @@ print mcu_toolchain_matrix(platform_filter=options.general_filter_regex) exit(0) - if options.source_dir: - for path in options.source_dir : - if not isfile(path) and not isdir(path) : - args_error(parser, "[ERROR] you passed \"{}\" to --source, which does not exist". - format(path)) - # Print available tests in order and exit if options.list_tests is True: print '\n'.join(map(str, sorted(TEST_MAP.values()))) @@ -197,25 +209,9 @@ # force program to "0" if a source dir is specified if options.source_dir is not None: p = 0 - n = None else: # Program Number or name - p, n = options.program, options.program_name - - if n is not None and p is not None: - args_error(parser, "[ERROR] specify either '-n' or '-p', not both") - if n: - # We will transform 'n' to list of 'p' (integers which are test numbers) - nlist = n.split(',') - for test_id in nlist: - if test_id not in TEST_MAP.keys(): - args_error(parser, "[ERROR] Program with name '%s' not found"% test_id) - - p = [TEST_MAP[n].n for n in nlist] - elif p is None or (p < 0) or (p > (len(TESTS)-1)): - message = "[ERROR] You have to specify one of the following tests:\n" - message += '\n'.join(map(str, sorted(TEST_MAP.values()))) - args_error(parser, message) + p = options.program # If 'p' was set via -n to list of numbers make this a single element integer list if type(p) != type([]): diff --git a/tools/test.py b/tools/test.py index 3231a4da29f..4eaee354c29 100644 --- a/tools/test.py +++ b/tools/test.py @@ -32,14 +32,14 @@ from tools.targets import TARGET_MAP from tools.utils import mkdir, ToolException, NotSupportedException from tools.test_exporters import ReportExporter, ResultExporterType -from utils import argparse_lowercase_type +from utils import argparse_filestring_type, argparse_lowercase_type if __name__ == '__main__': try: # Parse Options parser = get_default_options_parser() - parser.add_argument("-D", "", + parser.add_argument("-D", action="append", dest="macros", help="Add a macro definition") @@ -51,6 +51,7 @@ help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)") parser.add_argument("--source", dest="source_dir", + type=argparse_filestring_type, default=None, help="The source (input) directory (for sources other than tests). Defaults to current directory.", action="append") parser.add_argument("--build", dest="build_dir", @@ -60,18 +61,20 @@ default=False, help="List (recursively) available tests in order and exit") parser.add_argument("-p", "--paths", dest="paths", + type=argparse_filestring_type, nargs="*" default=None, help="Limit the tests to those within the specified comma separated list of paths") format_choices = ["list", "json"] format_default_choice = "list" format_help = "Change the format in which tests are listed. Choices include: %s. Default: %s" % (", ".join(format_choices), format_default_choice) - parser.add_argument("-f", "--format", type=argparse_lowercase_type(format_coices,"format"), dest="format", - default=format_default_choice, help=format_help) + parser.add_argument("-f", "--format", dest="format", + type=argparse_lowercase_type(format_choices, "format"), + default=format_default_choice, help=format_help) parser.add_argument("--continue-on-build-fail", action="store_true", dest="continue_on_build_fail", default=None, help="Continue trying to build all tests if a build failure occurs") - parser.add_argument("-n", "--names", dest="names", + parser.add_argument("-n", "--names", dest="names", nargs="*" default=None, help="Limit the tests to a comma separated list of names") parser.add_argument("--test-spec", dest="test_spec", @@ -90,7 +93,7 @@ # Filter tests by path if specified if options.paths: - all_paths = options.paths.split(",") + all_paths = options.paths else: all_paths = ["."] @@ -103,7 +106,7 @@ # Filter tests by name if specified if options.names: - all_names = options.names.split(",") + all_names = options.names all_names = [x.lower() for x in all_names] for name in all_names: diff --git a/tools/utils.py b/tools/utils.py index c2ae4bd156d..2f763d3f07e 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -217,3 +217,7 @@ def parse_type(string): argparse_lowercase_type = argparse_list_type(str.lower, False) argparse_uppercase_hyphen_type = argparse_list_type(str.upper, True) argparse_lowercase_hyphen_type = argparse_list_type(str.lower, True) + +def argparse_filestring_type(string) : + if exists(string) : return string + else : raise argparse.ArgumentTypeError("{0} does not exist in the filesystem.".format(string)) From e4c6bcd72477b5ef4925dea503b8beadf6efe940 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Tue, 21 Jun 2016 13:59:28 -0500 Subject: [PATCH 06/17] Move test parsers to tests.py --- tools/make.py | 18 +----------------- tools/tests.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/tools/make.py b/tools/make.py index 431384168a9..b19321923a5 100644 --- a/tools/make.py +++ b/tools/make.py @@ -38,29 +38,13 @@ from tools.paths import UBLOX_LIBRARY from tools.tests import TESTS, Test, TEST_MAP from tools.tests import TEST_MBED_LIB +from tools.tests import test_known, test_name_known from tools.targets import TARGET_MAP from tools.options import get_default_options_parser from tools.build_api import build_project from tools.build_api import mcu_toolchain_matrix from utils import argparse_filestring_type from argparse import ArgumentTypeError -try: - import tools.private_settings as ps -except: - ps = object() - -def test_known(string): - i = int(string) - if i >= 0 and i < len(TESTS) : return i - else : raise ArgumentTypeError("{0} does not index a test".format(i)) - -def test_name_known(string): - nlist = string.split(',') - for test_id in nlist: - if test_id not in TEST_MAP.keys(): - raise ArgumentTypeError("Program with name '%s' not found"% test_id) - - return [TEST_MAP[n].n for n in nlist] if __name__ == '__main__': # Parse Options diff --git a/tools/tests.py b/tools/tests.py index 1b70f61e032..415fc140293 100644 --- a/tools/tests.py +++ b/tools/tests.py @@ -16,6 +16,12 @@ """ from tools.paths import * from tools.data.support import * +from argparse import ArgumentTypeError + +try: + import tools.private_settings as ps +except: + ps = object() TEST_CMSIS_LIB = join(TEST_DIR, "cmsis", "lib") TEST_MBED_LIB = join(TEST_DIR, "mbed", "env") @@ -1212,3 +1218,19 @@ def __getitem__(self, key): return None TEST_MAP = dict([(test['id'], Test(i)) for i, test in enumerate(TESTS)]) + +# parser helpers +def test_known(string): + i = int(string) + if i >= 0 and i < len(TESTS) : return i + else : raise ArgumentTypeError("{0} does not index a test".format(i)) + +def test_name_known(string): + nlist = string.split(',') + for test_id in nlist: + if test_id not in TEST_MAP.keys(): + if getattr(ps, "test_alias", None) is None or \ + ps.test_alias.get(test_id, "") not in TEST_MAP.keys(): + raise ArgumentTypeError("Program with name '%s' not found"% test_id) + + return [TEST_MAP[n].n for n in nlist] From c5ac2cfdec6f5bb43d9de454b4c7056af41b367c Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Tue, 21 Jun 2016 14:00:07 -0500 Subject: [PATCH 07/17] Create type combinator many --- tools/utils.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/utils.py b/tools/utils.py index 2f763d3f07e..c2c2f7141f6 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -199,7 +199,7 @@ def json_file_to_dict(fname): return dict_to_ascii(json.load(f, object_pairs_hook=OrderedDict)) # Wowza, double closure -def argparse_list_type(casedness, prefer_hyphen=False) : +def argparse_type(casedness, prefer_hyphen=False) : def middle(list, type_name): def parse_type(string): if prefer_hyphen: newstring = casedness(string).replace("_","-") @@ -213,10 +213,15 @@ def parse_type(string): return parse_type return middle -argparse_uppercase_type = argparse_list_type(str.upper, False) -argparse_lowercase_type = argparse_list_type(str.lower, False) -argparse_uppercase_hyphen_type = argparse_list_type(str.upper, True) -argparse_lowercase_hyphen_type = argparse_list_type(str.lower, True) +argparse_uppercase_type = argparse_type(str.upper, False) +argparse_lowercase_type = argparse_type(str.lower, False) +argparse_uppercase_hyphen_type = argparse_type(str.upper, True) +argparse_lowercase_hyphen_type = argparse_type(str.lower, True) + +def argparse_many(fn): + def wrap(string): + return [fn(s) for s in string.split(",")] + return wrap def argparse_filestring_type(string) : if exists(string) : return string From 18868ff3fb91323c89dcc2bebece8bfcb70c44a8 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Tue, 21 Jun 2016 14:00:32 -0500 Subject: [PATCH 08/17] Convert project.py to the new style of argument parsing --- tools/project.py | 111 +++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 70 deletions(-) diff --git a/tools/project.py b/tools/project.py index e41f6c3faaa..5b8aa6ee4b6 100644 --- a/tools/project.py +++ b/tools/project.py @@ -4,7 +4,7 @@ sys.path.insert(0, ROOT) from shutil import move, rmtree -from optparse import OptionParser +from argparse import ArgumentParser from os import path from tools.paths import EXPORT_DIR, EXPORT_WORKSPACE, EXPORT_TMP @@ -12,84 +12,89 @@ from tools.export import export, setup_user_prj, EXPORTERS, mcu_ide_matrix from tools.utils import args_error, mkdir from tools.tests import TESTS, Test, TEST_MAP +from tools.tests import test_known, test_name_known from tools.targets import TARGET_NAMES from tools.libraries import LIBRARIES +from utils import argparse_lowercase_type, argparse_uppercase_type, argparse_filestring_type, argparse_many -try: - import tools.private_settings as ps -except: - ps = object() if __name__ == '__main__': # Parse Options - parser = OptionParser() + parser = ArgumentParser() targetnames = TARGET_NAMES targetnames.sort() toolchainlist = EXPORTERS.keys() toolchainlist.sort() - parser.add_option("-m", "--mcu", + parser.add_argument("-m", "--mcu", metavar="MCU", default='LPC1768', + required=True, + type=argparse_many(argparse_uppercase_type(targetnames, "MCU")), help="generate project for the given MCU (%s)"% ', '.join(targetnames)) - parser.add_option("-i", + parser.add_argument("-i", dest="ide", default='uvision', + required=True, + type=argparse_many(argparse_lowercase_type(toolchainlist, "toolchain")), help="The target IDE: %s"% str(toolchainlist)) - parser.add_option("-c", "--clean", + parser.add_argument("-c", "--clean", action="store_true", default=False, help="clean the export directory") - parser.add_option("-p", - type="int", + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("-p", + type=test_known, dest="program", help="The index of the desired test program: [0-%d]"% (len(TESTS)-1)) - parser.add_option("-n", - dest="program_name", + group.add_argument("-n", + type=test_name_known, + dest="program", help="The name of the desired test program") - parser.add_option("-b", + parser.add_argument("-b", dest="build", action="store_true", default=False, help="use the mbed library build, instead of the sources") - parser.add_option("-L", "--list-tests", + parser.add_argument("-L", "--list-tests", action="store_true", dest="list_tests", default=False, help="list available programs in order and exit") - parser.add_option("-S", "--list-matrix", + parser.add_argument("-S", "--list-matrix", action="store_true", dest="supported_ides", default=False, help="displays supported matrix of MCUs and IDEs") - parser.add_option("-E", + parser.add_argument("-E", action="store_true", dest="supported_ides_html", default=False, help="writes tools/export/README.md") - parser.add_option("--source", - action="append", + parser.add_argument("--source", + nargs="*", + type=argparse_filestring_type, dest="source_dir", - default=None, + default=[], help="The source (input) directory") - parser.add_option("-D", "", + parser.add_argument("-D", action="append", dest="macros", help="Add a macro definition") - (options, args) = parser.parse_args() + options = parser.parse_args() # Print available tests in order and exit if options.list_tests is True: @@ -122,16 +127,6 @@ if exists(EXPORT_DIR): rmtree(EXPORT_DIR) - # Target - if options.mcu is None : - args_error(parser, "[ERROR] You should specify an MCU") - mcus = options.mcu - - # IDE - if options.ide is None: - args_error(parser, "[ERROR] You should specify an IDE") - ide = options.ide - # Export results successes = [] failures = [] @@ -141,14 +136,14 @@ # source_dir = use relative paths, otherwise sources are copied sources_relative = True if options.source_dir else False - for mcu in mcus.split(','): + for mcu in options.mcu: # Program Number or name - p, n, src, ide = options.program, options.program_name, options.source_dir, options.ide + p, src, ides = options.program, options.source_dir, options.ide - if src is not None: + if src: # --source is used to generate IDE files to toolchain directly in the source tree and doesn't generate zip file project_dir = options.source_dir - project_name = n if n else "Unnamed_Project" + project_name = TESTS[p] project_temp = path.join(options.source_dir[0], 'projectfiles', ide) mkdir(project_temp) lib_symbols = [] @@ -157,31 +152,6 @@ zip = False # don't create zip clean = False # don't cleanup because we use the actual source tree to generate IDE files else: - if n is not None and p is not None: - args_error(parser, "[ERROR] specify either '-n' or '-p', not both") - if n: - if not n in TEST_MAP.keys(): - # Check if there is an alias for this in private_settings.py - if getattr(ps, "test_alias", None) is not None: - alias = ps.test_alias.get(n, "") - if not alias in TEST_MAP.keys(): - args_error(parser, "[ERROR] Program with name '%s' not found" % n) - else: - n = alias - else: - args_error(parser, "[ERROR] Program with name '%s' not found" % n) - p = TEST_MAP[n].n - - if p is None or (p < 0) or (p > (len(TESTS)-1)): - message = "[ERROR] You have to specify one of the following tests:\n" - message += '\n'.join(map(str, sorted(TEST_MAP.values()))) - args_error(parser, message) - - # Project - if p is None or (p < 0) or (p > (len(TESTS)-1)): - message = "[ERROR] You have to specify one of the following tests:\n" - message += '\n'.join(map(str, sorted(TEST_MAP.values()))) - args_error(parser, message) test = Test(p) # Some libraries have extra macros (called by exporter symbols) to we need to pass @@ -210,16 +180,17 @@ setup_user_prj(project_dir[0], test.source_dir, test.dependencies) # Export to selected toolchain - tmp_path, report = export(project_dir, project_name, ide, mcu, project_dir[0], project_temp, clean=clean, zip=zip, extra_symbols=lib_symbols, relative=sources_relative) - if report['success']: - if not zip: - zip_path = join(project_temp, "%s_%s" % (project_name, mcu)) + for ide in ides: + tmp_path, report = export(project_dir, project_name, ide, mcu, project_dir[0], project_temp, clean=clean, zip=zip, extra_symbols=lib_symbols, relative=sources_relative) + if report['success']: + if not zip: + zip_path = join(project_temp, "%s_%s" % (project_name, mcu)) + else: + zip_path = join(EXPORT_DIR, "%s_%s_%s.zip" % (project_name, ide, mcu)) + move(tmp_path, zip_path) + successes.append("%s::%s\t%s"% (mcu, ide, zip_path)) else: - zip_path = join(EXPORT_DIR, "%s_%s_%s.zip" % (project_name, ide, mcu)) - move(tmp_path, zip_path) - successes.append("%s::%s\t%s"% (mcu, ide, zip_path)) - else: - failures.append("%s::%s\t%s"% (mcu, ide, report['errormsg'])) + failures.append("%s::%s\t%s"% (mcu, ide, report['errormsg'])) # Prints export results print From 2fc4d64b07cb43daa0147ecf5acaf645848b1a61 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Tue, 21 Jun 2016 14:57:56 -0500 Subject: [PATCH 09/17] Brought test_api.py and users into the new order of argument parsing --- tools/singletest.py | 8 +- tools/test_api.py | 443 ++++++++++++++++++++++--------------------- tools/test_webapi.py | 19 +- 3 files changed, 242 insertions(+), 228 deletions(-) diff --git a/tools/singletest.py b/tools/singletest.py index 058b96d4d17..eb14ddb5270 100644 --- a/tools/singletest.py +++ b/tools/singletest.py @@ -100,7 +100,7 @@ def get_version(): parser.description = """This script allows you to run mbed defined test cases for particular MCU(s) and corresponding toolchain(s).""" parser.epilog = """Example: singletest.py -i test_spec.json -M muts_all.json""" - (opts, args) = parser.parse_args() + opts = parser.parse_args() # Print scrip version if opts.version: @@ -154,10 +154,10 @@ def get_version(): mut['disk']) # Set up parameters for test specification filter function (we need to set toolchains per target here) - use_default_toolchain = 'default' in opts.toolchains_filter.split(',') if opts.toolchains_filter is not None else True - use_supported_toolchains = 'all' in opts.toolchains_filter.split(',') if opts.toolchains_filter is not None else False + use_default_toolchain = 'default' in opts.toolchains_filter if opts.toolchains_filter is not None else True + use_supported_toolchains = 'all' in opts.toolchains_filter if opts.toolchains_filter is not None else False toolchain_filter = opts.toolchains_filter - platform_name_filter = opts.general_filter_regex.split(',') if opts.general_filter_regex is not None else opts.general_filter_regex + platform_name_filter = opts.general_filter_regex if opts.general_filter_regex is not None else opts.general_filter_regex # Test specification with information about each target and associated toolchain test_spec = get_autodetected_TEST_SPEC(MUTs.values(), use_default_toolchain=use_default_toolchain, diff --git a/tools/test_api.py b/tools/test_api.py index 745bce563f9..c4643f3bc2a 100644 --- a/tools/test_api.py +++ b/tools/test_api.py @@ -24,7 +24,7 @@ import uuid import pprint import random -import optparse +import argparse import datetime import threading import ctypes @@ -58,7 +58,12 @@ from tools.build_api import scan_for_source_paths from tools.libraries import LIBRARIES, LIBRARY_MAP from tools.toolchains import TOOLCHAIN_BIN_PATH +from tools.toolchains import TOOLCHAINS from tools.test_exporters import ReportExporter, ResultExporterType +from tools.utils import argparse_filestring_type +from tools.utils import argparse_uppercase_type +from tools.utils import argparse_lowercase_type +from tools.utils import argparse_many import tools.host_tests.host_tests_plugins as host_tests_plugins @@ -623,7 +628,7 @@ def get_valid_tests(self, test_map_keys, target, toolchain, test_ids, include_no for test_id in test_map_keys: test = TEST_MAP[test_id] - if self.opts_test_by_names and test_id not in self.opts_test_by_names.split(','): + if self.opts_test_by_names and test_id not in self.opts_test_by_names: continue if test_ids and test_id not in test_ids: @@ -634,7 +639,7 @@ def get_valid_tests(self, test_map_keys, target, toolchain, test_ids, include_no print self.logger.log_line(self.logger.LogType.INFO, 'Common test skipped for target %s'% (target)) continue - if self.opts_peripheral_by_names and test.peripherals and not len([i for i in test.peripherals if i in self.opts_peripheral_by_names.split(',')]): + if self.opts_peripheral_by_names and test.peripherals and not len([i for i in test.peripherals if i in self.opts_peripheral_by_names]): # We will skip tests not forced with -p option if self.opts_verbose_skipped_tests: print self.logger.log_line(self.logger.LogType.INFO, 'Common test skipped for target %s'% (target)) @@ -655,7 +660,7 @@ def get_valid_tests(self, test_map_keys, target, toolchain, test_ids, include_no # When users are using 'build only flag' and test do not have # specified peripherals we can allow test building by default pass - elif self.opts_peripheral_by_names and test_id not in self.opts_peripheral_by_names.split(','): + elif self.opts_peripheral_by_names and test_id not in self.opts_peripheral_by_names: # If we force peripheral with option -p we expect test # to pass even if peripheral is not in MUTs file. pass @@ -773,7 +778,7 @@ def test_loop_list_to_dict(self, test_loops_str): """ result = {} if test_loops_str: - test_loops = test_loops_str.split(',') + test_loops = test_loops_str for test_loop in test_loops: test_loop_count = test_loop.split('=') if len(test_loop_count) == 2: @@ -1713,7 +1718,7 @@ def get_autodetected_TEST_SPEC(mbeds_list, toolchains += supported_toolchains if toolchain_filter is not None: all_toolchains = supported_toolchains + [default_toolchain] - for toolchain in toolchain_filter.split(','): + for toolchain in toolchain_filter: if toolchain in all_toolchains: toolchains.append(toolchain) @@ -1724,231 +1729,239 @@ def get_autodetected_TEST_SPEC(mbeds_list, def get_default_test_options_parser(): """ Get common test script options used by CLI, web services etc. """ - parser = optparse.OptionParser() - parser.add_option('-i', '--tests', - dest='test_spec_filename', - metavar="FILE", - help='Points to file with test specification') - - parser.add_option('-M', '--MUTS', - dest='muts_spec_filename', - metavar="FILE", - help='Points to file with MUTs specification (overwrites settings.py and private_settings.py)') - - parser.add_option("-j", "--jobs", - dest='jobs', - metavar="NUMBER", - type="int", - help="Define number of compilation jobs. Default value is 1") + parser = argparse.ArgumentParser() + parser.add_argument('-i', '--tests', + dest='test_spec_filename', + metavar="FILE", + type=argparse_filestring_type, + help='Points to file with test specification') + + parser.add_argument('-M', '--MUTS', + dest='muts_spec_filename', + metavar="FILE", + type=argparse_filestring_type, + help='Points to file with MUTs specification (overwrites settings.py and private_settings.py)') + + parser.add_argument("-j", "--jobs", + dest='jobs', + metavar="NUMBER", + type=int, + help="Define number of compilation jobs. Default value is 1") if get_module_avail('mbed_lstools'): # Additional features available when mbed_lstools is installed on host and imported # mbed_lstools allow users to detect connected to host mbed-enabled devices - parser.add_option('', '--auto', - dest='auto_detect', - metavar=False, - action="store_true", - help='Use mbed-ls module to detect all connected mbed devices') + parser.add_argument('--auto', + dest='auto_detect', + action="store_true", + help='Use mbed-ls module to detect all connected mbed devices') - parser.add_option('', '--tc', - dest='toolchains_filter', - help="Toolchain filter for --auto option. Use toolchains names separated by comma, 'default' or 'all' to select toolchains") + toolchain_list = list(TOOLCHAINS) + ["DEFAULT", "ALL"] + parser.add_argument('--tc', + dest='toolchains_filter', + type=argparse_many(argparse_uppercase_type(toolchain_list, "toolchains")), + help="Toolchain filter for --auto argument. Use toolchains names separated by comma, 'default' or 'all' to select toolchains") test_scopes = ','.join(["'%s'" % n for n in get_available_oper_test_scopes()]) - parser.add_option('', '--oper', - dest='operability_checks', - help='Perform interoperability tests between host and connected mbed devices. Available test scopes are: %s' % test_scopes) - - parser.add_option('', '--clean', - dest='clean', - metavar=False, - action="store_true", - help='Clean the build directory') - - parser.add_option('-P', '--only-peripherals', - dest='test_only_peripheral', - default=False, - action="store_true", - help='Test only peripheral declared for MUT and skip common tests') - - parser.add_option('-C', '--only-commons', - dest='test_only_common', - default=False, - action="store_true", - help='Test only board internals. Skip perpherials tests and perform common tests') - - parser.add_option('-n', '--test-by-names', - dest='test_by_names', - help='Runs only test enumerated it this switch. Use comma to separate test case names') - - parser.add_option('-p', '--peripheral-by-names', + parser.add_argument('--oper', + dest='operability_checks', + type=argparse_lowercase_type(get_available_oper_test_scopes(), "scopes"), + help='Perform interoperability tests between host and connected mbed devices. Available test scopes are: %s' % test_scopes) + + parser.add_argument('--clean', + dest='clean', + action="store_true", + help='Clean the build directory') + + parser.add_argument('-P', '--only-peripherals', + dest='test_only_peripheral', + default=False, + action="store_true", + help='Test only peripheral declared for MUT and skip common tests') + + parser.add_argument('-C', '--only-commons', + dest='test_only_common', + default=False, + action="store_true", + help='Test only board internals. Skip perpherials tests and perform common tests') + + parser.add_argument('-n', '--test-by-names', + dest='test_by_names', + type=argparse_many(str), + help='Runs only test enumerated it this switch. Use comma to separate test case names') + + parser.add_argument('-p', '--peripheral-by-names', dest='peripheral_by_names', + type=argparse_many(str), help='Forces discovery of particular peripherals. Use comma to separate peripheral names') copy_methods = host_tests_plugins.get_plugin_caps('CopyMethod') copy_methods_str = "Plugin support: " + ', '.join(copy_methods) - parser.add_option('-c', '--copy-method', - dest='copy_method', - help="Select binary copy (flash) method. Default is Python's shutil.copy() method. %s"% copy_methods_str) + parser.add_argument('-c', '--copy-method', + dest='copy_method', + type=argparse_uppercase_type(copy_methods, "flash method"), + help="Select binary copy (flash) method. Default is Python's shutil.copy() method. %s"% copy_methods_str) reset_methods = host_tests_plugins.get_plugin_caps('ResetMethod') reset_methods_str = "Plugin support: " + ', '.join(reset_methods) - parser.add_option('-r', '--reset-type', - dest='mut_reset_type', - default=None, - help='Extra reset method used to reset MUT by host test script. %s'% reset_methods_str) - - parser.add_option('-g', '--goanna-for-tests', - dest='goanna_for_tests', - metavar=False, - action="store_true", - help='Run Goanna static analyse tool for tests. (Project will be rebuilded)') - - parser.add_option('-G', '--goanna-for-sdk', - dest='goanna_for_mbed_sdk', - metavar=False, - action="store_true", - help='Run Goanna static analyse tool for mbed SDK (Project will be rebuilded)') - - parser.add_option('-s', '--suppress-summary', - dest='suppress_summary', - default=False, - action="store_true", - help='Suppresses display of wellformatted table with test results') - - parser.add_option('-t', '--test-summary', - dest='test_x_toolchain_summary', - default=False, - action="store_true", - help='Displays wellformatted table with test x toolchain test result per target') - - parser.add_option('-A', '--test-automation-report', - dest='test_automation_report', - default=False, - action="store_true", - help='Prints information about all tests and exits') - - parser.add_option('-R', '--test-case-report', - dest='test_case_report', - default=False, - action="store_true", - help='Prints information about all test cases and exits') - - parser.add_option("-S", "--supported-toolchains", - action="store_true", - dest="supported_toolchains", - default=False, - help="Displays supported matrix of MCUs and toolchains") - - parser.add_option("-O", "--only-build", - action="store_true", - dest="only_build_tests", - default=False, - help="Only build tests, skips actual test procedures (flashing etc.)") - - parser.add_option('', '--parallel', - dest='parallel_test_exec', - default=False, - action="store_true", - help='Experimental, you execute test runners for connected to your host MUTs in parallel (speeds up test result collection)') - - parser.add_option('', '--config', - dest='verbose_test_configuration_only', - default=False, - action="store_true", - help='Displays full test specification and MUTs configration and exits') - - parser.add_option('', '--loops', - dest='test_loops_list', - help='Set no. of loops per test. Format: TEST_1=1,TEST_2=2,TEST_3=3') - - parser.add_option('', '--global-loops', - dest='test_global_loops_value', - help='Set global number of test loops per test. Default value is set 1') - - parser.add_option('', '--consolidate-waterfall', - dest='consolidate_waterfall_test', - default=False, - action="store_true", - help='Used with --waterfall option. Adds only one test to report reflecting outcome of waterfall test.') - - parser.add_option('-W', '--waterfall', - dest='waterfall_test', - default=False, - action="store_true", - help='Used with --loops or --global-loops options. Tests until OK result occurs and assumes test passed') - - parser.add_option('-N', '--firmware-name', - dest='firmware_global_name', - help='Set global name for all produced projects. Note, proper file extension will be added by buid scripts') - - parser.add_option('-u', '--shuffle', - dest='shuffle_test_order', - default=False, - action="store_true", - help='Shuffles test execution order') - - parser.add_option('', '--shuffle-seed', - dest='shuffle_test_seed', - default=None, - help='Shuffle seed (If you want to reproduce your shuffle order please use seed provided in test summary)') - - parser.add_option('-f', '--filter', - dest='general_filter_regex', - default=None, - help='For some commands you can use filter to filter out results') - - parser.add_option('', '--inc-timeout', - dest='extend_test_timeout', - metavar="NUMBER", - type="int", - help='You can increase global timeout for each test by specifying additional test timeout in seconds') - - parser.add_option('', '--db', - dest='db_url', - help='This specifies what database test suite uses to store its state. To pass DB connection info use database connection string. Example: \'mysql://username:password@127.0.0.1/db_name\'') - - parser.add_option('-l', '--log', - dest='log_file_name', - help='Log events to external file (note not all console entries may be visible in log file)') - - parser.add_option('', '--report-html', - dest='report_html_file_name', - help='You can log test suite results in form of HTML report') - - parser.add_option('', '--report-junit', - dest='report_junit_file_name', - help='You can log test suite results in form of JUnit compliant XML report') - - parser.add_option("", "--report-build", - dest="report_build_file_name", - help="Output the build results to a junit xml file") - - parser.add_option('', '--verbose-skipped', - dest='verbose_skipped_tests', - default=False, - action="store_true", - help='Prints some extra information about skipped tests') - - parser.add_option('-V', '--verbose-test-result', - dest='verbose_test_result_only', - default=False, - action="store_true", - help='Prints test serial output') - - parser.add_option('-v', '--verbose', - dest='verbose', - default=False, - action="store_true", - help='Verbose mode (prints some extra information)') - - parser.add_option('', '--version', - dest='version', - default=False, - action="store_true", - help='Prints script version and exits') + parser.add_argument('-r', '--reset-type', + dest='mut_reset_type', + default=None, + type=argparse_uppercase_type(reset_methods, "reset method"), + help='Extra reset method used to reset MUT by host test script. %s'% reset_methods_str) + + parser.add_argument('-g', '--goanna-for-tests', + dest='goanna_for_tests', + action="store_true", + help='Run Goanna static analyse tool for tests. (Project will be rebuilded)') + + parser.add_argument('-G', '--goanna-for-sdk', + dest='goanna_for_mbed_sdk', + action="store_true", + help='Run Goanna static analyse tool for mbed SDK (Project will be rebuilded)') + + parser.add_argument('-s', '--suppress-summary', + dest='suppress_summary', + default=False, + action="store_true", + help='Suppresses display of wellformatted table with test results') + + parser.add_argument('-t', '--test-summary', + dest='test_x_toolchain_summary', + default=False, + action="store_true", + help='Displays wellformatted table with test x toolchain test result per target') + + parser.add_argument('-A', '--test-automation-report', + dest='test_automation_report', + default=False, + action="store_true", + help='Prints information about all tests and exits') + + parser.add_argument('-R', '--test-case-report', + dest='test_case_report', + default=False, + action="store_true", + help='Prints information about all test cases and exits') + + parser.add_argument("-S", "--supported-toolchains", + action="store_true", + dest="supported_toolchains", + default=False, + help="Displays supported matrix of MCUs and toolchains") + + parser.add_argument("-O", "--only-build", + action="store_true", + dest="only_build_tests", + default=False, + help="Only build tests, skips actual test procedures (flashing etc.)") + + parser.add_argument('--parallel', + dest='parallel_test_exec', + default=False, + action="store_true", + help='Experimental, you execute test runners for connected to your host MUTs in parallel (speeds up test result collection)') + + parser.add_argument('--config', + dest='verbose_test_configuration_only', + default=False, + action="store_true", + help='Displays full test specification and MUTs configration and exits') + + parser.add_argument('--loops', + dest='test_loops_list', + type=argparse_many(str), + help='Set no. of loops per test. Format: TEST_1=1,TEST_2=2,TEST_3=3') + + parser.add_argument('--global-loops', + dest='test_global_loops_value', + type=int, + help='Set global number of test loops per test. Default value is set 1') + + parser.add_argument('--consolidate-waterfall', + dest='consolidate_waterfall_test', + default=False, + action="store_true", + help='Used with --waterfall argument. Adds only one test to report reflecting outcome of waterfall test.') + + parser.add_argument('-W', '--waterfall', + dest='waterfall_test', + default=False, + action="store_true", + help='Used with --loops or --global-loops arguments. Tests until OK result occurs and assumes test passed') + + parser.add_argument('-N', '--firmware-name', + dest='firmware_global_name', + help='Set global name for all produced projects. Note, proper file extension will be added by buid scripts') + + parser.add_argument('-u', '--shuffle', + dest='shuffle_test_order', + default=False, + action="store_true", + help='Shuffles test execution order') + + parser.add_argument('--shuffle-seed', + dest='shuffle_test_seed', + default=None, + help='Shuffle seed (If you want to reproduce your shuffle order please use seed provided in test summary)') + + parser.add_argument('-f', '--filter', + dest='general_filter_regex', + type=argparse_many(str), + default=None, + help='For some commands you can use filter to filter out results') + + parser.add_argument('--inc-timeout', + dest='extend_test_timeout', + metavar="NUMBER", + type=int, + help='You can increase global timeout for each test by specifying additional test timeout in seconds') + + parser.add_argument('--db', + dest='db_url', + help='This specifies what database test suite uses to store its state. To pass DB connection info use database connection string. Example: \'mysql://username:password@127.0.0.1/db_name\'') + + parser.add_argument('-l', '--log', + dest='log_file_name', + help='Log events to external file (note not all console entries may be visible in log file)') + + parser.add_argument('--report-html', + dest='report_html_file_name', + help='You can log test suite results in form of HTML report') + + parser.add_argument('--report-junit', + dest='report_junit_file_name', + help='You can log test suite results in form of JUnit compliant XML report') + + parser.add_argument("--report-build", + dest="report_build_file_name", + help="Output the build results to a junit xml file") + + parser.add_argument('--verbose-skipped', + dest='verbose_skipped_tests', + default=False, + action="store_true", + help='Prints some extra information about skipped tests') + + parser.add_argument('-V', '--verbose-test-result', + dest='verbose_test_result_only', + default=False, + action="store_true", + help='Prints test serial output') + + parser.add_argument('-v', '--verbose', + dest='verbose', + default=False, + action="store_true", + help='Verbose mode (prints some extra information)') + + parser.add_argument('--version', + dest='version', + default=False, + action="store_true", + help='Prints script version and exits') return parser def test_path_to_name(path): @@ -2083,4 +2096,4 @@ def test_spec_from_test_builds(test_builds): return { "builds": test_builds } - \ No newline at end of file + diff --git a/tools/test_webapi.py b/tools/test_webapi.py index ffed0e46243..437a719aded 100644 --- a/tools/test_webapi.py +++ b/tools/test_webapi.py @@ -106,15 +106,16 @@ def get_default_test_webservice_options_parser(): parser = get_default_test_options_parser() # Things related to web services offered by test suite scripts - parser.add_option('', '--rest-api', - dest='rest_api_enabled', - default=False, - action="store_true", - help='Enables REST API.') - - parser.add_option('', '--rest-api-port', - dest='rest_api_port_no', - help='Sets port for REST API interface') + parser.add_argument('', '--rest-api', + dest='rest_api_enabled', + default=False, + action="store_true", + help='Enables REST API.') + + parser.add_argument('', '--rest-api-port', + dest='rest_api_port_no', + type=int, + help='Sets port for REST API interface') return parser From 91c45a7b6f700f5a5d665317923a8664d506b267 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Wed, 22 Jun 2016 11:26:41 -0500 Subject: [PATCH 10/17] Improve test -n and -p failure messages --- tools/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/tests.py b/tools/tests.py index 415fc140293..687a2d649c4 100644 --- a/tools/tests.py +++ b/tools/tests.py @@ -1223,7 +1223,7 @@ def __getitem__(self, key): def test_known(string): i = int(string) if i >= 0 and i < len(TESTS) : return i - else : raise ArgumentTypeError("{0} does not index a test".format(i)) + else : raise ArgumentTypeError("{0} does not index a test. The accepted range is 0 to {1}".format(i, len(TEST_MAP) - 1)) def test_name_known(string): nlist = string.split(',') @@ -1231,6 +1231,6 @@ def test_name_known(string): if test_id not in TEST_MAP.keys(): if getattr(ps, "test_alias", None) is None or \ ps.test_alias.get(test_id, "") not in TEST_MAP.keys(): - raise ArgumentTypeError("Program with name '%s' not found"% test_id) + raise ArgumentTypeError("Program with name '{0}' not found. Supported tests are {1}".format(test_id, ", ".join(TEST_MAP.keys()))) return [TEST_MAP[n].n for n in nlist] From c969a4c784a20a92443aa6a8a1bd536299ee736f Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Wed, 22 Jun 2016 12:09:02 -0500 Subject: [PATCH 11/17] Better test completion and everything that can be is columnated --- tools/tests.py | 5 +++-- tools/utils.py | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/tools/tests.py b/tools/tests.py index 687a2d649c4..4164d452020 100644 --- a/tools/tests.py +++ b/tools/tests.py @@ -17,6 +17,7 @@ from tools.paths import * from tools.data.support import * from argparse import ArgumentTypeError +from utils import columnate try: import tools.private_settings as ps @@ -1223,7 +1224,7 @@ def __getitem__(self, key): def test_known(string): i = int(string) if i >= 0 and i < len(TESTS) : return i - else : raise ArgumentTypeError("{0} does not index a test. The accepted range is 0 to {1}".format(i, len(TEST_MAP) - 1)) + else : raise ArgumentTypeError("{0} does not index a test. The accepted range is 0 to {1}\nThe test mapping is:\n{2}".format(i, len(TEST_MAP) - 1, columnate([str(i) + ":" + t['id'] for i,t in zip(range(len(TESTS)), TESTS)]))) def test_name_known(string): nlist = string.split(',') @@ -1231,6 +1232,6 @@ def test_name_known(string): if test_id not in TEST_MAP.keys(): if getattr(ps, "test_alias", None) is None or \ ps.test_alias.get(test_id, "") not in TEST_MAP.keys(): - raise ArgumentTypeError("Program with name '{0}' not found. Supported tests are {1}".format(test_id, ", ".join(TEST_MAP.keys()))) + raise ArgumentTypeError("Program with name '{0}' not found. Supported tests are: \n{1}".format(test_id, columnate([t['id'] for t in TESTS]))) return [TEST_MAP[n].n for n in nlist] diff --git a/tools/utils.py b/tools/utils.py index c2c2f7141f6..6ffca38c9f6 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -18,6 +18,7 @@ import inspect import os import argparse +import math from os import listdir, remove, makedirs from shutil import copyfile from os.path import isdir, join, exists, split, relpath, splitext @@ -209,7 +210,7 @@ def parse_type(string): elif string not in list and newstring in list: raise argparse.ArgumentTypeError("{0} is not a supported {1}. Did you mean {2}?".format(string, type_name, newstring)) else: - raise argparse.ArgumentTypeError("{0} is not a supported {1}. Supported {1}s are {2}.".format(string, type_name, ", ".join(list))) + raise argparse.ArgumentTypeError("{0} is not a supported {1}. Supported {1}s are:\n{2}".format(string, type_name, columnate(list))) return parse_type return middle @@ -226,3 +227,19 @@ def wrap(string): def argparse_filestring_type(string) : if exists(string) : return string else : raise argparse.ArgumentTypeError("{0} does not exist in the filesystem.".format(string)) + +def columnate(strings, seperator=", ", chars=80): + col_width = max(len(s) for s in strings) + total_width = col_width + len(seperator) + columns = math.floor(chars / total_width) + output = "" + for i, s in zip(range(len(strings)), strings): + append = s + if i != len(strings) - 1: + append += seperator + if i % columns == columns - 1: + append += "\n" + else: + append = append.ljust(total_width) + output += append + return output From 053efc68648b75f0728e19c855617341fcae2810 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Thu, 23 Jun 2016 15:08:36 -0500 Subject: [PATCH 12/17] Add -S, -L, and --source to the mutually exclusive group --- tools/make.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/make.py b/tools/make.py index b19321923a5..54cdbfb2cc7 100644 --- a/tools/make.py +++ b/tools/make.py @@ -83,7 +83,7 @@ dest="macros", help="Add a macro definition") - parser.add_argument("-S", "--supported-toolchains", + group.add_argument("-S", "--supported-toolchains", action="store_true", dest="supported_toolchains", default=False, @@ -105,7 +105,7 @@ default=None, help="Required peripherals") parser.add_argument("--dep", dest="dependencies", default=None, help="Dependencies") - parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type, + group.add_argument("--source", dest="source_dir", type=argparse_filestring_type, default=None, help="The source (input) directory", action="append") parser.add_argument("--duration", type=int, dest="duration", default=None, help="Duration of the test") @@ -119,7 +119,7 @@ default=None, help="The mbed serial port") parser.add_argument("-b", "--baud", type=int, dest="baud", default=None, help="The mbed serial baud rate") - parser.add_argument("-L", "--list-tests", action="store_true", dest="list_tests", + group.add_argument("-L", "--list-tests", action="store_true", dest="list_tests", default=False, help="List available tests in order and exit") # Ideally, all the tests with a single "main" thread can be run with, or From 439d2e853965744b8889a89dd26e7555caf0bf2d Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Thu, 23 Jun 2016 15:26:10 -0500 Subject: [PATCH 13/17] Add -S, -L, and --source to the project.py mutually exclusive group --- tools/project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/project.py b/tools/project.py index 5b8aa6ee4b6..b16e9dc39d1 100644 --- a/tools/project.py +++ b/tools/project.py @@ -64,13 +64,13 @@ default=False, help="use the mbed library build, instead of the sources") - parser.add_argument("-L", "--list-tests", + group.add_argument("-L", "--list-tests", action="store_true", dest="list_tests", default=False, help="list available programs in order and exit") - parser.add_argument("-S", "--list-matrix", + group.add_argument("-S", "--list-matrix", action="store_true", dest="supported_ides", default=False, @@ -82,7 +82,7 @@ default=False, help="writes tools/export/README.md") - parser.add_argument("--source", + group.add_argument("--source", nargs="*", type=argparse_filestring_type, dest="source_dir", From 3276854f4950861770640fdd05b49de982bc0161 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Thu, 23 Jun 2016 15:57:36 -0500 Subject: [PATCH 14/17] fix parse error in test.py and make -n + -p comma separated --- tools/test.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/test.py b/tools/test.py index 4eaee354c29..0fa745f1d1c 100644 --- a/tools/test.py +++ b/tools/test.py @@ -32,7 +32,7 @@ from tools.targets import TARGET_MAP from tools.utils import mkdir, ToolException, NotSupportedException from tools.test_exporters import ReportExporter, ResultExporterType -from utils import argparse_filestring_type, argparse_lowercase_type +from utils import argparse_filestring_type, argparse_lowercase_type, argparse_many if __name__ == '__main__': try: @@ -61,7 +61,7 @@ default=False, help="List (recursively) available tests in order and exit") parser.add_argument("-p", "--paths", dest="paths", - type=argparse_filestring_type, nargs="*" + type=argparse_many(argparse_filestring_type), default=None, help="Limit the tests to those within the specified comma separated list of paths") format_choices = ["list", "json"] @@ -74,7 +74,8 @@ parser.add_argument("--continue-on-build-fail", action="store_true", dest="continue_on_build_fail", default=None, help="Continue trying to build all tests if a build failure occurs") - parser.add_argument("-n", "--names", dest="names", nargs="*" + #TODO validate the names instead of just passing through str + parser.add_argument("-n", "--names", dest="names", type=argparse_many(str), default=None, help="Limit the tests to a comma separated list of names") parser.add_argument("--test-spec", dest="test_spec", From 7e5deaa7d0244f4f0482cb392ed80f632d305eab Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Thu, 23 Jun 2016 16:14:18 -0500 Subject: [PATCH 15/17] standardize on nargs="*" --- tools/build.py | 4 ++-- tools/get_config.py | 4 ++-- tools/make.py | 4 ++-- tools/options.py | 2 +- tools/project.py | 2 +- tools/test.py | 6 +++--- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/build.py b/tools/build.py index 691129dcc99..1dd9de6aa0c 100644 --- a/tools/build.py +++ b/tools/build.py @@ -44,7 +44,7 @@ parser = get_default_options_parser() parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type, - default=None, help="The source (input) directory", action="append") + default=None, help="The source (input) directory", nargs="*") parser.add_argument("--build", dest="build_dir", type=argparse_filestring_type, default=None, help="The build (output) directory") @@ -107,7 +107,7 @@ help="Compiles 'cpputest' unit test library (library should be on the same directory level as mbed repository)") parser.add_argument("-D", - action="append", + nargs="*", dest="macros", help="Add a macro definition") diff --git a/tools/get_config.py b/tools/get_config.py index 8efb30293f6..91dbccf5488 100644 --- a/tools/get_config.py +++ b/tools/get_config.py @@ -38,8 +38,8 @@ # Parse Options parser = get_default_options_parser(add_clean=False, add_options=False) parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type, - default=[], help="The source (input) directory", action="append") - parser.add_argument("--prefix", dest="prefix", action="append", + default=[], help="The source (input) directory", nargs="*") + parser.add_argument("--prefix", dest="prefix", nargs="*", default=[], help="Restrict listing to parameters that have this prefix") parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Verbose diagnostic output") diff --git a/tools/make.py b/tools/make.py index 54cdbfb2cc7..a77fc2a7721 100644 --- a/tools/make.py +++ b/tools/make.py @@ -79,7 +79,7 @@ help="Silent diagnostic output (no copy, compile notification)") parser.add_argument("-D", - action="append", + nargs="*", dest="macros", help="Add a macro definition") @@ -106,7 +106,7 @@ parser.add_argument("--dep", dest="dependencies", default=None, help="Dependencies") group.add_argument("--source", dest="source_dir", type=argparse_filestring_type, - default=None, help="The source (input) directory", action="append") + default=None, help="The source (input) directory", nargs="*") parser.add_argument("--duration", type=int, dest="duration", default=None, help="Duration of the test") parser.add_argument("--build", dest="build_dir", diff --git a/tools/options.py b/tools/options.py index d4e338b90dc..16bb7af93a8 100644 --- a/tools/options.py +++ b/tools/options.py @@ -43,7 +43,7 @@ def get_default_options_parser(add_clean=True, add_options=True): help="clean the build directory") if add_options: - parser.add_argument("-o", "--options", action="append", + parser.add_argument("-o", "--options", nargs="*", help='Add a build argument ("save-asm": save the asm generated by the compiler, "debug-info": generate debugging information, "analyze": run Goanna static code analyzer")', type=argparse_lowercase_hyphen_type(['save-asm', 'debug-info', 'analyze'], "build option")) diff --git a/tools/project.py b/tools/project.py index b16e9dc39d1..a44afd283bd 100644 --- a/tools/project.py +++ b/tools/project.py @@ -90,7 +90,7 @@ help="The source (input) directory") parser.add_argument("-D", - action="append", + nargs="*", dest="macros", help="Add a macro definition") diff --git a/tools/test.py b/tools/test.py index 0fa745f1d1c..dbec9ed5759 100644 --- a/tools/test.py +++ b/tools/test.py @@ -40,10 +40,10 @@ parser = get_default_options_parser() parser.add_argument("-D", - action="append", + nargs="*", dest="macros", help="Add a macro definition") - + parser.add_argument("-j", "--jobs", type=int, dest="jobs", @@ -52,7 +52,7 @@ parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type, - default=None, help="The source (input) directory (for sources other than tests). Defaults to current directory.", action="append") + default=None, help="The source (input) directory (for sources other than tests). Defaults to current directory.", nargs="*") parser.add_argument("--build", dest="build_dir", default=None, help="The build (output) directory") From d757f35d159f0560563c651b900664ed8344896d Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Fri, 24 Jun 2016 12:04:31 -0500 Subject: [PATCH 16/17] Update style --- tools/utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/utils.py b/tools/utils.py index 6ffca38c9f6..bce6c648021 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -225,8 +225,10 @@ def wrap(string): return wrap def argparse_filestring_type(string) : - if exists(string) : return string - else : raise argparse.ArgumentTypeError("{0} does not exist in the filesystem.".format(string)) + if exists(string) : + return string + else : + raise argparse.ArgumentTypeError("{0}"" does not exist in the filesystem.".format(string)) def columnate(strings, seperator=", ", chars=80): col_width = max(len(s) for s in strings) From 7b3ef2179f0ee41bd5e2e727328188994e93c426 Mon Sep 17 00:00:00 2001 From: Jimmy Brisson Date: Fri, 24 Jun 2016 12:19:12 -0500 Subject: [PATCH 17/17] Make mcu and tool arguments many and update all consumers of them --- tools/build.py | 12 ++---------- tools/make.py | 4 ++-- tools/options.py | 6 +++--- tools/test.py | 6 +++--- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/tools/build.py b/tools/build.py index 1dd9de6aa0c..e388ebd7aea 100644 --- a/tools/build.py +++ b/tools/build.py @@ -159,18 +159,10 @@ exit(0) # Get target list - if options.mcu: - mcu_list = (options.mcu).split(",") - targets = mcu_list - else: - targets = TARGET_NAMES + targets = options.mcu if options.mcu else TARGET_NAMES # Get toolchains list - if options.tool: - toolchain_list = (options.tool).split(",") - toolchains = toolchain_list - else: - toolchains = TOOLCHAINS + toolchains = options.tool if options.tool else TOOLCHAINS # Get libraries list libraries = [] diff --git a/tools/make.py b/tools/make.py index a77fc2a7721..7fedb733028 100644 --- a/tools/make.py +++ b/tools/make.py @@ -204,12 +204,12 @@ # Target if options.mcu is None : args_error(parser, "[ERROR] You should specify an MCU") - mcu = options.mcu + mcu = options.mcu[0] # Toolchain if options.tool is None: args_error(parser, "[ERROR] You should specify a TOOLCHAIN") - toolchain = options.tool + toolchain = options.tool[0] # Test for test_no in p: diff --git a/tools/options.py b/tools/options.py index 16bb7af93a8..1585323b14d 100644 --- a/tools/options.py +++ b/tools/options.py @@ -17,7 +17,7 @@ from argparse import ArgumentParser from tools.toolchains import TOOLCHAINS from tools.targets import TARGET_NAMES -from utils import argparse_uppercase_type, argparse_lowercase_hyphen_type +from utils import argparse_uppercase_type, argparse_lowercase_hyphen_type, argparse_many def get_default_options_parser(add_clean=True, add_options=True): @@ -31,12 +31,12 @@ def get_default_options_parser(add_clean=True, add_options=True): parser.add_argument("-m", "--mcu", help="build for the given MCU (%s)" % ', '.join(targetnames), metavar="MCU", - type=argparse_uppercase_type(targetnames, "MCU")) + type=argparse_many(argparse_uppercase_type(targetnames, "MCU"))) parser.add_argument("-t", "--tool", help="build using the given TOOLCHAIN (%s)" % ', '.join(toolchainlist), metavar="TOOLCHAIN", - type=argparse_uppercase_type(toolchainlist, "toolchain")) + type=argparse_many(argparse_uppercase_type(toolchainlist, "toolchain"))) if add_clean: parser.add_argument("-c", "--clean", action="store_true", default=False, diff --git a/tools/test.py b/tools/test.py index dbec9ed5759..b74446a725b 100644 --- a/tools/test.py +++ b/tools/test.py @@ -137,7 +137,7 @@ base_source_paths = ['.'] - target = TARGET_MAP[options.mcu] + target = TARGET_MAP[options.mcu[0]] build_report = {} build_properties = {} @@ -145,7 +145,7 @@ library_build_success = False try: # Build sources - build_library(base_source_paths, options.build_dir, target, options.tool, + build_library(base_source_paths, options.build_dir, target, options.tool[0], options=options.options, jobs=options.jobs, clean=options.clean, @@ -171,7 +171,7 @@ print "Failed to build library" else: # Build all the tests - test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, target, options.tool, + test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, target, options.tool[0], options=options.options, clean=options.clean, report=build_report,