diff --git a/repoman.py b/repoman.py index a4f8808..458d43f 100644 --- a/repoman.py +++ b/repoman.py @@ -25,7 +25,7 @@ from rich.live import Live from rich.table import Table from rich.text import Text -__version__ = "1.0.4" +__version__ = "1.0.5" console = Console() @@ -301,30 +301,35 @@ def render(entries: list[RepoEntry], cursor: int, base: Path, owner: str, status # Cursor caret = Text("▶", style="bold yellow") if i == cursor else Text(" ") - # Estado + # Estat if e.cloning: state = Text(f"{spinner_frame()} clonant…", style="bold blue") elif e.cloned_ok is True: - state = Text("✓ clonado", style="bold green") + state = Text("✓ clonat", style="bold green") elif e.cloned_ok is False: - state = Text(f"✗ {e.error[:11]}", style="bold red") + state = Text("✗ error", style="bold red") elif e.local_path is not None and e.remote is None: - state = Text("◇ sólo local", style="dim yellow") + state = Text("◇ només local", style="dim yellow") elif e.local_path is not None: state = Text("● en local", style="green") elif e.selected: - state = Text("☑ marcado", style="bold cyan") + state = Text("☑ marcat", style="bold cyan") else: - state = Text("○ remoto", style="dim") + state = Text("○ remot", style="dim") - # Nombre con marca de privado + # Nom amb marca de privat name = Text(e.name) if e.remote and e.remote.private: name = Text("🔒 ", style="yellow") + name if i == cursor: name.stylize("bold underline") - desc = (e.remote.description if e.remote else "(no está en el servidor)") or "—" + # Descripció: motiu de l'error si n'hi ha, si no la del repo + if e.cloned_ok is False and e.error: + desc = Text(e.error, style="red") + else: + desc_text = (e.remote.description if e.remote else "(no està al servidor)") or "—" + desc = Text(desc_text) table.add_row(caret, state, name, desc) legend = Text.assemble( @@ -346,28 +351,42 @@ def render(entries: list[RepoEntry], cursor: int, base: Path, owner: str, status def clone_one(entry: RepoEntry, base: Path, cfg: Config) -> tuple[RepoEntry, bool, str]: if entry.remote is None: - return entry, False, "sin info remota" + return entry, False, "sense info remota" url = entry.remote.ssh_url if cfg.clone_protocol == "ssh" else entry.remote.clone_url if not url: - return entry, False, "URL vacía" + return entry, False, "URL buida" target = base / entry.name if target.exists(): - return entry, False, "ya existe en local" + return entry, False, "ja existeix en local" + env = { + **os.environ, + "GIT_TERMINAL_PROMPT": "0", # mai demanar credencials interactivament + "GIT_ASKPASS": "/bin/true", # cap helper interactiu + "SSH_ASKPASS": "/bin/true", + } try: result = subprocess.run( ["git", "clone", "--quiet", url, str(target)], capture_output=True, text=True, timeout=600, + stdin=subprocess.DEVNULL, + env=env, ) if result.returncode != 0: - err = (result.stderr or result.stdout or "git clone falló").strip().splitlines() - return entry, False, err[-1][:80] if err else "error" + # Netegem la carpeta parcial si git la va crear + if target.exists(): + shutil.rmtree(target, ignore_errors=True) + err_lines = (result.stderr or result.stdout or "git clone ha fallat").strip().splitlines() + err_msg = " ".join(l.strip() for l in err_lines if l.strip()) + return entry, False, err_msg or "error desconegut" return entry, True, "ok" except subprocess.TimeoutExpired: - return entry, False, "timeout" + if target.exists(): + shutil.rmtree(target, ignore_errors=True) + return entry, False, "timeout (>10 min)" except FileNotFoundError: - return entry, False, "git no encontrado" + return entry, False, "git no trobat" def run_clone_queue(entries: list[RepoEntry], base: Path, cfg: Config, live: Live, cursor: int, owner: str) -> int: