blob: cdbec62ee2441560fcb1639c40732223dbb90d40 [file] [log] [blame]
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -08001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4r"""
5Class describing lint configuration object
6"""
7
8import logging as log
9import sys
10from pathlib import Path
11
12from tabulate import tabulate
13
Udi Jonnalagaddadf49fb82020-03-17 11:05:17 -070014from Deploy import *
15from Modes import *
16from OneShotCfg import OneShotCfg
17from utils import *
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -080018
19
20# helper function for printing messages
21def _print_msg_list(msg_list_name, msg_list):
22 md_results = ""
23 if msg_list:
24 md_results += "### %s\n" % msg_list_name
25 md_results += "```\n"
26 for msg in msg_list:
27 msg_parts = msg.split()
28 md_results += msg + "\n\n"
29 md_results += "```\n"
30 return md_results
31
32
33class LintCfg(OneShotCfg):
34 """Derivative class for linting purposes.
35 """
36 def __init__(self, flow_cfg_file, proj_root, args):
37 super().__init__(flow_cfg_file, proj_root, args)
38
39 def __post_init__(self):
40 super().__post_init__()
41 # Set the title for lint results.
42 self.results_title = self.name.upper() + " Lint Results"
43
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -080044 @staticmethod
45 def create_instance(flow_cfg_file, proj_root, args):
46 '''Create a new instance of this class as with given parameters.
47 '''
48 return LintCfg(flow_cfg_file, proj_root, args)
49
50 def gen_results_summary(self):
51 '''
52 Gathers the aggregated results from all sub configs
53 '''
54
Michael Schaffnerb60aaa52020-03-31 18:38:46 -070055 # Generate results table for runs.
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -080056 log.info("Create summary of lint results")
57
58 results_str = "## " + self.results_title + " (Summary)\n\n"
59 results_str += "### " + self.timestamp_long + "\n\n"
60
61 header = [
62 "Name", "Tool Warnings", "Tool Errors", "Lint Warnings",
63 "Lint Errors"
64 ]
65 colalign = ("center", ) * len(header)
66 table = [header]
67
68 for cfg in self.cfgs:
69
70 results_page = cfg.results_server_dir + '/results.html'
71 results_page_url = results_page.replace(
72 cfg.results_server_prefix, cfg.results_server_url_prefix)
73 name_with_link = "[" + cfg.name.upper(
74 ) + "](" + results_page_url + ")"
75 table.append([
76 name_with_link,
77 str(len(cfg.result_summary["warnings"])) + " W",
78 str(len(cfg.result_summary["errors"])) + " E",
79 str(len(cfg.result_summary["lint_warnings"])) + " W",
80 str(len(cfg.result_summary["lint_errors"])) + " E"
81 ])
82
83 if len(table) > 1:
84 self.results_summary_md = results_str + tabulate(
85 table, headers="firstrow", tablefmt="pipe",
86 colalign=colalign) + "\n"
87 else:
88 self.results_summary_md = results_str + "\nNo results to display.\n"
89
90 print(self.results_summary_md)
91
92 # Return only the tables
93 return self.results_summary_md
94
95 def _gen_results(self):
96 # '''
97 # The function is called after the regression has completed. It looks
98 # for a regr_results.hjson file with aggregated results from the lint run.
99 # The hjson needs to have the following (potentially empty) fields
100 #
101 # {
102 # tool: ""
103 # errors: []
104 # warnings: []
105 # lint_errors: []
106 # lint_warning: []
107 # lint_infos: []
108 # }
109 #
110 # where each entry is a string representing a lint message. This allows
111 # to reuse the same LintCfg class with different tools since just the
112 # parsing script that transforms the tool output into the hjson above
113 # needs to be adapted.
114 #
115 # note that if this is a master config, the results will
116 # be generated using the _gen_results_summary function
117 # '''
118
119 # Generate results table for runs.
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800120 results_str = "## " + self.results_title + "\n\n"
121 results_str += "### " + self.timestamp_long + "\n"
122 results_str += "### Lint Tool: " + self.tool.upper() + "\n\n"
123
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800124 header = [
125 "Build Mode", "Tool Warnings", "Tool Errors", "Lint Warnings",
126 "Lint Errors"
127 ]
128 colalign = ("center", ) * len(header)
129 table = [header]
130
131 # aggregated counts
132 self.result_summary["warnings"] = []
133 self.result_summary["errors"] = []
134 self.result_summary["lint_warnings"] = []
135 self.result_summary["lint_errors"] = []
136
137 fail_msgs = ""
138 for mode in self.build_modes:
139
140 result_data = Path(
141 subst_wildcards(self.build_dir, {"build_mode": mode.name}) +
142 '/results.hjson')
143 log.info("looking for result data file at %s", result_data)
144
145 try:
146 with open(result_data, "r") as results_file:
147 self.result = hjson.load(results_file, use_decimal=True)
148 except IOError as err:
149 log.warning("%s", err)
150 self.result = {
151 "tool": "",
152 "errors": ["IOError: %s" % err],
153 "warnings": [],
154 "lint_errors": [],
155 "lint_warnings": [],
156 "lint_infos": []
157 }
158 if self.result:
159 table.append([
160 mode.name,
161 str(len(self.result["warnings"])) + " W ",
162 str(len(self.result["errors"])) + " E",
163 # We currently do not publish these infos at
164 # the moment len(self.result["lint_infos"]),
165 str(len(self.result["lint_warnings"])) + " W",
166 str(len(self.result["lint_errors"])) + " E"
167 ])
168 else:
169 self.result = {
170 "tool": "",
171 "errors": [],
172 "warnings": [],
173 "lint_errors": [],
174 "lint_warnings": [],
175 "lint_infos": []
176 }
177
178 self.result_summary["warnings"] += self.result["warnings"]
179 self.result_summary["errors"] += self.result["errors"]
180 self.result_summary["lint_warnings"] += self.result[
181 "lint_warnings"]
182 self.result_summary["lint_errors"] += self.result["lint_errors"]
183
184 # Append detailed messages if they exist
185 if sum([
186 len(self.result["warnings"]),
187 len(self.result["errors"]),
188 len(self.result["lint_warnings"]),
189 len(self.result["lint_errors"])
190 ]):
191 fail_msgs += "\n## Errors and Warnings for Build Mode `'" + mode.name + "'`\n"
192 fail_msgs += _print_msg_list("Tool Errors",
193 self.result["errors"])
194 fail_msgs += _print_msg_list("Tool Warnings",
195 self.result["warnings"])
196 fail_msgs += _print_msg_list("Lint Errors",
197 self.result["lint_errors"])
198 fail_msgs += _print_msg_list("Lint Warnings",
199 self.result["lint_warnings"])
200 #fail_msgs += _print_msg_list("Lint Infos", results["lint_infos"])
201
202 if len(table) > 1:
203 self.results_md = results_str + tabulate(
204 table, headers="firstrow", tablefmt="pipe",
205 colalign=colalign) + "\n" + fail_msgs
206 else:
207 self.results_md = results_str + "\nNo results to display.\n"
208
209 # Write results to the scratch area
210 self.results_file = self.scratch_path + "/results_" + self.timestamp + ".md"
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800211 with open(self.results_file, 'w') as f:
212 f.write(self.results_md)
213
Srikrishna Iyerfbaa01a2020-03-19 15:32:23 -0700214 log.info("[results page]: [%s] [%s]", self.name, results_file)
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800215 return self.results_md