Skip to content

Commit

Permalink
PR Feedback: Black formatting violations, lock requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
tastycode committed Jul 22, 2024
1 parent bf7fb5a commit 4b0f291
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 1 deletion.
41 changes: 41 additions & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ The only build able to send debug messages via sysex is the "debug" build, so yo
To make debug log prints in your code, which will be sent to the console, here is a code example:
`D_PRINTLN("my log message which prints an integer value %d", theIntegerValue);`

Similar functionality is available for popup windows

`D_POPUP("%d bottles of beer on the wall.", 100/2);`

### Useful extra debug options

Using the previously mentionned sysex debugging, the following option can be toggled to enable pad logging for the pad matrix driver:
Expand All @@ -237,6 +241,43 @@ This is a sample of the output:
@matrix_driver.cpp:71: UI=instrument_clip_view,PAD_X=17,PAD_Y=2,VEL=0
```

### Automatically logging all function calls.

A task exists that will traverse through the source files in a path and annotate each function with a `D_PRINT` statement, revealing the line and the calling function call on each instance.

`dbt annotate add -p src/deluge/gui/views`

This will add a logging line to every function invocation unless the function is in the blacklist in `scripts/tasks/task-annotate.py`

```
ArrangerView::ArrangerView() {
D_PRINTLN("ArrangerView"); // ArrangerView DBT:ANNOTATE
doingAutoScrollNow = false;
lastInteractedOutputIndex = 0;
lastInteractedPos = -1;
lastInteractedSection = 0;
lastInteractedClipInstance = nullptr;
}
void ArrangerView::renderOLED(deluge::hid::display::oled_canvas::Canvas& canvas) {
D_PRINTLN("renderOLED"); // renderOLED DBT:ANNOTATE
sessionView.renderOLED(canvas);
}
void ArrangerView::moveClipToSession() {
D_PRINTLN("moveClipToSession"); // moveClipToSession DBT:ANNOTATE
Output* output = outputsOnScreen[yPressedEffective];
```

To remove the potentially hundreds of added log invocations. simply call

`dbt annotate rm -p src/deluge/ui/views`

each logging call added during `dbt annotate add` has a string marker used to later remove the annotations



### Deluge Crash Reader Discord Bot

If deluge crashes, there is a colorful pixelated image that gets displayed across the main pads and sidebar. In case
Expand Down
199 changes: 199 additions & 0 deletions scripts/tasks/task-annotate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import os
import clang.cindex
import argparse
import subprocess
from iterfzf import iterfzf


FN_BLACKLIST = ["graphicsRoutine"]
tags_file = "tags" # Replace with the actual path to your tags file


def argparser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="annotate", description="Adds print statements everywhere"
)
parser.add_argument("action", choices=["add", "rm"], help="The action to perform")
parser.add_argument("-p", "--path", help="the directory to process")
parser.add_argument(
"-c",
"--comment",
help="A comment added to the annotation to help with search/removal",
default="DBT:ANNOTATE",
)
parser.add_argument("-m", "--max", help="Maximum number of files to annotate")
parser.add_argument(
"-t",
"--template",
help="A template for the log statement",
default='D_PRINTLN("{function}");',
)

return parser


def remove_specific_lines(file_path, text_to_remove):
with open(file_path, "r") as file:
lines = file.readlines()
filtered_lines = [line for line in lines if text_to_remove not in line]
if len(filtered_lines) < len(lines):
with open(file_path, "w") as file:
file.writelines(filtered_lines)
print(f"Removed {len(lines) - len(filtered_lines)} lines from {file_path}")
return


def remove_annotations(args):
for root, dirs, files in os.walk(args.path):
for file in files:
if file.endswith(".cpp"):
remove_specific_lines(os.path.join(root, file), args.comment)


def is_function_definition(node):
"""
Check if the node is a function definition.
"""
if node.kind != clang.cindex.CursorKind.CXX_METHOD:
return False
for child in node.get_children():
if child.kind == clang.cindex.CursorKind.COMPOUND_STMT:
return True
return False


def ensure_tags_exist():
result = subprocess.run(["ctags", "--version"])
ctags_binary = "ctags"
if result.returncode != 0:

def iter_ctags_binaries():
which_ctags_result = subprocess.run(
["which", "-a", "ctags"], capture_output=True
)
for line in which_ctags_result.stdout.decode("utf-8").splitlines():
yield line

print(
"Default ctags is erroring out on `ctags --version`. GNU standard ctags required. (brew install universal-ctags on MacOSX)."
)
ctags_binary = iterfzf(
iter_ctags_binaries(), prompt="Please choose the appropriate ctags path: "
)

ctags_invocation = [
ctags_binary,
"-R",
"-x",
"--c++-types=f",
"--extras=q",
"--format=1",
"src/deluge/gui/views",
"src/deluge/deluge.cpp",
"src/deluge/model/action",
"src/deluge/model/clip",
"src/deluge/model/consequence",
"src/deluge/model/drum",
"src/deluge/model/instrument",
]
print(f'invoking {" ".join(ctags_invocation)}')
result = subprocess.run(ctags_invocation, capture_output=True)
if result.returncode == 0:
with open(tags_file, "w+") as tags_file_pointer:
tags_file_pointer.write(result.stdout.decode("utf-8"))
else:
print(f'Failed to invoke {" ".join(ctags_invocation)}')
exit(1)


def parse_ctags_output(tags_file):
function_map = {}
ensure_tags_exist()
with open(tags_file, "r") as file:
for line in file:
parts = line.split()
if len(parts) >= 3:
function_name, line_number, file_path = (
parts[0],
int(parts[1]),
parts[2],
)

# Check if the function (namespaced or not) is already in the map
already_included = any(
fn in function_name or function_name in fn
for fn, _ in function_map.get(file_path, [])
)

if file_path not in function_map:
function_map[file_path] = []

blacklisted = False
for blacklisted_fn in FN_BLACKLIST:
if blacklisted_fn in function_name:
blacklisted = True
break
# Add the function if it's not a non-namespaced version of an existing namespaced function
if not already_included and not blacklisted:
function_map[file_path].append((function_name, line_number))
return function_map


def add_annotations(args):
function_map = parse_ctags_output(tags_file)

processed_files = 0
for root, dirs, files in os.walk(args.path, followlinks=False):
for file in files:
if file.endswith(".cpp"):
file_path = os.path.join(root, file)
if file_path in function_map:
functions = sorted(
function_map[file_path], key=lambda x: x[1], reverse=True
)
if args.max and processed_files > int(args.max):
break
annotate_file(file_path, functions, args)
processed_files += 1


def annotate_file(file_path, functions, args):
with open(file_path, "r") as file:
lines = file.readlines()

for function_name, line_number in functions:
# Search for the opening curly brace from the line number
insertion_point = line_number
for i in range(
line_number - 1, min(line_number + 5, len(lines))
): # Check next few lines for the opening brace
if "{" in lines[i]:
insertion_point = i + 1 # Insert after the opening brace
break

# basename without extension
basename = os.path.basename(file_path)
debug_line = args.template.replace("{function}", f"{function_name}").replace(
"{file}", basename
)
debug_line += f" // {function_name} {args.comment}\n"

if debug_line.strip() not in lines[insertion_point].strip(): # Avoid duplicates
lines.insert(insertion_point, debug_line)

print("".join(lines))
# Uncomment to write changes
with open(file_path, "w") as file:
file.writelines(lines)


# Rest of the script remains the same...


def main() -> int:
args = argparser().parse_args()
if args.action == "rm":
remove_annotations(args)
else:
add_annotations(args)
return 0
4 changes: 3 additions & 1 deletion scripts/toolchain/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ certifi==2024.7.4
setuptools==71.0.3
pyserial==3.5
ansi==0.3.7
python-rtmidi==1.5.8
python-rtmidi==1.5.8
iterfzf==1.4.0.51.0
libclang==18.1.1

0 comments on commit 4b0f291

Please sign in to comment.