blob: ef173bcb3f9ed5cb979262c04368063a2c63bc35 [file] [log] [blame]
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -08001# Lint as: python3
2# Copyright (C) 2019 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""Emit warning messages to html or csv files."""
17
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -070018# Many functions in this module have too many arguments to be refactored.
19# pylint:disable=too-many-arguments,missing-function-docstring
20
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -080021# To emit html page of warning messages:
22# flags: --byproject, --url, --separator
23# Old stuff for static html components:
24# html_script_style: static html scripts and styles
25# htmlbig:
26# dump_stats, dump_html_prologue, dump_html_epilogue:
27# emit_buttons:
28# dump_fixed
29# sort_warnings:
30# emit_stats_by_project:
31# all_patterns,
32# findproject, classify_warning
33# dump_html
34#
35# New dynamic HTML page's static JavaScript data:
36# Some data are copied from Python to JavaScript, to generate HTML elements.
37# FlagPlatform flags.platform
38# FlagURL flags.url, used by 'android'
39# FlagSeparator flags.separator, used by 'android'
40# SeverityColors: list of colors for all severity levels
41# SeverityHeaders: list of headers for all severity levels
42# SeverityColumnHeaders: list of column_headers for all severity levels
43# ProjectNames: project_names, or project_list[*][0]
44# WarnPatternsSeverity: warn_patterns[*]['severity']
45# WarnPatternsDescription: warn_patterns[*]['description']
46# WarningMessages: warning_messages
47# Warnings: warning_records
48# StatsHeader: warning count table header row
49# StatsRows: array of warning count table rows
50#
51# New dynamic HTML page's dynamic JavaScript data:
52#
53# New dynamic HTML related function to emit data:
54# escape_string, strip_escape_string, emit_warning_arrays
55# emit_js_data():
56
57from __future__ import print_function
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -080058import csv
Chih-Hung Hsieh7cc0e152021-04-26 17:09:36 -070059import html
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -080060import sys
61
62# pylint:disable=relative-beyond-top-level
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -080063from .severity import Severity
64
65
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -070066HTML_HEAD_SCRIPTS = """\
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -080067 <script type="text/javascript">
68 function expand(id) {
69 var e = document.getElementById(id);
70 var f = document.getElementById(id + "_mark");
71 if (e.style.display == 'block') {
72 e.style.display = 'none';
73 f.innerHTML = '&#x2295';
74 }
75 else {
76 e.style.display = 'block';
77 f.innerHTML = '&#x2296';
78 }
79 };
80 function expandCollapse(show) {
81 for (var id = 1; ; id++) {
82 var e = document.getElementById(id + "");
83 var f = document.getElementById(id + "_mark");
84 if (!e || !f) break;
85 e.style.display = (show ? 'block' : 'none');
86 f.innerHTML = (show ? '&#x2296' : '&#x2295');
87 }
88 };
89 </script>
90 <style type="text/css">
91 th,td{border-collapse:collapse; border:1px solid black;}
92 .button{color:blue;font-size:110%;font-weight:bolder;}
93 .bt{color:black;background-color:transparent;border:none;outline:none;
94 font-size:140%;font-weight:bolder;}
95 .c0{background-color:#e0e0e0;}
96 .c1{background-color:#d0d0d0;}
97 .t1{border-collapse:collapse; width:100%; border:1px solid black;}
98 </style>
99 <script src="https://www.gstatic.com/charts/loader.js"></script>
100"""
101
102
103def make_writer(output_stream):
104
105 def writer(text):
106 return output_stream.write(text + '\n')
107
108 return writer
109
110
111def html_big(param):
112 return '<font size="+2">' + param + '</font>'
113
114
115def dump_html_prologue(title, writer, warn_patterns, project_names):
116 writer('<html>\n<head>')
117 writer('<title>' + title + '</title>')
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -0700118 writer(HTML_HEAD_SCRIPTS)
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800119 emit_stats_by_project(writer, warn_patterns, project_names)
120 writer('</head>\n<body>')
121 writer(html_big(title))
122 writer('<p>')
123
124
125def dump_html_epilogue(writer):
126 writer('</body>\n</head>\n</html>')
127
128
129def sort_warnings(warn_patterns):
130 for i in warn_patterns:
131 i['members'] = sorted(set(i['members']))
132
133
134def create_warnings(warn_patterns, project_names):
135 """Creates warnings s.t.
136
137 warnings[p][s] is as specified in above docs.
138
139 Args:
140 warn_patterns: list of warning patterns for specified platform
141 project_names: list of project names
142
143 Returns:
144 2D warnings array where warnings[p][s] is # of warnings in project name p of
145 severity level s
146 """
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800147 warnings = {p: {s.value: 0 for s in Severity.levels} for p in project_names}
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700148 for pattern in warn_patterns:
149 value = pattern['severity'].value
150 for project in pattern['projects']:
151 warnings[project][value] += pattern['projects'][project]
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800152 return warnings
153
154
155def get_total_by_project(warnings, project_names):
156 """Returns dict, project as key and # warnings for that project as value."""
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800157 return {
158 p: sum(warnings[p][s.value] for s in Severity.levels)
159 for p in project_names
160 }
161
162
163def get_total_by_severity(warnings, project_names):
164 """Returns dict, severity as key and # warnings of that severity as value."""
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800165 return {
166 s.value: sum(warnings[p][s.value] for p in project_names)
167 for s in Severity.levels
168 }
169
170
171def emit_table_header(total_by_severity):
172 """Returns list of HTML-formatted content for severity stats."""
173
174 stats_header = ['Project']
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700175 for severity in Severity.levels:
176 if total_by_severity[severity.value]:
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800177 stats_header.append(
178 '<span style=\'background-color:{}\'>{}</span>'.format(
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700179 severity.color, severity.column_header))
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800180 stats_header.append('TOTAL')
181 return stats_header
182
183
184def emit_row_counts_per_project(warnings, total_by_project, total_by_severity,
185 project_names):
186 """Returns total project warnings and row of stats for each project.
187
188 Args:
189 warnings: output of create_warnings(warn_patterns, project_names)
190 total_by_project: output of get_total_by_project(project_names)
191 total_by_severity: output of get_total_by_severity(project_names)
192 project_names: list of project names
193
194 Returns:
195 total_all_projects, the total number of warnings over all projects
196 stats_rows, a 2d list where each row is [Project Name, <severity counts>,
197 total # warnings for this project]
198 """
199
200 total_all_projects = 0
201 stats_rows = []
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700202 for p_name in project_names:
203 if total_by_project[p_name]:
204 one_row = [p_name]
205 for severity in Severity.levels:
206 if total_by_severity[severity.value]:
207 one_row.append(warnings[p_name][severity.value])
208 one_row.append(total_by_project[p_name])
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800209 stats_rows.append(one_row)
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700210 total_all_projects += total_by_project[p_name]
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800211 return total_all_projects, stats_rows
212
213
214def emit_row_counts_per_severity(total_by_severity, stats_header, stats_rows,
215 total_all_projects, writer):
216 """Emits stats_header and stats_rows as specified above.
217
218 Args:
219 total_by_severity: output of get_total_by_severity()
220 stats_header: output of emit_table_header()
221 stats_rows: output of emit_row_counts_per_project()
222 total_all_projects: output of emit_row_counts_per_project()
223 writer: writer returned by make_writer(output_stream)
224 """
225
226 total_all_severities = 0
227 one_row = ['<b>TOTAL</b>']
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700228 for severity in Severity.levels:
229 if total_by_severity[severity.value]:
230 one_row.append(total_by_severity[severity.value])
231 total_all_severities += total_by_severity[severity.value]
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800232 one_row.append(total_all_projects)
233 stats_rows.append(one_row)
234 writer('<script>')
235 emit_const_string_array('StatsHeader', stats_header, writer)
236 emit_const_object_array('StatsRows', stats_rows, writer)
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -0700237 writer(DRAW_TABLE_JAVASCRIPT)
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800238 writer('</script>')
239
240
241def emit_stats_by_project(writer, warn_patterns, project_names):
242 """Dump a google chart table of warnings per project and severity."""
243
244 warnings = create_warnings(warn_patterns, project_names)
245 total_by_project = get_total_by_project(warnings, project_names)
246 total_by_severity = get_total_by_severity(warnings, project_names)
247 stats_header = emit_table_header(total_by_severity)
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -0700248 total_all_projects, stats_rows = emit_row_counts_per_project(
249 warnings, total_by_project, total_by_severity, project_names)
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800250 emit_row_counts_per_severity(total_by_severity, stats_header, stats_rows,
251 total_all_projects, writer)
252
253
254def dump_stats(writer, warn_patterns):
255 """Dump some stats about total number of warnings and such."""
256
257 known = 0
258 skipped = 0
259 unknown = 0
260 sort_warnings(warn_patterns)
261 for i in warn_patterns:
262 if i['severity'] == Severity.UNMATCHED:
263 unknown += len(i['members'])
264 elif i['severity'] == Severity.SKIP:
265 skipped += len(i['members'])
266 else:
267 known += len(i['members'])
268 writer('Number of classified warnings: <b>' + str(known) + '</b><br>')
269 writer('Number of skipped warnings: <b>' + str(skipped) + '</b><br>')
270 writer('Number of unclassified warnings: <b>' + str(unknown) + '</b><br>')
271 total = unknown + known + skipped
272 extra_msg = ''
273 if total < 1000:
274 extra_msg = ' (low count may indicate incremental build)'
275 writer('Total number of warnings: <b>' + str(total) + '</b>' + extra_msg)
276
277
278# New base table of warnings, [severity, warn_id, project, warning_message]
279# Need buttons to show warnings in different grouping options.
280# (1) Current, group by severity, id for each warning pattern
281# sort by severity, warn_id, warning_message
282# (2) Current --byproject, group by severity,
283# id for each warning pattern + project name
284# sort by severity, warn_id, project, warning_message
285# (3) New, group by project + severity,
286# id for each warning pattern
287# sort by project, severity, warn_id, warning_message
288def emit_buttons(writer):
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -0700289 """Write the button elements in HTML."""
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800290 writer('<button class="button" onclick="expandCollapse(1);">'
291 'Expand all warnings</button>\n'
292 '<button class="button" onclick="expandCollapse(0);">'
293 'Collapse all warnings</button>\n'
294 '<button class="button" onclick="groupBySeverity();">'
295 'Group warnings by severity</button>\n'
296 '<button class="button" onclick="groupByProject();">'
297 'Group warnings by project</button><br>')
298
299
300def all_patterns(category):
301 patterns = ''
302 for i in category['patterns']:
303 patterns += i
304 patterns += ' / '
305 return patterns
306
307
308def dump_fixed(writer, warn_patterns):
309 """Show which warnings no longer occur."""
310 anchor = 'fixed_warnings'
311 mark = anchor + '_mark'
312 writer('\n<br><p style="background-color:lightblue"><b>'
313 '<button id="' + mark + '" '
314 'class="bt" onclick="expand(\'' + anchor + '\');">'
315 '&#x2295</button> Fixed warnings. '
316 'No more occurrences. Please consider turning these into '
317 'errors if possible, before they are reintroduced in to the build'
318 ':</b></p>')
319 writer('<blockquote>')
320 fixed_patterns = []
321 for i in warn_patterns:
322 if not i['members']:
323 fixed_patterns.append(i['description'] + ' (' + all_patterns(i) + ')')
324 fixed_patterns = sorted(fixed_patterns)
325 writer('<div id="' + anchor + '" style="display:none;"><table>')
326 cur_row_class = 0
327 for text in fixed_patterns:
328 cur_row_class = 1 - cur_row_class
329 # remove last '\n'
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700330 out_text = text[:-1] if text[-1] == '\n' else text
Chih-Hung Hsieh5d9ee042021-06-01 16:03:22 -0700331 writer('<tr><td class="c' + str(cur_row_class) + '">'
332 + out_text + '</td></tr>')
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800333 writer('</table></div>')
334 writer('</blockquote>')
335
336
337def write_severity(csvwriter, sev, kind, warn_patterns):
338 """Count warnings of given severity and write CSV entries to writer."""
339 total = 0
340 for pattern in warn_patterns:
341 if pattern['severity'] == sev and pattern['members']:
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700342 num_members = len(pattern['members'])
343 total += num_members
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800344 warning = kind + ': ' + (pattern['description'] or '?')
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700345 csvwriter.writerow([num_members, '', warning])
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800346 # print number of warnings for each project, ordered by project name
347 projects = sorted(pattern['projects'].keys())
348 for project in projects:
349 csvwriter.writerow([pattern['projects'][project], project, warning])
350 csvwriter.writerow([total, '', kind + ' warnings'])
351 return total
352
353
354def dump_csv(csvwriter, warn_patterns):
355 """Dump number of warnings in CSV format to writer."""
356 sort_warnings(warn_patterns)
357 total = 0
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700358 for severity in Severity.levels:
Chih-Hung Hsieh5d9ee042021-06-01 16:03:22 -0700359 total += write_severity(
360 csvwriter, severity, severity.column_header, warn_patterns)
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800361 csvwriter.writerow([total, '', 'All warnings'])
362
363
Saeid Farivar Asanjan75dc8d22020-11-18 00:29:43 +0000364def dump_csv_with_description(csvwriter, warning_records, warning_messages,
365 warn_patterns, project_names):
366 """Outputs all the warning messages by project."""
367 csv_output = []
368 for record in warning_records:
369 project_name = project_names[record[1]]
370 pattern = warn_patterns[record[0]]
371 severity = pattern['severity'].header
372 category = pattern['category']
373 description = pattern['description']
374 warning = warning_messages[record[2]]
375 csv_output.append([project_name, severity,
376 category, description,
377 warning])
378 csv_output = sorted(csv_output)
379 for output in csv_output:
380 csvwriter.writerow(output)
381
382
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700383# Return line with escaped backslash and quotation characters.
384def escape_string(line):
385 return line.replace('\\', '\\\\').replace('"', '\\"')
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800386
387
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700388# Return line without trailing '\n' and escape the quotation characters.
389def strip_escape_string(line):
390 if not line:
391 return line
392 line = line[:-1] if line[-1] == '\n' else line
393 return escape_string(line)
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800394
395
396def emit_warning_array(name, writer, warn_patterns):
397 writer('var warning_{} = ['.format(name))
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700398 for pattern in warn_patterns:
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800399 if name == 'severity':
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700400 writer('{},'.format(pattern[name].value))
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800401 else:
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700402 writer('{},'.format(pattern[name]))
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800403 writer('];')
404
405
406def emit_warning_arrays(writer, warn_patterns):
407 emit_warning_array('severity', writer, warn_patterns)
408 writer('var warning_description = [')
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700409 for pattern in warn_patterns:
410 if pattern['members']:
411 writer('"{}",'.format(escape_string(pattern['description'])))
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800412 else:
413 writer('"",') # no such warning
414 writer('];')
415
416
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -0700417SCRIPTS_FOR_WARNING_GROUPS = """
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800418 function compareMessages(x1, x2) { // of the same warning type
419 return (WarningMessages[x1[2]] <= WarningMessages[x2[2]]) ? -1 : 1;
420 }
421 function byMessageCount(x1, x2) {
422 return x2[2] - x1[2]; // reversed order
423 }
424 function bySeverityMessageCount(x1, x2) {
425 // orer by severity first
426 if (x1[1] != x2[1])
427 return x1[1] - x2[1];
428 return byMessageCount(x1, x2);
429 }
430 const ParseLinePattern = /^([^ :]+):(\\d+):(.+)/;
431 function addURL(line) { // used by Android
432 if (FlagURL == "") return line;
433 if (FlagSeparator == "") {
434 return line.replace(ParseLinePattern,
435 "<a target='_blank' href='" + FlagURL + "/$1'>$1</a>:$2:$3");
436 }
437 return line.replace(ParseLinePattern,
438 "<a target='_blank' href='" + FlagURL + "/$1" + FlagSeparator +
439 "$2'>$1:$2</a>:$3");
440 }
441 function addURLToLine(line, link) { // used by Chrome
442 let line_split = line.split(":");
443 let path = line_split.slice(0,3).join(":");
444 let msg = line_split.slice(3).join(":");
445 let html_link = `<a target="_blank" href="${link}">${path}</a>${msg}`;
446 return html_link;
447 }
448 function createArrayOfDictionaries(n) {
449 var result = [];
450 for (var i=0; i<n; i++) result.push({});
451 return result;
452 }
453 function groupWarningsBySeverity() {
454 // groups is an array of dictionaries,
455 // each dictionary maps from warning type to array of warning messages.
456 var groups = createArrayOfDictionaries(SeverityColors.length);
457 for (var i=0; i<Warnings.length; i++) {
458 var w = Warnings[i][0];
459 var s = WarnPatternsSeverity[w];
460 var k = w.toString();
461 if (!(k in groups[s]))
462 groups[s][k] = [];
463 groups[s][k].push(Warnings[i]);
464 }
465 return groups;
466 }
467 function groupWarningsByProject() {
468 var groups = createArrayOfDictionaries(ProjectNames.length);
469 for (var i=0; i<Warnings.length; i++) {
470 var w = Warnings[i][0];
471 var p = Warnings[i][1];
472 var k = w.toString();
473 if (!(k in groups[p]))
474 groups[p][k] = [];
475 groups[p][k].push(Warnings[i]);
476 }
477 return groups;
478 }
479 var GlobalAnchor = 0;
480 function createWarningSection(header, color, group) {
481 var result = "";
482 var groupKeys = [];
483 var totalMessages = 0;
484 for (var k in group) {
485 totalMessages += group[k].length;
486 groupKeys.push([k, WarnPatternsSeverity[parseInt(k)], group[k].length]);
487 }
488 groupKeys.sort(bySeverityMessageCount);
489 for (var idx=0; idx<groupKeys.length; idx++) {
490 var k = groupKeys[idx][0];
491 var messages = group[k];
492 var w = parseInt(k);
493 var wcolor = SeverityColors[WarnPatternsSeverity[w]];
494 var description = WarnPatternsDescription[w];
495 if (description.length == 0)
496 description = "???";
497 GlobalAnchor += 1;
498 result += "<table class='t1'><tr bgcolor='" + wcolor + "'><td>" +
499 "<button class='bt' id='" + GlobalAnchor + "_mark" +
500 "' onclick='expand(\\"" + GlobalAnchor + "\\");'>" +
501 "&#x2295</button> " +
502 description + " (" + messages.length + ")</td></tr></table>";
503 result += "<div id='" + GlobalAnchor +
504 "' style='display:none;'><table class='t1'>";
505 var c = 0;
506 messages.sort(compareMessages);
507 if (FlagPlatform == "chrome") {
508 for (var i=0; i<messages.length; i++) {
509 result += "<tr><td class='c" + c + "'>" +
510 addURLToLine(WarningMessages[messages[i][2]], WarningLinks[messages[i][3]]) + "</td></tr>";
511 c = 1 - c;
512 }
513 } else {
514 for (var i=0; i<messages.length; i++) {
515 result += "<tr><td class='c" + c + "'>" +
516 addURL(WarningMessages[messages[i][2]]) + "</td></tr>";
517 c = 1 - c;
518 }
519 }
520 result += "</table></div>";
521 }
522 if (result.length > 0) {
523 return "<br><span style='background-color:" + color + "'><b>" +
524 header + ": " + totalMessages +
525 "</b></span><blockquote><table class='t1'>" +
526 result + "</table></blockquote>";
527
528 }
529 return ""; // empty section
530 }
531 function generateSectionsBySeverity() {
532 var result = "";
533 var groups = groupWarningsBySeverity();
534 for (s=0; s<SeverityColors.length; s++) {
535 result += createWarningSection(SeverityHeaders[s], SeverityColors[s],
536 groups[s]);
537 }
538 return result;
539 }
540 function generateSectionsByProject() {
541 var result = "";
542 var groups = groupWarningsByProject();
543 for (i=0; i<groups.length; i++) {
544 result += createWarningSection(ProjectNames[i], 'lightgrey', groups[i]);
545 }
546 return result;
547 }
548 function groupWarnings(generator) {
549 GlobalAnchor = 0;
550 var e = document.getElementById("warning_groups");
551 e.innerHTML = generator();
552 }
553 function groupBySeverity() {
554 groupWarnings(generateSectionsBySeverity);
555 }
556 function groupByProject() {
557 groupWarnings(generateSectionsByProject);
558 }
559"""
560
561
562# Emit a JavaScript const string
563def emit_const_string(name, value, writer):
564 writer('const ' + name + ' = "' + escape_string(value) + '";')
565
566
567# Emit a JavaScript const integer array.
568def emit_const_int_array(name, array, writer):
569 writer('const ' + name + ' = [')
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700570 for item in array:
571 writer(str(item) + ',')
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800572 writer('];')
573
574
575# Emit a JavaScript const string array.
576def emit_const_string_array(name, array, writer):
577 writer('const ' + name + ' = [')
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700578 for item in array:
579 writer('"' + strip_escape_string(item) + '",')
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800580 writer('];')
581
582
583# Emit a JavaScript const string array for HTML.
584def emit_const_html_string_array(name, array, writer):
585 writer('const ' + name + ' = [')
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700586 for item in array:
587 writer('"' + html.escape(strip_escape_string(item)) + '",')
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800588 writer('];')
589
590
591# Emit a JavaScript const object array.
592def emit_const_object_array(name, array, writer):
593 writer('const ' + name + ' = [')
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700594 for item in array:
595 writer(str(item) + ',')
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800596 writer('];')
597
598
599def emit_js_data(writer, flags, warning_messages, warning_links,
600 warning_records, warn_patterns, project_names):
601 """Dump dynamic HTML page's static JavaScript data."""
602 emit_const_string('FlagPlatform', flags.platform, writer)
603 emit_const_string('FlagURL', flags.url, writer)
604 emit_const_string('FlagSeparator', flags.separator, writer)
605 emit_const_string_array('SeverityColors', [s.color for s in Severity.levels],
606 writer)
607 emit_const_string_array('SeverityHeaders',
608 [s.header for s in Severity.levels], writer)
609 emit_const_string_array('SeverityColumnHeaders',
610 [s.column_header for s in Severity.levels], writer)
611 emit_const_string_array('ProjectNames', project_names, writer)
612 # pytype: disable=attribute-error
613 emit_const_int_array('WarnPatternsSeverity',
614 [w['severity'].value for w in warn_patterns], writer)
615 # pytype: enable=attribute-error
616 emit_const_html_string_array('WarnPatternsDescription',
617 [w['description'] for w in warn_patterns],
618 writer)
619 emit_const_html_string_array('WarningMessages', warning_messages, writer)
620 emit_const_object_array('Warnings', warning_records, writer)
621 if flags.platform == 'chrome':
622 emit_const_html_string_array('WarningLinks', warning_links, writer)
623
624
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -0700625DRAW_TABLE_JAVASCRIPT = """
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800626google.charts.load('current', {'packages':['table']});
627google.charts.setOnLoadCallback(drawTable);
628function drawTable() {
629 var data = new google.visualization.DataTable();
630 data.addColumn('string', StatsHeader[0]);
631 for (var i=1; i<StatsHeader.length; i++) {
632 data.addColumn('number', StatsHeader[i]);
633 }
634 data.addRows(StatsRows);
635 for (var i=0; i<StatsRows.length; i++) {
636 for (var j=0; j<StatsHeader.length; j++) {
637 data.setProperty(i, j, 'style', 'border:1px solid black;');
638 }
639 }
640 var table = new google.visualization.Table(
641 document.getElementById('stats_table'));
642 table.draw(data, {allowHtml: true, alternatingRowStyle: true});
643}
644"""
645
646
647def dump_html(flags, output_stream, warning_messages, warning_links,
648 warning_records, header_str, warn_patterns, project_names):
649 """Dump the flags output to output_stream."""
650 writer = make_writer(output_stream)
651 dump_html_prologue('Warnings for ' + header_str, writer, warn_patterns,
652 project_names)
653 dump_stats(writer, warn_patterns)
654 writer('<br><div id="stats_table"></div><br>')
655 writer('\n<script>')
656 emit_js_data(writer, flags, warning_messages, warning_links, warning_records,
657 warn_patterns, project_names)
Chih-Hung Hsieh98b285d2021-04-28 14:49:32 -0700658 writer(SCRIPTS_FOR_WARNING_GROUPS)
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800659 writer('</script>')
660 emit_buttons(writer)
661 # Warning messages are grouped by severities or project names.
662 writer('<br><div id="warning_groups"></div>')
663 if flags.byproject:
664 writer('<script>groupByProject();</script>')
665 else:
666 writer('<script>groupBySeverity();</script>')
667 dump_fixed(writer, warn_patterns)
668 dump_html_epilogue(writer)
669
670
671def write_html(flags, project_names, warn_patterns, html_path, warning_messages,
672 warning_links, warning_records, header_str):
673 """Write warnings html file."""
674 if html_path:
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700675 with open(html_path, 'w') as outf:
676 dump_html(flags, outf, warning_messages, warning_links, warning_records,
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800677 header_str, warn_patterns, project_names)
678
679
680def write_out_csv(flags, warn_patterns, warning_messages, warning_links,
681 warning_records, header_str, project_names):
682 """Write warnings csv file."""
683 if flags.csvpath:
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700684 with open(flags.csvpath, 'w') as outf:
685 dump_csv(csv.writer(outf, lineterminator='\n'), warn_patterns)
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800686
Saeid Farivar Asanjan75dc8d22020-11-18 00:29:43 +0000687 if flags.csvwithdescription:
Chih-Hung Hsieha6068222021-04-30 14:30:58 -0700688 with open(flags.csvwithdescription, 'w') as outf:
689 dump_csv_with_description(csv.writer(outf, lineterminator='\n'),
Saeid Farivar Asanjan75dc8d22020-11-18 00:29:43 +0000690 warning_records, warning_messages,
691 warn_patterns, project_names)
692
Chih-Hung Hsieh3cce2bc2020-02-27 15:39:18 -0800693 if flags.gencsv:
694 dump_csv(csv.writer(sys.stdout, lineterminator='\n'), warn_patterns)
695 else:
696 dump_html(flags, sys.stdout, warning_messages, warning_links,
697 warning_records, header_str, warn_patterns, project_names)