chaos

Projet Documentation en

Remarques :
WIP

Motivation

Automatiser la génération de documentation

L'automatisation a normalement pour but de faire gagner du temps ou de simplifier des choses.

Mais je m’en fiche — je le fais parce que le processus est farfelu et que j’aime le défi. De plus, beaucoup de logiciels manquent de documentation explicative, notamment les miens.

Je souhaite décrire les outils que j'utilise pour générer rapidement et à grande échelle de documentation logicielle. Les objectifs sont divers, et je ne suis pas sûre des priorités dès le départ. C'est pourquoi je le considère comme un “Work in Progress” jusqu'à nouvel ordre.

Les fichiers que je crée nécessitent une séquence particulière de programmes, mais vous pouvez considérer la chaîne d'outils présentée ci-dessous comme une pile d'utilitaires et de techniques. Certains logiciels sont décrits séparément, et vous pouvez d'en choisir uniquement ceux qui répondent à vos besoins. Je propose également des alternatives à la fin de la page pour ceux qui souhaitent explorer d'autres options.

Ce que j’ai réussi à faire

Aujourd’hui, je peux écrire un seul fichier texte, lancer une seule commande dans le terminal et obtenir plusieurs fichiers différents. Le document original, au format reStructuredText (reST), est converti directement en page man et en fichier HTML. Ensuite, le HTML sert de base pour générer un PDF.

Chaîne d’outils

Certains outils de cette chaîne sont standards (par exemple rst2html5, rst2man), tandis que d’autres sont des scripts personnalisés (manheader, htidy, make_doc). Cette chaîne est conçue pour mon usage personnel et peut ne pas être portable ni reproductible dans d’autres environnements.

Un fichier au format reStructuredText est écrit dans n’importe quel éditeur de texte simple (pas dans un traitement de texte). Vim Exemple :
flnews_post_proc.rst (reStructuredText)
Le seul autre outil que j’utilise directement depuis la ligne de commande est un petit script shell personnel, make_doc. Je le lance dans un dossier donné, et il y cherche tous les fichiers reST pour les traiter un par un. make_doc (Mon script)
make_doc appelle rst2man afin de produire une page man à partir du fichier original au format reStructuredText. rst2man (Docutils)
Il manque encore, dans la page man générée par rst2man, les valeurs des champs date, section, version et category. Bien que rst2man puisse en définir quelques-uns automatiquement, je préfère vérifier qu’ils sont tous bien présents en appelant mon ruby-script manheader. manheader (Mon script)
La page finale est comprimée avec gzip. gzip (GNU) Exemple:
flnews_post_proc.1.gz (man page)
make_doc appelle rst2html5 qui produit un fichier HTML. J’impose que le code d’une feuille de style explicitement nommée soit intégré. rst2html5 (Docutils)
CSS (feuille de style)
Pour normaliser le HTML5 généré et améliorer la conformité avec XHTML5, j’utilise HTML Tidy. Un petit script htidy rassemble certaines déclarations et paramètres de configuration. htidy (Mon script)
Exemple:
flnews_post_proc.html
Pour la création d’un fichier PDF, je lance Apache FOP sur le fichier HTML créé précédemment, en utilisant une feuille de style XSL-FO préparée soit pour le projet, soit pour un usage général. Dans l’environnement FOP/Java, deux actions sont exécutées, et il semble normal qu’il n’existe pas encore de réponse simple à la question qui fait quoi :
  1. D’une façon ou d’une autre, l’HTML est transformé en FO (“Formatting Objects”), probablement en confiant la transformation XSL à un processeur XSL interne Java dérivé de Xalan (voir ci‑dessous pour une alternative).
  2. FOP génère un PDF à partir du code FO.
Tout fonctionne parfaitement au final, et je n’ai pas vraiment envie de savoir pourquoi. Affirmer d’un air entendu que tel outil ou telle bibliothèque fait ceci ou cela m’exposerait sans doute à quelque châtiment exemplaire. Je m’en abstiens.
FOP (Apache)
stylesheet.xsl (feuille de style XSL-FO)
html2Pdf.xsl (feuille de style XSL-FO )
Le premier PDF est converti en un nouveau, revendiquant la compatibilité avec la version 2.0, à l’aide de Ghostscript. ghostscript (Artifex) manuel en Français
Quelques champs de métadonnées sont ensuite paramétrés avec l’outil cpdf cpdf (Coherent Graphics) Exemple :
flnews_post_proc.pdf

