diff --git a/tools/build.py b/tools/build.py index e47cd6a411f..275d89cdf95 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,115 +43,115 @@ # Parse Options parser = get_default_options_parser() - parser.add_option("--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=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: @@ -158,26 +159,10 @@ exit(0) # 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 + targets = options.mcu if options.mcu else TARGET_NAMES # 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 + toolchains = options.tool if options.tool else TOOLCHAINS # Get libraries list libraries = [] 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..c9b2a9bebc3 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,28 +37,24 @@ if __name__ == '__main__': # Parse Options parser = get_default_options_parser(add_clean=False, add_options=False) - parser.add_option("--source", dest="source_dir", - default=None, help="The source (input) directory", action="append") - parser.add_option("--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("--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="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, args) = parser.parse_args() + 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") - target = options.mcu + target = 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] options.prefix = options.prefix or [""] diff --git a/tools/host_tests/host_tests_plugins/module_copy_smart.py b/tools/host_tests/host_tests_plugins/module_copy_smart.py index 1af9eaf70aa..486382bada9 100644 --- a/tools/host_tests/host_tests_plugins/module_copy_smart.py +++ b/tools/host_tests/host_tests_plugins/module_copy_smart.py @@ -22,7 +22,7 @@ from host_test_plugins import HostTestPluginBase sys.path.append(abspath(join(dirname(__file__), "../../../"))) -from tools.test_api import get_autodetected_MUTS_list +import tools.test_api class HostTestPluginCopyMethod_Smart(HostTestPluginBase): @@ -74,7 +74,7 @@ def execute(self, capability, *args, **kwargs): for i in range(0, 60): print('Looking for %s with MBEDLS' % target_mcu) - muts_list = get_autodetected_MUTS_list(platform_name_filter=platform_name_filter) + muts_list = tools.test_api.get_autodetected_MUTS_list(platform_name_filter=platform_name_filter) if 1 in muts_list: mut = muts_list[1] diff --git a/tools/make.py b/tools/make.py index 200a2b336a8..ba86f5170a9 100644 --- a/tools/make.py +++ b/tools/make.py @@ -38,157 +38,154 @@ 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 -try: - import tools.private_settings as ps -except: - ps = object() +from utils import argparse_filestring_type +from utils import argparse_many +from argparse import ArgumentTypeError if __name__ == '__main__': # Parse Options parser = get_default_options_parser() - parser.add_option("-p", - type="int", + group = parser.add_mutually_exclusive_group(required=False) + group.add_argument("-p", + type=argparse_many(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=argparse_many(test_name_known), + dest="program", 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", + group.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", - default=None, help="The source (input) directory", action="append") - parser.add_option("--duration", type="int", dest="duration", + 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") - 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", + 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 # 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", + type=argparse_filestring_type, 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: 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 +194,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([]): @@ -224,12 +205,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/memap.py b/tools/memap.py index a5441fdd964..94d378024f9 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, argparse_filestring_type from prettytable import PrettyTable debug = False @@ -339,6 +340,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 @@ -488,6 +491,8 @@ def get_memory_summary(self): """ return self.mem_summary + toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "IAR"] + def parse(self, mapfile, toolchain): """ Parse and decode map file depending on the toolchain @@ -518,15 +523,15 @@ def main(): # Parser handling parser = argparse.ArgumentParser(description="Memory Map File Analyser for ARM mbed\nversion %s" % version) - parser.add_argument('file', help='memory map file') + parser.add_argument('file', type=argparse_filestring_type, 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=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,\ - help="export format (examples: 'json', 'csv-ci', 'table': default)") + 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) @@ -544,13 +549,8 @@ 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 - if not args.export: - args.export = 'table' - # Write output in file if args.output != None: memap.generate_output(args.export, args.output) diff --git a/tools/options.py b/tools/options.py index 250e8e19484..36789f505a3 100644 --- a/tools/options.py +++ b/tools/options.py @@ -14,33 +14,36 @@ 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_force_uppercase_type, argparse_lowercase_hyphen_type, argparse_many 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_many(argparse_force_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_many(argparse_force_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/project.py b/tools/project.py index 239507aea3b..c58858d79d7 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,90 @@ 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 +from utils import argparse_force_lowercase_type, argparse_force_uppercase_type -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_force_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_force_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=False) + 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", + group.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", + group.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", + parser.add_argument("--source", action="append", + 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 +128,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 +137,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, ide = 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] if p else "Unnamed_project" project_temp = path.join(options.source_dir[0], 'projectfiles', '%s_%s' % (ide, mcu)) mkdir(project_temp) lib_symbols = [] @@ -157,31 +153,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 diff --git a/tools/singletest.py b/tools/singletest.py index 4142878b0bd..bde208c5214 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.py b/tools/test.py index 62dc6e74e3e..96ea461aee9 100644 --- a/tools/test.py +++ b/tools/test.py @@ -33,64 +33,69 @@ 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, argparse_many 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", - default=None, help="The source (input) directory (for sources other than tests). Defaults to current directory.", action="append") + 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_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", + 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"] 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_option("--continue-on-build-fail", action="store_true", dest="continue_on_build_fail", + 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_option("-n", "--names", dest="names", + #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_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: - all_paths = options.paths.split(",") + all_paths = options.paths else: all_paths = ["."] @@ -103,7 +108,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: @@ -133,15 +138,15 @@ base_source_paths = ['.'] - target = options.mcu - + target = options.mcu[0] + build_report = {} build_properties = {} 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, @@ -167,7 +172,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, diff --git a/tools/test_api.py b/tools/test_api.py index fc28f67fd0e..6797cae9240 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 @@ -59,7 +59,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 @@ -626,7 +631,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: @@ -637,7 +642,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)) @@ -658,7 +663,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 @@ -776,7 +781,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: @@ -1720,7 +1725,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) @@ -1731,235 +1736,243 @@ 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("", "--report-text", - dest="report_text_file_name", - help="Output the build results to a text 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("--report-text", + dest="report_text_file_name", + help="Output the build results to a text 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): 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 diff --git a/tools/tests.py b/tools/tests.py index a085b001fd5..8cc9576f017 100644 --- a/tools/tests.py +++ b/tools/tests.py @@ -16,6 +16,13 @@ """ from tools.paths import * from tools.data.support import * +from argparse import ArgumentTypeError +from utils import columnate + +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") @@ -1217,3 +1224,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. 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): + if string not in TEST_MAP.keys() and \ + (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: \n{1}".format(string, columnate([t['id'] for t in TESTS]))) + + return TEST_MAP[string].n diff --git a/tools/utils.py b/tools/utils.py index 55752b8750d..5c64c41e65d 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -17,6 +17,8 @@ import sys 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 @@ -196,3 +198,75 @@ 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_type(casedness, prefer_hyphen=False) : + def middle(list, type_name): + # validate that an argument passed in (as string) is a member of the list of possible + # arguments. Offer a suggestion if the case of the string, or the hyphens/underscores + # do not match the expected style of the argument. + 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:\n{2}".format(string, type_name, columnate(list))) + return parse_type + return middle + +# short cuts for the argparse_type versions +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_force_type(case): + def middle(list, type_name): + # validate that an argument passed in (as string) is a member of the list of possible + # arguments after converting it's case. Offer a suggestion if the hyphens/underscores + # do not match the expected style of the argument. + def parse_type(string): + for option in list: + if case(string) == case(option): + return option + 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 + +# these two types convert the case of their arguments _before_ validation +argparse_force_uppercase_type = argparse_force_type(str.upper) +argparse_force_lowercase_type = argparse_force_type(str.lower) + +# An argument parser combinator that takes in an argument parser and creates a new parser that +# accepts a comma separated list of the same thing. +def argparse_many(fn): + def wrap(string): + return [fn(s) for s in string.split(",")] + return wrap + +# An argument parser that verifies that a string passed in corresponds to a file +def argparse_filestring_type(string) : + if exists(string) : + return string + else : + raise argparse.ArgumentTypeError("{0}"" does not exist in the filesystem.".format(string)) + +# render a list of strings as a in a bunch of columns +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