Переглянути джерело

:memo: Explain how to automatically index projets

DricomDragon 1 рік тому
батько
коміт
17089e4e30
1 змінених файлів з 228 додано та 3 видалено
  1. 228 3
      src/projets/pandoc_site/content.src.md

+ 228 - 3
src/projets/pandoc_site/content.src.md

@@ -478,23 +478,244 @@ source .env.local
 
 #### YQ
 
+Comment générer la page listant tous les projets ?
+
 En plus de Pandoc et GNU Make, j'ai eu besoin d'une troisième dépendance afin de manipuler programmatiquement les métadonnées stockées dans des fichiers YAML.
 
-Cette brique technique est essentielle pour construire dynamiquement la page des projets.
+##### Recenser les projets
+
+Mon besoin est d'avoir une page qui recense tous mes projets. Chaque projet possède un encart avec une description, une illustration et une icône, ainsi qu'un lien vers la page détaillée qui permet d'en savoir plus.
+
+*illustration encart + detail projet*
+
+L'objectif serait d'automatiser la découverte des projets et la génération de cette page d'indexation.
 
 ##### Description d'une page de projet
 
-Meta + Contenu
+Avant toute chose, regardons comment est structuré un projet.
+
+- `src/projets/pandoc_site/` : dossier racine d'un projet
+    - `content.src.md` : fichier source décrivant le projet
+    - `content.gen.html` : *fichier temporaire généré par pandoc*
+    - `content.meta.yml` : métadonnées du projet
+    - `pandocHtmlIcon.png` : icône du projet
+    - `pandocMakeHtmlLogo.png` : image d'illustration du projet
+
+Le contenu du fichier `content.meta.yml` contient toutes les métadonnées utilisées dans le modèle *Pandoc* qui sont spécifiques à la page associée :
+
+```yaml
+---
+title: Pandoc HTML
+img:
+        icon:
+                path: "pandocHtmlIcon.png"
+                alt: "Pandoc : HTML document with Markdown inside it"
+        main:
+                path: "pandocMakeHtmlLogo.png"
+                alt: "From Markdown to HTML via GNU/Make and Pandoc"
+subtitle: Génération statique de mon site web avec GNU/Make et Pandoc.
+content-date: 2023-06-05
+content-description:
+        Article explicatif sur Pandoc piloté par GNU/Make
+        pour générer mon site web statique.
+...
+```
+
+Ces métadonnées du contenu, en plus d'enrichir les métadonnées des documents HTML générés, sont utilisés dans mon modèle personnalisé de pandoc pour générer du contenu visible normalisé :
+
+```html
+<main role="main" class="container">
+$if(title)$
+            <header id="title-block-header" class="focus-center">
+                <h1 class="title">$title$</h1>
+$if(img.main)$
+                <img class="img-fluid rounded" src="$img.main.path$"$if(img.main.alt)$ alt="$img.main.alt$"$endif$>
+$elseif(img.icon)$
+                <img class="img-fluid rounded" src="$img.icon.path$"$if(img.icon.alt)$ alt="$img.icon.alt$"$endif$>
+$endif$
+```
+
+Pouvoir parcourir les métadonnées de tous les projets est une bonne piste pour générer automatiquement une page indexant les projets.
 
 ##### Itérer sur la liste des projets
 
 Étant donné une liste de projets au format yaml, nous pouvons utiliser les [parties du moteur de template de Pandoc](https://pandoc.org/MANUAL.html#partials) pour l'appliquer à chaque élément de la liste et ainsi formater une liste de projets.
 
+Étant donné un fichier `yaml` listant tous les projets (je l'ai tronqué pour un souci de concision) que l'on pourrait passer en entrée à *Pandoc* via l'argument `--metadata-file` :
+
+```yaml
+list:
+  - data:
+      title: ASCII Space Destroyer
+      img: {}
+      subtitle: Jeu vidéo réalisé en C++
+      content-date: 2015-08-15
+      content-description: ASCII description
+    target:
+      content: content.html
+      dir: ascii_space
+  - data:
+      title: Pandoc HTML
+      img: {}
+      subtitle: Génération statique de mon site web avec GNU/Make et Pandoc.
+      content-date: 2023-06-05
+      content-description: Pandoc description
+    target:
+      content: content.html
+      dir: pandoc_site
+```
+
+Il est possible d'utiliser les [parties](https://pandoc.org/MANUAL.html#partials) de Pandoc pour itérer sur chaque projet et générer l'aperçu associé. Le code du template principal associé à chaque projet :
+
+```html
+$if(list)$
+            <div class="card-columns">
+                    $^$${ list:card() }
+            </div>
+$endif$
+```
+
+Il faut alors que le template `card.html` existe et soit dans le même dossier que le modèle principal, l'élément de la liste courant étant accessible via la variable `it` :
+
+```html
+<div class="card">
+    <img class="card-img-top" src="$it.target.dir$/$it.data.img.main.path$"$if(it.img.main.alt)$ alt="$it.data.img.main.alt$"$endif$>
+    <div class="card-body">
+        <h4 class="card-title">
+            <img class="icon" src="$it.target.dir$/$it.data.img.icon.path$"$if(it.img.icon.alt)$ alt="$it.data.img.icon.alt$"$endif$>
+            $it.data.title$
+        </h4>
+        <p class="card-text">
+            $it.data.content-description$
+        </p>
+        <a href="$it.target.dir$/$it.target.content$" class="btn btn-success btn-block">
+            Page du projet
+        </a>
+    </div>
+</div>
+```
+
+Côté `makefile`, il faut créer une recette particulière pour ajouter le fichier `list.gen.yml` pour la page listant les projets seulement, sinon les projets seraient listés dans toutes les pages.
+
+```makefile
+DIR_OF_PROJECTS := src/projets
+GEN_LIST_YML := $(DIR_OF_PROJECTS)/list.gen.yml
+
+$(DIR_OF_PROJECTS)/content.gen.html: $(DIR_OF_PROJECTS)/content.src.html $(DIR_OF_PROJECTS)/content.meta.yml $(GEN_LIST_YML) $(SRC_TEMPLATES)
+    $(PANDOC_GEN) --metadata-file $(DIR_OF_PROJECTS)/content.meta.yml --metadata-file $(GEN_LIST_YML) --output $@ $<
+```
+
+Si le dossier `list.gen.yml` existe, tout est prêt pour générer automatiquement la page des projets.
+
+```sh
+make src/projets/content.gen.html
+```
+
+Il reste à déterminer comment construire ce nécessaire fichier `list.gen.yml`.
+
 ##### Construire automatiquement la liste de projets
 
 L'enjeu est donc de construire la liste YAML des projets automatiquement à partir des meta données de chaque projet pour éviter la double saisie.
 
-C'est là que YQ entre en jeu.
+J'ai pour cela eu recours à [yq](https://mikefarah.gitbook.io/yq/), qui est un utilitaire qui permet de manipuler les fichiers yaml.
+
+La première étape consiste à simplement aggréger les fichiers yaml présents dans tous les sous-dossiers du dossier `projets` en un seul fichier.
+
+```sh
+yq eval-all '. as $item ireduce ([]; . + $item) | {"list": .}' projets/*/*.meta.yml
+```
+
+On obtient alors le code yaml suivant dans la sortie standard :
+
+```yaml
+list:
+  - title: ASCII Space Destroyer
+    img: {}
+    subtitle: Jeu vidéo réalisé en C++
+    content-date: 2015-08-15
+    content-description: ASCII description
+  - title: Pandoc HTML
+    img: {}
+    subtitle: Génération statique de mon site web avec GNU/Make et Pandoc.
+    content-date: 2023-06-05
+    content-description: Pandoc description
+```
+
+La deuxième partie fut un peu plus acrobatique et consistait à construire une entrée `target` pour chaque élément afin de construire le lien vers la page du projet concerné. Heureusement, `yq` fournit une variable contenant le nom du fichier origine du fichier `yaml` en cours de traitement.
+
+```sh
+yq eval-all '{"data": ., "target": filename} as $item ireduce ([]; . + $item) | {"list": .}' projets/*/*.meta.yml
+```
+
+Vous remarquerez que j'en ai aussi profité pour regrouper les données brutes dans le bloc data :
+
+```yaml
+list:
+  - data:
+      title: ASCII Space Destroyer
+      img: {}
+      subtitle: ASCII subtitle
+      content-date: 2015-08-15
+      content-description: ASCII description
+    target: ascii_space/content.meta.yml
+  - data:
+      title: Pandoc HTML
+      img: {}
+      subtitle: Pandoc subtitle
+      content-date: 2023-06-05
+      content-description: Pandoc description
+    target: pandoc_site/content.meta.yml
+```
+
+Il reste maintenant à créer deux entrées dans target : une pour le dossier du projet, une autre pour le nom de fichier de contenu. Cette séparation est nécessaire pour que les images incluses dans la liste des projets soit relatif au dossier du projet.
+
+Cette opération est possible avec `yq`, grâce à sa fonction de substitution `sub` qui accepte les expressions régulières en argument. La lisibilité est cependant fortement impactée, accrochez vous :
+
+```sh
+yq eval-all '{"data": ., "target": {"content": filename | sub("meta.yml", "html") | sub(".*/", ""), "dir": filename | sub("projets/", "") | sub("/[^/]*.yml", "")}} as $item ireduce ([]; . + $item) | {"list": .}' projets/*/*.meta.yml
+```
+
+Mais cela permet bien d'obtenir l'aggrégation nécessaire à notre modèle Pandoc.
+
+```yaml
+list:
+  - data:
+      title: ASCII Space Destroyer
+      img: {}
+      subtitle: ASCII subtitle
+      content-date: 2015-08-15
+      content-description: ASCII description
+    target:
+      content: content.html
+      dir: ascii_space
+  - data:
+      title: Pandoc HTML
+      img: {}
+      subtitle: Pandoc subtitle
+      content-date: 2023-06-05
+      content-description: Pandoc description
+    target:
+      content: content.html
+      dir: pandoc_site
+```
+
+Je vous laisse parcourir la [documentation yq](https://mikefarah.gitbook.io/yq/operators/reduce) pour déchiffrer les commandes `yq`. Je vous préviens, un peu de pratique est nécessaire pour en maîtriser la puissance.
+
+Il reste un dernier effort à accomplir pour injecter cette commande dans notre `makefile` :
+
+```makefile
+DIR_OF_PROJECTS := src/projets
+GEN_LIST_YML := $(DIR_OF_PROJECTS)/list.gen.yml
+
+SRC_LIST_YML := $(shell echo $(DIR_OF_PROJECTS)/*/*.meta.yml)
+
+LIST_GEN := yq eval-all '{"data": ., "target": {"content": filename | sub("meta.yml", "html") | sub(".*/", ""), "dir": filename | sub("$(DIR_OF_PROJECTS)/", "") | sub("/[^/]*.yml", "")}} as $$item ireduce ([]; . + $$item) | {"list": .}'
+
+$(GEN_LIST_YML): $(SRC_LIST_YML)
+    $(LIST_GEN) $(SRC_LIST_YML) > $@
+```
+
+Et voilà, nous avons achevé notre `makefile` permettant la génération complète de mon site web !
 
 ### Limites
 
@@ -530,6 +751,10 @@ Enlever les caractères blancs, les commentaires, supprimer le CSS ou JS inutili
 
 Déclencher un `make install` à chaque sauvegarde de fichier.
 
+#### Utiliser les fonctionnalités de référence de Pandoc
+
+Pour avoir un sommaire et des références en bas de page. Vous aurez peut-être remarqué que le lien sur les [parties](https://pandoc.org/MANUAL.html#partials) était présent à plusieurs endroits, ce qui n'est pas facile à maintenir en cas de changement de lien ou en cas d'envie d'avoir une liste complète des références.
+
 ### Conclusion
 
 J'ai donc construit un système plus léger au niveau de la rédaction de contenu qui me permettra de facilement produire du nouveau contenu en markdown. J'ai troqué la dépendance serveur PHP contre deux dépendances au build, pandoc et GNU Make. L'opération est donc un succès et j'utilise aujourd'hui ce projet en production.