"""Tient les README au même niveau que le code, à partir de la même table. La liste des verbes existait en trois exemplaires : l'aide en ligne, la table de délégation, et les README. Ils ont divergé, comme toujours dans ce cas : « autostart » manquait dans une description, « login » et « list » n'apparaissaient nulle part dans la liste des verbes affichée. Une seule table fait désormais foi, `runtime.VERBES`. Ce programme en recopie le contenu entre deux balises dans chaque README. python docs.py met les README à jour python docs.py --check échoue s'ils ne sont plus à jour Le mode --check tourne en intégration continue : une dérive doit être signalée, pas tolérée jusqu'à ce que quelqu'un s'en aperçoive. """ import argparse from pathlib import Path import runtime BASE_DIR = Path(__file__).resolve().parent DEBUT = "" FIN = "" def bloc(langue: str) -> str: """Liste des verbes, en bloc de code, dans la langue demandée.""" largeur = max(len(v) for v in runtime.VERBES) lignes = [f"{nom:<{largeur}} # {getattr(verbe, langue)}" for nom, verbe in runtime.VERBES.items()] entete = ("Une commande, un verbe par action. `blink2video --help` donne " "les options de chacun." if langue == "fr" else "One command, one verb per action. `blink2video --help` gives " "each one's options.") corps = "\n".join(f"blink2video {ligne}" for ligne in lignes) return f"{DEBUT}\n{entete}\n\n```bash\n{corps}\n```\n{FIN}" def caracteres_parasites(texte: str) -> list: """Lignes contenant un caractère de contrôle. Un correctif appliqué par script a un jour transformé « C:\\path\\to » en tabulation et « \\blink » en retour arrière, au beau milieu d'un exemple PowerShell. Invisible à la relecture, recopié tel quel par le lecteur, et évidemment inopérant.""" return [ (numero, ligne) for numero, ligne in enumerate(texte.splitlines(), 1) if any(ord(caractere) < 32 for caractere in ligne) ] def appliquer(verifier: bool) -> int: ecarts = [] for chemin, langue in (("README.md", "en"), ("README.fr.md", "fr")): fichier = BASE_DIR / chemin texte = fichier.read_text(encoding="utf-8") for numero, ligne in caracteres_parasites(texte): print(f"{chemin}:{numero} : caractère de contrôle dans « {ligne.strip()} »") ecarts.append(chemin) if DEBUT not in texte or FIN not in texte: print(f"{chemin} : balises {DEBUT} … {FIN} absentes") ecarts.append(chemin) continue avant, reste = texte.split(DEBUT, 1) _, apres = reste.split(FIN, 1) attendu = avant + bloc(langue) + apres if attendu == texte: print(f"{chemin} : à jour") continue ecarts.append(chemin) if verifier: print(f"{chemin} : PÉRIMÉ, lancez « python docs.py »") else: fichier.write_text(attendu, encoding="utf-8") print(f"{chemin} : mis à jour") if verifier and ecarts: return 1 return 0 def main() -> int: parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) parser.add_argument("--check", action="store_true", help="échouer si les README ne sont pas à jour, sans les modifier") args = parser.parse_args() return appliquer(args.check) if __name__ == "__main__": raise SystemExit(main())