-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple features: source path substitution, relative source filename display, custom HTML report title #14
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -16,9 +16,32 @@ def main(): | |||||||||||||||
"--source-dir", | ||||||||||||||||
help="specifies the source directory", | ||||||||||||||||
) | ||||||||||||||||
parser.add_argument( | ||||||||||||||||
"--substitute-path", | ||||||||||||||||
action="append", | ||||||||||||||||
help="specifies a substitution rule `from:to` for finding source files on disk. example: --substitute-path /foo:/bar", | ||||||||||||||||
nargs='?' | ||||||||||||||||
) | ||||||||||||||||
parser.add_argument( | ||||||||||||||||
"--relativize", | ||||||||||||||||
action="append", | ||||||||||||||||
help="specifies a prefix to remove from displayed source filenames. example: --relativize /foo/bar", | ||||||||||||||||
nargs='?' | ||||||||||||||||
) | ||||||||||||||||
parser.add_argument( | ||||||||||||||||
"--relativize-from-substitute-paths", | ||||||||||||||||
default=False, | ||||||||||||||||
action="store_true", | ||||||||||||||||
help="use the `from` values in the substitution rules as prefixes to remove from displayed source filenames", | ||||||||||||||||
) | ||||||||||||||||
parser.add_argument( | ||||||||||||||||
"--output-dir", help="directory where the HTML report will be generated" | ||||||||||||||||
) | ||||||||||||||||
parser.add_argument( | ||||||||||||||||
"--html-report-title", | ||||||||||||||||
default="ValgrindCI Report", | ||||||||||||||||
help="the title of the generated HTML report" | ||||||||||||||||
) | ||||||||||||||||
parser.add_argument( | ||||||||||||||||
"--summary", | ||||||||||||||||
default=False, | ||||||||||||||||
|
@@ -55,6 +78,27 @@ def main(): | |||||||||||||||
data.parse(args.xml_file) | ||||||||||||||||
data.set_source_dir(args.source_dir) | ||||||||||||||||
|
||||||||||||||||
if args.substitute_path: | ||||||||||||||||
substitute_paths = [] | ||||||||||||||||
for s in args.substitute_path: | ||||||||||||||||
substitute_paths.append({"from": s.split(":")[0], "to": s.split(":")[1] }) | ||||||||||||||||
data.set_substitute_paths(substitute_paths) | ||||||||||||||||
Comment on lines
+83
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
|
||||||||||||||||
if args.relativize: | ||||||||||||||||
prefixes = [] | ||||||||||||||||
for p in args.relativize: | ||||||||||||||||
prefixes.append(p) | ||||||||||||||||
data.set_relative_prefixes(prefixes) | ||||||||||||||||
Comment on lines
+87
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you duplicating the list
Suggested change
|
||||||||||||||||
|
||||||||||||||||
if args.relativize_from_substitute_paths: | ||||||||||||||||
if not args.substitute_path: | ||||||||||||||||
print("No substitution paths specified on the command line.") | ||||||||||||||||
else: | ||||||||||||||||
prefixes = data._relative_prefixes.copy() | ||||||||||||||||
for s in data._substitute_paths: | ||||||||||||||||
prefixes.append(s.get("from")) | ||||||||||||||||
data.set_relative_prefixes(prefixes) | ||||||||||||||||
|
||||||||||||||||
errors_total = data.get_num_errors() | ||||||||||||||||
if args.abort_on_errors and errors_total != 0: | ||||||||||||||||
print("{} errors reported by Valgrind - Abort".format(errors_total)) | ||||||||||||||||
|
@@ -63,7 +107,7 @@ def main(): | |||||||||||||||
if args.output_dir: | ||||||||||||||||
renderer = HTMLRenderer(data) | ||||||||||||||||
renderer.set_source_dir(args.source_dir) | ||||||||||||||||
renderer.render(args.output_dir, args.lines_before, args.lines_after) | ||||||||||||||||
renderer.render(args.html_report_title, args.output_dir, args.lines_before, args.lines_after) | ||||||||||||||||
|
||||||||||||||||
if args.number_of_errors: | ||||||||||||||||
print("{} errors.".format(errors_total)) | ||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -118,6 +118,8 @@ class ValgrindData: | |||||||||||
def __init__(self) -> None: | ||||||||||||
self.errors: List[Error] = [] | ||||||||||||
self._source_dir: Optional[str] = None | ||||||||||||
self._substitute_paths: Optional[List[dict]] = [] | ||||||||||||
self._relative_prefixes: Optional[List[str]] = [] | ||||||||||||
Comment on lines
+121
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are these members declared
Suggested change
|
||||||||||||
|
||||||||||||
def parse(self, xml_file: str) -> None: | ||||||||||||
root = et.parse(xml_file).getroot() | ||||||||||||
|
@@ -130,6 +132,27 @@ def set_source_dir(self, source_dir: Optional[str]) -> None: | |||||||||||
else: | ||||||||||||
self._source_dir = None | ||||||||||||
|
||||||||||||
def set_substitute_paths(self, substitute_paths: Optional[List[dict]]) -> None: | ||||||||||||
if substitute_paths is not None: | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can the parameter |
||||||||||||
self._substitute_paths = substitute_paths | ||||||||||||
|
||||||||||||
def set_relative_prefixes(self, relative_prefixes: Optional[str]) -> None: | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't the parameter
Suggested change
|
||||||||||||
if relative_prefixes is not None: | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can the parameter |
||||||||||||
self._relative_prefixes = relative_prefixes | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mypy reports an error for this line of code: Please fix it. |
||||||||||||
|
||||||||||||
def substitute_path(self, path: str) -> str: | ||||||||||||
for s in self._substitute_paths: | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mypy reports an error for this line of code Please fix it. |
||||||||||||
path = path.replace(s.get("from"), s.get("to")) | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mypy reports 2 errors for this line of code:
Please fix them |
||||||||||||
return path | ||||||||||||
|
||||||||||||
def relativize(self, path: str) -> str: | ||||||||||||
for p in self._relative_prefixes: | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mypy reports an error for this line of code: Please fix it. |
||||||||||||
if path.startswith(p): | ||||||||||||
path = path.replace(p, "") | ||||||||||||
if path.startswith("/"): | ||||||||||||
path = path[1:] | ||||||||||||
Comment on lines
+151
to
+153
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use òs.path.commonprefix()
Suggested change
|
||||||||||||
return path | ||||||||||||
|
||||||||||||
def get_num_errors(self) -> int: | ||||||||||||
if self._source_dir is None: | ||||||||||||
return len(self.errors) | ||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -44,7 +44,7 @@ def set_source_dir(self, source_dir: Optional[str]) -> None: | |||||||
else: | ||||||||
self._source_dir = None | ||||||||
|
||||||||
def render(self, output_dir: str, lines_before: int, lines_after: int) -> None: | ||||||||
def render(self, report_title: str, output_dir: str, lines_before: int, lines_after: int) -> None: | ||||||||
if not os.path.exists(output_dir): | ||||||||
os.makedirs(output_dir) | ||||||||
shutil.copy( | ||||||||
|
@@ -71,14 +71,14 @@ def render(self, output_dir: str, lines_before: int, lines_after: int) -> None: | |||||||
f.write( | ||||||||
self._source_tmpl.render( | ||||||||
num_errors=num_errors, | ||||||||
source_file_name=source_file, | ||||||||
source_file_name=self._data.relativize(source_file), | ||||||||
codelines=lines_of_code, | ||||||||
) | ||||||||
) | ||||||||
|
||||||||
summary.append( | ||||||||
{ | ||||||||
"filename": source_file, | ||||||||
"filename": self._data.relativize(source_file), | ||||||||
"errors": num_errors, | ||||||||
"link": html_filename, | ||||||||
} | ||||||||
|
@@ -88,7 +88,9 @@ def render(self, output_dir: str, lines_before: int, lines_after: int) -> None: | |||||||
with open(os.path.join(output_dir, "index.html"), "w") as f: | ||||||||
f.write( | ||||||||
self._index_tmpl.render( | ||||||||
source_list=summary, num_errors=total_num_errors | ||||||||
title=report_title, | ||||||||
source_list=summary, | ||||||||
num_errors=total_num_errors | ||||||||
) | ||||||||
) | ||||||||
|
||||||||
|
@@ -121,13 +123,17 @@ def _extract_error_data( | |||||||
assert error_line is not None | ||||||||
stack["line"] = error_line - lines_before - 1 | ||||||||
stack["error_line"] = lines_before + 1 | ||||||||
stack["fileref"] = "{}:{}".format( | ||||||||
frame.get_path(self._source_dir), error_line | ||||||||
) | ||||||||
with open(fullname, "r") as f: | ||||||||
for l, code_line in enumerate(f.readlines()): | ||||||||
if l >= stack["line"] and l <= error_line + lines_after - 1: | ||||||||
stack["code"].append(code_line) | ||||||||
frame_source = frame.get_path(self._source_dir) | ||||||||
frame_source = self._data.relativize(frame_source) | ||||||||
stack["fileref"] = "{}:{}".format(frame_source, error_line) | ||||||||
fullname = self._data.substitute_path(fullname) | ||||||||
try: | ||||||||
with open(fullname, "r", errors="replace") as f: | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the point of using |
||||||||
for l, code_line in enumerate(f.readlines()): | ||||||||
if l >= stack["line"] and l <= error_line + lines_after - 1: | ||||||||
stack["code"].append(code_line) | ||||||||
except OSError as e: | ||||||||
print(f"Warning: cannot read stack data from missing source file: {e.filename}") | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't
Suggested change
|
||||||||
issue["stack"].append(stack) | ||||||||
return issue | ||||||||
|
||||||||
|
@@ -143,16 +149,20 @@ def _extract_data_per_source_file( | |||||||
else: | ||||||||
filename = source_file | ||||||||
|
||||||||
with open(filename, "r") as f: | ||||||||
for l, line in enumerate(f.readlines()): | ||||||||
klass = None | ||||||||
issue = None | ||||||||
if l + 1 in error_lines: | ||||||||
klass = "error" | ||||||||
issue = self._extract_error_data( | ||||||||
src_data, l + 1, lines_before, lines_after | ||||||||
filename = self._data.substitute_path(filename) | ||||||||
try: | ||||||||
with open(filename, "r", errors="replace") as f: | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There again, what is the point of using |
||||||||
for l, line in enumerate(f.readlines()): | ||||||||
klass = None | ||||||||
issue = None | ||||||||
if l + 1 in error_lines: | ||||||||
klass = "error" | ||||||||
issue = self._extract_error_data( | ||||||||
src_data, l + 1, lines_before, lines_after | ||||||||
) | ||||||||
lines_of_code.append( | ||||||||
{"line": line[:-1], "klass": klass, "issue": issue} | ||||||||
) | ||||||||
lines_of_code.append( | ||||||||
{"line": line[:-1], "klass": klass, "issue": issue} | ||||||||
) | ||||||||
except OSError as e: | ||||||||
print(f"Warning: cannot extract data from missing source file: {e.filename}") | ||||||||
return lines_of_code, len(error_lines) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point of including this piece of documentation ? Which audience is it intended to ?