La Forge des Communs Numériques Éducatifs — Tutoriel 3/3 : Compiler et publier

J'ai dit dans la partie précédente que les bonnes pratiques voulaient que les sources des fichiers soient ajoutés au dépôt (fichiers .odt, .tex, etc.), mais pas les fichiers compilés (.pdf notamment). Mais avoir ces fichiers .pdf à disposition est très pratique, notamment dans les deux scénanios suivants.

  1. Sophie a un dépôt contenant tous ses cours en LaTeX, publiés sous licence libre. Son collègue Joseph-Louis, d'un autre établissement, est intéressé par son travail. Mais en parcourant son dépôt, il ne voit que des fichiers .tex, qu'il ne peut pas lire, même en diagonale, à moins de télécharger et compiler chacun d'entre eux. Si les fichiers .pdf sont disponibles avec les fichiers .tex, cela rend cette consultation plus pratique.
  2. Sophie utilise ce dépôt pour synchroniser son ordinateur personnel et sa clef USB, qu'elle utilise dans son lycée. Un jour, elle travaille chez elle, valide ses modifications sur le dépôt, les envoie sur la forge, et les télécharge sur sa clef USB. Elle doit maintenant compiler chacun des fichiers modifiés sur sa clef USB pour avoir une version à jour des fichiers .pdf compilés. Il serait bien pratique d'avoir une manière de compiler automatiquement tous les fichiers modifiés, et seulement ceux là.

Dans ce tutoriel, nous allons voir comment :

  • faire en sorte de compiler tous les documents qui ont changé (et uniquement ceux-là) ;
  • publier (rendre accessible) les documents compilés.

Préface : gitlab-ci

L'intégration continue consiste, lors du développement d'un logiciel, en l'exécution de tests à chaque validation (ou commit) pour vérifier qu'aucune régression n'a eu lieu (c'est-à-dire, que les nouvelles fonctionnalités ajoutées n'ont pas « cassé » les fonctionnalités déjà présentes).

Cela fait maintenant quelques années que les outils mis en place pour l'intégration continue sont aussi utilisés pour la livraison continue, c'est-à-dire la publication des logiciels à chaque validation (ou commit). Ce sont ces outils de « CI/CD » (intégration continue et livraison continue) que nous allons utiliser pour compiler nos fichiers à chaque validation (ou plutôt à chaque push).

Compilation

Cette partie suppose que vous travaillez sous GNU/Linux. Mais elle devrait aussi fonctionner avec MacOS, et probablement également avec Windows, à condition d'avoir installé les bons outils1. De toutes manière, puisque la publication sera faite sur les serveurs de la forge, qui ne permettent (sauf erreur de ma part) que l'utilisation de GNU/Linux, il est nécessaire de connaître les rudiments de ligne de commande sous GNU/Linux.

Je présente ici différents outils ; à vous de choisir le plus adapté à vos besoins.

Make

Le premier outil est le vénérable make, dont le développent a démarré en 1976, mais qui est toujours utile et efficace. Le principe est de désigner des cibles (ici les fichiers .pdf), qui dépendent de sources (fichiers .odt ou .tex par exemple), et des règles pour générer les cibles à partir des sources.

⚠️ Ce logiciel gère mal les espaces dans les noms de fichiers. Donc si vous voulez l'utiliser, il vous faudra renommer vos fichiers pour enlever les espaces, ou utiliser par exemple Évariste, présenté plus bas.

Un premier exemple très simple serait d'avoir un fichier Makefile contenant le code suivant :

toto.pdf: toto.tex
    pdflatex toto.tex

Ce fichier signifie : pour créer (ou mettre à jour) le fichier toto.pdf à partir du fichier toto.tex, il faut lancer la commande pdflatex toto.tex. Cela est exécuté à l'appel de la commande make dans le même répertoire que ce fichier Makefile, et la commande est ignorée si le fichier .pdf est plus récent que .tex (ce qui permet de ne recompiler le fichier LaTeX que lorsqu'il a changé).

Passons tout de suite à la version experte de ce fichier Makefile :

