Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 1 | # python3 |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 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 | """Grep warnings messages and output HTML tables or warning counts in CSV. |
| 17 | |
| 18 | Default is to output warnings in HTML tables grouped by warning severity. |
| 19 | Use option --byproject to output tables grouped by source file projects. |
| 20 | Use option --gencsv to output warning counts in CSV format. |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 21 | |
| 22 | Default input file is build.log, which can be changed with the --log flag. |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 23 | """ |
| 24 | |
| 25 | # List of important data structures and functions in this script. |
| 26 | # |
| 27 | # To parse and keep warning message in the input file: |
| 28 | # severity: classification of message severity |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 29 | # warn_patterns: |
| 30 | # warn_patterns[w]['category'] tool that issued the warning, not used now |
| 31 | # warn_patterns[w]['description'] table heading |
| 32 | # warn_patterns[w]['members'] matched warnings from input |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 33 | # warn_patterns[w]['patterns'] regular expressions to match warnings |
| 34 | # warn_patterns[w]['projects'][p] number of warnings of pattern w in p |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 35 | # warn_patterns[w]['severity'] severity tuple |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 36 | # project_list[p][0] project name |
| 37 | # project_list[p][1] regular expression to match a project path |
| 38 | # project_patterns[p] re.compile(project_list[p][1]) |
| 39 | # project_names[p] project_list[p][0] |
| 40 | # warning_messages array of each warning message, without source url |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 41 | # warning_links array of each warning code search link; for 'chrome' |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 42 | # warning_records array of [idx to warn_patterns, |
| 43 | # idx to project_names, |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 44 | # idx to warning_messages, |
| 45 | # idx to warning_links] |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 46 | # parse_input_file |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 47 | # |
| 48 | # To emit html page of warning messages: |
| 49 | # flags: --byproject, --url, --separator |
| 50 | # Old stuff for static html components: |
| 51 | # html_script_style: static html scripts and styles |
| 52 | # htmlbig: |
| 53 | # dump_stats, dump_html_prologue, dump_html_epilogue: |
| 54 | # emit_buttons: |
| 55 | # dump_fixed |
| 56 | # sort_warnings: |
| 57 | # emit_stats_by_project: |
| 58 | # all_patterns, |
| 59 | # findproject, classify_warning |
| 60 | # dump_html |
| 61 | # |
| 62 | # New dynamic HTML page's static JavaScript data: |
| 63 | # Some data are copied from Python to JavaScript, to generate HTML elements. |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 64 | # FlagPlatform flags.platform |
| 65 | # FlagURL flags.url, used by 'android' |
| 66 | # FlagSeparator flags.separator, used by 'android' |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 67 | # SeverityColors: list of colors for all severity levels |
| 68 | # SeverityHeaders: list of headers for all severity levels |
| 69 | # SeverityColumnHeaders: list of column_headers for all severity levels |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 70 | # ProjectNames: project_names, or project_list[*][0] |
| 71 | # WarnPatternsSeverity: warn_patterns[*]['severity'] |
| 72 | # WarnPatternsDescription: warn_patterns[*]['description'] |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 73 | # WarningMessages: warning_messages |
| 74 | # Warnings: warning_records |
| 75 | # StatsHeader: warning count table header row |
| 76 | # StatsRows: array of warning count table rows |
| 77 | # |
| 78 | # New dynamic HTML page's dynamic JavaScript data: |
| 79 | # |
| 80 | # New dynamic HTML related function to emit data: |
| 81 | # escape_string, strip_escape_string, emit_warning_arrays |
| 82 | # emit_js_data(): |
| 83 | |
| 84 | from __future__ import print_function |
| 85 | import argparse |
| 86 | import cgi |
| 87 | import csv |
| 88 | import io |
| 89 | import multiprocessing |
| 90 | import os |
| 91 | import re |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 92 | import sys |
| 93 | |
| 94 | # pylint:disable=relative-beyond-top-level |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 95 | from . import android_project_list |
| 96 | from . import chrome_project_list |
| 97 | from . import cpp_warn_patterns as cpp_patterns |
| 98 | from . import java_warn_patterns as java_patterns |
| 99 | from . import make_warn_patterns as make_patterns |
| 100 | from . import other_warn_patterns as other_patterns |
| 101 | from . import tidy_warn_patterns as tidy_patterns |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 102 | # pylint:disable=g-importing-member |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 103 | from .severity import Severity |
| 104 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 105 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 106 | def parse_args(use_google3): |
| 107 | """Define and parse the args. Return the parse_args() result.""" |
| 108 | parser = argparse.ArgumentParser( |
| 109 | description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) |
| 110 | parser.add_argument('--capacitor_path', default='', |
| 111 | help='Save capacitor warning file to the passed absolute' |
| 112 | ' path') |
| 113 | # csvpath has a different naming than the above path because historically the |
| 114 | # original Android script used csvpath, so other scripts rely on it |
| 115 | parser.add_argument('--csvpath', default='', |
| 116 | help='Save CSV warning file to the passed path') |
| 117 | parser.add_argument('--gencsv', action='store_true', |
| 118 | help='Generate CSV file with number of various warnings') |
| 119 | parser.add_argument('--byproject', action='store_true', |
| 120 | help='Separate warnings in HTML output by project names') |
| 121 | parser.add_argument('--url', default='', |
| 122 | help='Root URL of an Android source code tree prefixed ' |
| 123 | 'before files in warnings') |
| 124 | parser.add_argument('--separator', default='?l=', |
| 125 | help='Separator between the end of a URL and the line ' |
| 126 | 'number argument. e.g. #') |
| 127 | parser.add_argument('--processes', default=multiprocessing.cpu_count(), |
| 128 | type=int, |
| 129 | help='Number of parallel processes to process warnings') |
| 130 | # Old Android build scripts call warn.py without --platform, |
| 131 | # so the default platform is set to 'android'. |
| 132 | parser.add_argument('--platform', default='android', |
| 133 | choices=['chrome', 'android'], |
| 134 | help='Platform of the build log') |
| 135 | # Old Android build scripts call warn.py with only a build.log file path. |
| 136 | parser.add_argument('--log', help='Path to build log file') |
| 137 | parser.add_argument(dest='buildlog', metavar='build.log', |
| 138 | default='build.log', nargs='?', |
| 139 | help='Path to build.log file') |
| 140 | flags = parser.parse_args() |
| 141 | if not flags.log: |
| 142 | flags.log = flags.buildlog |
| 143 | if not use_google3 and not os.path.exists(flags.log): |
| 144 | sys.exit('Cannot find log file: ' + flags.log) |
| 145 | return flags |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 146 | |
| 147 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 148 | def get_project_names(project_list): |
| 149 | """Get project_names from project_list.""" |
| 150 | return [p[0] for p in project_list] |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 151 | |
| 152 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 153 | html_head_scripts = """\ |
| 154 | <script type="text/javascript"> |
| 155 | function expand(id) { |
| 156 | var e = document.getElementById(id); |
| 157 | var f = document.getElementById(id + "_mark"); |
| 158 | if (e.style.display == 'block') { |
| 159 | e.style.display = 'none'; |
| 160 | f.innerHTML = '⊕'; |
| 161 | } |
| 162 | else { |
| 163 | e.style.display = 'block'; |
| 164 | f.innerHTML = '⊖'; |
| 165 | } |
| 166 | }; |
| 167 | function expandCollapse(show) { |
| 168 | for (var id = 1; ; id++) { |
| 169 | var e = document.getElementById(id + ""); |
| 170 | var f = document.getElementById(id + "_mark"); |
| 171 | if (!e || !f) break; |
| 172 | e.style.display = (show ? 'block' : 'none'); |
| 173 | f.innerHTML = (show ? '⊖' : '⊕'); |
| 174 | } |
| 175 | }; |
| 176 | </script> |
| 177 | <style type="text/css"> |
| 178 | th,td{border-collapse:collapse; border:1px solid black;} |
| 179 | .button{color:blue;font-size:110%;font-weight:bolder;} |
| 180 | .bt{color:black;background-color:transparent;border:none;outline:none; |
| 181 | font-size:140%;font-weight:bolder;} |
| 182 | .c0{background-color:#e0e0e0;} |
| 183 | .c1{background-color:#d0d0d0;} |
| 184 | .t1{border-collapse:collapse; width:100%; border:1px solid black;} |
| 185 | </style> |
| 186 | <script src="https://www.gstatic.com/charts/loader.js"></script> |
| 187 | """ |
| 188 | |
| 189 | |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 190 | def make_writer(output_stream): |
| 191 | |
| 192 | def writer(text): |
| 193 | return output_stream.write(text + '\n') |
| 194 | |
| 195 | return writer |
| 196 | |
| 197 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 198 | def html_big(param): |
| 199 | return '<font size="+2">' + param + '</font>' |
| 200 | |
| 201 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 202 | def dump_html_prologue(title, writer, warn_patterns, project_names): |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 203 | writer('<html>\n<head>') |
| 204 | writer('<title>' + title + '</title>') |
| 205 | writer(html_head_scripts) |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 206 | emit_stats_by_project(writer, warn_patterns, project_names) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 207 | writer('</head>\n<body>') |
| 208 | writer(html_big(title)) |
| 209 | writer('<p>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 210 | |
| 211 | |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 212 | def dump_html_epilogue(writer): |
| 213 | writer('</body>\n</head>\n</html>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 214 | |
| 215 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 216 | def sort_warnings(warn_patterns): |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 217 | for i in warn_patterns: |
| 218 | i['members'] = sorted(set(i['members'])) |
| 219 | |
| 220 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 221 | def create_warnings(warn_patterns, project_names): |
| 222 | """Creates warnings s.t. |
| 223 | |
| 224 | warnings[p][s] is as specified in above docs. |
| 225 | |
| 226 | Args: |
| 227 | warn_patterns: list of warning patterns for specified platform |
| 228 | project_names: list of project names |
| 229 | |
| 230 | Returns: |
| 231 | 2D warnings array where warnings[p][s] is # of warnings in project name p of |
| 232 | severity level s |
| 233 | """ |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 234 | # pylint:disable=g-complex-comprehension |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 235 | warnings = {p: {s.value: 0 for s in Severity.levels} for p in project_names} |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 236 | for i in warn_patterns: |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 237 | s = i['severity'].value |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 238 | for p in i['projects']: |
| 239 | warnings[p][s] += i['projects'][p] |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 240 | return warnings |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 241 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 242 | |
| 243 | def get_total_by_project(warnings, project_names): |
| 244 | """Returns dict, project as key and # warnings for that project as value.""" |
| 245 | # pylint:disable=g-complex-comprehension |
| 246 | return { |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 247 | p: sum(warnings[p][s.value] for s in Severity.levels) |
| 248 | for p in project_names |
| 249 | } |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 250 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 251 | |
| 252 | def get_total_by_severity(warnings, project_names): |
| 253 | """Returns dict, severity as key and # warnings of that severity as value.""" |
| 254 | # pylint:disable=g-complex-comprehension |
| 255 | return { |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 256 | s.value: sum(warnings[p][s.value] for p in project_names) |
| 257 | for s in Severity.levels |
| 258 | } |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 259 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 260 | |
| 261 | def emit_table_header(total_by_severity): |
| 262 | """Returns list of HTML-formatted content for severity stats.""" |
| 263 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 264 | stats_header = ['Project'] |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 265 | for s in Severity.levels: |
| 266 | if total_by_severity[s.value]: |
| 267 | stats_header.append( |
| 268 | '<span style=\'background-color:{}\'>{}</span>'.format( |
| 269 | s.color, s.column_header)) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 270 | stats_header.append('TOTAL') |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 271 | return stats_header |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 272 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 273 | |
| 274 | def emit_row_counts_per_project(warnings, total_by_project, total_by_severity, |
| 275 | project_names): |
| 276 | """Returns total project warnings and row of stats for each project. |
| 277 | |
| 278 | Args: |
| 279 | warnings: output of create_warnings(warn_patterns, project_names) |
| 280 | total_by_project: output of get_total_by_project(project_names) |
| 281 | total_by_severity: output of get_total_by_severity(project_names) |
| 282 | project_names: list of project names |
| 283 | |
| 284 | Returns: |
| 285 | total_all_projects, the total number of warnings over all projects |
| 286 | stats_rows, a 2d list where each row is [Project Name, <severity counts>, |
| 287 | total # warnings for this project] |
| 288 | """ |
| 289 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 290 | total_all_projects = 0 |
| 291 | stats_rows = [] |
| 292 | for p in project_names: |
| 293 | if total_by_project[p]: |
| 294 | one_row = [p] |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 295 | for s in Severity.levels: |
| 296 | if total_by_severity[s.value]: |
| 297 | one_row.append(warnings[p][s.value]) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 298 | one_row.append(total_by_project[p]) |
| 299 | stats_rows.append(one_row) |
| 300 | total_all_projects += total_by_project[p] |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 301 | return total_all_projects, stats_rows |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 302 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 303 | |
| 304 | def emit_row_counts_per_severity(total_by_severity, stats_header, stats_rows, |
| 305 | total_all_projects, writer): |
| 306 | """Emits stats_header and stats_rows as specified above. |
| 307 | |
| 308 | Args: |
| 309 | total_by_severity: output of get_total_by_severity() |
| 310 | stats_header: output of emit_table_header() |
| 311 | stats_rows: output of emit_row_counts_per_project() |
| 312 | total_all_projects: output of emit_row_counts_per_project() |
| 313 | writer: writer returned by make_writer(output_stream) |
| 314 | """ |
| 315 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 316 | total_all_severities = 0 |
| 317 | one_row = ['<b>TOTAL</b>'] |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 318 | for s in Severity.levels: |
| 319 | if total_by_severity[s.value]: |
| 320 | one_row.append(total_by_severity[s.value]) |
| 321 | total_all_severities += total_by_severity[s.value] |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 322 | one_row.append(total_all_projects) |
| 323 | stats_rows.append(one_row) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 324 | writer('<script>') |
| 325 | emit_const_string_array('StatsHeader', stats_header, writer) |
| 326 | emit_const_object_array('StatsRows', stats_rows, writer) |
| 327 | writer(draw_table_javascript) |
| 328 | writer('</script>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 329 | |
| 330 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 331 | def emit_stats_by_project(writer, warn_patterns, project_names): |
| 332 | """Dump a google chart table of warnings per project and severity.""" |
| 333 | |
| 334 | warnings = create_warnings(warn_patterns, project_names) |
| 335 | total_by_project = get_total_by_project(warnings, project_names) |
| 336 | total_by_severity = get_total_by_severity(warnings, project_names) |
| 337 | stats_header = emit_table_header(total_by_severity) |
| 338 | total_all_projects, stats_rows = \ |
| 339 | emit_row_counts_per_project(warnings, total_by_project, total_by_severity, project_names) |
| 340 | emit_row_counts_per_severity(total_by_severity, stats_header, stats_rows, |
| 341 | total_all_projects, writer) |
| 342 | |
| 343 | |
| 344 | def dump_stats(writer, warn_patterns): |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 345 | """Dump some stats about total number of warnings and such.""" |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 346 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 347 | known = 0 |
| 348 | skipped = 0 |
| 349 | unknown = 0 |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 350 | sort_warnings(warn_patterns) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 351 | for i in warn_patterns: |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 352 | if i['severity'] == Severity.UNMATCHED: |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 353 | unknown += len(i['members']) |
| 354 | elif i['severity'] == Severity.SKIP: |
| 355 | skipped += len(i['members']) |
| 356 | else: |
| 357 | known += len(i['members']) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 358 | writer('Number of classified warnings: <b>' + str(known) + '</b><br>') |
| 359 | writer('Number of skipped warnings: <b>' + str(skipped) + '</b><br>') |
| 360 | writer('Number of unclassified warnings: <b>' + str(unknown) + '</b><br>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 361 | total = unknown + known + skipped |
| 362 | extra_msg = '' |
| 363 | if total < 1000: |
| 364 | extra_msg = ' (low count may indicate incremental build)' |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 365 | writer('Total number of warnings: <b>' + str(total) + '</b>' + extra_msg) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 366 | |
| 367 | |
| 368 | # New base table of warnings, [severity, warn_id, project, warning_message] |
| 369 | # Need buttons to show warnings in different grouping options. |
| 370 | # (1) Current, group by severity, id for each warning pattern |
| 371 | # sort by severity, warn_id, warning_message |
| 372 | # (2) Current --byproject, group by severity, |
| 373 | # id for each warning pattern + project name |
| 374 | # sort by severity, warn_id, project, warning_message |
| 375 | # (3) New, group by project + severity, |
| 376 | # id for each warning pattern |
| 377 | # sort by project, severity, warn_id, warning_message |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 378 | def emit_buttons(writer): |
| 379 | writer('<button class="button" onclick="expandCollapse(1);">' |
| 380 | 'Expand all warnings</button>\n' |
| 381 | '<button class="button" onclick="expandCollapse(0);">' |
| 382 | 'Collapse all warnings</button>\n' |
| 383 | '<button class="button" onclick="groupBySeverity();">' |
| 384 | 'Group warnings by severity</button>\n' |
| 385 | '<button class="button" onclick="groupByProject();">' |
| 386 | 'Group warnings by project</button><br>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 387 | |
| 388 | |
| 389 | def all_patterns(category): |
| 390 | patterns = '' |
| 391 | for i in category['patterns']: |
| 392 | patterns += i |
| 393 | patterns += ' / ' |
| 394 | return patterns |
| 395 | |
| 396 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 397 | def dump_fixed(writer, warn_patterns): |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 398 | """Show which warnings no longer occur.""" |
| 399 | anchor = 'fixed_warnings' |
| 400 | mark = anchor + '_mark' |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 401 | writer('\n<br><p style="background-color:lightblue"><b>' |
| 402 | '<button id="' + mark + '" ' |
| 403 | 'class="bt" onclick="expand(\'' + anchor + '\');">' |
| 404 | '⊕</button> Fixed warnings. ' |
| 405 | 'No more occurrences. Please consider turning these into ' |
| 406 | 'errors if possible, before they are reintroduced in to the build' |
| 407 | ':</b></p>') |
| 408 | writer('<blockquote>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 409 | fixed_patterns = [] |
| 410 | for i in warn_patterns: |
| 411 | if not i['members']: |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 412 | fixed_patterns.append(i['description'] + ' (' + all_patterns(i) + ')') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 413 | fixed_patterns = sorted(fixed_patterns) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 414 | writer('<div id="' + anchor + '" style="display:none;"><table>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 415 | cur_row_class = 0 |
| 416 | for text in fixed_patterns: |
| 417 | cur_row_class = 1 - cur_row_class |
| 418 | # remove last '\n' |
| 419 | t = text[:-1] if text[-1] == '\n' else text |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 420 | writer('<tr><td class="c' + str(cur_row_class) + '">' + t + '</td></tr>') |
| 421 | writer('</table></div>') |
| 422 | writer('</blockquote>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 423 | |
| 424 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 425 | def write_severity(csvwriter, sev, kind, warn_patterns): |
| 426 | """Count warnings of given severity and write CSV entries to writer.""" |
| 427 | total = 0 |
| 428 | for pattern in warn_patterns: |
| 429 | if pattern['severity'] == sev and pattern['members']: |
| 430 | n = len(pattern['members']) |
| 431 | total += n |
| 432 | warning = kind + ': ' + (pattern['description'] or '?') |
| 433 | csvwriter.writerow([n, '', warning]) |
| 434 | # print number of warnings for each project, ordered by project name |
| 435 | projects = sorted(pattern['projects'].keys()) |
| 436 | for project in projects: |
| 437 | csvwriter.writerow([pattern['projects'][project], project, warning]) |
| 438 | csvwriter.writerow([total, '', kind + ' warnings']) |
| 439 | return total |
| 440 | |
| 441 | |
| 442 | def dump_csv(csvwriter, warn_patterns): |
| 443 | """Dump number of warnings in CSV format to writer.""" |
| 444 | sort_warnings(warn_patterns) |
| 445 | total = 0 |
| 446 | for s in Severity.levels: |
| 447 | total += write_severity(csvwriter, s, s.column_header, warn_patterns) |
| 448 | csvwriter.writerow([total, '', 'All warnings']) |
| 449 | |
| 450 | |
| 451 | def find_project_index(line, project_patterns): |
| 452 | for i, p in enumerate(project_patterns): |
| 453 | if p.match(line): |
| 454 | return i |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 455 | return -1 |
| 456 | |
| 457 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 458 | def classify_one_warning(warning, link, results, project_patterns, |
| 459 | warn_patterns): |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 460 | """Classify one warning line.""" |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 461 | for i, w in enumerate(warn_patterns): |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 462 | for cpat in w['compiled_patterns']: |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 463 | if cpat.match(warning): |
| 464 | p = find_project_index(warning, project_patterns) |
| 465 | results.append([warning, link, i, p]) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 466 | return |
| 467 | else: |
| 468 | # If we end up here, there was a problem parsing the log |
| 469 | # probably caused by 'make -j' mixing the output from |
| 470 | # 2 or more concurrent compiles |
| 471 | pass |
| 472 | |
| 473 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 474 | def remove_prefix(s, sub): |
| 475 | """Remove everything before last occurrence of substring sub in string s.""" |
| 476 | if sub in s: |
| 477 | inc_sub = s.rfind(sub) |
| 478 | return s[inc_sub:] |
| 479 | return s |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 480 | |
| 481 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 482 | # TODO(emmavukelj): Don't have any generate_*_cs_link functions call |
| 483 | # normalize_path a second time (the first time being in parse_input_file) |
| 484 | def generate_cs_link(warning_line, flags, android_root=None): |
| 485 | if flags.platform == 'chrome': |
| 486 | return generate_chrome_cs_link(warning_line, flags) |
| 487 | if flags.platform == 'android': |
| 488 | return generate_android_cs_link(warning_line, flags, android_root) |
| 489 | return 'https://cs.corp.google.com/' |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 490 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 491 | |
| 492 | def generate_android_cs_link(warning_line, flags, android_root): |
| 493 | """Generate the code search link for a warning line in Android.""" |
| 494 | # max_splits=2 -> only 3 items |
| 495 | raw_path, line_number_str, _ = warning_line.split(':', 2) |
| 496 | normalized_path = normalize_path(raw_path, flags, android_root) |
| 497 | if not flags.url: |
| 498 | return normalized_path |
| 499 | link_path = flags.url + '/' + normalized_path |
| 500 | if line_number_str.isdigit(): |
| 501 | link_path += flags.separator + line_number_str |
| 502 | return link_path |
| 503 | |
| 504 | |
| 505 | def generate_chrome_cs_link(warning_line, flags): |
| 506 | """Generate the code search link for a warning line in Chrome.""" |
| 507 | split_line = warning_line.split(':') |
| 508 | raw_path = split_line[0] |
| 509 | normalized_path = normalize_path(raw_path, flags) |
| 510 | link_base = 'https://cs.chromium.org/' |
| 511 | link_add = 'chromium' |
| 512 | link_path = None |
| 513 | |
| 514 | # Basically just going through a few specific directory cases and specifying |
| 515 | # the proper behavior for that case. This list of cases was accumulated |
| 516 | # through trial and error manually going through the warnings. |
| 517 | # |
| 518 | # This code pattern of using case-specific "if"s instead of "elif"s looks |
| 519 | # possibly accidental and mistaken but it is intentional because some paths |
| 520 | # fall under several cases (e.g. third_party/lib/nghttp2_frame.c) and for |
| 521 | # those we want the most specific case to be applied. If there is reliable |
| 522 | # knowledge of exactly where these occur, this could be changed to "elif"s |
| 523 | # but there is no reliable set of paths falling under multiple cases at the |
| 524 | # moment. |
| 525 | if '/src/third_party' in raw_path: |
| 526 | link_path = remove_prefix(raw_path, '/src/third_party/') |
| 527 | if '/chrome_root/src_internal/' in raw_path: |
| 528 | link_path = remove_prefix(raw_path, '/chrome_root/src_internal/') |
| 529 | link_path = link_path[len('/chrome_root'):] # remove chrome_root |
| 530 | if '/chrome_root/src/' in raw_path: |
| 531 | link_path = remove_prefix(raw_path, '/chrome_root/src/') |
| 532 | link_path = link_path[len('/chrome_root'):] # remove chrome_root |
| 533 | if '/libassistant/' in raw_path: |
| 534 | link_add = 'eureka_internal/chromium/src' |
| 535 | link_base = 'https://cs.corp.google.com/' # internal data |
| 536 | link_path = remove_prefix(normalized_path, '/libassistant/') |
| 537 | if raw_path.startswith('gen/'): |
| 538 | link_path = '/src/out/Debug/gen/' + normalized_path |
| 539 | if '/gen/' in raw_path: |
| 540 | return '%s?q=file:%s' % (link_base, remove_prefix(normalized_path, '/gen/')) |
| 541 | |
| 542 | if not link_path and (raw_path.startswith('src/') or |
| 543 | raw_path.startswith('src_internal/')): |
| 544 | link_path = '/%s' % raw_path |
| 545 | |
| 546 | if not link_path: # can't find specific link, send a query |
| 547 | return '%s?q=file:%s' % (link_base, normalized_path) |
| 548 | |
| 549 | line_number = int(split_line[1]) |
| 550 | link = '%s%s%s?l=%d' % (link_base, link_add, link_path, line_number) |
| 551 | return link |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 552 | |
| 553 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 554 | def find_warn_py_and_android_root(path): |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 555 | """Return android source root path if warn.py is found.""" |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 556 | parts = path.split('/') |
| 557 | for idx in reversed(range(2, len(parts))): |
| 558 | root_path = '/'.join(parts[:idx]) |
| 559 | # Android root directory should contain this script. |
| 560 | if os.path.exists(root_path + '/build/make/tools/warn.py'): |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 561 | return root_path |
| 562 | return '' |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 563 | |
| 564 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 565 | def find_android_root(buildlog): |
| 566 | """Guess android source root from common prefix of file paths.""" |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 567 | # Use the longest common prefix of the absolute file paths |
| 568 | # of the first 10000 warning messages as the android_root. |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 569 | warning_lines = [] |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 570 | warning_pattern = re.compile('^/[^ ]*/[^ ]*: warning: .*') |
| 571 | count = 0 |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 572 | for line in buildlog: |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 573 | if warning_pattern.match(line): |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 574 | warning_lines.append(line) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 575 | count += 1 |
| 576 | if count > 9999: |
| 577 | break |
| 578 | # Try to find warn.py and use its location to find |
| 579 | # the source tree root. |
| 580 | if count < 100: |
| 581 | path = os.path.normpath(re.sub(':.*$', '', line)) |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 582 | android_root = find_warn_py_and_android_root(path) |
| 583 | if android_root: |
| 584 | return android_root |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 585 | # Do not use common prefix of a small number of paths. |
| 586 | if count > 10: |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 587 | # pytype: disable=wrong-arg-types |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 588 | root_path = os.path.commonprefix(warning_lines) |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 589 | # pytype: enable=wrong-arg-types |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 590 | if len(root_path) > 2 and root_path[len(root_path) - 1] == '/': |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 591 | return root_path[:-1] |
| 592 | return '' |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 593 | |
| 594 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 595 | def remove_android_root_prefix(path, android_root): |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 596 | """Remove android_root prefix from path if it is found.""" |
| 597 | if path.startswith(android_root): |
| 598 | return path[1 + len(android_root):] |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 599 | return path |
| 600 | |
| 601 | |
| 602 | def normalize_path(path, flags, android_root=None): |
| 603 | """Normalize file path relative to src/ or src-internal/ directory.""" |
| 604 | path = os.path.normpath(path) |
| 605 | |
| 606 | if flags.platform == 'android': |
| 607 | if android_root: |
| 608 | return remove_android_root_prefix(path, android_root) |
| 609 | return path |
| 610 | |
| 611 | # Remove known prefix of root path and normalize the suffix. |
| 612 | idx = path.find('chrome_root/') |
| 613 | if idx >= 0: |
| 614 | # remove chrome_root/, we want path relative to that |
| 615 | return path[idx + len('chrome_root/'):] |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 616 | else: |
| 617 | return path |
| 618 | |
| 619 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 620 | def normalize_warning_line(line, flags, android_root=None): |
| 621 | """Normalize file path relative to src directory in a warning line.""" |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 622 | line = re.sub(u'[\u2018\u2019]', '\'', line) |
| 623 | # replace non-ASCII chars to spaces |
| 624 | line = re.sub(u'[^\x00-\x7f]', ' ', line) |
| 625 | line = line.strip() |
| 626 | first_column = line.find(':') |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 627 | return normalize_path(line[:first_column], flags, |
| 628 | android_root) + line[first_column:] |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 629 | |
| 630 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 631 | def parse_input_file_chrome(infile, flags): |
| 632 | """Parse Chrome input file, collect parameters and warning lines.""" |
| 633 | platform_version = 'unknown' |
| 634 | board_name = 'unknown' |
| 635 | architecture = 'unknown' |
| 636 | |
| 637 | # only handle warning lines of format 'file_path:line_no:col_no: warning: ...' |
| 638 | chrome_warning_pattern = r'^[^ ]*/[^ ]*:[0-9]+:[0-9]+: warning: .*' |
| 639 | |
| 640 | warning_pattern = re.compile(chrome_warning_pattern) |
| 641 | |
| 642 | # Collect all unique warning lines |
| 643 | # Remove the duplicated warnings save ~8% of time when parsing |
| 644 | # one typical build log than before |
| 645 | unique_warnings = dict() |
| 646 | for line in infile: |
| 647 | if warning_pattern.match(line): |
| 648 | normalized_line = normalize_warning_line(line, flags) |
| 649 | if normalized_line not in unique_warnings: |
| 650 | unique_warnings[normalized_line] = generate_cs_link(line, flags) |
| 651 | elif (platform_version == 'unknown' or board_name == 'unknown' or |
| 652 | architecture == 'unknown'): |
| 653 | m = re.match(r'.+Package:.+chromeos-base/chromeos-chrome-', line) |
| 654 | if m is not None: |
| 655 | platform_version = 'R' + line.split('chrome-')[1].split('_')[0] |
| 656 | continue |
| 657 | m = re.match(r'.+Source\sunpacked\sin\s(.+)', line) |
| 658 | if m is not None: |
| 659 | board_name = m.group(1).split('/')[2] |
| 660 | continue |
| 661 | m = re.match(r'.+USE:\s*([^\s]*).*', line) |
| 662 | if m is not None: |
| 663 | architecture = m.group(1) |
| 664 | continue |
| 665 | |
| 666 | header_str = '%s - %s - %s' % (platform_version, board_name, architecture) |
| 667 | return unique_warnings, header_str |
| 668 | |
| 669 | |
| 670 | def add_normalized_line_to_warnings(line, flags, android_root, unique_warnings): |
| 671 | """Parse/normalize path, updating warning line and add to warnings dict.""" |
| 672 | normalized_line = normalize_warning_line(line, flags, android_root) |
| 673 | if normalized_line not in unique_warnings: |
| 674 | unique_warnings[normalized_line] = generate_cs_link(line, flags, |
| 675 | android_root) |
| 676 | return unique_warnings |
| 677 | |
| 678 | |
| 679 | def parse_input_file_android(infile, flags): |
| 680 | """Parse Android input file, collect parameters and warning lines.""" |
| 681 | platform_version = 'unknown' |
| 682 | target_product = 'unknown' |
| 683 | target_variant = 'unknown' |
| 684 | android_root = find_android_root(infile) |
| 685 | infile.seek(0) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 686 | |
| 687 | # rustc warning messages have two lines that should be combined: |
| 688 | # warning: description |
| 689 | # --> file_path:line_number:column_number |
| 690 | # Some warning messages have no file name: |
| 691 | # warning: macro replacement list ... [bugprone-macro-parentheses] |
| 692 | # Some makefile warning messages have no line number: |
| 693 | # some/path/file.mk: warning: description |
| 694 | # C/C++ compiler warning messages have line and column numbers: |
| 695 | # some/path/file.c:line_number:column_number: warning: description |
| 696 | warning_pattern = re.compile('(^[^ ]*/[^ ]*: warning: .*)|(^warning: .*)') |
| 697 | warning_without_file = re.compile('^warning: .*') |
| 698 | rustc_file_position = re.compile('^[ ]+--> [^ ]*/[^ ]*:[0-9]+:[0-9]+') |
| 699 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 700 | # Collect all unique warning lines |
| 701 | # Remove the duplicated warnings save ~8% of time when parsing |
| 702 | # one typical build log than before |
| 703 | unique_warnings = dict() |
| 704 | line_counter = 0 |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 705 | prev_warning = '' |
| 706 | for line in infile: |
| 707 | if prev_warning: |
| 708 | if rustc_file_position.match(line): |
| 709 | # must be a rustc warning, combine 2 lines into one warning |
| 710 | line = line.strip().replace('--> ', '') + ': ' + prev_warning |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 711 | unique_warnings = add_normalized_line_to_warnings( |
| 712 | line, flags, android_root, unique_warnings) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 713 | prev_warning = '' |
| 714 | continue |
| 715 | # add prev_warning, and then process the current line |
| 716 | prev_warning = 'unknown_source_file: ' + prev_warning |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 717 | unique_warnings = add_normalized_line_to_warnings( |
| 718 | prev_warning, flags, android_root, unique_warnings) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 719 | prev_warning = '' |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 720 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 721 | if warning_pattern.match(line): |
| 722 | if warning_without_file.match(line): |
| 723 | # save this line and combine it with the next line |
| 724 | prev_warning = line |
| 725 | else: |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 726 | unique_warnings = add_normalized_line_to_warnings( |
| 727 | line, flags, android_root, unique_warnings) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 728 | continue |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 729 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 730 | if line_counter < 100: |
| 731 | # save a little bit of time by only doing this for the first few lines |
| 732 | line_counter += 1 |
| 733 | m = re.search('(?<=^PLATFORM_VERSION=).*', line) |
| 734 | if m is not None: |
| 735 | platform_version = m.group(0) |
| 736 | m = re.search('(?<=^TARGET_PRODUCT=).*', line) |
| 737 | if m is not None: |
| 738 | target_product = m.group(0) |
| 739 | m = re.search('(?<=^TARGET_BUILD_VARIANT=).*', line) |
| 740 | if m is not None: |
| 741 | target_variant = m.group(0) |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 742 | m = re.search('(?<=^TOP=).*', line) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 743 | if m is not None: |
| 744 | android_root = m.group(1) |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 745 | |
| 746 | if android_root: |
| 747 | new_unique_warnings = dict() |
| 748 | for warning_line in unique_warnings: |
| 749 | normalized_line = normalize_warning_line(warning_line, flags, |
| 750 | android_root) |
| 751 | new_unique_warnings[normalized_line] = generate_android_cs_link( |
| 752 | warning_line, flags, android_root) |
| 753 | unique_warnings = new_unique_warnings |
| 754 | |
| 755 | header_str = '%s - %s - %s' % (platform_version, target_product, |
| 756 | target_variant) |
| 757 | return unique_warnings, header_str |
| 758 | |
| 759 | |
| 760 | def parse_input_file(infile, flags): |
| 761 | if flags.platform == 'chrome': |
| 762 | return parse_input_file_chrome(infile, flags) |
| 763 | if flags.platform == 'android': |
| 764 | return parse_input_file_android(infile, flags) |
| 765 | raise RuntimeError('parse_input_file not defined for platform %s' % |
| 766 | flags.platform) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 767 | |
| 768 | |
| 769 | # Return s with escaped backslash and quotation characters. |
| 770 | def escape_string(s): |
| 771 | return s.replace('\\', '\\\\').replace('"', '\\"') |
| 772 | |
| 773 | |
| 774 | # Return s without trailing '\n' and escape the quotation characters. |
| 775 | def strip_escape_string(s): |
| 776 | if not s: |
| 777 | return s |
| 778 | s = s[:-1] if s[-1] == '\n' else s |
| 779 | return escape_string(s) |
| 780 | |
| 781 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 782 | def emit_warning_array(name, writer, warn_patterns): |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 783 | writer('var warning_{} = ['.format(name)) |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 784 | for w in warn_patterns: |
| 785 | if name == 'severity': |
| 786 | writer('{},'.format(w[name].value)) |
| 787 | else: |
| 788 | writer('{},'.format(w[name])) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 789 | writer('];') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 790 | |
| 791 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 792 | def emit_warning_arrays(writer, warn_patterns): |
| 793 | emit_warning_array('severity', writer, warn_patterns) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 794 | writer('var warning_description = [') |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 795 | for w in warn_patterns: |
| 796 | if w['members']: |
| 797 | writer('"{}",'.format(escape_string(w['description']))) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 798 | else: |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 799 | writer('"",') # no such warning |
| 800 | writer('];') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 801 | |
| 802 | |
| 803 | scripts_for_warning_groups = """ |
| 804 | function compareMessages(x1, x2) { // of the same warning type |
| 805 | return (WarningMessages[x1[2]] <= WarningMessages[x2[2]]) ? -1 : 1; |
| 806 | } |
| 807 | function byMessageCount(x1, x2) { |
| 808 | return x2[2] - x1[2]; // reversed order |
| 809 | } |
| 810 | function bySeverityMessageCount(x1, x2) { |
| 811 | // orer by severity first |
| 812 | if (x1[1] != x2[1]) |
| 813 | return x1[1] - x2[1]; |
| 814 | return byMessageCount(x1, x2); |
| 815 | } |
| 816 | const ParseLinePattern = /^([^ :]+):(\\d+):(.+)/; |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 817 | function addURL(line) { // used by Android |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 818 | if (FlagURL == "") return line; |
| 819 | if (FlagSeparator == "") { |
| 820 | return line.replace(ParseLinePattern, |
| 821 | "<a target='_blank' href='" + FlagURL + "/$1'>$1</a>:$2:$3"); |
| 822 | } |
| 823 | return line.replace(ParseLinePattern, |
| 824 | "<a target='_blank' href='" + FlagURL + "/$1" + FlagSeparator + |
| 825 | "$2'>$1:$2</a>:$3"); |
| 826 | } |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 827 | function addURLToLine(line, link) { // used by Chrome |
| 828 | let line_split = line.split(":"); |
| 829 | let path = line_split.slice(0,3).join(":"); |
| 830 | let msg = line_split.slice(3).join(":"); |
| 831 | let html_link = `<a target="_blank" href="${link}">${path}</a>${msg}`; |
| 832 | return html_link; |
| 833 | } |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 834 | function createArrayOfDictionaries(n) { |
| 835 | var result = []; |
| 836 | for (var i=0; i<n; i++) result.push({}); |
| 837 | return result; |
| 838 | } |
| 839 | function groupWarningsBySeverity() { |
| 840 | // groups is an array of dictionaries, |
| 841 | // each dictionary maps from warning type to array of warning messages. |
| 842 | var groups = createArrayOfDictionaries(SeverityColors.length); |
| 843 | for (var i=0; i<Warnings.length; i++) { |
| 844 | var w = Warnings[i][0]; |
| 845 | var s = WarnPatternsSeverity[w]; |
| 846 | var k = w.toString(); |
| 847 | if (!(k in groups[s])) |
| 848 | groups[s][k] = []; |
| 849 | groups[s][k].push(Warnings[i]); |
| 850 | } |
| 851 | return groups; |
| 852 | } |
| 853 | function groupWarningsByProject() { |
| 854 | var groups = createArrayOfDictionaries(ProjectNames.length); |
| 855 | for (var i=0; i<Warnings.length; i++) { |
| 856 | var w = Warnings[i][0]; |
| 857 | var p = Warnings[i][1]; |
| 858 | var k = w.toString(); |
| 859 | if (!(k in groups[p])) |
| 860 | groups[p][k] = []; |
| 861 | groups[p][k].push(Warnings[i]); |
| 862 | } |
| 863 | return groups; |
| 864 | } |
| 865 | var GlobalAnchor = 0; |
| 866 | function createWarningSection(header, color, group) { |
| 867 | var result = ""; |
| 868 | var groupKeys = []; |
| 869 | var totalMessages = 0; |
| 870 | for (var k in group) { |
| 871 | totalMessages += group[k].length; |
| 872 | groupKeys.push([k, WarnPatternsSeverity[parseInt(k)], group[k].length]); |
| 873 | } |
| 874 | groupKeys.sort(bySeverityMessageCount); |
| 875 | for (var idx=0; idx<groupKeys.length; idx++) { |
| 876 | var k = groupKeys[idx][0]; |
| 877 | var messages = group[k]; |
| 878 | var w = parseInt(k); |
| 879 | var wcolor = SeverityColors[WarnPatternsSeverity[w]]; |
| 880 | var description = WarnPatternsDescription[w]; |
| 881 | if (description.length == 0) |
| 882 | description = "???"; |
| 883 | GlobalAnchor += 1; |
| 884 | result += "<table class='t1'><tr bgcolor='" + wcolor + "'><td>" + |
| 885 | "<button class='bt' id='" + GlobalAnchor + "_mark" + |
| 886 | "' onclick='expand(\\"" + GlobalAnchor + "\\");'>" + |
| 887 | "⊕</button> " + |
| 888 | description + " (" + messages.length + ")</td></tr></table>"; |
| 889 | result += "<div id='" + GlobalAnchor + |
| 890 | "' style='display:none;'><table class='t1'>"; |
| 891 | var c = 0; |
| 892 | messages.sort(compareMessages); |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 893 | if (FlagPlatform == "chrome") { |
| 894 | for (var i=0; i<messages.length; i++) { |
| 895 | result += "<tr><td class='c" + c + "'>" + |
| 896 | addURLToLine(WarningMessages[messages[i][2]], WarningLinks[messages[i][3]]) + "</td></tr>"; |
| 897 | c = 1 - c; |
| 898 | } |
| 899 | } else { |
| 900 | for (var i=0; i<messages.length; i++) { |
| 901 | result += "<tr><td class='c" + c + "'>" + |
| 902 | addURL(WarningMessages[messages[i][2]]) + "</td></tr>"; |
| 903 | c = 1 - c; |
| 904 | } |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 905 | } |
| 906 | result += "</table></div>"; |
| 907 | } |
| 908 | if (result.length > 0) { |
| 909 | return "<br><span style='background-color:" + color + "'><b>" + |
| 910 | header + ": " + totalMessages + |
| 911 | "</b></span><blockquote><table class='t1'>" + |
| 912 | result + "</table></blockquote>"; |
| 913 | |
| 914 | } |
| 915 | return ""; // empty section |
| 916 | } |
| 917 | function generateSectionsBySeverity() { |
| 918 | var result = ""; |
| 919 | var groups = groupWarningsBySeverity(); |
| 920 | for (s=0; s<SeverityColors.length; s++) { |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 921 | result += createWarningSection(SeverityHeaders[s], SeverityColors[s], |
| 922 | groups[s]); |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 923 | } |
| 924 | return result; |
| 925 | } |
| 926 | function generateSectionsByProject() { |
| 927 | var result = ""; |
| 928 | var groups = groupWarningsByProject(); |
| 929 | for (i=0; i<groups.length; i++) { |
| 930 | result += createWarningSection(ProjectNames[i], 'lightgrey', groups[i]); |
| 931 | } |
| 932 | return result; |
| 933 | } |
| 934 | function groupWarnings(generator) { |
| 935 | GlobalAnchor = 0; |
| 936 | var e = document.getElementById("warning_groups"); |
| 937 | e.innerHTML = generator(); |
| 938 | } |
| 939 | function groupBySeverity() { |
| 940 | groupWarnings(generateSectionsBySeverity); |
| 941 | } |
| 942 | function groupByProject() { |
| 943 | groupWarnings(generateSectionsByProject); |
| 944 | } |
| 945 | """ |
| 946 | |
| 947 | |
| 948 | # Emit a JavaScript const string |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 949 | def emit_const_string(name, value, writer): |
| 950 | writer('const ' + name + ' = "' + escape_string(value) + '";') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 951 | |
| 952 | |
| 953 | # Emit a JavaScript const integer array. |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 954 | def emit_const_int_array(name, array, writer): |
| 955 | writer('const ' + name + ' = [') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 956 | for n in array: |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 957 | writer(str(n) + ',') |
| 958 | writer('];') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 959 | |
| 960 | |
| 961 | # Emit a JavaScript const string array. |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 962 | def emit_const_string_array(name, array, writer): |
| 963 | writer('const ' + name + ' = [') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 964 | for s in array: |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 965 | writer('"' + strip_escape_string(s) + '",') |
| 966 | writer('];') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 967 | |
| 968 | |
| 969 | # Emit a JavaScript const string array for HTML. |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 970 | def emit_const_html_string_array(name, array, writer): |
| 971 | writer('const ' + name + ' = [') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 972 | for s in array: |
| 973 | # Not using html.escape yet, to work for both python 2 and 3, |
| 974 | # until all users switch to python 3. |
| 975 | # pylint:disable=deprecated-method |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 976 | writer('"' + cgi.escape(strip_escape_string(s)) + '",') |
| 977 | writer('];') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 978 | |
| 979 | |
| 980 | # Emit a JavaScript const object array. |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 981 | def emit_const_object_array(name, array, writer): |
| 982 | writer('const ' + name + ' = [') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 983 | for x in array: |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 984 | writer(str(x) + ',') |
| 985 | writer('];') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 986 | |
| 987 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 988 | def emit_js_data(writer, flags, warning_messages, warning_links, |
| 989 | warning_records, warn_patterns, project_names): |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 990 | """Dump dynamic HTML page's static JavaScript data.""" |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 991 | emit_const_string('FlagPlatform', flags.platform, writer) |
| 992 | emit_const_string('FlagURL', flags.url, writer) |
| 993 | emit_const_string('FlagSeparator', flags.separator, writer) |
| 994 | emit_const_string_array('SeverityColors', [s.color for s in Severity.levels], |
| 995 | writer) |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 996 | emit_const_string_array('SeverityHeaders', |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 997 | [s.header for s in Severity.levels], writer) |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 998 | emit_const_string_array('SeverityColumnHeaders', |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 999 | [s.column_header for s in Severity.levels], writer) |
| 1000 | emit_const_string_array('ProjectNames', project_names, writer) |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 1001 | # pytype: disable=attribute-error |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1002 | emit_const_int_array('WarnPatternsSeverity', |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1003 | [w['severity'].value for w in warn_patterns], writer) |
Chih-Hung Hsieh | 949205a | 2020-01-10 10:33:40 -0800 | [diff] [blame] | 1004 | # pytype: enable=attribute-error |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1005 | emit_const_html_string_array('WarnPatternsDescription', |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1006 | [w['description'] for w in warn_patterns], |
| 1007 | writer) |
| 1008 | emit_const_html_string_array('WarningMessages', warning_messages, writer) |
| 1009 | emit_const_object_array('Warnings', warning_records, writer) |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1010 | if flags.platform == 'chrome': |
| 1011 | emit_const_html_string_array('WarningLinks', warning_links, writer) |
| 1012 | |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1013 | |
| 1014 | draw_table_javascript = """ |
| 1015 | google.charts.load('current', {'packages':['table']}); |
| 1016 | google.charts.setOnLoadCallback(drawTable); |
| 1017 | function drawTable() { |
| 1018 | var data = new google.visualization.DataTable(); |
| 1019 | data.addColumn('string', StatsHeader[0]); |
| 1020 | for (var i=1; i<StatsHeader.length; i++) { |
| 1021 | data.addColumn('number', StatsHeader[i]); |
| 1022 | } |
| 1023 | data.addRows(StatsRows); |
| 1024 | for (var i=0; i<StatsRows.length; i++) { |
| 1025 | for (var j=0; j<StatsHeader.length; j++) { |
| 1026 | data.setProperty(i, j, 'style', 'border:1px solid black;'); |
| 1027 | } |
| 1028 | } |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1029 | var table = new google.visualization.Table( |
| 1030 | document.getElementById('stats_table')); |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1031 | table.draw(data, {allowHtml: true, alternatingRowStyle: true}); |
| 1032 | } |
| 1033 | """ |
| 1034 | |
| 1035 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1036 | def dump_html(flags, output_stream, warning_messages, warning_links, |
| 1037 | warning_records, header_str, warn_patterns, project_names): |
| 1038 | """Dump the flags output to output_stream.""" |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1039 | writer = make_writer(output_stream) |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1040 | dump_html_prologue('Warnings for ' + header_str, writer, warn_patterns, |
| 1041 | project_names) |
| 1042 | dump_stats(writer, warn_patterns) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1043 | writer('<br><div id="stats_table"></div><br>') |
| 1044 | writer('\n<script>') |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1045 | emit_js_data(writer, flags, warning_messages, warning_links, warning_records, |
| 1046 | warn_patterns, project_names) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1047 | writer(scripts_for_warning_groups) |
| 1048 | writer('</script>') |
| 1049 | emit_buttons(writer) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1050 | # Warning messages are grouped by severities or project names. |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1051 | writer('<br><div id="warning_groups"></div>') |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1052 | if flags.byproject: |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1053 | writer('<script>groupByProject();</script>') |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1054 | else: |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1055 | writer('<script>groupBySeverity();</script>') |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1056 | dump_fixed(writer, warn_patterns) |
Chih-Hung Hsieh | 5392cdb | 2020-01-13 14:05:17 -0800 | [diff] [blame] | 1057 | dump_html_epilogue(writer) |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1058 | |
| 1059 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1060 | def parse_compiler_output(compiler_output): |
| 1061 | """Parse compiler output for relevant info.""" |
| 1062 | split_output = compiler_output.split(':', 3) # 3 = max splits |
| 1063 | file_path = split_output[0] |
| 1064 | line_number = int(split_output[1]) |
| 1065 | col_number = int(split_output[2].split(' ')[0]) |
| 1066 | warning_message = split_output[3] |
| 1067 | return file_path, line_number, col_number, warning_message |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1068 | |
| 1069 | |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1070 | def get_warn_patterns(platform): |
| 1071 | """Get and initialize warn_patterns.""" |
| 1072 | warn_patterns = [] |
| 1073 | if platform == 'chrome': |
| 1074 | warn_patterns = cpp_patterns.warn_patterns |
| 1075 | elif platform == 'android': |
| 1076 | warn_patterns = make_patterns.warn_patterns + cpp_patterns.warn_patterns + java_patterns.warn_patterns + tidy_patterns.warn_patterns + other_patterns.warn_patterns |
Chih-Hung Hsieh | 888d143 | 2019-12-09 19:32:03 -0800 | [diff] [blame] | 1077 | else: |
Chih-Hung Hsieh | 5ae5519 | 2020-02-24 10:20:36 -0800 | [diff] [blame^] | 1078 | raise Exception('platform name %s is not valid' % platform) |
| 1079 | for w in warn_patterns: |
| 1080 | w['members'] = [] |
| 1081 | # Each warning pattern has a 'projects' dictionary, that |
| 1082 | # maps a project name to number of warnings in that project. |
| 1083 | w['projects'] = {} |
| 1084 | return warn_patterns |
| 1085 | |
| 1086 | |
| 1087 | def get_project_list(platform): |
| 1088 | """Return project list for appropriate platform.""" |
| 1089 | if platform == 'chrome': |
| 1090 | return chrome_project_list.project_list |
| 1091 | if platform == 'android': |
| 1092 | return android_project_list.project_list |
| 1093 | raise Exception('platform name %s is not valid' % platform) |
| 1094 | |
| 1095 | |
| 1096 | def parallel_classify_warnings(warning_data, args, project_names, |
| 1097 | project_patterns, warn_patterns, |
| 1098 | use_google3, create_launch_subprocs_fn, |
| 1099 | classify_warnings_fn): |
| 1100 | """Classify all warning lines with num_cpu parallel processes.""" |
| 1101 | num_cpu = args.processes |
| 1102 | group_results = [] |
| 1103 | |
| 1104 | if num_cpu > 1: |
| 1105 | # set up parallel processing for this... |
| 1106 | warning_groups = [[] for _ in range(num_cpu)] |
| 1107 | i = 0 |
| 1108 | for warning, link in warning_data.items(): |
| 1109 | warning_groups[i].append((warning, link)) |
| 1110 | i = (i + 1) % num_cpu |
| 1111 | arg_groups = [[] for _ in range(num_cpu)] |
| 1112 | for i, group in enumerate(warning_groups): |
| 1113 | arg_groups[i] = [{ |
| 1114 | 'group': group, |
| 1115 | 'project_patterns': project_patterns, |
| 1116 | 'warn_patterns': warn_patterns, |
| 1117 | 'num_processes': num_cpu |
| 1118 | }] |
| 1119 | |
| 1120 | group_results = create_launch_subprocs_fn(num_cpu, |
| 1121 | classify_warnings_fn, |
| 1122 | arg_groups, |
| 1123 | group_results) |
| 1124 | else: |
| 1125 | group_results = [] |
| 1126 | for warning, link in warning_data.items(): |
| 1127 | classify_one_warning(warning, link, group_results, |
| 1128 | project_patterns, warn_patterns) |
| 1129 | group_results = [group_results] |
| 1130 | |
| 1131 | warning_messages = [] |
| 1132 | warning_links = [] |
| 1133 | warning_records = [] |
| 1134 | if use_google3: |
| 1135 | group_results = [group_results] |
| 1136 | for group_result in group_results: |
| 1137 | for result in group_result: |
| 1138 | for line, link, pattern_idx, project_idx in result: |
| 1139 | pattern = warn_patterns[pattern_idx] |
| 1140 | pattern['members'].append(line) |
| 1141 | message_idx = len(warning_messages) |
| 1142 | warning_messages.append(line) |
| 1143 | link_idx = len(warning_links) |
| 1144 | warning_links.append(link) |
| 1145 | warning_records.append([pattern_idx, project_idx, message_idx, |
| 1146 | link_idx]) |
| 1147 | pname = '???' if project_idx < 0 else project_names[project_idx] |
| 1148 | # Count warnings by project. |
| 1149 | if pname in pattern['projects']: |
| 1150 | pattern['projects'][pname] += 1 |
| 1151 | else: |
| 1152 | pattern['projects'][pname] = 1 |
| 1153 | return warning_messages, warning_links, warning_records |
| 1154 | |
| 1155 | |
| 1156 | def write_html(flags, project_names, warn_patterns, html_path, warning_messages, |
| 1157 | warning_links, warning_records, header_str): |
| 1158 | """Write warnings html file.""" |
| 1159 | if html_path: |
| 1160 | with open(html_path, 'w') as f: |
| 1161 | dump_html(flags, f, warning_messages, warning_links, warning_records, |
| 1162 | header_str, warn_patterns, project_names) |
| 1163 | |
| 1164 | |
| 1165 | def write_out_csv(flags, warn_patterns, warning_messages, warning_links, |
| 1166 | warning_records, header_str, project_names): |
| 1167 | """Write warnings csv file.""" |
| 1168 | if flags.csvpath: |
| 1169 | with open(flags.csvpath, 'w') as f: |
| 1170 | dump_csv(csv.writer(f, lineterminator='\n'), warn_patterns) |
| 1171 | |
| 1172 | if flags.gencsv: |
| 1173 | dump_csv(csv.writer(sys.stdout, lineterminator='\n'), warn_patterns) |
| 1174 | else: |
| 1175 | dump_html(flags, sys.stdout, warning_messages, warning_links, |
| 1176 | warning_records, header_str, warn_patterns, project_names) |
| 1177 | |
| 1178 | |
| 1179 | def process_log(logfile, flags, project_names, project_patterns, warn_patterns, |
| 1180 | html_path, use_google3, create_launch_subprocs_fn, |
| 1181 | classify_warnings_fn, logfile_object): |
| 1182 | # pylint: disable=g-doc-args |
| 1183 | # pylint: disable=g-doc-return-or-yield |
| 1184 | """Function that handles processing of a log. |
| 1185 | |
| 1186 | This is isolated into its own function (rather than just taking place in main) |
| 1187 | so that it can be used by both warn.py and the borg job process_gs_logs.py, to |
| 1188 | avoid duplication of code. |
| 1189 | Note that if the arguments to this function change, process_gs_logs.py must |
| 1190 | be updated accordingly. |
| 1191 | """ |
| 1192 | if logfile_object is None: |
| 1193 | with io.open(logfile, encoding='utf-8') as log: |
| 1194 | warning_lines_and_links, header_str = parse_input_file(log, flags) |
| 1195 | else: |
| 1196 | warning_lines_and_links, header_str = parse_input_file( |
| 1197 | logfile_object, flags) |
| 1198 | warning_messages, warning_links, warning_records = parallel_classify_warnings( |
| 1199 | warning_lines_and_links, flags, project_names, project_patterns, |
| 1200 | warn_patterns, use_google3, create_launch_subprocs_fn, |
| 1201 | classify_warnings_fn) |
| 1202 | |
| 1203 | write_html(flags, project_names, warn_patterns, html_path, |
| 1204 | warning_messages, warning_links, warning_records, |
| 1205 | header_str) |
| 1206 | |
| 1207 | return warning_messages, warning_links, warning_records, header_str |
| 1208 | |
| 1209 | |
| 1210 | def common_main(use_google3, create_launch_subprocs_fn, classify_warnings_fn, |
| 1211 | logfile_object=None): |
| 1212 | """Shared main function for Google3 and non-Google3 versions of warn.py.""" |
| 1213 | flags = parse_args(use_google3) |
| 1214 | warn_patterns = get_warn_patterns(flags.platform) |
| 1215 | project_list = get_project_list(flags.platform) |
| 1216 | |
| 1217 | project_names = get_project_names(project_list) |
| 1218 | project_patterns = [re.compile(p[1]) for p in project_list] |
| 1219 | |
| 1220 | # html_path=None because we output html below if not outputting CSV |
| 1221 | warning_messages, warning_links, warning_records, header_str = process_log( |
| 1222 | logfile=flags.log, flags=flags, project_names=project_names, |
| 1223 | project_patterns=project_patterns, warn_patterns=warn_patterns, |
| 1224 | html_path=None, use_google3=use_google3, |
| 1225 | create_launch_subprocs_fn=create_launch_subprocs_fn, |
| 1226 | classify_warnings_fn=classify_warnings_fn, |
| 1227 | logfile_object=logfile_object) |
| 1228 | |
| 1229 | write_out_csv(flags, warn_patterns, warning_messages, warning_links, |
| 1230 | warning_records, header_str, project_names) |
| 1231 | |
| 1232 | # Return these values, so that caller can use them, if desired. |
| 1233 | return flags, warning_messages, warning_records, warn_patterns |