Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 1 | # Copyright lowRISC contributors. |
| 2 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | r""" |
| 5 | Class describing lint configuration object |
| 6 | """ |
| 7 | |
Rupert Swarbrick | 6cc2011 | 2020-04-24 09:44:35 +0100 | [diff] [blame] | 8 | import hjson |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 9 | import logging as log |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 10 | from pathlib import Path |
| 11 | |
| 12 | from tabulate import tabulate |
| 13 | |
Udi Jonnalagadda | df49fb8 | 2020-03-17 11:05:17 -0700 | [diff] [blame] | 14 | from OneShotCfg import OneShotCfg |
Srikrishna Iyer | 559daed | 2020-12-04 18:22:18 -0800 | [diff] [blame] | 15 | from utils import VERBOSE, print_msg_list, subst_wildcards |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 16 | |
Michael Schaffner | 373f6d1 | 2020-07-10 14:46:34 -0700 | [diff] [blame] | 17 | |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 18 | class LintCfg(OneShotCfg): |
| 19 | """Derivative class for linting purposes. |
| 20 | """ |
Rupert Swarbrick | a23dfec | 2020-09-07 10:01:28 +0100 | [diff] [blame] | 21 | |
| 22 | flow = 'lint' |
| 23 | |
| 24 | def __init__(self, flow_cfg_file, hjson_data, args, mk_config): |
Michael Schaffner | 4204a8d | 2020-04-06 13:04:41 -0700 | [diff] [blame] | 25 | # This is a lint-specific attribute |
| 26 | self.is_style_lint = "" |
Rupert Swarbrick | a23dfec | 2020-09-07 10:01:28 +0100 | [diff] [blame] | 27 | super().__init__(flow_cfg_file, hjson_data, args, mk_config) |
Michael Schaffner | 4204a8d | 2020-04-06 13:04:41 -0700 | [diff] [blame] | 28 | |
| 29 | # Convert to boolean |
| 30 | if self.is_style_lint == "True": |
| 31 | self.is_style_lint = True |
| 32 | else: |
| 33 | self.is_style_lint = False |
| 34 | |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 35 | # Set the title for lint results. |
Michael Schaffner | 4204a8d | 2020-04-06 13:04:41 -0700 | [diff] [blame] | 36 | if self.is_style_lint: |
| 37 | self.results_title = self.name.upper() + " Style Lint Results" |
| 38 | else: |
| 39 | self.results_title = self.name.upper() + " Lint Results" |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 40 | |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 41 | def gen_results_summary(self): |
| 42 | ''' |
| 43 | Gathers the aggregated results from all sub configs |
| 44 | ''' |
| 45 | |
Michael Schaffner | b60aaa5 | 2020-03-31 18:38:46 -0700 | [diff] [blame] | 46 | # Generate results table for runs. |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 47 | log.info("Create summary of lint results") |
| 48 | |
| 49 | results_str = "## " + self.results_title + " (Summary)\n\n" |
Michael Schaffner | cb61dc4 | 2020-07-10 16:36:39 -0700 | [diff] [blame] | 50 | results_str += "### " + self.timestamp_long + "\n" |
Srikrishna Iyer | dddf93b | 2020-12-04 18:24:46 -0800 | [diff] [blame] | 51 | if self.revision: |
| 52 | results_str += "### " + self.revision + "\n" |
Srikrishna Iyer | 559daed | 2020-12-04 18:22:18 -0800 | [diff] [blame] | 53 | results_str += "### Branch: " + self.branch + "\n" |
Michael Schaffner | cb61dc4 | 2020-07-10 16:36:39 -0700 | [diff] [blame] | 54 | results_str += "\n" |
| 55 | |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 56 | header = [ |
Michael Schaffner | 6260739 | 2021-01-28 22:04:14 -0800 | [diff] [blame] | 57 | "Name", "Tool Warnings", "Tool Errors", "Lint Warnings", |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 58 | "Lint Errors" |
| 59 | ] |
| 60 | colalign = ("center", ) * len(header) |
| 61 | table = [header] |
| 62 | |
| 63 | for cfg in self.cfgs: |
| 64 | |
| 65 | results_page = cfg.results_server_dir + '/results.html' |
| 66 | results_page_url = results_page.replace( |
| 67 | cfg.results_server_prefix, cfg.results_server_url_prefix) |
| 68 | name_with_link = "[" + cfg.name.upper( |
| 69 | ) + "](" + results_page_url + ")" |
| 70 | table.append([ |
| 71 | name_with_link, |
| 72 | str(len(cfg.result_summary["warnings"])) + " W", |
| 73 | str(len(cfg.result_summary["errors"])) + " E", |
| 74 | str(len(cfg.result_summary["lint_warnings"])) + " W", |
| 75 | str(len(cfg.result_summary["lint_errors"])) + " E" |
| 76 | ]) |
| 77 | |
| 78 | if len(table) > 1: |
| 79 | self.results_summary_md = results_str + tabulate( |
| 80 | table, headers="firstrow", tablefmt="pipe", |
| 81 | colalign=colalign) + "\n" |
| 82 | else: |
| 83 | self.results_summary_md = results_str + "\nNo results to display.\n" |
| 84 | |
| 85 | print(self.results_summary_md) |
| 86 | |
| 87 | # Return only the tables |
| 88 | return self.results_summary_md |
| 89 | |
Rupert Swarbrick | a2892a5 | 2020-10-12 08:50:08 +0100 | [diff] [blame] | 90 | def _gen_results(self, results): |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 91 | # ''' |
| 92 | # The function is called after the regression has completed. It looks |
| 93 | # for a regr_results.hjson file with aggregated results from the lint run. |
| 94 | # The hjson needs to have the following (potentially empty) fields |
| 95 | # |
| 96 | # { |
| 97 | # tool: "" |
| 98 | # errors: [] |
| 99 | # warnings: [] |
| 100 | # lint_errors: [] |
| 101 | # lint_warning: [] |
| 102 | # lint_infos: [] |
| 103 | # } |
| 104 | # |
| 105 | # where each entry is a string representing a lint message. This allows |
| 106 | # to reuse the same LintCfg class with different tools since just the |
| 107 | # parsing script that transforms the tool output into the hjson above |
| 108 | # needs to be adapted. |
| 109 | # |
Scott Johnson | fe79c4b | 2020-07-08 10:31:08 -0700 | [diff] [blame] | 110 | # note that if this is a primary config, the results will |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 111 | # be generated using the _gen_results_summary function |
| 112 | # ''' |
| 113 | |
| 114 | # Generate results table for runs. |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 115 | results_str = "## " + self.results_title + "\n\n" |
| 116 | results_str += "### " + self.timestamp_long + "\n" |
Srikrishna Iyer | dddf93b | 2020-12-04 18:24:46 -0800 | [diff] [blame] | 117 | if self.revision: |
| 118 | results_str += "### " + self.revision + "\n" |
Srikrishna Iyer | 559daed | 2020-12-04 18:22:18 -0800 | [diff] [blame] | 119 | results_str += "### Branch: " + self.branch + "\n" |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 120 | results_str += "### Lint Tool: " + self.tool.upper() + "\n\n" |
| 121 | |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 122 | header = [ |
| 123 | "Build Mode", "Tool Warnings", "Tool Errors", "Lint Warnings", |
| 124 | "Lint Errors" |
| 125 | ] |
| 126 | colalign = ("center", ) * len(header) |
| 127 | table = [header] |
| 128 | |
| 129 | # aggregated counts |
| 130 | self.result_summary["warnings"] = [] |
| 131 | self.result_summary["errors"] = [] |
| 132 | self.result_summary["lint_warnings"] = [] |
| 133 | self.result_summary["lint_errors"] = [] |
| 134 | |
| 135 | fail_msgs = "" |
| 136 | for mode in self.build_modes: |
| 137 | |
| 138 | result_data = Path( |
| 139 | subst_wildcards(self.build_dir, {"build_mode": mode.name}) + |
| 140 | '/results.hjson') |
Srikrishna Iyer | 559daed | 2020-12-04 18:22:18 -0800 | [diff] [blame] | 141 | log.info("[results:hjson]: [%s]: [%s]", self.name, result_data) |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 142 | |
| 143 | try: |
Michael Schaffner | 065297d | 2020-07-14 21:05:55 -0700 | [diff] [blame] | 144 | with result_data.open() as results_file: |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 145 | self.result = hjson.load(results_file, use_decimal=True) |
| 146 | except IOError as err: |
| 147 | log.warning("%s", err) |
| 148 | self.result = { |
| 149 | "tool": "", |
| 150 | "errors": ["IOError: %s" % err], |
| 151 | "warnings": [], |
| 152 | "lint_errors": [], |
| 153 | "lint_warnings": [], |
| 154 | "lint_infos": [] |
| 155 | } |
| 156 | if self.result: |
| 157 | table.append([ |
| 158 | mode.name, |
| 159 | str(len(self.result["warnings"])) + " W ", |
| 160 | str(len(self.result["errors"])) + " E", |
| 161 | # We currently do not publish these infos at |
| 162 | # the moment len(self.result["lint_infos"]), |
| 163 | str(len(self.result["lint_warnings"])) + " W", |
| 164 | str(len(self.result["lint_errors"])) + " E" |
| 165 | ]) |
| 166 | else: |
| 167 | self.result = { |
| 168 | "tool": "", |
| 169 | "errors": [], |
| 170 | "warnings": [], |
| 171 | "lint_errors": [], |
| 172 | "lint_warnings": [], |
| 173 | "lint_infos": [] |
| 174 | } |
| 175 | |
| 176 | self.result_summary["warnings"] += self.result["warnings"] |
| 177 | self.result_summary["errors"] += self.result["errors"] |
| 178 | self.result_summary["lint_warnings"] += self.result[ |
| 179 | "lint_warnings"] |
| 180 | self.result_summary["lint_errors"] += self.result["lint_errors"] |
| 181 | |
| 182 | # Append detailed messages if they exist |
Michael Schaffner | 6260739 | 2021-01-28 22:04:14 -0800 | [diff] [blame] | 183 | hdr_key_pairs = [("Tool Warnings", "warnings"), |
| 184 | ("Tool Errors", "errors"), |
| 185 | ("Lint Warnings", "lint_warnings"), |
| 186 | ("Lint Errors", "lint_errors")] |
Michael Schaffner | 8fc927c | 2020-06-22 15:43:32 -0700 | [diff] [blame] | 187 | |
Michael Schaffner | 0409c2c | 2020-07-14 22:19:40 -0700 | [diff] [blame] | 188 | # Lint fails if any warning or error message has occurred |
| 189 | self.errors_seen = False |
Michael Schaffner | 6260739 | 2021-01-28 22:04:14 -0800 | [diff] [blame] | 190 | for _, key in hdr_key_pairs: |
Michael Schaffner | 8fc927c | 2020-06-22 15:43:32 -0700 | [diff] [blame] | 191 | if key in self.result: |
Michael Schaffner | 0409c2c | 2020-07-14 22:19:40 -0700 | [diff] [blame] | 192 | if self.result.get(key): |
Michael Schaffner | 6260739 | 2021-01-28 22:04:14 -0800 | [diff] [blame] | 193 | self.errors_seen = True |
Michael Schaffner | 0409c2c | 2020-07-14 22:19:40 -0700 | [diff] [blame] | 194 | break |
Michael Schaffner | 8fc927c | 2020-06-22 15:43:32 -0700 | [diff] [blame] | 195 | |
Michael Schaffner | 6260739 | 2021-01-28 22:04:14 -0800 | [diff] [blame] | 196 | if self.errors_seen: |
Michael Schaffner | 16102e5 | 2020-06-24 11:28:37 -0700 | [diff] [blame] | 197 | fail_msgs += "\n### Errors and Warnings for Build Mode `'" + mode.name + "'`\n" |
Michael Schaffner | 6260739 | 2021-01-28 22:04:14 -0800 | [diff] [blame] | 198 | for hdr, key in hdr_key_pairs: |
Michael Schaffner | 8fc927c | 2020-06-22 15:43:32 -0700 | [diff] [blame] | 199 | msgs = self.result.get(key) |
Michael Schaffner | 16102e5 | 2020-06-24 11:28:37 -0700 | [diff] [blame] | 200 | fail_msgs += print_msg_list("#### " + hdr, msgs, self.max_msg_count) |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 201 | |
| 202 | if len(table) > 1: |
| 203 | self.results_md = results_str + tabulate( |
| 204 | table, headers="firstrow", tablefmt="pipe", |
Michael Schaffner | 373f6d1 | 2020-07-10 14:46:34 -0700 | [diff] [blame] | 205 | colalign=colalign) + "\n" |
| 206 | |
| 207 | # the email and published reports will default to self.results_md if they are |
| 208 | # empty. in case they need to be sanitized, override them and do not append |
| 209 | # detailed messages. |
| 210 | if self.sanitize_email_results: |
| 211 | self.email_results_md = self.results_md |
| 212 | if self.sanitize_publish_results: |
| 213 | self.publish_results_md = self.results_md |
| 214 | # locally generated result always contains all details |
| 215 | self.results_md += fail_msgs |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 216 | else: |
| 217 | self.results_md = results_str + "\nNo results to display.\n" |
Michael Schaffner | 373f6d1 | 2020-07-10 14:46:34 -0700 | [diff] [blame] | 218 | self.email_results_md = self.results_md |
| 219 | self.publish_results_md = self.results_md |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 220 | |
Michael Schaffner | 8ac6c4c | 2020-03-03 15:00:20 -0800 | [diff] [blame] | 221 | return self.results_md |