|  | #!/usr/bin/env python3 | 
|  | # Copyright lowRISC contributors. | 
|  | # Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  | r"""Helper class for parsing lint reports into a generic hjson format. | 
|  | """ | 
|  | import re | 
|  | import hjson | 
|  |  | 
|  | from pathlib import Path | 
|  | from typing import List, Dict, Tuple | 
|  |  | 
|  |  | 
|  | # TODO(#9079): this class will be refactored so that it can be integrated into | 
|  | # the Dvsim core code. | 
|  | class LintParser(): | 
|  |  | 
|  | def __init__(self) -> None: | 
|  | self.buckets = { | 
|  | 'flow_warning': [], | 
|  | 'flow_error': [], | 
|  | 'lint_info': [], | 
|  | 'lint_warning': [], | 
|  | 'lint_error': [], | 
|  | # this bucket is temporary and will be removed at the end of the | 
|  | # parsing pass. | 
|  | 'fusesoc-error': [] | 
|  | } | 
|  | self.severities = { | 
|  | 'flow_warning': 'warning', | 
|  | 'flow_error': 'error', | 
|  | 'lint_info': 'info', | 
|  | 'lint_warning': 'warning', | 
|  | 'lint_error': 'error', | 
|  | } | 
|  |  | 
|  | def extract_messages(self, log_content: str, patterns: List[str]) -> None: | 
|  | """ | 
|  | This extracts messages from the string buffer log_content. | 
|  | The argument patterns needs to be a list of tuples with | 
|  | (<error_severity>, <pattern_to_match_for>). | 
|  | """ | 
|  | for bucket, pattern in patterns: | 
|  | self.buckets[bucket] += \ | 
|  | re.findall(pattern, log_content, flags=re.MULTILINE) | 
|  |  | 
|  | def get_results(self, args: Dict[Path, List[Tuple]]) -> Dict[str, int]: | 
|  | """ | 
|  | Parse report and corresponding logfiles and extract error, warning | 
|  | and info messages for each IP present in the result folder | 
|  | """ | 
|  |  | 
|  | # Open all log files | 
|  | for path, patterns in args.items(): | 
|  | try: | 
|  | with path.open() as f: | 
|  | log_content = f.read() | 
|  | self.extract_messages(log_content, patterns) | 
|  | except IOError as err: | 
|  | self.buckets['flow_error'] += \ | 
|  | ["IOError: %s" % err] | 
|  |  | 
|  | # If there are no errors or warnings, add the "fusesoc-error" field to | 
|  | # "errors" (which will be reported as tooling errors). Remove the | 
|  | # "fusesoc-error" field either way. | 
|  | num_messages = { | 
|  | 'info': 0, | 
|  | 'warning': 0, | 
|  | 'error': 0 | 
|  | } | 
|  | for key, sev in self.severities.items(): | 
|  | num_messages[sev] += len(self.buckets[key]) | 
|  | if num_messages['error'] == 0 and num_messages['warning'] == 0: | 
|  | self.buckets['flow_error'] = self.buckets['fusesoc-error'] | 
|  | del self.buckets['fusesoc-error'] | 
|  |  | 
|  | return num_messages | 
|  |  | 
|  | def write_results_as_hjson(self, outpath: Path) -> None: | 
|  | with outpath.open("w") as results_file: | 
|  | # Construct results dict for Hjson file. | 
|  | hjson.dump(self.buckets, | 
|  | results_file, | 
|  | ensure_ascii=False, | 
|  | for_json=True, | 
|  | use_decimal=True) |