4 points par GN⁺ 2024-03-01 | 1 commentaires | Partager sur WhatsApp
  • Pour les utilisateurs qui veulent lire des articles web directement dans le terminal, James' Coffee Blog propose aussi ses articles au format pages de manuel Linux
  • Pour une même URL, si le client envoie Accept: text/roff, il reçoit un document roff au lieu du HTML grâce à la négociation de contenu HTTP
  • Le fichier .man de chaque article est généré à partir d’un modèle avec les sections TITLE, AUTHOR, PUBLISHED, POST et URL
  • Le corps utilise le Markdown d’origine pour le rendre plus lisible que du HTML, même si l’espacement n’est pas toujours parfaitement propre dans une page de manuel
  • NGINX détecte les requêtes text/roff et réécrit l’URL vers un fichier .man, ce qui permet de l’enregistrer avec curl puis de l’ouvrir avec man ./post.page

Lire un article de blog avec man

  • Les pages de manuel de Linux sont le moyen standard de consulter l’utilisation d’une commande dans le terminal, généralement avec man <command>
  • Par exemple, on peut consulter le manuel de la commande tac ainsi
man tac
  • James' Coffee Blog met en place un flux qui permet de lire aussi les articles du blog de cette manière, en téléchargeant la version roff de l’URL d’un article puis en l’ouvrant avec man
  • Voici un exemple réel de requête
curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/ > post.page && man ./post.page

Choisir le format avec la négociation de contenu HTTP

  • Le cœur de l’implémentation repose sur la négociation de contenu HTTP, qui permet au client d’indiquer au serveur le format de réponse souhaité
  • L’en-tête Accept sert à transmettre le type de contenu voulu
    • Par exemple, Accept: image/png signifie qu’on souhaite recevoir un fichier PNG si possible
    • Il est aussi possible d’indiquer plusieurs types de contenu et leurs priorités, mais ici seul un format précis est demandé
  • Pour recevoir un article de blog au format page de manuel, on envoie l’en-tête Accept: text/roff
  • Le serveur lit cet en-tête et renvoie une réponse text/roff ouvrable avec man au lieu du HTML

Comment les fichiers .man sont générés

  • Les pages de manuel Linux sont écrites avec la syntaxe roff
  • Le site a été modifié pour générer une version man pour chaque article de blog
  • La structure du modèle utilisé est la suivante
.TH jamesg.blog 1 "" "jamesg.blog"
.SH TITLE
...
.SH AUTHOR
James' Coffee Blog (https://jamesg.blog)
.SH PUBLISHED
...
.SH POST
...
.SH URL
...
  • Le modèle utilise le nom de domaine comme en-tête et crée cinq sections
    • TITLE
    • AUTHOR
    • PUBLISHED
    • POST
    • URL
  • Le corps reprend le Markdown d’origine
    • L’espacement n’est pas toujours parfaitement rendu dans une page de manuel
    • Malgré cela, c’est plus lisible que du HTML et cela préserve mieux les informations de titres et de paragraphes que du simple texte

Récupérer avec curl et ouvrir avec man

  • La version roff d’un article de blog peut être demandée avec la commande suivante
curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/ > post.page
  • Le résultat enregistré peut ensuite être ouvert comme une page de manuel locale
man ./post.page
  • Si un navigateur classique demande l’URL du même article, il reçoit la version HTML
  • En revanche, la commande curl ci-dessus demande explicitement la version text/roff pour cette même URL

Réécriture vers les fichiers .man dans NGINX

  • Le serveur gère séparément les requêtes text/roff avec quelques lignes de configuration NGINX
  • Dans /etc/nginx/nginx.conf, des variables sont déclarées pour lever un indicateur lorsqu’un type de contenu précis est détecté
map $uri $redirect_suffix {
~^/(.*)/$ $1;
default "";
}
map $http_accept $redirect_location {
default "";
"~^text/roff" 1;
}
  • Dans le fichier de configuration du site, sous /etc/nginx/sites-enabled, une règle est ajoutée pour traiter les requêtes de pages roff