# Recherche tous les fichiers .tex du dépôt
TEX := $(shell find . -type f -regex ".*\.tex")
# Recherche tous les fichiers LibreOffice du dépôt
ODT := $(shell find . -type f -regex ".*\.odt")
ODS := $(shell find . -type f -regex ".*\.ods")
ODG := $(shell find . -type f -regex ".*\.odg")
ODP := $(shell find . -type f -regex ".*\.odp")
# Regroupe les noms des fichiers PDF qui seront générés à partir des fichiers LaTeX et LibreOffice
PDF := $(TEX:.tex=.pdf) $(ODT:.odt=.pdf) $(ODS:.ods=.pdf) $(ODG:.odg=.pdf) $(ODP:.odp=.pdf)

# Sans argument à `make`, compile tous les PDF
all: $(PDF)

# Règle pour la compilation des fichiers LaTeX
%.pdf: %.tex
    cd $(@D) && pdflatex $(<F)

# Règles pour la compilation des fichiers LibreOffice
%.pdf: %.ods
    cd $(@D) && libreoffice --headless --convert-to pdf $(<F)

%.pdf: %.odt
    cd $(@D) && libreoffice --headless --convert-to pdf $(<F)

%.pdf: %.odg
    cd $(@D) && libreoffice --headless --convert-to pdf $(<F)

%.pdf: %.odp
    cd $(@D) && libreoffice --headless --convert-to pdf $(<F)

Si ce fichier Makefile est présent à la racine de votre dépôt, après chaque git pull, exécutez simplement make dans un terminal, dans le même répertoire, et tous les fichiers LaTeX et LibreOffice qui ont été modifiés seront recompilés en .pdf, mais pas les autres.

Cela fonctionne bien, jusqu'au moment où certains de vos fichiers LaTeX doivent être compilés avec pdflatex, d'autres avec lualatex, et d'autres encore avec latex+dvipdf (ce qui peut arriver selon les paquets que vous utilisez).

Arara, Spix, etc.

Pour vos fichiers LaTeX, il est possible de préciser à l'intérieur du fichier le(s) logiciel(s) utilisé(s) pour le compiler (latex ? lualatex ? pdflatex ? avec une seule passe ? plusieurs passes ? avec biblatex ? etc.).

Arara

Arara est un logiciel libre permettant de définir dans le fichier .tex les outils nécessaires pour sa compilation. Dans sa version la plus simple, en écrivant le commentaire % arara: pdflatex au début de votre fichier .tex, vous indiquez que votre fichier doit être compilé avec pdflatex (et non pas avec latex ou lualatex, par exemple). Pour des règles plus complexes, je vous laisse consulter la documentation.

% arara: pdflatex

\documentclass{article}

\begin{document}
Bonjour, monde !
\end{document}

Si tous vos fichiers .tex précisent une telle règle, alors vous pouvez remplacer dans le fichier Makefile de la partie précédente la règle :

%.pdf: %.tex
    cd $(@D) && pdflatex $(<F)

par la nouvelle règle :

%.pdf: %.tex
    cd $(@D) && arara $(<F)

Désormais, lorsque vous lancerez la commande make, chaque fichier LaTeX sera compilé avec la ou les commandes adaptées.

SpiX

