Skip to content

Commit

Permalink
Merge pull request #115 from Pennycook/meta-warnings
Browse files Browse the repository at this point in the history
Introduce meta-warnings
  • Loading branch information
Pennycook authored Oct 10, 2024
2 parents 65c4392 + 9abcf0c commit c62fba3
Showing 1 changed file with 74 additions and 2 deletions.
76 changes: 74 additions & 2 deletions codebasin/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import argparse
import logging
import os
import re
import sys

from codebasin import CodeBase, config, finder, report, util
Expand Down Expand Up @@ -55,10 +56,10 @@ def _help_string(*lines: str, is_long=False, is_last=False):


class Formatter(logging.Formatter):
def __init__(self, *, colors=False):
def __init__(self, *, colors: bool = False):
self.colors = colors

def format(self, record):
def format(self, record: logging.LogRecord) -> str:
msg = record.msg
level = record.levelname.lower()

Expand Down Expand Up @@ -86,6 +87,68 @@ def format(self, record):
return f"{BOLD}{color}{level}{RESET}: {msg}"


class MetaWarning:
"""
A MetaWarning is used to represent multiple warnings, and provide suggested
actions to the user.
"""

def __init__(self, regex: str, msg: str):
self.regex = re.compile(regex)
self.msg = msg
self._count = 0

def inspect(self, record: logging.LogRecord):
if self.regex.search(record.msg):
self._count += 1

def warn(self):
if self._count == 0:
return
log.warning(self.msg.format(self._count))


class WarningAggregator(logging.Filter):
"""
Inspect warnings to generate meta-warnings and statistics.
"""

def __init__(self):
self.meta_warnings = [
MetaWarning(".", "{} warnings generated during preprocessing."),
MetaWarning(
"user include",
"{} user include files could not be found.\n"
+ " These could contain important macros and includes.\n"
+ " Suggested solutions:\n"
+ " - Check that the file(s) exist in the code base.\n"
+ " - Check the include paths in the compilation database.\n"
+ " - Check if the include(s) should have used '<>'.",
),
MetaWarning(
"system include",
"{} system include files could not be found.\n"
+ " These could define important feature macros.\n"
+ " Suggested solutions:\n"
+ " - Check that the file(s) exist on your system.\n"
+ " - Use .cbi/config to define system include paths.\n"
+ " - Use .cbi/config to define important macros.",
),
]

def filter(self, record: logging.LogRecord) -> bool:
if record.levelno == logging.WARNING:
for meta_warning in self.meta_warnings:
meta_warning.inspect(record)

# Do not filter anything.
return True

def warn(self):
for meta_warning in self.meta_warnings:
meta_warning.warn()


def main():
# Read command-line arguments
parser = argparse.ArgumentParser(
Expand Down Expand Up @@ -181,11 +244,14 @@ def main():
# - All messages are written to a log file
# - Only errors are written to the terminal by default
# - Messages written to terminal are based on -q and -v flags
# - Meta-warnings and statistics are generated by a WarningAggregator
aggregator = WarningAggregator()
log.setLevel(logging.DEBUG)

file_handler = logging.FileHandler("cbi.log", mode="w")
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(Formatter())
file_handler.addFilter(aggregator)
log.addHandler(file_handler)

# Inform the user that a log file has been created.
Expand Down Expand Up @@ -257,6 +323,12 @@ def main():
legacy_warnings=False,
)

# Generate meta-warnings and statistics.
# Temporarily override log_level to ensure they are visible.
stdout_handler.setLevel(logging.WARNING)
aggregator.warn()
stdout_handler.setLevel(log_level)

# Count lines for platforms
platform_mapper = PlatformMapper(codebase)
setmap = platform_mapper.walk(state)
Expand Down

0 comments on commit c62fba3

Please sign in to comment.