Les tests longs lançaient la CLI sans privilège, alors que le dossier des images appartient à root en 755 : arrêt à l'étape 1 sur « Permission refusée », avant d'avoir rien créé. Ils ne pouvaient donc pas tourner du tout — pas même échouer utilement. Le menu passe sudo depuis toujours ; c'est cette forme qui est reprise, et jamais à blanc. Le refus de place d'un miroir reprenait un champ que tout appelant laisse à zéro : « moins de 0 o libres » n'annonce aucun seuil et ne dit pas ce qui a été mesuré. Treize tests héritaient du plancher de production, 10 Gio, et rougissaient sur un /tmp en tmpfs. --- EN --- The long tests ran the CLI unprivileged, while the image directory is owned by root, mode 755: they stopped at step 1 on "permission denied", before creating anything. They therefore could not run at all — not even fail usefully. The menu has always passed sudo; that is the form taken here, and never on a dry run. A mirror's refusal for lack of space echoed a field every caller leaves at zero: "less than 0 B free" announces no threshold and does not say what was measured. Thirteen tests inherited the production floor, 10 GiB, and went red on a tmpfs /tmp. Assisted-by: Claude Opus 5
164 lines
18 KiB
Go
164 lines
18 KiB
Go
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
package main
|
|
|
|
// anglais traduit les messages humains du binaire. La clé est le texte
|
|
// français mot pour mot, tel que T le reçoit ; une clé absente sort en
|
|
// français. langue_test.go refuse un T(...) sans entrée, une entrée
|
|
// qu'aucun T(...) n'emploie, et une traduction qui ne garde pas les mêmes
|
|
// verbes de format que son original.
|
|
var anglais = map[string]string{
|
|
"taille vide": "empty size",
|
|
"taille illisible %q : essayer 50G, 500M, 2T": "unreadable size %q: try 50G, 500M, 2T",
|
|
"effacer le moins récemment servi jusqu'à tenir sous cette taille (ex. 50G)": "erase the least recently served until the cache fits under this size (e.g. 50G)",
|
|
"purge au plafond : %v\n": "size purge: %v\n",
|
|
"[à blanc] ": "[dry run] ",
|
|
"plafond %s : le cache occupe %s\n": "ceiling %s: the cache occupies %s\n",
|
|
"%sobjets : %d, %s ; dépôts : %d, %s ; reste %s\n": "%sobjects: %d, %s; repositories: %d, %s; %s left\n",
|
|
"cache : variante de %s non gardée : %v": "cache: variant of %s not kept: %v",
|
|
"langue des messages : fr ou en ; à défaut, EL_LANG": "language of messages: fr or en; otherwise EL_LANG",
|
|
"granularité inconnue %q : jour, semaine ou mois": "unknown granularity %q: day, week or month",
|
|
"durée vide": "empty duration",
|
|
"durée illisible %q": "unreadable duration %q",
|
|
"durée illisible %q : essayer 30j, 12h, 90m": "unreadable duration %q: try 30d, 12h, 90m",
|
|
"Âge du dernier usage, par %s.\n": "Age of last use, by %s.\n",
|
|
"\nUn objet servi voit sa date remise à jour : « vieux » veut donc dire\n« n'a plus servi », et non « est entré il y a longtemps ».\n": "\nA served object has its date renewed: « old » therefore means\n« no longer served », not « stored long ago ».\n",
|
|
" rien": " nothing",
|
|
"[à blanc] objets qui partiraient : %d, %s\n": "[dry run] objects that would go: %d, %s\n",
|
|
"[à blanc] dépôts qui partiraient : %d, %s\n": "[dry run] repositories that would go: %d, %s\n",
|
|
"[à blanc] rien n'a été effacé.": "[dry run] nothing was erased.",
|
|
"erplibre_go_qemu_cache : requête adressée au cache lui-même, refusée.\n demandé : %s\nLa relayer la renverrait vers cette même écoute, sans fin.\n": "erplibre_go_qemu_cache: request addressed to the cache itself, refused.\n requested: %s\nRelaying it would send it back to this same listener, endlessly.\n",
|
|
"boucle refusée : %s vise le cache lui-même": "loop refused: %s targets the cache itself",
|
|
"adresse MAC vide": "empty MAC address",
|
|
"adresse MAC illisible %q": "unreadable MAC address %q",
|
|
"adresse MAC de %d octets, six attendus": "MAC address of %d bytes, six expected",
|
|
"%s est une adresse de groupe : jamais une adresse source": "%s is a group address: never a source address",
|
|
"l'adresse nulle n'identifie aucune machine": "the null address identifies no machine",
|
|
"dépôt illisible %q": "unreadable repository %q",
|
|
"dépôt sans chemin %q": "repository without a path %q",
|
|
"chemin de dépôt refusé %q": "repository path refused %q",
|
|
"miroir refusé pour %s : %s libres sous %s, plancher de %s": "mirror refused for %s: %s free under %s, floor of %s",
|
|
"miroir git : sonde de %s en échec (%v) ; ses miroirs sont servis sans rafraîchissement jusqu'à ce qu'il réponde": "git mirror: probe of %s failed (%v); its mirrors are served without refresh until it answers",
|
|
"git %s : %v : %s": "git %s: %v: %s",
|
|
"miroir éteint": "mirror disabled",
|
|
"hors des miroirs : %s": "outside the mirrors: %s",
|
|
"amont connu muet : l'établissement vient d'échouer, il n'est pas retenté": "upstream known mute: connecting just failed, it is not retried",
|
|
"répertoire des objets gardés": "directory of kept objects",
|
|
"répertoire de l'autorité de certification": "certificate authority directory",
|
|
"écoute pour le 80 détourné": "listener for redirected port 80",
|
|
"écoute pour le 443 détourné": "listener for redirected port 443",
|
|
"pont libvirt des VM": "libvirt bridge of the VMs",
|
|
"sous-réseau des VM": "subnet of the VMs",
|
|
"journal d'accès JSON par ligne": "access log, one JSON object per line",
|
|
"hôtes à ne jamais déchiffrer, séparés par des virgules": "hosts never to decrypt, comma-separated",
|
|
"dire chaque requête": "log every request",
|
|
"dire ce que le cache occupe, puis sortir": "print what the cache occupies, then exit",
|
|
"montrer les gestes privilégiés sans en faire un": "show the privileged steps without performing any",
|
|
"créer l'autorité si elle manque, puis sortir": "create the authority if missing, then exit",
|
|
"écrire les règles nft seules, à passer à « nft -f - »": "print the nft rules alone, to feed to « nft -f - »",
|
|
"écrire les commandes iptables seules, une par ligne": "print the iptables commands alone, one per line",
|
|
"liste des VM soustraites au détournement, une MAC par ligne": "list of VMs excluded from redirection, one MAC per line",
|
|
"soustraire cette adresse MAC au détournement": "exclude this MAC address from redirection",
|
|
"nom de la VM, écrit à côté de la MAC ajoutée": "VM name, written next to the added MAC",
|
|
"rendre cette adresse MAC au détournement": "return this MAC address to redirection",
|
|
"racine des dépôts git tenus en miroir ; vide, git est simplement relayé vers l'amont": "root of the mirrored git repositories; empty, git is simply relayed upstream",
|
|
"délai en deçà duquel un dépôt n'est pas re-interrogé": "delay under which a repository is not queried again",
|
|
"fichier de dépôts, un par ligne, à tenir en miroir d'avance": "file of repositories, one per line, to mirror ahead",
|
|
"dépôts clonés en parallèle par le pré-remplissage": "repositories cloned in parallel by the prefill",
|
|
"dire ce que le cache occupe, groupé par âge du dernier usage": "print what the cache occupies, grouped by age of last use",
|
|
"découpage du relevé par âge : jour, semaine ou mois": "split of the age report: day, week or month",
|
|
"effacer TOUT le cache : objets et dépôts en miroir": "erase the WHOLE cache: objects and mirrored repositories",
|
|
"n'effacer que ce qui n'a pas servi depuis ce délai (ex. 30j, 12h)": "erase only what has not served for this delay (e.g. 30d, 12h)",
|
|
"dire les dépôts tenus en miroir, du plus lourd au plus léger": "list the mirrored repositories, heaviest first",
|
|
"effacer le miroir de ce dépôt ; il se refera au prochain besoin": "erase this repository's mirror; it is rebuilt when next needed",
|
|
"dire les exceptions en place, une « MAC nom » par ligne": "list the exceptions in place, one « MAC name » per line",
|
|
"dire la version, puis sortir": "print the version, then exit",
|
|
"lire des lignes « MÉTHODE URL » sur l'entrée standard et dire, pour chacune, ce que le magasin tient : une ligne séparée par des tabulations « verdict statut stored_at classe méthode url », verdict garde (corps 200), statut (statut seul, sans corps), absent ou non-cachable. Lecture seule : --cache-dir suffit, sans privilège, et l'âge des objets n'est pas touché": "read « METHOD URL » lines on standard input and say, for each, what the store holds: a tab-separated line « verdict status stored_at class method url », verdict garde (200 body), statut (status only, no body), absent or non-cachable. Read-only: --cache-dir is enough, no privilege, and object ages are not touched",
|
|
"entrée illisible : %v\n": "unreadable input: %v\n",
|
|
"exceptions illisibles : %v\n": "unreadable exceptions: %v\n",
|
|
"exception refusée : %v\n": "exception refused: %v\n",
|
|
"exception posée : %s %s\n": "exception added: %s %s\n",
|
|
"aucune exception pour %s\n": "no exception for %s\n",
|
|
"efface ce qui n'a pas servi depuis %s (avant %s)\n": "erasing what has not served for %s (before %s)\n",
|
|
"efface TOUT le cache": "erasing the WHOLE cache",
|
|
"purge des objets : %v\n": "object purge: %v\n",
|
|
"objets effacés : %d, %s rendus\n": "objects erased: %d, %s freed\n",
|
|
"purge des miroirs : %v\n": "mirror purge: %v\n",
|
|
"dépôts effacés : %d, %s rendus\n": "repositories erased: %d, %s freed\n",
|
|
"aucun dépôt en miroir": "no mirrored repository",
|
|
"%10s %d dépôts\n": "%10s %d repositories\n",
|
|
"effacement : %v\n": "erasure: %v\n",
|
|
"miroir effacé : %s\n": "mirror erased: %s\n",
|
|
"miroir git éteint : passer --git-mirror-dir": "git mirror disabled: pass --git-mirror-dir",
|
|
"liste illisible : %v\n": "unreadable list: %v\n",
|
|
"%d dépôts à tenir en miroir sous %s\n": "%d repositories to mirror under %s\n",
|
|
"%d en miroir, %d en échec, %s occupés\n": "%d mirrored, %d failed, %s used\n",
|
|
"état illisible : %v\n": "unreadable state: %v\n",
|
|
"autorité : %v\n": "authority: %v\n",
|
|
"autorité : %s\n": "authority: %s\n",
|
|
"empreinte : %s\n": "fingerprint: %s\n",
|
|
"miroir git demandé mais « git-http-backend » est introuvable : git sera relayé vers l'amont (%s)": "git mirror requested but « git-http-backend » is missing: git will be relayed upstream (%s)",
|
|
"le cache s'arrête : %v": "the cache stops: %v",
|
|
"%d écriture(s) interrompue(s) retirée(s)": "%d interrupted write(s) removed",
|
|
"écoute HTTP : %w": "HTTP listener: %w",
|
|
"écoute TLS : %w": "TLS listener: %w",
|
|
"cache : %s": "cache: %s",
|
|
"autorité : %s (%s)": "authority: %s (%s)",
|
|
"écoutes : http %d, tls %d": "listeners: http %d, tls %d",
|
|
"répertoire : %s\n": "directory : %s\n",
|
|
"objets : %d\n": "objects : %d\n",
|
|
"occupation : %s\n": "occupied : %s\n",
|
|
"plus ancien : aucun objet\n": "oldest : no object\n",
|
|
"plus ancien : %s\n": "oldest : %s\n",
|
|
"autorité : %s\n": "authority : %s\n",
|
|
"empreinte : %s\n": "fingerprint : %s\n",
|
|
"empreinte : autorité absente\n": "fingerprint : authority missing\n",
|
|
"dépôts git : %d en miroir, %s\n": "git repos : %d mirrored, %s\n",
|
|
"exceptions : aucune\n": "exceptions : none\n",
|
|
"exceptions : %d VM soustraite(s) au détournement\n": "exceptions : %d VM(s) excluded from redirection\n",
|
|
"\nAucune éviction n'est écrite : ce cache ne diminue jamais\n": "\nNo eviction is written: this cache never shrinks\n",
|
|
"de lui-même, et il vit sur le disque de l'orchestrateur.\n": "by itself, and it lives on the orchestrator's disk.\n",
|
|
"À blanc — rien n'est écrit, rien n'est posé.\n\n": "Dry run — nothing is written, nothing is set.\n\n",
|
|
"Répertoire du cache, créé au démarrage :\n %s\n\n": "Cache directory, created at startup:\n %s\n\n",
|
|
"Autorité, créée si elle manque :\n %s (clé en 0600)\n\n": "Authority, created if missing:\n %s (key in 0600)\n\n",
|
|
"Règles nft à poser sur l'hôte :\n": "nft rules to set on the host:\n",
|
|
"\nÀ défaut de nft :\n": "\nWithout nft:\n",
|
|
"\nRetrait :\n %s\n": "\nRemoval:\n %s\n",
|
|
"\nDans chaque VM qui utilise le cache :\n": "\nIn each VM that uses the cache:\n",
|
|
" %-7s %s/erplibre-cache.crt puis %s\n": " %-7s %s/erplibre-cache.crt then %s\n",
|
|
"clé de l'autorité illisible : %w": "unreadable authority key: %w",
|
|
"autorité illisible : PEM invalide": "unreadable authority: invalid PEM",
|
|
"tunnel opaque retenu pour %s (%d échec(s)) : %v": "opaque tunnel kept for %s (%d failure(s)): %v",
|
|
"poignée de main interrompue pour %s : %v": "handshake interrupted for %s: %v",
|
|
"tunnel impossible pour %q : destination inconnue (%v)": "tunnel impossible for %q: unknown destination (%v)",
|
|
"tunnel refusé pour %q : connexion non détournée, sa destination %s est cette écoute même": "tunnel refused for %q: connection not redirected, its destination %s is this very listener",
|
|
"tunnel vers %s : %v ; %s est déchiffré à la place": "tunnel to %s: %v; %s is decrypted instead",
|
|
"tunnel vers %s refermé après %s : %s vers l'amont, %s vers l'invité": "tunnel to %s closed after %s: %s upstream, %s to the guest",
|
|
"tunnel vers %s : %v": "tunnel to %s: %v",
|
|
"ce n'est pas une poignée de main TLS (type %d)": "not a TLS handshake (type %d)",
|
|
"longueur d'enregistrement invraisemblable : %d": "implausible record length: %d",
|
|
"la connexion n'est pas une socket TCP": "the connection is not a TCP socket",
|
|
"aucune destination d'origine : la connexion n'est pas redirigée": "no original destination: the connection is not redirected",
|
|
"interception transparente : Linux seulement": "transparent interception: Linux only",
|
|
"requête sans hôte : ni ligne absolue ni en-tête Host": "request without host: neither absolute line nor Host header",
|
|
"cache : écriture impossible pour %s : %v": "cache: cannot write %s: %v",
|
|
"cache : %s non gardé : %v": "cache: %s not kept: %v",
|
|
"erplibre_go_qemu_cache : amont injoignable et rien en réserve.\n demandé : %s\n classe : %s\n cause : %v\n%sCe fichier n'a jamais traversé ce cache. Rétablir le réseau, ou\ndéployer une VM identique à celle qui a rempli le cache.\n": "erplibre_go_qemu_cache: upstream unreachable and nothing in store.\n requested: %s\n class : %s\n cause : %v\n%sThis file never crossed this cache. Restore the network, or\ndeploy a VM identical to the one that filled the cache.\n",
|
|
"hors ligne, absent du cache : %s": "offline, missing from the cache: %s",
|
|
"corps tronqué : %d octets sur %d": "truncated body: %d bytes of %d",
|
|
"%d o": "%d B",
|
|
"%.1f Pio": "%.1f PiB",
|
|
"Kio": "KiB",
|
|
"Mio": "MiB",
|
|
"Gio": "GiB",
|
|
"Tio": "TiB",
|
|
"Objets du cache :": "Cache objects:",
|
|
"Dépôts en miroir :": "Mirrored repositories:",
|
|
"objets": "objects",
|
|
"dépôts": "repos",
|
|
"jour": "day",
|
|
"semaine": "week",
|
|
"mois": "month",
|
|
"L'établissement vers cet amont vient d'échouer : aucune connexion\nn'a été tentée pour cette requête, l'amont sera retenté sous peu.\n": "Connecting to this upstream just failed: no connection\nwas attempted for this request, upstream will be retried shortly.\n",
|
|
}
|