From 67e415fc6aea3f5f5328fdb89a2cf0446312d6ac Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 3 Oct 2024 19:00:48 +0200 Subject: [PATCH] Also write to a log file by default Write the log of outcome analysis to a log file by default. This is a cheap way of getting the outcome analysis log in an easy-to-access form on the CI: with our current CI scripts, they are now automatically available as an artifact called `analyze_outcomes.log`. Signed-off-by: Gilles Peskine --- scripts/mbedtls_framework/outcome_analysis.py | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/scripts/mbedtls_framework/outcome_analysis.py b/scripts/mbedtls_framework/outcome_analysis.py index 829b149b9..75310aa51 100644 --- a/scripts/mbedtls_framework/outcome_analysis.py +++ b/scripts/mbedtls_framework/outcome_analysis.py @@ -47,9 +47,20 @@ Outcomes = typing.Dict[str, ComponentOutcomes] class Results: """Process analysis results.""" - def __init__(self): + def __init__(self, + stderr: bool = True, + log_file: str = '') -> None: + """Log and count errors. + + Log to stderr if stderr is true. + Log to log_file if specified and non-empty. + """ self.error_count = 0 self.warning_count = 0 + self.stderr = stderr + self.log_file = None + if log_file: + self.log_file = open(log_file, 'w', encoding='utf-8') def new_section(self, fmt, *args, **kwargs): self._print_line('\n*** ' + fmt + ' ***\n', *args, **kwargs) @@ -65,9 +76,12 @@ class Results: self.warning_count += 1 self._print_line('Warning: ' + fmt, *args, **kwargs) - @staticmethod - def _print_line(fmt, *args, **kwargs): - sys.stderr.write((fmt + '\n').format(*args, **kwargs)) + def _print_line(self, fmt, *args, **kwargs): + line = (fmt + '\n').format(*args, **kwargs) + if self.stderr: + sys.stderr.write(line) + if self.log_file: + self.log_file.write(line) def execute_reference_driver_tests(results: Results, ref_component: str, driver_component: str, \ outcome_file: str) -> None: @@ -284,8 +298,6 @@ class DriverVSReference(Task): def main(known_tasks: typing.Dict[str, typing.Type[Task]]) -> None: - main_results = Results() - try: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('outcomes', metavar='OUTCOMES.CSV', @@ -297,6 +309,10 @@ def main(known_tasks: typing.Dict[str, typing.Type[Task]]) -> None: 'comma/space-separated list of tasks. ') parser.add_argument('--list', action='store_true', help='List all available tasks and exit.') + parser.add_argument('--log-file', + default='tests/analyze_outcomes.log', + help='Log file (default: tests/analyze_outcomes.log;' + ' empty means no log file)') parser.add_argument('--require-full-coverage', action='store_true', dest='full_coverage', help="Require all available " "test cases to be executed and issue an error " @@ -309,6 +325,8 @@ def main(known_tasks: typing.Dict[str, typing.Type[Task]]) -> None: print(task_name) sys.exit(0) + main_results = Results(log_file=options.log_file) + if options.specified_tasks == 'all': tasks_list = list(known_tasks.keys()) else: