Merge "Fix Google pylint warnings." am: bcd229277a
am: 64af14a4d2
Change-Id: I332da66829738d6793ca1795103f903271f235c6
This commit is contained in:
commit
14a22e9222
437
tools/warn.py
437
tools/warn.py
|
@ -1,17 +1,24 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/python
|
||||||
# This file uses the following encoding: utf-8
|
# This file uses the following encoding: utf-8
|
||||||
|
|
||||||
|
"""Grep warnings messages and output HTML tables or warning counts in CSV.
|
||||||
|
|
||||||
|
Default is to output warnings in HTML tables grouped by warning severity.
|
||||||
|
Use option --byproject to output tables grouped by source file projects.
|
||||||
|
Use option --gencsv to output warning counts in CSV format.
|
||||||
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import re
|
import re
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Convert a build log into HTML')
|
parser = argparse.ArgumentParser(description='Convert a build log into HTML')
|
||||||
parser.add_argument('--gencsv',
|
parser.add_argument('--gencsv',
|
||||||
help='Generate a CSV file with number of various warnings',
|
help='Generate a CSV file with number of various warnings',
|
||||||
action="store_true",
|
action='store_true',
|
||||||
default=False)
|
default=False)
|
||||||
parser.add_argument('--byproject',
|
parser.add_argument('--byproject',
|
||||||
help='Separate warnings in HTML output by project names',
|
help='Separate warnings in HTML output by project names',
|
||||||
action="store_true",
|
action='store_true',
|
||||||
default=False)
|
default=False)
|
||||||
parser.add_argument('--url',
|
parser.add_argument('--url',
|
||||||
help='Root URL of an Android source code tree prefixed '
|
help='Root URL of an Android source code tree prefixed '
|
||||||
|
@ -23,8 +30,10 @@ parser.add_argument(dest='buildlog', metavar='build.log',
|
||||||
help='Path to build.log file')
|
help='Path to build.log file')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
# if you add another level, don't forget to give it a color below
|
# if you add another level, don't forget to give it a color below
|
||||||
class severity:
|
class severity: # pylint:disable=invalid-name,old-style-class
|
||||||
|
"""Severity levels and attributes."""
|
||||||
UNKNOWN = 0
|
UNKNOWN = 0
|
||||||
FIXMENOW = 1
|
FIXMENOW = 1
|
||||||
HIGH = 2
|
HIGH = 2
|
||||||
|
@ -34,6 +43,7 @@ class severity:
|
||||||
HARMLESS = 6
|
HARMLESS = 6
|
||||||
SKIP = 7
|
SKIP = 7
|
||||||
attributes = [
|
attributes = [
|
||||||
|
# pylint:disable=bad-whitespace
|
||||||
['lightblue', 'Unknown', 'Unknown warnings'],
|
['lightblue', 'Unknown', 'Unknown warnings'],
|
||||||
['fuchsia', 'FixNow', 'Critical warnings, fix me now'],
|
['fuchsia', 'FixNow', 'Critical warnings, fix me now'],
|
||||||
['red', 'High', 'High severity warnings'],
|
['red', 'High', 'High severity warnings'],
|
||||||
|
@ -44,12 +54,15 @@ class severity:
|
||||||
['grey', 'Unhandled', 'Unhandled warnings']
|
['grey', 'Unhandled', 'Unhandled warnings']
|
||||||
]
|
]
|
||||||
color = [a[0] for a in attributes]
|
color = [a[0] for a in attributes]
|
||||||
columnheader = [a[1] for a in attributes]
|
column_headers = [a[1] for a in attributes]
|
||||||
header = [a[2] for a in attributes]
|
header = [a[2] for a in attributes]
|
||||||
# order to dump by severity
|
# order to dump by severity
|
||||||
kinds = [FIXMENOW, HIGH, MEDIUM, LOW, TIDY, HARMLESS, UNKNOWN, SKIP]
|
kinds = [FIXMENOW, HIGH, MEDIUM, LOW, TIDY, HARMLESS, UNKNOWN, SKIP]
|
||||||
|
|
||||||
warnpatterns = [
|
warn_patterns = [
|
||||||
|
# TODO(chh): fix pylint space and indentation warnings
|
||||||
|
# pylint:disable=bad-whitespace,bad-continuation,
|
||||||
|
# pylint:disable=line-too-long,g-inconsistent-quotes
|
||||||
{ 'category':'make', 'severity':severity.MEDIUM,
|
{ 'category':'make', 'severity':severity.MEDIUM,
|
||||||
'description':'make: overriding commands/ignoring old commands',
|
'description':'make: overriding commands/ignoring old commands',
|
||||||
'patterns':[r".*: warning: overriding commands for target .+",
|
'patterns':[r".*: warning: overriding commands for target .+",
|
||||||
|
@ -1158,6 +1171,8 @@ warnpatterns = [
|
||||||
{ 'category':'C/C++', 'severity':severity.MEDIUM, 'option':'-Wmissing-noreturn',
|
{ 'category':'C/C++', 'severity':severity.MEDIUM, 'option':'-Wmissing-noreturn',
|
||||||
'description':'Missing noreturn',
|
'description':'Missing noreturn',
|
||||||
'patterns':[r".*: warning: function '.*' could be declared with attribute 'noreturn'"] },
|
'patterns':[r".*: warning: function '.*' could be declared with attribute 'noreturn'"] },
|
||||||
|
# pylint:disable=anomalous-backslash-in-string
|
||||||
|
# TODO(chh): fix the backslash pylint warning.
|
||||||
{ 'category':'gcc', 'severity':severity.MEDIUM,
|
{ 'category':'gcc', 'severity':severity.MEDIUM,
|
||||||
'description':'Invalid option for C file',
|
'description':'Invalid option for C file',
|
||||||
'patterns':[r".*: warning: command line option "".+"" is valid for C\+\+\/ObjC\+\+ but not for C"] },
|
'patterns':[r".*: warning: command line option "".+"" is valid for C\+\+\/ObjC\+\+ but not for C"] },
|
||||||
|
@ -1577,14 +1592,11 @@ warnpatterns = [
|
||||||
'patterns':[r".*: warning: .+"] },
|
'patterns':[r".*: warning: .+"] },
|
||||||
]
|
]
|
||||||
|
|
||||||
for w in warnpatterns:
|
|
||||||
w['members'] = []
|
|
||||||
if 'option' not in w:
|
|
||||||
w['option'] = ''
|
|
||||||
|
|
||||||
# A list of [project_name, file_path_pattern].
|
# A list of [project_name, file_path_pattern].
|
||||||
# project_name should not contain comma, to be used in CSV output.
|
# project_name should not contain comma, to be used in CSV output.
|
||||||
projectlist = [
|
project_list = [
|
||||||
|
# pylint:disable=bad-whitespace,g-inconsistent-quotes,line-too-long
|
||||||
['art', r"(^|.*/)art/.*: warning:"],
|
['art', r"(^|.*/)art/.*: warning:"],
|
||||||
['bionic', r"(^|.*/)bionic/.*: warning:"],
|
['bionic', r"(^|.*/)bionic/.*: warning:"],
|
||||||
['bootable', r"(^|.*/)bootable/.*: warning:"],
|
['bootable', r"(^|.*/)bootable/.*: warning:"],
|
||||||
|
@ -1619,24 +1631,37 @@ projectlist = [
|
||||||
['other', r".*: warning:"],
|
['other', r".*: warning:"],
|
||||||
]
|
]
|
||||||
|
|
||||||
projectpatterns = []
|
project_patterns = []
|
||||||
for p in projectlist:
|
project_names = []
|
||||||
projectpatterns.append({'description':p[0], 'members':[], 'pattern':re.compile(p[1])})
|
|
||||||
|
|
||||||
projectnames = [p[0] for p in projectlist]
|
|
||||||
|
|
||||||
# Each warning pattern has 3 dictionaries:
|
def initialize_arrays():
|
||||||
# (1) 'projects' maps a project name to number of warnings in that project.
|
"""Complete global arrays before they are used."""
|
||||||
# (2) 'projectanchor' maps a project name to its anchor number for HTML.
|
global project_names
|
||||||
# (3) 'projectwarning' maps a project name to a list of warning of that project.
|
project_names = [p[0] for p in project_list]
|
||||||
for w in warnpatterns:
|
for p in project_list:
|
||||||
|
project_patterns.append({'description': p[0],
|
||||||
|
'members': [],
|
||||||
|
'pattern': re.compile(p[1])})
|
||||||
|
# Each warning pattern has 3 dictionaries:
|
||||||
|
# (1) 'projects' maps a project name to number of warnings in that project.
|
||||||
|
# (2) 'project_anchor' maps a project name to its anchor number for HTML.
|
||||||
|
# (3) 'project_warnings' maps a project name to a list of warning messages.
|
||||||
|
for w in warn_patterns:
|
||||||
|
w['members'] = []
|
||||||
|
if 'option' not in w:
|
||||||
|
w['option'] = ''
|
||||||
w['projects'] = {}
|
w['projects'] = {}
|
||||||
w['projectanchor'] = {}
|
w['project_anchor'] = {}
|
||||||
w['projectwarning'] = {}
|
w['project_warnings'] = {}
|
||||||
|
|
||||||
platformversion = 'unknown'
|
|
||||||
targetproduct = 'unknown'
|
initialize_arrays()
|
||||||
targetvariant = 'unknown'
|
|
||||||
|
|
||||||
|
platform_version = 'unknown'
|
||||||
|
target_product = 'unknown'
|
||||||
|
target_variant = 'unknown'
|
||||||
|
|
||||||
|
|
||||||
##### Data and functions to dump html file. ##################################
|
##### Data and functions to dump html file. ##################################
|
||||||
|
@ -1682,100 +1707,104 @@ html_script_style = """\
|
||||||
def output(text):
|
def output(text):
|
||||||
print text,
|
print text,
|
||||||
|
|
||||||
def htmlbig(param):
|
|
||||||
|
def html_big(param):
|
||||||
return '<font size="+2">' + param + '</font>'
|
return '<font size="+2">' + param + '</font>'
|
||||||
|
|
||||||
def dumphtmlprologue(title):
|
|
||||||
|
def dump_html_prologue(title):
|
||||||
output('<html>\n<head>\n')
|
output('<html>\n<head>\n')
|
||||||
output('<title>' + title + '</title>\n')
|
output('<title>' + title + '</title>\n')
|
||||||
output(html_script_style)
|
output(html_script_style)
|
||||||
output('</head>\n<body>\n')
|
output('</head>\n<body>\n')
|
||||||
output(htmlbig(title))
|
output(html_big(title))
|
||||||
output('<p>\n')
|
output('<p>\n')
|
||||||
|
|
||||||
def dumphtmlepilogue():
|
|
||||||
|
def dump_html_epilogue():
|
||||||
output('</body>\n</head>\n</html>\n')
|
output('</body>\n</head>\n</html>\n')
|
||||||
|
|
||||||
def tablerow(text):
|
|
||||||
|
def table_row(text):
|
||||||
global cur_row_class
|
global cur_row_class
|
||||||
cur_row_class = 1 - cur_row_class
|
cur_row_class = 1 - cur_row_class
|
||||||
# remove last '\n'
|
# remove last '\n'
|
||||||
t = text[:-1] if text[-1] == '\n' else text
|
t = text[:-1] if text[-1] == '\n' else text
|
||||||
output('<tr><td class="c' + str(cur_row_class) + '">' + t + '</td></tr>\n')
|
output('<tr><td class="c' + str(cur_row_class) + '">' + t + '</td></tr>\n')
|
||||||
|
|
||||||
def sortwarnings():
|
|
||||||
for i in warnpatterns:
|
def sort_warnings():
|
||||||
|
for i in warn_patterns:
|
||||||
i['members'] = sorted(set(i['members']))
|
i['members'] = sorted(set(i['members']))
|
||||||
|
|
||||||
# dump a table of warnings per project and severity
|
|
||||||
def dumpstatsbyproject():
|
|
||||||
projects = set(projectnames)
|
|
||||||
severities = set(severity.kinds)
|
|
||||||
|
|
||||||
|
def dump_stats_by_project():
|
||||||
|
"""Dump a table of warnings per project and severity."""
|
||||||
# warnings[p][s] is number of warnings in project p of severity s.
|
# warnings[p][s] is number of warnings in project p of severity s.
|
||||||
warnings = {p:{s:0 for s in severity.kinds} for p in projectnames}
|
warnings = {p: {s: 0 for s in severity.kinds} for p in project_names}
|
||||||
for i in warnpatterns:
|
for i in warn_patterns:
|
||||||
s = i['severity']
|
s = i['severity']
|
||||||
for p in i['projects']:
|
for p in i['projects']:
|
||||||
warnings[p][s] += i['projects'][p]
|
warnings[p][s] += i['projects'][p]
|
||||||
|
|
||||||
# totalbyproject[p] is number of warnings in project p.
|
# total_by_project[p] is number of warnings in project p.
|
||||||
totalbyproject = {p:sum(warnings[p][s] for s in severity.kinds)
|
total_by_project = {p: sum(warnings[p][s] for s in severity.kinds)
|
||||||
for p in projectnames}
|
for p in project_names}
|
||||||
|
|
||||||
# totalbyseverity[s] is number of warnings of severity s.
|
# total_by_severity[s] is number of warnings of severity s.
|
||||||
totalbyseverity = {s:sum(warnings[p][s] for p in projectnames)
|
total_by_severity = {s: sum(warnings[p][s] for p in project_names)
|
||||||
for s in severity.kinds}
|
for s in severity.kinds}
|
||||||
|
|
||||||
# emit table header
|
# emit table header
|
||||||
output('<blockquote><table border=1>\n<tr><th>Project</th>\n')
|
output('<blockquote><table border=1>\n<tr><th>Project</th>\n')
|
||||||
for s in severity.kinds:
|
for s in severity.kinds:
|
||||||
if totalbyseverity[s]:
|
if total_by_severity[s]:
|
||||||
output('<th width="8%"><span style="background-color:{}">{}</span></th>'.
|
output('<th width="8%"><span style="background-color:{}">{}</span></th>'.
|
||||||
format(severity.color[s], severity.columnheader[s]))
|
format(severity.color[s], severity.column_headers[s]))
|
||||||
output('<th>TOTAL</th></tr>\n')
|
output('<th>TOTAL</th></tr>\n')
|
||||||
|
|
||||||
# emit a row of warning counts per project, skip no-warning projects
|
# emit a row of warning counts per project, skip no-warning projects
|
||||||
totalallprojects = 0
|
total_all_projects = 0
|
||||||
for p in projectnames:
|
for p in project_names:
|
||||||
if totalbyproject[p]:
|
if total_by_project[p]:
|
||||||
output('<tr><td align="left">{}</td>'.format(p))
|
output('<tr><td align="left">{}</td>'.format(p))
|
||||||
for s in severity.kinds:
|
for s in severity.kinds:
|
||||||
if totalbyseverity[s]:
|
if total_by_severity[s]:
|
||||||
output('<td align="right">{}</td>'.format(warnings[p][s]))
|
output('<td align="right">{}</td>'.format(warnings[p][s]))
|
||||||
output('<td align="right">{}</td>'.format(totalbyproject[p]))
|
output('<td align="right">{}</td>'.format(total_by_project[p]))
|
||||||
totalallprojects += totalbyproject[p]
|
total_all_projects += total_by_project[p]
|
||||||
output('</tr>\n')
|
output('</tr>\n')
|
||||||
|
|
||||||
# emit a row of warning counts per severity
|
# emit a row of warning counts per severity
|
||||||
totalallseverities = 0
|
total_all_severities = 0
|
||||||
output('<tr><td align="right">TOTAL</td>')
|
output('<tr><td align="right">TOTAL</td>')
|
||||||
for s in severity.kinds:
|
for s in severity.kinds:
|
||||||
if totalbyseverity[s]:
|
if total_by_severity[s]:
|
||||||
output('<td align="right">{}</td>'.format(totalbyseverity[s]))
|
output('<td align="right">{}</td>'.format(total_by_severity[s]))
|
||||||
totalallseverities += totalbyseverity[s]
|
total_all_severities += total_by_severity[s]
|
||||||
output('<td align="right">{}</td></tr>\n'.format(totalallprojects))
|
output('<td align="right">{}</td></tr>\n'.format(total_all_projects))
|
||||||
|
|
||||||
# at the end of table, verify total counts
|
# at the end of table, verify total counts
|
||||||
output('</table></blockquote><br>\n')
|
output('</table></blockquote><br>\n')
|
||||||
if totalallprojects != totalallseverities:
|
if total_all_projects != total_all_severities:
|
||||||
output('<h3>ERROR: Sum of warnings by project ' +
|
output('<h3>ERROR: Sum of warnings by project '
|
||||||
'!= Sum of warnings by severity.</h3>\n')
|
'!= Sum of warnings by severity.</h3>\n')
|
||||||
|
|
||||||
# dump some stats about total number of warnings and such
|
|
||||||
def dumpstats():
|
def dump_stats():
|
||||||
|
"""Dump some stats about total number of warnings and such."""
|
||||||
known = 0
|
known = 0
|
||||||
skipped = 0
|
skipped = 0
|
||||||
unknown = 0
|
unknown = 0
|
||||||
sortwarnings()
|
sort_warnings()
|
||||||
for i in warnpatterns:
|
for i in warn_patterns:
|
||||||
if i['severity'] == severity.UNKNOWN:
|
if i['severity'] == severity.UNKNOWN:
|
||||||
unknown += len(i['members'])
|
unknown += len(i['members'])
|
||||||
elif i['severity'] == severity.SKIP:
|
elif i['severity'] == severity.SKIP:
|
||||||
skipped += len(i['members'])
|
skipped += len(i['members'])
|
||||||
else:
|
else:
|
||||||
known += len(i['members'])
|
known += len(i['members'])
|
||||||
output('\nNumber of classified warnings: <b>' + str(known) + '</b><br>' )
|
output('\nNumber of classified warnings: <b>' + str(known) + '</b><br>')
|
||||||
output('\nNumber of skipped warnings: <b>' + str(skipped) + '</b><br>')
|
output('\nNumber of skipped warnings: <b>' + str(skipped) + '</b><br>')
|
||||||
output('\nNumber of unclassified warnings: <b>' + str(unknown) + '</b><br>')
|
output('\nNumber of unclassified warnings: <b>' + str(unknown) + '</b><br>')
|
||||||
total = unknown + known + skipped
|
total = unknown + known + skipped
|
||||||
|
@ -1784,140 +1813,155 @@ def dumpstats():
|
||||||
output('(low count may indicate incremental build)')
|
output('(low count may indicate incremental build)')
|
||||||
output('<br><br>\n')
|
output('<br><br>\n')
|
||||||
|
|
||||||
def emitbuttons():
|
|
||||||
output('<button class="button" onclick="expand_collapse(1);">' +
|
def emit_buttons():
|
||||||
'Expand all warnings</button>\n' +
|
output('<button class="button" onclick="expand_collapse(1);">'
|
||||||
'<button class="button" onclick="expand_collapse(0);">' +
|
'Expand all warnings</button>\n'
|
||||||
|
'<button class="button" onclick="expand_collapse(0);">'
|
||||||
'Collapse all warnings</button><br>\n')
|
'Collapse all warnings</button><br>\n')
|
||||||
|
|
||||||
# dump everything for a given severity
|
|
||||||
def dumpseverity(sev):
|
def dump_severity(sev):
|
||||||
|
"""Dump everything for a given severity."""
|
||||||
global anchor
|
global anchor
|
||||||
total = 0
|
total = 0
|
||||||
for i in warnpatterns:
|
for i in warn_patterns:
|
||||||
if i['severity'] == sev:
|
if i['severity'] == sev:
|
||||||
total = total + len(i['members'])
|
total += len(i['members'])
|
||||||
output('\n<br><span style="background-color:' + severity.color[sev] + '"><b>' +
|
output('\n<br><span style="background-color:' + severity.color[sev] +
|
||||||
severity.header[sev] + ': ' + str(total) + '</b></span>\n')
|
'"><b>' + severity.header[sev] + ': ' + str(total) + '</b></span>\n')
|
||||||
output('<blockquote>\n')
|
output('<blockquote>\n')
|
||||||
for i in warnpatterns:
|
for i in warn_patterns:
|
||||||
if i['severity'] == sev and len(i['members']) > 0:
|
if i['severity'] == sev and i['members']:
|
||||||
anchor += 1
|
anchor += 1
|
||||||
i['anchor'] = str(anchor)
|
i['anchor'] = str(anchor)
|
||||||
if args.byproject:
|
if args.byproject:
|
||||||
dumpcategorybyproject(sev, i)
|
dump_category_by_project(sev, i)
|
||||||
else:
|
else:
|
||||||
dumpcategory(sev, i)
|
dump_category(sev, i)
|
||||||
output('</blockquote>\n')
|
output('</blockquote>\n')
|
||||||
|
|
||||||
# emit all skipped project anchors for expand_collapse.
|
|
||||||
def dumpskippedanchors():
|
def dump_skipped_anchors():
|
||||||
|
"""emit all skipped project anchors for expand_collapse."""
|
||||||
output('<div style="display:none;">\n') # hide these fake elements
|
output('<div style="display:none;">\n') # hide these fake elements
|
||||||
for i in warnpatterns:
|
for i in warn_patterns:
|
||||||
if i['severity'] == severity.SKIP and len(i['members']) > 0:
|
if i['severity'] == severity.SKIP and i['members']:
|
||||||
projects = i['projectwarning'].keys()
|
projects = i['project_warnings'].keys()
|
||||||
for p in projects:
|
for p in projects:
|
||||||
output('<div id="' + i['projectanchor'][p] + '"></div>' +
|
output('<div id="' + i['project_anchor'][p] + '"></div>' +
|
||||||
'<div id="' + i['projectanchor'][p] + '_mark"></div>\n')
|
'<div id="' + i['project_anchor'][p] + '_mark"></div>\n')
|
||||||
output('</div>\n')
|
output('</div>\n')
|
||||||
|
|
||||||
def allpatterns(cat):
|
|
||||||
|
def all_patterns(cat):
|
||||||
pats = ''
|
pats = ''
|
||||||
for i in cat['patterns']:
|
for i in cat['patterns']:
|
||||||
pats += i
|
pats += i
|
||||||
pats += ' / '
|
pats += ' / '
|
||||||
return pats
|
return pats
|
||||||
|
|
||||||
def descriptionfor(cat):
|
|
||||||
if cat['description'] != '':
|
def description_for(cat):
|
||||||
|
if cat['description']:
|
||||||
return cat['description']
|
return cat['description']
|
||||||
return allpatterns(cat)
|
return all_patterns(cat)
|
||||||
|
|
||||||
|
|
||||||
# show which warnings no longer occur
|
def dump_fixed():
|
||||||
def dumpfixed():
|
"""Show which warnings no longer occur."""
|
||||||
global anchor
|
global anchor
|
||||||
anchor += 1
|
anchor += 1
|
||||||
mark = str(anchor) + '_mark'
|
mark = str(anchor) + '_mark'
|
||||||
output('\n<br><p style="background-color:lightblue"><b>' +
|
output('\n<br><p style="background-color:lightblue"><b>'
|
||||||
'<button id="' + mark + '" ' +
|
'<button id="' + mark + '" '
|
||||||
'class="bt" onclick="expand(' + str(anchor) + ');">' +
|
'class="bt" onclick="expand(' + str(anchor) + ');">'
|
||||||
'⊕</button> Fixed warnings. ' +
|
'⊕</button> Fixed warnings. '
|
||||||
'No more occurences. Please consider turning these into ' +
|
'No more occurrences. Please consider turning these into '
|
||||||
'errors if possible, before they are reintroduced in to the build' +
|
'errors if possible, before they are reintroduced in to the build'
|
||||||
':</b></p>\n')
|
':</b></p>\n')
|
||||||
output('<blockquote>\n')
|
output('<blockquote>\n')
|
||||||
fixed_patterns = []
|
fixed_patterns = []
|
||||||
for i in warnpatterns:
|
for i in warn_patterns:
|
||||||
if len(i['members']) == 0:
|
if not i['members']:
|
||||||
fixed_patterns.append(i['description'] + ' (' +
|
fixed_patterns.append(i['description'] + ' (' +
|
||||||
allpatterns(i) + ')')
|
all_patterns(i) + ')')
|
||||||
if i['option']:
|
if i['option']:
|
||||||
fixed_patterns.append(' ' + i['option'])
|
fixed_patterns.append(' ' + i['option'])
|
||||||
fixed_patterns.sort()
|
fixed_patterns.sort()
|
||||||
output('<div id="' + str(anchor) + '" style="display:none;"><table>\n')
|
output('<div id="' + str(anchor) + '" style="display:none;"><table>\n')
|
||||||
for i in fixed_patterns:
|
for i in fixed_patterns:
|
||||||
tablerow(i)
|
table_row(i)
|
||||||
output('</table></div>\n')
|
output('</table></div>\n')
|
||||||
output('</blockquote>\n')
|
output('</blockquote>\n')
|
||||||
|
|
||||||
def warningwithurl(line):
|
|
||||||
|
def warning_with_url(line):
|
||||||
|
"""Returns a warning message line with HTML link to given args.url."""
|
||||||
if not args.url:
|
if not args.url:
|
||||||
return line
|
return line
|
||||||
m = re.search( r'^([^ :]+):(\d+):(.+)', line, re.M|re.I)
|
m = re.search(r'^([^ :]+):(\d+):(.+)', line, re.M|re.I)
|
||||||
if not m:
|
if not m:
|
||||||
return line
|
return line
|
||||||
filepath = m.group(1)
|
file_path = m.group(1)
|
||||||
linenumber = m.group(2)
|
line_number = m.group(2)
|
||||||
warning = m.group(3)
|
warning = m.group(3)
|
||||||
|
prefix = '<a href="' + args.url + '/' + file_path
|
||||||
if args.separator:
|
if args.separator:
|
||||||
return '<a href="' + args.url + '/' + filepath + args.separator + linenumber + '">' + filepath + ':' + linenumber + '</a>:' + warning
|
return (prefix + args.separator + line_number + '">' + file_path +
|
||||||
|
':' + line_number + '</a>:' + warning)
|
||||||
else:
|
else:
|
||||||
return '<a href="' + args.url + '/' + filepath + '">' + filepath + '</a>:' + linenumber + ':' + warning
|
return prefix + '">' + file_path + '</a>:' + line_number + ':' + warning
|
||||||
|
|
||||||
def dumpgroup(sev, anchor, description, warnings):
|
|
||||||
mark = anchor + '_mark'
|
def dump_group(sev, anchor_str, description, warnings):
|
||||||
|
"""Dump warnings of given severity, anchor_str, and description."""
|
||||||
|
mark = anchor_str + '_mark'
|
||||||
output('\n<table class="t1">\n')
|
output('\n<table class="t1">\n')
|
||||||
output('<tr bgcolor="' + severity.color[sev] + '">' +
|
output('<tr bgcolor="' + severity.color[sev] + '">' +
|
||||||
'<td><button class="bt" id="' + mark +
|
'<td><button class="bt" id="' + mark +
|
||||||
'" onclick="expand(\'' + anchor + '\');">' +
|
'" onclick="expand(\'' + anchor_str + '\');">' +
|
||||||
'⊕</button> ' + description + '</td></tr>\n')
|
'⊕</button> ' + description + '</td></tr>\n')
|
||||||
output('</table>\n')
|
output('</table>\n')
|
||||||
output('<div id="' + anchor + '" style="display:none;">')
|
output('<div id="' + anchor_str + '" style="display:none;">')
|
||||||
output('<table class="t1">\n')
|
output('<table class="t1">\n')
|
||||||
for i in warnings:
|
for i in warnings:
|
||||||
tablerow(warningwithurl(i))
|
table_row(warning_with_url(i))
|
||||||
output('</table></div>\n')
|
output('</table></div>\n')
|
||||||
|
|
||||||
# dump warnings in a category
|
|
||||||
def dumpcategory(sev, cat):
|
|
||||||
description = descriptionfor(cat) + ' (' + str(len(cat['members'])) + ')'
|
|
||||||
dumpgroup(sev, cat['anchor'], description, cat['members'])
|
|
||||||
|
|
||||||
# similar to dumpcategory but output one table per project.
|
def dump_category(sev, cat):
|
||||||
def dumpcategorybyproject(sev, cat):
|
"""Dump warnings in a category."""
|
||||||
warning = descriptionfor(cat)
|
description = description_for(cat) + ' (' + str(len(cat['members'])) + ')'
|
||||||
projects = cat['projectwarning'].keys()
|
dump_group(sev, cat['anchor'], description, cat['members'])
|
||||||
|
|
||||||
|
|
||||||
|
def dump_category_by_project(sev, cat):
|
||||||
|
"""Similar to dump_category but output one table per project."""
|
||||||
|
warning = description_for(cat)
|
||||||
|
projects = cat['project_warnings'].keys()
|
||||||
projects.sort()
|
projects.sort()
|
||||||
for p in projects:
|
for p in projects:
|
||||||
anchor = cat['projectanchor'][p]
|
anchor_str = cat['project_anchor'][p]
|
||||||
projectwarnings = cat['projectwarning'][p]
|
project_warnings = cat['project_warnings'][p]
|
||||||
description = '{}, in {} ({})'.format(warning, p, len(projectwarnings))
|
description = '{}, in {} ({})'.format(warning, p, len(project_warnings))
|
||||||
dumpgroup(sev, anchor, description, projectwarnings)
|
dump_group(sev, anchor_str, description, project_warnings)
|
||||||
|
|
||||||
def findproject(line):
|
|
||||||
for p in projectpatterns:
|
def find_project(line):
|
||||||
|
for p in project_patterns:
|
||||||
if p['pattern'].match(line):
|
if p['pattern'].match(line):
|
||||||
return p['description']
|
return p['description']
|
||||||
return '???'
|
return '???'
|
||||||
|
|
||||||
def classifywarning(line):
|
|
||||||
|
def classify_warning(line):
|
||||||
global anchor
|
global anchor
|
||||||
for i in warnpatterns:
|
for i in warn_patterns:
|
||||||
for cpat in i['compiledpatterns']:
|
for cpat in i['compiled_patterns']:
|
||||||
if cpat.match(line):
|
if cpat.match(line):
|
||||||
i['members'].append(line)
|
i['members'].append(line)
|
||||||
pname = findproject(line)
|
pname = find_project(line)
|
||||||
# Count warnings by project.
|
# Count warnings by project.
|
||||||
if pname in i['projects']:
|
if pname in i['projects']:
|
||||||
i['projects'][pname] += 1
|
i['projects'][pname] += 1
|
||||||
|
@ -1925,13 +1969,13 @@ def classifywarning(line):
|
||||||
i['projects'][pname] = 1
|
i['projects'][pname] = 1
|
||||||
# Collect warnings by project.
|
# Collect warnings by project.
|
||||||
if args.byproject:
|
if args.byproject:
|
||||||
if pname in i['projectwarning']:
|
if pname in i['project_warnings']:
|
||||||
i['projectwarning'][pname].append(line)
|
i['project_warnings'][pname].append(line)
|
||||||
else:
|
else:
|
||||||
i['projectwarning'][pname] = [line]
|
i['project_warnings'][pname] = [line]
|
||||||
if pname not in i['projectanchor']:
|
if pname not in i['project_anchor']:
|
||||||
anchor += 1
|
anchor += 1
|
||||||
i['projectanchor'][pname] = str(anchor)
|
i['project_anchor'][pname] = str(anchor)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# If we end up here, there was a problem parsing the log
|
# If we end up here, there was a problem parsing the log
|
||||||
|
@ -1939,104 +1983,113 @@ def classifywarning(line):
|
||||||
# 2 or more concurrent compiles
|
# 2 or more concurrent compiles
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# precompiling every pattern speeds up parsing by about 30x
|
|
||||||
def compilepatterns():
|
def compile_patterns():
|
||||||
for i in warnpatterns:
|
"""Precompiling every pattern speeds up parsing by about 30x."""
|
||||||
i['compiledpatterns'] = []
|
for i in warn_patterns:
|
||||||
|
i['compiled_patterns'] = []
|
||||||
for pat in i['patterns']:
|
for pat in i['patterns']:
|
||||||
i['compiledpatterns'].append(re.compile(pat))
|
i['compiled_patterns'].append(re.compile(pat))
|
||||||
|
|
||||||
def parseinputfile():
|
|
||||||
global platformversion
|
def parse_input_file():
|
||||||
global targetproduct
|
"""Parse input file, match warning lines."""
|
||||||
global targetvariant
|
global platform_version
|
||||||
|
global target_product
|
||||||
|
global target_variant
|
||||||
infile = open(args.buildlog, 'r')
|
infile = open(args.buildlog, 'r')
|
||||||
linecounter = 0
|
line_counter = 0
|
||||||
|
|
||||||
warningpattern = re.compile('.* warning:.*')
|
warning_pattern = re.compile('.* warning:.*')
|
||||||
compilepatterns()
|
compile_patterns()
|
||||||
|
|
||||||
# read the log file and classify all the warnings
|
# read the log file and classify all the warnings
|
||||||
warninglines = set()
|
warning_lines = set()
|
||||||
for line in infile:
|
for line in infile:
|
||||||
# replace fancy quotes with plain ol' quotes
|
# replace fancy quotes with plain ol' quotes
|
||||||
line = line.replace("‘", "'");
|
line = line.replace('‘', "'")
|
||||||
line = line.replace("’", "'");
|
line = line.replace('’', "'")
|
||||||
if warningpattern.match(line):
|
if warning_pattern.match(line):
|
||||||
if line not in warninglines:
|
if line not in warning_lines:
|
||||||
classifywarning(line)
|
classify_warning(line)
|
||||||
warninglines.add(line)
|
warning_lines.add(line)
|
||||||
else:
|
else:
|
||||||
# save a little bit of time by only doing this for the first few lines
|
# save a little bit of time by only doing this for the first few lines
|
||||||
if linecounter < 50:
|
if line_counter < 50:
|
||||||
linecounter +=1
|
line_counter += 1
|
||||||
m = re.search('(?<=^PLATFORM_VERSION=).*', line)
|
m = re.search('(?<=^PLATFORM_VERSION=).*', line)
|
||||||
if m != None:
|
if m is not None:
|
||||||
platformversion = m.group(0)
|
platform_version = m.group(0)
|
||||||
m = re.search('(?<=^TARGET_PRODUCT=).*', line)
|
m = re.search('(?<=^TARGET_PRODUCT=).*', line)
|
||||||
if m != None:
|
if m is not None:
|
||||||
targetproduct = m.group(0)
|
target_product = m.group(0)
|
||||||
m = re.search('(?<=^TARGET_BUILD_VARIANT=).*', line)
|
m = re.search('(?<=^TARGET_BUILD_VARIANT=).*', line)
|
||||||
if m != None:
|
if m is not None:
|
||||||
targetvariant = m.group(0)
|
target_variant = m.group(0)
|
||||||
|
|
||||||
|
|
||||||
# dump the html output to stdout
|
def dump_html():
|
||||||
def dumphtml():
|
"""Dump the html output to stdout."""
|
||||||
dumphtmlprologue('Warnings for ' + platformversion + ' - ' + targetproduct + ' - ' + targetvariant)
|
dump_html_prologue('Warnings for ' + platform_version + ' - ' +
|
||||||
dumpstats()
|
target_product + ' - ' + target_variant)
|
||||||
dumpstatsbyproject()
|
dump_stats()
|
||||||
emitbuttons()
|
dump_stats_by_project()
|
||||||
# sort table based on number of members once dumpstats has deduplicated the
|
emit_buttons()
|
||||||
|
# sort table based on number of members once dump_stats has de-duplicated the
|
||||||
# members.
|
# members.
|
||||||
warnpatterns.sort(reverse=True, key=lambda i: len(i['members']))
|
warn_patterns.sort(reverse=True, key=lambda i: len(i['members']))
|
||||||
# Dump warnings by severity. If severity.SKIP warnings are not dumpped,
|
# Dump warnings by severity. If severity.SKIP warnings are not dumped,
|
||||||
# the project anchors should be dumped through dumpskippedanchors.
|
# the project anchors should be dumped through dump_skipped_anchors.
|
||||||
for s in severity.kinds:
|
for s in severity.kinds:
|
||||||
dumpseverity(s)
|
dump_severity(s)
|
||||||
dumpfixed()
|
dump_fixed()
|
||||||
dumphtmlepilogue()
|
dump_html_epilogue()
|
||||||
|
|
||||||
|
|
||||||
##### Functions to count warnings and dump csv file. #########################
|
##### Functions to count warnings and dump csv file. #########################
|
||||||
|
|
||||||
def descriptionforcsv(cat):
|
|
||||||
if cat['description'] == '':
|
def description_for_csv(cat):
|
||||||
|
if not cat['description']:
|
||||||
return '?'
|
return '?'
|
||||||
return cat['description']
|
return cat['description']
|
||||||
|
|
||||||
def stringforcsv(s):
|
|
||||||
|
def string_for_csv(s):
|
||||||
if ',' in s:
|
if ',' in s:
|
||||||
return '"{}"'.format(s)
|
return '"{}"'.format(s)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def countseverity(sev, kind):
|
|
||||||
sum = 0
|
def count_severity(sev, kind):
|
||||||
for i in warnpatterns:
|
"""Count warnings of given severity."""
|
||||||
if i['severity'] == sev and len(i['members']) > 0:
|
total = 0
|
||||||
|
for i in warn_patterns:
|
||||||
|
if i['severity'] == sev and i['members']:
|
||||||
n = len(i['members'])
|
n = len(i['members'])
|
||||||
sum += n
|
total += n
|
||||||
warning = stringforcsv(kind + ': ' + descriptionforcsv(i))
|
warning = string_for_csv(kind + ': ' + description_for_csv(i))
|
||||||
print '{},,{}'.format(n, warning)
|
print '{},,{}'.format(n, warning)
|
||||||
# print number of warnings for each project, ordered by project name.
|
# print number of warnings for each project, ordered by project name.
|
||||||
projects = i['projects'].keys()
|
projects = i['projects'].keys()
|
||||||
projects.sort()
|
projects.sort()
|
||||||
for p in projects:
|
for p in projects:
|
||||||
print '{},{},{}'.format(i['projects'][p], p, warning)
|
print '{},{},{}'.format(i['projects'][p], p, warning)
|
||||||
print '{},,{}'.format(sum, kind + ' warnings')
|
print '{},,{}'.format(total, kind + ' warnings')
|
||||||
return sum
|
return total
|
||||||
|
|
||||||
# dump number of warnings in csv format to stdout
|
|
||||||
def dumpcsv():
|
def dump_csv():
|
||||||
sortwarnings()
|
"""Dump number of warnings in csv format to stdout."""
|
||||||
|
sort_warnings()
|
||||||
total = 0
|
total = 0
|
||||||
for s in severity.kinds:
|
for s in severity.kinds:
|
||||||
total += countseverity(s, severity.columnheader[s])
|
total += count_severity(s, severity.column_headers[s])
|
||||||
print '{},,{}'.format(total, 'All warnings')
|
print '{},,{}'.format(total, 'All warnings')
|
||||||
|
|
||||||
|
|
||||||
parseinputfile()
|
parse_input_file()
|
||||||
if args.gencsv:
|
if args.gencsv:
|
||||||
dumpcsv()
|
dump_csv()
|
||||||
else:
|
else:
|
||||||
dumphtml()
|
dump_html()
|
||||||
|
|
Loading…
Reference in New Issue