SpiX (dont je suis l'auteur) prétend être une version plus simple (donc moins puissante) d'Arara. Il fonctionne de manière un peu similaire, en précisant dans les commentaires de début de fichier la ou les lignes de commandes utilisées pour la compilation. Par exemple, exécuter spix sur le fichier suivant le compilera deux fois de suite avec lualatex.

% Compiler avec lualatex:
%$ lualatex $basename
%$ lualatex $basename

\documentclass{article}

\begin{document}
Bonjour, monde !
\end{document}

Comme avec arara, si tous vos fichiers sont configurés pour utiliser spix, vous pouvez utiliser dans votre fichier Makefile la règle suivante pour compiler les fichiers .tex.

%.pdf: %.tex
    cd $(@D) && spix $(<F)

Évariste

Évariste (dont je suis l'auteur) permet, comme make vu plus haut, de définir des règles pour compiler l'ensemble des fichiers vérifiant des conditions, mais aussi de surcharger ces règles pour certains fichiers particuliers. Il a aussi l'avantage de permettre de générer une page HTML présentant l'ensemble des fichiers sources et compilés, mais nous verrons cela dans la partie suivante.

Par exemple, en ayant un fichier evariste.setup à la racine de votre dépôt, avec le contenu suivant :

[setup]
plugins =
  vcs.git
  action.command
  action.autocommand

[action.autocommand.latex]
extensions = tex
targets = {basename}.pdf
command = lualatex {basename}

[action.autocommand.opendocument]
mimetypes = application/vnd.oasis.opendocument.*
targets = {basename}.pdf
command = libreoffice --headless --convert-to pdf {filename}

Lorsque vous exécuterez la commande evariste evariste.setup, tous les fichiers LaTeX seront compilés avec lualatex, et tous les fichiers LibreOffice avec libreoffice. Ensuite, si un fichier particulier toto.tex doit être compilé avec latex+dvipdf, vous pourrez créer dans le même répertoire le fichier toto.tex.evsconfig avec le contenu suivant :

[action]
plugin = command

[action.command]
targets = {basename}.pdf
command =
  latex {basename}
  dvipdf {basename}.dvi {basename}.pdf

Et alors tous les fichiers LaTeX seront toujours compilés avec lualatex (règle générale), sauf celui-ci qui sera compilé avec latex+dvipdf (règle particulière).

Désormais, après chaque git pull, il suffira de lancer la commande suivante pour compiler uniquement les fichiers qui ont été changés :

$ evariste evariste.setup

Publication

Maintenant que nous avons réussi à compiler tous les fichiers de notre dépôt en une seule commande, nous allons voir comment réaliser automatiquement cette opération sur la forge, à chaque git push, pour publier les fichiers compilés.

Introduction

gitlab-pages

Les gitlab-pages sont une fonctionnalité de la forge permettant, à chaque fois que vous téléverser des fichiers :

  • d'exécuter des commandes (ce qui permet de compiler les fichiers, et de construire un site web) ;
  • et de publier ce site web.

La configuration de ces pages se fait dans un fichier .gitlab-ci.yml, situé à la racine de votre dépôt.

docker

Les programmes exécutés à chaque git push sur la forge le sont sur un système d'exploitation GNU/Linux fonctionnant dans un conteneur docker (qui peut être vu, pour ce qui nous intéresse ici, comme un système d'exploitation configuré aux petits oignons avec les logiciels qui vous sont nécessaires pour votre cas particulier). De nombreux conteneurs prêts à l'emploi sont disponibles sur le site de Docker (en voici un avec Python, un autre avec LaTeX, ou le mien avec Python, LaTeX, LibreOffice et quelques autres outils).

C'est un peu technique, mais vous pouvez aussi créer le votre gratuitement, et le téléverser sur la forge (dans votre projet, menu Déploiement, puis Registre de conteneur).

Adresse de votre site web

Une fois les gitlab-pages correctement configurées, votre site web sera publié. Mais où ? Pour cela, allez sur la page de votre projet sur la forge, dans le menu Déploiement, puis Pages.

Menu

Vous voyez maintenant l'adresse avec laquelle votre page est accessible, ici : https://cours-seconde-generale-germainsophie-17a27cc3ed6cf7eeaae7b57d8.forge.apps.education.fr.

Domaine

C'est par défaut un « domaine unique », donc ce site web est quasi-privé (public, à condition de connaître l'adresse). Pour le rendre public, décochez « Utiliser un domaine unique », et enregistrez les modifications. La nouvelle adresse de vos pages, réellement publice cette fois-ci, est alors composée de votre identifiant et de celui de votre projet : https://germainsophie.forge.apps.education.fr/cours-seconde-generale.