Décisions et contraintes

J’ai choisi des procédures qui me laissent une grande liberté pour mettre en forme les documents finaux comme je l’entends. Compte tenu de la diversité des outils disponibles, j’ai d’abord dû déterminer lesquels répondaient réellement à mes besoins.
Puis, après en avoir pesé les qualités et les limites, j’ai organisé leur interaction et ajusté leur configuration par essais et erreurs, jusqu’à obtenir un résultat acceptable.

Vous pouvez toujours saisir n’importe quel outil, lui fournir votre contenu et vous satisfaire du résultat imposé par défaut. Mais si vous voulez contrôler l’apparence des documents finaux, vous constaterez que l’individualisme a un prix : faciliter une tâche implique généralement de renoncer à certaines libertés.

Spécificités des fichiers créés

Au début, je ne m’intéressais pas aux outils ; je voulais simplement des documents à peu près lisibles et – pourquoi pas – agréablement mis en forme.

HTML

Le document HTML généré est mis en forme à l’aide d’une feuille de style CSS externe que je maintiens. Il existe une feuille de style de base, d’application générale, qui peut être utilisée telle quelle ; dans d’autres cas, elle est adaptée aux besoins d’un projet particulier. Chaque document fait donc référence à une feuille CSS spécifique au projet, modifiée ou non.

Le document HTML est généré directement à partir de la source reStructuredText à l’aide de rst2html5, un outil fourni par le package Docutils. J’exécute ensuite HTML Tidy sur le résultat — principalement pour normaliser et épurer le balisage avant la conversion en PDF.

Commandes utiles
rst2html5
--rfc-references --title=`capitalize "$NAME"` \
--xml-declaration --stylesheet="$CSS" ./"$rst" "$HTML"

Cette commande génère du HTML à partir de reST. Les options de rst2html5 sont listées lorsque vous exécutez le programme avec l’argument habituel --help. Je ne les détaille pas ici.

Le fichier crée de cette manière est basé sur un modèle qui établie la structure du code HTML. Vous pouvez vous contenter du modèle par défaut. Ceci est installé avec docutils mais il peut être utile d'écrire votre propre modèle. Le texte suivant est un modèle tout à fait complet, qui ajoute à la partie <head/> du code HTML les meta-balises pour le préchargement des polices et pour un favicon:

      %(head_prefix)s
      <rlink rel="preload" as="font" crossorigin="" 
         href="https://my_site/fonts/Classica/Classica-Book.ttf" type="font/ttf" />
      <link rel="preload" as="font" crossorigin="" 
         href="https://my_site/fonts/Classica/Classica-Bold.ttf" type="font/ttf" />
      <link rel="preload" as="font" crossorigin="" 
         href="https://my_site/fonts/Classica/Classica-BookOblique.ttf" type="font/ttf" />
      <link rel="preload" as="font" crossorigin="" 
         href="https://my_site/fonts/Fertigo_PRO.otf" type="font/otf" />
      <link rel="icon" type="/image/x-icon" href="images/favicon_Schreibfeder.ico" />
      %(head)s
      %(stylesheet)s
      %(body_prefix)s
      %(body_pre_docinfo)s
      %(docinfo)s
      %(body)s
      %(body_suffix)s

Si vous avez une feuille de style pour la définition des polices, vous devrez l'ajouter ce fichier à l'option stylesheet de rst2html5, ensemble avec votre modèle:

rst2html5
--template="mon_modele.txt" --rfc-references --title=`capitalize "$NAME"` \
--xml-declaration --stylesheet="mes_styles.css, fonts.css, /main/styles_globales.css"
./"$rst" "$HTML"
tidy
logo-i -m -n -asxhtml --indent-cdata yes --output-xhtml \
yes --vertical-space yes --strict-tags-attributes yes --add-xml-decl yes \
--doctype
"$DOCTYPE" --drop-proprietary-attributes yes -utf8 "$PAGE"

Tidy veille à ce que le code HTML soit produit dans un style XHTML (plus ou moins, selon le prestige momentané du Living Standard) et supprime la déclaration DOCTYPE, qui interférerait autrement lors de l’appel ultérieur à FOP pour la génération d’un PDF.

PDF

