[FIX] cache et guide : suivre la traduction du binaire et le hors ligne

Le rebase apporte trois choses auxquelles ce travail devait s'accorder.
Les messages du binaire se traduisent désormais : ceux du refus de place
et de l'aide de --oublie passent par T(), avec leur entrée au catalogue —
deux garde-fous refusent sinon un message sans traduction ou l'inverse.

Soustraire l'hôte au cache est REFUSÉ hors ligne : le magasin est alors la
seule source, et l'excepter ne le ferait pas télécharger en direct, cela
le priverait de tout, ses propres paquets compris.

Et le guide de connexion annonce les outils sur la voie Proxmox aussi ; il
n'y était plus écrit du tout, l'argument manquant étant avalé.

--- EN ---

The rebase brings three things this work had to align with. The binary's
messages are now translatable: the out-of-space refusal and the --oublie
help go through T(), with their catalogue entry — two guard rails
otherwise refuse a message without a translation, or the reverse.

Exempting the host from the cache is REFUSED offline: the store is then
the only source, and exempting it would not make it download directly, it
would leave it with nothing, its own packages included.

And the connection guide announces the tools on the Proxmox path too; it
was no longer written there at all, the missing argument being swallowed.

Assisted-by: Claude Opus 5
This commit is contained in:
Mathieu Benoit 2026-09-16 05:58:59 -04:00
parent 1f5bdceb2a
commit 0105cf16e5
3 changed files with 55 additions and 3 deletions

View file

@ -3594,8 +3594,13 @@ def guide_files(args: argparse.Namespace) -> list[tuple[str, str, str, str]]:
args.erplibre_make,
editor,
bool(args.desktop),
# « getattr » et non « args.vm_tools » : la voie Proxmox
# bâtit ses arguments à la main, et un champ qui lui manque
# ferait avaler le guide par son « except Exception ».
tuple(
c.strip() for c in args.vm_tools.split(",") if c.strip()
c.strip()
for c in getattr(args, "vm_tools", "").split(",")
if c.strip()
),
),
"",

View file

@ -1749,7 +1749,7 @@ class ProxmoxMenuMixin:
print(ligne)
vm.setdefault("notes", []).append(ligne.strip())
def _pve_cache_bypass_hote(self, host, vm):
def _pve_cache_bypass_hote(self, host, vm, hors_ligne=False):
"""Soustrait au cache l'hôte Proxmox qui porte un invité sans magasin.
Rend True quand l'exception est en place, False quand il n'y a rien à
@ -1774,7 +1774,16 @@ class ProxmoxMenuMixin:
CE QU'ELLE COÛTE. L'exception vaut pour TOUT ce que l'hôte relaie, y
compris ses propres téléchargements : il cesse de profiter du cache.
C'est le prix, et il est dit plutôt que subi.
JAMAIS HORS LIGNE. L'amont du cache est alors coupé et le magasin est
la SEULE source : excepter l'hôte ne le ferait pas télécharger en
direct, cela le priverait de tout — ses propres paquets compris. Les
deux issues échouent pour l'invité, mais celle-ci emporte l'hôte avec
lui. On garde donc le cache, et l'avertissement qui suit dit à
l'invité ce qui l'attend.
"""
if hors_ligne:
return False
try:
mod = self._qemu_import_module()
except Exception: # pragma: no cover - dépend du module
@ -2040,6 +2049,18 @@ class ProxmoxMenuMixin:
),
erplibre_make=self._qemu_make_target(cmd_install),
desktop=bool(vm.get("desktop")),
# Les outils que le guide annoncera, FILTRÉS par cette machine
# comme la voie libvirt le fait : en annoncer un que l'
# architecture ou l'absence de bureau écarte enverrait chercher
# une commande qui ne sera jamais posée.
vm_tools=",".join(
self._qemu_tools_for(
spec.get("vm_tools") or (),
vm.get("arch") or "amd64",
bool(vm.get("desktop")),
vm.get("distro") or "",
)
),
no_git_identity=False,
user=spec.get("user") or "erplibre",
)
@ -2295,7 +2316,9 @@ class ProxmoxMenuMixin:
# par fichier ne peut RIEN recevoir : on soustrait son
# hôte au cache à la place. L'autorité n'est posée que
# lorsqu'il y a quelqu'un pour la recevoir.
if not self._pve_cache_bypass_hote(host, vm):
if not self._pve_cache_bypass_hote(
host, vm, hors_ligne=bool(coupee)
):
self._pve_set_cache_ca(
vm["alias"],
vm,

View file

@ -2742,6 +2742,30 @@ class UnInviteImbriqueSortMasqueDerriereSonHote(unittest.TestCase):
)
self.assertIn('entry["notes"] = list(notes[name])', dep)
def test_offline_never_exempts(self):
"""L'amont du cache est alors coupé et le magasin est la SEULE
source : excepter l'hôte ne le ferait pas télécharger en direct, cela
le priverait de tout — ses propres paquets compris. Les deux issues
échouent pour l'invité, mais celle-ci emporte l'hôte avec lui."""
import contextlib
import io
import subprocess as sp
todo = self._todo()
todo._qemu_import_module = lambda: self._Mod
todo._qemu_list_domains = lambda: ["pve-local"]
todo._qemu_domain_mac = lambda nom: "52:54:00:ab:cd:ef"
lance = []
vrai = sp.run
self.addCleanup(setattr, sp, "run", vrai)
sp.run = lambda c, **k: lance.append(c)
with contextlib.redirect_stdout(io.StringIO()):
rendu = todo._pve_cache_bypass_hote(
{"target": "pve-local"}, {"distro": "nixos"}, hors_ligne=True
)
self.assertFalse(rendu)
self.assertEqual([], lance, "une exception posée hors ligne")
def test_the_price_is_said(self):
"""L'exception vaut pour TOUT ce que l'hôte relaie, ses propres
téléchargements compris. Le taire ferait chercher plus tard pourquoi