- Replaces manual path handling with `RepoCatalogState` abstraction - Simplifies repo status checks and removes redundant imports - Improves clarity and maintainability of interactive review process
89 lines
3.2 KiB
Python
89 lines
3.2 KiB
Python
from typer import Typer
|
|
from rich.console import Console
|
|
from rich.prompt import Prompt, Confirm
|
|
from datetime import datetime
|
|
import shutil
|
|
import typer
|
|
|
|
from repocat.config import load_config
|
|
from repocat.models.catalog import RepoCatalogState
|
|
from repocat.cli.move import move_command
|
|
from repocat.cli.archive import archive_repo
|
|
|
|
app = Typer()
|
|
console = Console()
|
|
|
|
|
|
@app.command("run")
|
|
def review():
|
|
"""
|
|
Führt interaktiv durch alle Repositories im Review-Ordner.
|
|
"""
|
|
catalog = RepoCatalogState.from_config(load_config())
|
|
|
|
archive_cat = next((c for c in catalog.categories if c.config.is_archive), None)
|
|
if not archive_cat:
|
|
console.print("[red]Keine Archiv-Kategorie in der Konfiguration gefunden.[/]")
|
|
raise typer.Exit(1)
|
|
|
|
review_cat = catalog.get_category("review")
|
|
if not review_cat:
|
|
console.print("[red]Kein 'review'-Eintrag in der Konfiguration gefunden.[/]")
|
|
raise typer.Exit(1)
|
|
|
|
if not review_cat.repos:
|
|
console.print("[green]✓ Keine Repositories im Review-Ordner.[/]")
|
|
return
|
|
|
|
for repo in sorted(review_cat.repos, key=lambda r: r.name):
|
|
console.rule(f"[bold cyan]{repo.name}")
|
|
|
|
console.print(f"[bold]Alter:[/] {repo.age_days} Tage")
|
|
console.print(f"[bold]Größe:[/] {repo.size_mb:.1f} MB")
|
|
|
|
if repo.git:
|
|
status = []
|
|
if repo.git.dirty:
|
|
status.append("uncommitted")
|
|
if repo.git.unpushed:
|
|
status.append("unpushed")
|
|
if not status:
|
|
status.append("clean")
|
|
else:
|
|
status = ["kein Git"]
|
|
|
|
console.print(f"[bold]Git:[/] {', '.join(status)}")
|
|
|
|
while True:
|
|
action = Prompt.ask(
|
|
"Aktion \\[m]ove / \\[a]rchive / \\[d]elete / \\[s]kip / \\[q]uit",
|
|
choices=["m", "a", "d", "s", "q"],
|
|
show_choices=False
|
|
)
|
|
|
|
if action in ("s", "skip", ""):
|
|
break
|
|
elif action in ("q", "quit"):
|
|
console.print("[bold yellow]Abgebrochen.[/]")
|
|
raise typer.Exit()
|
|
elif action in ("d", "delete"):
|
|
if Confirm.ask(f"Bist du sicher, dass du [red]{repo.name}[/] löschen willst?"):
|
|
shutil.rmtree(repo.path)
|
|
console.print(f"[red]✓ Gelöscht:[/] {repo.name}")
|
|
break
|
|
elif action in ("m", "move"):
|
|
target_categories = [c.config.name for c in catalog.categories if c.config.name != "review" and not c.config.is_archive]
|
|
target = Prompt.ask("Zielkategorie", choices=target_categories)
|
|
move_command(source=f"review/{repo.name}", target=target)
|
|
break
|
|
elif action in ("a", "archive"):
|
|
try:
|
|
archive_file = archive_repo(repo.path, archive_cat.path, dry_run=False)
|
|
console.print(f"[green]✓ Archiviert:[/] {archive_file.name}")
|
|
break
|
|
except Exception as e:
|
|
console.print(f"[red]Fehler beim Archivieren:[/] {e}")
|
|
else:
|
|
console.print("[yellow]Ungültige Eingabe. Gültig sind: m, d, s, q[/]")
|
|
|
|
console.print("[green]✓ Review abgeschlossen.[/]") |