Publication incrémentielle
Les sites pour l’éducation nécessitent souvent de pouvoir publier les chapitres du cours au fur et à mesure des semaines. Il en va de même avec les solutions des exercices qui ne doivent être publiés que lorsque les étudiants ont rendu leurs copies.
Installation
Pour permettre les opérations ci-dessus, nous avons besoin d’installer quelques plugins supplémentaires.
Allez dans le répertoire .devcontainer/mkdocs-edu/
et tapez les commandes suivantes
poetry add mkdocs-awesome-pages-plugin
poetry add mkdocs-macros-plugin
poetry add mkdocs-simple-hooks
Ajoutez aussi les plugins dans le fichier config/mkdocs.yml
:
...
plugins:
...
awesome-pages: {}
macros: {}
mkdocs-simple-hooks:
hooks:
on_pre_build: "hooks:on_pre_build"
Ajoutez aussi le fichier hooks.py
à la racine de votre projet:
import os
import jinja2
import logging
logger = logging.getLogger('mkdocs.hooks')
def on_pre_build(config):
logger.info("Running on_pre_build hook")
for root, dirs, files in os.walk(config["docs_dir"], topdown=False):
env = jinja2.Environment(
loader=jinja2.FileSystemLoader(root),
)
for name in files:
if name == "pages.j2":
template = env.get_template(name)
content = template.render(config=config, env=os.environ)
dst = os.path.join(root, ".pages")
# Do not write the file if the content is the same.
# Otherwise, the "watcher" will continuously reload the page.
if os.path.exists(dst):
with open(dst) as f:
orig = f.read()
if content == orig:
continue
with open(dst, "w") as f:
logger.info(f"Writing {dst}")
f.write(content)
Ce script permet de générer les fichiers .pages
pour le plugin awesome-pages
à partir des templates pages.j2
. Nous reviendrons sur l’utilisation de ces
fichiers plus tard.
Ajouter encore le fichier main.py
dans le dossier config/
:
import os
def define_env(env):
env.variables['solution'] = int(os.getenv("SHOW_SOLUTION") or 0)
env.variables['week'] = int(os.getenv("SELECT_WEEK") or 0)
Vous devez maintenant modifier le script serve
que nous avons vu
dans un chapitre précédent. Modifier le fichier .devcontainer/scripts/serve
avec le contenu suivant:
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
export SELECT_WEEK="999"
export SHOW_SOLUTION="999"
while getopts "w:s:" opt; do
case ${opt} in
w)
SELECT_WEEK=$OPTARG
;;
s)
SHOW_SOLUTION=$OPTARG
;;
\?)
echo "Usage: serve [-w week] [-s solution]" 1>&2
exit 1
;;
:)
echo "Invalid option: $OPTARG requires an argument" 1>&2
exit 2
;;
esac
done
# Serve MkDocs
mkdocs serve -f config/mkdocs.yml
Régénérez ensuite le devcontainer avec Ctrl+Shift+P ou Cmd+Shift+P et cherchez Remote-Containers: Rebuild Container.
La commande serve
accepte maintenant deux paramètres : -w
permet de choisir la
semaine à publier et -s
permet de contrôler la publication des solutions.
Publication incrémentielle du contenu
Pour publier le contenu de manière incrémentielle, ajoutez un fichier pages.j2
dans le dossier docs
ainsi que dans tous les sous-dossiers de docs
. La
documentation pour ce fichier se trouve sur le dépôt git du plugin mkdocs-awesome-pages-plugin et la configuration que nous
avons faite permet de générer les fichiers .pages
dynamiquement à partir des fichiers pages.j2
qui se trouvent dans le même dossier.
Un fichier pages.j2
typique ressemble à ça:
nav:
- index.md
{%- if env.SELECT_WEEK | int >= 1 %}
- chapter1.md
{%- endif %}
{%- if env.SELECT_WEEK | int >= 2 %}
- chapter2.md
{%- endif %}
{%- if env.SELECT_WEEK | int >= 3 %}
- chapter3.md
{%- endif %}
{%- if env.SELECT_WEEK | int >= 4 %}
- chapter4.md
{%- endif %}
Le fichier .pages
correspondant ne contiendra que les pages correspondantes
à la semaine choisie. Par exemple, si vous démarrez le serveur avec la commande
serve -w 2
, le fichier .pages
ci-dessus contiendra uniquement
les lignes suivantes :
nav:
- index.md
- chapter1.md
- chapter2.md
Publication incrémentielle des solutions
Pour le contrôle de la publication des solutions, nous devons agir sur le contenu du fichier markdown. Nous utilisons pour cela les blocs conditionnels du plugin macros
Un extrait d’un fichier markdown typique ressemble à ça:
!!! todo "Exercice N"
Donnée de l'exercice : ...
{% if solution >= 5 %}
??? success "Solution"
La solution est ...
{% endif %}
La solution ne sera alors publiée que si l’option -s
de la commande `serve``
est suivi d’un nombre supérieur ou égal à 5.
Astuce 1
Dans un chapitre donnée, les solutions seront souvent publiées en même temps. C’est assez
rare de ne devoir publier qu’une partie des solution à la fois. Au lieu d’écrire à chaque
fois le même nombre dans l’expression {% if solution >= 5 %}
, vous
pouvez définir la semaine dans le
front matter
de la page et si la solution doit être publiée une semaine plus tard, faites comme ça :
---
title: Titre de la page
week: 4
---
...
{% if solution >= page.meta.week + 1 %}
??? success "Solution"
La solution est ...
{% endif %}
Et si vraiment une solution doit être publiée une semaine plus tard, rien ne vous empêche d’écrire :
{% if solution >= page.meta.week + 2 %}
??? success "Solution"
La solution est ...
{% endif %}
Astuce 2
Si vous souhaitez numéroter les questions, vous pouvez utiliser une variable pour garantir une série régulière.
Au début de votre contenu markdown, définissez une variable (par exemple q
):
{% set q = 1 %}
et utilisez cette variable dans vos questions :
!!! todo "Exercice {{ q }}"
{% set q = q + 1 %}
...
Vous pourez en tout temps insérer des exercices dans votre document sans avois à vous soucier de la numérotation.
Modification du workflow pour la publication
Les paramètres de contrôle de la publication peuvent être définis dans des variables d’environnement.
Modifiez le fichier .github/workflows/website.yml
avec
la section suivante :
env:
SELECT_WEEK: 999
SHOW_SOLUTION: 999
Il vous suffit maintenant de changer ces valeurs chaque semaine et de faire un push de votre site pour l’actualiser.
Info
Je travaille sur une solution permettant d’également automatiser ce processus avec un calendrier. Contactez-moi si cette option vous intéresse.