catium

Un générateur de site statique - retour accueil

git clone git://bebou.netlib.re/catium
Log | Files | Refs | README |

commit 0c55fe09fa787ad1a9d44b397591d676e521c011
Auterice: arthur <arthur.pons@unistra.fr>
Date:   Fri, 23 Jun 2023 15:35:51 +0200

Premier commit

Diffstat:
A.gitignore | 2++
AREADME | 1574+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AUSAGE | 469+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/atomic | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/pug | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/pug2cat | 26++++++++++++++++++++++++++
Abin/shylus | 14++++++++++++++
Acommon | 22++++++++++++++++++++++
Alib/html | 10++++++++++
Amakefile | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Apage | 8++++++++
Arc/style.css | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/index.md | 42++++++++++++++++++++++++++++++++++++++++++
13 files changed, 2575 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,2 @@ +*.sw? +root diff --git a/README b/README @@ -0,0 +1,1574 @@ +Dépôt contenant les élèments du générateur de site statique Francium et les +sources du site du collectif Katzele +=========================================================================== + +## Une histoire de Francium + +Je discutais un jour avec une personne du contenu que l'on consommait sur +internet. Le dialogue était à peu près le suivant, elle commence : + +A - "Je suis abonné à plusieurs newsletters de journaux, de blogs, de revues +etc"\ +B - "Ah j'aime pas trop les newsletter, perso j'utilise des flux rss quand ils +existent"\ +A - *souriant je crois un peu nerveusement* "Ah ouais ? C'est pas vieux et +presque mort les flux rss ? Je pensais que plus personne n'utilisait ça."\ +B - "Bah c'est plus vraiment à la mode mais c'est encore presque partout et je +le préfère aux newsletter parce que *blablabla*" + +J'ai repensé plusieurs fois à cet échange depuis. Je n'ai pas été surpris pas +le manque de considération pour des technologies pensées comme vieillissantes, +obsolètes, démodées, remplacées. J'ai été cependant marqué par le fait que +cette personne percevait les flux rss comme plus vieux et donc moins digne +d'intérêt que les mails. Pourtant les mails (entre 27 et 50 ans) sont bien plus +anciens que les flux rss (23 ans). Il y a donc autre chose à l'œuvre, quelque +chose qui modifie notre perception de l'ancienneté d'une technologie +indépendamment de son âge réel. On peut imaginer pleins de facteurs pouvant +l'expliquer, le taux d'adoption en est un assez évident, comme si l'on +commençait à décompter l'âge d'une techno qu'à partir du déclin de son +utilisation. Je pense qu'il y en au moins un autre. Il se trouve que cette +personne écrit une newsletter et qu'elle utilise le service Substack pour le +faire. Substack est une plateforme proposant des services pour construire et +publier des newsletter monétisables. L'outil profite d'une certaine hype, +construit par défaut des newsletter avec tous les codes esthétique du web et +des pages webs associées. J'imagine que ce qui explique en partie que cette +personne ne voit pas la publication et l'agrégation de contenu web à travers +des mails comme une pratique obsolète contrairement aux flux rss est le fait +qu'elle le fait à travers un service qui a techniquement, mais surtout +socialement, repackagé la pratique. On n'envoie plus des mails à la papa, "on a +un Substack". La corolaire dit donc qu'une plateforme de la silicon valley ou +un projet open source à la mode pourrait relancer la popularité des flux rss +sans modifier quoi que ce soit à la techno. + +Ce phénomène, qui s'il en est vraiment un doit déjà être connu et porter un nom +que j'ignore, se retrouve à mon avis avec medium et la pratique d'avoir un blog +ainsi que jekyl/hugo et le fait de construire des sites statiques plutôt qu'une +single page app. + +On peut se réjouir de cette résurgence des sites statiques pour de multiples +raisons. On peut regretter - pas trop fort mais quand même - que cela ait +nécessité l'apparition de nouveaux logiciels pour motiver l'industrie à s'y +remettre. Cela semble être la démonstration parfaite que parfois, peut-être +même souvent, ce que la technologie facilite et sa façon de se présenter à nous +(voir le concept d'affordance, des outils de génération de sites statiques ont +toujours existé) a un impact conséquent sur les comportements humains jusqu'à +créer à posteriori les idées et justifications morales de son utilisation. +Autrement dit, on (du moins je) voyait peu d'articles faisant la promotion des +sites statiques avant l'apparition de ces outils. C'est dorénavant assez +fréquent avec une mention presque systématique de ces outils de là à presque +oublier pourquoi un site statique est dans certains cas préférable. + +Autre constat, ces outils destinés à produire des sites simples, le sont assez +rarement eux-mêmes. Évidemment cela dépend du référentiel choisi. On aura du +mal à argumenter qu'hugo est aussi lourd et complexe à dégainer que React. Mais +au regard des fonctionnalités essentielles pour un générateur de site statique, +il est possible d'argumenter qu'hugo est un logiciel trop complexe et faisant +trop de choix pour vous. On pourrait épiloguer là dessus, pour une autre fois +et une autre personne peut-être. + +Si ces outils ont relancé l'intérêt pour les sites statiques, Francium souhaite +à son tour profiter de l'intérêt nouveau pour les sites statiques afin de +relancer l'intérêt pour une certaine approche du développement d'outils +numériques, que l'on choisit à tort ou à raison d'appeler convivialiste. Plus +concrètement cette envie s'est cristallisée courant 2022 à l'Université de +Strasbourg autour du besoin de générer des sites statiques pour le domaine de +la recherche. L'une des utilisations identifiées était la création de page +personnelles pour les chercheureuses. Pour en faire une démonstration il avait +été décidé de faire la page de Marguerity Perey, chercheuse française ayant +travaillé à l'université de Strasbourg et ayant découvert... le francium.\ +Ce projet initial de générer des pages personnelles de chercheureuses n'est pas +mort. Un template html et une feuille de style adéquate, à l'identité visuelle +Unistra, pourrait aider à le concrétiser. + +C'est finalement la page perso de Marc Chantreux aujourd'hui hors ligne qui +sera le premier site généré et publié grâce à Francium. A date du 11 janvier +2023 le site généré par ce dépôt est le seul en ligne généré par Francium. Le +socle du projet a été conçu et développé par Marc Chantreux. Après la mise en +ligne de ce site le développement s'est étendu à d'autres membres du collectif +Kaztele. + +Il y aurait bien d'autres choses à dire sur la genèse du projet, d'où le titre +de cette rubrique, *Une* histoire de Francium. J'invite les autres parties +prenantes à écrire la leur. + +## Sur la nature de Francium + +Un jour Marc et moi sortions de plusieurs heures de discussions pendant +lesquelles nous avons plusieurs fois fait référence à Francium comme un outil +atomique, se suffisant à lui même. En disant ça nous mettions peut-être dans la +tête de nos interlocuteurs l'image d'un simple couteau qui tient dans la main, +dont les contours sont nettes et la forme plus ou moins identique pour tous ses +utilisateurices. En sortant nous nous sommes partagés une intuition commune : +cette image n'est pas celle qui se formait dans nos têtes quand on parlait de +Francium. Il est compliqué de définir le périmètre exact de ce qu'est Francium. + +Où est-ce que l'outil commence, où est-ce qu'il se termine ? Qu'est-ce qui +relève du générateur et qu'est-ce qui relève du contenu du site ? Ces +interrogations se retrouvent dans certains choix techniques que le projet est +amené à prendre. Ce dépôt permet aujourd'hui de versionner à la fois Francium +(sans savoir ce que c'est exactement) et le contenu du site de Katzele. Si nous +voulions créer un dépôt Francium pour d'autres projets nous devrions répondre à +ces questions pour détricoter l'un de l'autre. + +Pourquoi n'est-ce pas trivial ? + +Prenons en exemple atomic, le script permettant de générer des flux atom. + +Premier point d'accroche, tous les sites n'ont pas besoin d'un flux atom. Bien +que ce soit souvent utile et qu'atomic soit léger, l'inclure dans le dépôt +revient à penser que tous les projets, ou au moins une majorité, ont intérêt à +avoir un script de génération de flux atom. + +Second point, si l'on fait le choix de l'inclure par défaut, tous les flux ne +veulent pas y inclure les mêmes informations. Au delà de la spécification des +flux rss/atom, chaque projet peut vouloir mettre quelque chose de différent +dans les balises. Par exemple la balise "content" est très libre, et son +contenu peut éventuellement être mis en page avec de l'html. Autre exemple, un +flux annonçant des évènements dans le futur voudra sûrement inclure la date +dans le titre, la spécification atom n'ayant pas prévue de balise pour +renseigner la sortie d'un contenu dans le futur. La seule date prévue est celle +de publication du contenu qui ici est l'annonce au présent de la tenue de +l'évènement dans le futur. Il tombe donc sous le sens qu'aucun script atomic ne +se ressemblera. Quel doit donc être l'atomic par défaut ? Le minimum vital ? +Un script générant un flux orienté annonce d'évènements ou publications +d'articles ? + +Troisième point, qui découle du précédent, un projet pourrait vouloir générer +plusieurs flux aux formes différentes. Il pourrait alors vouloir plusieurs +atomic. Ce qui pose la question, qu'est-ce que l'on appel atomic ? Le script +par défaut tel que fourni dans le dépôt source s'il existe un jour ? La version +actuelle maintenue pour le site de Katzele ? L'idée de générer un flux atom via +du shell ? Bref on en a pas fini. + +Nous pourrions décliner ces questions pour toutes les parties de Francium. Pour +revenir à l'échange avec Marc, il avait d'avantage mûri la question que moi. +Francium ne devrait pas être pensé comme, un outil indivisible mais une comme +armature intellectuelle soutenant des outils, certains pré existants, d'autres +créés pour l'occasion. D'ailleurs pour le site de Katzele sed est un outil +autant nécessaire qu'atomic même si l'un a été développé pour et l'autre non.\ +Si l'on voulait pousser cette idée d'armature intellectuelle jusqu'au bout nous +pourrions dire que Francium est un système décrit à travers de la documentation +et non pas ses implémentations. Il n'existerait donc pas de sous-ensemble de ce +dépôt que l'on pourrait raisonnablement appelé Francium. Ce dépôt ne serait que +la première implémentation de Francium, celle sous une forme qui rend les +services dont le collectif Katzele a besoin à un instant T. + +Il existera probablement un jour un dépôt Francium dont le contenu aura été le +résultat de choix plus ou moins raisonnables, fait en fonction des projets qui +veulent utiliser Francium sur le moment. Ce sera certainement pour le mieux. Si +le concept un peu prétentieux d'armature intellectuelle nous sert à quelque +chose ce sera de faire sens de cette tension : construire un outil +convivialiste qui respecte autant que possible l'autonomie des personnes qui +l'utilisent en minimisant les choix qu'il véhicule et vouloir le publier +facilement n'est pas naturel. La première caractéristique incite à la +construction d'une armature, l'autre à celle d'un outil boite noire.\ +Tracer le contour optimisant la convivialité et la facilité de publication +étant hasardeux, on le fera à main levée et on compensera comme il se doit, en +conversant entre humains, en vivant ensemble. + +## Stop le blabla, comment ça fonctionne ? + +Comme expliqué précédemment la description suivante va mélanger ce qui pourrait +relever de Francium seul et du projet du site de Katzele. + +### Descriptif des dossiers et fichiers du projet + +#### Les fichiers + +makefile + +Le makefile décrivant les recettes pour générer les différents fichiers essentiels du projet. + +page + +Le script permettant de générer les pages html à partir des sources markdown. + +README + +Ce fichier. + +TODO + +La liste des choses à faire pour faire avancer le projet + +#### Les dossiers + +bin + +Contient des exécutables utilisés pour générer des fichiers cibles à partir de +fichiers sources. + + * atomic - un ensemble de fonctions shell pour construire un flux rss + * pug - + * pug2cat - + * shylus - + +lib + +Contient les layout html du site ? + + * html - le layout par défaut du site de Katzele + +rc + +Contient les templates html et css + + * grid.shylus - + * html - + * theme.shylus - + +root + +L'arborescence des fichiers cibles, la racine du site statique généré et à +servir par le serveur http. + +src + +L'arborescence des fichiers sources. Pour Katzele + +### Fonctionnement général + +Pour ce "manuel" j'ai fait le choix d'expliquer comment les choses fonctionnent +en reconstruisant ensemble Francium à un degré d'abstraction que l'on juge +convenable. Non seulement je pense que c'est une approche pédagogique +intéressante mais ce sera aussi la démonstration que penser, construire et +modifier ce genre de systèmes est à la portée de beaucoup plus de gens qu'on ne +le pense. Par forcément dans sa totalité, de bout en bout, pas forcément +spontanément dans un vide, pas forcément en mobilisant chaque petite astuce, +mais dans les grandes lignes. Si à la lecture de ce qui suit vous vous dîtes au +moins une ou deux fois "Ah oui pas bête, j'aurais éventuellement pu y penser !" +alors l'objectif sera accompli.\ +Le fait de pouvoir raconter l'histoire fictive d'une personne reconstruisant +tout Francium dans un simple document texte faisant + +echo "$(wc -l < README) lignes dont $(grep "^ " < README | wc -l) de code soit environ $(dc -e "$(wc -l < README) 50 / p") pages A4, $(dc -e "$(wc -l < README) $(grep '^ ' < README | wc -l) - 50 / p") sans les exemples de code" + +> Pour éviter de devoir refaire le compte à chaque fois je laisse la commande +> telle quelle que vous pouvez évaluer vous même. Si vous lisez ce document +> dans vim vous pouvez faire positionner le curseur sur la ligne et taper "!!sh +> entrée". + +est également une démonstration que l'outil est **relativement** simple. Une +trentaine de page c'est beaucoup mais il faut garder en tête que cela inclu +*tout* le code et ce qui motive l'ajout de chacune des lignes. Un travail +similaire serait plus ou moins inconcevable pour une large part des logiciels +que l'on utilise aujourd'hui. + +Le but de Francium est de prendre les fichiers du dossier src et d'en faire un +site logeant dans root. Pour ce faire Francium mobilise plusieurs exécutables +ou scripts qui transforment les sources et placent les données là où il faut +dans les schémas de données. + +#### Le makefile + +Le makefile est le grand orchestrateur, il appelle les scripts sur les fichiers +sources pour construire le dossier root. Un makefile est un fichier décrivant +les règles permettant au programme make de générer les fichiers que l'on +souhaite. Make était initialement utilisé pour compiler des programmes mais il +peut générer n'importe quel type de projet. Pour chaque fichier que l'on +souhaite générer le makefile renseigne ses dépendances et comment le générer. + +Prenons le site de Katzele en exemple, en commençant par la génération des +pages html. La première chose que le makefile cherche à faire est de créer la +liste des pages à générer. Partons du principe que chaque fichier markdown doit +être converti en html et se trouve dans l'arborescence de src à l'endroit où il +doit se trouver dans l'arborescence de root. Autrement dit root est en quelque +sorte le miroir html de src. Pour générer la liste il nous faut recueillir la +liste des fichiers md de src : + + sources != find src -type f -name '*.md' + +Ici on demande à find de trouver dans le dossier `src` tous les fichiers +(`-type f`) dont le nom fini par l'extension `.md` et de renvoyer leurs chemins +relatifs depuis la racine du projet (là où make sera lancé). La syntaxe `!=` +demande à make d'instancier la variable à la première lecture du fichier. En +l'occurence je pense que mettre simplement `=` ne changerait rien pour le site +de Katzele. Pour en savoir plus lire le chapitre 3.7 du manuel : + +https://www.gnu.org/software/make/manual/make.html#Reading-Makefiles + +A l'instant où j'écris cette ligne le résultat de cette commande pour le site +de Katzele est : + + src/notes/220917/les_ui_convivialistes/index.md + src/notes/221019/interfaces_alternatives_youtube/index.md + src/index.md + +`sources` contient dorénavant le chemin, depuis la racine du projet, vers tous +les fichiers md. Il faut ensuite à partir de cette liste créer la liste des +chemins des fichiers html correspondants à générer : + + pages = ${sources:src/%.md=root/%.html} + +La syntaxe `${variable:tr%uc=bid%ule} est un raccourci pour la fonction +`$(patsubst pattern, replacement, text)` soit $(patsubst tr%uc, bid%ule, +variable). Cette fonction prend le contenu de la variable ou du texte, la ou le +découpe en morceaux séparés par du blanc ou une nouvelle ligne et remplace les +occurrences de ce qu'il y a avant le signe `=` par ce qu'il y a après. Le +symbole `%` est un joker et peut correspondre à n'importe quoi. Dans notre +exemple la fonction prendra le premier chemin dans sources : + + src/notes/220917/les_ui_convivialistes/index.md + +détectera le `src/` du début qu'elle transformera en `root/` et le `.md` de la +fin qu'elle transformera en `.html`. Elle "mettra" +`notes/220917/les_ui_convivialistes/` "dans" %, qu'elle repercutera dans le +résultat final. On a donc : + + src/notes/220917/les_ui_convivialistes/index.md + ---- --- + % + ----- ----- + root/notes/220917/les_ui_convivialistes/index.html + +à savoir le chemin du fichier html que l'on souhaite générer. Pour en savoir +plus lire le chapitre 8.2 du manuel : + +https://www.gnu.org/software/make/manual/make.html#Text-Functions + +Nous avons dorénavant la liste de tous les fichiers html à générer dans la +variable pages : + + ./root/notes/220917/les_ui_convivialistes/index.html + ./root/notes/221019/interfaces_alternatives_youtube/index.html + ./root/index.html + +Nous allons maintenant appeler les règles permettant de construire ces fichiers. Une règle a la syntaxe + + cible : prérequis ; recette + suite recette + +Pour en savoir plus sur la syntaxe des règles lire le chapitre X.X du manuel : + +https://www.gnu.org/software/make/manual/make.html#Rule-Syntax + +La règle permettant d'écrire la cible `root/index.html` ressemble donc à : + + root/index.html : src/index.md page; src/index.md | install -D /dev/stdin root/index.html + +`src/index.md` est le fichier source, c'est donc naturellement un prérequis à +pouvoir construire `src/index.html`. `page` est le script permettant de +transformer le markdown en html, également un prérequis à la construction de +l'html. On reparlera de lui par la suite.\ +Make va vérifier si ces prérequis existent. S'il n'existent pas ils cherchera +et exécutera les règles pour les construire. S'ils existent il exécutera +directement la commande permettant de générer le fichier cible. Cette commande +appelle le fichier `src/index.md` qui est en réalité un script dont la sortie +est son propre contenu en html, le pipera dans `install` qui est une commande +copiant des fichiers d'un endroit à un autre. Pensez à `cp`, `mkdir` et `chmod` +combinés en un seul outil fréquemment utilisé dans les scripts d'installation. + +TODO : expliquer comment make sait s'il faut régénérer une cible ou pas en fonction de ses prérequis. Là c'est pas clair/pas expliqué + +Si vous suivez bien vous vous dîtes "Oui mais on devait générer trois fichiers +html, on va tout de même pas ajouter à la main une nouvelle règle à chaque fois +que l'on ajoute un fichier ?". Il est possible d'écrire les règles de façon +plus génériques. Puisque les fichiers html sont tous générés de la même façon +et que l'on a accès au joker `%`, on peut n'écrire qu'une seule règle : + + root/%.html : src/%.md page; $< | ${mk} $@ + +Vous reconnaitrez le couple `src/%.md` et `root/%.html`. Si make rencontre par +exemple le chemin `./root/notes/220917/les_ui_convivialistes/index.html` il +cherchera une règle qui correspond. `root/%.html` match avec +`%=notes/220917/les_ui_convivialistes/index`. Si `%` est réutilisé dans les +prérequis, make le remplacera par sa valeur dérivée de la cible. Dans notre ca +make vérifiera donc qu'il existe bien le prérequis +`src/notes/220917/les_ui_convivialistes/index.md` et le script `page`. Une fois +tous les prérequis réunit, make exécutera la commande. `$<` est l'une des +variables "automatiques" que make recalcule à chaque règle. Elle contiendra +toujours le chemin du premier prérequis. Dans notre exemple elle contient donc +le chemin vers le fichier source md. `$@` en est une autre, elle contient le +chemin vers le fichier cible html. Finalement ${mk} est une variable créée à la +main par la ligne + + mk = install -D /dev/stdin + +qui permet simplement de ne pas avoir à taper la commande en entier à chaque +fois et peut-être faire de fautes de frappe. Si l'on "déploie" chaque variable +on retrouve exactement la commande écrite plus haut. Nous avons donc une règle +générique pour tous les fichiers html ! + +Pour en savoir plus sur les variables dîtes automatiques lire le chapitre +10.5.3 du manuel : + +https://www.gnu.org/software/make/manual/make.html#Automatic-Variables + +Reste à savoir comment les appeler. Par défaut make cherche à créer la première +cible qu'il rencontre dans le makefile. Cela est pratique quand on veut générer +un binaire à partir de tout plein de sources. On met la règle pour le binaire +en premier avec toutes les dépendances. Make va chercher à construire ces +dépendance en appelant d'autres règles et ainsi de suite. Dans notre cas nous +n'avons pas un seul et unique but, nous voulons générer une arborescence, pas +un seul fichier. De plus, make va chercher la première règle qui n'est pas +"générique". Dans notre cas make ne ferait donc rien. Il nous faut donc une +règle pour les gouverner toutes. Par convention on nomme la cible de cette +règle "all". On appelle les cibles qui ne sont pas réellement des fichiers à +construire des cibles "phony" (fausses, bidons, hypocrite). + +Pour en savoir plus sur les phony targets lire le chapitre 4.6 du manuel : + +https://www.gnu.org/software/make/manual/make.html#Phony-Targets + +Cette règle ressemblerait à ceci et se trouverait en premier dans le makefile : + + all: ${pages} + +Pour rappel `pages` est une variable qui contient la liste de tous les fichiers +html à générer. Cette règle indique donc à make que tous les fichiers html sont +des prérequis à la fausse cible "all". Make va donc chercher à les construire +et faire appel, autant de fois que nécessaire, à la règle qui a pour cible +`root/%.html` que l'on a écrite récemment. Attention, cela ne fonctionne que +parce que + + 1. c'est la première règle du fichier, + 2. parce qu'il n'y a pas de fichier nommé "all" dans le projet et + 3. parce que la règle n'a pas de recette qui créé un fichier "all" + +Ça n'est pas magique. + +Le makefile qui résulte de tout ce travail a pour contenu, commenté : + + # Pour copier les fichiers d'un endroit à un autre + mk = install -D /dev/stdin + + # Dans sources les md à transformer en html + sources != find src -type f -name '*.md' + + # On construit dynamiquement les règles à invoquer avec des substitutions de + # chaînes de caractères + # Ex: Pour pages on prend tous les chemins de fichiers récupérés dans sources + # On substitue src/ par root/ et l'extension md par html + # Le fichier source "src/truc/bidule.md" donnera donc + # "root/truc/bidule.html" + pages = ${sources:src/%.md=root/%.html} + + # On appelle toutes les règles pour produire tous les fichiers + # nécessaires + # Pour chacune make va tenter de trouver une règle correspondante dans la + # liste qui suit + all: ${pages} + + clean:; rm -r root/* + + # Règle pour générer l'html depuis les fichiers md + # Va matcher toutes les règles stockées dans la variable pages + # Chaque fichier html requiert sont équivalent md dans src et le script + # page + # Ce que % match dans la cible sera substitué à la place de % dans les + # dépendances + # La commande pour la compilation revient à exécuter le fichier md (qui + # est en fait un script) et piper le contenu dans la commande stockée + # dans la variable mk avec pour argument la cible + # make substitue la variable $@ avec le chemin de la cible + root/%.html : src/%.md page; $< | ${mk} $@ + +Avec une petite "phony target" supplémentaire qu'est `clean`, qui ne dépend de +rien (notez le `;` directement après le `:`) et qui supprime tout le contenu de +`root`. Puisqu'elle n'est pas listée en premier la seule commande `make` ne +l'exécutera pas et puisqu'elle n'a pas de prérequis la cible sera toujours +considérée comme à jour. Pour nettoyer le projet il convient donc de passer en +argument la cible à la commande en faisant `make clean`. + +Vous avez maintenant compris l'esprit général du makefile. Tous les fichiers +que vous voudriez générer le seront ici grâce à une suite d'inventaire des +sources, de construction des chemins cibles, d'appels à des règles et +d'exécutions des commandes appropriées.\ +Par exemple admettons que vous voulez, en plus de générer l'html, copier les +fichiers md tel quel dans `root` pour que les personnes puissent accéder aux +sources et vous soumettre des modifications. +Autrement dit on veut que le fichier + + src/truc/bidule/chouette.md + +se retrouve dans + + root/truc/bidule/chouette.md + +au côté de `chouette.html` + +Nous avons déjà la liste des fichiers md dans la variable `sources`. On reprend la construction de la variable `pages` que l'on adapte à notre besoin : + + rawrules = ${sources:src/%.md=root/%.md} + +et on ajoute tous ces chemins en prérequis à la cible `all` : + + all: ${pages} ${rawrules} + +Reste à construire la règle qui matchera avec ces chemins. En se basant sur la +règle pour les fichiers html : + + root/%.md : src/%.md; install -D $< $@ + +Cette fois-ci la recette ne contient que la commande install puisqu'il n'y a +pas de transformation à faire. Hop c'est fait ! + +#### page et le format des fichiers markdown + +Quelque chose vous aura peut-être fait ticker dans cette explication du +makefile. Comment la commande suivante peut elle fonctionner et quel est son +rapport au script `page` prérequis a son bon fonctionnement sans pour autant +qu'il apparaisse. + + src/index.md | install -D /dev/stdin root/index.html + +La réponse courte à cette question est : + +> Deux astronautes sont dans l'espace faisant face à un Francium géant constitué de pleins de petits 'sh'\ +> Les astronautes sont l'un derrière l'autre, le premier contemple Francium, le +> second tient le premier à bout portant avec un pistolet\ +> Le premier dit "Wait, it's all shell scripts ?", le second répond "Always has been" + +``` +shshsh shshsh shshsh sh sh shshsh shshsh sh sh sh sh +sh sh sh sh sh shsh sh sh sh sh sh shshsh +shsh shshsh shshsh sh shsh sh sh sh sh sh sh +sh shsh sh sh sh shs sh sh sh sh sh sh +sh sh sh sh sh sh sh shshsh shshsh shshsh sh sh + + 웃 🔫웃-Always has been + \ + Wait it's all shell scripts ? +``` + +Plus sérieusement nous allons procéder comme pour le makefile, en partant du +premier besoin, le plus essentiel, et en brodant petit à petit autour jusqu'à +arriver au degré d'abstraction existant dans le projet du site Kaztele +aujourd'hui. En cours de route nous répondrons à la question. + +Vous savez peut-être déjà convertir du markdown en html. Le problème n'est pas +trivial parce qu'html c'est compliqué et le markdown défini de façon assez +ambigüe. Cette ambiguité est la raison pour laquelle un même fichier markdown +sera rendu de façon différente selon si c'est le README d'un projet github, de +la documentation docbook etc. Le projet commonmark tente de faire émerger un +standard. Plusieurs implémentations existent. Pandoc peut traduire du mardown +en html selon les specifications commonmark. Le projet lowdown en est une +implémentation assez légère en C. A l'heure où j'écris ces lignes le site de +Kaztele utilise lowdown.\ +Son utilisation est simple, markdown en entrée, html en sortie : + + <<% lowdown + # Titre 1 + + Une liste cool + + * elem 1 + * elem 2 + + [lien 1](katzele.net) + + ## titre 2 + + du texte + % + + <h1>Titre 1</h1> + <p>Une liste cool</p> + <ul> + <li>elem 1</li> + <li>elem 2</li> + </ul> + <p><a href="katzele.net">lien 1</a></p> + <h2>titre 2</h2> + <p>du texte</p> + +Si la syntaxe <<%...% ne vous est pas familière pas de souci, on en parlera +plus tard. + +Pandoc, lowdown etc ne génèrent que le strict minimum d'html nécessaire. Le +résultat ne comporte pas le "boilerplate" nécessaire pour faire une page html +complète, même la plus simple possible. De plus il faudrait pouvoir en plus du +contenu de la page permettre de spécifier par exemple le titre de l'article à +mettre dans la balise `<title> du header. Pour le premier besoin pandoc a un +système de template, pour le second il a une autre solution que j'ai utilisé +une fois y'a longtemps et que j'ai oublié.\ +Puisque nous utilisons lowdown qui essaye de rester très limité dans son +périmètre nous allons devoir faire preuve d'ingéniosité. + +Pour rester sur quelque chose de simple on voudrait créer un fichier avec cette +tête : + + <html> + <header> + <title>TITRE</title> + </header> + <body> + <main id="main" class="main"> + <h1>Titre 1</h1> + <p>Une liste cool</p> + <ul> + <li>elem 1</li> + <li>elem 2</li> + </ul> + <p><a href="katzele.net">lien 1</a></p> + <h2>titre 2</h2> + <p>du texte</p> + </div> + </body> + </html> + +La structure du template peut être spécifiée dans un heredoc. Un here-document (ou heredoc, here-doc) est une redirection particulière en shell. Sa syntaxe est : + + cmd <<delim + du texte + blabla + machin + delim + +ou encore + + <<delim cmd + du texte + blabla + machin + delim + +Le texte entre le premier délimiteur et le second sera donné à la commande +`cmd` dans son entrée standard `stdin`. Le heredoc utilisé plus haut disait +donc que tout le texte écrit entre la première ligne et le prochain `%` devait +être lu par la commande `lowdown`. Un template (ou layout) html sous la forme +d'un heredoc pourrait être : + + layout() { + <<@@ cat + <html><header><title>TITRE</title></header><body><main id="main" class="main">CONTENU</div></body></html> + @@ + } + +En l'état cette fonction shell ne fait que prendre le texte du template pour le +mettre dans la sortie standard `stdout` à l'aide de `cat`. Pour que `TITRE` et +`CONTENU` soit remplacés par les données que l'on veut on peut utiliser des +variables shell : + + TITRE="Page d'accueil" + CONTENU="# Page d'accueil du site + blabla + blabla" + +Il faudrait modifier le heredoc pour que `TITRE` et `CONTENU` deviennent des variables : + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$CONTENU</div></body></html> + @@ + } + +Si l'on fait ça le markdown dans `$CONTENU` ne sera pas transformé en html. +Il faudrait donner son contenu à `lowdown` en faisant par exemple : + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$(echo $CONTENU | lowdown)</div></body></html> + @@ + } + +La syntaxe `$(cmd) est une substitution de commande (ou command substitution ou +capture). Le shell va exécuter la commande entre parenthèses et remplacer la +substitution par sa sortie standard. Ici on utilise `echo` pour que le contenu +de `$CONTENU` se trouve en entrée de la commande `lowdown` qui renverra de +l'html. On aura donc entre les deux chevrons l'html du corps de la page. La commande donne : + + echo $CONTENU | lowdown + <h1>Page d'accueil du site</h1> + <p>blabla + blabla</p> + + +Donc à l'exécution de layout le shell déroulera les variables `$TITRE` et `$CONTENU` + + layout() { + <<@@ cat + <html><header><title>Page d'accueil</title></header><body><main id="main" class="main">$(echo "# Page d'accueil du site\nblabla\nblabla" | lowdown)</div></body></html> + @@ + } + +Puis déroulera la substitution de commande : + + layout() { + <<@@ cat + <html><header><title>Page d'accueil</title></header><body><main id="main" class="main"><h1>Page d'accueil du site</h1><p>blabla\nblabla</p></div></body></html> + @@ + } + +Et le heredoc s'exécutera : + + <html><header><title>Page d'accueil</title></header><body><main id="main" class="main"><h1>Page d'accueil du site</h1><p>blabla\nblabla</p></div></body></html> + +Au final notre document "markdown" ressemblera à ceci : + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$(echo $CONTENU | lowdown)</div></body></html> + @@ + } + + TITRE="Page d'accueil" + CONTENU="# Page d'accueil du site + blabla + blabla" + layout + +A l'exécution ce script génèrera l'html que l'on souhaite. C'est sur ce +principe, l'idée que les fichiers markdown sont en réalité des scripts +exécutables, que repose la commande construite pour le makefile. `src/index.md` +a lui seul produit l'html qui est ensuite pipé à `install` pour en faire +`root/index.html`. + +Maintenant que l'on sait comment construire et remplir un template html il est +temps de se simplifier quelque peu la tâche. Vous aurez peut-être remarqué +quelques faiblesses à ce système. + +La première est qu'il faudra réécrire la fonction layout et son appel dans +chaque fichier markdown. Si le site est destiné à accueillir de très nombreux +articles imaginez la galère que ce serait de vouloir le modifier partout en +même temps. Pour y remédier on peut chercher à faire un peu de factorisation en +déclarant la fonction layout dans un script séparé qui sera appelé en amont +lors de l'exécution des fichiers markdown. Appelons le layouthtml : + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$(echo $CONTENU | lowdown)</div></body></html> + @@ + } + + layout + +En l'état les variables `TITRE` et `CONTENU` ne contiennent rien. Si l'on +exécute layout tel quel on récupèrera le layout html sans titre et sans corps. +Il faut exécuter le script markdown entre temps. Pour cela on pourrait penser +qu'il suffit de l'exécuter avant l'appel à `layout` : + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$(echo $CONTENU | lowdown)</div></body></html> + @@ + } + + ./index.md + + layout + +Sauf que le résultat est le même. En effet un nouveau shell (un subshell) sera +ouvert pour interpréter les commandes se trouvant dans `index.md`. Ce subshell +ne partagera pas ses variables avec son processus père. Dans `layouthtml` +`$CONTENU` et `$TITRE` seront toujours vides. On peut contrôler ce qu'il se +passe visuellement dans `htop` : + + /bin/zsh + |_sh ./layouthtml + |_ /bin/sh ./index.md + +Il faudrait un moyen de faire comme si l'on copiait-collait les commandes +d'`index.md` dans `layouthtml`. Le shell a une commande spécifiquement prévue +pour cela, la commande `.` : + + . ./index.md + +Dans `htop` : + + /bin/zsh + |_sh ./layouthtml + +On voit qu'un seul processus est appelé, les commandes d'`index.md` sont +exécutées directement "dans" `layout.html`. Résultat, on a bien accès au +contenu des variables déclarées dans `index.md` et l'html est généré +correctement. + +Nous avons au final deux fichiers, l'un contenant l'échafaudage, l'autre le +contenu : + +layouthtml que génère l'html à l'exécution + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$(echo $CONTENU | lowdown)</div></body></html> + @@ + } + + . ./index.md + + layout + +et index.md dans lequel on écrit le contenu + + TITRE="Page d'accueil" + CONTENU="# Page d'accueil du site + blabla + blabla" + +Vous pourriez vous dire "On ne va pas tout de même modifier le chemin du +fichier md source à la main à chaque fois ?". Effectivement, on ne va pas. +D'autant plus qu'il sera préférable que le contenu de layouthtml ne change pas, +qu'il soit générique peut importe le fichier source. Pour cela on peut passer +le chemin du fichier source en argument à `layouthtml`. En le modifiant de la +sorte : + + . $1 + +On peut faire + + layouthtml ./chemin/vers/index.md + +`$1` est la variable contenant le premier argument passé à la commande. Ici +cette variable deviendra donc le chemin du fichier md. Cette technique nous +donne la possibilité d'appeler layouthtml sur tous les fichiers sources md. +Encore mieux, quitte à ce que les fichiers md soient en réalité des scripts, on +peut utiliser les shebang. Cette syntaxe que vous avez probablement déjà +rencontré permet d'indiquer par quel programme un fichier doit être interprété. +Elle prend la forme d'un dièse suivant d'un point d'exclamation suivi du chemin +vers un programme. Le plus classique est de voir + + #! /bin/sh + +au début de scripts shell. Si l'on met cela dans le fichier "exemple1" le +système passera le chemin du fichier en argument à ce qui suit le point +d'exclmation. Ici `/bin/sh exemple1`. Plutôt que de répétitivement exécuter +`page fichier.md` on peut donc ajouter `#! page` en première ligne de nos +fichiers markdown. Ainsi on pourra faire : + + ./index.md + +qui construira : + + page ./index.md + +qui exécutera bien la liste suivante de commandes : + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$(echo $CONTENU | lowdown)</div></body></html> + @@ + } + + . ./index.md + + layout + +Point d'étape, nous avons toujours deux fichiers avec le contenu suivant : + +page + + #! /bin/sh + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$(echo $CONTENU | lowdown)</div></body></html> + @@ + } + + . $1 + + layout + +index.md ou tout autre fichier md, en considérant que le script `page` se +trouve dans le dossier dans lequel on exécute le script. On peut toujours +changer le chemin. + + #! page + + TITRE="Page d'accueil" + CONTENU="# Page d'accueil du site + blabla + blabla" + +La deuxième faiblesse de ce système, toute relative, est la syntaxe des +fichiers markdown. Il est assez évident que ce ne sont pas des fichiers +markdown, il serait préférable de quelque peu le masquer. De plus, il faudrait +échapper tous les `"` pour éviter de mettre fin prématurément au contenu des +variables. Bref, pas très pratique.\ +Impossible d'échapper à la syntaxe de création de variables shell mais possible +de le masquer dans le script `page` à l'aide de variables. Admettons que l'on souhaite déclarer le titre d'un document avec un syntaxe type : + + %T Ceci est le titre de l'article + +On peut insérer un alias dans `page` : + + alias %T="title" + title() TITRE="$*" + +Un alias permet de donner un autre nom à une commande. Par exemple si je donne +la valeur `ls -la` à l'alias nommé `l` alors la commande : + + l truc + +sera remplacée par + + ls -la truc + +Dans notre cas `%T` sera remplacé par `title` qui se trouve être une fonction +que l'on défini juste en dessous qui donne une valeur à la variable `TITRE`. +`$*` est une variable sépciale qui, lorsqu'elle est entre double quote `"` est +remplacée par tous les arguments passés à la commande séparés par un espace et +rassemblés en une seule chaîne de caractère. La commande + + title Ceci est un titre blablabla + +sera donc équivalente à faire + + TITRE="Ceci est un titre blablabla" + +L'ajout de cet alias dans `page` permet donc d'écrire `index.md` comme ceci : + + %T Page d\'accueil + CONTENU="# Page d'accueil du site + blabla + blabla" + +En veillant à échapper le `'`. Echapper un caractère permet à l'interpréteur de +commande de ne pas considérer un caractère pour sa signification spéciale mais +pour sa valeur intrinsèque.\ +C'est un peu plus joli. Appliquer le même principe pour le contenu sera un peu +plus difficile. Le contenu se trouvant sur plusieurs lignes il faudra avoir +recours à un heredoc. L'alias sera : + + alias %S="<<% layout" + +Et le contenu d'`index.md` : + + %T Page d\'accueil + %S + + # Page d'accueil du site + blabla + blabla + + % + +La fonction layout doit également changer puisqu'il n'y a plus de variable +`CONTENU`. On peut la remplacer par un appel direct à la commande `lowdown` qui +prendra l'entrée de layout, c'est à dire le markdown dans le heredoc. On retire +également l'appel à layout à la fin du fichier puisque c'est `index.md` qui le +fait avec `%S`. + + layout() { + <<@@ cat + <html><header><title>$TITRE</title></header><body><main id="main" class="main">$(lowdown)</div></body></html> + @@ + } + +Nous avons enfin un fichier "markdown" très proche de ce à quoi ressemblerait +le fichier s'il ne contenait vraiment que du markdown. Maintenant imaginons que +l'on veut écrire un article avec des commandes dedans. On pourrait retrouver +dans le heredoc `%S` des choses comme : + + dc -e "2k $(wc -l < README) 50 / p" + +Cette commande calcul environ combien de pages A4 `README` remplirait. Si +l'on exécute `index.md` on obtient : + + <html><header><title>Page d'accueil</title></header><body><main id="main" class="main"><h2>Page d'accueil du site</h2> + <p>blabla + blabla</p> + <p>dc -e &quot;2k 13 50 / p&quot;</p></div></body></html> + +Vous remarquerez que la commande `wc -l < README` a été substituée. Par +défaut les heredocs déroulent (en anglais expand) les variables, les +substitutions de commandes etc. C'est évidemment très dangereux. Si le contenu +du l'article contient `$(rm -rf)` vous pourriez perdre des fichiers. La +solution est d'échapper le délimiteur. Ainsi le heredoc prendra tout au sens +littéral sans chercher à dérouler quoi que ce soit. L'alias sécurisé devrait +donc être : + + alias %S="<<\% layout" + +A ce stade si vous avez bien compris le fonctionnement vous pouvez apporter des +modifications simples et rapides au layout et aux données à y faire rentrer. +Par exemple nous pourrions vouloir ajouter le nom de l'auteur de l'article. +L'alias dans page : + + alias %A="author" + author() AUTHOR="$*" + +Dans le layout : + + layout() { + <<@@ cat + <html><header><meta name="author" content="$AUTHOR"<title>$TITRE</title></header><body><main id="main" class="main">$(lowdown)</div></body></html> + @@ + } + +et dans l'article + + %T Page d\'accueil + %A Jean Dupont + %S + + # Page d'accueil du site + blabla + blabla + + % + +Aussi simple que cela. + +On sait que si l'on oublie un champ la variable dans le layout sera simplement +remplacée par rien du tout. Comment lui donner une valeur par défaut ou lever +une alerte s'il manque ? Le shell à la rescousse. Prenons la variable `TITRE`. +Jusqu'à maintenant nous avons utilisé les variables sous des formes `${TITRE}` +ou `$TITRE`. Avec cette syntaxe le tout sera substitué par la valeur de la +variable si elle existe mais il en existe d'autre : + + * `${TITRE:-Titre par défaut}` - si `TITRE` n'existe pas ou est vide alors le + tout sera substitué par "Titre par défaut". + * `${TITRE:?Attention il manque un titre à l'article}` - si `TITRE` + n'existe pas ou est vide alors le script affiche le message d'erreur + et se termine + +Pour en connaître d'autres voir le chapitre "Parameter Expansion" du +manuel de sh. + +Nous pourrions donc modifier le layout comme ceci : + + layout() { + <<@@ cat + <html><header><meta name="author" content="${AUTHOR:-Jean Dupont}"><title>${TITRE:?Titre obligatoire (%T)}</title></header><body><main id="main" class="main">$(lowdown)</div></body></html> + @@ + } + +Pour que Jean Dupont soit l'auteur des articles par défaut à moins qu'il +soit précisé autrement, et qu'un article ne puisse être publié sans +titre. + +Point d'étape, nous avons + +page avec un peu de mise en forme pour le layout + + #! /bin/sh + + layout() { + <<@@ cat + <html> + <head> + <meta name="author" content="${AUTHOR:-Jean Dupont}"> + <title>${TITRE:?Titre obligatoire (%T)}</title> + </head> + <body> + <main id="main" class="main"> + $(lowdown) + </div> + </body> + </html> + @@ + } + + alias %T="title" + title() title="$*" + + alias %A="author" + author() author="$*" + + alias %S="<<\% layout" + + . $1 + +index.md ou tout autre fichier md, en considérant que le script `page` se +trouve dans le dossier dans lequel on exécute le script. On peut toujours +changer le chemin. + + #! page + + %T Page d\'accueil + %A Jean Dupont + %S + + # Page d'accueil du site + blabla + blabla + + % + +Il serait bon de vouloir sortir le layout dans un autre fichier. Pour cela nous pouvons +mettre la fonction ailleurs, disons un fichier `html` et l'appeler dans `page` à la +manière dont nous appelons `index.md`. + +html + + layout() { + <<@@ cat + <html> + <head> + <meta name="author" content="${AUTHOR:-Jean Dupont}"> + <title>${TITRE:?Titre obligatoire (%T)}</title> + </head> + <body> + <main id="main" class="main"> + $(lowdown) + </div> + </body> + </html> + @@ + } + +page + + #! /bin/sh + + alias %T="title" + title() title="$*" + + alias %A="author" + author() author="$*" + + alias %S="<<\% layout" + + . html + . $1 + +L'une des limitations de notre système qui vaut probablement la peine d'être +levée est celle de ne pouvoir insérer de l'html généré qu'à un seul endroit +prédéfini dans notre template. Cela peut tout à fait convenir à des sites très +simples mais être handicapant si l'on souhaite créer des structures plus +complexes et changeantes. + +TODO trouver un meilleur exemple ? + +Par exemple, admettons que notre site comporte une section "aside" dans +laquelle se trouve une courte description un peu meta de la page consultée. +Il faut donc un moyen pour la personne écrivant le contenu de dire que cela +va dans telle section du template et ceci dans telle autre section. Côté +utilisateurice une syntaxe sympa pourrait être de donner la section cible +après l'alias %S. Par exemple + + %S main + # Titre 1 + blabla + % + +irait dans la section main, le corps de l'article. + + %S aside + Cet article parle de ceci cela + % + +irait dans le section aside. Pour accomplir cela nous pouvons générer les +différentes parties html, les stocker dans des fichiers temporaires et +rappeler leurs contenus au bon endroit dans la fonction layout. Pour +créer un dossier temporaire nous pouvons utiliser la commande `mktemp` +avec l'option `-d` + + tempfolder=$(mktemp -d) + +Cette commande renvoie le chemin absolu du dossier temporaire créé, que +l'on stocke dans la variable tempfolder. Dans ce dossier temporaire nous +allons créer des fichiers ayant pour contenu l'HTML généré par lowdown pour +les différentes sections. Pour l'instant le markdown est directement donné +à la fonction layout qui interprète tout dans la section main de son +template. Pour éviter ce comportement il faut que l'alias %S appelle +une autre fonction qui elle créera les différents fichiers. Appelons cette +fonction `save_md` et modifions %S + + save_md() lowdown >> "$tempfolder/$1" + alias %S="<<\% save_md" + +L'alias %S appelle dorénavant la fonction `save_md` en lui passant en argument +le nom d'une section donnée (dans les exemples précédemment "main" et "aside") +qui se retrouveront dans la variable $1. Elle prendra dans stdin le markdown +écrit dans le heredoc, ce comportement n'a pas changé. Ainsi écrire + + %S main + # Titre 1 + blabla + % + +reviendra à exécuter + + <<% save_md main + # Titre 1 + blabla + % + +ou encore + + echo "# Titre 1\nblabla" | save_md main + +ce qui revient à + + echo "# Titre 1\nblabla" | lowdown >> "$tempfolder/main" + +ainsi il existera dans un fichier dont le chemin serait quelque chose +ressemblant à "tmp/tmp.xTpN5urieE/main" le contenu de l'HTML destiné à +la section main. Dans notre fichier `index.md` si l'on n'oublie pas de +bien fermer le heredoc pour la section main on peut enchainer les deux +sections + + %S main + # Titre 1 + blabla + % + + %S aside + Cet article parle de ceci cela + % + +Il ne reste plus qu'à adapter la fonction layout pour insérer l'html aux bon +endroits. Pour cela créons dans page une courte fonction qui permet de se +déplacer dans le dossier correspondant et d'afficher l'HTML d'une section +donnée + + display () { + cd $the; cat "$@" + } + +TODO demander à Marc pourquoi faire un cd ici et pas cat directement le chemin total + +L'utilisation du point virgule permet ici d'écrire deux instructions sur une +même ligne. Cela a pour seul but de raccourcir le fichier, notamment quand les +instruction en question sont courtes et très intelligibles. Cela est +strictement équivalent à + + display () { + cd $the + cat "$@" + } + +Utilisons là dans le layout + + layout() { + <<@@ cat + <html> + <head> + <meta name="author" content="${AUTHOR:-Jean Dupont}" + <title>${TITRE:?Titre obligatoire (%T)}</title> + </head> + <body> + <aside id="aside" class="aside"> + $(display aside) + </aside> + <main id="main" class="main"> + $(display main) + </main> + </body> + </html> + @@ + } + +Il faut s'assurer que la fonction layout soit bien appelée, maintenant qu'elle +ne l'est plus par l'alias %S. Il faut également s'assurer que le dossier +temporaire soit bien supprimé quand nous n'en avons plus besoin. `page` +ressemble dorénavant à + + #! /bin/sh + + tempfolder=$(mktemp -d) ; trap "rm -rf $tempfolder" EXIT + + alias %T="title" + title() title="$*" + + alias %A="author" + author() author="$*" + + save_md() lowdown >> "$tempfolder/$1" + alias %S="<<\% save_md" + + display () { + cd $the; cat "$@" + } + + . html + . $1 + layout + +La commande trap permet de demande l'exécution de `rm -rf $tempfolder` quand +le processus actif recevra le signal EXIT, autrement dit quand il se terminera. + +Voilà en l'état, avec ce triptyque nous avons les bases nécessaires pour écrire +des pages HTML depuis du markdown, agrémentées de métadonnées, suivant un +template modulaire. + +Petit bonus, le fait que les fichiers markdown soient des scripts shell permet +non seulement d'implémenter notre système de métadonnée et de templating mais +également d'avoir recours aux outils unix pour générer le contenu lui même. + +Exemple. Prenons un site avec une arborescence type + + . + ├── articles + │   ├── musique + │   │   └── index.md + │   └── youtube + │   └── index.md + ├── index.md + └── notes + ├── chatgpt + │   └── index.md + └── laconvivialite + └── index.md + +Dont les pages ont les métadonnées que l'on a vu précédemment, déclarées avec +%T et %A. Nous voudrions avoir la liste exhaustive de tous les articles du site. +Nous commençons à rédiger notre page, très sommaire (je mets un petit commentaire +pour l'exemple) : + + #! page + + %T Plan du site + %A Jean Dupont + + %S main + # Archives du site de Jean Dupont + + ## Articles + + Ci dessous tous les articles du site. Il n'y a pas encore grand chose mais ça arrive ! + % + +en fermant le heredoc je peux recommencer à y mettre du shell. Nous allons +chercher les fichiers markdown et les lister : + + find . -type f -name "*.md" + ./articles/youtube/index.md + ./articles/musique/index.md + +dont on va chercher les métadonnées + + + find . -type f -name "*.md" | xargs grep -EHm2 "%T|%A" + ./articles/youtube/index.md:%T Guide de survie en territoire youtubesque + ./articles/youtube/index.md:%A Jean Dupont + ./articles/musique/index.md:%T Gestion simpliste de playlist et migration depuis Spotify + ./articles/musique/index.md:%A Jean Dupont + +pour en faire une ligne par article + + find ./articles -type f -name "*.md" | xargs grep -EHm2 "%T|%A" | paste - - + ./articles/youtube/index.md:%T Guide de survie en territoire youtubesque /tmp/tmp.xTpN5urieE/articles/youtube/index.md:%A Jean Dupont + ./articles/musique/index.md:%T Gestion simpliste de playlist et migration depuis Spotify /tmp/tmp.xTpN5urieE/articles/musique/index.md:%A Jean Dupont + +et remanier les infos de façon à en faire du markdown + + find . -type f -name "*.md" | xargs grep -EHm2 "%T|%A" | paste - - | sed -Ee 's,(.*).md:%T (.*) .*%A (.*).*,* [\2](\1.html) - \3,' + * [Guide de survie en territoire youtubesque](./articles/youtube/index.html) - Jean Dupont + * [Gestion simpliste de playlist et migration depuis Spotify](./articles/musique/index.html) - Jean Dupont + +On ne peut pas le laisser vivre tout seul comme ça sinon à l'exécution le résultat ne +se retrouvera dans aucune section et n'apparaîtra pas. Il faut donc terminer parce un appel +à `save_md` + + find ./articles -type f -name "*.md" | xargs grep -EHm2 "%T|%A" | paste - - | sed -Ee 's,(.*).md:%T (.*) .*%A (.*).*,* [\2](\1.html) - \3,' | save_md main + +On peut ensuite appeler à nouveau l'alias %S pour reprendre la rédaction de l'article : + + %S main + + ## Notes + + Et les notes : + % + + find ./notes -type f -name "*.md" | xargs grep -EHm2 "%T|%A" | paste - - | sed -Ee 's,(.*).md:%T (.*) .*%A (.*).*,* [\2](\1.html) - \3,' | save_md main + +Cela fonctionne puisque l'on utilise l'opérateur de concaténation dans la fonction `save_md`. +On *ajoutera* toujours au fichier d'une section, sans le réécrire. + +Au final notre article source ressemble à + + #! page + + %T Plan du site + %A Jean Dupont + + %S main + # Archives du site de Jean Dupont + + ## Articles + + Ci dessous tous les articles du site. Il n'y a pas encore grand chose mais ça arrive ! + % + + find ./articles -type f -name "*.md" | xargs grep -EHm2 "%T|%A" | paste - - | sed -Ee 's,(.*).md:%T (.*) .*%A (.*).*,* [\2](\1.html) - \3,' | save_md main + %S main + + ## Notes + + Et les notes : + % + + find ./notes -type f -name "*.md" | xargs grep -EHm2 "%T|%A" | paste - - | sed -Ee 's,(.*).md:%T (.*) .*%A (.*).*,* [\2](\1.html) - \3,' | save_md main + +Ce qui reviendrait à écrire à la main + + #! page + + %T Plan du site + %A Jean Dupont + + %S main + # Archives du site de Jean Dupont + + ## Articles + + Ci dessous tous les articles du site. Il n'y a pas encore grand chose mais ça arrive ! + + * [Guide de survie en territoire youtubesque](./articles/youtube/index.html) - Jean Dupont + * [Gestion simpliste de playlist et migration depuis Spotify](./articles/musique/index.html) - Jean Dupont + + ## Notes + + Et les notes : + + * [Dialogue avec ChatGPT](./notes/chatgpt/index.html) - ChatGPT, Jean Dupont + * [Notes sur "La Convivialité" d'Ivan Illich](./notes/laconvivialite/index.html) - Jean Dupont + % + +En combinant markdown et instructions exécutables nous pouvons donc adapter le +contenu de nos pages en fonction de conditions extérieures, comme ici la +présence ou non d'un certain nombre d'articles. A noter, nous pouvons utiliser +ce que nous voulons comme langage. Il est naturel d'écrire du shell puisque +c'est comme cela que le fichier est interprété mais si vous êtes plus à l'aise +avec un autre langage il est tout à fait possible de l'utiliser. Par exemple +nous pourrions générer du markdown similaire en écrivant : + + python3 -c " + insérer du python ici + blabla + " | save_md main + +Pour avoir un aperçu complet de ce qu'il se passe déroulons tout le code à +partir de l'exécution du script index.md :\ +(j'ai un gros doute sur la façon de présenter ce truc, je sais pas ce que +je fais, qu'est-ce qu'il faut que je déroule ou pas etc) + +Pour l'index.md suivant + + #! page + %T Titre de la page + %A Jean Dupont + %S main + # Titre 1 + blabla + + * el1 + * el2 + % + + uptime | save_md main + + %S aside + ici le contenu de l'aside + % + +`./index.md` tombera sur `#! page` qui appelera `./page index.md` et +le code suivant sera exécuté : +TODO : rendre cela lisible en texte pur *et* en HTML ? + +Tel quel Avec les appels `. fichier` et la fonction layout dépliés Avec les variables, alias dépliés et appels à display dépliés + +tempfolder=$(mktemp -d) tempfolder=$(mktemp -d) tempfolder=$(mktemp -d) +trap "rm -rf $tempfolder" EXIT trap "rm -rf $tempfolder" EXIT trap "rm -rf /tmp/tmp.azerty" EXIT + +alias %T="title" alias %T="title" alias %T="title" +title() title="$*" title() title="$*" title() title="$*" + +alias %A="author" alias %A="author" alias %A="author" +author() author="$*" author() author="$*" author() author="$*" + +save_md() lowdown >> "$tempfolder/$1" save_md() lowdown >> "$tempfolder/$1" save_md() lowdown >> "/tmp/tmp.azerty/$1" +alias %S="<<\% save_md" alias %S="<<\% save_md" alias %S="<<\% save_md" + +display () { display () { display () { + cd $tempfolder cd $tempfolder cd $tempfolder + cat "$@" cat "$@" cat "$@" +} } } + +. html layout() {...} layout() {...} + +. $1 %T Titre de la page title="Titre de la page" + %A Jean Dupont author="Jean Dupont" + + %S main <<\% lowdown >> "/tmp/tmp.azerty/main" + # Titre 1 # Titre 1 + blabla blabla + + * el1 * el1 + * el2 * el2 + % % + + uptime | save_md main uptime | lowdown >> "/tmp/tmp.azerty/main" + + %S aside <</% lowdown >> "/tmp/tmp.azerty/aside" + ici le contenu de l'aside ici le contenu de l'aside + % % + +layout <<@@ cat <<@@ cat + <html> <html> + <head> <head> + <meta name="author" content="${author:-Jean Dupont}"> <meta name="author" content="Jean Dupont"> + <title>${title?Titre obligatoire (%T)}</title> <title>Titre de la page</title> + </head> </head> + <body> <body> + <aside id="aside" class="aside"> <aside id="aside" class="aside"> + $(display aside) cd /tmp/tmp.azerty + cat aside + </aside> </aside> + <main id="main" class="main"> <main id="main" class="main"> + $(display main) cd /tmp/tmp.azerty + cat main + </main> </main> + </body> </body> + </html> </html> + @@ @@ + +rm -rf $tempfolder rm -rf /tmp/tmp.azerty rm -rf /tmp/tmp.azerty + +J'ai généré le tableau précédent avec le format de donnée suivant et la commande +`column -ets';'`. + + Tel quel;Avec les appels `. fichier` et la fonction layout dépliés;Avec les variables, alias dépliés et appels à display dépliés + tempfolder=$(mktemp -d);tempfolder=$(mktemp -d);tempfolder=$(mktemp -d) + trap "rm -rf $tempfolder" EXIT;trap "rm -rf $tempfolder" EXIT;trap "rm -rf /tmp/tmp.azerty" EXIT + + alias %T="title";alias %T="title";alias %T="title" + title() title="$*";title() title="$*";title() title="$*" + + alias %A="author";alias %A="author";alias %A="author" + author() author="$*";author() author="$*";author() author="$*" + + save_md() lowdown >> "$tempfolder/$1";save_md() lowdown >> "$tempfolder/$1";save_md() lowdown >> "/tmp/tmp.azerty/$1" + alias %S="<<\% save_md";alias %S="<<\% save_md";alias %S="<<\% save_md" + + display () {;display () {;display () { + cd $tempfolder; cd $tempfolder; cd $tempfolder + cat "$@"; cat "$@"; cat "$@" + };};} + + . html;layout() {...};layout() {...} + + . $1;%T Titre de la page;title="Titre de la page" + ;%A Jean Dupont;author="Jean Dupont" + ; + ;%S main;<<\% lowdown >> "/tmp/tmp.azerty/main" + ;# Titre 1;# Titre 1 + ;blabla;blabla + ; + ;* el1;* el1 + ;* el2;* el2 + ;%;% + ; + ;uptime | save_md main;uptime | lowdown >> "/tmp/tmp.azerty/main" + ; + ;%S aside;<</% lowdown >> "/tmp/tmp.azerty/aside" + ;ici le contenu de l'aside;ici le contenu de l'aside + ;%;% + + layout;<<@@ cat;<<@@ cat + + ;<html>;<html> + ; <head>; <head> + ; <meta name="author" content="${author:-Jean Dupont}">; <meta name="author" content="Jean Dupont"> + ; <title>${title?Titre obligatoire (%T)}</title>; <title>Titre de la page</title> + ; </head>; </head> + ; <body>; <body> + ; <aside id="aside" class="aside">; <aside id="aside" class="aside"> + ; $(display aside); cd /tmp/tmp.azerty + ;; cat aside + ; </aside>; </aside> + ; <main id="main" class="main">; <main id="main" class="main"> + ; $(display main); cd /tmp/tmp.azerty + ;; cat main + ; </main>; </main> + ; </body>; </body> + ;</html>;</html> + ;@@;@@ + rm -rf $tempfolder;rm -rf /tmp/tmp.azerty;rm -rf /tmp/tmp.azerty + +TODO Atomic ? diff --git a/USAGE b/USAGE @@ -0,0 +1,469 @@ +# Comment utiliser Francium + +Ce document existe pour apprendre à utiliser Francium sans pour autant lire +toute la documentation se trouvant aujourd'hui dans le README qui explique +également comment et pourquoi Francium fonctionne de la sorte. + +A noter, Francium est conçu pour être modifiable et même inciter à l'être. +Ainsi ce document documente comment utiliser Francium tel qu'il est pour le +site de Katzele au début de l'année 2023. Il se peut donc que l'utilisation de +Francium soit très différente pour un autre projet ou à l'avenir. Des cas de +modifications relativement simples seront couverts à la fin de ce document mais +ils ne sauraient se substituer à la lecture du README. + +Il ne faut pas s'attendre à pouvoir modifier Francium facilement sans aucune +compétence en make/markdown/shell/html. L'idée est de faire de Francium un +logiciel favorisant l'apprentissage des ces technologies dont on estime quelles +constituent un socle de compétences de bases en informatique. On pourrait +évidemment débattre de ce que l'on inclu dans ce socle ou pas. + +## Dépendances + +En l'état Francium nécessite + + * un logiciel md -> html (par défaut `lowdown` mais pourrait être `pandoc` ou + `cmark` par exemple) + * un interpréteur shell POSIX + * perl si l'on utilise pug + +## Générer le site + +Francium génère le site via la commande `make`. Les règles de génération sont +écrites dans le fichier `makefile`. Pour lancer la génération faire + + make + +Il est possible d'accélérer le processus en parallélisant +Pour purger les fichiers produits faire + + make clean + +Il n'est pas toujours nécessaire de faire un `clean` avant de faire un `make`, +les fichiers seront réécrits. La génération du site va transposer les fichiers +et l'arborescence source - dans `./src` - vers la destination - le dossier +`./root`. Ainsi avec l'arborescence + + ./src + ├── archives + │   └── index.md + ├── articles + │   └── youtube + │   ├── arguments-to-plumber.patch + │   ├── display_author.patch + │   └── index.md + ├── index.md + └── notes + └── laconvivialite + └── index.md + +`make` génère l'arborescence + + ./root + ├── archives + │   ├── index.html + │   └── index.md + ├── articles + │   └── youtube + │   ├── arguments-to-plumber.patch + │   ├── display_author.patch + │   ├── index.html + │   └── index.md + ├── events.atom + ├── index.html + ├── index.md + ├── notes + │   └── laconvivialite + │   ├── index.html + │   └── index.md + └── style.css + +Pour chaque fichier présent dans `./src` le `makefile` a une règle expliquant à +`make` ce qu'il faut faire. Sans rentrer dans les détails, les fichiers `.md` +sont transformés en `.html` et copiés dans une arbo identique recrée sous +`./root`. + +## Créer le contenu + +L'exemple précédant se base sur le contenu du site Katzele mais vous voulez +évidemment faire le votre. Imaginons partir de zéro. + +### Template HTML + +Il nous faut au moins un template HTML qui structurera nos pages. Ce sera +l'échaffaudage pour nos pages. Ce template devra se trouver dans le dossier +`./lib/html`. + +Il existe un outil nommé pug qui permet de générer des templates. Je ne sais +pas encore l'utiliser donc je vais pour le moment documenter le fait d'écrire +des templates à la main. + +Prenons celui utilisé par le site Katzele qui a le mérite d'être basique + +layout() <<@@ cat + <!DOCTYPE html> + <html lang="fr"> + <head> + <meta charset="utf-8"> + <title>${title?La page dont le chemin s'affiche au dessus nécessite un titre}</title> + <meta name="viewport" content="width=device-width,initial-scale=1.0"> + ${STYLE:+<link rel=\"stylesheet\" href=\"$STYLE\"/>} + <meta name="description" content="$description"> + </head> + <body> + <main id="main" class="main"> + $(the main) + </main> + </body> + </html> +@@ + +Les lignes `layout() <<@@ cat` et à la fin `@@` déclarent une fonction shell qui +contient un heredoc. Si vous voulez en savoir plus lisez le README. Vous pouvez +faire abstraction sinon.\ +Le contenu qui se trouve entre ces deux lignes est un mélange d'HTML pur, de +variables shell et d'expansion de variables shell. Je ne vais pas les +expliciter ici. Ici ce template convient pour générer des pages très simples, +sans header ni footer, simplement le corps de la page que l'on écrit en +markdown. Si cela vous convient vous pouvez ne pas y toucher. Par défaut la +feuille de style qui sera utilisée est `./rc/style.css`. Elle contient le thème +de Katzele, vous pouvez la modifier à votre guise. + +Pour d'éventuelles modifications du template ce qu'il faut à minima retenir est +que vous pouvez ici ajouter de l'HTML comme bon vous semble et avoir recours à +la commande `the nom_de_section` pour ajouter des sections que vous +renseignerez en markdown dans vos fichiers sources. Si vous voulez des exemples +de modification voir plus loin dans ce document. + +### Fichier source markdown + +Les fichiers sources des pages doivent comporter l'extension `.md` et être +exécutables. Ils doivent commencer par la ligne + + #! page + +pour être préprocessé par le script `page`. Ils doivent ensuite contenir un +ensemble de métadonnée. En l'état Francium propose + + * `%T "titre de la page"` pour renseigner le contenu de la balise `<title>`, + savoir ce qui s'affiche dans le titre de l'onglet de votre navigateur + * `%A "nom de l'auteurice"` pour suivre qui a rédigé la page. Avec le + template présenté auparavant cette donnée ne se retrouvera nul par dans + l'HTML. Nous verrons un exemple de modification plus tard pour l'intégrer. + * `%P "date de publication de la page"` pour suivre la date de publication. + Elle peut ensuite être réutilisée dans la génération du site. Voir le + README pour un exemple. + * `%D "description du contenu"` pour alimenter la balise meta `description`, + à savoir ce qui s'affichera comme contenu dans le résultat des moteurs de + recherche par exemple. + +On renseigne ces métadonnées en appelant, dans le fichier md, les différentes "variables". +Par exemple pour une page d'accueil + + %T "Page d'accueil de mon site" + %A moi + %P 2023-06-21 + %D "Site de machin chose, bidule à chouette à truc muche" + +Il faut ensuite écrire le contenu markdown. Pour cela faire appel à +l'instruction `%S` marquant le début du markdown. Il faut mettre à la suite de +cette instruction la section du template dans laquelle on veut que le contenu +qui suive aille. Dans notre exemple de template il n'y a qu'une section +(marquée par la commande `$(the main)`) qui remplira bêtement la balise `main`, +unique balise du body. C'est le mot clef suivant `the` et non pas le nom de la +balise HTML qu'il faut retenir et faire correspondre avec ce que l'on va écrire +dans le fichier markdown. Il est naturel que la balise et le nom de la section +soient identiques mais cela n'est pas nécessaire. Pour y mettre du contenu nous +pouvons donc écrire : + + %S main + # Le site de machin chose + Salut ! + + ## Ma vie mon oeuvre + + J'ai travaillé ici, là-bas et accompli cela + + * premier truc + * second truc + % + +Il faut fermer l'instruction `%S` avec un autre `%`. Au final notre document +ressemble à : + + #! page + %T "Page d'accueil de mon site" + %A moi + %P 2023-06-21 + %D "Site de machin chose, bidule à chouette à truc muche" + %S main + # Le site de machin chose + Salut ! + + ## Ma vie mon œuvre + + J'ai travaillé ici, là-bas et accompli cela + + * premier truc + * second truc + % + +Si ce fichier se nomme `index.md` et se trouve à la racine du dossier `./src` +alors exécuter `make` génèrera ce `index.html` dans `./root` : + + <!DOCTYPE html> + <html lang="fr"> + <head> + <meta charset="utf-8"> + <title>Page d'accueil de mon site</title> + <meta name="viewport" content= + "width=device-width,initial-scale=1.0"> + <link rel="stylesheet" href="/style.css"> + <meta name="description" content= + "Site de machin chose, bidule à chouette à truc muche"> + </head> + <body> + <main id="main" class="main"> + <h1>Le site de machin chose</h1> + <p>Salut !</p> + <h2>Ma vie mon oeuvre</h2> + <p>J'ai travaillé ici, là-bas et accompli cela</p> + <ul> + <li>premier truc</li> + <li>second truc</li> + </ul> + </main> + </body> + </html> + +Dernière astuce, en dehors des blocs `%S nom_de_section ... %` vous pouvez +exécuter du shell. Ainsi il est possible, avec votre langage préféré, de +générer du markdown. Cela peut être pratique quand l'on veut générer quelque +chose en fonction d'un contenu qui change souvent et dont on ne connaît pas, à +priori, la teneur. Par exemple un plan de site. Pour ce faire écrivez le code +que vous souhaitez et pipez le dans la commande `save_md` suivi du nom de la +section dans laquelle vous voulez que le contenu apparaisse. Ainsi, en reprenant +la fin du document : + + J'ai travaillé ici, là-bas et accompli cela + + * premier truc + * second truc + % + + echo "[Un autre site cool](lien_vers_site_cool)" | save_md main + +Ajoutera un lien dans la section main + + <li>premier truc</li> + <li>second truc</li> + </ul> + <p><a href="lien_vers_site_cool">Un autre site cool</a></p> + </main> + </body> + </html> + +Cela peut être pratique pour générer tout ou partie d'un plan de site. +Pour un exemple plus utile lisez le README. + +Voilà, à partir de là si vous savez écrire du markdown et que vous n'avez pas +besoin d'autre chose que des pages simplistes comme celles générées avec le +template fourni vous avez les cartes en main pour créer votre site avec +Francium. Cela dit l'esprit de l'outil est qu'il est de nature "hackable" avec +des compétences que l'on juge, dans le collectif, comme étant de bonnes +candidates pour être des compétences "socles" dans l'informatique (si c'est le +cas ou pas n'est pas le sujet de ce document). + +Deux titres en dessous nous voyons quelques cas de modifications qui pourraient +vous intéresser ou vous mettre sur la bonne piste. + +## Générer des flux atom + +### Pour des évènements + +Le script se trouvant à `./bin/atomic` permet de générer un flux atom sur la +base d'un fichier descriptif d'évènements. C'est un besoin assez particulier que +provient de l'activité du collectif Katzele. Si vous n'êtes pas intéressé·e par +cette fonctionnalité vous pouvez sauter ce titre. + +Aujourd'hui au lancement de `make` Francium lit le fichier `./src/events/2022` +pour générer le flux `./root/events.atom`. Le nom du fichier (2022) est +arbitraire pour des raisons historiques mais devrait être modifié.\ +TODO bah le faire... +Le fichier `2022` doit commencer avec `#! ./bin/atomic`. Il faut ensuite +déclarer le nom du flux et son url avec les métadonnées + + * %T - titre + * %H - url du flux + +Puis appeler l'instruction `entries` qui marque le début des éléments du flux. + +La déclaration des évènements est assez similaire à l'écriture d'un article +(la technique derrière est la même). Les métadonnées disponibles (rappelées au +début du fichier) sont : + + * %T - title ou titre de l'évènement + * %P - published the ou publié le + * %L - location ou lieu de l'évènement + * %A - author ou auteurice de l'évènement, qui du collectif ou associé y a + participé ? + * %D - date de l'évènement au format ISO 8601 + * %U - date de fin l'évènement au format ISO 8601 + * %R - ressources type slides, captation vidéo/audio, pdf etc + * %S - contenu pour le flux rss, courte description de l'évènement + +L'ordre d'apparition des champs est important, il doit être TPLADURS. Comme +pour une page, il faut fermer un bloc `%S` avec `%`. Il est nécessaire d'échapper +les caractères spéciaux type `"` `|` `'` etc ou les encapsuler dans des cotes. +Les métadonnées de lieu, de ressources et le contenu peuvent être du markdown.\ +Pour les évènements de Katzele tout cela donne l'exemple suivant : + + %T Les interventions du collectif Katzele + %H http://people.netlib.re/events.atom + + entries + + %T Consommation alternative et sobre de youtube.com, le retour + %P 2022-10-26T11:39:38+01:00 + %L Lab Numérique, Atrium, Campus de l\'Esplanade, Strasbourg + %A Arthur Pons + %D 2022-12-14T17:30+01:00 + %U 2022-12-14T19:30+01:00 + %R "[Article](http://people.netlib.re/notes/221019/interfaces_alternatives_youtube/index.html) - [Agenda](https://services-numeriques.unistra.fr/agenda/evenement/article/atelier-consommation-alternative-et-sobre-de-youtube-lab-numerique-1.html)" + %S + Vous en avez marre de rater les dernières sorties de vos youtubeurs et ... + % + +### Pour le contenu du site + +Bientôt (Katzele time) +TODO intégrer cette fonctionnalité qui a été perdue lors de la spécialisation d'atomic pour les events +A priori y'aura rien à faire à part `make` ? + +## Modifier Francium + +Admettons que vous vouliez apporter les modifications suivantes à l'existant : + + * Gestion d'une métadonnée "langue" car le site est bilingue + * Ajouter une section au template + +### Ajouter une métadonnée + +Vous l'avez peut-être remarqué, il existe une balise `<html lang="fr">` dans +notre template. Cette balise sert à déclarer la langue du contenu qui suit. +Cela permet entre autre aux lecteurs d'écrans de lire correctement le contenu +de la page. Si vous tenez un site bilingue vous pourriez vouloir spécifier la +langue article par article et non pas de façon figée dans le template. + +Pour cela ajoutons une métadonnée qui nous utiliserons au début des articles. +Pour ajouter une métadonnée il nous faut modifier le fichier `page` qui +contient le code pour les rendre opérantes. Dans ce fichier, ajouter une +métadonnée revient à déclarer un nouvel alias et une fonction correspondante. +En ce basant sur ce qui existe pour `%T` : + + alias %L="lang" + lang() lang="$*" + +Dorénavant quand on écrira `%L fr" dans un fichier, la variable `lang` prendra +pour valeur "fr". Il suffit ensuite de l'appeler au bon endroit dans le template + + layout() <<@@ cat + <!DOCTYPE html> + <html lang="$lang"> + <head> + +Hop, nous pouvons dorénavant déclarer la langue d'un article. Nous pourrions +mettre un petit filet pour nous assurer de ne pas oublier d'un déclarer un : + + <html lang="${lang?Langue de l'article non déclarée}"> + +Si la variable est vide (parce que nous aurions oublié de renseigner `%L` dans +un article) alors la génération du site va se terminer et le message d'erreur +sera affiché. Alternativement il est possible de choisir une valeur par +défaut. Pour plus d'info lire le README ou consulter le manuel de `sh`. + +### Ajouter une section au template + +Admettons que nous souhaitons ajouter un footer et un aside donc nous voulons +maitriser le contenu. Rien de plus simple, il suffit de créer les balises +qui vont bien et d'appeler la commande `the` avec les noms des sections. + + layout() <<@@ cat + <!DOCTYPE html> + <html lang="fr"> + <head> + <meta charset="utf-8"> + <title>${title?La page dont le chemin s'affiche au dessus nécessite un titre}</title> + <meta name="viewport" content="width=device-width,initial-scale=1.0"> + ${STYLE:+<link rel=\"stylesheet\" href=\"$STYLE\"/>} + <meta name="description" content="$description"> + </head> + <body> + <main id="main" class="main"> + $(the main) + </main> + <aside id="aside" class="aside"> + $(the aside) + </aside> + <footer id="footer" class="footer"> + $(the footer) + <p>$author</p> + </footer> + </body> + </html> + @@ + +Au passage nous mettons le nom de l'auteurice, se trouvant dans la variable +`$author` grâce à l'instruction `%A`, dans le footer. +Dans les sources d'une page il faudrait ensuite appeler `%S` avec les noms de +sections : + + %S main + # Titre de l'article + blablalba + % + + %S aside + truc que l'on raconte dans l'aside + % + + %S footer + contenu du footer + % + +A noter, si vous en avez une utilité quelconque, il est possible d'ouvrir et de +fermer les `%S` à votre guise. Le contenu d'une section sera généré dans l'ordre +d'apparition dans le document mais les sections n'interfèrent pas entre elles.\ +Il est donc possible d'écrire : + + %S main + # Titre + azdazda + % + + %S footer + machin + % + + %S main + bidule + % + + %S footer + truc + % + +cela reviendrait à écrire + + + %S main + # Titre + azdazda + machin + % + + %S footer + bidule + truc + % + +Pareil avec les appels à la commande `save_md nom_de_section` suite à un pipe. diff --git a/bin/atomic b/bin/atomic @@ -0,0 +1,60 @@ +#! /bin/sh + +entry() { +<<% cat +<entry>\ +<title><![CDATA[$time-$until | $title]]></title>\ +<id>http://people.netlib.re#${updated:=${published?publication date (%P) required}}</id>\ +<author>\ +<name>${author?author required (%A)}</name>\ +${email+<email>$email</email>}\ +</author>\ +<published>$published</published><updated>$updated</updated>\ +<content type="html"><![CDATA[<h1>Lieu</h1><br>$(echo $location | lowdown)<h1><h1>Ressources</h1>$(echo $ressources | lowdown)<h1>Description</h1>$(lowdown)]]></content>\ +</entry> +% +title= published= author= updated= time= until= +} + +alias %T='title' +title() title="$*" + +alias %P='published' +published() published="$*" + +alias %L='location' +location() location="$*" + +alias %A='by' +by() author="$*" + +alias %D='at' +at() time=$(date -d "$*" +"%a %d %b %y %Hh%M") + +alias %U='end' +end() until=$(date -d "$*" +"%Hh%M") + +alias %R='ressources' +ressources() ressources="$*" + +alias %H='url' +url() url="$*" + +alias %S='<<\% entry' +alias %SS='<<\% entries' + +entries() { feed=true +<<% cat +<?xml version="1.0" encoding="UTF-8"?>\ +<feed xmlns="http://www.w3.org/2005/Atom">\ +<title type="text"><![CDATA[$title]]></title>\ +<updated>${updated-$(date -Is)}</updated>\ +<link rel="alternate" type="text/html" href="$url" />\ +<id>$url</id>\ +<link rel="self" type="application/atom+xml" href="$url/events.atom"/> +% +title= published= updated= +} + +. ${1:-/dev/stdin} +${feed-false} && echo -n "</feed>" diff --git a/bin/pug b/bin/pug @@ -0,0 +1,103 @@ +#! /usr/bin/perl +# Pugjs (https://pugjs.org/) was by far my prefered xml template system +# until v2 but required god knows how many javascript lines to run. +# Pugish is meant to be +# * with some syntax improvements +# * without template features (you can generate a template instead) +# * written in perl so there is no need for js anymore +# * rewritten in C ( or zig or C++) in the future +# +# example of final usage: +# svg(xmlns=http://www.w3.org/2000/svg width=320 height=320) +# path/ (style stroke: none; fill: blue) (d M 0 0 L 320 320) +# path/ (style stroke: red; fill: none) (d M 30 30 a 10 10 0 1 1 50 50) +# size/ (width 23) (height 34) + +# Known Bug: +# input#pour< name="pour" type="checkbox" checked > +# input#contre< name="contre" type="checkbox" checked > + +use warnings; +use strict; + +# TODO: handle -h, --help, --version +# TODO: support html section (using indent as well) + +my @indent; +my @to_close; + +my ( $indent, $text, $tag, $i ); + +sub get { + return unless defined ($_ = <>); + ($indent,$text) = /^(\s*)(.*)/; + 1; +} + +sub empty { not length $text } + +sub text { + for ($text) { + return 1 if + /^(# |$)/ + || ( /^[<]/ && print ) + || ( /^[|](.*)/ && print "$1\n" ) + } + 0; +} + +sub release { + pop @indent; + print "</", (pop @to_close) ,">" +} + +sub undeep { + $i = length $indent; + release while @indent && $indent[$#to_close] >= $i +} + +sub kvs { + my @pairs = split /;?\s+/, $1; + while (@pairs > 1) { + print qq( $pairs[0]="$pairs[1]"); + splice @pairs,0,2; + } +} + +sub node_open { + # TODO: multiline text when tailing '.' + for ($text) { + print '<', ($tag = m{^[^.#/\s(<]+}cg ? $& : 'div'); + print qq( id="$1") if m{\G[#]([^.#/\s(]+)}cg; + my @class; push @class, $1 while m{\G[.]([^.#/\s(]+)}cg; + @class and print qq( class="@class"); + # TODO: quoted values + if(m{\G[(](.*)[)] *(.*)}cg) { kvs $1 ; print ">$2" } + elsif(m{\G[/]\s*(.*)}cg) { print " $1/>" ; return } + elsif(m{\G(/?)<}cg) { + $_ = substr $_, (pos); + while (not />/) { + s/^(\S)/ $1/ or s/ +/ /g; + print; + defined ($_ = <>) + or die "you can't leave < alone! not now!"; + chomp; + s/^\t+ */ /; + } + s/^(\S)/ $1/ or s/ +/ /g; + print; + } + elsif(m{\G$}cg) { print '>' } + elsif(m{\G\s(.*)}cg) { print '>',$1 } + else { die "unexpected situation: $_"; } + } + push @indent , $i; + push @to_close, $tag; +} + +while (get) { + undeep; + next if empty || text; + node_open +} +release while @indent; diff --git a/bin/pug2cat b/bin/pug2cat @@ -0,0 +1,26 @@ +#! /bin/sh + +# for example: +# @@ layout +# html +# body ${title?title} +# @@ +# +# @@ another +# html +# body ${title?title} +# @@ + +# will be transformed as heredoc templates this way +# layout() <<@@ cat +# <html><body>${title?title}</body></html> +# @@ +# another() <<@@ cat +# <html><body>${title?title}</body></html> +# @@ + +sed -E ' + s/^@@ *(.+)/|\1() <<@@ cat/ + s/^@@$/|\n|&/ +' -- "$@" | bin/pug + diff --git a/bin/shylus b/bin/shylus @@ -0,0 +1,14 @@ +#! /bin/sh +set -eu +rule() RULES="${RULES:+$RULES;}$*" +attr() { RULES="${RULES:+$RULES;}$1:" ; shift; RULES="$RULES$*" ; } +DUMP() echo -n "$SELECTOR{${1+$@;}$RULES}" +alias DUMPS='echo -n "$*{$RULES}"' +SELECTOR() { + test $# = 0 && set "${DSELECTOR?a CSS selector is required}" + DSELECTOR= RULES= SELECTOR="${SELECTOR:+$SELECTOR }$@" +} +alias '?'='trap DUMP EXIT;SELECTOR' +alias '??'='trap DUMPS EXIT; set "${SELECTOR}"; set' +alias '@media'='trap DUMP EXIT;SELECTOR @media' +. "${1-/dev/stdin}" diff --git a/common b/common @@ -0,0 +1,22 @@ +#! /bin/sh + +the=$(mktemp -d) ; trap "rm -rf $the" EXIT +save_md() lowdown >> "$the/$1" + +alias %T="title" +title() title="$*" + +alias %A="author" +author() author="$*" + +alias %P=":" + +alias %D="description" +description() description="$*" + +the() ( + cd $the; cat "$@" +) + +alias '%S=<<\% save_md' +alias 'S%%=<<%% save_md' diff --git a/lib/html b/lib/html @@ -0,0 +1,10 @@ +layout() <<@@ cat +<html> +<header> ${STYLE:+<link rel="stylesheet" href="$STYLE"/>} +<title>${title?La page dont le chemin s'affiche au dessus nécessite un titre}</title> +</header> +<body> + <div class="main">$(the main)</div> +</body> +</html> +@@ diff --git a/makefile b/makefile @@ -0,0 +1,52 @@ +.DELETE_ON_ERROR: +# Pour copier les fichiers d'un endroit à un autre +mk = install -D /dev/stdin + +# On créé des variables contenant la liste des fichiers qui nous intéressent +# Dans sources les md à transformer en html +# Dans annexfiles les fichiers qui gravitent autour d'une page +# Dans allfiles l'union des deux pour générer le dossier raw +sources != find src -type f -name '*.md' +annexfiles != find src -type f -not -name '*.md' +allfiles = $(sources) $(annexfiles) +# find src -type f + +# On construit dynamiquement les règles à invoquer avec des substitutions de +# chaînes de caractères +# Ex: Pour pages on prend tous les chemins de fichiers récupérés dans sources +# On substitue src/ par root/ et l'extension md par html +# Le fichier source "src/truc/bidule.md" donnera donc +# "root/truc/bidule.html" +# Même mécanique pour les raw et les fichiers annexes +pages = ${sources:src/%.md=root/%.html} +annexrules = ${annexfiles:src/%=root/%} +rawrules = ${allfiles:src/%.md=root/%.md} + +# On appelle toutes les règles pour produire tous les fichiers +# nécessaires +# Pour chacune make va tenter de trouver une règle correspondante dans la +# liste qui suit +all: ${pages} ${annexrules} ${rawrules} root/style.css + +clean:; rm -r root/* + +# Règle pour générer le css +root/style.css: rc/style.css; cp $< $@ + +# Règle pour générer l'html depuis les fichiers md +# Va matcher toutes les règles stockées dans la variable pages +# Chaque fichier html requiert sont équivalent md dans src et le script +# page +# Ce que % match dans la cible sera substitué à la place de % dans les +# dépendances +# La commande pour la compilation revient à exécuter le fichier md (qui +# est en fait un script) et piper le contenu dans la commande stockée +# dans la variable mk avec pour argument la cible +# make substitue la variable $@ avec le chemin de la cible +root/index.html : FORCE ; STYLE=/style.css src/index.md | ${mk} $@ +root/%.html : src/%.md page common lib/html ; STYLE=/style.css $< | ${mk} $@ +root/% : src/%; install -D $< $@ +root/%.md : src/%.md; install -D $< $@ +page : lib/htmlhardcoded ; touch $@ +common : lib/htmlhardcoded ; touch $@ +FORCE: diff --git a/page b/page @@ -0,0 +1,8 @@ +#! /bin/sh + +. ./common + +. lib/html +[ "$1" ] || set - +. "$@" +layout diff --git a/rc/style.css b/rc/style.css @@ -0,0 +1,193 @@ +:root { + + /* Fonts */ + --font-system: Arial, -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + + /* + @TODO font base 18px + ** Typo scale base 16px + * Ratio = Quinte (1.5) + */ + --ratio: 1.5; + --space-xs: calc(var(--space-base) / var(--ratio)); /* 7.111px */ + --space-sm: calc(var(--space-base) / 1.5); /* 10.667px */ + --space-base: 1rem; /* 16px */ + --space-lg: calc(var(--space-base) * var(--ratio)); /* 24px */ + --space-xl: calc(var(--space-lg) * var(--ratio)); /* 36px */ + --space-2xl: calc(var(--space-xl) * var(--ratio)); /* 54px */ + --space-3xl: calc(var(--space-2xl) * var(--ratio)); /* 81px */ + --space-4xl: calc(var(--space-3xl) * var(--ratio)); /* 121.5px */ + + /* COLORS */ + --black: #2f383e; + --white: #fefffe; + --grey: #edead5; + --green: #68715E; + --yellow: #fdf6e3; + --blue: #2F7598; +} + +html { + -webkit-font-smoothing: antialiased; + --moz-osx-font-smoothing: grayscale; + scroll-behavior: smooth; + font-size: 100%; /* 16 pixels par défaut en moyenne */ +} + +body { + padding: 0 0.5rem; + min-height: 100vh; + font-family: var(--font-system); /* Utilisation d'une font système */ + font-weight: 400; + line-height: 1.56; + text-rendering: optimizeSpeed; + background-color: var(--yellow); +} + +body > * { max-width: 820px; } + +@media screen and (min-width: 90em) { + body > * { max-width: 940px; } +} + +/*TYPO*/ + +a { color: var(--blue); } +a:hover { color: var(--green); } + +/*TITLES*/ + +h1, h2, h3, h4, h5 { + position: relative; + font-weight: bold; +} + +h1, h2, h3 { + padding: 0 0.75rem; + background-color: var(--grey); + max-width: max-content; +} + +h1, .h1-like { + font-size: var(--space-2xl, 3.375rem); + line-height: 1.44; +} + +h2, .h2-like { + font-size: var(--space-xl, 2.25rem); + line-height: 1.54; + letter-spacing: 0.13px; +} + +h3, .h3-like { + font-size: var(--space-lg, 1.5rem); + line-height: 1.3333; + letter-spacing: 0.1px; +} + +/*Selection*/ + +::selection { + color: var(--yellow); + background-color: var(--green); +} + +/*A11y*/ + +a.skip-main { + left:-999px; + position:absolute; + top:auto; + width:1px; + height:1px; + overflow:hidden; + z-index:-999; +} + +a.skip-main:focus, a.skip-main:active { + color: var(--white); + background-color: var(--black); + left: auto; + top: auto; + width: 100%; + max-width: 100%; + height: auto; + overflow:auto; + padding:3px; + border-radius: 10px; + border:2px solid var(--blue); + text-align:center; + font-size:1.2em; + z-index:999; +} + +/*TABLE*/ + +tbody tr:nth-child(even), th { + background-color: var(--grey); +} + +/*HEADER*/ + +header { + padding-left: 1rem; + color: var(--blue); +} + +.logo { + font-size: var(--space-2xl); + font-weight: bold; + line-height: 0; +} + +nav ul { + padding: 0; + list-style: none; +} + +nav ul li a { + font-size: var(--space-lg); + font-weight: bold; +} + +/*BODY*/ + +/*@TODO un pattern + interaction design -> univers Katzele*/ + +blockquote { + border-left: solid 4px var(--grey); + padding-left: 28px; + color: var(--black); +} + +/*PRE*/ + +pre { + padding: 1rem 2rem; + width: max-content; + max-width: 100%; + tab-size: 2; + white-space: pre-wrap; + background: var(--black); + color: var(--white); +} + +/*LAYOUTS*/ + +body, +.container { padding: 1rem } + +@media screen and (min-width: 60em) { + body, + .container { padding: 1rem var(--space-2xl); } +} + +/*Link Blank */ +.blank[target="_blank"]:after { + content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==); + display: inline-block; + width: 0.5rem; + margin: 0 3px 0 5px; +} + +/*LIMITE à 200 lignes*/ diff --git a/src/index.md b/src/index.md @@ -0,0 +1,42 @@ +#! page +%T Une exploration collective du convivialisme numérique +%A katzele +%D Nous sommes un collectif de personnes interrogeant la place et l\'avenir du numérique dans une société contrainte de prendre en compte les limites planétaires +%S main + +# Katzele + +Une exploration collective du [convivialisme](https://fr.wikipedia.org/wiki/Outil_convivial) numérique, +Katzele est un groupe ouvert de citoyen* impliqué* dans la réflexion et +l'expérimentation d'un numérique qui permette de s'inscrire dans une société +que les crises sociales et environnementales nous imposent de refonder. Outre +l'urgence de la situation, nous pensons que cette refondation est une chance. + +Pour toute question, rencontre (physique ou virtuelle), animation, et en cas de doute, n'hésitez pas à +[nous contacter](contact.html) et nous partagerons avec vous [nos idées et nos références](about.html). + +En plus de nos réunions régulières, les prochaines occasions pour nous rencontrer sont : + +Nous maintenons une liste relativement exhaustive des +[évenements passés](./archives/index.html) auxquels nous avons eu le plaisir de participer +(en tant qu'invités, organisateurs, animateurs …) merci encore à toutes et tous pour +ces échanges, ces invitations… + +### Participer + +Que vous ayez 30 minutes à nous consacrer pour un petit coup de main ou un an à +investir dans des projets, votre participation sera grandement appréciée : +Organiser, expliquer, réparer, construire, programmer… tous nos projets manquent de bras. + +Il existe un [guide de contribution](articles/accueil/index.html) qui explique +comment nous échangeons et quels sont les logiciels que nous utilisons. + +## Articles et notes et code + +Parfois, on note des trucs. Attention, c'est rarement abouti.\ +Pour le code, ça se passe [sur la page de kit](kit.html) + +### les articles + + +### les notes