From 17d0d607415da1e42e0308a06db0ef9514e794e0 Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Thu, 13 Aug 2026 00:41:16 -0400 Subject: [PATCH] [ADD] tui qemu: rename a VM with the pencil MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A "✎" per row opens an input prefilled with the current name. The given name becomes an override like any other: it survives recomputation, and F4 removes it along with the VM's other settings. An explicit name makes automatic naming GIVE WAY. Switching the VM to GNOME no longer appends "-gnome": adding a suffix would amount to correcting the user. Clearing the field restores the automatic name, copy and desktop suffixes included. The name becomes the machine's HOSTNAME, so it is validated against RFC 1123 before being accepted. One capital or one dot too many and cloud-init silently ignores it -- the VM would stay "ubuntu", and you would find out once deployed. Capitals are lowered, the rest is refused with a message. --- FR --- Un « ✎ » par rangée ouvre une saisie préremplie du nom courant. Le nom donné devient une surcharge comme les autres : il survit au recalcul, et F4 le retire avec le reste des réglages de la VM. Un nom explicite fait CÉDER le nommage automatique. Passer la VM en GNOME n'y colle plus « -gnome » : y ajouter un suffixe reviendrait à corriger l'utilisateur. Vider le champ rend le nom automatique, suffixes de copie et de bureau compris. Le nom devient le NOM D'HÔTE de la machine : il est donc validé en RFC 1123 avant d'être retenu. Une majuscule ou un point de trop et cloud-init l'ignore en silence — la VM resterait « ubuntu », et on le découvrirait une fois déployée. Les majuscules sont abaissées, le reste est refusé avec un message. Assisted-by: Claude Opus 5 --- script/todo/qemu_deploy_form.py | 60 ++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/script/todo/qemu_deploy_form.py b/script/todo/qemu_deploy_form.py index 568b494..e982af9 100644 --- a/script/todo/qemu_deploy_form.py +++ b/script/todo/qemu_deploy_form.py @@ -180,6 +180,20 @@ def apply_overrides(vms, entries, overrides): return vms +def clean_hostname(value): + """Nom d'hote valide (RFC 1123) tire de la saisie, ou None. + + Le nom d'une VM devient son NOM D'HOTE : une majuscule ou un point de + trop et cloud-init l'ignore en silence, la machine reste « ubuntu ». + Mieux vaut refuser ici que le decouvrir sur une VM deja deployee.""" + txt = str(value or "").strip().lower() + if not txt or len(txt) > 63: + return None + if not re.fullmatch(r"[a-z0-9]([a-z0-9-]*[a-z0-9])?", txt): + return None + return txt + + def vm_name(base, desktop, suffixes): """Nom de VM, suffixé du bureau quand il y en a un. @@ -211,7 +225,11 @@ def build_vms( ) # APRÈS les surcharges : c'est là seulement que le type de chaque VM est # connu, puisqu'il se choisit machine par machine. - for vm in vms: + for vm, e in zip(vms, entries): + if (overrides or {}).get(entry_key(e), {}).get("name"): + # Nom donne a la main : il gagne, sans suffixe ajoute. Y coller + # « -gnome » reviendrait a corriger l'utilisateur. + continue vm["name"] = vm_name(vm["name"], vm.get("desktop"), suffixes) return vms @@ -368,6 +386,38 @@ def run_deploy_form(ctx, run_app: bool = True): f"RAM≥{e['ram']}Mo {e['disk']}" ) + class RenameScreen(ModalScreen): + """Nom d'une VM. Vide = revenir au nom automatique.""" + + BINDINGS = [("escape", "cancel", t("Cancel"))] + + def __init__(self, name, auto): + super().__init__() + self._name = name + self._auto = auto + + def compose(self) -> ComposeResult: + with Vertical(id="renbox"): + yield Static(t("Rename the VM"), id="rentitle") + yield Input(value=self._name, id="renval") + yield Static( + f" {t('Empty = back to the automatic name:')} " + f"{self._auto}", + id="renhint", + ) + with Horizontal(id="renbtns"): + yield Button(t("Cancel"), id="ren_no") + yield Button(t("Rename"), variant="primary", id="ren_ok") + + def on_button_pressed(self, event) -> None: + if event.button.id != "ren_ok": + self.dismiss(None) + return + self.dismiss(self.query_one("#renval", Input).value) + + def action_cancel(self) -> None: + self.dismiss(None) + class PreviewScreen(ModalScreen): """Aperçu des commandes qui seraient lancées (aucune exécution).""" @@ -427,6 +477,14 @@ def run_deploy_form(ctx, run_app: bool = True): .vmrow Select { width: 15; } .vmrow Input { width: 11; } #reslabel { color: $text-muted; } + RenameScreen { align: center middle; } + #renbox { + width: 60; height: auto; padding: 1 2; + border: thick $accent; background: $surface; + } + #rentitle { color: $accent; text-style: bold; } + #renhint { color: $text-muted; } + #renbtns { height: auto; padding-top: 1; } PreviewScreen { align: center middle; } #prevbox { width: 90%; height: 70%; padding: 1 2;