Compare commits
2
Commits
47528bae8d
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
503aa66dc0 | ||
|
|
5b312f7459 |
@@ -33,7 +33,8 @@ correspondant à votre système :
|
||||
|
||||
Une fenêtre s'ouvre et vous guide :
|
||||
|
||||
1. elle vérifie que **Python** et **Quarto** sont installés, et propose de les installer automatiquement sinon ;
|
||||
1. elle vérifie que **Python**, **Quarto** et les polices **Noto Sans / Noto Sans Mono** sont installés,
|
||||
et propose de les installer automatiquement sinon (sous Linux, les polices sont généralement déjà présentes) ;
|
||||
2. elle prépare l'environnement Python des schémas (dossier `.venv`, une seule fois) ;
|
||||
3. elle vous demande le **format** (PDF, LibreOffice .odt ou site web HTML) et les **supports** à produire
|
||||
(tous, ou un seul module) ;
|
||||
@@ -54,7 +55,9 @@ _output/ PDF générés (non versionnés)
|
||||
|
||||
## Produire les PDF
|
||||
|
||||
Prérequis : [Quarto](https://quarto.org/docs/get-started/) (inclut Pandoc et Typst).
|
||||
Prérequis : [Quarto](https://quarto.org/docs/get-started/) (inclut Pandoc et Typst) et les polices libres
|
||||
[Noto Sans et Noto Sans Mono](https://notofonts.github.io/) (paquets `noto-fonts` sous Arch,
|
||||
`fonts-noto-core fonts-noto-mono` sous Debian/Ubuntu).
|
||||
|
||||
```
|
||||
quarto render # tous les supports
|
||||
|
||||
+2
-2
@@ -17,9 +17,9 @@ format:
|
||||
margin:
|
||||
x: 2cm
|
||||
y: 2.2cm
|
||||
mainfont: "Segoe UI"
|
||||
mainfont: "Noto Sans"
|
||||
fontsize: 10pt
|
||||
codefont: "Consolas"
|
||||
codefont: "Noto Sans Mono"
|
||||
toc: false
|
||||
highlight-style: modele/code.theme
|
||||
include-in-header: modele/entete.typ
|
||||
|
||||
+104
-3
@@ -126,6 +126,8 @@ def installer_quarto():
|
||||
paquet = telecharger_quarto(f"linux-{arch}.deb")
|
||||
print(" Votre mot de passe peut être demandé (installation système).")
|
||||
subprocess.run(["sudo", "apt-get", "install", "-y", str(paquet)])
|
||||
elif SYSTEME == "Linux" and shutil.which("pacman"):
|
||||
return installer_quarto_arch()
|
||||
else:
|
||||
return False
|
||||
except Exception as erreur: # réseau indisponible, fichier introuvable…
|
||||
@@ -134,8 +136,30 @@ def installer_quarto():
|
||||
return True
|
||||
|
||||
|
||||
def installer_quarto_arch():
|
||||
"""Arch Linux et dérivées : dépôts officiels si le paquet y existe, sinon AUR via yay (ou paru)."""
|
||||
for nom in ("quarto-cli", "quarto"):
|
||||
if subprocess.run(["pacman", "-Si", nom], stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL).returncode == 0:
|
||||
print(" Votre mot de passe peut être demandé (installation système).")
|
||||
subprocess.run(["sudo", "pacman", "-S", "--needed", nom])
|
||||
return True
|
||||
paquet_aur = "quarto-cli-bin" # binaire officiel empaqueté, à jour (quarto-cli compile depuis les sources)
|
||||
for assistant_aur in ("yay", "paru"):
|
||||
if shutil.which(assistant_aur):
|
||||
print(f" Quarto n'est disponible que dans l'AUR : installation de « {paquet_aur} » avec {assistant_aur}.")
|
||||
print(" Validez les questions posées ; votre mot de passe sera demandé à la fin.")
|
||||
# Jamais avec sudo : yay et paru s'exécutent en utilisateur normal et appellent sudo eux-mêmes.
|
||||
subprocess.run([assistant_aur, "-S", "--needed", paquet_aur])
|
||||
return True
|
||||
print(" Sous Arch, Quarto n'est disponible que dans l'AUR (paquet « quarto-cli-bin »),")
|
||||
print(" et aucun assistant AUR (yay ou paru) n'a été trouvé sur cet ordinateur.")
|
||||
print(" Installez yay (https://github.com/Jguer/yay) puis relancez, ou installez le paquet à la main.")
|
||||
return False
|
||||
|
||||
|
||||
def verifier_quarto():
|
||||
titre("1/3 Quarto (outil de mise en page)")
|
||||
titre("1/4 Quarto (outil de mise en page)")
|
||||
quarto = trouver_quarto()
|
||||
if quarto:
|
||||
print(f" Quarto est installé : {quarto}")
|
||||
@@ -155,6 +179,82 @@ def verifier_quarto():
|
||||
return quarto
|
||||
|
||||
|
||||
# --- Polices -----------------------------------------------------------------------
|
||||
|
||||
DEPOT_NOTO = "https://github.com/notofonts/notofonts.github.io/raw/main/fonts"
|
||||
POLICES = { # famille attendue par _quarto.yml -> fichiers à installer si elle manque
|
||||
"Noto Sans": [f"NotoSans/hinted/ttf/NotoSans-{s}.ttf" for s in
|
||||
("Regular", "Italic", "SemiBold", "SemiBoldItalic", "Bold", "BoldItalic")],
|
||||
"Noto Sans Mono": [f"NotoSansMono/hinted/ttf/NotoSansMono-{s}.ttf" for s in ("Regular", "Bold")],
|
||||
}
|
||||
PAQUETS_POLICES = { # gestionnaire Linux -> commande d'installation des deux familles
|
||||
"apt-get": ["sudo", "apt-get", "install", "-y", "fonts-noto-core", "fonts-noto-mono"],
|
||||
"pacman": ["sudo", "pacman", "-S", "--needed", "noto-fonts"],
|
||||
"dnf": ["sudo", "dnf", "install", "-y", "google-noto-sans-fonts", "google-noto-sans-mono-fonts"],
|
||||
"zypper": ["sudo", "zypper", "install", "-y", "noto-sans-fonts", "noto-sans-mono-fonts"],
|
||||
}
|
||||
|
||||
|
||||
def polices_manquantes(quarto):
|
||||
"""Familles absentes, d'après la liste des polices réellement visibles par Typst."""
|
||||
resultat = subprocess.run([quarto, "typst", "fonts"], capture_output=True, text=True,
|
||||
encoding="utf-8", errors="replace")
|
||||
sortie = resultat.stdout + resultat.stderr # Quarto écrit la liste sur la sortie d'erreur
|
||||
familles = {ligne.strip() for ligne in sortie.splitlines()}
|
||||
return [f for f in POLICES if f not in familles]
|
||||
|
||||
|
||||
def dossier_polices_utilisateur():
|
||||
if SYSTEME == "Windows":
|
||||
return Path(os.environ["LOCALAPPDATA"]) / "Microsoft/Windows/Fonts"
|
||||
if SYSTEME == "Darwin":
|
||||
return Path.home() / "Library/Fonts"
|
||||
return Path.home() / ".local/share/fonts"
|
||||
|
||||
|
||||
def telecharger_polices(familles):
|
||||
"""Installe les polices pour l'utilisateur courant (aucun droit administrateur nécessaire)."""
|
||||
dossier = dossier_polices_utilisateur()
|
||||
dossier.mkdir(parents=True, exist_ok=True)
|
||||
for famille in familles:
|
||||
for chemin in POLICES[famille]:
|
||||
cible = dossier / Path(chemin).name
|
||||
print(f" Téléchargement de {cible.name}...")
|
||||
urllib.request.urlretrieve(f"{DEPOT_NOTO}/{chemin}", cible)
|
||||
if SYSTEME == "Windows": # déclarer la police pour l'utilisateur (comme « Installer » dans l'Explorateur)
|
||||
import winreg
|
||||
with winreg.OpenKey(winreg.HKEY_CURRENT_USER,
|
||||
r"Software\Microsoft\Windows NT\CurrentVersion\Fonts", 0,
|
||||
winreg.KEY_SET_VALUE) as cle:
|
||||
winreg.SetValueEx(cle, f"{cible.stem} (TrueType)", 0, winreg.REG_SZ, str(cible))
|
||||
if SYSTEME == "Linux" and shutil.which("fc-cache"):
|
||||
subprocess.run(["fc-cache", "-f", str(dossier)], stdout=subprocess.DEVNULL)
|
||||
|
||||
|
||||
def verifier_polices(quarto):
|
||||
titre("2/4 Polices (Noto Sans et Noto Sans Mono)")
|
||||
manquantes = polices_manquantes(quarto)
|
||||
if not manquantes:
|
||||
print(" Les polices sont installées.")
|
||||
return
|
||||
print(f" Polices manquantes : {', '.join(manquantes)}.")
|
||||
print(" Sans elles, les documents seraient produits avec une police de remplacement.")
|
||||
if not oui_non(" Les installer maintenant ?"):
|
||||
return
|
||||
gestionnaire = next((g for g in PAQUETS_POLICES if SYSTEME == "Linux" and shutil.which(g)), None)
|
||||
try:
|
||||
if gestionnaire:
|
||||
print(" Votre mot de passe peut être demandé (installation système).")
|
||||
subprocess.run(PAQUETS_POLICES[gestionnaire])
|
||||
if not gestionnaire or polices_manquantes(quarto):
|
||||
telecharger_polices(polices_manquantes(quarto))
|
||||
except Exception as erreur:
|
||||
print(f" L'installation des polices a échoué : {erreur}")
|
||||
reste = polices_manquantes(quarto)
|
||||
print(" Polices installées." if not reste else
|
||||
f" Toujours introuvables : {', '.join(reste)} (les documents seront produits quand même).")
|
||||
|
||||
|
||||
# --- Environnement Python des schémas ----------------------------------------------
|
||||
|
||||
def python_du_venv():
|
||||
@@ -162,7 +262,7 @@ def python_du_venv():
|
||||
|
||||
|
||||
def preparer_venv():
|
||||
titre("2/3 Environnement Python (schémas)")
|
||||
titre("3/4 Environnement Python (schémas)")
|
||||
empreinte = hashlib.sha256(EXIGENCES.read_bytes()).hexdigest()
|
||||
temoin = VENV / ".empreinte-requirements"
|
||||
if python_du_venv().exists() and temoin.exists() and temoin.read_text().strip() == empreinte:
|
||||
@@ -207,7 +307,7 @@ def ouvrir_dossier(dossier):
|
||||
|
||||
|
||||
def generer(quarto, venv_ok):
|
||||
titre("3/3 Génération des documents")
|
||||
titre("4/4 Génération des documents")
|
||||
i_format = choisir("Quel format ?", [f[0] for f in FORMATS])
|
||||
libelle, cible, extension = FORMATS[i_format]
|
||||
supports = lister_supports()
|
||||
@@ -244,6 +344,7 @@ def main():
|
||||
print("Python 3.9 ou plus récent est nécessaire.")
|
||||
raise SystemExit(1)
|
||||
quarto = verifier_quarto()
|
||||
verifier_polices(quarto)
|
||||
venv_ok = preparer_venv()
|
||||
while True:
|
||||
generer(quarto, venv_ok)
|
||||
|
||||
Reference in New Issue
Block a user