Migrando do Jekyll Para Org Mode E Ações Github

Table of Contents

1 Introdução

Meu website era até agora gerado pelo Github Pages usando uma ferramenta de geração de sites estáticos chamada Jekyll e o tema Lagom.

2 Github Pages

Github Pages permite hospedar sites estáticos em repositórios Github de graça. É bem simples, você simplesmente coloca o webs em um ramo (e.g. gh-pages) e o Github o servirá como username.github.io/repo/, ou mediante um domínio customizado adicionando um simples arquivo de texto CNAME ao repositório.

3 Geradores de Sites Estáticos

Se você não quer editar o HTML diretamente, pode usar um gerador de site estático para manter um conjunto de gabaritos e conteúdo no repositório git e colocando a saída do gerador (os arquivos HTML) no ramo gh-branch para ser servido pelo Github.

Além de poder escrever o conteúdo em Markdown, geradores de sites estáticos tornam muito mais fácil manter conteúdo como um blog, com características como gabaritos distintos para as postagens, destaque de sintaxe para os códigos, rascunhos e suporte para temas, que permitem modificar a aparência e a forma do site mudando apenas uma opção de configuração e regenerando-o.

Se você quer que este processo seja automático, vodê pode executar a geração como parte de algum trabalho de integração contínua (e.g. com o TravisCI), tal que o site é regenerado quando seus fontes são atualizados.

4 Suporte a Jekyll em Github Pages

Jekyll é um destes geradores de site estático e foi o mais popular por um tempo. A parte legal era que se você usasse Jekyll, Github Pages geraria seu site automaticamente, sem ter que configurar um sistema de integração contínua. Apenas insira suas mudanças e no minuto seguinte seu site era publicado.

Por outro lado, você estava limitado a usar a versão de Jekyll que estivesse instalada no Github, e não poderia simplesmente instalar qualquer adicional que quisesse. Você não podia controlar o ambiente no mesmo nível que faria num sistema de integração contínua típico.

5 Saindo do Jekyll

Jekyll simplesmente funcionava. Eu não posso reclamar disso. Porém, eu me sentia tão amarrado a um ano atrás e vivia com plugins que o ambiente suportava, e mais nada.

Se eu configurasse meu próprio fluxo de integração para superar essa limitação, por que continuar a usar Jekyll? Hugo começava a parecer mais rápido, mais fácil de implantar localmente e majoritariamente compatível.

Eu tenho usado Emacs por mais de dez anos. Há três anos, eu mudei meus clientes de e-mail do Thunderbird para mu4e em cima do Emacs. Então eu descobri o org-mode como sistema de organização pessoal em texto puro e gradualmente comecei a viver mais tempo dentro do Emacs. Microsoft fez um trabalho tão com Visual Studio Code que por um momento eu pensei que não iria resistir. Porém, Microsoft criou um ecossistema fazendo a interação entre linguagens de programação um padrão, mediante o Language Server Protocol, e emacs-lsp tornou minha experiência de programação com o Emacs simplesmente melhor.

Eu sabia que o org-mode era muito bom em exportação. Depois de eu ter visto um par de websites gerados de arquivos org, eu comecei a brincar com a ideia de usar org também. Esta também seria uma boa oportunidade de aprender Emacs Lisp de verdade. Então eu comecei a aprender sobre org e websites.

6 Inspiração

Como eu não sabia por onde começar, eu comecei lendo um monte de soluções de outras pessoas, documentação, posts &c.

A maior parte da estrutura desta solução final, suas ideias, convenções, configurações e alguns trechos foram retirados dos projetos a seguir:

7 Implementação

7.1 Princípios

Uma vez que eu tinha uma clara figura do domínio, eu decidi como eu queria e meus próprios requerimentos:

  • Usar o máximo de pacotes padrão possível, e.g. org-publish. Evitar o uso de "frameworks" em cima do emacs/org
  • Ligações para posts antigos deveriam continuar funcionando (eu configurei o Jekyll para usar /year/month/day/post-name.html)
  • Links para posts antigos deveriam continuar funcionando (eu tinha configurado o Jekyll para usar /year/month/day/post-name.html)
  • Inicialmente, eu pensei na possibilidade de migrar o conteúdo gradualmente, e.g. mantendo posts em Markdown por um tempo
  • Autocontido. Tudo deveria estar contido em um único repositório git, sem interferir no meu emacs.d
  • Capacidade de executá-lo da linha de comando, de forma que a integração contínua pudesse ser usada para gerar automaticamente o site a partir do repositório.

