4 pontos por GN⁺ 2024-03-01 | 1 comentários | Compartilhar no WhatsApp
  • Para usuários que querem ler posts da web diretamente no terminal, o James' Coffee Blog também oferece os artigos no formato de páginas de manual do Linux
  • Mesmo com a mesma URL, se o cliente enviar Accept: text/roff, recebe um documento roff em vez de HTML, usando negociação de conteúdo HTTP
  • O arquivo .man de cada post é gerado com um template que inclui as seções TITLE, AUTHOR, PUBLISHED, POST e URL
  • No corpo, foi usado o Markdown original para torná-lo mais legível do que HTML, embora o espaçamento nem sempre fique perfeitamente alinhado na página de manual
  • O NGINX detecta requisições text/roff e reescreve a URL para um arquivo .man, permitindo salvar com curl e abrir com man ./post.page

Ler posts de blog com man

  • As páginas de manual do Linux são a forma básica de consultar o uso de comandos no terminal, normalmente abertas com man <command>
  • Por exemplo, o manual do comando tac pode ser visto assim
man tac
  • O James' Coffee Blog montou um fluxo para que posts da web também possam ser lidos da mesma forma, baixando a versão roff da URL do artigo e abrindo-a com man
  • Um exemplo real de requisição é o seguinte
curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/ > post.page && man ./post.page

Escolhendo o formato com negociação de conteúdo HTTP

  • O núcleo da implementação é a negociação de conteúdo HTTP, em que o cliente informa ao servidor qual formato de resposta deseja
  • O cabeçalho Accept é usado para transmitir o tipo de conteúdo desejado
    • Por exemplo, Accept: image/png significa “envie um arquivo PNG, se possível”
    • Também é possível especificar vários tipos de conteúdo e prioridades, mas aqui é usado apenas o pedido de um formato específico
  • Quando se quer receber um post de blog em formato de página de manual, envia-se o cabeçalho Accept: text/roff
  • Ao ver esse cabeçalho, o servidor retorna uma resposta text/roff que pode ser aberta no man, em vez de HTML

Como os arquivos .man são gerados

  • As páginas de manual do Linux são escritas na sintaxe roff
  • O site foi modificado para gerar uma versão em página man para cada post do blog
  • A estrutura do template usado é a seguinte
.TH jamesg.blog 1 "" "jamesg.blog"
.SH TITLE
...
.SH AUTHOR
James' Coffee Blog (https://jamesg.blog)
.SH PUBLISHED
...
.SH POST
...
.SH URL
...
  • O template usa o nome de domínio como cabeçalho e cria cinco seções
    • TITLE
    • AUTHOR
    • PUBLISHED
    • POST
    • URL
  • No corpo, é usado o Markdown original
    • O espaçamento na página de manual nem sempre fica perfeito
    • Ainda assim, ficou mais fácil de ler do que HTML e perdeu menos informação sobre títulos e parágrafos do que texto puro

Baixando com curl e abrindo com man

  • A versão roff de um post do blog pode ser requisitada com o seguinte comando
curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/ > post.page
  • O resultado salvo pode ser aberto como uma página de manual local
man ./post.page
  • Se um navegador comum requisitar a mesma URL do artigo, ele recebe a versão HTML
  • Já o comando curl acima solicita explicitamente a versão text/roff para a mesma URL

Reescrevendo para arquivos .man no NGINX

  • O servidor trata separadamente as requisições text/roff com algumas linhas de configuração do NGINX
  • Em /etc/nginx/nginx.conf, são declaradas variáveis que ativam uma flag quando um tipo de conteúdo específico é detectado
map $uri $redirect_suffix {
~^/(.*)/$ $1;
default "";
}
map $http_accept $redirect_location {
default "";
"~^text/roff" 1;
}
  • No arquivo de configuração do site, em /etc/nginx/sites-enabled, adiciona-se uma regra para tratar requisições de páginas roff
server {
...
location / {
if ($redirect_location = 1) {
rewrite ^/(.*)/$ /$1.man last;
}
...
}
}
  • Essa configuração remove a barra final da URL e adiciona .man quando existe o cabeçalho Accept: text/roff
  • Como resultado, o NGINX lê o arquivo .man correspondente em vez do index.html de cada post
  • Com isso, o mesmo post do blog pode ser lido em HTML no navegador e como página de manual do Linux no terminal

