xref: /aosp_15_r20/build/make/tools/warn/html_writer.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker# Lint as: python3
2*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2019 The Android Open Source Project
3*9e94795aSAndroid Build Coastguard Worker#
4*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*9e94795aSAndroid Build Coastguard Worker#
8*9e94795aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*9e94795aSAndroid Build Coastguard Worker#
10*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*9e94795aSAndroid Build Coastguard Worker# limitations under the License.
15*9e94795aSAndroid Build Coastguard Worker
16*9e94795aSAndroid Build Coastguard Worker"""Emit warning messages to html or csv files."""
17*9e94795aSAndroid Build Coastguard Worker
18*9e94795aSAndroid Build Coastguard Worker# Many functions in this module have too many arguments to be refactored.
19*9e94795aSAndroid Build Coastguard Worker# pylint:disable=too-many-arguments,missing-function-docstring
20*9e94795aSAndroid Build Coastguard Worker
21*9e94795aSAndroid Build Coastguard Worker# To emit html page of warning messages:
22*9e94795aSAndroid Build Coastguard Worker#   flags: --byproject, --url, --separator
23*9e94795aSAndroid Build Coastguard Worker# Old stuff for static html components:
24*9e94795aSAndroid Build Coastguard Worker#   html_script_style:  static html scripts and styles
25*9e94795aSAndroid Build Coastguard Worker#   htmlbig:
26*9e94795aSAndroid Build Coastguard Worker#   dump_stats, dump_html_prologue, dump_html_epilogue:
27*9e94795aSAndroid Build Coastguard Worker#   emit_buttons:
28*9e94795aSAndroid Build Coastguard Worker#   dump_fixed
29*9e94795aSAndroid Build Coastguard Worker#   sort_warnings:
30*9e94795aSAndroid Build Coastguard Worker#   emit_stats_by_project:
31*9e94795aSAndroid Build Coastguard Worker#   all_patterns,
32*9e94795aSAndroid Build Coastguard Worker#   findproject, classify_warning
33*9e94795aSAndroid Build Coastguard Worker#   dump_html
34*9e94795aSAndroid Build Coastguard Worker#
35*9e94795aSAndroid Build Coastguard Worker# New dynamic HTML page's static JavaScript data:
36*9e94795aSAndroid Build Coastguard Worker#   Some data are copied from Python to JavaScript, to generate HTML elements.
37*9e94795aSAndroid Build Coastguard Worker#   FlagPlatform           flags.platform
38*9e94795aSAndroid Build Coastguard Worker#   FlagURL                flags.url, used by 'android'
39*9e94795aSAndroid Build Coastguard Worker#   FlagSeparator          flags.separator, used by 'android'
40*9e94795aSAndroid Build Coastguard Worker#   SeverityColors:        list of colors for all severity levels
41*9e94795aSAndroid Build Coastguard Worker#   SeverityHeaders:       list of headers for all severity levels
42*9e94795aSAndroid Build Coastguard Worker#   SeverityColumnHeaders: list of column_headers for all severity levels
43*9e94795aSAndroid Build Coastguard Worker#   ProjectNames:          project_names, or project_list[*][0]
44*9e94795aSAndroid Build Coastguard Worker#   WarnPatternsSeverity:     warn_patterns[*]['severity']
45*9e94795aSAndroid Build Coastguard Worker#   WarnPatternsDescription:  warn_patterns[*]['description']
46*9e94795aSAndroid Build Coastguard Worker#   WarningMessages:          warning_messages
47*9e94795aSAndroid Build Coastguard Worker#   Warnings:                 warning_records
48*9e94795aSAndroid Build Coastguard Worker#   StatsHeader:           warning count table header row
49*9e94795aSAndroid Build Coastguard Worker#   StatsRows:             array of warning count table rows
50*9e94795aSAndroid Build Coastguard Worker#
51*9e94795aSAndroid Build Coastguard Worker# New dynamic HTML page's dynamic JavaScript data:
52*9e94795aSAndroid Build Coastguard Worker#
53*9e94795aSAndroid Build Coastguard Worker# New dynamic HTML related function to emit data:
54*9e94795aSAndroid Build Coastguard Worker#   escape_string, strip_escape_string, emit_warning_arrays
55*9e94795aSAndroid Build Coastguard Worker#   emit_js_data():
56*9e94795aSAndroid Build Coastguard Worker
57*9e94795aSAndroid Build Coastguard Workerfrom __future__ import print_function
58*9e94795aSAndroid Build Coastguard Workerimport csv
59*9e94795aSAndroid Build Coastguard Workerimport datetime
60*9e94795aSAndroid Build Coastguard Workerimport html
61*9e94795aSAndroid Build Coastguard Workerimport sys
62*9e94795aSAndroid Build Coastguard Worker
63*9e94795aSAndroid Build Coastguard Worker# pylint:disable=relative-beyond-top-level
64*9e94795aSAndroid Build Coastguard Workerfrom .severity import Severity
65*9e94795aSAndroid Build Coastguard Worker
66*9e94795aSAndroid Build Coastguard Worker
67*9e94795aSAndroid Build Coastguard Worker# Report files with this number of warnings or more.
68*9e94795aSAndroid Build Coastguard WorkerLIMIT_WARNINGS_PER_FILE = 100
69*9e94795aSAndroid Build Coastguard Worker# Report files/directories with this percentage of total warnings or more.
70*9e94795aSAndroid Build Coastguard WorkerLIMIT_PERCENT_WARNINGS = 1
71*9e94795aSAndroid Build Coastguard Worker
72*9e94795aSAndroid Build Coastguard WorkerHTML_HEAD_SCRIPTS = """\
73*9e94795aSAndroid Build Coastguard Worker  <script type="text/javascript">
74*9e94795aSAndroid Build Coastguard Worker  function expand(id) {
75*9e94795aSAndroid Build Coastguard Worker    var e = document.getElementById(id);
76*9e94795aSAndroid Build Coastguard Worker    var f = document.getElementById(id + "_mark");
77*9e94795aSAndroid Build Coastguard Worker    if (e.style.display == 'block') {
78*9e94795aSAndroid Build Coastguard Worker       e.style.display = 'none';
79*9e94795aSAndroid Build Coastguard Worker       f.innerHTML = '&#x2295';
80*9e94795aSAndroid Build Coastguard Worker    }
81*9e94795aSAndroid Build Coastguard Worker    else {
82*9e94795aSAndroid Build Coastguard Worker       e.style.display = 'block';
83*9e94795aSAndroid Build Coastguard Worker       f.innerHTML = '&#x2296';
84*9e94795aSAndroid Build Coastguard Worker    }
85*9e94795aSAndroid Build Coastguard Worker  };
86*9e94795aSAndroid Build Coastguard Worker  function expandCollapse(show) {
87*9e94795aSAndroid Build Coastguard Worker    for (var id = 1; ; id++) {
88*9e94795aSAndroid Build Coastguard Worker      var e = document.getElementById(id + "");
89*9e94795aSAndroid Build Coastguard Worker      var f = document.getElementById(id + "_mark");
90*9e94795aSAndroid Build Coastguard Worker      if (!e || !f) break;
91*9e94795aSAndroid Build Coastguard Worker      e.style.display = (show ? 'block' : 'none');
92*9e94795aSAndroid Build Coastguard Worker      f.innerHTML = (show ? '&#x2296' : '&#x2295');
93*9e94795aSAndroid Build Coastguard Worker    }
94*9e94795aSAndroid Build Coastguard Worker  };
95*9e94795aSAndroid Build Coastguard Worker  </script>
96*9e94795aSAndroid Build Coastguard Worker  <style type="text/css">
97*9e94795aSAndroid Build Coastguard Worker  th,td{border-collapse:collapse; border:1px solid black;}
98*9e94795aSAndroid Build Coastguard Worker  .button{color:blue;font-size:100%;font-weight:bolder;}
99*9e94795aSAndroid Build Coastguard Worker  .bt{color:black;background-color:transparent;border:none;outline:none;
100*9e94795aSAndroid Build Coastguard Worker      font-size:140%;font-weight:bolder;}
101*9e94795aSAndroid Build Coastguard Worker  .c0{background-color:#e0e0e0;}
102*9e94795aSAndroid Build Coastguard Worker  .c1{background-color:#d0d0d0;}
103*9e94795aSAndroid Build Coastguard Worker  .t1{border-collapse:collapse; width:100%; border:1px solid black;}
104*9e94795aSAndroid Build Coastguard Worker  .box{margin:5pt; padding:5pt; border:1px solid;}
105*9e94795aSAndroid Build Coastguard Worker  </style>
106*9e94795aSAndroid Build Coastguard Worker  <script src="https://www.gstatic.com/charts/loader.js"></script>
107*9e94795aSAndroid Build Coastguard Worker"""
108*9e94795aSAndroid Build Coastguard Worker
109*9e94795aSAndroid Build Coastguard Worker
110*9e94795aSAndroid Build Coastguard Workerdef make_writer(output_stream):
111*9e94795aSAndroid Build Coastguard Worker
112*9e94795aSAndroid Build Coastguard Worker  def writer(text):
113*9e94795aSAndroid Build Coastguard Worker    return output_stream.write(text + '\n')
114*9e94795aSAndroid Build Coastguard Worker
115*9e94795aSAndroid Build Coastguard Worker  return writer
116*9e94795aSAndroid Build Coastguard Worker
117*9e94795aSAndroid Build Coastguard Worker
118*9e94795aSAndroid Build Coastguard Workerdef html_big(param):
119*9e94795aSAndroid Build Coastguard Worker  return '<font size="+2">' + param + '</font>'
120*9e94795aSAndroid Build Coastguard Worker
121*9e94795aSAndroid Build Coastguard Worker
122*9e94795aSAndroid Build Coastguard Workerdef dump_html_prologue(title, writer, warn_patterns, project_names):
123*9e94795aSAndroid Build Coastguard Worker  writer('<html>\n<head>')
124*9e94795aSAndroid Build Coastguard Worker  writer('<title>' + title + '</title>')
125*9e94795aSAndroid Build Coastguard Worker  writer(HTML_HEAD_SCRIPTS)
126*9e94795aSAndroid Build Coastguard Worker  emit_stats_by_project(writer, warn_patterns, project_names)
127*9e94795aSAndroid Build Coastguard Worker  writer('</head>\n<body>')
128*9e94795aSAndroid Build Coastguard Worker  writer(html_big(title))
129*9e94795aSAndroid Build Coastguard Worker  writer('<p>')
130*9e94795aSAndroid Build Coastguard Worker
131*9e94795aSAndroid Build Coastguard Worker
132*9e94795aSAndroid Build Coastguard Workerdef dump_html_epilogue(writer):
133*9e94795aSAndroid Build Coastguard Worker  writer('</body>\n</head>\n</html>')
134*9e94795aSAndroid Build Coastguard Worker
135*9e94795aSAndroid Build Coastguard Worker
136*9e94795aSAndroid Build Coastguard Workerdef sort_warnings(warn_patterns):
137*9e94795aSAndroid Build Coastguard Worker  for i in warn_patterns:
138*9e94795aSAndroid Build Coastguard Worker    i['members'] = sorted(set(i['members']))
139*9e94795aSAndroid Build Coastguard Worker
140*9e94795aSAndroid Build Coastguard Worker
141*9e94795aSAndroid Build Coastguard Workerdef create_warnings(warn_patterns, project_names):
142*9e94795aSAndroid Build Coastguard Worker  """Creates warnings s.t.
143*9e94795aSAndroid Build Coastguard Worker
144*9e94795aSAndroid Build Coastguard Worker  warnings[p][s] is as specified in above docs.
145*9e94795aSAndroid Build Coastguard Worker
146*9e94795aSAndroid Build Coastguard Worker  Args:
147*9e94795aSAndroid Build Coastguard Worker    warn_patterns: list of warning patterns for specified platform
148*9e94795aSAndroid Build Coastguard Worker    project_names: list of project names
149*9e94795aSAndroid Build Coastguard Worker
150*9e94795aSAndroid Build Coastguard Worker  Returns:
151*9e94795aSAndroid Build Coastguard Worker    2D warnings array where warnings[p][s] is # of warnings in project name p of
152*9e94795aSAndroid Build Coastguard Worker    severity level s
153*9e94795aSAndroid Build Coastguard Worker  """
154*9e94795aSAndroid Build Coastguard Worker  warnings = {p: {s.value: 0 for s in Severity.levels} for p in project_names}
155*9e94795aSAndroid Build Coastguard Worker  for pattern in warn_patterns:
156*9e94795aSAndroid Build Coastguard Worker    value = pattern['severity'].value
157*9e94795aSAndroid Build Coastguard Worker    for project in pattern['projects']:
158*9e94795aSAndroid Build Coastguard Worker      warnings[project][value] += pattern['projects'][project]
159*9e94795aSAndroid Build Coastguard Worker  return warnings
160*9e94795aSAndroid Build Coastguard Worker
161*9e94795aSAndroid Build Coastguard Worker
162*9e94795aSAndroid Build Coastguard Workerdef get_total_by_project(warnings, project_names):
163*9e94795aSAndroid Build Coastguard Worker  """Returns dict, project as key and # warnings for that project as value."""
164*9e94795aSAndroid Build Coastguard Worker  return {
165*9e94795aSAndroid Build Coastguard Worker      p: sum(warnings[p][s.value] for s in Severity.levels)
166*9e94795aSAndroid Build Coastguard Worker      for p in project_names
167*9e94795aSAndroid Build Coastguard Worker  }
168*9e94795aSAndroid Build Coastguard Worker
169*9e94795aSAndroid Build Coastguard Worker
170*9e94795aSAndroid Build Coastguard Workerdef get_total_by_severity(warnings, project_names):
171*9e94795aSAndroid Build Coastguard Worker  """Returns dict, severity as key and # warnings of that severity as value."""
172*9e94795aSAndroid Build Coastguard Worker  return {
173*9e94795aSAndroid Build Coastguard Worker      s.value: sum(warnings[p][s.value] for p in project_names)
174*9e94795aSAndroid Build Coastguard Worker      for s in Severity.levels
175*9e94795aSAndroid Build Coastguard Worker  }
176*9e94795aSAndroid Build Coastguard Worker
177*9e94795aSAndroid Build Coastguard Worker
178*9e94795aSAndroid Build Coastguard Workerdef emit_table_header(total_by_severity):
179*9e94795aSAndroid Build Coastguard Worker  """Returns list of HTML-formatted content for severity stats."""
180*9e94795aSAndroid Build Coastguard Worker
181*9e94795aSAndroid Build Coastguard Worker  stats_header = ['Project']
182*9e94795aSAndroid Build Coastguard Worker  for severity in Severity.levels:
183*9e94795aSAndroid Build Coastguard Worker    if total_by_severity[severity.value]:
184*9e94795aSAndroid Build Coastguard Worker      stats_header.append(
185*9e94795aSAndroid Build Coastguard Worker          '<span style=\'background-color:{}\'>{}</span>'.format(
186*9e94795aSAndroid Build Coastguard Worker              severity.color, severity.column_header))
187*9e94795aSAndroid Build Coastguard Worker  stats_header.append('TOTAL')
188*9e94795aSAndroid Build Coastguard Worker  return stats_header
189*9e94795aSAndroid Build Coastguard Worker
190*9e94795aSAndroid Build Coastguard Worker
191*9e94795aSAndroid Build Coastguard Workerdef emit_row_counts_per_project(warnings, total_by_project, total_by_severity,
192*9e94795aSAndroid Build Coastguard Worker                                project_names):
193*9e94795aSAndroid Build Coastguard Worker  """Returns total project warnings and row of stats for each project.
194*9e94795aSAndroid Build Coastguard Worker
195*9e94795aSAndroid Build Coastguard Worker  Args:
196*9e94795aSAndroid Build Coastguard Worker    warnings: output of create_warnings(warn_patterns, project_names)
197*9e94795aSAndroid Build Coastguard Worker    total_by_project: output of get_total_by_project(project_names)
198*9e94795aSAndroid Build Coastguard Worker    total_by_severity: output of get_total_by_severity(project_names)
199*9e94795aSAndroid Build Coastguard Worker    project_names: list of project names
200*9e94795aSAndroid Build Coastguard Worker
201*9e94795aSAndroid Build Coastguard Worker  Returns:
202*9e94795aSAndroid Build Coastguard Worker    total_all_projects, the total number of warnings over all projects
203*9e94795aSAndroid Build Coastguard Worker    stats_rows, a 2d list where each row is [Project Name, <severity counts>,
204*9e94795aSAndroid Build Coastguard Worker    total # warnings for this project]
205*9e94795aSAndroid Build Coastguard Worker  """
206*9e94795aSAndroid Build Coastguard Worker
207*9e94795aSAndroid Build Coastguard Worker  total_all_projects = 0
208*9e94795aSAndroid Build Coastguard Worker  stats_rows = []
209*9e94795aSAndroid Build Coastguard Worker  for p_name in project_names:
210*9e94795aSAndroid Build Coastguard Worker    if total_by_project[p_name]:
211*9e94795aSAndroid Build Coastguard Worker      one_row = [p_name]
212*9e94795aSAndroid Build Coastguard Worker      for severity in Severity.levels:
213*9e94795aSAndroid Build Coastguard Worker        if total_by_severity[severity.value]:
214*9e94795aSAndroid Build Coastguard Worker          one_row.append(warnings[p_name][severity.value])
215*9e94795aSAndroid Build Coastguard Worker      one_row.append(total_by_project[p_name])
216*9e94795aSAndroid Build Coastguard Worker      stats_rows.append(one_row)
217*9e94795aSAndroid Build Coastguard Worker      total_all_projects += total_by_project[p_name]
218*9e94795aSAndroid Build Coastguard Worker  return total_all_projects, stats_rows
219*9e94795aSAndroid Build Coastguard Worker
220*9e94795aSAndroid Build Coastguard Worker
221*9e94795aSAndroid Build Coastguard Workerdef emit_row_counts_per_severity(total_by_severity, stats_header, stats_rows,
222*9e94795aSAndroid Build Coastguard Worker                                 total_all_projects, writer):
223*9e94795aSAndroid Build Coastguard Worker  """Emits stats_header and stats_rows as specified above.
224*9e94795aSAndroid Build Coastguard Worker
225*9e94795aSAndroid Build Coastguard Worker  Args:
226*9e94795aSAndroid Build Coastguard Worker    total_by_severity: output of get_total_by_severity()
227*9e94795aSAndroid Build Coastguard Worker    stats_header: output of emit_table_header()
228*9e94795aSAndroid Build Coastguard Worker    stats_rows: output of emit_row_counts_per_project()
229*9e94795aSAndroid Build Coastguard Worker    total_all_projects: output of emit_row_counts_per_project()
230*9e94795aSAndroid Build Coastguard Worker    writer: writer returned by make_writer(output_stream)
231*9e94795aSAndroid Build Coastguard Worker  """
232*9e94795aSAndroid Build Coastguard Worker
233*9e94795aSAndroid Build Coastguard Worker  total_all_severities = 0
234*9e94795aSAndroid Build Coastguard Worker  one_row = ['<b>TOTAL</b>']
235*9e94795aSAndroid Build Coastguard Worker  for severity in Severity.levels:
236*9e94795aSAndroid Build Coastguard Worker    if total_by_severity[severity.value]:
237*9e94795aSAndroid Build Coastguard Worker      one_row.append(total_by_severity[severity.value])
238*9e94795aSAndroid Build Coastguard Worker      total_all_severities += total_by_severity[severity.value]
239*9e94795aSAndroid Build Coastguard Worker  one_row.append(total_all_projects)
240*9e94795aSAndroid Build Coastguard Worker  stats_rows.append(one_row)
241*9e94795aSAndroid Build Coastguard Worker  writer('<script>')
242*9e94795aSAndroid Build Coastguard Worker  emit_const_string_array('StatsHeader', stats_header, writer)
243*9e94795aSAndroid Build Coastguard Worker  emit_const_object_array('StatsRows', stats_rows, writer)
244*9e94795aSAndroid Build Coastguard Worker  writer(DRAW_TABLE_JAVASCRIPT)
245*9e94795aSAndroid Build Coastguard Worker  writer('</script>')
246*9e94795aSAndroid Build Coastguard Worker
247*9e94795aSAndroid Build Coastguard Worker
248*9e94795aSAndroid Build Coastguard Workerdef emit_stats_by_project(writer, warn_patterns, project_names):
249*9e94795aSAndroid Build Coastguard Worker  """Dump a google chart table of warnings per project and severity."""
250*9e94795aSAndroid Build Coastguard Worker
251*9e94795aSAndroid Build Coastguard Worker  warnings = create_warnings(warn_patterns, project_names)
252*9e94795aSAndroid Build Coastguard Worker  total_by_project = get_total_by_project(warnings, project_names)
253*9e94795aSAndroid Build Coastguard Worker  total_by_severity = get_total_by_severity(warnings, project_names)
254*9e94795aSAndroid Build Coastguard Worker  stats_header = emit_table_header(total_by_severity)
255*9e94795aSAndroid Build Coastguard Worker  total_all_projects, stats_rows = emit_row_counts_per_project(
256*9e94795aSAndroid Build Coastguard Worker      warnings, total_by_project, total_by_severity, project_names)
257*9e94795aSAndroid Build Coastguard Worker  emit_row_counts_per_severity(total_by_severity, stats_header, stats_rows,
258*9e94795aSAndroid Build Coastguard Worker                               total_all_projects, writer)
259*9e94795aSAndroid Build Coastguard Worker
260*9e94795aSAndroid Build Coastguard Worker
261*9e94795aSAndroid Build Coastguard Workerdef dump_stats(writer, warn_patterns):
262*9e94795aSAndroid Build Coastguard Worker  """Dump some stats about total number of warnings and date."""
263*9e94795aSAndroid Build Coastguard Worker
264*9e94795aSAndroid Build Coastguard Worker  known = 0
265*9e94795aSAndroid Build Coastguard Worker  skipped = 0
266*9e94795aSAndroid Build Coastguard Worker  unknown = 0
267*9e94795aSAndroid Build Coastguard Worker  sort_warnings(warn_patterns)
268*9e94795aSAndroid Build Coastguard Worker  for i in warn_patterns:
269*9e94795aSAndroid Build Coastguard Worker    if i['severity'] == Severity.UNMATCHED:
270*9e94795aSAndroid Build Coastguard Worker      unknown += len(i['members'])
271*9e94795aSAndroid Build Coastguard Worker    elif i['severity'] == Severity.SKIP:
272*9e94795aSAndroid Build Coastguard Worker      skipped += len(i['members'])
273*9e94795aSAndroid Build Coastguard Worker    else:
274*9e94795aSAndroid Build Coastguard Worker      known += len(i['members'])
275*9e94795aSAndroid Build Coastguard Worker  writer('Number of classified warnings: <b>' + str(known) + '</b><br>')
276*9e94795aSAndroid Build Coastguard Worker  writer('Number of skipped warnings: <b>' + str(skipped) + '</b><br>')
277*9e94795aSAndroid Build Coastguard Worker  writer('Number of unclassified warnings: <b>' + str(unknown) + '</b><br>')
278*9e94795aSAndroid Build Coastguard Worker  total = unknown + known + skipped
279*9e94795aSAndroid Build Coastguard Worker  extra_msg = ''
280*9e94795aSAndroid Build Coastguard Worker  if total < 1000:
281*9e94795aSAndroid Build Coastguard Worker    extra_msg = ' (low count may indicate incremental build)'
282*9e94795aSAndroid Build Coastguard Worker  writer('Total number of warnings: <b>' + str(total) + '</b>' + extra_msg)
283*9e94795aSAndroid Build Coastguard Worker  date_time_str = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
284*9e94795aSAndroid Build Coastguard Worker  writer('<p>(generated on ' + date_time_str + ')')
285*9e94795aSAndroid Build Coastguard Worker
286*9e94795aSAndroid Build Coastguard Worker
287*9e94795aSAndroid Build Coastguard Worker# New base table of warnings, [severity, warn_id, project, warning_message]
288*9e94795aSAndroid Build Coastguard Worker# Need buttons to show warnings in different grouping options.
289*9e94795aSAndroid Build Coastguard Worker# (1) Current, group by severity, id for each warning pattern
290*9e94795aSAndroid Build Coastguard Worker#     sort by severity, warn_id, warning_message
291*9e94795aSAndroid Build Coastguard Worker# (2) Current --byproject, group by severity,
292*9e94795aSAndroid Build Coastguard Worker#     id for each warning pattern + project name
293*9e94795aSAndroid Build Coastguard Worker#     sort by severity, warn_id, project, warning_message
294*9e94795aSAndroid Build Coastguard Worker# (3) New, group by project + severity,
295*9e94795aSAndroid Build Coastguard Worker#     id for each warning pattern
296*9e94795aSAndroid Build Coastguard Worker#     sort by project, severity, warn_id, warning_message
297*9e94795aSAndroid Build Coastguard Workerdef emit_buttons(writer):
298*9e94795aSAndroid Build Coastguard Worker  """Write the button elements in HTML."""
299*9e94795aSAndroid Build Coastguard Worker  writer('<p><button class="button" onclick="expandCollapse(1);">'
300*9e94795aSAndroid Build Coastguard Worker         'Expand all warnings</button>\n'
301*9e94795aSAndroid Build Coastguard Worker         '<button class="button" onclick="expandCollapse(0);">'
302*9e94795aSAndroid Build Coastguard Worker         'Collapse all warnings</button>\n'
303*9e94795aSAndroid Build Coastguard Worker         '<p><button class="button" onclick="groupBySeverity();">'
304*9e94795aSAndroid Build Coastguard Worker         'Group warnings by severity</button>\n'
305*9e94795aSAndroid Build Coastguard Worker         '<button class="button" onclick="groupByProject();">'
306*9e94795aSAndroid Build Coastguard Worker         'Group warnings by project</button>')
307*9e94795aSAndroid Build Coastguard Worker
308*9e94795aSAndroid Build Coastguard Worker
309*9e94795aSAndroid Build Coastguard Workerdef all_patterns(category):
310*9e94795aSAndroid Build Coastguard Worker  patterns = ''
311*9e94795aSAndroid Build Coastguard Worker  for i in category['patterns']:
312*9e94795aSAndroid Build Coastguard Worker    patterns += i
313*9e94795aSAndroid Build Coastguard Worker    patterns += ' / '
314*9e94795aSAndroid Build Coastguard Worker  return patterns
315*9e94795aSAndroid Build Coastguard Worker
316*9e94795aSAndroid Build Coastguard Worker
317*9e94795aSAndroid Build Coastguard Workerdef dump_fixed(writer, warn_patterns):
318*9e94795aSAndroid Build Coastguard Worker  """Show which warnings no longer occur."""
319*9e94795aSAndroid Build Coastguard Worker  anchor = 'fixed_warnings'
320*9e94795aSAndroid Build Coastguard Worker  mark = anchor + '_mark'
321*9e94795aSAndroid Build Coastguard Worker  writer('\n<br><p style="background-color:lightblue"><b>'
322*9e94795aSAndroid Build Coastguard Worker         '<button id="' + mark + '" '
323*9e94795aSAndroid Build Coastguard Worker         'class="bt" onclick="expand(\'' + anchor + '\');">'
324*9e94795aSAndroid Build Coastguard Worker         '&#x2295</button> Fixed warnings. '
325*9e94795aSAndroid Build Coastguard Worker         'No more occurrences. Please consider turning these into '
326*9e94795aSAndroid Build Coastguard Worker         'errors if possible, before they are reintroduced in to the build'
327*9e94795aSAndroid Build Coastguard Worker         ':</b></p>')
328*9e94795aSAndroid Build Coastguard Worker  writer('<blockquote>')
329*9e94795aSAndroid Build Coastguard Worker  fixed_patterns = []
330*9e94795aSAndroid Build Coastguard Worker  for i in warn_patterns:
331*9e94795aSAndroid Build Coastguard Worker    if not i['members']:
332*9e94795aSAndroid Build Coastguard Worker      fixed_patterns.append(i['description'] + ' (' + all_patterns(i) + ')')
333*9e94795aSAndroid Build Coastguard Worker  fixed_patterns = sorted(fixed_patterns)
334*9e94795aSAndroid Build Coastguard Worker  writer('<div id="' + anchor + '" style="display:none;"><table>')
335*9e94795aSAndroid Build Coastguard Worker  cur_row_class = 0
336*9e94795aSAndroid Build Coastguard Worker  for text in fixed_patterns:
337*9e94795aSAndroid Build Coastguard Worker    cur_row_class = 1 - cur_row_class
338*9e94795aSAndroid Build Coastguard Worker    # remove last '\n'
339*9e94795aSAndroid Build Coastguard Worker    out_text = text[:-1] if text[-1] == '\n' else text
340*9e94795aSAndroid Build Coastguard Worker    writer('<tr><td class="c' + str(cur_row_class) + '">'
341*9e94795aSAndroid Build Coastguard Worker           + out_text + '</td></tr>')
342*9e94795aSAndroid Build Coastguard Worker  writer('</table></div>')
343*9e94795aSAndroid Build Coastguard Worker  writer('</blockquote>')
344*9e94795aSAndroid Build Coastguard Worker
345*9e94795aSAndroid Build Coastguard Worker
346*9e94795aSAndroid Build Coastguard Workerdef write_severity(csvwriter, sev, kind, warn_patterns):
347*9e94795aSAndroid Build Coastguard Worker  """Count warnings of given severity and write CSV entries to writer."""
348*9e94795aSAndroid Build Coastguard Worker  total = 0
349*9e94795aSAndroid Build Coastguard Worker  for pattern in warn_patterns:
350*9e94795aSAndroid Build Coastguard Worker    if pattern['severity'] == sev and pattern['members']:
351*9e94795aSAndroid Build Coastguard Worker      num_members = len(pattern['members'])
352*9e94795aSAndroid Build Coastguard Worker      total += num_members
353*9e94795aSAndroid Build Coastguard Worker      warning = kind + ': ' + (pattern['description'] or '?')
354*9e94795aSAndroid Build Coastguard Worker      csvwriter.writerow([num_members, '', warning])
355*9e94795aSAndroid Build Coastguard Worker      # print number of warnings for each project, ordered by project name
356*9e94795aSAndroid Build Coastguard Worker      projects = sorted(pattern['projects'].keys())
357*9e94795aSAndroid Build Coastguard Worker      for project in projects:
358*9e94795aSAndroid Build Coastguard Worker        csvwriter.writerow([pattern['projects'][project], project, warning])
359*9e94795aSAndroid Build Coastguard Worker  csvwriter.writerow([total, '', kind + ' warnings'])
360*9e94795aSAndroid Build Coastguard Worker  return total
361*9e94795aSAndroid Build Coastguard Worker
362*9e94795aSAndroid Build Coastguard Worker
363*9e94795aSAndroid Build Coastguard Workerdef dump_csv(csvwriter, warn_patterns):
364*9e94795aSAndroid Build Coastguard Worker  """Dump number of warnings in CSV format to writer."""
365*9e94795aSAndroid Build Coastguard Worker  sort_warnings(warn_patterns)
366*9e94795aSAndroid Build Coastguard Worker  total = 0
367*9e94795aSAndroid Build Coastguard Worker  for severity in Severity.levels:
368*9e94795aSAndroid Build Coastguard Worker    total += write_severity(
369*9e94795aSAndroid Build Coastguard Worker        csvwriter, severity, severity.column_header, warn_patterns)
370*9e94795aSAndroid Build Coastguard Worker  csvwriter.writerow([total, '', 'All warnings'])
371*9e94795aSAndroid Build Coastguard Worker
372*9e94795aSAndroid Build Coastguard Worker
373*9e94795aSAndroid Build Coastguard Workerdef dump_csv_with_description(csvwriter, warning_records, warning_messages,
374*9e94795aSAndroid Build Coastguard Worker                              warn_patterns, project_names):
375*9e94795aSAndroid Build Coastguard Worker  """Outputs all the warning messages by project."""
376*9e94795aSAndroid Build Coastguard Worker  csv_output = []
377*9e94795aSAndroid Build Coastguard Worker  for record in warning_records:
378*9e94795aSAndroid Build Coastguard Worker    project_name = project_names[record[1]]
379*9e94795aSAndroid Build Coastguard Worker    pattern = warn_patterns[record[0]]
380*9e94795aSAndroid Build Coastguard Worker    severity = pattern['severity'].header
381*9e94795aSAndroid Build Coastguard Worker    category = pattern['category']
382*9e94795aSAndroid Build Coastguard Worker    description = pattern['description']
383*9e94795aSAndroid Build Coastguard Worker    warning = warning_messages[record[2]]
384*9e94795aSAndroid Build Coastguard Worker    csv_output.append([project_name, severity,
385*9e94795aSAndroid Build Coastguard Worker                       category, description,
386*9e94795aSAndroid Build Coastguard Worker                       warning])
387*9e94795aSAndroid Build Coastguard Worker  csv_output = sorted(csv_output)
388*9e94795aSAndroid Build Coastguard Worker  for output in csv_output:
389*9e94795aSAndroid Build Coastguard Worker    csvwriter.writerow(output)
390*9e94795aSAndroid Build Coastguard Worker
391*9e94795aSAndroid Build Coastguard Worker
392*9e94795aSAndroid Build Coastguard Worker# Return line with escaped backslash and quotation characters.
393*9e94795aSAndroid Build Coastguard Workerdef escape_string(line):
394*9e94795aSAndroid Build Coastguard Worker  return line.replace('\\', '\\\\').replace('"', '\\"')
395*9e94795aSAndroid Build Coastguard Worker
396*9e94795aSAndroid Build Coastguard Worker
397*9e94795aSAndroid Build Coastguard Worker# Return line without trailing '\n' and escape the quotation characters.
398*9e94795aSAndroid Build Coastguard Workerdef strip_escape_string(line):
399*9e94795aSAndroid Build Coastguard Worker  if not line:
400*9e94795aSAndroid Build Coastguard Worker    return line
401*9e94795aSAndroid Build Coastguard Worker  line = line[:-1] if line[-1] == '\n' else line
402*9e94795aSAndroid Build Coastguard Worker  return escape_string(line)
403*9e94795aSAndroid Build Coastguard Worker
404*9e94795aSAndroid Build Coastguard Worker
405*9e94795aSAndroid Build Coastguard Workerdef emit_warning_array(name, writer, warn_patterns):
406*9e94795aSAndroid Build Coastguard Worker  writer('var warning_{} = ['.format(name))
407*9e94795aSAndroid Build Coastguard Worker  for pattern in warn_patterns:
408*9e94795aSAndroid Build Coastguard Worker    if name == 'severity':
409*9e94795aSAndroid Build Coastguard Worker      writer('{},'.format(pattern[name].value))
410*9e94795aSAndroid Build Coastguard Worker    else:
411*9e94795aSAndroid Build Coastguard Worker      writer('{},'.format(pattern[name]))
412*9e94795aSAndroid Build Coastguard Worker  writer('];')
413*9e94795aSAndroid Build Coastguard Worker
414*9e94795aSAndroid Build Coastguard Worker
415*9e94795aSAndroid Build Coastguard Workerdef emit_warning_arrays(writer, warn_patterns):
416*9e94795aSAndroid Build Coastguard Worker  emit_warning_array('severity', writer, warn_patterns)
417*9e94795aSAndroid Build Coastguard Worker  writer('var warning_description = [')
418*9e94795aSAndroid Build Coastguard Worker  for pattern in warn_patterns:
419*9e94795aSAndroid Build Coastguard Worker    if pattern['members']:
420*9e94795aSAndroid Build Coastguard Worker      writer('"{}",'.format(escape_string(pattern['description'])))
421*9e94795aSAndroid Build Coastguard Worker    else:
422*9e94795aSAndroid Build Coastguard Worker      writer('"",')  # no such warning
423*9e94795aSAndroid Build Coastguard Worker  writer('];')
424*9e94795aSAndroid Build Coastguard Worker
425*9e94795aSAndroid Build Coastguard Worker
426*9e94795aSAndroid Build Coastguard WorkerSCRIPTS_FOR_WARNING_GROUPS = """
427*9e94795aSAndroid Build Coastguard Worker  function compareMessages(x1, x2) { // of the same warning type
428*9e94795aSAndroid Build Coastguard Worker    return (WarningMessages[x1[2]] <= WarningMessages[x2[2]]) ? -1 : 1;
429*9e94795aSAndroid Build Coastguard Worker  }
430*9e94795aSAndroid Build Coastguard Worker  function byMessageCount(x1, x2) {
431*9e94795aSAndroid Build Coastguard Worker    return x2[2] - x1[2];  // reversed order
432*9e94795aSAndroid Build Coastguard Worker  }
433*9e94795aSAndroid Build Coastguard Worker  function bySeverityMessageCount(x1, x2) {
434*9e94795aSAndroid Build Coastguard Worker    // orer by severity first
435*9e94795aSAndroid Build Coastguard Worker    if (x1[1] != x2[1])
436*9e94795aSAndroid Build Coastguard Worker      return  x1[1] - x2[1];
437*9e94795aSAndroid Build Coastguard Worker    return byMessageCount(x1, x2);
438*9e94795aSAndroid Build Coastguard Worker  }
439*9e94795aSAndroid Build Coastguard Worker  const ParseLinePattern = /^([^ :]+):(\\d+):(.+)/;
440*9e94795aSAndroid Build Coastguard Worker  function addURL(line) { // used by Android
441*9e94795aSAndroid Build Coastguard Worker    if (FlagURL == "") return line;
442*9e94795aSAndroid Build Coastguard Worker    if (FlagSeparator == "") {
443*9e94795aSAndroid Build Coastguard Worker      return line.replace(ParseLinePattern,
444*9e94795aSAndroid Build Coastguard Worker        "<a target='_blank' href='" + FlagURL + "/$1'>$1</a>:$2:$3");
445*9e94795aSAndroid Build Coastguard Worker    }
446*9e94795aSAndroid Build Coastguard Worker    return line.replace(ParseLinePattern,
447*9e94795aSAndroid Build Coastguard Worker      "<a target='_blank' href='" + FlagURL + "/$1" + FlagSeparator +
448*9e94795aSAndroid Build Coastguard Worker        "$2'>$1:$2</a>:$3");
449*9e94795aSAndroid Build Coastguard Worker  }
450*9e94795aSAndroid Build Coastguard Worker  function addURLToLine(line, link) { // used by Chrome
451*9e94795aSAndroid Build Coastguard Worker      let line_split = line.split(":");
452*9e94795aSAndroid Build Coastguard Worker      let path = line_split.slice(0,3).join(":");
453*9e94795aSAndroid Build Coastguard Worker      let msg = line_split.slice(3).join(":");
454*9e94795aSAndroid Build Coastguard Worker      let html_link = `<a target="_blank" href="${link}">${path}</a>${msg}`;
455*9e94795aSAndroid Build Coastguard Worker      return html_link;
456*9e94795aSAndroid Build Coastguard Worker  }
457*9e94795aSAndroid Build Coastguard Worker  function createArrayOfDictionaries(n) {
458*9e94795aSAndroid Build Coastguard Worker    var result = [];
459*9e94795aSAndroid Build Coastguard Worker    for (var i=0; i<n; i++) result.push({});
460*9e94795aSAndroid Build Coastguard Worker    return result;
461*9e94795aSAndroid Build Coastguard Worker  }
462*9e94795aSAndroid Build Coastguard Worker  function groupWarningsBySeverity() {
463*9e94795aSAndroid Build Coastguard Worker    // groups is an array of dictionaries,
464*9e94795aSAndroid Build Coastguard Worker    // each dictionary maps from warning type to array of warning messages.
465*9e94795aSAndroid Build Coastguard Worker    var groups = createArrayOfDictionaries(SeverityColors.length);
466*9e94795aSAndroid Build Coastguard Worker    for (var i=0; i<Warnings.length; i++) {
467*9e94795aSAndroid Build Coastguard Worker      var w = Warnings[i][0];
468*9e94795aSAndroid Build Coastguard Worker      var s = WarnPatternsSeverity[w];
469*9e94795aSAndroid Build Coastguard Worker      var k = w.toString();
470*9e94795aSAndroid Build Coastguard Worker      if (!(k in groups[s]))
471*9e94795aSAndroid Build Coastguard Worker        groups[s][k] = [];
472*9e94795aSAndroid Build Coastguard Worker      groups[s][k].push(Warnings[i]);
473*9e94795aSAndroid Build Coastguard Worker    }
474*9e94795aSAndroid Build Coastguard Worker    return groups;
475*9e94795aSAndroid Build Coastguard Worker  }
476*9e94795aSAndroid Build Coastguard Worker  function groupWarningsByProject() {
477*9e94795aSAndroid Build Coastguard Worker    var groups = createArrayOfDictionaries(ProjectNames.length);
478*9e94795aSAndroid Build Coastguard Worker    for (var i=0; i<Warnings.length; i++) {
479*9e94795aSAndroid Build Coastguard Worker      var w = Warnings[i][0];
480*9e94795aSAndroid Build Coastguard Worker      var p = Warnings[i][1];
481*9e94795aSAndroid Build Coastguard Worker      var k = w.toString();
482*9e94795aSAndroid Build Coastguard Worker      if (!(k in groups[p]))
483*9e94795aSAndroid Build Coastguard Worker        groups[p][k] = [];
484*9e94795aSAndroid Build Coastguard Worker      groups[p][k].push(Warnings[i]);
485*9e94795aSAndroid Build Coastguard Worker    }
486*9e94795aSAndroid Build Coastguard Worker    return groups;
487*9e94795aSAndroid Build Coastguard Worker  }
488*9e94795aSAndroid Build Coastguard Worker  var GlobalAnchor = 0;
489*9e94795aSAndroid Build Coastguard Worker  function createWarningSection(header, color, group) {
490*9e94795aSAndroid Build Coastguard Worker    var result = "";
491*9e94795aSAndroid Build Coastguard Worker    var groupKeys = [];
492*9e94795aSAndroid Build Coastguard Worker    var totalMessages = 0;
493*9e94795aSAndroid Build Coastguard Worker    for (var k in group) {
494*9e94795aSAndroid Build Coastguard Worker       totalMessages += group[k].length;
495*9e94795aSAndroid Build Coastguard Worker       groupKeys.push([k, WarnPatternsSeverity[parseInt(k)], group[k].length]);
496*9e94795aSAndroid Build Coastguard Worker    }
497*9e94795aSAndroid Build Coastguard Worker    groupKeys.sort(bySeverityMessageCount);
498*9e94795aSAndroid Build Coastguard Worker    for (var idx=0; idx<groupKeys.length; idx++) {
499*9e94795aSAndroid Build Coastguard Worker      var k = groupKeys[idx][0];
500*9e94795aSAndroid Build Coastguard Worker      var messages = group[k];
501*9e94795aSAndroid Build Coastguard Worker      var w = parseInt(k);
502*9e94795aSAndroid Build Coastguard Worker      var wcolor = SeverityColors[WarnPatternsSeverity[w]];
503*9e94795aSAndroid Build Coastguard Worker      var description = WarnPatternsDescription[w];
504*9e94795aSAndroid Build Coastguard Worker      if (description.length == 0)
505*9e94795aSAndroid Build Coastguard Worker          description = "???";
506*9e94795aSAndroid Build Coastguard Worker      GlobalAnchor += 1;
507*9e94795aSAndroid Build Coastguard Worker      result += "<table class='t1'><tr bgcolor='" + wcolor + "'><td>" +
508*9e94795aSAndroid Build Coastguard Worker                "<button class='bt' id='" + GlobalAnchor + "_mark" +
509*9e94795aSAndroid Build Coastguard Worker                "' onclick='expand(\\"" + GlobalAnchor + "\\");'>" +
510*9e94795aSAndroid Build Coastguard Worker                "&#x2295</button> " +
511*9e94795aSAndroid Build Coastguard Worker                description + " (" + messages.length + ")</td></tr></table>";
512*9e94795aSAndroid Build Coastguard Worker      result += "<div id='" + GlobalAnchor +
513*9e94795aSAndroid Build Coastguard Worker                "' style='display:none;'><table class='t1'>";
514*9e94795aSAndroid Build Coastguard Worker      var c = 0;
515*9e94795aSAndroid Build Coastguard Worker      messages.sort(compareMessages);
516*9e94795aSAndroid Build Coastguard Worker      if (FlagPlatform == "chrome") {
517*9e94795aSAndroid Build Coastguard Worker        for (var i=0; i<messages.length; i++) {
518*9e94795aSAndroid Build Coastguard Worker          result += "<tr><td class='c" + c + "'>" +
519*9e94795aSAndroid Build Coastguard Worker                    addURLToLine(WarningMessages[messages[i][2]], WarningLinks[messages[i][3]]) + "</td></tr>";
520*9e94795aSAndroid Build Coastguard Worker          c = 1 - c;
521*9e94795aSAndroid Build Coastguard Worker        }
522*9e94795aSAndroid Build Coastguard Worker      } else {
523*9e94795aSAndroid Build Coastguard Worker        for (var i=0; i<messages.length; i++) {
524*9e94795aSAndroid Build Coastguard Worker          result += "<tr><td class='c" + c + "'>" +
525*9e94795aSAndroid Build Coastguard Worker                    addURL(WarningMessages[messages[i][2]]) + "</td></tr>";
526*9e94795aSAndroid Build Coastguard Worker          c = 1 - c;
527*9e94795aSAndroid Build Coastguard Worker        }
528*9e94795aSAndroid Build Coastguard Worker      }
529*9e94795aSAndroid Build Coastguard Worker      result += "</table></div>";
530*9e94795aSAndroid Build Coastguard Worker    }
531*9e94795aSAndroid Build Coastguard Worker    if (result.length > 0) {
532*9e94795aSAndroid Build Coastguard Worker      return "<br><span style='background-color:" + color + "'><b>" +
533*9e94795aSAndroid Build Coastguard Worker             header + ": " + totalMessages +
534*9e94795aSAndroid Build Coastguard Worker             "</b></span><blockquote><table class='t1'>" +
535*9e94795aSAndroid Build Coastguard Worker             result + "</table></blockquote>";
536*9e94795aSAndroid Build Coastguard Worker
537*9e94795aSAndroid Build Coastguard Worker    }
538*9e94795aSAndroid Build Coastguard Worker    return "";  // empty section
539*9e94795aSAndroid Build Coastguard Worker  }
540*9e94795aSAndroid Build Coastguard Worker  function generateSectionsBySeverity() {
541*9e94795aSAndroid Build Coastguard Worker    var result = "";
542*9e94795aSAndroid Build Coastguard Worker    var groups = groupWarningsBySeverity();
543*9e94795aSAndroid Build Coastguard Worker    for (s=0; s<SeverityColors.length; s++) {
544*9e94795aSAndroid Build Coastguard Worker      result += createWarningSection(SeverityHeaders[s], SeverityColors[s],
545*9e94795aSAndroid Build Coastguard Worker                                     groups[s]);
546*9e94795aSAndroid Build Coastguard Worker    }
547*9e94795aSAndroid Build Coastguard Worker    return result;
548*9e94795aSAndroid Build Coastguard Worker  }
549*9e94795aSAndroid Build Coastguard Worker  function generateSectionsByProject() {
550*9e94795aSAndroid Build Coastguard Worker    var result = "";
551*9e94795aSAndroid Build Coastguard Worker    var groups = groupWarningsByProject();
552*9e94795aSAndroid Build Coastguard Worker    for (i=0; i<groups.length; i++) {
553*9e94795aSAndroid Build Coastguard Worker      result += createWarningSection(ProjectNames[i], 'lightgrey', groups[i]);
554*9e94795aSAndroid Build Coastguard Worker    }
555*9e94795aSAndroid Build Coastguard Worker    return result;
556*9e94795aSAndroid Build Coastguard Worker  }
557*9e94795aSAndroid Build Coastguard Worker  function groupWarnings(generator) {
558*9e94795aSAndroid Build Coastguard Worker    GlobalAnchor = 0;
559*9e94795aSAndroid Build Coastguard Worker    var e = document.getElementById("warning_groups");
560*9e94795aSAndroid Build Coastguard Worker    e.innerHTML = generator();
561*9e94795aSAndroid Build Coastguard Worker  }
562*9e94795aSAndroid Build Coastguard Worker  function groupBySeverity() {
563*9e94795aSAndroid Build Coastguard Worker    groupWarnings(generateSectionsBySeverity);
564*9e94795aSAndroid Build Coastguard Worker  }
565*9e94795aSAndroid Build Coastguard Worker  function groupByProject() {
566*9e94795aSAndroid Build Coastguard Worker    groupWarnings(generateSectionsByProject);
567*9e94795aSAndroid Build Coastguard Worker  }
568*9e94795aSAndroid Build Coastguard Worker"""
569*9e94795aSAndroid Build Coastguard Worker
570*9e94795aSAndroid Build Coastguard Worker
571*9e94795aSAndroid Build Coastguard Worker# Emit a JavaScript const number
572*9e94795aSAndroid Build Coastguard Workerdef emit_const_number(name, value, writer):
573*9e94795aSAndroid Build Coastguard Worker  writer('const ' + name + ' = ' + str(value) + ';')
574*9e94795aSAndroid Build Coastguard Worker
575*9e94795aSAndroid Build Coastguard Worker
576*9e94795aSAndroid Build Coastguard Worker# Emit a JavaScript const string
577*9e94795aSAndroid Build Coastguard Workerdef emit_const_string(name, value, writer):
578*9e94795aSAndroid Build Coastguard Worker  writer('const ' + name + ' = "' + escape_string(value) + '";')
579*9e94795aSAndroid Build Coastguard Worker
580*9e94795aSAndroid Build Coastguard Worker
581*9e94795aSAndroid Build Coastguard Worker# Emit a JavaScript const integer array.
582*9e94795aSAndroid Build Coastguard Workerdef emit_const_int_array(name, array, writer):
583*9e94795aSAndroid Build Coastguard Worker  writer('const ' + name + ' = [')
584*9e94795aSAndroid Build Coastguard Worker  for item in array:
585*9e94795aSAndroid Build Coastguard Worker    writer(str(item) + ',')
586*9e94795aSAndroid Build Coastguard Worker  writer('];')
587*9e94795aSAndroid Build Coastguard Worker
588*9e94795aSAndroid Build Coastguard Worker
589*9e94795aSAndroid Build Coastguard Worker# Emit a JavaScript const string array.
590*9e94795aSAndroid Build Coastguard Workerdef emit_const_string_array(name, array, writer):
591*9e94795aSAndroid Build Coastguard Worker  writer('const ' + name + ' = [')
592*9e94795aSAndroid Build Coastguard Worker  for item in array:
593*9e94795aSAndroid Build Coastguard Worker    writer('"' + strip_escape_string(item) + '",')
594*9e94795aSAndroid Build Coastguard Worker  writer('];')
595*9e94795aSAndroid Build Coastguard Worker
596*9e94795aSAndroid Build Coastguard Worker
597*9e94795aSAndroid Build Coastguard Worker# Emit a JavaScript const string array for HTML.
598*9e94795aSAndroid Build Coastguard Workerdef emit_const_html_string_array(name, array, writer):
599*9e94795aSAndroid Build Coastguard Worker  writer('const ' + name + ' = [')
600*9e94795aSAndroid Build Coastguard Worker  for item in array:
601*9e94795aSAndroid Build Coastguard Worker    writer('"' + html.escape(strip_escape_string(item)) + '",')
602*9e94795aSAndroid Build Coastguard Worker  writer('];')
603*9e94795aSAndroid Build Coastguard Worker
604*9e94795aSAndroid Build Coastguard Worker
605*9e94795aSAndroid Build Coastguard Worker# Emit a JavaScript const object array.
606*9e94795aSAndroid Build Coastguard Workerdef emit_const_object_array(name, array, writer):
607*9e94795aSAndroid Build Coastguard Worker  writer('const ' + name + ' = [')
608*9e94795aSAndroid Build Coastguard Worker  for item in array:
609*9e94795aSAndroid Build Coastguard Worker    writer(str(item) + ',')
610*9e94795aSAndroid Build Coastguard Worker  writer('];')
611*9e94795aSAndroid Build Coastguard Worker
612*9e94795aSAndroid Build Coastguard Worker
613*9e94795aSAndroid Build Coastguard Workerdef emit_js_data(writer, flags, warning_messages, warning_links,
614*9e94795aSAndroid Build Coastguard Worker                 warning_records, warn_patterns, project_names):
615*9e94795aSAndroid Build Coastguard Worker  """Dump dynamic HTML page's static JavaScript data."""
616*9e94795aSAndroid Build Coastguard Worker  emit_const_string('FlagPlatform', flags.platform, writer)
617*9e94795aSAndroid Build Coastguard Worker  emit_const_string('FlagURL', flags.url, writer)
618*9e94795aSAndroid Build Coastguard Worker  emit_const_string('FlagSeparator', flags.separator, writer)
619*9e94795aSAndroid Build Coastguard Worker  emit_const_number('LimitWarningsPerFile', LIMIT_WARNINGS_PER_FILE, writer)
620*9e94795aSAndroid Build Coastguard Worker  emit_const_number('LimitPercentWarnings', LIMIT_PERCENT_WARNINGS, writer)
621*9e94795aSAndroid Build Coastguard Worker  emit_const_string_array('SeverityColors', [s.color for s in Severity.levels],
622*9e94795aSAndroid Build Coastguard Worker                          writer)
623*9e94795aSAndroid Build Coastguard Worker  emit_const_string_array('SeverityHeaders',
624*9e94795aSAndroid Build Coastguard Worker                          [s.header for s in Severity.levels], writer)
625*9e94795aSAndroid Build Coastguard Worker  emit_const_string_array('SeverityColumnHeaders',
626*9e94795aSAndroid Build Coastguard Worker                          [s.column_header for s in Severity.levels], writer)
627*9e94795aSAndroid Build Coastguard Worker  emit_const_string_array('ProjectNames', project_names, writer)
628*9e94795aSAndroid Build Coastguard Worker  # pytype: disable=attribute-error
629*9e94795aSAndroid Build Coastguard Worker  emit_const_int_array('WarnPatternsSeverity',
630*9e94795aSAndroid Build Coastguard Worker                       [w['severity'].value for w in warn_patterns], writer)
631*9e94795aSAndroid Build Coastguard Worker  # pytype: enable=attribute-error
632*9e94795aSAndroid Build Coastguard Worker  emit_const_html_string_array('WarnPatternsDescription',
633*9e94795aSAndroid Build Coastguard Worker                               [w['description'] for w in warn_patterns],
634*9e94795aSAndroid Build Coastguard Worker                               writer)
635*9e94795aSAndroid Build Coastguard Worker  emit_const_html_string_array('WarningMessages', warning_messages, writer)
636*9e94795aSAndroid Build Coastguard Worker  emit_const_object_array('Warnings', warning_records, writer)
637*9e94795aSAndroid Build Coastguard Worker  if flags.platform == 'chrome':
638*9e94795aSAndroid Build Coastguard Worker    emit_const_html_string_array('WarningLinks', warning_links, writer)
639*9e94795aSAndroid Build Coastguard Worker
640*9e94795aSAndroid Build Coastguard Worker
641*9e94795aSAndroid Build Coastguard WorkerDRAW_TABLE_JAVASCRIPT = """
642*9e94795aSAndroid Build Coastguard Workergoogle.charts.load('current', {'packages':['table']});
643*9e94795aSAndroid Build Coastguard Workergoogle.charts.setOnLoadCallback(genTables);
644*9e94795aSAndroid Build Coastguard Workerfunction genSelectedProjectsTable() {
645*9e94795aSAndroid Build Coastguard Worker  var data = new google.visualization.DataTable();
646*9e94795aSAndroid Build Coastguard Worker  data.addColumn('string', StatsHeader[0]);
647*9e94795aSAndroid Build Coastguard Worker  for (var i=1; i<StatsHeader.length; i++) {
648*9e94795aSAndroid Build Coastguard Worker    data.addColumn('number', StatsHeader[i]);
649*9e94795aSAndroid Build Coastguard Worker  }
650*9e94795aSAndroid Build Coastguard Worker  data.addRows(StatsRows);
651*9e94795aSAndroid Build Coastguard Worker  for (var i=0; i<StatsRows.length; i++) {
652*9e94795aSAndroid Build Coastguard Worker    for (var j=0; j<StatsHeader.length; j++) {
653*9e94795aSAndroid Build Coastguard Worker      data.setProperty(i, j, 'style', 'border:1px solid black;');
654*9e94795aSAndroid Build Coastguard Worker    }
655*9e94795aSAndroid Build Coastguard Worker  }
656*9e94795aSAndroid Build Coastguard Worker  var table = new google.visualization.Table(
657*9e94795aSAndroid Build Coastguard Worker      document.getElementById('selected_projects_section'));
658*9e94795aSAndroid Build Coastguard Worker  table.draw(data, {allowHtml: true, alternatingRowStyle: true});
659*9e94795aSAndroid Build Coastguard Worker}
660*9e94795aSAndroid Build Coastguard Worker// Global TopDirs and TopFiles are computed later by genTables.
661*9e94795aSAndroid Build Coastguard Workerwindow.TopDirs = [];
662*9e94795aSAndroid Build Coastguard Workerwindow.TopFiles = [];
663*9e94795aSAndroid Build Coastguard Workerfunction computeTopDirsFiles() {
664*9e94795aSAndroid Build Coastguard Worker  var numWarnings = WarningMessages.length;
665*9e94795aSAndroid Build Coastguard Worker  var warningsOfFiles = {};
666*9e94795aSAndroid Build Coastguard Worker  var warningsOfDirs = {};
667*9e94795aSAndroid Build Coastguard Worker  var subDirs = {};
668*9e94795aSAndroid Build Coastguard Worker  function addOneWarning(map, key, type, unique) {
669*9e94795aSAndroid Build Coastguard Worker    function increaseCounter(idx) {
670*9e94795aSAndroid Build Coastguard Worker      map[idx] = 1 + ((idx in map) ? map[idx] : 0);
671*9e94795aSAndroid Build Coastguard Worker    }
672*9e94795aSAndroid Build Coastguard Worker    increaseCounter(key)
673*9e94795aSAndroid Build Coastguard Worker    if (type != "") {
674*9e94795aSAndroid Build Coastguard Worker      increaseCounter(type + " " + key)
675*9e94795aSAndroid Build Coastguard Worker      if (unique) {
676*9e94795aSAndroid Build Coastguard Worker        increaseCounter(type + " *")
677*9e94795aSAndroid Build Coastguard Worker      }
678*9e94795aSAndroid Build Coastguard Worker    }
679*9e94795aSAndroid Build Coastguard Worker  }
680*9e94795aSAndroid Build Coastguard Worker  for (var i = 0; i < numWarnings; i++) {
681*9e94795aSAndroid Build Coastguard Worker    var message = WarningMessages[i]
682*9e94795aSAndroid Build Coastguard Worker    var file = message.replace(/:.*/, "");
683*9e94795aSAndroid Build Coastguard Worker    var warningType = message.endsWith("]") ? message.replace(/.*\[/, "[") : "";
684*9e94795aSAndroid Build Coastguard Worker    addOneWarning(warningsOfFiles, file, warningType, true);
685*9e94795aSAndroid Build Coastguard Worker    var dirs = file.split("/");
686*9e94795aSAndroid Build Coastguard Worker    var dir = dirs[0];
687*9e94795aSAndroid Build Coastguard Worker    addOneWarning(warningsOfDirs, dir, warningType, true);
688*9e94795aSAndroid Build Coastguard Worker    for (var d = 1; d < dirs.length - 1; d++) {
689*9e94795aSAndroid Build Coastguard Worker      var subDir = dir + "/" + dirs[d];
690*9e94795aSAndroid Build Coastguard Worker      if (!(dir in subDirs)) {
691*9e94795aSAndroid Build Coastguard Worker        subDirs[dir] = {};
692*9e94795aSAndroid Build Coastguard Worker      }
693*9e94795aSAndroid Build Coastguard Worker      subDirs[dir][subDir] = 1;
694*9e94795aSAndroid Build Coastguard Worker      dir = subDir;
695*9e94795aSAndroid Build Coastguard Worker      addOneWarning(warningsOfDirs, dir, warningType, false);
696*9e94795aSAndroid Build Coastguard Worker    }
697*9e94795aSAndroid Build Coastguard Worker  }
698*9e94795aSAndroid Build Coastguard Worker  var minDirWarnings = numWarnings*(LimitPercentWarnings/100);
699*9e94795aSAndroid Build Coastguard Worker  var minFileWarnings = Math.min(LimitWarningsPerFile, minDirWarnings);
700*9e94795aSAndroid Build Coastguard Worker  // Each row in TopDirs and TopFiles has
701*9e94795aSAndroid Build Coastguard Worker  // [index, {v:<num_of_warnings>, f:<percent>}, file_or_dir_name]
702*9e94795aSAndroid Build Coastguard Worker  function countWarnings(minWarnings, warningsOf, isDir) {
703*9e94795aSAndroid Build Coastguard Worker    var rows = [];
704*9e94795aSAndroid Build Coastguard Worker    for (var name in warningsOf) {
705*9e94795aSAndroid Build Coastguard Worker      if (isDir && name in subDirs && Object.keys(subDirs[name]).length < 2) {
706*9e94795aSAndroid Build Coastguard Worker        continue; // skip a directory if it has only one subdir
707*9e94795aSAndroid Build Coastguard Worker      }
708*9e94795aSAndroid Build Coastguard Worker      var count = warningsOf[name];
709*9e94795aSAndroid Build Coastguard Worker      if (count >= minWarnings) {
710*9e94795aSAndroid Build Coastguard Worker        name = isDir ? (name + "/...") : name;
711*9e94795aSAndroid Build Coastguard Worker        var percent = (100*count/numWarnings).toFixed(1);
712*9e94795aSAndroid Build Coastguard Worker        var countFormat = count + ' (' + percent + '%)';
713*9e94795aSAndroid Build Coastguard Worker        rows.push([0, {v:count, f:countFormat}, name]);
714*9e94795aSAndroid Build Coastguard Worker      }
715*9e94795aSAndroid Build Coastguard Worker    }
716*9e94795aSAndroid Build Coastguard Worker    rows.sort((a,b) => b[1].v - a[1].v);
717*9e94795aSAndroid Build Coastguard Worker    for (var i=0; i<rows.length; i++) {
718*9e94795aSAndroid Build Coastguard Worker      rows[i][0] = i;
719*9e94795aSAndroid Build Coastguard Worker    }
720*9e94795aSAndroid Build Coastguard Worker    return rows;
721*9e94795aSAndroid Build Coastguard Worker  }
722*9e94795aSAndroid Build Coastguard Worker  TopDirs = countWarnings(minDirWarnings, warningsOfDirs, true);
723*9e94795aSAndroid Build Coastguard Worker  TopFiles = countWarnings(minFileWarnings, warningsOfFiles, false);
724*9e94795aSAndroid Build Coastguard Worker}
725*9e94795aSAndroid Build Coastguard Workerfunction genTopDirsFilesTables() {
726*9e94795aSAndroid Build Coastguard Worker  computeTopDirsFiles();
727*9e94795aSAndroid Build Coastguard Worker  function addTable(name, divName, rows, clickFunction) {
728*9e94795aSAndroid Build Coastguard Worker    var data = new google.visualization.DataTable();
729*9e94795aSAndroid Build Coastguard Worker    data.addColumn("number", "index"); // not shown in view
730*9e94795aSAndroid Build Coastguard Worker    data.addColumn("number", "# of warnings");
731*9e94795aSAndroid Build Coastguard Worker    data.addColumn("string", name);
732*9e94795aSAndroid Build Coastguard Worker    data.addRows(rows);
733*9e94795aSAndroid Build Coastguard Worker    var formatter = new google.visualization.PatternFormat(
734*9e94795aSAndroid Build Coastguard Worker      '<p onclick="' + clickFunction + '({0})">{2}</p>');
735*9e94795aSAndroid Build Coastguard Worker    formatter.format(data, [0, 1, 2], 2);
736*9e94795aSAndroid Build Coastguard Worker    var view = new google.visualization.DataView(data);
737*9e94795aSAndroid Build Coastguard Worker    view.setColumns([1,2]); // hide the index column
738*9e94795aSAndroid Build Coastguard Worker    var table = new google.visualization.Table(
739*9e94795aSAndroid Build Coastguard Worker        document.getElementById(divName));
740*9e94795aSAndroid Build Coastguard Worker    table.draw(view, {allowHtml: true, alternatingRowStyle: true});
741*9e94795aSAndroid Build Coastguard Worker  }
742*9e94795aSAndroid Build Coastguard Worker  addTable("[Warning Type] Directory", "top_dirs_table", TopDirs, "selectDir");
743*9e94795aSAndroid Build Coastguard Worker  addTable("[Warning Type] File", "top_files_table", TopFiles, "selectFile");
744*9e94795aSAndroid Build Coastguard Worker}
745*9e94795aSAndroid Build Coastguard Workerfunction selectDirFile(idx, rows, dirFile) {
746*9e94795aSAndroid Build Coastguard Worker  if (rows.length <= idx) {
747*9e94795aSAndroid Build Coastguard Worker    return;
748*9e94795aSAndroid Build Coastguard Worker  }
749*9e94795aSAndroid Build Coastguard Worker  var name = rows[idx][2];
750*9e94795aSAndroid Build Coastguard Worker  var type = "";
751*9e94795aSAndroid Build Coastguard Worker  if (name.startsWith("[")) {
752*9e94795aSAndroid Build Coastguard Worker    type = " " + name.replace(/ .*/, "");
753*9e94795aSAndroid Build Coastguard Worker    name = name.replace(/.* /, "");
754*9e94795aSAndroid Build Coastguard Worker  }
755*9e94795aSAndroid Build Coastguard Worker  var spanName = "selected_" + dirFile + "_name";
756*9e94795aSAndroid Build Coastguard Worker  document.getElementById(spanName).innerHTML = name + type;
757*9e94795aSAndroid Build Coastguard Worker  var divName = "selected_" + dirFile + "_warnings";
758*9e94795aSAndroid Build Coastguard Worker  var numWarnings = rows[idx][1].v;
759*9e94795aSAndroid Build Coastguard Worker  var prefix = name.replace(/\\.\\.\\.$/, "");
760*9e94795aSAndroid Build Coastguard Worker  var data = new google.visualization.DataTable();
761*9e94795aSAndroid Build Coastguard Worker  data.addColumn('string', numWarnings + type + ' warnings in ' + name);
762*9e94795aSAndroid Build Coastguard Worker  var getWarningMessage = (FlagPlatform == "chrome")
763*9e94795aSAndroid Build Coastguard Worker        ? ((x) => addURLToLine(WarningMessages[Warnings[x][2]],
764*9e94795aSAndroid Build Coastguard Worker                               WarningLinks[Warnings[x][3]]))
765*9e94795aSAndroid Build Coastguard Worker        : ((x) => addURL(WarningMessages[Warnings[x][2]]));
766*9e94795aSAndroid Build Coastguard Worker  for (var i = 0; i < Warnings.length; i++) {
767*9e94795aSAndroid Build Coastguard Worker    if ((prefix.startsWith("*") || WarningMessages[Warnings[i][2]].startsWith(prefix)) &&
768*9e94795aSAndroid Build Coastguard Worker        (type == "" || WarningMessages[Warnings[i][2]].endsWith(type))) {
769*9e94795aSAndroid Build Coastguard Worker      data.addRow([getWarningMessage(i)]);
770*9e94795aSAndroid Build Coastguard Worker    }
771*9e94795aSAndroid Build Coastguard Worker  }
772*9e94795aSAndroid Build Coastguard Worker  var table = new google.visualization.Table(
773*9e94795aSAndroid Build Coastguard Worker      document.getElementById(divName));
774*9e94795aSAndroid Build Coastguard Worker  table.draw(data, {allowHtml: true, alternatingRowStyle: true});
775*9e94795aSAndroid Build Coastguard Worker}
776*9e94795aSAndroid Build Coastguard Workerfunction selectDir(idx) {
777*9e94795aSAndroid Build Coastguard Worker  selectDirFile(idx, TopDirs, "directory")
778*9e94795aSAndroid Build Coastguard Worker}
779*9e94795aSAndroid Build Coastguard Workerfunction selectFile(idx) {
780*9e94795aSAndroid Build Coastguard Worker  selectDirFile(idx, TopFiles, "file");
781*9e94795aSAndroid Build Coastguard Worker}
782*9e94795aSAndroid Build Coastguard Workerfunction genTables() {
783*9e94795aSAndroid Build Coastguard Worker  genSelectedProjectsTable();
784*9e94795aSAndroid Build Coastguard Worker  if (WarningMessages.length > 1) {
785*9e94795aSAndroid Build Coastguard Worker    genTopDirsFilesTables();
786*9e94795aSAndroid Build Coastguard Worker  }
787*9e94795aSAndroid Build Coastguard Worker}
788*9e94795aSAndroid Build Coastguard Worker"""
789*9e94795aSAndroid Build Coastguard Worker
790*9e94795aSAndroid Build Coastguard Worker
791*9e94795aSAndroid Build Coastguard Workerdef dump_boxed_section(writer, func):
792*9e94795aSAndroid Build Coastguard Worker  writer('<div class="box">')
793*9e94795aSAndroid Build Coastguard Worker  func()
794*9e94795aSAndroid Build Coastguard Worker  writer('</div>')
795*9e94795aSAndroid Build Coastguard Worker
796*9e94795aSAndroid Build Coastguard Worker
797*9e94795aSAndroid Build Coastguard Workerdef dump_section_header(writer, table_name, section_title):
798*9e94795aSAndroid Build Coastguard Worker  writer('<h3><b><button id="' + table_name + '_mark" class="bt"\n' +
799*9e94795aSAndroid Build Coastguard Worker         ' onclick="expand(\'' + table_name + '\');">&#x2295</button></b>\n' +
800*9e94795aSAndroid Build Coastguard Worker         section_title + '</h3>')
801*9e94795aSAndroid Build Coastguard Worker
802*9e94795aSAndroid Build Coastguard Worker
803*9e94795aSAndroid Build Coastguard Workerdef dump_table_section(writer, table_name, section_title):
804*9e94795aSAndroid Build Coastguard Worker  dump_section_header(writer, table_name, section_title)
805*9e94795aSAndroid Build Coastguard Worker  writer('<div id="' + table_name + '" style="display:none;"></div>')
806*9e94795aSAndroid Build Coastguard Worker
807*9e94795aSAndroid Build Coastguard Worker
808*9e94795aSAndroid Build Coastguard Workerdef dump_dir_file_section(writer, dir_file, table_name, section_title):
809*9e94795aSAndroid Build Coastguard Worker  section_name = 'top_' + dir_file + '_section'
810*9e94795aSAndroid Build Coastguard Worker  dump_section_header(writer, section_name, section_title)
811*9e94795aSAndroid Build Coastguard Worker  writer('<div id="' + section_name + '" style="display:none;">')
812*9e94795aSAndroid Build Coastguard Worker  writer('<div id="' + table_name + '"></div>')
813*9e94795aSAndroid Build Coastguard Worker  def subsection():
814*9e94795aSAndroid Build Coastguard Worker    subsection_name = 'selected_' + dir_file + '_warnings'
815*9e94795aSAndroid Build Coastguard Worker    subsection_title = ('Warnings in <span id="selected_' + dir_file +
816*9e94795aSAndroid Build Coastguard Worker                        '_name">(click a ' + dir_file +
817*9e94795aSAndroid Build Coastguard Worker                        ' in the above table)</span>')
818*9e94795aSAndroid Build Coastguard Worker    dump_section_header(writer, subsection_name, subsection_title)
819*9e94795aSAndroid Build Coastguard Worker    writer('<div id="' + subsection_name + '" style="display:none;"></div>')
820*9e94795aSAndroid Build Coastguard Worker  dump_boxed_section(writer, subsection)
821*9e94795aSAndroid Build Coastguard Worker  writer('</div>')
822*9e94795aSAndroid Build Coastguard Worker
823*9e94795aSAndroid Build Coastguard Worker
824*9e94795aSAndroid Build Coastguard Worker# HTML output has the following major div elements:
825*9e94795aSAndroid Build Coastguard Worker#  selected_projects_section
826*9e94795aSAndroid Build Coastguard Worker#  top_directory_section
827*9e94795aSAndroid Build Coastguard Worker#    top_dirs_table
828*9e94795aSAndroid Build Coastguard Worker#    selected_directory_warnings
829*9e94795aSAndroid Build Coastguard Worker#  top_file_section
830*9e94795aSAndroid Build Coastguard Worker#    top_files_table
831*9e94795aSAndroid Build Coastguard Worker#    selected_file_warnings
832*9e94795aSAndroid Build Coastguard Worker#  all_warnings_section
833*9e94795aSAndroid Build Coastguard Worker#    warning_groups
834*9e94795aSAndroid Build Coastguard Worker#    fixed_warnings
835*9e94795aSAndroid Build Coastguard Workerdef dump_html(flags, output_stream, warning_messages, warning_links,
836*9e94795aSAndroid Build Coastguard Worker              warning_records, header_str, warn_patterns, project_names):
837*9e94795aSAndroid Build Coastguard Worker  """Dump the flags output to output_stream."""
838*9e94795aSAndroid Build Coastguard Worker  writer = make_writer(output_stream)
839*9e94795aSAndroid Build Coastguard Worker  dump_html_prologue('Warnings for ' + header_str, writer, warn_patterns,
840*9e94795aSAndroid Build Coastguard Worker                     project_names)
841*9e94795aSAndroid Build Coastguard Worker  dump_stats(writer, warn_patterns)
842*9e94795aSAndroid Build Coastguard Worker  writer('<br><br>Press &#x2295 to show section content,'
843*9e94795aSAndroid Build Coastguard Worker         ' and &#x2296 to hide the content.')
844*9e94795aSAndroid Build Coastguard Worker  def section1():
845*9e94795aSAndroid Build Coastguard Worker    dump_table_section(writer, 'selected_projects_section',
846*9e94795aSAndroid Build Coastguard Worker                       'Number of warnings in preselected project directories')
847*9e94795aSAndroid Build Coastguard Worker  def section2():
848*9e94795aSAndroid Build Coastguard Worker    dump_dir_file_section(
849*9e94795aSAndroid Build Coastguard Worker        writer, 'directory', 'top_dirs_table',
850*9e94795aSAndroid Build Coastguard Worker        'Directories/Warnings with at least ' +
851*9e94795aSAndroid Build Coastguard Worker        str(LIMIT_PERCENT_WARNINGS) + '% of all cases')
852*9e94795aSAndroid Build Coastguard Worker  def section3():
853*9e94795aSAndroid Build Coastguard Worker    dump_dir_file_section(
854*9e94795aSAndroid Build Coastguard Worker        writer, 'file', 'top_files_table',
855*9e94795aSAndroid Build Coastguard Worker        'Files/Warnings with at least ' +
856*9e94795aSAndroid Build Coastguard Worker        str(LIMIT_PERCENT_WARNINGS) + '% of all or ' +
857*9e94795aSAndroid Build Coastguard Worker        str(LIMIT_WARNINGS_PER_FILE) + ' cases')
858*9e94795aSAndroid Build Coastguard Worker  def section4():
859*9e94795aSAndroid Build Coastguard Worker    writer('<script>')
860*9e94795aSAndroid Build Coastguard Worker    emit_js_data(writer, flags, warning_messages, warning_links,
861*9e94795aSAndroid Build Coastguard Worker                 warning_records, warn_patterns, project_names)
862*9e94795aSAndroid Build Coastguard Worker    writer(SCRIPTS_FOR_WARNING_GROUPS)
863*9e94795aSAndroid Build Coastguard Worker    writer('</script>')
864*9e94795aSAndroid Build Coastguard Worker    dump_section_header(writer, 'all_warnings_section',
865*9e94795aSAndroid Build Coastguard Worker                        'All warnings grouped by severities or projects')
866*9e94795aSAndroid Build Coastguard Worker    writer('<div id="all_warnings_section" style="display:none;">')
867*9e94795aSAndroid Build Coastguard Worker    emit_buttons(writer)
868*9e94795aSAndroid Build Coastguard Worker    # Warning messages are grouped by severities or project names.
869*9e94795aSAndroid Build Coastguard Worker    writer('<br><div id="warning_groups"></div>')
870*9e94795aSAndroid Build Coastguard Worker    if flags.byproject:
871*9e94795aSAndroid Build Coastguard Worker      writer('<script>groupByProject();</script>')
872*9e94795aSAndroid Build Coastguard Worker    else:
873*9e94795aSAndroid Build Coastguard Worker      writer('<script>groupBySeverity();</script>')
874*9e94795aSAndroid Build Coastguard Worker    dump_fixed(writer, warn_patterns)
875*9e94795aSAndroid Build Coastguard Worker    writer('</div>')
876*9e94795aSAndroid Build Coastguard Worker  dump_boxed_section(writer, section1)
877*9e94795aSAndroid Build Coastguard Worker  dump_boxed_section(writer, section2)
878*9e94795aSAndroid Build Coastguard Worker  dump_boxed_section(writer, section3)
879*9e94795aSAndroid Build Coastguard Worker  dump_boxed_section(writer, section4)
880*9e94795aSAndroid Build Coastguard Worker  dump_html_epilogue(writer)
881*9e94795aSAndroid Build Coastguard Worker
882*9e94795aSAndroid Build Coastguard Worker
883*9e94795aSAndroid Build Coastguard Workerdef write_html(flags, project_names, warn_patterns, html_path, warning_messages,
884*9e94795aSAndroid Build Coastguard Worker               warning_links, warning_records, header_str):
885*9e94795aSAndroid Build Coastguard Worker  """Write warnings html file."""
886*9e94795aSAndroid Build Coastguard Worker  if html_path:
887*9e94795aSAndroid Build Coastguard Worker    with open(html_path, 'w') as outf:
888*9e94795aSAndroid Build Coastguard Worker      dump_html(flags, outf, warning_messages, warning_links, warning_records,
889*9e94795aSAndroid Build Coastguard Worker                header_str, warn_patterns, project_names)
890*9e94795aSAndroid Build Coastguard Worker
891*9e94795aSAndroid Build Coastguard Worker
892*9e94795aSAndroid Build Coastguard Workerdef write_out_csv(flags, warn_patterns, warning_messages, warning_links,
893*9e94795aSAndroid Build Coastguard Worker                  warning_records, header_str, project_names):
894*9e94795aSAndroid Build Coastguard Worker  """Write warnings csv file."""
895*9e94795aSAndroid Build Coastguard Worker  if flags.csvpath:
896*9e94795aSAndroid Build Coastguard Worker    with open(flags.csvpath, 'w') as outf:
897*9e94795aSAndroid Build Coastguard Worker      dump_csv(csv.writer(outf, lineterminator='\n'), warn_patterns)
898*9e94795aSAndroid Build Coastguard Worker
899*9e94795aSAndroid Build Coastguard Worker  if flags.csvwithdescription:
900*9e94795aSAndroid Build Coastguard Worker    with open(flags.csvwithdescription, 'w') as outf:
901*9e94795aSAndroid Build Coastguard Worker      dump_csv_with_description(csv.writer(outf, lineterminator='\n'),
902*9e94795aSAndroid Build Coastguard Worker                                warning_records, warning_messages,
903*9e94795aSAndroid Build Coastguard Worker                                warn_patterns, project_names)
904*9e94795aSAndroid Build Coastguard Worker
905*9e94795aSAndroid Build Coastguard Worker  if flags.gencsv:
906*9e94795aSAndroid Build Coastguard Worker    dump_csv(csv.writer(sys.stdout, lineterminator='\n'), warn_patterns)
907*9e94795aSAndroid Build Coastguard Worker  else:
908*9e94795aSAndroid Build Coastguard Worker    dump_html(flags, sys.stdout, warning_messages, warning_links,
909*9e94795aSAndroid Build Coastguard Worker              warning_records, header_str, warn_patterns, project_names)
910