Mon PDF intègre des sous-ensembles de polices et ressemble beaucoup à la sortie HTML. En revanche, toute la mise en forme doit être codée dans la feuille de style XSL-FO. Lorsque FOP est invoqué, deux transformations sont effectuées successivement. Il est donc plus juste de parler d’un processeur XSL-FO.

Une autre caractéristique du fichier PDF est la présence d’une arborescence de signets. C'est la structure arborescente qui peut être affichée à la place des vignettes des pages dans la barre latérale du lecteur PDF. Elle vous permet de naviguer dans le document sans devoir revenir à la table des matières ou à un élément équivalent. Cette structure est définie explicitement dans la feuille de style XSL-FO. J’ai choisi un code réutilisable dans différents projets et je n’investis pas de temps ni d’effort supplémentaires dans la régénération de l’arborescence de signets chaque fois que des chapitres sont supprimés, ajoutés ou renommés. Beaucoup d’exemples que je trouve sur le Web ne sont pas écrits ainsi. Les auteurs ont plutôt choisi de cibler directement des titres de chapitres. Mais cela n’est guère pratique lorsqu'il faut modifier ces titres ou les déplacer. Ma première version d’une telle arborescence de signets dynamique date d’avant 2010. À l’époque, j’étais rémunéré pour son développement. Que cette possibilité soit encore largement ignorée me surprend beaucoup. Utiliser une technologie conçue pour l’automatisation, pour ensuite en contrecarrer l’objectif, remet en question la valeur même d’une telle technologie.

Commandes utiles
export FOP_OPTS="-Djavax.xml.accessExternalStylesheet=all -Djavax.xml.accessExternalDTD=all"

Pour des raisons de sécurité, FOP refuse par défaut les feuilles de style imbriquées. Une fois ces options activées, elles sont de nouveau acceptées. Ceux d’entre vous qui apprécient un défi conceptuel peuvent ajouter des options à FOP afin de confier la première étape de la transformation XSL-FO à un autre processeur XSL. Vous saurez ainsi — une bonne fois pour toutes — quel outil fait quoi.

~/bin/fop
logo-c ~/bin/fop-2.11/fop/conf/fop.xconf -xml "$HTML" -xsl "$XSL" -pdf "$PDF"

J’utilise une version récente d’Apache FOP que j’ai installée dans mon répertoire personnel. Bien qu’il s’agisse de la seule version installée sur cet ordinateur, je souhaite éviter tout conflit éventuel si elle devait un jour coexister avec une version plus ancienne provenant des dépôts Debian.

gs
logo-dEmbedAllFonts=true -dSubsetFonts=false -dPDFSETTINGS=/prepress \
-sDEVICE=pdfwrite -dOmitXMP=true -dCompatibilityLevel=2.0 \
-dNOPAUSE -dBATCH -o "$PDF_2" "$PDF"

Cet appel à Ghostscript convertit le premier fichier PDF en un format qui devrait se rapprocher autant que possible de la version 2.0 du standard PDF. Il supprime également la balise de métadonnées XMP, qui n’est pas nécessaire dans ce type de fichier PDF (je sais qu’elle ne l’est pas — mais vous pourriez aimer XMP pour une raison insondable). Pour une conformité complète avec PDF 2.0, d’autres outils seraient nécessaires.

cpdf
logo"$PDF" -set-creator "$VIM, $DOCUTILS" AND \
-set-producer "$FOP, $GS, $CPDF" AND \
-set-author "<michael.uplawski at uplawski.eu>" AND \
-set-title "$NAME manual" AND -o "$PDF_2"

cpdf est un autre outil puissant, mais je ne l’utilise que pour attribuer des valeurs raisonnables à quelques champs de métadonnées (hors XMP). Ghostscript (voir plus haut) peut le faire également, à l’exception du champ Producer. Avec cpdf, il est possible de copier des métadonnées XMP depuis un fichier, mais je considère cet effort inutile pour le moment — et je tiens XMP pour un standard idiot.

Alternatives

Les fichiers de documentation peuvent être créés de bien d’autres manières que celles décrites ci-dessus.

rst2pdf

logo Vous pouvez générer un PDF directement en utilisant l’un des outils appelés rst2pdf. L’un fait partie du paquet Docutils, l’autre est un projet totalement indépendant. Je n’aime pas le rendu produit par l’outil fourni avec Docutils.