8 Conceitos do Emacs a Serem Usados

Existe uma série de conceitos do Emacs que ajudam a juntar todas as peças:

8.1 Modo batch do Emacs

Apesar de eu poder ter colocado a maior parte da configuração em meu ~/.emacs.d/init.el, eu queria uma solução autocontida, sem depender de minha configuração pessoal do Emacs estar sempre disponível.

Existe uma porção de opções do Emacs que auxilia a alcançar este objetivo:

Com estas opções, podemos colocar toda a nossa configuração e funções auxiliares em um arquivo elisp, executar o Emacs como uma máquina de script, ignorar a configuração pessoal, carregar o arquivo com a configuração e chamar a função que executa tudo.

9 Org Mode Export (ox)

O Org Mode inclui um sub-sistema de exportação com diversos formatos-alvo (ASCII, beamer, HTML, &c.). Cada conversor é um conjunto de funções que toma as estruturas org já analisadas (e.g. lista, marca de tempo, parágrafo) e converte para o formato-alvo. Worg, uma seção do website do Org Mode que é escrita por uma comunidade de voluntários fãs do Org Mode, fornece documentação sobre como definir um backend de exportação (org-export-define-backend). Daqui é importante entender o sistema de filtros e o org-export-define-derived-backend, que permite definir um backend sobrescrevendo um já existente. É isto o queneu usarei para modificar como, por exemplo, as marcas de tempo são exportadas.

10 org-publish

Org Mode inclui um sistema de gerenciamento de publicação que ajuda a exportar um conjunto interligado de arquivos Org. Também tem um belo tutorial disponível.

Usar org-publish consiste em definir uma lista de componentes (postagens do blog, RSS, recursos), suas opções (diretório base, diretório alvo, exclusões e inclusões, função de publicação), sendo a função de publicação uma das mais importantes, dado que o org vem com algumas predefinidas e.g org-html-publish-to-html para publicar arquivos em HTML e org-publish-attachment para publicar recursos estáticos. A coisa mais importante a aprender aqui é que você pode envelopá-los em suas próprias coisas adicionais e customizar a publicação muito facilmente. Eu uso isto para, por exemplo, ignorar os posts de rascunho ou escrever arquivos de redireção para certos posts além do próprio.

11 A Solução

11.1 Estrutura de Diretórios

Dentro da árvore de diretórios, você pode encontrar:

  • um arquivo publish.el com a descrição do projeto e todo o código de suoporte e funções auxiliares
  • Um arqivo CNAME para informar ao Github Pages o nome do meu domínio
  • Um diretório com um arquivo CSS para o site todo. Outro é incluído somente na página de índice
  • Um Makefile que simplesmente invoca o Emacs com os parâmetros que descrevemos acima e chama a função duncan-publish-all
  • Um subdiretório para cada post, e mais um para os tutoriais
  • Um diretório público onde os arquivos de saída são gerados e os recursos estáticos copiados
  • Um diretório de trechos de código com códigos de preâmbulo, postâmbulo e Google Analytics

11.2 publish.el

O arquivo principal contendo o código e a configuração inclui algumas funções de publicação customizadas que são usadas como ganchos para a publicação e criação de sitemaps.

11.3 Projeto do org-publish

O projeto do org-publish (org-publish-project-alist) é definido na variável duncan–publish-project-alist, e define os componentes a seguir:

11.3.1 blog

Este componente lê todos os arquivos org no diretório ./posts/, e os exporta para para HTML usando duncan/org-html-publish-post-to-html como função de publicação.

Esta função injeta a data como subtítulo da página na lista de propriedades antes de delegar para a função original. Este é um padrão comum que você pode usar para sobrescrever a função de publicação. Note que o subtítulo é uma propriedade de configuração do backend de exportação HTML reconhecida.