server {
...
location / {
if ($redirect_location = 1) {
rewrite ^/(.*)/$ /$1.man last;
}
...
}
}
  • Cette configuration supprime la barre oblique finale de l’URL et ajoute .man lorsqu’elle voit l’en-tête Accept: text/roff
  • En pratique, NGINX lit alors le fichier .man correspondant au lieu du index.html de chaque article
  • On peut ainsi lire un même article de blog en HTML dans un navigateur web, ou comme page de manuel Linux dans le terminal

1 commentaires

 
GN⁺ 2024-03-01
Commentaires sur Hacker News
  • Ce serait chouette de proposer un dépôt deb comme mode d’abonnement à un blog
    L’idée serait de récupérer tous les articles avec apt update, puis de voir le dernier article et les liens vers l’index complet avec man your-blog

    • L’idée en elle-même est excellente, mais si cela se généralisait, les occasions de diffuser des malwares inhérentes à cette approche semblent assez évidentes
      Je pense que j’aurais peur de m’y abonner
    • Il existe des précédents. Debian proposait autrefois un accès à Linux Gazette, aujourd’hui disparu, et fournit encore divers paquets d’information comme la documentation des paquets, les pages de manuel, les pages info, les RFC, les Linux HOWTO, etc.
      On peut les consulter en local avec le paquet dwww : « Read all on-line documentation with a WWW browser »
      https://packages.debian.org/bookworm/dwww
      Joerg Jaspert était l’ancien mainteneur du paquet Linux Gazette : https://people.debian.org/~joerg/ (2002)
      C’est l’un des meilleurs exemples que j’aie vus d’intégration de la diffusion d’information et de la documentation dans un système d’exploitation, et cela rend notamment les documents man/info plus utiles que les interfaces traditionnelles en terminal
      Il existe aussi Debian Planet, un blog lié à Debian, mais il ne semble jamais avoir été fourni comme paquet Debian lui-même
      Honnêtement, pour s’abonner à un blog, RSS est probablement un meilleur choix
    • Je suis en train de travailler dessus
      https://github.com/capjamesg/jamesg.blog.deb contient de quoi créer, avec les commandes ci-dessous, un fichier deb ne contenant que des pages man
      git clone [https://github.com/capjamesg/jamesg.blog.deb](<https://github.com/capjamesg/jamesg.blog.deb>;)
      cd jamesg.blog.deb
      dpkg-deb --build --root-owner-group jamesg.blog
      sudo dpkg -i jamesg.blog.deb
      Vous devriez alors voir une sortie du type Processing triggers for man-db (2.9.1-1) ..., ce qui signifie que la page de manuel pour man jamesg.blog est disponible
      Pour l’instant, il n’y a qu’un placeholder, mais je finirai probablement demain
      Cela deviendra peut-être bientôt un billet de blog
  • On peut directement le piper vers man, sans fork ni fichier intermédiaire
    curl -sL -H "Accept: text/roff" [https://jamesg.blog/2024/02/28/programming-projects/](<https://jamesg.blog/2024/02/28/programming-projects/>;) | man -l -

    • Il vaut mieux éviter. Il y a 2 heures, yrro a publié quelque chose de similaire, et voilà que le débat sur le fait de piper {curl,wget} vers une commande recommence
      Un ami ne laisse pas un ami piper directement un flux vers une commande
      https://news.ycombinator.com/item?id=39554044
  • Pour info, curl -sL -H "Accept: text/roff" [https://jamesg.blog/2024/02/28/programming-projects/](<https://jamesg.blog/2024/02/28/programming-projects/>;) | man -l /dev/stdin fonctionne chez moi
    Pas besoin d’enregistrer le fichier roff en local

    • Je pense que l’auteur de l’article original a délibérément évité de le faire. Pipeliner directement vers quelque chose comme bash des commandes ou du contenu récupérés sur Internet est généralement considéré comme une mauvaise pratique
      Personnellement, je trouve ça acceptable. Les personnes qui comprennent les implications de sécurité connaissent presque certainement aussi ce genre de méthode de conversion, donc inutile de le leur indiquer
      En revanche, ce n’est pas une bonne chose à montrer aux débutants. Un jour, ils pourraient se faire avoir. En gagnant en compétence, ils découvriront naturellement ce type de fonctionnalité, et j’espère qu’à ce moment-là ils en auront aussi compris les implications
      Ce n’est pas moi qui ai écrit cet article : https://www.seancassidy.me/dont-pipe-to-your-shell.html
    • Malheureusement, cette commande ne fonctionne pas sous macOS : /usr/bin/man: illegal option -- l
      J’ai essayé de faire une commande en une ligne avec un pipe sur Mac, mais j’obtenais toujours des erreurs
      L’implémentation de man sur macOS n’a pas le flag -l. J’ai vérifié la page de manuel
    • Si vous utilisez bash, vous pouvez gagner quelques caractères avec une substitution de processus au lieu d’un pipe
      man -l <(curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/)
  • À propos des URL qui font des choses amusantes dans le terminal, j’en avais vu une autrefois sur textfiles.com
    Elle affiche un court film d’animation avec des codes de terminal VT100, le tout servi depuis un seul URI
    Sur les systèmes modernes, on peut la regarder en limitant le débit
    curl --limit-rate 1000 [http://textfiles.com/sf/STARTREK/trek.vt](<http://textfiles.com/sf/STARTREK/trek.vt>;) && reset
    Le reset est là parce que le terminal peut se retrouver dans un sale état
    Parmi les autres URI orientées terminal, curl cheat.sh/tar récupère des exemples d’utilisation du programme après le /, et curl wttr.in/berlin récupère la météo mise en forme pour le terminal

    • Si vous voulez créer directement une vidéo ASCII via telnet, j’avais fait ça en Go il y a quelques années : https://github.com/bfontaine/RickASCIIRoll
      En pratique, c’est assez simple ; le plus difficile est la génération des images
      Ça peut se faire avec ffmpeg+img2txt.py : https://github.com/bfontaine/RickASCIIRoll/tree/master/movie...
    • Il y a quelques années, j’ai créé un visualiseur d’art ANSI avec émulation de vitesse de modem
      Il dispose d’un ancien miroir de https://16colo.rs/, ce qui permet de voir la plupart des œuvres ANSI publiées jusqu’ici
      Exemple : curl ansi.hrtk.in/ungenannt_1453.ans
    • C’est vraiment génial, mais ça a aussi complètement cassé mon terminal. C’était amusant
    • Il existe aussi Star Wars à regarder via telnet
      https://itsfoss.com/star-wars-linux/
    • Avec tritty, on peut simuler des débits de transmission de 1200/9600 BPS
  • Il ne manque plus qu’un convertisseur de Markdown vers roff, et en cherchant un peu, il en existe déjà
    https://github.com/postmodern/kramdown-man
    https://rtomayko.github.io/ronn/ronn.1.html
    https://kristaps.bsd.lv/lowdown/

  • Il existe un paquet Emacs qui installe le SICP d’Abelson et Sussman dans le répertoire Info
    Il suffit de taper M-x package-install sicp RET
    En voyant ça, je me suis dit qu’on pourrait aussi installer toute une bibliothèque d’archives de blogs avec un lecteur de flux modifié
    Lire Info dans Emacs permet aussi d’utiliser des signets

    • Il faut aussi installer chicken-scheme. Ensuite, l’exécuter en root
      chicken-install srfi-203
      chicken-install srtfi216
      Le ~/.csirc pour SICP ressemble à ceci
      (import scheme)
      (import (srfi 203))
      (import (srfi 216))
      (define (inc x) (+ x 1))
      (define (dec x) (- x 1))
      Ensuite, on utilise comme d’habitude user geiser et geiser pour chicken
    • Pour mémoire, le SICP est bien le livre d’Abelson et Sussman
  • Je pourrais sans doute trouver la réponse sur Internet, mais j’aimerais poser la question sur HN
    Au lycée, sur HP-UX, je me souviens que quelqu’un m’avait montré comment sauter vers un mot souligné, c’est-à-dire une référence de section, avec une combinaison de touches, mais impossible de me rappeler laquelle
    J’ai aussi vérifié man(1) et man(7), sans trouver. C’est peut-être un faux souvenir

    • Si c’était bien man, il faut garder à l’esprit que man ohman revient essentiellement à nroff -man /usr/share/man/man1/ohman.1 | $PAGER
      Autrement dit, on n’interagit pas avec man ou nroff, mais avec le pager
      Aujourd’hui, less est le plus courant, et more est très probablement less en pratique, mais autrefois il y en avait d’autres, et HPUX utilisait peut-être quelque chose comme pg
      pg venait de la lignée AT&T, more de la lignée BSD, et less de la lignée GNU
      Les trois lancent une recherche par expression régulière avec /, donc on peut trouver le terme qu’il soit souligné ou non
      less prend aussi en charge les fichiers de tags, ce qui permet de sauter au tag suivant avec t
    • Je ne connais pas bien les fonctions de visualiseur man séparé, mais vous pensez peut-être à dthelpview, le visualiseur d’aide CDE. Il pouvait peut-être afficher des pages man
    • Ça ressemble à texinfo, qu’on ouvre avec la commande info
      Ironiquement, une bonne partie de la documentation groff d’origine est écrite en texinfo : https://lists.gnu.org/archive/html/groff/2005-10/msg00107.ht...
  • Je ne sais pas pourquoi ce détail insignifiant a déclenché mon instinct de pinaillage. Peut-être parce que quelqu’un sur Internet avait un peu tort
    C’est peut-être parce que c’était inutilement centré sur Linux dès le départ, ou parce que je m’attendais à autre chose et qu’au final ce n’était qu’une courte démo de négociation de contenu avec NGINX
    Bref, il y a quelques remarques inutiles que j’ai quand même envie de faire
    À strictement parler, ce n’est pas du roff qui est renvoyé. Des éléments comme .TH ne font pas partie de roff lui-même, mais d’un package de macros destiné à l’écriture de pages man
    J’ai été déçu qu’il n’y ait pas de conversion Markdown-to-roff. Je pensais que ce serait la partie intéressante de l’article, et au moins un outil existant aurait pu être utilisé
    De même, à cause de cela, la mise en forme du texte n’est en fait pas vraiment correcte. L’entrée roff est censée avoir une phrase par ligne, afin de distinguer le . en fin de phrase du . utilisé à d’autres fins
    De plus, toute ligne commençant par . peut être interprétée comme une commande et poser problème
    Ou alors je ne suis peut-être qu’un vieux ronchon

    • Merci d’avoir partagé ça. Je ne savais pas exactement comment s’articulait la relation entre roff et man, et j’ai retouché cet article plusieurs fois pour essayer de tomber juste
      L’existence d’autres outils comme groff et nroff rendait les choses encore plus confuses
      Un article qui expliquerait simplement “ce que sont roff/les pages man/nroff/les autres variantes et comment on les utilise” suffirait largement à faire un billet de blog à part entière
      J’aurais apprécié une explication courte et claire, et je pense qu’elle serait utile à d’autres aussi
      Je voyais la conversion Markdown-to-roff comme une v2. Quand j’ai commencé à réfléchir à l’implémentation d’un parseur, quelqu’un m’a indiqué https://github.com/sunaku/md2man, et cela semble régler le problème
      Il faudra que je voie comment l’intégrer à mon site Python qui tourne sur GitHub Pages, donc il y aura un peu de travail d’adaptation
    • Moi aussi, j’ai été assez surpris qu’il n’y ait pas de conversion Markdown-to-roff
      Pandoc peut convertir du Markdown en roff de page man très facilement
      En l’insérant dans le template donné, le résultat ressemblerait davantage à une vraie page man
  • Le bon type de média, selon la RFC 4263, est text/troff : https://www.rfc-editor.org/rfc/rfc4263.html

  • Super idée. Maintenant, il ne reste plus qu’à lancer le chrono jusqu’à “proposer mes billets de blog sous forme de DOOM WAD jouable”

    • À ajouter à la liste des quelques trucs sympas où l’IA peut réellement aider