Si vous n’avez pas encore décidé quelle technologie utiliser, vous pouvez éventuellement essayer l’outil disponible sur rst2pdf.org. Il permet de définir des feuilles de style personnalisées. Ces feuilles de style sont des fichiers en texte brut au format YAML.

Comme vous l’avez remarqué dans la description de la chaîne d’outils plus haut, j’écris déjà des feuilles de style CSS pour le HTML et des feuilles de style XSL pour les PDF. Bien que j’aie déjà écrit du YAML pour la configuration de logiciels, cela commence à ressembler à un joyeux zoo de langages de style. Je me limite pour le moment au XSLT et n’inclurai pas rst2pdf dans ma chaîne d’outils. Les transformations XSL-FO sont ce que je connais le mieux lorsqu’il faut automatiser la production de PDF.

Saxon — processeur XSLT et XQuery

logo Si vous voulez utiliser une version open source et récente du processeur XSLT et XQuery Saxon, peut-être parce que vous avez besoin de XSLT 3.0 ou parce que la manière dont FOP transforme tous les <xsl:message/> en Warning vous dérange, une manière simple de remplacer le processeur XSL (peu importe ce que cela signifie), consiste à l’exécuter avec le fichier d’entrée comme argument afin de produire un fichier FO, puis à appeler FOP uniquement pour la conversion finale du fichier FO en PDF. Pas de bricolage avec le classpath, les options Java ou la définition des FOP_OPTS, mentionnée plus haut.

java ~/bin/saxon-12.9/saxon-he-12.9.jar \
-s:"infile.html" -xsl:"stylesheet.xsl" -o:"output.fo" loglevel='debug'

Cette commande appelle le processeur Saxon sur le fichier d’entrée infile.html et produit un fichier FO, en appliquant les règles de mise e forme définies dans stylesheet.xsl. Vous pouvez passer des valeurs de variables au processus XSLT, comme loglevel, si la feuille de style les définit en interne. Le résultat peut ensuite être transmis à FOP pour la production d’un fichier PDF.

Outils LibTIFF pour un contenu PDF non modifiable

La bibliothèque LibTIFF est accompagnée de quelques programmes utilitaires qui transforment des images au format TIFF en PDF. Ces fichiers ne peuvent pas être modifiés autrement qu’au moyen d’un logiciel graphique.
Cela ne suffit pas à justifier la procédure. Mais il n’y aura pas non plus de problèmes d’affichage sur des ordinateurs qui ne disposent pas des polices nécessaires, ni avec des imprimantes qui auraient du mal à gérer certains glyphes si la police est intégrée dans un fichier PDF.

Selon vos habitudes et votre expérience, les fichiers créés avec les outils LibTIFF seront plus grands ou plus petits. Un traitement de texte, par exemple, peut intégrer beaucoup d’informations dans un fichier PDF, dont certaines inutiles ou redondantes. Dans ce cas, transformer chaque page d’un fichier PDF en image, puis à nouveau en fichier PDF, peut réduire considérablement la taille du fichier.
D’autre part, un PDF généré par une transformation XSL-FO, comme décrit plus haut, est déjà très petit, surtout s’il ne contient pas d’images supplémentaires. Ici, la conversion vers des images, puis à partir de celles-ci, peut faire exploser la taille du fichier jusqu’à plusieurs fois celle du fichier d’origine.

gs
-sDEVICE=tiff24nc -r400x400 -sPAPERSIZE=a4 \
-sOutputFile=
page_%04d.tif -dNOPAUSE \
--
infile.pdf

Cet appel à gs crée une image Tiff pour chaque page du fichier PDF infile.pdf. Si le fichier PDF était flnews_post_proc.pdf, le résultat serait 7 fichiers Tiff, chacun portant un suffixe numérique indiquant la position de la page correspondante dans le PDF.

tiffcp
page*.tif new_file.tif

tiffcp assemble un fichier Tiff multicouche à partir de tous les fichiers Tiff créés précédemment.

tiff2pdf
-z new_file.tif -o new_file.pdf

Enfin, à partir de toutes les pages transformées en images, puis en couches d’un grand fichier TIFF, un nouveau fichier PDF est créé. L’argument -z de tiff2pdf impose l’application d’une compression ZIP. Comme indiqué précédemment, si le fichier PDF original était très petit, celui créé à partir des images peut devenir extrêmement grand : la nouvelle version flnews_post_proc_b.pdf est un fichier de 1,6 M, soit 18 fois la taille de celui généré avec XSL-FO.

