Jeg har brugt den seneste uge på at flytte væk fra Ghost blogplatformen. Ikke fordi platformen var ringe på nogen måde (den kan varmt anbefales til andre som gerne vil igang), men mere fordi jeg har fundet noget som passer mig meget bedre. Da jeg startede med at blogge ville jeg bare igang med det samme, og jeg valgte derfor at købe mig til start, og finde ud af hvad der var det bedste: det har jeg fundet ud af nu. Valget faldt på:

  • hugo
  • org-mode

Jeg har i lang tid sværget til org formatet (og derved også org-mode (og derved også emacs)). Jeg prøvede derfor at finde noget som kunne understøtte org ud af boksen, og jeg fandt hugo, en statisk site generator. Jeg har i den seneste tid flyttet alle mine indlæg over, sat en pipeline op i gitlab, som kan bygge sitet, og udgive det, og du sidder pt og læser resultatet heraf.

Hvis du gerne selv vil igang giver jeg dig her nogle fifs og tricks til hvordan du kan komme igang, og jeg vil til sidst forklare hvorfor org (og org-mode) er langt bedre end alle andre formater (this will blow your mind). Så vær forberedt.

Tips og tricks til hugo start

Hugo, Gitlab, Cloudflare

Man skal selvfølgelig have hugo installeret. Når det er gjort, kan man gå igang. Jeg vil anbefale at følge quickstart'en, så har du et site sat op på ingen tid (med et meget grimt theme). Jeg har sat et repo op i gitlab, som hoster sitet (faktisk hoster den alle mine noter, og en folderne er en posts folder). Jeg har en pipeline, som flytter alle posts over i på mit site, bygger det, og releaser det. Serveren som hoster sitet er en meget lille server placeret i Finland. Den er frontet af Cloudflare. Opsummering:

  1. en gitlab repo med posts og site
  2. en server til at hoste sitet
  3. en pipeline som

    • bygger sitet
    • releaser sitet
  4. eventuel host det som en gitlab side (det har jeg dog ingen erfaring med)
  5. Prop en CDN ind foran (Fx Cloudflare)

Pipeline siger du?

Yes! Og jeg vil med glæde del den

image: alpine
variables:
  GIT_SUBMODULE_STRATEGY: recursive

stages:
    - compile
    - release

