From 4c5b4faf2f275e95a7bd928e0e152e9a1702945b Mon Sep 17 00:00:00 2001 From: Patryk Obara Date: Sat, 21 Sep 2019 12:14:49 +0200 Subject: [PATCH] Set the upper limit on warnings number This way it will be possible to prevent users from introducing new warnings. As new fixes will be upstreamed, the maximum limit of allowed warnings should be taken lower and lower, so this script could be eventually replaced by -Werror. --- .github/workflows/compilation.yml | 30 +++++++---- scripts/count-warnings.py | 88 +++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 scripts/count-warnings.py diff --git a/.github/workflows/compilation.yml b/.github/workflows/compilation.yml index fe372f45..6ff0a397 100644 --- a/.github/workflows/compilation.yml +++ b/.github/workflows/compilation.yml @@ -20,8 +20,10 @@ jobs: set -x $CXX --version ./autogen.sh - ./configure - make -j "$(nproc)" + ./configure CXXFLAGS="-Wall -fdiagnostics-color=always" + make -j "$(nproc)" |& tee build.log + - name: Summarize warnings + run: python3 ./scripts/count-warnings.py build.log build_gcc8: name: "GCC 8 (ubuntu-18.04)" @@ -39,8 +41,10 @@ jobs: set -x $CXX --version ./autogen.sh - ./configure - make -j "$(nproc)" + ./configure CXXFLAGS="-Wall -fdiagnostics-color=always" + make -j "$(nproc)" |& tee build.log + - name: Summarize warnings + run: python3 ./scripts/count-warnings.py build.log build_ubuntu: name: "GCC" @@ -58,8 +62,10 @@ jobs: set -x g++ --version ./autogen.sh - ./configure - make -j "$(nproc)" + ./configure CXXFLAGS="-Wall -fdiagnostics-color=always" + make -j "$(nproc)" |& tee build.log + - name: Summarize warnings + run: python3 ./scripts/count-warnings.py build.log build_clang: name: "Clang 6 (ubuntu-18.04)" @@ -77,8 +83,10 @@ jobs: set -x $CXX --version ./autogen.sh - ./configure - make -j "$(nproc)" + ./configure CXXFLAGS="-Wall" + make -j "$(nproc)" |& tee build.log + - name: Summarize warnings + run: python3 ./scripts/count-warnings.py build.log build_macos: name: "Clang (macOS-10.14)" @@ -93,5 +101,7 @@ jobs: set -x clang++ --version ./autogen.sh - ./configure - make -j "$(sysctl -n hw.physicalcpu)" + ./configure CXXFLAGS="-Wall" + make -j "$(sysctl -n hw.physicalcpu)" 2>&1 | tee build.log + - name: Summarize warnings + run: python3 ./scripts/count-warnings.py build.log diff --git a/scripts/count-warnings.py b/scripts/count-warnings.py new file mode 100644 index 00000000..54aa06a8 --- /dev/null +++ b/scripts/count-warnings.py @@ -0,0 +1,88 @@ +#!/usr/bin/python3 + +# Copyright (c) 2019 Patryk Obara + +# This script counts and all warnings and prints a summary. +# +# Usage: ./count-warnings.py build.log +# Usage: cat "*.log" | ./count-warnings.py - +# +# 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. + +# pylint: disable=invalid-name +# pylint: disable=missing-docstring + +import os +import re +import sys + +# Maximum allowed number of warnings; if build will include more warnings, +# then script will return with status 1. Simply change this line if you +# want to set a different limit. +# +MAX_WARNINGS = 357 + +# 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 print_summary(warning_types): + print("Warnings grouped by type:\n") + summary = list(warning_types.items()) + for warning, count in sorted(summary, key=lambda x: -x[1]): + print(' {:28s}: {}'.format(warning, count)) + print() + + +def main(): + total = 0 + warning_types = {} + for line in get_input_lines(sys.argv[1]): + total += count_warning(line, warning_types) + if warning_types: + print_summary(warning_types) + print('Total: {} warnings\n'.format(total)) + if total > MAX_WARNINGS: + print('Error: upper limit of warnings is', MAX_WARNINGS) + sys.exit(1) + + +if __name__ == '__main__': + main()