mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-17 21:18:18 -04:00
add line counter tool and update README with code stats
https://claude.ai/code/session_01Gt1RfK8m2hxciLMMMYG8xg
This commit is contained in:
86
tools/line_counter.py
Normal file
86
tools/line_counter.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""Count lines of code in the repository, grouped by file type."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_tracked_files() -> list[str]:
|
||||
"""Get all git-tracked files."""
|
||||
result = subprocess.run(
|
||||
["git", "ls-files"], # noqa: S603, S607
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
return [f for f in result.stdout.strip().splitlines() if f]
|
||||
|
||||
|
||||
def count_lines(filepath: str) -> int:
|
||||
"""Count lines in a file, returning 0 for binary files."""
|
||||
try:
|
||||
return len(Path(filepath).read_text(encoding="utf-8").splitlines())
|
||||
except (UnicodeDecodeError, OSError):
|
||||
return 0
|
||||
|
||||
|
||||
def count_lines_by_type() -> dict[str, int]:
|
||||
"""Count lines grouped by file extension."""
|
||||
lines_by_type: dict[str, int] = defaultdict(int)
|
||||
for filepath in get_tracked_files():
|
||||
ext = Path(filepath).suffix.lstrip(".")
|
||||
if not ext:
|
||||
ext = Path(filepath).name
|
||||
lines_by_type[ext] += count_lines(filepath)
|
||||
# Exclude binary/non-code files
|
||||
for key in ("png", "lock"):
|
||||
lines_by_type.pop(key, None)
|
||||
return dict(sorted(lines_by_type.items(), key=lambda x: x[1], reverse=True))
|
||||
|
||||
|
||||
def format_report() -> str:
|
||||
"""Generate a formatted line count report."""
|
||||
lines_by_type = count_lines_by_type()
|
||||
total = sum(lines_by_type.values())
|
||||
|
||||
lines = [
|
||||
f"This repo has **{total:,}** lines of technical debt.",
|
||||
"",
|
||||
"| File Type | Lines | Percentage |",
|
||||
"|-----------|------:|-----------:|",
|
||||
]
|
||||
for ext, count in lines_by_type.items():
|
||||
if count > 0:
|
||||
pct = count / total * 100
|
||||
prefix = "." if not ext.startswith(".") else ""
|
||||
lines.append(f"| {prefix}{ext} | {count:,} | {pct:.1f}% |")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def update_readme() -> None:
|
||||
"""Update README.md with the line count report."""
|
||||
readme_path = Path("README.md")
|
||||
report = format_report()
|
||||
|
||||
start_marker = "<!-- LINE-COUNT-START -->"
|
||||
end_marker = "<!-- LINE-COUNT-END -->"
|
||||
|
||||
content = readme_path.read_text(encoding="utf-8")
|
||||
|
||||
section = f"{start_marker}\n{report}\n{end_marker}"
|
||||
|
||||
if start_marker in content:
|
||||
start = content.index(start_marker)
|
||||
end = content.index(end_marker) + len(end_marker)
|
||||
content = content[:start] + section + content[end:]
|
||||
else:
|
||||
content = content.rstrip() + "\n\n" + section + "\n"
|
||||
|
||||
readme_path.write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_readme()
|
||||
Reference in New Issue
Block a user