À noter que Gitlab permet de publier un site web en utilisant un nom de domaine personnalisé (comme celui que j'utilise ici), mais cela n'a pas été configuré par les administrateur·ice·s de la Forge (et il est probable que ce ne sera jamais le cas).

Avec un modèle déjà existant

Si vous êtes parti d'un modèle, soit l'un de ceux proposés à la création d'un projet, soit celui proposé dans la documentation de la forge, alors ce fichier .gitlab-ci.yml existe déjà. Il faut juste y ajouter les instructions de compilation détaillées plus haut, pour que les fichiers soient compilés juste avant que le site web soit construit.

Cela se fait généralement dans la section build: ou pages. Par exemple, avec le site proposé sur la documentation, la section build: est la suivante.

build:
  stage: build
  before_script:
    - python -m venv .venv
    - source .venv/bin/activate
    - pip install -r requirements.txt
  script:
    - |
      if [ $CI_COMMIT_REF_NAME = "main" ] ; then
        mkdocs build
      else
        mkdocs build --no-directory-urls
      fi
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_REF_NAME == 'main'
  artifacts:
    paths:
      - site

Si vous souhaitez, par exemple, compiler vos fichiers avec make, comme décrit plus haut, il faudra ajouter une ligne dans la partie script:, qui deviendra alors :

  script:
    - make
    - |
      if [ $CI_COMMIT_REF_NAME = "main" ] ; then
        mkdocs build
      else
        mkdocs build --no-directory-urls
      fi

Si la compilation échoue, c'est peut-être parce que les logiciels nécessaires ne sont pas installés. Choisissez alors une image docker qui les intègre (première ligne du fichier .gitlab-ci.yml : image: python:3.10-alpine), ou installez-les à la volée dans la section before_script: de la section build:.

À la prochaine construction des pages, vos fichiers seront compilés avant la création du site, donc votre site peut contenir des liens vers les fichiers .pdf, même si ceux-ci ne sont pas présents dans votre dépôts (mais sont compilés à la volée grâce au fichier .gitlab-ci.yml).

En partant de zéro

Si vous ne souhaitez pas un « vrai » site web, mais simplement une liste brute de tous les fichiers du dépôts, avec les sources et la version compilée, evariste (déjà présenté plus haut) peut faire cela. Le rendu ressemble à cela.

Pour ce faire, il faut :

  • configurer evariste pour construire ce site web ;
  • configurer gitlab-ci pour exécuter evariste, et publier le site web.

Configuration d'evariste

Ajoutez (et modifiez) ce fichier evariste.setup à la racine de votre site web.

[setup]
plugins =
  vcs.git
  action.command
  action.autocommand

[changed]
time = vcs

[action.autocommand.latex]
extensions = tex
targets = {basename}.pdf
command = lualatex {basename}

[action.autocommand.opendocument]
mimetypes = application/vnd.oasis.opendocument.*
targets = {basename}.pdf
command = libreoffice --headless --convert-to pdf {filename}

[renderer.html.readme.mdwn]
enable = True

[renderer.htmlplus]
enable = True
destfile = public/index.html
destdir = public
staticdir = public/static

[renderer.htmlplus.templatevar]
# Des options en plus pour la page générée : titre, langue, favicon, texte en début de page…
title = Cours de mathématiques de seconde générale
lang = fr
favicon = ./logo.png
header = 
    <p>
       Du bla bla en HTML qui sera intégré en début de la page…
    </p>

Les premières parties définissent la manière dont les fichiers seront compilés. Les dernières parties (qui commencent par renderer) définissent la manière dont le site web sera généré.

Vous pouvez aussi définir, dans un fichier .evsignore, la liste des fichiers ignorés par evariste (que vous ne voulez pas voir dans la page générée), par exemple :

.gitignore
.gitlab-ci.yml
README.md
evariste.setup
logo.png

Configuration de gitlab-pages

Le fichier de configuration suivant, enregistré comme .gitlab-ci.yml à la racine de votre site web, permettra de compiler vos fichiers avec evariste, puis de publier la page web.

image: paternal/cours

pages:
  script:
    - evariste --verbose evariste.setup
  cache:
    untracked: true
  artifacts:
    paths:
      - public
  only:
    - main

C'est tout ! À la prochaine exécution des gitlab-pages, votre page web (liste brute de vos fichiers) devrait être publiée !

Licence

Comme expliqué dans la partie précédente du tutoriel, puisque vous publiez des fichiers, vous devez vous assurer que :

  • vous avez le droit de publier tout ce qui a été écrit par d'autres (autorisation, ou domaine public, ou licence permissive) ;
  • vous avez précisé une licence pour votre travail, si vous souhaitez que vos collègues puisse l'utiliser à leur tour.

  1. Outils que je ne connais pas, puisque je n'utilise plus Windows depuis une quinzaine d'année. Peut-être que WSL serait utile ici ?