evita prompts de git interactius i mostra el motiu d'error sencer
This commit is contained in:
+35
-16
@@ -25,7 +25,7 @@ from rich.live import Live
|
|||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
|
|
||||||
__version__ = "1.0.4"
|
__version__ = "1.0.5"
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
@@ -301,30 +301,35 @@ def render(entries: list[RepoEntry], cursor: int, base: Path, owner: str, status
|
|||||||
# Cursor
|
# Cursor
|
||||||
caret = Text("▶", style="bold yellow") if i == cursor else Text(" ")
|
caret = Text("▶", style="bold yellow") if i == cursor else Text(" ")
|
||||||
|
|
||||||
# Estado
|
# Estat
|
||||||
if e.cloning:
|
if e.cloning:
|
||||||
state = Text(f"{spinner_frame()} clonant…", style="bold blue")
|
state = Text(f"{spinner_frame()} clonant…", style="bold blue")
|
||||||
elif e.cloned_ok is True:
|
elif e.cloned_ok is True:
|
||||||
state = Text("✓ clonado", style="bold green")
|
state = Text("✓ clonat", style="bold green")
|
||||||
elif e.cloned_ok is False:
|
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:
|
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:
|
elif e.local_path is not None:
|
||||||
state = Text("● en local", style="green")
|
state = Text("● en local", style="green")
|
||||||
elif e.selected:
|
elif e.selected:
|
||||||
state = Text("☑ marcado", style="bold cyan")
|
state = Text("☑ marcat", style="bold cyan")
|
||||||
else:
|
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)
|
name = Text(e.name)
|
||||||
if e.remote and e.remote.private:
|
if e.remote and e.remote.private:
|
||||||
name = Text("🔒 ", style="yellow") + name
|
name = Text("🔒 ", style="yellow") + name
|
||||||
if i == cursor:
|
if i == cursor:
|
||||||
name.stylize("bold underline")
|
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)
|
table.add_row(caret, state, name, desc)
|
||||||
|
|
||||||
legend = Text.assemble(
|
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]:
|
def clone_one(entry: RepoEntry, base: Path, cfg: Config) -> tuple[RepoEntry, bool, str]:
|
||||||
if entry.remote is None:
|
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
|
url = entry.remote.ssh_url if cfg.clone_protocol == "ssh" else entry.remote.clone_url
|
||||||
if not url:
|
if not url:
|
||||||
return entry, False, "URL vacía"
|
return entry, False, "URL buida"
|
||||||
target = base / entry.name
|
target = base / entry.name
|
||||||
if target.exists():
|
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:
|
try:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["git", "clone", "--quiet", url, str(target)],
|
["git", "clone", "--quiet", url, str(target)],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
timeout=600,
|
timeout=600,
|
||||||
|
stdin=subprocess.DEVNULL,
|
||||||
|
env=env,
|
||||||
)
|
)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
err = (result.stderr or result.stdout or "git clone falló").strip().splitlines()
|
# Netegem la carpeta parcial si git la va crear
|
||||||
return entry, False, err[-1][:80] if err else "error"
|
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"
|
return entry, True, "ok"
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
return entry, False, "timeout"
|
if target.exists():
|
||||||
|
shutil.rmtree(target, ignore_errors=True)
|
||||||
|
return entry, False, "timeout (>10 min)"
|
||||||
except FileNotFoundError:
|
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:
|
def run_clone_queue(entries: list[RepoEntry], base: Path, cfg: Config, live: Live, cursor: int, owner: str) -> int:
|
||||||
|
|||||||
Reference in New Issue
Block a user