From e0c7e5fd89335623b45f6c4fb0996f0bf8b6dcf7 Mon Sep 17 00:00:00 2001 From: Brian Daniels Date: Mon, 6 Jun 2016 18:18:15 +0100 Subject: [PATCH 1/4] Compiling tests stops on first failure by default, with option to continue --- tools/test.py | 6 +++++- tools/test_api.py | 9 +++++++-- tools/test_exporters.py | 16 ++++++++++------ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/tools/test.py b/tools/test.py index 1956cfec56..88a333e825 100644 --- a/tools/test.py +++ b/tools/test.py @@ -66,6 +66,9 @@ if __name__ == '__main__': 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", + default=None, help="Continue trying to build all tests if a build failure occurs") + parser.add_option("-n", "--names", dest="names", default=None, help="Limit the tests to a comma separated list of names") @@ -157,7 +160,8 @@ if __name__ == '__main__': properties=build_properties, macros=options.macros, verbose=options.verbose, - jobs=options.jobs) + jobs=options.jobs, + continue_on_build_fail=options.continue_on_build_fail) # If a path to a test spec is provided, write it to a file if options.test_spec: diff --git a/tools/test_api.py b/tools/test_api.py index d238cf8172..b1951b99c2 100644 --- a/tools/test_api.py +++ b/tools/test_api.py @@ -2027,7 +2027,8 @@ def print_tests(tests, format="list"): def build_tests(tests, base_source_paths, build_path, target, toolchain_name, options=None, clean=False, notify=None, verbose=False, jobs=1, - macros=None, silent=False, report=None, properties=None): + macros=None, silent=False, report=None, properties=None, + continue_on_build_fail=False): """Given the data structure from 'find_tests' and the typical build parameters, build all the tests @@ -2062,7 +2063,11 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name, except Exception, e: result = False - continue + + if continue_on_build_fail: + continue + else: + break # If a clean build was carried out last time, disable it for the next build. # Otherwise the previously built test will be deleted. diff --git a/tools/test_exporters.py b/tools/test_exporters.py index a65fd29fb1..857a6bfcd3 100644 --- a/tools/test_exporters.py +++ b/tools/test_exporters.py @@ -20,7 +20,6 @@ Author: Przemyslaw Wirkus from tools.utils import construct_enum, mkdir import os - ResultExporterType = construct_enum(HTML='Html_Exporter', JUNIT='JUnit_Exporter', JUNIT_OPER='JUnit_Exporter_Interoperability', @@ -73,7 +72,8 @@ class ReportExporter(): self.result_exporter_type = result_exporter_type self.package = package - def report(self, test_summary_ext, test_suite_properties=None): + def report(self, test_summary_ext, test_suite_properties=None, + print_log_for_failures=True): """ Invokes report depending on exporter_type set in constructor """ if self.result_exporter_type == ResultExporterType.HTML: @@ -87,7 +87,7 @@ class ReportExporter(): return self.exporter_junit_ioper(test_summary_ext, test_suite_properties) elif self.result_exporter_type == ResultExporterType.PRINT: # JUNIT exporter for interoperability test - return self.exporter_print(test_summary_ext) + return self.exporter_print(test_summary_ext, print_log_for_failures=print_log_for_failures) return None def report_to_file(self, test_summary_ext, file_name, test_suite_properties=None): @@ -297,11 +297,15 @@ class ReportExporter(): test_suites.append(ts) return TestSuite.to_xml_string(test_suites) - def exporter_print_helper(self, array): + def exporter_print_helper(self, array, print_log=False): for item in array: print " * %s::%s::%s" % (item["target_name"], item["toolchain_name"], item["id"]) + if print_log: + log_lines = item["output"].split("\n") + for log_line in log_lines: + print " %s" % log_line - def exporter_print(self, test_result_ext): + def exporter_print(self, test_result_ext, print_log_for_failures=False): """ Export test results in print format. """ failures = [] @@ -340,7 +344,7 @@ class ReportExporter(): if failures: print "\n\nBuild failures:" - self.exporter_print_helper(failures) + self.exporter_print_helper(failures, print_log=print_log_for_failures) return False else: return True From 68cb86f61fdcc32daf1f81e37c3d831b12022268 Mon Sep 17 00:00:00 2001 From: Brian Daniels Date: Mon, 6 Jun 2016 18:19:41 +0100 Subject: [PATCH 2/4] Adding entry to build report, even if no update was needed --- tools/build_api.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/tools/build_api.py b/tools/build_api.py index 354d4c05e5..a8c3f901d7 100644 --- a/tools/build_api.py +++ b/tools/build_api.py @@ -206,9 +206,9 @@ def build_project(src_path, build_path, target, toolchain_name, resources.objects.extend(objects) # Link Program - res, needed_update = toolchain.link_program(resources, build_path, name) + res, _ = toolchain.link_program(resources, build_path, name) - if report != None and needed_update: + if report != None: end = time() cur_result["elapsed_time"] = end - start cur_result["output"] = toolchain.get_output() @@ -233,8 +233,6 @@ def build_project(src_path, build_path, target, toolchain_name, if toolchain_output: cur_result["output"] += toolchain_output - cur_result["output"] += str(e) - add_result_to_report(report, cur_result) # Let Exception propagate @@ -359,11 +357,9 @@ def build_library(src_paths, build_path, target, toolchain_name, resources.objects.extend(objects) if archive: - needed_update = toolchain.build_library(resources.objects, build_path, name) - else: - needed_update = True + toolchain.build_library(objects, build_path, name) - if report != None and needed_update: + if report != None: end = time() cur_result["elapsed_time"] = end - start cur_result["output"] = toolchain.get_output() @@ -510,12 +506,12 @@ def build_mbed_libs(target, toolchain_name, options=None, verbose=False, clean=F for o in separate_objects: objects.remove(o) - needed_update = toolchain.build_library(objects, BUILD_TOOLCHAIN, "mbed") + toolchain.build_library(objects, BUILD_TOOLCHAIN, "mbed") for o in separate_objects: toolchain.copy_files(o, BUILD_TOOLCHAIN) - if report != None and needed_update: + if report != None: end = time() cur_result["elapsed_time"] = end - start cur_result["output"] = toolchain.get_output() From da4a16975200113899c47a8b60952bd1cd030e8e Mon Sep 17 00:00:00 2001 From: Brian Daniels Date: Mon, 6 Jun 2016 18:19:59 +0100 Subject: [PATCH 3/4] Fixing issue with non-verbose error message for GCC There was an issue when compiling with GCC_ARM, the tools would print the incorrect file where the error was present. This modifies the regular expression and matching logic used to find the error. This was tested with the 4.9 q2 release of GCC ARM. --- tools/toolchains/gcc.py | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/tools/toolchains/gcc.py b/tools/toolchains/gcc.py index 0a0b91f410..e1313ef474 100644 --- a/tools/toolchains/gcc.py +++ b/tools/toolchains/gcc.py @@ -28,7 +28,7 @@ class GCC(mbedToolchain): STD_LIB_NAME = "lib%s.a" CIRCULAR_DEPENDENCIES = True - DIAGNOSTIC_PATTERN = re.compile('((?P\d+):)(\d+:)? (?Pwarning|error): (?P.+)') + DIAGNOSTIC_PATTERN = re.compile('((?P[^:]+):(?P\d+):)(\d+:)? (?Pwarning|error): (?P.+)') def __init__(self, target, options=None, notify=None, macros=None, silent=False, tool_path="", extra_verbose=False): mbedToolchain.__init__(self, target, options, notify, macros, silent, extra_verbose=extra_verbose) @@ -138,27 +138,16 @@ class GCC(mbedToolchain): ) continue - # Each line should start with the file information: "filepath: ..." - # i should point past the file path ^ - # avoid the first column in Windows (C:\) - i = line.find(':', 2) - if i == -1: continue - - if state == WHERE: - file = line[:i] - message = line[i+1:].strip() + ' ' - state = WHAT - - elif state == WHAT: - match = GCC.DIAGNOSTIC_PATTERN.match(line[i+1:]) - if match is None: - state = WHERE - continue + match = GCC.DIAGNOSTIC_PATTERN.match(line) + if match is not None: self.cc_info( - match.group('severity'), - file, match.group('line'), - message + match.group('message') + match.group('severity').lower(), + match.group('file'), + match.group('line'), + match.group('message'), + target_name=self.target.name, + toolchain_name=self.name ) def get_dep_option(self, object): From 71fe5e86658de65510e7e5e2016ef98b8d286b0a Mon Sep 17 00:00:00 2001 From: Brian Daniels Date: Tue, 7 Jun 2016 13:24:25 +0100 Subject: [PATCH 4/4] Printing build summary at the end of build, as well as build log for failures --- tools/test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/test.py b/tools/test.py index 88a333e825..a9c7775f94 100644 --- a/tools/test.py +++ b/tools/test.py @@ -185,7 +185,10 @@ if __name__ == '__main__': report_exporter = ReportExporter(ResultExporterType.JUNIT, package="build") report_exporter.report_to_file(build_report, options.build_report_junit, test_suite_properties=build_properties) - if library_build_success and test_build_success: + print_report_exporter = ReportExporter(ResultExporterType.PRINT, package="build") + status = print_report_exporter.report(build_report) + + if status: sys.exit(0) else: sys.exit(1)