chore: resilience boot (sudoers, purge, image docker), goldens de non-regression, doc des 3 canaux
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
check_goldens.py — C0 · goldens de non-régression du moteur
|
||||
===========================================================
|
||||
Rend chaque golden_*.yaml présent et compare sa STRUCTURE (nb de
|
||||
slides, nb de shapes par slide) au manifeste goldens_manifest.json.
|
||||
Le PPTX contient des timestamps : un diff binaire est impossible — la
|
||||
structure, elle, est déterministe et attrape les régressions de rendu
|
||||
(shape manquante, layout cassé, exception).
|
||||
|
||||
python3 check_goldens.py → vérifie (code retour 1 si écart)
|
||||
python3 check_goldens.py --update → (re)génère le manifeste
|
||||
|
||||
À lancer avant tout push moteur (ou en tâche DSM hebdo).
|
||||
"""
|
||||
import glob
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MANIFEST = Path("goldens_manifest.json")
|
||||
|
||||
|
||||
def structure(pptx_path):
|
||||
from pptx import Presentation
|
||||
prs = Presentation(pptx_path)
|
||||
return [len(list(s.shapes)) for s in prs.slides]
|
||||
|
||||
|
||||
def render_all():
|
||||
out = {}
|
||||
for y in sorted(glob.glob("golden_*.yaml")):
|
||||
pptx = "_check_%s.pptx" % Path(y).stem
|
||||
r = subprocess.run(
|
||||
["python3", "render_engine_v2.py", y, pptx,
|
||||
"--assets", "assets"],
|
||||
capture_output=True, text=True)
|
||||
if r.returncode != 0:
|
||||
print(" ! %s : le rendu ÉCHOUE\n%s" % (y, r.stdout[-400:]))
|
||||
sys.exit(1)
|
||||
out[y] = structure(pptx)
|
||||
Path(pptx).unlink(missing_ok=True)
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
got = render_all()
|
||||
if "--update" in sys.argv:
|
||||
MANIFEST.write_text(json.dumps(got, indent=2))
|
||||
print(" + Manifeste écrit : %d goldens, %d slides au total."
|
||||
% (len(got), sum(len(v) for v in got.values())))
|
||||
return
|
||||
if not MANIFEST.exists():
|
||||
print(" ! Pas de manifeste — lancer d'abord : "
|
||||
"python3 check_goldens.py --update")
|
||||
sys.exit(1)
|
||||
want = json.loads(MANIFEST.read_text())
|
||||
ok = True
|
||||
for y, shapes in got.items():
|
||||
ref = want.get(y)
|
||||
if ref is None:
|
||||
print(" ~ %s : nouveau golden (absent du manifeste)" % y)
|
||||
continue
|
||||
if shapes != ref:
|
||||
ok = False
|
||||
print(" ! %s : ÉCART — slides/shapes %s ≠ attendu %s"
|
||||
% (y, shapes, ref))
|
||||
for y in want:
|
||||
if y not in got:
|
||||
ok = False
|
||||
print(" ! %s : golden du manifeste INTROUVABLE" % y)
|
||||
print(" %s" % ("✓ goldens conformes (%d fichiers)" % len(got)
|
||||
if ok else "✗ régression détectée"))
|
||||
sys.exit(0 if ok else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# resilience_boot.sh — Résilience C2 · à planifier en tâche DSM
|
||||
# « Au démarrage », utilisateur ROOT (recrée la règle sudoers).
|
||||
# Rejouable sans risque (idempotent). Journalise dans resilience.log.
|
||||
|
||||
BASE=/volume1/homes/Master/App/Sliding/python-pptx
|
||||
LOG="$BASE/resilience.log"
|
||||
TS=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# 1. Règle sudoers de la preview (sautée par les MAJ DSM majeures)
|
||||
SUDOERS=/etc/sudoers.d/sliding-preview
|
||||
if [ ! -f "$SUDOERS" ]; then
|
||||
printf 'Master ALL=(root) NOPASSWD: %s/preview.sh\n' "$BASE" > "$SUDOERS"
|
||||
chmod 440 "$SUDOERS"
|
||||
echo "$TS [sudoers] regle sliding-preview RECREEE" >> "$LOG"
|
||||
fi
|
||||
|
||||
# 2. Purge des previews de plus de 30 jours (le disque du DS218 est petit)
|
||||
N=$(find "$BASE/projets" -type d -name "*_previews" -mtime +30 2>/dev/null | wc -l)
|
||||
if [ "$N" -gt 0 ]; then
|
||||
find "$BASE/projets" -type d -name "*_previews" -mtime +30 -exec rm -rf {} + 2>/dev/null
|
||||
echo "$TS [purge] $N dossier(s) de previews > 30j supprimes" >> "$LOG"
|
||||
fi
|
||||
|
||||
# 3. L'image docker de la preview a-t-elle survécu ?
|
||||
DOCKER=/volume1/@appstore/ContainerManager/usr/bin/docker
|
||||
if [ -x "$DOCKER" ]; then
|
||||
if ! "$DOCKER" image inspect sliding-preview >/dev/null 2>&1; then
|
||||
echo "$TS [docker] IMAGE sliding-preview ABSENTE — rebuild requis (voir fiche systeme Trilium)" >> "$LOG"
|
||||
fi
|
||||
else
|
||||
echo "$TS [docker] demon/binaire docker indisponible" >> "$LOG"
|
||||
fi
|
||||
Reference in New Issue
Block a user