From aaf02c4ee69787d2d567318973edfee482eb07c8 Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Thu, 13 Aug 2026 04:51:27 -0400 Subject: [PATCH] [ADD] tui qemu: F9 dumps the form state, widgets and model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A per-VM setting appears not to be taken into account, and nothing on screen tells which link failed: the gap may be between the widget and the model, or between the model and the spec. A screenshot shows neither. F9 writes both side by side into ~/.erplibre/deploy-form-dump.txt: profile, shared values, overrides, locks, row generation, then VM by VM what the list DISPLAYS against what the model HOLDS, and finally the spec that would go to deployment. The file can be pasted into a message, unlike an image, and it answers the question on its own: if the list shows 16384 while the model says 1024, the defect is in the intake; if they agree and the created VM differs, it is downstream, in deploy_qemu. --- FR --- Un réglage par VM ne semble pas pris en compte, et rien dans ce que l'écran montre ne permet de trancher : l'écart peut être entre le widget et le modèle, ou entre le modèle et la spec. Une capture d'écran ne dit ni l'un ni l'autre. F9 écrit les deux côte à côte dans ~/.erplibre/deploy-form-dump.txt : profil, valeurs communes, surcharges, verrous, génération des rangées, puis VM par VM ce que la liste AFFICHE contre ce que le modèle CONTIENT, et enfin la spec qui partirait au déploiement. Le fichier se recopie dans un message, contrairement à une image, et il répond seul à la question : si la liste montre 16384 et que le modèle dit 1024, le défaut est dans la prise en compte ; s'ils s'accordent et que la VM créée diffère, il est en aval, dans deploy_qemu. Assisted-by: Claude Opus 5 --- script/todo/qemu_deploy_form.py | 56 +++++++++++++++++++++++++++++++++ script/todo/todo_i18n.py | 2 ++ 2 files changed, 58 insertions(+) diff --git a/script/todo/qemu_deploy_form.py b/script/todo/qemu_deploy_form.py index 61c5397..d86f5e7 100644 --- a/script/todo/qemu_deploy_form.py +++ b/script/todo/qemu_deploy_form.py @@ -524,6 +524,7 @@ def run_deploy_form(ctx, run_app: bool = True): ("f5", "deploy", t("Deploy")), ("f4", "clear_vm", t("Reset VM")), ("f3", "preview", t("Preview")), + ("f9", "dump_state", t("Diagnostic dump")), ("f6", "select_all", t("All")), ("f7", "select_main", t("Main versions")), ("f8", "select_none", t("None")), @@ -1755,6 +1756,61 @@ def run_deploy_form(ctx, run_app: bool = True): lines = [build(vm, spec, True) for vm in spec["vms"]] self.push_screen(PreviewScreen(lines or [t("Nothing selected.")])) + def action_dump_state(self) -> None: + """Écrit l'état COMPLET dans un fichier, widgets ET modèle. + + Une capture d'écran ne dit pas si l'écart vient de ce qu'on voit + ou de ce qui sera déployé. Ce vidage met les deux côte à côte, VM + par VM : si la liste affiche 16384 et que le modèle dit 1024, le + défaut est dans la prise en compte ; s'ils s'accordent et que la + VM déployée diffère, il est en aval.""" + path = os.path.expanduser("~/.erplibre/deploy-form-dump.txt") + os.makedirs(os.path.dirname(path), exist_ok=True) + out = [ + "=== formulaire de deploiement ===", + f"profil={self.profile} custom={self.custom}", + f"verrous={sorted(self.locked)}", + f"surcharges={self.overrides}", + f"generation={self._gen} jeu_monte={self._shown_ids}", + f"branche_globale={self._branch()}", + f"profil_odoo_global={self._profile_cmd()}", + "", + " # widget -> modele, VM par VM", + ] + for i, r in enumerate(self.rows): + vm = r["vm"] + shown = {} + for f in ("vcpus", "ram", "disk", "type", "branch", "prof"): + try: + shown[f] = self.query_one(f"#v{i}_{f}", Select).value + except Exception: + shown[f] = "-" + try: + free = self.query_one(f"#c{i}_{f}", Input) + if free.display: + shown[f] = f"libre:{free.value!r}" + except Exception: + pass + out.append(f" [{i}] {vm['name']} etat={r['state']}") + out.append(f" widgets = {shown}") + out.append( + f" modele = vcpus={vm['vcpus']} ram={vm['ram']} " + f"disk={vm['disk']} desktop={vm.get('desktop')!r} " + f"branch={vm.get('branch')!r} cmd={vm.get('install_cmd')!r}" + ) + spec = build_spec(self.vms, domains, self._form_values()) + out.append("") + out.append(" # spec qui partirait au deploiement") + for vm in spec["vms"]: + out.append( + f" {vm['name']}: ram={vm['ram']} vcpus={vm['vcpus']} " + f"disk={vm['disk']}" + ) + out.append(f" ignorees (existent deja) = {spec['existing']}") + with open(path, "w", encoding="utf-8") as fh: + fh.write("\n".join(out) + "\n") + self.notify(f"{t('State written to')} {path}") + def action_deploy(self) -> None: if not self.vms: self.notify(t("Nothing selected."), severity="warning") diff --git a/script/todo/todo_i18n.py b/script/todo/todo_i18n.py index 775f041..b4e69f7 100644 --- a/script/todo/todo_i18n.py +++ b/script/todo/todo_i18n.py @@ -2275,6 +2275,8 @@ TRANSLATIONS = { "en": "already defined, not counted", }, "RAM: 2048 or 8G": {"fr": "RAM : 2048 ou 8G", "en": "RAM: 2048 or 8G"}, + "Diagnostic dump": {"fr": "Diagnostic", "en": "Diagnostic dump"}, + "State written to": {"fr": "État écrit dans", "en": "State written to"}, "Reset VM": { "fr": "Réinit. VM", "en": "Reset VM",