Merge "Fix Google pylint warnings." am: bcd229277a

am: 64af14a4d2

Change-Id: I332da66829738d6793ca1795103f903271f235c6
This commit is contained in:
Chih-Hung Hsieh 2016-09-26 21:25:25 +00:00 committed by android-build-merger
commit 14a22e9222
1 changed files with 423 additions and 370 deletions

View File

@ -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) + ');">'
'&#x2295</button> Fixed warnings. ' + '&#x2295</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 + '\');">' +
'&#x2295</button> ' + description + '</td></tr>\n') '&#x2295</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()