(defun duncan/org-html-publish-post-to-html (plist filename
pub-dir)
  "Wraps org-html-publish-to-html.  Append post date as subtitle to PLIST.
  FILENAME and PUB-DIR are passed."
  (let ((project (cons 'blog plist)))
    (plist-put plist :subtitle
               (format-time-string "%b %d, %Y" (org-publish-find-date filename
                                                                      project)))
    (duncan/org-html-publish-to-html plist filename pub-dir)))

A função também verifica a propriedade #+REDIRECT_TO e gera páginas de redireção de acordo, criando outra exportação para um caminho diferente no mesmo pub_dir.

Este componente é configurado com uma função sitemap que, mesmo se passar por todos os posts é programada para tomar apenas alguns e escrever um arquivo Org com links para eles. Este arquivo (posts.org) é então incluído em index.org e usado como lista de posts recentes.

11.3.2 archive-rss

Este componente também opera em /.posts/, mas em vez de gerar HTML, usa o backend RSS para gerar um arquivo completo do site como RSS.

A função sitemap também é configurada, assim como no componente blog, mas esta função gera um arquivo Org com todos os posts, não apenas os mais recentes. A função sitemap-format-entry é compartilhada entre as funções sitemap, dado que a lista de posts é semelhante.

sitemap-function.png

11.3.3 site

O restante do conteúdo do site, incluindo a página index.org e os arquivos org gerados para o arquivo (archive.org) e os posts recentes (posts.org)

11.3.4 assets

Todos os arquivos que são simplesmente copiados

11.3.5 tutorials

Funciona como os posts, mas eu configuro cada um (não espero que tenham muitos) para usar o tema ReadTheOrg. Ele usa a função padrão de publicação HTML.

readtheorg.png

11.4 Fluxo de exportação

publishing-function.png

12 Aparência

Eu consegui portar a maior parte da aparência do tema Lagom iniciando um CSS do zero (aprendi CSS Grid no processo) e consertando cada diferença manualmente. Eu fiquei bem satisfeito com o resultado final. Eu tive que usar algum CSS específico para certas páginas a fim de esconder o título na página inicial ou exibir ícones FontAwesome.

12.1 Antes

jekyll.png

12.2 Depois

org.png

13 Publicação

Ainda que localmente se possa testar executando o Emacs pelo Makefile, eu queria uma forma nova de executar a geração em cada git push:

  • Comecei com o Travis, mas não consegui mais encontrar trabalhos de contêiner. Quando eu notei que o Ubuntu tinha uma versão do Emacs mais antiga eu simplesmente perdi o interesse.
  • Gitlab foi fácil de fazer funcionar. Não somente porque é bem simples e elegante, mas alguns dos exemplos dos quais tomei inspiração já estavam usando-o, junto à imagem contêiner do Emacs Alpine. Porém, eu não queria ter tudo no Github, exceto meu site.
  • Daí notei que Github Actions estava em beta, mas ainda não estava dentro. Até que:

    https://twitter.com/natfriedman/status/1165778104280707072

13.1 Estabelecendo um fluxo de trabalho para montar o site

Enquanto no Linux ações do Github rodam em Ubuntu, elas permitem executar uma ação dentro de um contêiner.

name: Build and publish to pages
on:
  push:
    branches:
    - master

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
      with:
        fetch-depth: 1
    - name: build
      uses: docker://iquiw/alpine-emacs
      if: github.event.deleted == false
      with:
        args: ./build.sh
    - name: deploy
      uses: peaceiris/[email protected]
      if: success()
      env:
        GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
        PUBLISH_BRANCH: gh-pages
        PUBLISH_DIR: ./public

Combinando actions/checkout, nosso próprio script de montagem rodando como contêiner docker://iquiw/alpine-emacs dentro da máquina virtual, e peaceiris/actions-gh-pages, obtemos os resultados desejados.

Como aviso, você precisa configurar um token de acesso pessoal para a ação, dado que o padrão não vai funcionar e o que é postado para o gh-pages não será mostrado em seu website.

A experiência com Github Actions foi bastante positiva. Eu definitivamente substituirei a maior parte do meu uso de TravisCI em meus repositórios. Parabéns ao time do Github.

14 Conclusões

Não apenas eu tenho um website executado pela ferramenta que eu uso diariamente, mas também empacotado com características impressionantes. Por exemplo, os diagramas neste post são postos inline como código PlantUML no arquivo Org e exportados via Org Babel.

Isso também me dei um projeto para aprender Emacs Lisp. Eu planejo adicionar algumas características, como tags ou categorias e talvez comentários. O aprendizado também beneficiará a personalização do meu editor e cliente de e-mail.

Os fontes deste site estão disponíveis no Github.

15 META

Author: Tradutor Bastardo

Created: 2020-04-04 sáb 03:17

Validate