Skip to content

Add verbose #78

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,44 @@ pre-commit run --files $(git diff --name-only)

This approach ensures that only modified files are checked, further speeding up the linting process during development.

### Verbose Output and Debugging

For debugging issues or getting more detailed information about what the hooks are doing, you can enable verbose output:

```yaml
repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v0.8.1
hooks:
- id: clang-format
args: [--style=file, --version=18, --verbose] # Enable verbose output
- id: clang-tidy
args: [--checks=.clang-tidy, --version=18, --verbose] # Enable verbose output
```

When you run pre-commit with verbose mode, you'll get detailed debug information:

```bash
# Run pre-commit with verbose output
pre-commit run --verbose --all-files

# Run specific hook with verbose output
pre-commit run clang-format --verbose
```

The verbose output includes:
- The exact command being executed
- The path to the clang tool executable
- The tool version being used
- Exit codes and detailed error messages
- Both stdout and stderr output from the tools

This is particularly useful when debugging issues like:
- Exit code 247 (tool execution errors)
- Missing compilation databases for clang-tidy
- Configuration file loading issues
- Tool installation problems

## Output

### clang-format Example
Expand Down Expand Up @@ -148,7 +186,6 @@ Use -header-filter=.* to display errors from all non-system headers. Use -system
for (;;)
^
{

```

## Contributing
Expand Down
43 changes: 25 additions & 18 deletions cpp_linter_hooks/clang_format.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import subprocess
from argparse import ArgumentParser
from typing import Tuple

from .util import ensure_installed, DEFAULT_CLANG_VERSION
from .util import (
ensure_installed,
DEFAULT_CLANG_VERSION,
debug_print,
run_subprocess_with_logging,
)


parser = ArgumentParser()
parser.add_argument("--version", default=DEFAULT_CLANG_VERSION)
parser.add_argument(
"-v", "--verbose", action="store_true", help="Enable verbose output"
)


def run_clang_format(args=None) -> Tuple[int, str]:
Expand All @@ -15,27 +22,27 @@ def run_clang_format(args=None) -> Tuple[int, str]:
command = [str(path), "-i"]
command.extend(other_args)

retval = 0
output = ""
try:
if "--dry-run" in command:
sp = subprocess.run(command, stdout=subprocess.PIPE, encoding="utf-8")
retval = -1 # Not a fail just identify it's a dry-run.
output = sp.stdout
else:
retval = subprocess.run(command, stdout=subprocess.PIPE).returncode
return retval, output
except FileNotFoundError as stderr:
retval = 1
return retval, str(stderr)
verbose = hook_args.verbose

# Log initial debug information
debug_print(f"clang-format version: {hook_args.version}", verbose)
debug_print(f"clang-format executable: {path}", verbose)

# Check for dry-run mode
dry_run = "--dry-run" in command

# Use the utility function for subprocess execution
return run_subprocess_with_logging(
command=command, tool_name="clang-format", verbose=verbose, dry_run=dry_run
)


def main() -> int:
retval, output = run_clang_format()
if retval != 0:
print(output)
if retval != 0: # pragma: no cover
print(output) # pragma: no cover
return retval


if __name__ == "__main__":
if __name__ == "__main__": # pragma: no cover
raise SystemExit(main())
39 changes: 22 additions & 17 deletions cpp_linter_hooks/clang_tidy.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import subprocess
from argparse import ArgumentParser
from typing import Tuple

from .util import ensure_installed, DEFAULT_CLANG_VERSION
from .util import (
ensure_installed,
DEFAULT_CLANG_VERSION,
debug_print,
run_subprocess_with_logging,
)


parser = ArgumentParser()
parser.add_argument("--version", default=DEFAULT_CLANG_VERSION)
parser.add_argument(
"-v", "--verbose", action="store_true", help="Enable verbose output"
)


def run_clang_tidy(args=None) -> Tuple[int, str]:
Expand All @@ -15,26 +22,24 @@ def run_clang_tidy(args=None) -> Tuple[int, str]:
command = [str(path)]
command.extend(other_args)

retval = 0
output = ""
try:
sp = subprocess.run(command, stdout=subprocess.PIPE, encoding="utf-8")
retval = sp.returncode
output = sp.stdout
if "warning:" in output or "error:" in output:
retval = 1
return retval, output
except FileNotFoundError as stderr:
retval = 1
return retval, str(stderr)
verbose = hook_args.verbose

# Log initial debug information
debug_print(f"clang-tidy version: {hook_args.version}", verbose)
debug_print(f"clang-tidy executable: {path}", verbose)

# Use the utility function for subprocess execution
return run_subprocess_with_logging(
command=command, tool_name="clang-tidy", verbose=verbose, dry_run=False
)


def main() -> int:
retval, output = run_clang_tidy()
if retval != 0:
print(output)
if retval != 0: # pragma: no cover
print(output) # pragma: no cover
return retval


if __name__ == "__main__":
if __name__ == "__main__": # pragma: no cover
raise SystemExit(main())
77 changes: 76 additions & 1 deletion cpp_linter_hooks/util.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import sys
from pathlib import Path
import logging
from typing import Optional
import subprocess
from typing import Optional, Tuple, List

from clang_tools.util import Version
from clang_tools.install import is_installed as _is_installed, install_tool
Expand All @@ -13,6 +14,80 @@
DEFAULT_CLANG_VERSION = "18" # Default version for clang tools, can be overridden


def debug_print(message: str, verbose: bool = False) -> None:
"""Print debug message to stderr if verbose mode is enabled."""
if verbose:
print(f"[DEBUG] {message}", file=sys.stderr)


def run_subprocess_with_logging(
command: List[str], tool_name: str, verbose: bool = False, dry_run: bool = False
) -> Tuple[int, str]:
"""
Run subprocess with comprehensive logging and error handling.

Args:
command: Command list to execute
tool_name: Name of the tool (for logging)
verbose: Enable verbose debug output
dry_run: Whether this is a dry run (affects return code for clang-format)

Returns:
Tuple of (return_code, combined_output)
"""
debug_print(f"{tool_name} command: {' '.join(command)}", verbose)

retval = 0
output = ""
stderr_output = ""

try:
sp = subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8"
)

output = sp.stdout
stderr_output = sp.stderr
retval = sp.returncode

if dry_run and tool_name == "clang-format":
debug_print("Dry-run mode detected", verbose)
debug_print(f"Exit code: {retval} (converted to -1 for dry-run)", verbose)
retval = -1 # Special handling for clang-format dry-run
else:
debug_print(f"Exit code: {retval}", verbose)

# Log outputs if verbose
if verbose and (output or stderr_output):
debug_print(f"stdout: {repr(output)}", verbose)
debug_print(f"stderr: {repr(stderr_output)}", verbose)

# Combine stdout and stderr for comprehensive output
combined_output = ""
if output:
combined_output += output
if stderr_output:
if combined_output:
combined_output += "\n"
combined_output += stderr_output

# Special handling for clang-tidy warnings/errors
if tool_name == "clang-tidy" and (
"warning:" in combined_output or "error:" in combined_output
):
if retval == 0: # Only override if it was successful
retval = 1
debug_print("Found warnings/errors, setting exit code to 1", verbose)

return retval, combined_output

except FileNotFoundError as error:
error_msg = f"{tool_name} executable not found: {error}"
debug_print(f"FileNotFoundError: {error}", verbose)
debug_print(f"Command attempted: {' '.join(command)}", verbose)
return 1, error_msg


def is_installed(tool_name: str, version: str) -> Optional[Path]:
"""Check if tool is installed.

Expand Down
25 changes: 25 additions & 0 deletions testing/pre-commit-config-verbose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Example .pre-commit-config.yaml with verbose debugging enabled

repos:
- repo: https://github.com/cpp-linter/cpp-linter-hooks
rev: v0.8.1 # Use the tag or commit you want
hooks:
- id: clang-format
args: [--style=file, --version=18, --verbose] # Added --verbose
files: ^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$
- id: clang-tidy
args: [--checks=.clang-tidy, --version=18, --verbose] # Added --verbose
files: ^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$

# To use this configuration:
# 1. Save this as .pre-commit-config.yaml in your project root
# 2. Run: pre-commit run --verbose --all-files
# 3. The --verbose flag to pre-commit combined with --verbose in args
# will give you maximum debugging information

# For your specific exit code 247 issue, you'll now see:
# - The exact clang-format command being executed
# - The path to the clang-format executable
# - The version being used
# - Both stdout and stderr output
# - The actual exit code from clang-format
2 changes: 1 addition & 1 deletion testing/run.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
rm -f result.txt
git restore testing/main.c

for config in testing/pre-commit-config.yaml testing/pre-commit-config-version.yaml; do
for config in testing/pre-commit-config.yaml testing/pre-commit-config-version.yaml testing/pre-commit-config-verbose.yaml; do
pre-commit clean
pre-commit run -c $config --files testing/main.c | tee -a result.txt || true
git restore testing/main.c
Expand Down
Loading
Loading