[ADD] tui qemu: F9 dumps the form state, widgets and model

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
This commit is contained in:
Mathieu Benoit 2026-08-13 04:51:27 -04:00
parent f7f5e800fe
commit aaf02c4ee6
2 changed files with 58 additions and 0 deletions

View file

@ -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")

View file

@ -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",