Rédiger des pages de manuel avec un traitement de texte

Pour beaucoup de gens, écrire quelque chose signifie utiliser un traitement de texte.
Et la majorité des personnes qui savent rédiger une documentation parfaitement structurée et compréhensible ne sont pas des passionnés d’informatique et ne souhaitent peut-être pas maîtriser une pile technologique comme celle que je présente sur cette page.

La bonne nouvelle est que les traitements de texte écrivent aujourd’hui du XML, sauf indication contraire. Chaque traitement de texte peut avoir un type de fichier considéré comme standard, mais la plupart peuvent également produire d’autres formats XML.

Microsoft Word®
écrit Docx, c’est-à-dire OOXML. Les fichiers ont normalement l’extension docx et sont compressés. Lorsqu’on extrait un fichier de ce type, le contenu textuel se trouve dans le fichier document.xml du sous-répertoire word.
Apache OpenOffice
écrit ODT, c’est-à-dire Open Document Format. L’extension des fichiers est odt. Ces fichiers sont normalement compressés au format ZIP ; après extraction, le contenu textuel se trouve dans content.xml.
LibreOffice
écrit aussi ODT.
SoftMaker TextMaker®
écrit TMDX, qui est un sous-ensemble d’OOXML, mais peut autrement être traité comme un fichier docx.
AbiWord
écrit son propre format XML dans des fichiers avec l’extension abw. Ces fichiers ne sont pas forcément compressés et tout le contenu, ainsi que les définitions des styles utilisés, se trouvent dans le même fichier.

Tous les programmes listés ci-dessus peuvent écrire des fichiers au format OOXML (docx) et ODF (odt).

Pendant que la majorité des traitements de texte — peut-être tous — font un bon travail pour l’export en PDF, les pages de manuel (man) sont pour eux un univers étranger. Le choix d’un format XML, pourtant, laisse la possibilité de convertir les productions des traitements de texte en tout ce que vous voulez…

Vous pouvez — par exemple — transformer un fichier AbiWord en instructions de composition Troff, et donc en page de manuel. Bonne chance avec ça ! (Je ne doute pas une fraction de seconde qu’il existe des personnes qui prétendent que coder en Troff est la seule manière acceptable d’écrire des pages de manuel.)

Mais vous pouvez aussi, tout simplement, produire du reStructuredText à partir de l’un des formats XML listés ci-dessus. Comme vous y êtes, vous pouvez identifier des parties du document original qui ne doivent pas être incluses dans la documentation pour l’utilisateur final, et encourager l’auteur à se servir des formats de paragraphes et de caractères dédiés à la communication des explications à un potentiel traducteur.

Ô vous qui manquez de foi !
AbiWord

Voici un exemple de code XML produit par AbiWord : flnews_post_proc.abw, et voici la feuille de style XSLT : abw2reST.xsl. Lorsqu’on les présente au processeur XSL Saxon, ils deviennent ce document reStructuredText : test.rst.
Notez que, encore une fois, la déclaration DOCTYPE doit être supprimée dans le document d’entrée.

Notez que AbiWord peut convertir des documents au format XSL‑FO, et ainsi vous épargner de la moitié du travail pour la production d'un fichier PDF. Cependant le succès de cette opération dépend de la manière comment le document d'origine est rédigé et mis en page : Lors de mes propres tests, AbiWord a souvent planté et n'a pas généré de fichier XSL-FO

Faites encore mieux

Lorsque divers documents sont basés sur le même modèle, ces modèles sont détectables dans les fichiers XML résultants. Plusieurs transformations en reStructuredText (et en pages de manuel) peuvent alors bénéficier du même travail préparatoire et de la même feuille de style XSL. Il n’est jamais nécessaire de connaître les définitions précises des mises en forme configurées dans le traitement de texte d’origine. Tout ce qui est nécessaire est le nom d’un style afin de reconstituer la structure d’un document. La feuille de style XSL n’a pas besoin de reproduire les styles du traitement de texte.
En même temps, comme les feuilles de style peuvent être imbriquées, rien ne vous empêche de préparer un traitement spécial pour quelques documents, indépendamment du modèle dont ils sont dérivés.

… ou soyez une lamentable pile de misère

Vous pouvez toujours demander à une IA de convertir tout ce que vous voulez en TROFF et en être fier.

Commentez par mail: address
Omega validator