* Updated copyright headers
* Revert "Fixed linker warnings in docs snippets on Windows (#15119)"
This reverts commit 372699ec49.
121 lines
4.3 KiB
Python
121 lines
4.3 KiB
Python
# Copyright (C) 2018-2023 Intel Corporation
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
"""
|
|
Doxygen and Sphinx logs parsing routines
|
|
"""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
class LogParser:
|
|
"""
|
|
This class reads a log file and converts it to a structured format represented as a python `dict`
|
|
"""
|
|
exclude_symbols = (
|
|
'\x1b[91m',
|
|
'[39;49;00m'
|
|
)
|
|
|
|
# a regex that is used to match log lines containing a filepath,
|
|
# a line number, and an error,warning or critical
|
|
regex = r'^(?!\*)(.*?):?([0-9]*):? ?(warning|error|critical): (.+)'
|
|
|
|
def __init__(self, log: Path, strip: str, xfail_list: list, suppress_warnings: list):
|
|
"""
|
|
Initialize a LogParser object for parsing doxygen and sphinx logs
|
|
:param log: Path to a log file represented as a `pathlib.Path` object
|
|
:param strip: A part of the filepath that should be removed
|
|
:param suppress_warnings: A list of warnings that should be ignored
|
|
:param xfail_list: A list of filepaths that should be ignored
|
|
"""
|
|
self.log = log
|
|
if not strip.endswith('/'):
|
|
strip = strip + '/'
|
|
self.strip = strip.replace('\\', '/').lower()
|
|
self.xfail_list = xfail_list
|
|
self.suppress_warnings = suppress_warnings
|
|
self.out = dict()
|
|
|
|
def get_match(self, line: str):
|
|
"""
|
|
Match a log line against the regex defined by this class
|
|
"""
|
|
return re.match(self.regex, line)
|
|
|
|
def preprocess_line(self, line):
|
|
"""
|
|
Clear log line from unwanted symbols
|
|
"""
|
|
for sym in self.exclude_symbols:
|
|
line = line.replace(sym, '')
|
|
return line.strip().lower()
|
|
|
|
def strip_path(self, path):
|
|
"""
|
|
Strip `path` components ends on `strip`
|
|
"""
|
|
path = path.replace('\\', '/').lower()
|
|
|
|
new_path = path.split(self.strip)[-1]
|
|
if new_path.startswith('build/docs/'):
|
|
new_path = new_path.split('build/docs/')[-1]
|
|
return new_path
|
|
|
|
def filter(self):
|
|
"""
|
|
Filter out a log file to remove files or warning based on the values provided in `strip`,
|
|
`suppress_warnings`, and 'xfail_list`
|
|
"""
|
|
filtered_out = dict()
|
|
for filepath, warnings in self.out.items():
|
|
filepath = self.strip_path(filepath)
|
|
if filepath in self.xfail_list:
|
|
continue
|
|
warnings = list(filter(lambda item: not self.is_suppressed(item), warnings))
|
|
if warnings:
|
|
filtered_out[filepath] = warnings
|
|
return filtered_out
|
|
|
|
def is_suppressed(self, line):
|
|
return any([re.search(re.compile(warning, re.IGNORECASE), line) for warning in self.suppress_warnings])
|
|
|
|
def parse(self):
|
|
"""
|
|
Parse a log file to convert it to a structured format
|
|
"""
|
|
with open(self.log, 'r', errors='ignore') as f:
|
|
log_lines = f.readlines()
|
|
|
|
# iterate each line in the log file
|
|
i = 0
|
|
while i < len(log_lines):
|
|
j = i + 1
|
|
line = self.preprocess_line(log_lines[i])
|
|
match = self.get_match(line)
|
|
# if match is true then we found a line containing a filepath,
|
|
# a line number, and a warning/error
|
|
if match and not self.is_suppressed(line):
|
|
filepath = match.group(1) or 'warning'
|
|
linenum = match.group(2)
|
|
warning = match.group(4)
|
|
if not filepath in self.out:
|
|
self.out[filepath] = set()
|
|
if linenum:
|
|
warning = f'{warning} line ({linenum})'
|
|
self.out[filepath].add(warning)
|
|
# in this case, the filepath might contain several errors on separate lines,
|
|
# so we need to iterate next lines until we find a line
|
|
# that matches the regex defined in this class
|
|
while j < len(log_lines):
|
|
next_line = self.preprocess_line(log_lines[j])
|
|
match = self.get_match(next_line)
|
|
if match:
|
|
break
|
|
if next_line:
|
|
self.out[filepath].add(self.preprocess_line(next_line))
|
|
j += 1
|
|
i = j
|
|
return self.out
|