1 comentários

 
GN⁺ 2024-03-01
Opiniões no Hacker News
  • Seria legal oferecer um repositório deb como forma de assinatura de blog
    Algo como baixar todos os posts com apt update e poder ver o post mais recente e links para o índice de todos os posts com man your-blog

    • A ideia em si é excelente, mas, se isso se espalhar, as oportunidades de distribuição de malware inerentes a esse método também parecem bem óbvias
      Acho que eu teria medo de assinar
    • Há precedentes. O Debian antigamente oferecia acesso ao Linux Gazette, hoje extinto, e ainda fornece vários pacotes informativos, como documentação de pacotes, páginas de manual, páginas info, RFCs, Linux HOWTOs etc.
      Eles podem ser vistos localmente com o pacote dwww: “Read all on-line documentation with a WWW browser”
      https://packages.debian.org/bookworm/dwww
      Joerg Jaspert foi o antigo mantenedor do pacote Linux Gazette: https://people.debian.org/~joerg/ (2002)
      Foi um dos melhores casos que já vi de integração de entrega de informação e documentação ao sistema operacional, especialmente por tornar a documentação man/info mais útil do que as interfaces tradicionais baseadas em terminal
      Também existe o Debian Planet, um blog relacionado ao Debian, mas acho que ele nunca foi oferecido como pacote do próprio Debian
      Sinceramente, RSS provavelmente é uma opção melhor para assinar blogs
    • Estou trabalhando nisso agora
      Em https://github.com/capjamesg/jamesg.blog.deb há conteúdo para criar, com os comandos abaixo, um arquivo deb que contém apenas a página 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
      Então você deve ver uma saída como Processing triggers for man-db (2.9.1-1) ..., o que significa que a página de manual para man jamesg.blog está disponível
      Por enquanto há apenas um placeholder, e provavelmente vou finalizar amanhã
      Pode virar um post do blog em breve
  • Dá para enviar direto por pipe para o man, sem precisar fazer fork nem usar um arquivo intermediário
    curl -sL -H "Accept: text/roff" [https://jamesg.blog/2024/02/28/programming-projects/](<https://jamesg.blog/2024/02/28/programming-projects/>;) | man -l -

    • Melhor não fazer isso. Duas horas atrás o yrro postou algo parecido, e agora vai começar de novo a discussão sobre enviar {curl,wget} por pipe para comandos
      Amigos não deixam amigos enviar streams diretamente por pipe para comandos
      https://news.ycombinator.com/item?id=39554044
  • Para referência, 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 funciona no meu ambiente
    Não é preciso salvar o arquivo roff localmente

    • Acho que o autor do post original evitou fazer isso de propósito. Enviar comandos ou conteúdo recebido da internet diretamente por pipe para algo como bash costuma ser considerado uma má prática
      Pessoalmente, acho aceitável. Quem entende as implicações de segurança quase certamente também sabe fazer esse tipo de conversão, então não há necessidade de ensinar
      Mas não é bom ensinar isso a iniciantes. Um dia eles podem acabar caindo em alguma armadilha. Conforme ganharem experiência, vão descobrir naturalmente esse recurso, e espero que até lá também tenham aprendido as implicações
      O texto não é meu: https://www.seancassidy.me/dont-pipe-to-your-shell.html
    • Infelizmente, esse comando não funciona no macOS: /usr/bin/man: illegal option -- l
      Tentei criar um comando de uma linha com pipe no Mac, mas ele continuou dando erro
      A implementação de man do macOS não tem a flag -l. Conferi a página de manual
    • Se você usa bash, dá para economizar alguns caracteres usando substituição de processo em vez de pipe
      man -l <(curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/)
  • Se a conversa for sobre URLs que fazem coisas divertidas no terminal, lembro de algo que vi há tempos no textfiles.com
    Era uma forma de exibir um curta de animação usando códigos de terminal VT100, tudo servido a partir de um único URI
    Em sistemas modernos, dá para assistir aplicando um limite de velocidade
    curl --limit-rate 1000 [http://textfiles.com/sf/STARTREK/trek.vt](<http://textfiles.com/sf/STARTREK/trek.vt>;) && reset
    O reset está aí porque o terminal pode ficar bagunçado
    Outros URIs baseados em terminal: curl cheat.sh/tar busca exemplos de uso do programa depois da /, e curl wttr.in/berlin traz informações de clima formatadas para o terminal

    • Se quiser criar diretamente um vídeo em ASCII via telnet, fiz algo em Go alguns anos atrás: https://github.com/bfontaine/RickASCIIRoll
      Na prática é bem simples; a parte mais difícil é gerar os frames
      Dá para fazer isso com ffmpeg+img2txt.py: https://github.com/bfontaine/RickASCIIRoll/tree/master/movie...
    • Alguns anos atrás, criei um visualizador de arte ANSI com emulação de velocidade de modem
      Havia um mirror antigo de https://16colo.rs/, então dá para ver a maior parte da arte ANSI já publicada até hoje
      Ex.: curl ansi.hrtk.in/ungenannt_1453.ans
    • É realmente incrível, mas também destruiu completamente meu terminal. Foi divertido
    • Também há Star Wars via telnet
      https://itsfoss.com/star-wars-linux/
    • Com tritty, dá para simular velocidades de transmissão de 1200/9600 BPS
  • Agora só falta um conversor de Markdown para roff, e, ao procurar, vi que já existem alguns
    https://github.com/postmodern/kramdown-man
    https://rtomayko.github.io/ronn/ronn.1.html
    https://kristaps.bsd.lv/lowdown/

  • Há um pacote do Emacs que instala o SICP de Abelson e Sussman no diretório Info
    Basta digitar M-x package-install sicp RET
    Ao ver isso, pensei que também daria para instalar uma estante inteira de arquivos de blogs com um leitor de feeds modificado
    Ao ler Info no Emacs, também dá para usar bookmarks

    • Também é só instalar chicken-scheme. Depois execute como root
      chicken-install srfi-203
      chicken-install srtfi216
      O ~/.csirc para o SICP fica assim
      (import scheme)
      (import (srfi 203))
      (import (srfi 216))
      (define (inc x) (+ x 1))
      (define (dec x) (- x 1))
      Depois, é só usar o Geiser de usuário e o Geiser para Chicken como de costume
    • Para constar, o SICP é o livro de Abelson e Sussman
  • Talvez eu consiga descobrir a resposta pesquisando na internet, mas quero perguntar no HN
    No ensino médio, no HP-UX, lembro de alguém me mostrar como pular para uma palavra sublinhada, ou seja, uma referência de seção, usando alguma combinação de teclas, mas não consigo lembrar de jeito nenhum quais eram
    Também verifiquei man(1) e man(7), mas não encontrei. Pode ser uma falsa memória

    • Se aquilo era man, é preciso lembrar que man ohman é, essencialmente, nroff -man /usr/share/man/man1/ohman.1 | $PAGER
      Ou seja, você não está interagindo com o man nem com o nroff, mas com o pager
      Hoje em dia, less é o mais comum, e é bem provável que more também seja, na prática, less; mas antigamente havia outros, e o HPUX talvez usasse algo como pg
      pg era da linhagem AT&T, more da linhagem BSD, e less da linhagem GNU
      Todos os três iniciam uma busca por regex com /, então dá para encontrar independentemente de estar sublinhado ou não
      less também suporta arquivos de tags, então dá para pular para a próxima tag com t
    • Não conheço bem uma função separada de visualizador de man, mas talvez você esteja lembrando do dthelpview, o visualizador de ajuda do CDE. Ele pode ter exibido páginas man
    • Isso parece texinfo, aberto com o comando info
      Ironicamente, boa parte da documentação original do groff é escrita em texinfo: https://lists.gnu.org/archive/html/groff/2005-10/msg00107.ht...
  • Não sei por que esse detalhe tão pequeno ativou meu instinto de implicar. Talvez seja porque alguém na internet estava ligeiramente errado
    Talvez porque desde o início fosse desnecessariamente centrado em Linux, ou porque eu esperava outra coisa e no fim era só uma breve demonstração de negociação de conteúdo do NGINX
    De todo modo, há alguns pontos inúteis que faço questão de mencionar
    Tecnicamente, ele não está retornando roff. Coisas como .TH não são roff em si, mas parte de um pacote de macros para escrever páginas man
    Fiquei decepcionado por não haver conversão de Markdown para roff. Achei que essa seria a parte interessante do artigo, e pelo menos uma ferramenta existente poderia ter sido usada
    Da mesma forma, por causa disso, a formatação do texto na verdade também não fica correta. A entrada roff pressupõe uma linha por frase, para distinguir o . no fim de uma frase de . com outros usos
    Além disso, qualquer linha que comece com . pode ser interpretada como um comando e causar problemas
    Ou talvez eu seja apenas um velho ranzinza

    • Obrigado por compartilhar isso. Eu não sabia exatamente como era estruturada a relação entre roff e man, e tentei acertar enquanto revisava este texto várias vezes
      Fiquei ainda mais confuso por existirem outras ferramentas como groff e nroff
      Só um texto explicando “o que são roff/páginas man/nroff/outras variantes e como usá-los” já daria um post de blog por si só
      Eu teria gostado de uma explicação curta e clara, e acho que também ajudaria outras pessoas
      Pensei em Markdown para roff como uma v2. Quando comecei a pensar em implementar um parser, alguém me indicou https://github.com/sunaku/md2man, e isso parece resolver o problema
      Ainda preciso descobrir como integrar isso ao meu site em Python rodando sobre GitHub Pages, então vou ter que ajustar um pouco
    • Também fiquei bem surpreso por não haver conversão de Markdown para roff
      O Pandoc consegue converter Markdown para roff de página man com muita facilidade
      Se você colocar isso em um template apropriado, vai parecer bem mais uma página man de verdade
  • O tipo de mídia correto, segundo a RFC 4263, é text/troff: https://www.rfc-editor.org/rfc/rfc4263.html

  • Ideia bacana. Agora é só ligar o cronômetro até aparecer “oferecendo meus posts de blog como um DOOM WAD jogável”

    • Dá para acrescentar isso à lista das poucas coisas legais em que a IA pode realmente ajudar