feat: in-place per-file progress for classify, count, and large-file steps
This commit is contained in:
parent
bbaf387cb7
commit
206d2d34f6
3 changed files with 49 additions and 10 deletions
40
luminos.py
40
luminos.py
|
|
@ -3,8 +3,9 @@
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
from luminos_lib.tree import build_tree, render_tree
|
from luminos_lib.tree import build_tree, render_tree
|
||||||
from luminos_lib.filetypes import classify_files, summarize_categories
|
from luminos_lib.filetypes import classify_files, summarize_categories
|
||||||
|
|
@ -15,6 +16,28 @@ from luminos_lib.watch import watch_loop
|
||||||
from luminos_lib.report import format_report
|
from luminos_lib.report import format_report
|
||||||
|
|
||||||
|
|
||||||
|
def _progress(label):
|
||||||
|
"""Return (on_file, finish) for in-place per-file progress on stderr.
|
||||||
|
|
||||||
|
on_file(path) overwrites the current line with the label and truncated path.
|
||||||
|
finish() finalises the line with a newline.
|
||||||
|
"""
|
||||||
|
cols = shutil.get_terminal_size((80, 20)).columns
|
||||||
|
prefix = f" [scan] {label}... "
|
||||||
|
available = max(cols - len(prefix), 10)
|
||||||
|
|
||||||
|
def on_file(path):
|
||||||
|
rel = os.path.relpath(path)
|
||||||
|
if len(rel) > available:
|
||||||
|
rel = "..." + rel[-(available - 3):]
|
||||||
|
print(f"\r{prefix}{rel}\033[K", end="", file=sys.stderr, flush=True)
|
||||||
|
|
||||||
|
def finish():
|
||||||
|
print(f"\r{prefix}done\033[K", file=sys.stderr, flush=True)
|
||||||
|
|
||||||
|
return on_file, finish
|
||||||
|
|
||||||
|
|
||||||
def scan(target, depth=3, show_hidden=False):
|
def scan(target, depth=3, show_hidden=False):
|
||||||
"""Run all analyses on the target directory and return a report dict."""
|
"""Run all analyses on the target directory and return a report dict."""
|
||||||
report = {}
|
report = {}
|
||||||
|
|
@ -24,16 +47,21 @@ def scan(target, depth=3, show_hidden=False):
|
||||||
report["tree"] = tree
|
report["tree"] = tree
|
||||||
report["tree_rendered"] = render_tree(tree)
|
report["tree_rendered"] = render_tree(tree)
|
||||||
|
|
||||||
print(" [scan] Classifying files...", file=sys.stderr)
|
on_file, finish = _progress("Classifying files")
|
||||||
classified = classify_files(target, show_hidden=show_hidden)
|
classified = classify_files(target, show_hidden=show_hidden, on_file=on_file)
|
||||||
|
finish()
|
||||||
report["file_categories"] = summarize_categories(classified)
|
report["file_categories"] = summarize_categories(classified)
|
||||||
report["classified_files"] = classified
|
report["classified_files"] = classified
|
||||||
|
|
||||||
print(" [scan] Detecting languages and counting lines...", file=sys.stderr)
|
on_file, finish = _progress("Counting lines")
|
||||||
languages, loc = detect_languages(classified)
|
languages, loc = detect_languages(classified, on_file=on_file)
|
||||||
|
finish()
|
||||||
report["languages"] = languages
|
report["languages"] = languages
|
||||||
report["lines_of_code"] = loc
|
report["lines_of_code"] = loc
|
||||||
report["large_files"] = find_large_files(classified)
|
|
||||||
|
on_file, finish = _progress("Checking for large files")
|
||||||
|
report["large_files"] = find_large_files(classified, on_file=on_file)
|
||||||
|
finish()
|
||||||
|
|
||||||
print(" [scan] Finding recently modified files...", file=sys.stderr)
|
print(" [scan] Finding recently modified files...", file=sys.stderr)
|
||||||
report["recent_files"] = find_recent_files(target, show_hidden=show_hidden)
|
report["recent_files"] = find_recent_files(target, show_hidden=show_hidden)
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,11 @@ def _count_lines(filepath):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def detect_languages(classified_files):
|
def detect_languages(classified_files, on_file=None):
|
||||||
"""Detect languages present and count lines of code per language.
|
"""Detect languages present and count lines of code per language.
|
||||||
|
|
||||||
Returns (languages_set, loc_by_language).
|
Returns (languages_set, loc_by_language).
|
||||||
|
on_file(path) is called per source file, if provided.
|
||||||
"""
|
"""
|
||||||
source_files = [f for f in classified_files if f["category"] == "source"]
|
source_files = [f for f in classified_files if f["category"] == "source"]
|
||||||
languages = set()
|
languages = set()
|
||||||
|
|
@ -49,12 +50,17 @@ def detect_languages(classified_files):
|
||||||
languages.add(lang)
|
languages.add(lang)
|
||||||
lines = _count_lines(f["path"])
|
lines = _count_lines(f["path"])
|
||||||
loc[lang] = loc.get(lang, 0) + lines
|
loc[lang] = loc.get(lang, 0) + lines
|
||||||
|
if on_file:
|
||||||
|
on_file(f["path"])
|
||||||
|
|
||||||
return sorted(languages), loc
|
return sorted(languages), loc
|
||||||
|
|
||||||
|
|
||||||
def find_large_files(classified_files):
|
def find_large_files(classified_files, on_file=None):
|
||||||
"""Find files that are unusually large (>1000 lines or >10MB)."""
|
"""Find files that are unusually large (>1000 lines or >10MB).
|
||||||
|
|
||||||
|
on_file(path) is called per source file checked, if provided.
|
||||||
|
"""
|
||||||
source_files = [f for f in classified_files if f["category"] == "source"]
|
source_files = [f for f in classified_files if f["category"] == "source"]
|
||||||
large = []
|
large = []
|
||||||
|
|
||||||
|
|
@ -68,5 +74,7 @@ def find_large_files(classified_files):
|
||||||
if reasons:
|
if reasons:
|
||||||
large.append({"path": f["path"], "name": f["name"],
|
large.append({"path": f["path"], "name": f["name"],
|
||||||
"reasons": reasons})
|
"reasons": reasons})
|
||||||
|
if on_file:
|
||||||
|
on_file(f["path"])
|
||||||
|
|
||||||
return large
|
return large
|
||||||
|
|
|
||||||
|
|
@ -86,10 +86,11 @@ def _classify_one(filepath):
|
||||||
return "unknown", desc
|
return "unknown", desc
|
||||||
|
|
||||||
|
|
||||||
def classify_files(target, show_hidden=False):
|
def classify_files(target, show_hidden=False, on_file=None):
|
||||||
"""Walk the target directory and classify every file.
|
"""Walk the target directory and classify every file.
|
||||||
|
|
||||||
Returns a list of dicts: {path, name, category, size, description}.
|
Returns a list of dicts: {path, name, category, size, description}.
|
||||||
|
on_file(path) is called after each file is classified, if provided.
|
||||||
"""
|
"""
|
||||||
results = []
|
results = []
|
||||||
for root, dirs, files in os.walk(target):
|
for root, dirs, files in os.walk(target):
|
||||||
|
|
@ -112,6 +113,8 @@ def classify_files(target, show_hidden=False):
|
||||||
"size": size,
|
"size": size,
|
||||||
"description": desc,
|
"description": desc,
|
||||||
})
|
})
|
||||||
|
if on_file:
|
||||||
|
on_file(full)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue