200 lines
7.4 KiB
Python
200 lines
7.4 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
# -*- coding: utf-8 -*-
|
||
|
|
"""
|
||
|
|
patch_facilitator_c2.py — Chantier C2 (Preview PNG)
|
||
|
|
===================================================
|
||
|
|
Patch strict de facilitator_v9.py :
|
||
|
|
P1. Config : PREVIEW_SCRIPT (.env, défaut ./preview.sh).
|
||
|
|
P2. Insère run_preview() + maybe_preview() avant la section
|
||
|
|
ARCHIVAGE TRILIUM (asynchrone par défaut, log dédié).
|
||
|
|
P3-P6. Propose les aperçus aux 4 sorties PPTX : flux standard,
|
||
|
|
flux libre, révision ciblée, révision complète.
|
||
|
|
P7. CLI : --preview <pptx> (mode bloquant, pour usage direct).
|
||
|
|
|
||
|
|
Usage (dossier du pipeline, single-line) :
|
||
|
|
python3 patch_facilitator_c2.py
|
||
|
|
Compatible avant/après le patch C1 (ancres indépendantes). Vérifie
|
||
|
|
chaque ancre, écrit .bak, compile, idempotent.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import py_compile
|
||
|
|
import shutil
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
TARGET = Path("facilitator_v9.py")
|
||
|
|
|
||
|
|
FUNC = '''
|
||
|
|
def run_preview(pptx_path: Path, wait: bool = False) -> bool:
|
||
|
|
"""Aperçus PNG par slide via preview.sh (chantier C2).
|
||
|
|
wait=False : lancement en arrière-plan (le DS218 est lent), sortie
|
||
|
|
consignée dans <pptx>_preview.log. wait=True : bloquant (CLI)."""
|
||
|
|
script = Path(PREVIEW_SCRIPT)
|
||
|
|
if not script.exists():
|
||
|
|
warn(f"{PREVIEW_SCRIPT} introuvable — aperçus indisponibles.")
|
||
|
|
return False
|
||
|
|
out_dir = pptx_path.parent / f"{pptx_path.stem}_previews"
|
||
|
|
if wait:
|
||
|
|
info("Génération des aperçus (quelques minutes sur le NAS)...")
|
||
|
|
r = subprocess.run([str(script), str(pptx_path)],
|
||
|
|
capture_output=True, text=True)
|
||
|
|
if r.returncode == 0:
|
||
|
|
ok(f"Aperçus : {out_dir}")
|
||
|
|
ok(f"Galerie : {out_dir / 'index.html'}")
|
||
|
|
return True
|
||
|
|
warn("Échec de la génération des aperçus :")
|
||
|
|
print(textwrap.indent((r.stderr or r.stdout or "?").strip(),
|
||
|
|
" "))
|
||
|
|
return False
|
||
|
|
log = pptx_path.parent / f"{pptx_path.stem}_preview.log"
|
||
|
|
with open(log, "w", encoding="utf-8") as lf:
|
||
|
|
subprocess.Popen([str(script), str(pptx_path)],
|
||
|
|
stdout=lf, stderr=subprocess.STDOUT)
|
||
|
|
info(f"Aperçus en arrière-plan → {out_dir}")
|
||
|
|
info(f"Suivi : {log}")
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
def maybe_preview(pptx_path) -> None:
|
||
|
|
"""Propose la génération des aperçus après une sortie PPTX."""
|
||
|
|
if not pptx_path or not Path(PREVIEW_SCRIPT).exists():
|
||
|
|
return
|
||
|
|
if ask("Générer les aperçus PNG ? (o/N) :").lower() in (
|
||
|
|
"o", "oui", "y", "yes"):
|
||
|
|
run_preview(pptx_path, wait=False)
|
||
|
|
|
||
|
|
'''
|
||
|
|
|
||
|
|
PATCHES = [
|
||
|
|
# P1 — config
|
||
|
|
(
|
||
|
|
'LAYOUTS_PATH = os.getenv("LAYOUTS_PATH", "layouts_v2.yaml")\n',
|
||
|
|
'LAYOUTS_PATH = os.getenv("LAYOUTS_PATH", "layouts_v2.yaml")\n'
|
||
|
|
'PREVIEW_SCRIPT = os.getenv("PREVIEW_SCRIPT", "./preview.sh")'
|
||
|
|
' # C2\n',
|
||
|
|
),
|
||
|
|
# P3 — flux standard (indentation 12)
|
||
|
|
(
|
||
|
|
' ok(f"Fichier PPTX : {pptx_path}")\n'
|
||
|
|
' ok(f"Taille : {pptx_path.stat().st_size/1024:.1f}'
|
||
|
|
' Ko")\n'
|
||
|
|
' else:\n'
|
||
|
|
' warn("Le PPTX n\'a pas pu être généré.")\n'
|
||
|
|
' info(f"Le YAML est dans : {proj.outputs}")\n',
|
||
|
|
' ok(f"Fichier PPTX : {pptx_path}")\n'
|
||
|
|
' ok(f"Taille : {pptx_path.stat().st_size/1024:.1f}'
|
||
|
|
' Ko")\n'
|
||
|
|
' maybe_preview(pptx_path)\n'
|
||
|
|
' else:\n'
|
||
|
|
' warn("Le PPTX n\'a pas pu être généré.")\n'
|
||
|
|
' info(f"Le YAML est dans : {proj.outputs}")\n',
|
||
|
|
),
|
||
|
|
# P4 — flux libre (indentation 20)
|
||
|
|
(
|
||
|
|
' ok(f"Fichier PPTX : {pptx_path}")\n'
|
||
|
|
' ok(f"Taille : '
|
||
|
|
'{pptx_path.stat().st_size/1024:.1f} Ko")\n',
|
||
|
|
' ok(f"Fichier PPTX : {pptx_path}")\n'
|
||
|
|
' ok(f"Taille : '
|
||
|
|
'{pptx_path.stat().st_size/1024:.1f} Ko")\n'
|
||
|
|
' maybe_preview(pptx_path)\n',
|
||
|
|
),
|
||
|
|
# P5 — révision ciblée
|
||
|
|
(
|
||
|
|
' ok(f"PPTX des slides révisées : {pptx_path}")\n'
|
||
|
|
' info("Ouvre ce fichier et copie-colle les slides dans '
|
||
|
|
'ton deck maître.")\n',
|
||
|
|
' ok(f"PPTX des slides révisées : {pptx_path}")\n'
|
||
|
|
' info("Ouvre ce fichier et copie-colle les slides dans '
|
||
|
|
'ton deck maître.")\n'
|
||
|
|
' maybe_preview(pptx_path)\n',
|
||
|
|
),
|
||
|
|
# P6 — révision complète
|
||
|
|
(
|
||
|
|
' section("DECK COMPLET RÉGÉNÉRÉ")\n'
|
||
|
|
' ok(f"Nouveau PPTX complet : {pptx_path}")\n',
|
||
|
|
' section("DECK COMPLET RÉGÉNÉRÉ")\n'
|
||
|
|
' ok(f"Nouveau PPTX complet : {pptx_path}")\n'
|
||
|
|
' maybe_preview(pptx_path)\n',
|
||
|
|
),
|
||
|
|
# P7a — argument CLI
|
||
|
|
(
|
||
|
|
' parser.add_argument("--render", metavar="YAML",\n'
|
||
|
|
' help="Rendu direct d\'un YAML existant, '
|
||
|
|
'sans agents")\n',
|
||
|
|
' parser.add_argument("--render", metavar="YAML",\n'
|
||
|
|
' help="Rendu direct d\'un YAML existant, '
|
||
|
|
'sans agents")\n'
|
||
|
|
' parser.add_argument("--preview", metavar="PPTX",\n'
|
||
|
|
' help="Aperçus PNG d\'un PPTX existant '
|
||
|
|
'(C2)")\n',
|
||
|
|
),
|
||
|
|
# P7b — traitement CLI
|
||
|
|
(
|
||
|
|
' if args.render:\n',
|
||
|
|
' if args.preview:\n'
|
||
|
|
' p = Path(args.preview)\n'
|
||
|
|
' if not p.exists():\n'
|
||
|
|
' warn(f"Fichier introuvable : {p}")\n'
|
||
|
|
' sys.exit(1)\n'
|
||
|
|
' sys.exit(0 if run_preview(p, wait=True) else 1)\n'
|
||
|
|
'\n'
|
||
|
|
' if args.render:\n',
|
||
|
|
),
|
||
|
|
]
|
||
|
|
|
||
|
|
MARKER = "def run_preview"
|
||
|
|
ANCHOR_SECTION = "# ARCHIVAGE TRILIUM"
|
||
|
|
|
||
|
|
|
||
|
|
def fail(msg):
|
||
|
|
print(" ! %s" % msg)
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
if not TARGET.exists():
|
||
|
|
fail("%s introuvable — lancer depuis le dossier du pipeline."
|
||
|
|
% TARGET)
|
||
|
|
content = TARGET.read_text(encoding="utf-8")
|
||
|
|
if MARKER in content:
|
||
|
|
fail("Déjà patché (run_preview présent) — rien à faire.")
|
||
|
|
|
||
|
|
for i, (old, _) in enumerate(PATCHES, 1):
|
||
|
|
n = content.count(old)
|
||
|
|
if n == 0:
|
||
|
|
fail("Ancre du patch %d introuvable — facilitator inattendu."
|
||
|
|
% i)
|
||
|
|
if n > 1:
|
||
|
|
fail("Ancre du patch %d non unique (%d occurrences)." % (i, n))
|
||
|
|
if content.count(ANCHOR_SECTION) != 1:
|
||
|
|
fail("Ancre de section ARCHIVAGE TRILIUM introuvable ou non unique.")
|
||
|
|
|
||
|
|
shutil.copy2(TARGET, str(TARGET) + ".bak-c2")
|
||
|
|
print(" + Sauvegarde : %s.bak-c2" % TARGET)
|
||
|
|
|
||
|
|
for old, new in PATCHES:
|
||
|
|
content = content.replace(old, new)
|
||
|
|
|
||
|
|
lines = content.split("\n")
|
||
|
|
idx = next(i for i, l in enumerate(lines) if ANCHOR_SECTION in l)
|
||
|
|
ins = idx - 1 if lines[idx - 1].startswith("# ───") else idx
|
||
|
|
lines[ins:ins] = FUNC.split("\n")
|
||
|
|
content = "\n".join(lines)
|
||
|
|
|
||
|
|
TARGET.write_text(content, encoding="utf-8")
|
||
|
|
print(" + 7 patchs appliqués.")
|
||
|
|
try:
|
||
|
|
py_compile.compile(str(TARGET), doraise=True)
|
||
|
|
print(" + Compilation OK.")
|
||
|
|
except py_compile.PyCompileError as e:
|
||
|
|
shutil.copy2(str(TARGET) + ".bak-c2", TARGET)
|
||
|
|
fail("Erreur de compilation — fichier restauré :\n%s" % e)
|
||
|
|
print("\n Test direct : python3 facilitator_v9.py --preview "
|
||
|
|
"<deck.pptx>")
|
||
|
|
print(" Config .env optionnelle : PREVIEW_SCRIPT=./preview.sh")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|