[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"sort"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Le cache ne diminue jamais de lui-même — c'est assumé, et la place se
|
|
|
|
|
// surveille à la main. Encore faut-il pouvoir la surveiller : savoir CE QUI
|
|
|
|
|
// occupe, et depuis QUAND, avant de décider ce qui peut partir.
|
|
|
|
|
//
|
|
|
|
|
// L'âge retenu est la date du dernier USAGE et non celle du stockage. Un
|
|
|
|
|
// paquet servi tous les jours depuis un an n'est pas vieux : le supprimer
|
|
|
|
|
// obligerait à le retélécharger le lendemain. C'est ce qu'un opérateur veut
|
|
|
|
|
// dire par « nettoyer ce qui ne sert plus », et c'est pour cela que le service
|
|
|
|
|
// remet la date d'un objet à chaque fois qu'il le sert.
|
|
|
|
|
|
|
|
|
|
// Tranche est un groupe d'objets d'un même âge.
|
|
|
|
|
type Tranche struct {
|
|
|
|
|
// Debut est le premier instant de la tranche ; Libelle la nomme.
|
|
|
|
|
Debut time.Time
|
|
|
|
|
Libelle string
|
|
|
|
|
Objets int
|
|
|
|
|
Octets int64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Granularite dit comment les tranches sont découpées.
|
|
|
|
|
type Granularite string
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
ParJour Granularite = "jour"
|
|
|
|
|
ParSemaine Granularite = "semaine"
|
|
|
|
|
ParMois Granularite = "mois"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// LireGranularite tolère l'anglais comme le français : le CLI est bilingue
|
|
|
|
|
// partout ailleurs dans ce dépôt.
|
|
|
|
|
func LireGranularite(s string) (Granularite, error) {
|
|
|
|
|
switch strings.ToLower(strings.TrimSpace(s)) {
|
|
|
|
|
case "jour", "day", "j", "d":
|
|
|
|
|
return ParJour, nil
|
|
|
|
|
case "semaine", "week", "s", "w":
|
|
|
|
|
return ParSemaine, nil
|
|
|
|
|
case "mois", "month", "m":
|
|
|
|
|
return ParMois, nil
|
|
|
|
|
}
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
return "", fmt.Errorf(T("granularité inconnue %q : jour, semaine ou mois"), s)
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// debutDeTranche ramène un instant au premier de sa tranche.
|
|
|
|
|
//
|
|
|
|
|
// La semaine commence le LUNDI : c'est la convention ISO, et celle que
|
|
|
|
|
// « %V » et les outils du système emploient. Ramener au dimanche donnerait des
|
|
|
|
|
// tranches qui ne correspondent à aucun autre relevé de la machine.
|
|
|
|
|
func debutDeTranche(t time.Time, g Granularite) time.Time {
|
|
|
|
|
t = t.Local()
|
|
|
|
|
jour := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
|
|
|
|
switch g {
|
|
|
|
|
case ParSemaine:
|
|
|
|
|
recul := (int(jour.Weekday()) + 6) % 7
|
|
|
|
|
return jour.AddDate(0, 0, -recul)
|
|
|
|
|
case ParMois:
|
|
|
|
|
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
|
|
|
|
|
}
|
|
|
|
|
return jour
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func libelleDeTranche(t time.Time, g Granularite) string {
|
|
|
|
|
switch g {
|
|
|
|
|
case ParSemaine:
|
|
|
|
|
an, sem := t.ISOWeek()
|
|
|
|
|
return fmt.Sprintf("%d-S%02d", an, sem)
|
|
|
|
|
case ParMois:
|
|
|
|
|
return t.Format("2006-01")
|
|
|
|
|
}
|
|
|
|
|
return t.Format("2006-01-02")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TranchesStore groupe les objets du magasin par âge, du plus récent au plus
|
|
|
|
|
// ancien.
|
|
|
|
|
func (s *Store) Tranches(g Granularite) []Tranche {
|
|
|
|
|
par := map[time.Time]*Tranche{}
|
|
|
|
|
filepath.Walk(s.Dir, func(p string, info os.FileInfo, err error) error {
|
|
|
|
|
if err != nil || info == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if horsCasier(s.Dir, p, info) {
|
|
|
|
|
return filepath.SkipDir
|
|
|
|
|
}
|
|
|
|
|
if info.IsDir() || filepath.Ext(p) != ".body" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
d := debutDeTranche(info.ModTime(), g)
|
|
|
|
|
tr, ok := par[d]
|
|
|
|
|
if !ok {
|
|
|
|
|
tr = &Tranche{Debut: d, Libelle: libelleDeTranche(d, g)}
|
|
|
|
|
par[d] = tr
|
|
|
|
|
}
|
|
|
|
|
tr.Objets++
|
|
|
|
|
tr.Octets += info.Size()
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
return trier(par)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TranchesMiroirs fait de même pour les dépôts git.
|
|
|
|
|
//
|
|
|
|
|
// Un dépôt entier par tranche, pas ses fichiers : ce qui s'efface est un
|
|
|
|
|
// dépôt, et le compter au fichier donnerait un relevé qu'on ne peut pas
|
|
|
|
|
// suivre d'un geste.
|
|
|
|
|
func (g *GitMirror) Tranches(gran Granularite) []Tranche {
|
|
|
|
|
if g == nil || g.Dir == "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
par := map[time.Time]*Tranche{}
|
|
|
|
|
for _, d := range g.Depots() {
|
|
|
|
|
debut := debutDeTranche(d.Maj, gran)
|
|
|
|
|
tr, ok := par[debut]
|
|
|
|
|
if !ok {
|
|
|
|
|
tr = &Tranche{Debut: debut, Libelle: libelleDeTranche(debut, gran)}
|
|
|
|
|
par[debut] = tr
|
|
|
|
|
}
|
|
|
|
|
tr.Objets++
|
|
|
|
|
tr.Octets += d.Octets
|
|
|
|
|
}
|
|
|
|
|
return trier(par)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func trier(par map[time.Time]*Tranche) []Tranche {
|
|
|
|
|
out := make([]Tranche, 0, len(par))
|
|
|
|
|
for _, tr := range par {
|
|
|
|
|
out = append(out, *tr)
|
|
|
|
|
}
|
|
|
|
|
sort.Slice(out, func(i, j int) bool {
|
|
|
|
|
return out[i].Debut.After(out[j].Debut)
|
|
|
|
|
})
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Purger efface les objets dont le dernier usage précède `avant`.
|
|
|
|
|
//
|
|
|
|
|
// Le méta part AVEC le corps : un méta orphelin ferait croire à une copie
|
|
|
|
|
// présente, et la lecture échouerait au moment de servir, c'est-à-dire au pire
|
|
|
|
|
// moment. Rend (objets effacés, octets rendus).
|
|
|
|
|
func (s *Store) Purger(avant time.Time) (int, int64, error) {
|
|
|
|
|
n, octets := 0, int64(0)
|
|
|
|
|
err := filepath.Walk(s.Dir, func(
|
|
|
|
|
p string, info os.FileInfo, err error,
|
|
|
|
|
) error {
|
|
|
|
|
if err != nil || info == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if horsCasier(s.Dir, p, info) {
|
|
|
|
|
return filepath.SkipDir
|
|
|
|
|
}
|
|
|
|
|
if info.IsDir() || filepath.Ext(p) != ".body" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if !info.ModTime().Before(avant) {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
taille := info.Size()
|
|
|
|
|
if e := os.Remove(p); e != nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
os.Remove(strings.TrimSuffix(p, ".body") + ".meta")
|
|
|
|
|
n++
|
|
|
|
|
octets += taille
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
return n, octets, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PurgerMiroirs efface les dépôts qui n'ont pas été rafraîchis depuis
|
|
|
|
|
// `avant`. Rend (dépôts effacés, octets rendus).
|
|
|
|
|
func (g *GitMirror) PurgerMiroirs(avant time.Time) (int, int64, error) {
|
|
|
|
|
if g == nil || g.Dir == "" {
|
|
|
|
|
return 0, 0, nil
|
|
|
|
|
}
|
|
|
|
|
n, octets := 0, int64(0)
|
|
|
|
|
for _, d := range g.Depots() {
|
|
|
|
|
if !d.Maj.Before(avant) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if err := g.Retirer(d.Chemin); err != nil {
|
|
|
|
|
return n, octets, err
|
|
|
|
|
}
|
|
|
|
|
n++
|
|
|
|
|
octets += d.Octets
|
|
|
|
|
}
|
|
|
|
|
return n, octets, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LireDuree accepte les suffixes de Go et, en plus, « j » pour un jour.
|
|
|
|
|
//
|
|
|
|
|
// « 30d » n'existe pas dans la bibliothèque, et un opérateur qui nettoie
|
|
|
|
|
// raisonne en jours, pas en sept cent vingt heures.
|
|
|
|
|
func LireDuree(s string) (time.Duration, error) {
|
|
|
|
|
s = strings.ToLower(strings.TrimSpace(s))
|
|
|
|
|
if s == "" {
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
return 0, fmt.Errorf("%s", T("durée vide"))
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
}
|
|
|
|
|
if n, unite := s[:len(s)-1], s[len(s)-1]; unite == 'j' || unite == 'd' {
|
|
|
|
|
var jours float64
|
|
|
|
|
if _, err := fmt.Sscanf(n, "%g", &jours); err != nil || jours < 0 {
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
return 0, fmt.Errorf(T("durée illisible %q"), s)
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
}
|
|
|
|
|
return time.Duration(jours * 24 * float64(time.Hour)), nil
|
|
|
|
|
}
|
|
|
|
|
d, err := time.ParseDuration(s)
|
|
|
|
|
if err != nil || d < 0 {
|
|
|
|
|
return 0, fmt.Errorf(
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
T("durée illisible %q : essayer 30j, 12h, 90m"), s)
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
}
|
|
|
|
|
return d, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// printAge écrit le relevé par âge : les objets, puis les dépôts.
|
|
|
|
|
//
|
|
|
|
|
// Les deux SÉPARÉMENT : ils ne s'effacent pas de la même façon — un objet est
|
|
|
|
|
// un fichier, un dépôt est un arbre — et un total commun cacherait qu'un seul
|
|
|
|
|
// dépôt pèse plus que mille objets.
|
|
|
|
|
func printAge(store *Store, miroir *GitMirror, gran Granularite) {
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
fmt.Printf(T("Âge du dernier usage, par %s.\n"), T(string(gran)))
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
fmt.Printf(
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
"%s", T("\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"))
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
|
|
|
|
|
ecrire := func(titre string, tranches []Tranche, quoi string) {
|
|
|
|
|
fmt.Printf("\n%s\n", titre)
|
|
|
|
|
if len(tranches) == 0 {
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
fmt.Println(T(" rien"))
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var n int
|
|
|
|
|
var octets int64
|
|
|
|
|
for _, tr := range tranches {
|
|
|
|
|
fmt.Printf(" %-12s %6d %-8s %10s\n",
|
|
|
|
|
tr.Libelle, tr.Objets, quoi, HumanBytes(tr.Octets))
|
|
|
|
|
n += tr.Objets
|
|
|
|
|
octets += tr.Octets
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf(" %-12s %6d %-8s %10s\n", "total", n, quoi,
|
|
|
|
|
HumanBytes(octets))
|
|
|
|
|
}
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
ecrire(T("Objets du cache :"), store.Tranches(gran), T("objets"))
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
if miroir.Actif() {
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
ecrire(T("Dépôts en miroir :"), miroir.Tranches(gran), T("dépôts"))
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// printPurgeABlanc dit ce qu'une purge emporterait, sans rien effacer.
|
|
|
|
|
//
|
|
|
|
|
// Une purge ne se rattrape pas — les octets sont rendus, il faut les
|
|
|
|
|
// retélécharger — et c'est le genre de geste qu'on veut relire avant.
|
|
|
|
|
func printPurgeABlanc(store *Store, miroir *GitMirror, avant time.Time) {
|
|
|
|
|
var n int
|
|
|
|
|
var octets int64
|
|
|
|
|
for _, tr := range store.Tranches(ParJour) {
|
|
|
|
|
if tr.Debut.Before(avant) {
|
|
|
|
|
n += tr.Objets
|
|
|
|
|
octets += tr.Octets
|
|
|
|
|
}
|
|
|
|
|
}
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
fmt.Printf(T("[à blanc] objets qui partiraient : %d, %s\n"),
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
n, HumanBytes(octets))
|
|
|
|
|
|
|
|
|
|
var nd int
|
|
|
|
|
var octd int64
|
|
|
|
|
for _, d := range miroir.Depots() {
|
|
|
|
|
if d.Maj.Before(avant) {
|
|
|
|
|
nd++
|
|
|
|
|
octd += d.Octets
|
|
|
|
|
}
|
|
|
|
|
}
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
fmt.Printf(T("[à blanc] dépôts qui partiraient : %d, %s\n"),
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
nd, HumanBytes(octd))
|
[ADD] cache qemu : messages du binaire en anglais ou en français
Le binaire ne parlait que français alors que le menu suit EL_LANG : un
opérateur anglophone lisait un statut qu'il ne comprenait pas. Chaque message
humain passe par T(), dont la clé EST le texte français, et un catalogue
anglais le traduit ; la langue vient de --lang, puis d'EL_LANG, le français
restant le défaut. Le menu demande le français pour ce qu'il RELIT, ses
motifs ne connaissant que cette langue. Un test refuse un message sans
traduction, une traduction orpheline et un verbe de format qui diverge.
--- EN ---
The binary spoke French only while the menu follows EL_LANG: an English
reader got a status he could not read. Every human message goes through T(),
whose key IS the French text, and an English catalogue translates it; the
language comes from --lang, then EL_LANG, French remaining the default. The
menu asks for French for what it READS BACK, its patterns knowing that
language alone. A test refuses a message without translation, an orphan
translation, and a format verb that drifts.
Assisted-by: Claude Opus 5
2026-09-16 02:59:01 -04:00
|
|
|
fmt.Println(T("[à blanc] rien n'a été effacé."))
|
[ADD] cache qemu : miroir des téléchargements des VM, hors ligne compris
VMs of one host pulled the same packages again and again, and an install
could not be proven to work without the network. A Go service intercepts the
bridge transparently: a package file is served from disk, an index is always
revalidated upstream and replayed only when upstream is mute, git is mirrored.
Deployment poses the cache authority in QEMU and Proxmox VE guests, and can cut
the network for a whole install. The TODO menu installs, diagnoses, fills,
cleans and copies the store; long_test/qemu_cache.py measures that a second VM
pulls no package upstream. Covered by Go tests and test/test_qemu_cache_*.py.
--- FR ---
Les VM d'un hôte tiraient sans cesse les mêmes paquets, et rien ne prouvait
qu'une installation marche sans réseau. Un service Go intercepte le pont de
façon transparente : un fichier de paquet est servi du disque, un index est
toujours revalidé à l'amont et rejoué seulement quand l'amont est muet, git
est mis en miroir. Le déploiement pose l'autorité du cache dans les invités
QEMU et Proxmox VE, et peut couper le réseau pour toute une installation. Le
menu TODO installe, diagnostique, remplit, nettoie et emporte le magasin ;
long_test/qemu_cache.py mesure qu'une seconde VM ne tire aucun paquet de
l'amont. Couvert par les tests Go et test/test_qemu_cache_*.py.
Assisted-by: Claude Opus 5
2026-09-14 14:41:19 -04:00
|
|
|
}
|