www

My personal website(s)
Log | Files | Refs

2020-03-22-org-mode-website.html (31532B)


      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4 <!-- Sep 03, 2024 -->
      5 <meta charset="utf-8" />
      6 <meta name="viewport" content="width=device-width, initial-scale=1" />
      7 <title>Migrating to an org-mode website</title>
      8 <meta name="author" content="Vincent Demeester" />
      9 <meta name="generator" content="Org Mode" />
     10 <link rel='icon' type='image/x-icon' href='/images/favicon.ico'/>
     11 <meta name='viewport' content='width=device-width, initial-scale=1'>
     12 <link rel='stylesheet' href='/css/new.css' type='text/css'/>
     13 <link rel='stylesheet' href='/css/syntax.css' type='text/css'/>
     14 <link href='/index.xml' rel='alternate' type='application/rss+xml' title='Vincent Demeester' />
     15 </head>
     16 <body>
     17 <main id="content" class="content">
     18 <header>
     19 <h1 class="title">Migrating to an org-mode website</h1>
     20 </header><section id="outline-container-Introduction" class="outline-2">
     21 <h2 id="Introduction">Introduction</h2>
     22 <div class="outline-text-2" id="text-Introduction">
     23 <p>
     24 This is a story… a story of me changing the way I code and publish my website. In the
     25 past, I&rsquo;ve switch from <a href="https://vincent.demeester.fr/posts/2012-05-07-reinit-and-jekyll/">Jekyll</a> to <a href="https://vincent.demeester.fr/posts/2015-05-01-orgmode-et-jekyll/">&ldquo;<code>orgmode</code> and Jekyll&rdquo;</a> to <a href="https://vincent.demeester.fr/posts/2015-05-09-migration-to-hugo/">Hugo</a> (sorry those are written
     26 in french). The past year, I&rsquo;ve written and documented myself a little bit about
     27 <a href="https://www.theminimalists.com/minimalism/">minimalism</a> and <a href="https://www.goodreads.com/book/show/40672036-digital-minimalism">digital minimalism</a>. Although I don&rsquo;t see myself as a minimalist, it helped
     28 me realize some issues I had.
     29 </p>
     30 
     31 <p>
     32 I also realized if I want to write more, I need to lower the barrier between writing and
     33 publishing my content ; <i>if I want it to be published, of course</i>. This <i>post</i> is about
     34 what I&rsquo;m putting in place for this, with a premise : I spend my life in <a href="https://www.gnu.org/software/emacs/">Emacs</a> and thus in
     35 <a href="https://orgmode.org/"><code>orgmode</code></a>. And <a href="https://orgmode.org/"><code>orgmode</code></a> is feature-full and has this badass feature : <code>org-publish</code>.
     36 </p>
     37 
     38 <p>
     39 To build and publish this website, we will <i>try</i> to rely on a reproducible setup, meaning
     40 <a href="https://www.gnu.org/software/emacs/">Emacs</a> and <a href="https://orgmode.org/"><code>orgmode</code></a> of course, <a href="https://www.gnu.org/software/make/">GNU Make</a> of course <b>but</b> most importantly, <a href="https://nixos.org/nix/">Nix</a> (in the near
     41 future 👼).
     42 </p>
     43 
     44 <div class='drawer update'>
     45 <h6>Update</h6>
     46 <p>
     47 There is now an article about it, that uses literate programming: <a href="../articles/meta_publishing_this_website.html">publishing this
     48 website</a>. The content of the post might no be up-to-date at some point.
     49 </p>
     50 </div>
     51 </div>
     52 </section>
     53 <section id="outline-container-Requirements" class="outline-2">
     54 <h2 id="Requirements">Requirements</h2>
     55 <div class="outline-text-2" id="text-Requirements">
     56 <p>
     57 Let&rsquo;s list the requirements I feel I have for my website:
     58 </p>
     59 
     60 <dl class="org-dl">
     61 <dt>Full control over the URL of the published posts.</dt><dd>This is a golden rule of the web: should I change the publishing system, I want to be
     62 able to stick to the same URLs or else all external references would be broken. This is
     63 a big no-no and in my opinion it makes most blogging systems unacceptable.</dd>
     64 <dt>Top-notch Org support.</dt><dd>I believe generators like Jekyll and Hugo only have partial Org support. You end up
     65 requiring some conversion tooling to get the job done.</dd>
     66 <dt>Simple publishing pipeline.</dt><dd>I want the generation process to be as simple as possible. This is important for
     67 maintenance. Should I someday switch host, I want to be sure that I can set up the same
     68 pipeline.</dd>
     69 <dt>Full control over the publishing system.</dt><dd>I want maximum control over the generation process. I don’t want to be restricted by a
     70 non-Turing-complete configuration file or a dumb programming language.</dd>
     71 <dt>Ease of use.</dt><dd>The process as a whole must be as immediate and friction-less as possible, or else I
     72 take the risk of feeling too lazy to publish new posts and update the content.</dd>
     73 <dt>Hackability.</dt><dd>Last but not least, and this probably supersedes all other requirements: The system must
     74 be hackable. Lisp-based systems are prime contenders in that area.</dd>
     75 </dl>
     76 </div>
     77 </section>
     78 <section id="outline-container-Organizing" class="outline-2">
     79 <h2 id="Organizing"><span class="done DONE">DONE</span> Organizing</h2>
     80 <div class="outline-text-2" id="text-Organizing">
     81 <div class='drawer logbook'>
     82 <h6>Logbook</h6>
     83 <ul class="org-ul">
     84 <li>State &ldquo;DONE&rdquo;       from &ldquo;TODO&rdquo;       <span class="timestamp-wrapper"><span class="timestamp">[2020-03-21 Sat 17:57]</span></span></li>
     85 </ul>
     86 </div>
     87 
     88 <p>
     89 Let&rsquo;s describe what I do want to publish here:
     90 </p>
     91 
     92 <dl class="org-dl">
     93 <dt>Posts</dt><dd>this is what we call <i>blog</i> these days : short to medium article that are valid
     94 at a point of time, as may contain <i>deprecated</i> content, or content that do not reflect
     95 my views at a later point in time.</dd>
     96 <dt>Articles</dt><dd>medium to long article about a topic. Those should be up-to-date or
     97 explicitly mark as deprecated or invalid. <i>In a ideal world this is my <b>ready for the
     98 public</b> knowledge database, a bit like <a href="https://braindump.jethro.dev/">Jethro&rsquo;s Braindump</a></i>.</dd>
     99 <dt>Configurations</dt><dd>medium to long article about my configurations. Those are base on my
    100 <code>home</code> <i>configuration</i> mono-repository, and usually follow literate programming
    101 principles.</dd>
    102 <dt>About</dt><dd>an about page about the author of the website (aka <a href="https://vincent.demeester.fr">me</a>), linking external
    103 contributions (GitHub/Gitlab/… profiles, Talks, …).</dd>
    104 </dl>
    105 </div>
    106 </section>
    107 <section id="outline-container-Publishing" class="outline-2">
    108 <h2 id="Publishing"><span class="done DONE">DONE</span> Publishing</h2>
    109 <div class="outline-text-2" id="text-Publishing">
    110 <div class='drawer logbook'>
    111 <h6>Logbook</h6>
    112 <ul class="org-ul">
    113 <li>State &ldquo;DONE&rdquo;       from &ldquo;TODO&rdquo;       <span class="timestamp-wrapper"><span class="timestamp">[2020-03-25 Wed 15:54]</span></span></li>
    114 </ul>
    115 </div>
    116 
    117 <p>
    118 As said above, the goal is to publish everything using only <a href="https://www.gnu.org/software/emacs/">Emacs</a> and <a href="https://orgmode.org/"><code>orgmode</code></a> (with the
    119 help of some standard GNU tools).
    120 </p>
    121 
    122 <p>
    123 The <a href="file:///home/vincent/src/sbr/publish.el"><code>publish.el</code></a> file is where all the magic happens:
    124 </p>
    125 
    126 <ul class="org-ul">
    127 <li><p>
    128 I want to generate something that is <code>html5</code> (almost?). The <i>preamble</i>, <i>content</i> and
    129 <i>postamble</i> <code>div</code> can be customized using <code>org-html-div</code>. Same goes for the <i>container</i>
    130 element that is used for &ldquo;wrapping top level sections&rdquo;, it is customized using
    131 <code>org-html-container-helement</code> (we want <code>&lt;section&gt;</code>). There is a few additional variable
    132 that I might document one day 😛.
    133 </p>
    134 
    135 <div class="org-src-container">
    136 <pre class="src src-emacs-lisp">(setq org-export-use-babel nil)
    137 (setq org-link-abbrev-alist '(("att" . org-attach-expand-link)))
    138 
    139 ;; setting to nil, avoids "Author: x" at the bottom
    140 (setq org-export-with-section-numbers nil
    141       org-export-with-smart-quotes t
    142       org-export-with-toc nil)
    143 
    144 (defvar sbr-date-format "%b %d, %Y")
    145 
    146 (setq org-html-divs '((preamble "header" "top")
    147                       (content "main" "content")
    148                       (postamble "footer" "postamble"))
    149       org-html-container-element "section"
    150       org-html-metadata-timestamp-format sbr-date-format
    151       org-html-checkbox-type 'unicode
    152       org-html-html5-fancy t
    153       org-html-doctype "html5"
    154       org-html-htmlize-output-type 'css
    155       org-html-htmlize-font-prefix "org-"
    156       org-src-fontify-natively t
    157       org-html-coding-system 'utf-8-unix)
    158 </pre>
    159 </div></li>
    160 
    161 <li>Part of the <code>&lt;head&gt;</code>, preamble and postamble are customized for the website.
    162 <dl class="org-dl">
    163 <dt><code>head</code></dt><dd><div class="org-src-container">
    164 <pre class="src src-emacs-lisp">(defvar sbr-website-html-head
    165   "&lt;link rel='icon' type='image/x-icon' href='/images/favicon.ico'/&gt;
    166 &lt;meta name='viewport' content='width=device-width, initial-scale=1'&gt;
    167 &lt;link rel='stylesheet' href='/css/new.css' type='text/css'/&gt;
    168 &lt;link rel='stylesheet' href='/css/syntax.css' type='text/css'/&gt;
    169 &lt;link href='/index.xml' rel='alternate' type='application/rss+xml' title='Vincent Demeester' /&gt;")
    170 </pre>
    171 </div></dd>
    172 <dt>premable</dt><dd><div class="org-src-container">
    173 <pre class="src src-emacs-lisp">(defun sbr-website-html-preamble (plist)
    174   "PLIST: An entry."
    175   ;; Skip adding subtitle to the post if :KEYWORDS don't have 'post' has a
    176   ;; keyword
    177   (when (string-match-p "post" (format "%s" (plist-get plist :keywords)))
    178     (plist-put plist
    179                :subtitle (format "Published on %s by %s."
    180                                  (org-export-get-date plist sbr-date-format)
    181                                  (car (plist-get plist :author)))))
    182 
    183   ;; Below content will be added anyways
    184   "&lt;nav&gt;
    185 &lt;img src=\"/images/favicon.ico\" id=\"sitelogo\"/&gt; &lt;a href='/'&gt;home&lt;/a&gt; /
    186 &lt;a href='/posts/'&gt;posts&lt;/a&gt; (&lt;a href='/index.xml'&gt;rss&lt;/a&gt;) /
    187 &lt;a href='/articles/'&gt;articles&lt;/a&gt; /
    188 &lt;a href='/configurations/'&gt;configurations&lt;/a&gt; /
    189 &lt;a href='https://dl.sbr.pm/'&gt;files&lt;/a&gt; /
    190 &lt;a href='/about/'&gt;about&lt;/a&gt;&lt;/li&gt;
    191 &lt;/nav&gt;")
    192 </pre>
    193 </div></dd>
    194 <dt>postamble</dt><dd><div class="org-src-container">
    195 <pre class="src src-emacs-lisp">(defvar sbr-website-html-postamble
    196   "&lt;footer&gt;
    197      &lt;span class='questions'&gt;Questions, comments ? Please use my &lt;a href=\"https://lists.sr.ht/~vdemeester/public-inbox\"&gt;public inbox&lt;/a&gt; by sending a plain-text email to &lt;a href=\"mailto:~vdemeester/public-inbox@lists.sr.ht\"&gt;~vdemeester/public-inbox@lists.sr.ht&lt;/a&gt;.&lt;/span&gt;
    198      &lt;span class='opinions'&gt;Opinions stated here are my own and do not express the views of my employer, spouse, children, pets, neighbors, secret crushes, favorite authors, or anyone else who is not me. And maybe not even me, depending on how old this is.&lt;/span&gt;
    199      &lt;span class='copyright'&gt;
    200       Content and design by Vincent Demeester
    201       (&lt;a rel='licence' href='http://creativecommons.org/licenses/by-nc-sa/3.0/'&gt;Some rights reserved&lt;/a&gt;)
    202     &lt;/span&gt;&lt;br /&gt;
    203     &lt;span class='engine'&gt;
    204       Powered by &lt;a href='https://www.gnu.org/software/emacs/'&gt;Gnu Emacs&lt;/a&gt; and &lt;a href='https://orgmode.org'&gt;orgmode&lt;/a&gt;
    205     &lt;/span&gt;
    206 &lt;/footer&gt;")
    207 </pre>
    208 </div></dd>
    209 </dl></li>
    210 <li><p>
    211 <code>orgmode</code> is able to generate a site-map. This is what we are going to use to generate
    212 the index files for <code>posts/</code> and <code>articles</code> mainly.
    213 </p>
    214 <div class="org-src-container">
    215 <pre class="src src-emacs-lisp">(defun sbr/org-sitemap-format-entry (entry style project)
    216   "Format posts with author and published data in the index page.
    217 
    218 ENTRY: file-name
    219 STYLE:
    220 PROJECT: `posts in this case."
    221   (cond ((not (directory-name-p entry))
    222          (format "%s — [[file:%s][%s]]
    223                  :PROPERTIES:
    224                  :PUBDATE: [%s]
    225                  :END:"
    226                  (format-time-string "%Y-%m-%d"
    227                                      (org-publish-find-date entry project))
    228                  entry
    229                  (org-publish-find-title entry project)
    230                  (format-time-string "%Y-%m-%d"
    231                                      (org-publish-find-date entry project))))
    232         ((eq style 'tree) (file-name-nondirectory (directory-file-name entry)))
    233         (t entry)))
    234 
    235 (defun sbr/org-publish-sitemap (title list)
    236   ""
    237   (concat "#+TITLE: " title "\n\n"
    238           (org-list-to-subtree list)))
    239 </pre>
    240 </div></li>
    241 <li><p>
    242 <code>orgmode</code> is able to generate a rss, with <code>ox-rss</code>. This is what we are going to use to
    243 generate the rss files for <code>posts</code> and <code>articles</code>. This is <span class="underline">heavily</span> customized.
    244 </p>
    245 <div class="org-src-container">
    246 <pre class="src src-emacs-lisp">(defun sbr/org-get-first-paragraph (file)
    247   "Get string content of first paragraph of file."
    248   (ignore-errors
    249     (with-temp-buffer
    250     (insert-file-contents file)
    251     (goto-char (point-min))
    252     (show-all)
    253     (let ((first-begin (progn
    254                          (org-forward-heading-same-level 1)
    255                          (next-line)
    256                          (point)))
    257           (first-end (progn
    258                        (org-next-visible-heading 1)
    259                        (point))))
    260       (buffer-substring first-begin first-end)))))
    261 
    262 (defun sbr/org-rss-publish-to-rss (plist filename pub-dir)
    263   "Prepare rss.org file before exporting."
    264   (let* ((postsdir (plist-get plist :base-directory)))
    265     (with-current-buffer (find-file filename)
    266       (erase-buffer)
    267       (insert "#+TITLE: Posts\n")
    268       (insert "#+AUTHOR: Vincent Demeester\n")
    269       (insert "#+OPTIONS: toc:nil\n")
    270       (let* ((files-all
    271               (reverse (directory-files "." nil
    272                                         "[0-9-]+.*\\.org$")))
    273              (files (subseq files-all 0 (min (length files-all) 30))))
    274         (message (format "foo: %s" filename))
    275         (dolist (post files)
    276           (let* ((post-file post)
    277                  (post-title (org-publish-find-title post-file plist))
    278                  (preview-str (sbr/org-get-first-paragraph post-file))
    279                  (date (replace-regexp-in-string
    280                         "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-.*"
    281                         "\\1" post)))
    282             (insert (concat "* [[file:" postsdir "/" post "][" post-title "]]\n\n"))
    283             (org-set-property "ID" post)
    284             (org-set-property "RSS_TITLE" post-title)
    285             ;; ox-rss prepends html-link-home to permalink
    286             (org-set-property "RSS_PERMALINK"
    287                               (concat postsdir "/"
    288                                       (file-name-sans-extension post)
    289                                       ".html"))
    290             (org-set-property
    291              "PUBDATE"
    292              (format-time-string
    293               "&lt;%Y-%m-%d %a %H:%M&gt;"
    294               (org-time-string-to-time
    295                (replace-regexp-in-string
    296                 "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-.*"
    297                 "\\1" post))))
    298             (insert preview-str)
    299             (newline 1)
    300             (insert (concat "[[file:" postsdir "/" post "][(Read more)]]\n\n"))))
    301         (save-buffer))))
    302   (let ((user-mail-address "t")
    303         (org-export-with-broken-links t)
    304         (org-rss-use-entry-url-as-guid nil))
    305     (org-rss-publish-to-rss plist filename pub-dir)))
    306 </pre>
    307 </div></li>
    308 <li><p>
    309 Finally let&rsquo;s set the <code>org-publish-project-alist</code> to publish our projects
    310 </p>
    311 <div class="org-src-container">
    312 <pre class="src src-emacs-lisp">(setq org-publish-project-alist
    313       `(("posts"
    314          :base-directory "posts"
    315          :base-extension "org"
    316          :recursive t
    317          :publishing-function org-html-publish-to-html
    318          :publishing-directory "./public/posts"
    319          :exclude ,(regexp-opt '("README.org" "draft"))
    320          :auto-sitemap t
    321          :with-footnotes t
    322          :with-toc nil
    323          :with-drawers t
    324          :sitemap-filename "index.org"
    325          :sitemap-title "Posts"
    326          :sitemap-format-entry sbr/org-sitemap-format-entry
    327          :sitemap-style list
    328          :sitemap-sort-files anti-chronologically
    329          :sitemap-function sbr/org-publish-sitemap
    330          :html-head-include-scripts nil
    331          :html-head-include-default-style nil
    332          :html-head ,sbr-website-html-head
    333          :html-preamble sbr-website-html-preamble
    334          :html-postamble ,sbr-website-html-postamble)
    335         ("posts-rss"
    336          :base-directory "posts"
    337          :base-extension "org"
    338          :recursive t
    339          :html-link-home "https://vincent.demeester.fr/"
    340          :rss-link-home "https://vincent.demeester.fr/posts/"
    341          :html-link-use-abs-url t
    342          :rss-extension "xml"
    343          :publishing-directory "./public"
    344          :publishing-function (sbr/org-rss-publish-to-rss)
    345          :section-number nil
    346          :exclude ".*"
    347          :include ("index.org"))
    348         ("articles"
    349          :base-directory "articles"
    350          :base-extension "org"
    351          :recursive t
    352          :publishing-function org-html-publish-to-html
    353          :publishing-directory "./public/articles"
    354          :exclude ,(regexp-opt '("README.org" "draft"))
    355          :auto-sitemap t
    356          :with-footnotes t
    357          :with-toc nil
    358          :with-drawers t
    359          :sitemap-filename "sitemap.org"
    360          :sitemap-title "Articles"
    361          :sitemap-style tree
    362          :sitemap-sort-files anti-chronologically
    363          ;;:sitemap-format-entry sbr/org-sitemap-format-entry
    364          ;;:sitemap-function sbr/org-publish-sitemap
    365          :html-head-include-scripts nil
    366          :html-head-include-default-style nil
    367          :html-head ,sbr-website-html-head
    368          :html-preamble sbr-website-html-preamble
    369          :html-postamble ,sbr-website-html-postamble)
    370         ("articles-assets"
    371          :exclude ,(regexp-opt '("*.org"))
    372          :base-directory "articles"
    373          :base-extension ,site-attachments
    374          :publishing-directory "./public/articles"
    375          :publishing-function org-publish-attachment
    376          :recursive t)
    377         ("about"
    378          :base-directory "about"
    379          :base-extension "org"
    380          :exclude ,(regexp-opt '("README.org" "draft"))
    381          :index-filename "index.org"
    382          :recursive nil
    383          :with-footnotes t
    384          :with-toc nil
    385          :with-drawers t
    386          :publishing-function org-html-publish-to-html
    387          :publishing-directory "./public/about"
    388          :html-head-include-scripts nil
    389          :html-head-include-default-style nil
    390          :html-head ,sbr-website-html-head
    391          :html-preamble sbr-website-html-preamble
    392          :html-postamble ,sbr-website-html-postamble)
    393         ("index"
    394          :base-directory ""
    395          :base-extension "org"
    396          :exclude ,(regexp-opt '("README.org" "draft"))
    397          :index-filename "index.org"
    398          :recursive nil
    399          :with-footnotes t
    400          :with-toc nil
    401          :with-drawers t
    402          :with-title nil
    403          :publishing-function org-html-publish-to-html
    404          :publishing-directory "./public"
    405          :html-head-include-scripts nil
    406          :html-head-include-default-style nil
    407          :html-head ,sbr-website-html-head
    408          :html-preamble sbr-website-html-preamble
    409          :html-postamble ,sbr-website-html-postamble)
    410         ("css"
    411          :base-directory "./css"
    412          :base-extension ,site-attachments
    413          :recursive t
    414          :publishing-directory "./public/css"
    415          :publishing-function org-publish-attachment
    416          :recursive t)
    417         ("images"
    418          :base-directory "./images"
    419          :base-extension ,site-attachments
    420          :publishing-directory "./public/images"
    421          :publishing-function org-publish-attachment
    422          :recursive t)
    423         ("assets"
    424          :base-directory "./assets"
    425          :base-extension ,site-attachments
    426          :publishing-directory "./public/assets"
    427          :publishing-function org-publish-attachment
    428          :recursive t)
    429         ("legacy"
    430          :base-directory "./legacy"
    431          :base-extension ,site-attachments
    432          :publishing-directory "./public/"
    433          :publishing-function org-publish-attachment
    434          :recursive t)
    435         ("all" :components ("posts" "about" "index" "articles" "articles-assets" "css" "images" "assets" "legacy" "posts-rss"))))
    436 </pre>
    437 </div></li>
    438 </ul>
    439 
    440 <p>
    441 Here are some <i>inspiration</i> I took for this publishing code:
    442 </p>
    443 
    444 <ul class="org-ul">
    445 <li><a href="https://thibaultmarin.github.io/blog/posts/2016-11-13-Personal_website_in_org.html">Personal website in org</a></li>
    446 <li><a href="https://vicarie.in/posts/blogging-with-org.html">Blogging with Org publishing</a></li>
    447 <li><a href="https://ambrevar.xyz/blog-architecture/">A blog in pure Org/Lisp</a></li>
    448 <li><a href="https://zngguvnf.org/2017-07-13--blogging-with-org-static-blog.html">Blogging with org-static-blog</a></li>
    449 <li><a href="https://bastibe.de/2013-11-13-blogging-with-emacs.html">Blogging with Emacs</a></li>
    450 <li><a href="https://gjhenrique.com/meta.html">Blogging with org-mode and Gitlab Pages</a></li>
    451 </ul>
    452 </div>
    453 </section>
    454 <section id="outline-container-Styling" class="outline-2">
    455 <h2 id="Styling"><span class="done DONE">DONE</span> Styling</h2>
    456 <div class="outline-text-2" id="text-Styling">
    457 <div class='drawer logbook'>
    458 <h6>Logbook</h6>
    459 <ul class="org-ul">
    460 <li>State &ldquo;DONE&rdquo;       from &ldquo;STARTED&rdquo;    <span class="timestamp-wrapper"><span class="timestamp">[2020-03-23 Mon 19:02]</span></span></li>
    461 </ul>
    462 </div>
    463 
    464 <p>
    465 The style of the website has be as simple as possible, and also really light. This means:
    466 </p>
    467 <ul class="org-ul">
    468 <li>use default system font as much as possible</li>
    469 <li>have a small stylesheet, rely on the default as much as we can</li>
    470 </ul>
    471 
    472 <p>
    473 In addition, I want support for:
    474 </p>
    475 <ul class="org-ul">
    476 <li>side notes</li>
    477 <li>code syntax highlight</li>
    478 <li>table of content</li>
    479 </ul>
    480 
    481 <p>
    482 The inspiration for this website, in term of style are the following:
    483 </p>
    484 <ul class="org-ul">
    485 <li><a href="https://vincent.demeester.fr/posts/2018-08-16-gotest-tools-assertions/">Vincent Demeester</a></li>
    486 <li><a href="https://braindump.jethro.dev/zettels/zettelkasten/">Jethro&rsquo;s Braindump</a></li>
    487 <li><a href="https://hamberg.no/gtd/">GTD in 15 minutes – A Pragmatic Guide to Getting Things Done</a></li>
    488 <li><a href="https://www.inkandswitch.com/local-first.html">Local-first software: You own your data, in spite of the cloud</a></li>
    489 <li><a href="https://archive.casouri.cat/note/2018/blog-in-org-mode-revisited/index.html">Blog in Org Mode, Revisited</a></li>
    490 <li><a href="https://kind.sigs.k8s.io/">kind</a></li>
    491 <li><a href="http://willcrichton.net/notes/idioms-of-dynamic-languages/">Idioms of Dynamic Languages | Will Crichton</a></li>
    492 <li><a href="https://peter.bourgon.org/blog/2019/09/11/programming-with-errors.html">Peter Bourgon · Programming with errors</a></li>
    493 <li><a href="https://johv.dk/blog/bare-metal-assembly-tutorial.html">Getting started with bare-metal assembly — Jonas Hvid</a></li>
    494 </ul>
    495 
    496 <p>
    497 To be able to define the style a bit, let&rsquo;s try some things below. From this point on,
    498 this is random content just to try my style out. 👼
    499 </p>
    500 
    501 <p>
    502 There is more in <a href="../articles/sandbox.html">the sandbox</a>.
    503 </p>
    504 
    505 <hr>
    506 
    507 <div class="abstract" id="org026d63b">
    508 <p>
    509 Let&rsquo;s dig into how I setup my development environment when working on <code>tektoncd/pipeline</code>
    510 </p>
    511 
    512 </div>
    513 
    514 <nav id="table-of-contents" role="doc-toc">
    515 <h2>Table of Contents</h2>
    516 <div id="text-table-of-contents" role="doc-toc">
    517 <ul>
    518 <li><a href="#Introduction">Introduction</a></li>
    519 <li><a href="#Requirements">Requirements</a></li>
    520 <li><a href="#Organizing"><span class="done DONE">DONE</span> Organizing</a></li>
    521 <li><a href="#Publishing"><span class="done DONE">DONE</span> Publishing</a></li>
    522 <li><a href="#Styling"><span class="done DONE">DONE</span> Styling</a>
    523 <ul>
    524 <li><a href="#sub-heading%201">sub-heading 1</a></li>
    525 <li><a href="#sub-heading%202">sub-heading 2</a></li>
    526 </ul>
    527 </li>
    528 <li><a href="#What%27s%20next%20%3F">What&rsquo;s next ?</a></li>
    529 </ul>
    530 </div>
    531 </nav>
    532 </div>
    533 <div id="outline-container-sub-heading%201" class="outline-3">
    534 <h3 id="sub-heading%201">sub-heading 1</h3>
    535 <div class="outline-text-3" id="text-sub-heading%201">
    536 <p>
    537 Checking for errors is <b>very common</b> in Go, having <code>Comparison</code> function for it was a requirement.
    538 </p>
    539 
    540 <aside id="org13d2778">
    541 <p>
    542 This is a side note. If collection is a string, item must also be a string, and is
    543 compared using <code>strings.Contains()</code>. If collection is a Map, contains will succeed if item
    544 is a key in the map.
    545 </p>
    546 </aside>
    547 
    548 <ul class="org-ul">
    549 <li><code>Error</code> fails if the error is <code>nil</code> <b>or</b> the error message is not the expected one.</li>
    550 <li><code>ErrorContains</code> fails if the error is <code>nil</code> <b>or</b> the error message does not contain the expected substring.</li>
    551 <li><code>ErrorType</code> fails if the error is <code>nil</code> <b>or</b> the error type is not the expected type.</li>
    552 </ul>
    553 
    554 <p>
    555 Let&rsquo;s first look at the most used : <code>Error</code> and <code>ErrorContains</code>.
    556 When you&rsquo;re working on <code>pipeline</code>, usually you want :
    557 </p>
    558 
    559 <ol class="org-ol">
    560 <li>make sure it compiles : <code>go build -v ./..</code></li>
    561 <li>Running unit tests : <code>go test ./...</code> (bonus use <a href="https://github.com/vdemeester/ram"><code>ram</code></a> for continuous testing)</li>
    562 <li><p>
    563 End-to-end tests : <code>go test -tags e2e ./...</code> (or simply using `./test/` package)
    564 </p>
    565 
    566 <p>
    567 <b>Make sure you re-deploy before running the e2e tests</b> using <code>ko apply -f ./config</code>,
    568 otherwise you&rsquo;re testing the wrong code.
    569 </p></li>
    570 </ol>
    571 
    572 <div class="org-src-container">
    573 <pre class="src src-go">var err error
    574 // will fail with : expected an error, got nil
    575 assert.Check(t, cmp.Error(err, "message in a bottle"))
    576 err = errors.Wrap(errors.New("other"), "wrapped")
    577 // will fail with : expected error "other", got "wrapped: other"
    578 assert.Check(t, cmp.Error(err, "other"))
    579 // will succeed
    580 assert.Check(t, cmp.ErrorContains(err, "other"))
    581 </pre>
    582 </div>
    583 
    584 
    585 <figure id="org202916a">
    586 <img src="../images/emacs/2020-02-29-13-46-08.png" alt="2020-02-29-13-46-08.png" width="100%">
    587 
    588 <figcaption><span class="figure-number">Figure 1: </span>This is the caption for the next figure link (or table)</figcaption>
    589 </figure>
    590 
    591 <p>
    592 If this is the case, then what makes dynamic languages feel easy? Can we take what we learn in answering this question and improve the ergonomics of our static languages? For example, in 2018, I don’t think there’s as strong an argument for “you don’t have to write out the types,” since modern type inference eliminates most of the keystrokes required (even though many major languages still lack such facilities). Plus, saving a few keystrokes does not seem like a critical bottleneck in the programming process.
    593 </p>
    594 
    595 
    596 <figure id="org079eac9">
    597 <img src="../images/emacs/2020-02-29-14-41-59.png" alt="2020-02-29-14-41-59.png">
    598 
    599 </figure>
    600 </div>
    601 </div>
    602 <div id="outline-container-sub-heading%202" class="outline-3">
    603 <h3 id="sub-heading%202">sub-heading 2</h3>
    604 <div class="outline-text-3" id="text-sub-heading%202">
    605 <p>
    606 Some content from my other org-mode files.
    607 </p>
    608 
    609 <div class="description" id="orga53ead1">
    610 <p>
    611 I already wrote 2 previous posts about golang and testing. It&rsquo;s something I care deeply about and I wanted to continue
    612 writing about it. It took me a bit more time than I thought, but getting back to it. Since the <a href="http://vincent.demeester.fr/posts/2017-04-22-golang-testing-golden-file/">last post</a>, Daniel
    613 Nephin
    614 and I worked (but mainly Daniel 🤗) on bootstrapping a testing helper library.
    615 </p>
    616 
    617 </div>
    618 
    619 <blockquote>
    620 <p>
    621 Package assert provides assertions for comparing expected values to actual values. When
    622 assertion fails a helpful error message is printed.
    623 </p>
    624 </blockquote>
    625 
    626 <p>
    627 There is already some good <code>testing</code> helpers in the Go ecosystem : <a href="https://github.com/stretchr/testify"><code>testify</code></a>, <a href="http://labix.org/gocheck"><code>gocheck</code></a>,
    628 <a href="https://github.com/onsi/ginkgo"><code>ginkgo</code></a> and a lot more — so why create a new one ? There is multiple reason for it, most
    629 of them can be seen in the following <a href="https://github.com/gotestyourself/gotest.tools/issues/49#issuecomment-362436026">GitHub issue</a>.
    630 </p>
    631 
    632 <p>
    633 <a href="https://github.com/dnephin/">Daniel</a> also wrote a very useful <sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>converter if your code base is currently using <code>testify</code> :
    634 <code>gty-migrate-from-testify</code>.
    635 </p>
    636 
    637 <div class="org-src-container">
    638 <pre class="src src-sh">$ go get -u gotest.tools/assert/cmd/gty-migrate-from-testify
    639 # […]
    640 $ go list \
    641      -f '{{.ImportPath}} {{if .XTestGoFiles}}{{"\n"}}{{.ImportPath}}_test{{end}}' \
    642      ./... | xargs gty-migrate-from-testify
    643 </pre>
    644 </div>
    645 
    646 <p>
    647 We&rsquo;ll Use <code>Assert</code> for the rest of the section but any example here would work with
    648 <code>Check</code> too. When we said <code>Comparison</code> above, it&rsquo;s mainly the <a href="https://godoc.org/gotest.tools/assert#BoolOrComparison">BoolOrComparison</a> interface —
    649 it can either be a boolean expression, or a <a href="https://godoc.org/gotest.tools/assert/cmp#Comparison">cmp.Comparison</a> type. <code>Assert</code> and <code>Check</code> code
    650 will be <i>smart</i> enough to detect which one it is.
    651 </p>
    652 
    653 <div class="org-src-container">
    654 <pre class="src src-go">assert.Assert(t, ok)
    655 assert.Assert(t, err != nil)
    656 assert.Assert(t, foo.IsBar())
    657 </pre>
    658 </div>
    659 </div>
    660 </div>
    661 </section>
    662 <section id="outline-container-What%27s%20next%20%3F" class="outline-2">
    663 <h2 id="What%27s%20next%20%3F">What&rsquo;s next ?</h2>
    664 <div class="outline-text-2" id="text-What%27s%20next%20%3F">
    665 <p>
    666 One thing is to import old blog posts from <a href="https://vincent.demeester.fr">vincent.demeester.fr</a>. This is easily done with
    667 <a href="https://pandoc.org/">Pandoc</a> and a small bash loop — and some manual adjusting later on 😛.
    668 </p>
    669 
    670 <div class="org-src-container">
    671 <pre class="src src-bash">for post in ~/src/github.com/vdemeester/blog/content/posts/*.md; do
    672     pandoc -f markdown -t org -o posts/$(basename -s .md ${post}).org ${post}
    673 done
    674 </pre>
    675 </div>
    676 
    677 
    678 <p>
    679 What is still <i>to do</i> after this initial take.
    680 </p>
    681 
    682 <ul class="org-ul">
    683 <li class="off">&#x2610; List <code>FILETAGS</code> for taximony</li>
    684 <li class="off">&#x2610; Maybe use <a href="https://css-tricks.com/snippets/css/complete-guide-grid/">css grid</a> for the UI</li>
    685 </ul>
    686 </div>
    687 </section>
    688 <div id="footnotes">
    689 <h2 class="footnotes">Footnotes: </h2>
    690 <div id="text-footnotes">
    691 
    692 <div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
    693 foo is bar, bar is baz
    694 </p></div></div>
    695 
    696 
    697 </div>
    698 </div></main>
    699 <footer id="postamble" class="status">
    700 <footer>
    701      <small><a href="/" rel="history">Index</a> • <a href="/sitemap.html">Sitemap</a> • <a href="https://dl.sbr.pm/">Files</a></small><br/>
    702      <small class='questions'>Questions, comments ? Please use my <a href="https://lists.sr.ht/~vdemeester/public-inbox">public inbox</a> by sending a plain-text email to <a href="mailto:~vdemeester/public-inbox@lists.sr.ht">~vdemeester/public-inbox@lists.sr.ht</a>.</small><br/>
    703      <small class='copyright'>
    704       Content and design by Vincent Demeester
    705       (<a rel='licence' href='http://creativecommons.org/licenses/by-nc-sa/3.0/'>Some rights reserved</a>)
    706     </small><br />
    707 </footer>
    708 </footer>
    709 </body>
    710 </html>