diff --git a/script/todo/qemu_install_monitor.py b/script/todo/qemu_install_monitor.py index 8f89266..9630465 100644 --- a/script/todo/qemu_install_monitor.py +++ b/script/todo/qemu_install_monitor.py @@ -44,6 +44,34 @@ def session_dir() -> Path: return base +def list_install_runs() -> list: + """Runs d'installation passés (chacun a un session.json), TRIÉS du plus + récent au plus ancien. Chaque entrée : dict {label, manifest, mtime, + vms, branch}. Permet de ROUVRIR le suivi d'un run (le dashboard s'étant + fermé sur un bug, on reprend l'analyse).""" + runs = [] + for d in sorted(session_dir().glob("*/"), reverse=True): + manifest = d / "session.json" + if not manifest.is_file(): + continue + try: + data = json.loads(manifest.read_text()) + mtime = manifest.stat().st_mtime + except (OSError, ValueError): + continue + runs.append( + { + "label": d.name.rstrip("/"), + "manifest": str(manifest), + "mtime": mtime, + "vms": data.get("vms", []), + "branch": data.get("branch", ""), + } + ) + runs.sort(key=lambda r: r["mtime"], reverse=True) + return runs + + def _launch_one(ip: str, remote_cmd: str, log_path: str) -> None: """Lance une install SSH DÉTACHÉE : attend le sshd, exécute, journalise la sortie puis écrit le marqueur de fin avec le code de sortie.""" diff --git a/script/todo/todo.py b/script/todo/todo.py index f97059b..4115952 100755 --- a/script/todo/todo.py +++ b/script/todo/todo.py @@ -1087,6 +1087,11 @@ class TODO: "Test a VM (open Odoo in a CLI browser)" ) }, + { + "prompt_description": t( + "Reopen install monitoring (last run / history)" + ) + }, {"section": t("Catalog")}, {"prompt_description": t("List available images and specs")}, ] @@ -1121,6 +1126,8 @@ class TODO: elif status == "10": self._qemu_test_vm() elif status == "11": + self._qemu_reopen_monitor() + elif status == "12": self._qemu_list_images() else: cmd_no_found = True @@ -1383,6 +1390,46 @@ class TODO: ) print(f"⚠ {msg}") + def _qemu_reopen_monitor(self): + """Rouvre le suivi d'installation (dashboard) sur un run PASSÉ : le + dernier par défaut, ou un choix dans l'historique. Utile quand le + dashboard s'est fermé et qu'on veut reprendre l'analyse.""" + from script.todo import qemu_install_monitor as mon + + runs = mon.list_install_runs() + if not runs: + print(t("No install run found in history.")) + return + print(f"\n{t('Install runs (most recent first):')}") + for i, r in enumerate(runs, 1): + names = ", ".join(v.get("name", "?") for v in r["vms"]) + star = " *" if i == 1 else "" + print( + f" [{i}] {r['label']} — {len(r['vms'])} VM{star}\n" + f" {names}" + ) + sel = input( + t("Choice (number, blank = last): ") + ).strip() + run = runs[0] + if sel: + try: + idx = int(sel) - 1 + if 0 <= idx < len(runs): + run = runs[idx] + else: + print(t("Invalid selection.")) + return + except ValueError: + print(t("Invalid selection.")) + return + try: + mon.run_monitor(run["manifest"]) + except ImportError: + print(t("Install textual for the dashboard (pip).")) + except Exception as exc: + print(f"{t('Command failed: ')}{exc}") + def _qemu_choose_cli_browser(self): """Offre la LISTE des navigateurs CLI installés, plus une option pour en INSTALLER un autre, et renvoie celui choisi, sinon None.""" diff --git a/script/todo/todo_i18n.py b/script/todo/todo_i18n.py index bd1e830..93996e6 100644 --- a/script/todo/todo_i18n.py +++ b/script/todo/todo_i18n.py @@ -1488,6 +1488,26 @@ TRANSLATIONS = { "fr": "🧪 Tester une VM (ouvrir Odoo dans un navigateur CLI)", "en": "🧪 Test a VM (open Odoo in a CLI browser)", }, + "Reopen install monitoring (last run / history)": { + "fr": "📈 Rouvrir le suivi d'installation (dernier run / historique)", + "en": "📈 Reopen install monitoring (last run / history)", + }, + "No install run found in history.": { + "fr": "Aucun run d'installation dans l'historique.", + "en": "No install run found in history.", + }, + "Install runs (most recent first):": { + "fr": "Runs d'installation (du plus récent) :", + "en": "Install runs (most recent first):", + }, + "Choice (number, blank = last): ": { + "fr": "Choix (numéro, vide = le dernier) : ", + "en": "Choice (number, blank = last): ", + }, + "Invalid selection.": { + "fr": "Sélection invalide.", + "en": "Invalid selection.", + }, "Resolving VM IP...": { "fr": "Résolution de l'IP de la VM…", "en": "Resolving VM IP...",