compile:
    stage: compile
    script:
      - apk update
      - apk add hugo
      - mkdir -p hugo/content/danish/post
      - mkdir hugo/images
      - cp posts/*.jpg hugo/static/images
      - cp posts/*.png hugo/static/images
      - cp posts/*.svg hugo/static/images
      - cp -r posts/* hugo/content/danish/post
      - rm -rf hugo/content/danish/post/drafts
      - cp notes/*-links.org hugo/content/danish/post/2020-01-01-links.org
      - hugo version
      - cd hugo
      - sed -i "s/\$DISQUS_SHORTNAME/$DISQUS_SHORTNAME_KEY/g" config.toml
      - sed -i "s/\$GOOGLE_ANALYTICS_ID/$GOOGLE_ANALYTICS_ID_KEY/g" config.toml
      - hugo -d ../public
    artifacts:
        paths:
            - public
        expire_in: 1 hour

release:
    stage: release
    script:
      - apk update
      - apk add openssh-client rsync
      - eval $(ssh-agent -s)
      - mkdir ~/.ssh
      - touch ~/.ssh/config
      - echo "$SSH_DOCS_DEPLOY_KEY" | tr -d '\r' | ssh-add -
      - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
      - rsync -r public/* user@host:/usr/share/nginx/html

Jeg deployer med ssh. Det theme jeg har skal bruge en disqus shortname og google analytics key. Disse har jeg som variabler i min config.toml og udskifter dem med sed. Det samme gør jeg med ssh key'en. Alle disse nøgler er gemt i en gitlab library, som er nem og ligetil at udfylde via UI'et.

Jeg kopierer enkelte noter over som jeg gerne vil have som posts, samt billeder og andet. Det er egentlig meget ligetil.

Org

Og nu til hvorfor jeg skriver dette indlæg: orgmode (og org-roam, og org-babel). Jeg har lavet hele dette setup fordi: jeg elsker org (som er formatet) og orgmode, som er en major mode til emacs, som kan vise formatet. Jeg vil i dette afsnit, og de efterfølgende afsnit prøve at vise hvorfor orgmode (og hele økosystemet omkring) er betydelig bedre end fx markdown (i alle dens afskygninger). Jeg vil fra nu af referer til org og orgmode, som: orgmode. Lad mig begynde at slå en ting fast: både orgmode og fx markdown kan bruges til at formatere tekst med. I mine øjne er den ene ikke hverken bedre eller værre end den anden. Vil du blot:

  • formatere noget tekst, og
  • converte det

så er det, i mine øjne ligegyldig hvad du vælger, men her stopper sammenfaldene også. Brat. Orgmode (og specielt org-roam og org-babel) buldrer videre og efterlader markdown og alle de andre i støvet. Grædende. Frådende. Efterladt. Tabt.

Orgmode > markdown > text

Man kan i orgmode formatere alle de ting som man kan i fx markdown. I orgmode sker dette med #+BEGIN_SRC og #+END_SRC

#+BEGIN_SRC python
print('hello');
#+END_SRC

Da du læser bloggen kan du også se ved selvsyn hvordan det bliver formateret. Smart. Men kan man ekskrevere det inde i kodeblokken, spørger du (kan jeg høre): JA: 100 gange ja. Man gør det ved, i emacs, at placere cursor'en i kode blokken, og trykke C-c C-c. org-babel smider den om til backend'en, ekskrevere koden, og returnere resultatet i en #+RESULTS. udfører man overstående vil man få følgende tilbage (man kan kun ekskrevere sprog som er understøttet, læs mere her - simpel markup virker dog på et utal af sprog)

#+BEGIN_SRC python
print('hello');
#+END_SRC

#+RESULTS:
: None

Ikke lige hvad vi forventede. Der er flere forskellige modes det kan køres i. Den mode vi leder efter er :results output. Smider man det på, og udfører koden igen, før man det som man forventer

#+BEGIN_SRC python :results output
print('hello');
#+END_SRC

#+RESULTS:
: hello

Default mode, som er :results code, gør at man kan returnere fra kode blokken (dvs at det kun er sidste statement som bliver vist i #+RESULTS, mens :results outout viser alle print statements), og derved bruge kode blokken som en funktion (som kan kaldes med #+CALL andre steder i ens org dokument … Ja. Det er meta: du kan lave funktioner med kodeblokke, som kan genbruges andre steder i dokumentet host Excel host). Fx har jeg her en kodeblok, som hedder func og laver efterfølgende en #+CALL: func som evaluere kodeblokken igen og returnere resultatet igen

#+NAME: func
#+BEGIN_SRC python
return 1-2+100
#+END_SRC

#+RESULTS: func
: 99

Her laver jeg overstående call, som også bliver kaldt når hugo evaluerer denne org post:

99

En sand meta post jeg har gang i.

Men det kan blive vildere meta endnu

I org-mode kan man lave tabeller, og det er endda let. Her er en tabel som har fikset sammen til mit interne budget (det bliver lidt personligt men det er ok):

Subscription Name Monthly Cost (DKK) Needed Category
Netflix 79 TV
Viaplay 99 x TV
Yoga 119 x Work
Disney 79 x TV
Adobe 100 Photo
Office 365 118 x Text
BackThen 29 x Photo
Spotify 149 x Music
Information 95 x News
Zetland 129 x News
1Password 30 x Tech
Server 80 x Tech
Blog 220 Tech

Kildekoden ser således ud

#+NAME: subscription_table
| Subscription Name | Monthly Cost (DKK) | Needed | Category |
|-------------------+--------------------+--------+----------|
| Netflix           |                 79 |        | TV       |
| Viaplay           |                 99 | x      | TV       |
| Yoga              |                119 | x      | Work     |
| Disney            |                 79 | x      | TV       |
| Adobe             |                100 |        | Photo    |
| Office 365        |                118 | x      | Text     |
| BackThen          |                 29 | x      | Photo    |
| Spotify           |                149 | x      | Music    |
| Information       |                 95 | x      | News     |
| Zetland           |                129 | x      | News     |
| 1Password         |                 30 | x      | Tech     |
| Server            |                 80 | x      | Tech     |
| Blog              |                220 |        | Tech     |

org-mode har indbygget tabel support, så man bruger blot TAB osv. Den sørger for at indentere, når man laver lange tekster i kolonnerne. Mega fedt, og forventligt, men det kan man jo også (med lidt møje og besvær) i fx notepad, osv: MEN … hvad nu hvis man gerne vil udregne totalen? I Excel kan man bruge SUM (der findes sådanne indbyggede funktioner i org-mode også), men hvis man vil lave noget som er lidt mere avanceret, så må man ty til andre midler: programmering. What? Ja! Programmering, som i Excel. Det er her org-babel virkelig kommer til sin ret, da den understøtter et væld af backends, man skal blot have den givne compiler til rådighed. Jeg har valgt at lave udregningen i python


#+NAME: total
#+BEGIN_SRC python :var tabel=subscription_table
total_price = 0;
for row in tabel:
    price = row[1]
    total_price += price
return total_price
#+END_SRC

#+RESULTS: total
: 1326

Hvis man C-c C-c selve BEGIN_SRC så får man, som ved de andre eksempler, vist RESULTS, tillad mig at gøre det med hugo

total_price = 0;
for row in tabel:
    price = row[1]
    total_price += price
return total_price

Jeg har lige C-c C-c'et denne funktion, og den har givet mig følgende resultat

1326

Som i kan se så tager den tabellen som input … OG JA, det jeg lige har kørt, bruger den tabel som du ser ovenover, som input … Det er MINDBLOWN!! Det kan man ikke med markdown eller med notepad, eller hvad editor man nu lige sidder og bruger. DET ER FEDT! Men det kan blive ViLdErE endnu: grafer :D til det skal vi bruge R, så det kan lige installeres på din boks. Lad mig vise eksemplet først


#+NAME: only_needed_table
#+BEGIN_SRC python :var tabel=subscription_table
array = []
for row in tabel:
    needed = row[2]
    if needed == 'x':
        array.append(row)
return array
#+END_SRC

#+RESULTS: only_needed_table
| Viaplay     |  99 | x | TV    |
| Yoga        | 119 | x | Work  |
| Disney      |  79 | x | TV    |
| Office 365  | 118 | x | Text  |
| BackThen    |  29 | x | Photo |
| Spotify     | 149 | x | Music |
| Information |  95 | x | News  |
| Zetland     | 129 | x | News  |
| 1Password   |  30 | x | Tech  |
| Server      |  80 | x | Tech  |

#+NAME: piechart
#+BEGIN_SRC R :var table=only_needed_table :results file graphics :file ../pie.png
data <- aggregate(x = table[2], by = table[4], FUN = sum)

pie(data[,2], data[,1])
#+END_SRC

Her kører jeg noget python som outputter de subscriptions som vi SKAL have, til en ny tabel. Den nye tabel bruger jeg som input til noget R kode som tegner denne piechart

/images/pie.png

Når man C-c C-c bliver piechart'en selvfølgelig indsat som et billede i RESULTS, hvis ens emacs er bygget med de fornødne visuelle biblioteker (og var R installeret i gitlab kom den også med ud når man kørte hugo)

/images/piechart-example.png

Excel? Ja: på ketogan, i en natklub med gratis coke.

https://media.giphy.com/media/26ufdipQqU2lhNA4g/giphy.gif

Konklusion

Jeg er blevet rimelig glad for org-mode og org-babel. Jeg har en massiv todo og note struktur, som jeg bruger til både privat og arbejde, hvor jeg hælder alt ned i. Org-mode kan lave nogle fine TODO lister, som man kan arbejde med, men det må jeg skrive om en anden gang (man kan lave timere i det og tracke tid!!).

Jeg håber I kunne lide indlægget, og er blevet inspireret til at prøve kræfter med org-mode, org-babel, hugo og git-lab. Det kan klart anbefales!!