Files
repoCat/src/repocat/cli/archive.py
Max P. 39f01b266f
All checks were successful
Auto Changelog & (Release) / release (push) Successful in 6s
Build and Publish nightly package / build-and-publish (push) Successful in 31s
fix(archive): skip categories with zero or unset days config
2025-11-27 19:57:43 +01:00

99 lines
3.5 KiB
Python

import shutil
import tarfile
from datetime import datetime
from pathlib import Path
from typer import Typer, Option
from rich.console import Console
from rich.table import Table
import zstandard
import uuid
from repocat.config import load_config
from repocat.models.catalog import RepoCatalogState
app = Typer()
console = Console()
def archive_repo(source: Path, target_dir: Path, dry_run: bool) -> Path:
today = datetime.today().strftime("%Y.%m.%d")
unique = uuid.uuid4().hex[:8]
archive_name = f"{today} - {source.name} - {unique}.tar.zst"
archive_path = target_dir / archive_name
if archive_path.exists():
raise FileExistsError(f"Archiv existiert bereits: {archive_path}")
if dry_run:
return archive_path
with open(archive_path, "wb") as f:
cctx = zstandard.ZstdCompressor(level=20, threads=-1)
with cctx.stream_writer(f) as compressor:
with tarfile.open(fileobj=compressor, mode="w|") as tar:
tar.add(source, arcname=source.name)
shutil.rmtree(source)
return archive_path
@app.command("run")
def run(
older_than: int = Option(30, "--older-than", help="Nur Repositories älter als X Tage archivieren."),
dry_run: bool = Option(False, "--dry-run", help="Keine Änderungen vornehmen."),
category: list[str] = Option(None, "--category", "-c", help="Nur bestimmte Kategorien prüfen."),
):
config = load_config()
catalog = RepoCatalogState.from_config(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 SystemExit(1)
archive_path = archive_cat.path
archive_path.mkdir(parents=True, exist_ok=True)
table = Table(title="Archivierung")
table.add_column("Kategorie")
table.add_column("Repository")
table.add_column("Alter", justify="right")
table.add_column("Größe (MB)", justify="right")
table.add_column("Aktion")
archived = 0
skipped = 0
for cat in catalog.categories:
if cat.config.is_archive or cat.config.name == "review" or cat.config.volatile:
continue
if category and cat.config.name not in category:
continue
if cat.config.days == 0 or cat.config.days is None:
continue
limit_days = cat.config.days if cat.config.days is not None else older_than
for repo in cat.repos:
if not repo.is_expired(limit_days):
table.add_row(cat.config.name, repo.name, str(repo.age_days), f"{repo.size_mb:.1f}", "[blue]Zu jung[/]")
skipped += 1
continue
if repo.git and repo.git.is_protected:
table.add_row(cat.config.name, repo.name, str(repo.age_days), f"{repo.size_mb:.1f}", "[blue]Geschützt (git)[/]")
skipped += 1
continue
try:
archive_file = archive_repo(repo.path, archive_path, dry_run)
action = "[yellow]Würde archivieren[/]" if dry_run else f"[green]Archiviert →[/] {archive_file.name}"
archived += 1
except Exception as e:
action = f"[red]Fehler: {e}[/]"
table.add_row(cat.config.name, repo.name, str(repo.age_days), f"{repo.size_mb:.1f}", action)
console.print(table)
console.print(f"\n[green]✓ Archivierung abgeschlossen[/] – {archived} archiviert, {skipped} übersprungen")