Skip to content
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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

aallrd
Copy link

@aallrd aallrd commented May 23, 2023

Hello,
I would like to contribute the below features:

  • source path substitution
    • The source files used to build the application will not always be in the expected location.
    • This is the same feature as the gdb substitution path to locate source files on disk.
  • relative source filename display
    • The full path of the source files can be long and meaningless (see above).
    • This feature allows to display only relative paths, removing a list of prefixes.
  • custom HTML report title
    • Self explanatory, ability to change the title of the HTML report from the default "ValgrindCI report"

Copy link
Owner

@bcoconni bcoconni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for submitting a PR @aallrd, this is much appreciated.
I have made a number of comments in your code, could you please address them ?

In particular your code is rightfully rejected by mypy which reports 5 errors. I have mentioned them in my comments, please fix them.

Comment on lines +47 to +56
#### Build and package an executable with `pyinstaller`

You can use `pyinstaller` to create a single-file executable binary:

```bash
> pip install pyinstaller
> pyinstaller --onefile --add-data ValgrindCI:ValgrindCI valgrind-ci
> ./dist/valgrind-ci --help
```

Copy link
Owner

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 ?

Comment on lines +83 to +85
for s in args.substitute_path:
substitute_paths.append({"from": s.split(":")[0], "to": s.split(":")[1] })
data.set_substitute_paths(substitute_paths)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s.split(':') is executed twice which is inefficient. Please use local variables instead:

Suggested change
for s in args.substitute_path:
substitute_paths.append({"from": s.split(":")[0], "to": s.split(":")[1] })
data.set_substitute_paths(substitute_paths)
for s in args.substitute_path:
_from, _to = s.split(':')
substitute_paths.append({"from": _from, "to": _to})
data.set_substitute_paths(substitute_paths)

Comment on lines +87 to +91
if args.relativize:
prefixes = []
for p in args.relativize:
prefixes.append(p)
data.set_relative_prefixes(prefixes)
Copy link
Owner

@bcoconni bcoconni May 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you duplicating the list args.relativize in another list prefixes ? Wouldn't it be simpler to send args.relativize as an argument to data.set_relative_prefixes() ?

Suggested change
if args.relativize:
prefixes = []
for p in args.relativize:
prefixes.append(p)
data.set_relative_prefixes(prefixes)
if args.relativize:
data.set_relative_prefixes(args.relativize)

Comment on lines +121 to +122
self._substitute_paths: Optional[List[dict]] = []
self._relative_prefixes: Optional[List[str]] = []
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these members declared Optional[] ? It doesn't seem to me they can ever be None...

Suggested change
self._substitute_paths: Optional[List[dict]] = []
self._relative_prefixes: Optional[List[str]] = []
self._substitute_paths: List[dict] = []
self._relative_prefixes: List[str] = []

@@ -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:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the parameter substitute_paths ever be None ? Why is substitute_paths of type Optional[} ?

return path

def relativize(self, path: str) -> str:
for p in self._relative_prefixes:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mypy reports an error for this line of code: ValgrindCI/parse.py:149: error: Item "None" of "Optional[List[str]]" has no attribute "__iter__" (not iterable) [union-attr]

Please fix it.

Comment on lines +151 to +153
path = path.replace(p, "")
if path.startswith("/"):
path = path[1:]
Copy link
Owner

@bcoconni bcoconni May 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use òs.path.commonprefix()andos.path.relpath()` which are portable across OSes rather than homemade code:

Suggested change
path = path.replace(p, "")
if path.startswith("/"):
path = path[1:]
if os.path.commonprefix([p, path]) == p:
path = os.path.relpath(path, p)

stack["fileref"] = "{}:{}".format(frame_source, error_line)
fullname = self._data.substitute_path(fullname)
try:
with open(fullname, "r", errors="replace") as f:
Copy link
Owner

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 using errors="replace" when reading a file ?

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}")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't continue be called when swallowing this exception in order to avoid adding a malformed "stack" to the issue dictionary ?

Suggested change
print(f"Warning: cannot read stack data from missing source file: {e.filename}")
print(f"Warning: cannot read stack data from missing source file: {e.filename}")
continue

src_data, l + 1, lines_before, lines_after
filename = self._data.substitute_path(filename)
try:
with open(filename, "r", errors="replace") as f:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There again, what is the point of using errors="replace" when reading a file ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants