1
0
Fork 0
dosbox-staging/scripts/count-warnings.py
krcroft fd74aa0720 Allow maximum-issues to be set via command-line
This change allows the maximum issues to be passed in as an argument.
If nothing is passed, then the existing build-in maximum is
used.

Retaining the existing built-in value makes sense for home
users to keep track of their local build (otherwise they would have
to remember the prior number of warnings and pass that value
in for subsequent builds).

Motivation: until now the built-in maximum covers the build permutation
that happens to generate the most warnings versus other builds.
In some cases new warnings may not be cause if they elicit a warning
from the lesser-warning build(s) or compilers, but not in the
maximum-warning build.

This change lets us tighten-down the warning uniquely for each build,
so we can be sure all new warnings are flagged to the developer.
2019-11-24 15:16:44 +01:00

125 lines
3.8 KiB
Python
Executable file

#!/usr/bin/python3
# Copyright (c) 2019 Patryk Obara <patryk.obara@gmail.com>
# SPDX-License-Identifier: GPL-2.0-or-later
#
# pylint: disable=invalid-name
# pylint: disable=missing-docstring
"""
This script counts all compiler warnings and prints a summary.
It returns success to the shell if the number or warnings encountered
is less than or equal to the desired maximum warnings. See --help
for a description of how to set the maximum.
note: new compilers include additional flag -fdiagnostics-format=[text|json],
which could be used instead of parsing using regex, but we want to preserve
human-readable output in standard log.
"""
import argparse
import os
import re
import sys
# For recognizing warnings in GCC format in stderr:
#
WARNING_PATTERN = re.compile(r'([^:]+):(\d+):\d+: warning: .* \[-W(.+)\]')
# ~~~~~ ~~~ ~~~ ~~ ~~
# ↑ ↑ ↑ ↑ ↑
# file line column message type
# For removing color when GCC is invoked with -fdiagnostics-color=always
#
ANSI_COLOR_PATTERN = re.compile(r'\x1b\[[0-9;]*[mGKH]')
def remove_colors(line):
return re.sub(ANSI_COLOR_PATTERN, '', line)
def count_warning(line, warning_types):
line = remove_colors(line)
match = WARNING_PATTERN.match(line)
if not match:
return 0
# file = match.group(1)
# line = match.group(2)
wtype = match.group(3)
count = warning_types.get(wtype) or 0
warning_types[wtype] = count + 1
return 1
def get_input_lines(name):
if name == '-':
return sys.stdin.readlines()
if not os.path.isfile(name):
print('{}: no such file.'.format(name))
sys.exit(2)
with open(name, 'r') as logs:
return logs.readlines()
def find_longest_name_length(names):
return max(len(x) for x in names)
def print_summary(issues):
summary = list(issues.items())
size = find_longest_name_length(issues.keys()) + 1
for warning, count in sorted(summary, key=lambda x: -x[1]):
print(' {text:{field_size}s}: {count}'.format(
text=warning, count=count, field_size=size))
print()
def to_int(value):
return int(value) if value is not None else None
def parse_args():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter, description=__doc__)
parser.add_argument(
'logfile',
metavar='LOGFILE',
help=("Path to the logfile, or use - to read from stdin"))
max_warnings = to_int(os.getenv('MAX_WARNINGS', None))
parser.add_argument(
'-m', '--max-warnings',
type=int,
required=not isinstance(max_warnings, int),
default=max_warnings,
help='Defines the maximum number of warnings permitted to exist\n'
'in the log file before returning a failure to the shell.\n'
'If not provided, the script will attempt to read it from\n'
'the MAX_WARNINGS environment variable, which is currently\n'
'set to: {}. If a maximum of -1 is set then success is\n'
'always returned to the shell.\n\n'.format(str(max_warnings)))
return parser.parse_args()
def main():
rcode = 0
total = 0
warning_types = {}
args = parse_args()
for line in get_input_lines(args.logfile):
total += count_warning(line, warning_types)
if warning_types:
print("Warnings grouped by type:\n")
print_summary(warning_types)
print('Total: {} warnings'.format(total), end='')
if args.max_warnings >= 0:
print(' (out of {} allowed)\n'.format(args.max_warnings))
if total > args.max_warnings:
print('Error: upper limit of allowed warnings is', args.max_warnings)
rcode = 1
else:
print('\n')
return rcode
if __name__ == '__main__':
sys.exit(main())