diff --git a/tools/test.py b/tools/test.py index 3d60b3bc58..136a55fda6 100644 --- a/tools/test.py +++ b/tools/test.py @@ -21,17 +21,32 @@ TEST BUILD & RUN import sys import os import json -from optparse import OptionParser ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) sys.path.insert(0, ROOT) -from tools.test_api import test_path_to_name, find_tests, print_tests +from tools.test_api import test_path_to_name, find_tests, print_tests, build_tests, test_spec_from_test_build +from tools.options import get_default_options_parser +from tools.build_api import build_project +from tools.targets import TARGET_MAP +from tools.utils import mkdir if __name__ == '__main__': try: # Parse Options - parser = OptionParser() + parser = get_default_options_parser() + + parser.add_option("-j", "--jobs", + type="int", + dest="jobs", + default=1, + help="Number of concurrent jobs (default 1). Use 0 for 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_option("--build", dest="build_dir", + default=None, help="The build (output) directory") parser.add_option("-l", "--list", action="store_true", dest="list", default=False, help="List (recursively) available tests in order and exit") @@ -39,24 +54,93 @@ if __name__ == '__main__': parser.add_option("-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=["list", "json"], default="list", help="List available tests in order and exit") + choices=format_choices, default=format_default_choice, help=format_help) + + parser.add_option("-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", + default=None, help="Destination path for a test spec file that can be used by the Greentea automated test tool") + + parser.add_option("-v", "--verbose", + action="store_true", + dest="verbose", + default=False, + help="Verbose diagnostic output") (options, args) = parser.parse_args() - # Print available tests in order and exit - if options.list is True: - tests = {} - - if options.paths: - all_paths = options.paths.split(",") - for path in all_paths: - tests.update(find_tests(path)) - else: - tests = find_tests('.') + # Filter tests by path if specified + if options.paths: + all_paths = options.paths.split(",") + else: + all_paths = ["."] + + all_tests = {} + tests = {} + + # Find all tests in the relevant paths + for path in all_paths: + all_tests.update(find_tests(path)) + + # Filter tests by name if specified + if options.names: + all_names = options.names.split(",") + all_tests_keys = all_tests.keys() + for name in all_names: + if name in all_tests_keys: + tests[name] = all_tests[name] + else: + print "[Warning] Test with name '%s' was not found in the available tests" % (name) + else: + tests = all_tests + + if options.list: + # Print available tests in order and exit print_tests(tests, options.format) - sys.exit() + else: + # Build all tests + if not options.build_dir: + print "[ERROR] You must specify a build path" + sys.exit(1) + + base_source_paths = options.source_dir + + # Default base source path is the current directory + if not base_source_paths: + base_source_paths = ['.'] + + target = TARGET_MAP[options.mcu] + + # Build all the tests + test_build = build_tests(tests, base_source_paths, options.build_dir, target, options.tool, + options=options.options, + clean=options.clean, + jobs=options.jobs) + + # If a path to a test spec is provided, write it to a file + if options.test_spec: + test_spec_data = test_spec_from_test_build(test_build) + + # Create the target dir for the test spec if necessary + # mkdir will not create the dir if it already exists + test_spec_dir = os.path.dirname(options.test_spec) + if test_spec_dir: + mkdir(test_spec_dir) + + try: + with open(options.test_spec, 'w') as f: + f.write(json.dumps(test_spec_data, indent=2)) + except IOError, e: + print "[ERROR] Error writing test spec to file" + print e + + sys.exit() except KeyboardInterrupt, e: print "\n[CTRL+c] exit" diff --git a/tools/test_api.py b/tools/test_api.py index 737fc84c26..44a6b6aed6 100644 --- a/tools/test_api.py +++ b/tools/test_api.py @@ -2023,4 +2023,62 @@ def print_tests(tests, format="list"): print json.dumps(tests, indent=2) else: print "Unknown format '%s'" % format - sys.exit(1) \ No newline at end of file + sys.exit(1) + +def build_tests(tests, base_source_paths, build_path, target, toolchain_name, + options=None, clean=False, notify=None, verbose=False, jobs=1, + silent=False, report=None, properties=None): + """Given the data structure from 'find_tests' and the typical build parameters, + build all the tests and return a test build data structure""" + + test_build = { + "platform": target.name, + "toolchain": toolchain_name, + "base_path": build_path, + "baud_rate": 9600, + "binary_type": "bootable", + "tests": {} + } + + for test_name, test_path in tests.iteritems(): + src_path = base_source_paths + [test_path] + artifact_name = os.path.join(test_path, test_name) + bin_file = build_project(src_path, build_path, target, toolchain_name, + options=options, + jobs=jobs, + clean=clean, + name=artifact_name, + report=report, + properties=properties, + verbose=verbose) + + # If a clean build was carried out last time, disable it for the next build. + # Otherwise the previously built test will be deleted. + if clean: + clean = False + + # Normalize the path + bin_file = os.path.normpath(bin_file) + + test_build['tests'][test_name] = { + "binaries": [ + { + "path": bin_file + } + ] + } + + print 'Image: %s'% bin_file + + test_builds = {} + test_builds["%s-%s" % (target.name, toolchain_name)] = test_build + + + return test_builds + + +def test_spec_from_test_build(test_builds): + return { + "builds": test_builds + } + \ No newline at end of file diff --git a/tools/toolchains/__init__.py b/tools/toolchains/__init__.py index 4683b691a4..71cad7ec10 100644 --- a/tools/toolchains/__init__.py +++ b/tools/toolchains/__init__.py @@ -685,7 +685,12 @@ class mbedToolchain: if self.target.OUTPUT_NAMING == "8.3": name = name[0:8] ext = ext[0:3] - + + # Create destination directory + head, tail = split(name) + new_path = join(tmp_path, head) + mkdir(new_path) + filename = name+'.'+ext elf = join(tmp_path, name + '.elf') bin = join(tmp_path, filename)