< expLog

Org Configuration

My current solution is based on derivatives of my previous publishing configuration as well as this post around publishing with Github Actions. It relies on running emacs in batch mode to generate the website, with all the configuration in publish.el with a helper script publi.sh to build locally or on Github.

Build script (publi.sh)

#!/bin/sh
set -x
set -e

LOCAL=0
FORCE=0
for arg in "$@"
do
    case $arg in
        -l|--local)
        LOCAL=1
        shift
        ;;
        -f|--force)
        FORCE=1
        shift
        ;;
    esac
done

INCLUDE="$@"

git config --global user.email "bhalla.kunal@gmail.com"
git config --global user.name "Kunal Bhalla"

DATE_MARKER=$(date)
HOST=$(hostname)

if [ $LOCAL != 1 ]
then
    set +x
    echo "+ TARGET_REPO=<redacted>"
    TARGET_REPO="https://kunalb:$API_TOKEN@github.com/kunalb/kunalb.github.io.git"
    set -x
else
    TARGET_REPO="git@github.com:kunalb/explog.git"
fi

cd "$(dirname "$0")"

if [ ! -d "build" ]
then
    set +x
    echo "git clone <redacted> build"
    git clone $TARGET_REPO build
    set -x
fi

INCLUDE=$INCLUDE FORCE=$FORCE LOCAL=$LOCAL emacs --batch -l publish.el

if [ $LOCAL != 1 ]
then
    cd build
    git add . && git commit -am "$DATE_MARKER: Built on $HOST"

    set +x
    echo "git push <redacted>"
    git push $TARGET_REPO
    set -x
fi

Elisp to export everything (publish.el)

;;; Publish expLog


;; Local build
(setq localp (string= "1" (getenv "LOCAL")))
(setq forcep (string= "1" (getenv "FORCE")))
(setq include (getenv "INCLUDE"))

;; Enable debugging for better stack traces
(setq debug-on-error t)

;; Set up packages
(setq package-archives
      '(("melpa" . "http://melpa.org/packages/")
        ("elpa" . "http://elpa.gnu.org/packages/")
        ("nongnu" . "http://elpa.nongnu.org/nongnu/")))
(package-initialize)
(unless localp (package-refresh-contents))
(package-install 'htmlize)
(package-install 'org-contrib)

(with-temp-buffer
  (url-insert-file-contents
   "https://raw.githubusercontent.com/emacsmirror/ox-rss/80b5001c3d1c10b578d799bd8ff49e9267a2d5ff/ox-rss.el")
  (eval-buffer))

(require 'org)
(require 'ox-publish)
(require 'ox-rss)
(require 'htmlize)
(require 'subr-x)

;; Include options
(setq include-options
      (if (not (string-empty-p include))
          `(:exclude ".*" :include ,(split-string include))
        '()))

;; Basic settings
(setq make-backup-files nil)
(setq org-confirm-babel-evaluate nil)
(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t)
   (python . t)))
(setq org-export-global-macros
      '((margin . "@@html:<span class='margin'>@@$1@@html:</span>@@")
        (notice . "@@html:<span class='notice'>@@$1@@html:</span>@@")))

(defun repeat-string (str num)
  (apply 'concat (make-list num str)))

(setq root-directory
      (expand-file-name default-directory))

(defun create-preamble (options)
  (let* ((current-file-name (plist-get options :input-file))
         (current-file-depth (-
                              (length (split-string (file-relative-name
                                                     current-file-name
                                                     root-directory)
                                                    "\/"))
                              2)))
    (if (not (string-suffix-p
              "org/index.org"
              (plist-get options :input-file)))
        (concat
         "<div>&lt; <a href='"
         (repeat-string "../" current-file-depth)
         "index.html'>expLog</a></div>"))))

(defun create-header (options)
  (let* ((current-file-name (plist-get options :input-file))
         (current-file-depth (-
                              (length (split-string (file-relative-name
                                                     current-file-name
                                                     root-directory)
                                                    "\/"))
                              2)))
    (concat
     "<link rel=\"stylesheet\" href='"
     (repeat-string "../" current-file-depth)
     "static/style.css' />"
     )))

(defun custom-header (fn &rest args)
  (let ((res (apply fn args)))
    (concat
     res
     (create-header (car args)))))

(advice-add 'org-html--build-head :around #'custom-header)

;; Publish the actual website
(org-publish
 `("expLog"
   :base-directory "org"
   :publishing-directory "build"
   :base-extension "org"
   :recursive t
   :htmlized-source t
   :publishing-function org-html-publish-to-html
   :with-author nil
   :with-toc nil
   :section-numbers nil
   :html-validation-link nil
   :html-head-include-scripts nil
   :html-postamble nil
   :html5-fancy t
   :html-head-extra "
<script data-goatcounter='https://knl.goatcounter.com/count'
        async src='//gc.zgo.at/count.js'></script>
"
   :html-preamble ,'create-preamble
   ,@include-options
   )
 (or forcep (not localp)))


(if (null include-options)
    ;; Copy over static resources
    (org-publish
     '("static"
       :base-directory "org/static"
       :publishing-directory "build/static"
       :base-extension any
       :recursive t
       :publishing-function org-publish-attachment)
     (or forcep (not localp))))

(if (null include-options)
    ;; RSS
    (org-publish
     '("rss"
       :base-directory "org"
       :base-extension "org"
       :html-link-home "https://explog.in/"
       :html-link-use-abs-url t
       :rss-extension "xml"
       :publishing-directory "build"
       :publishing-function (org-rss-publish-to-rss)
       :section-numbers nil
       :exclude ".*"
       :include ("rss.org")
       :table-of-contents nil)
     (or forcep (not localp))))

Github Action (.github/workflows/publish.yml)

name: Publish

on:
  push:
  workflow_dispatch:

jobs:
  publish-explog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
      - name: Install software
	run: sudo apt-get install emacs git
      - name: Install python dependencies
	run: |
	  python3 -m pip install --upgrade pip
	  pip install matplotlib
      - name: Build new site
	run: ./publi.sh -f
	env:
	  API_TOKEN: ${{ secrets.API_TOKEN }}

Updates

  • 2022-01-10: Extracted CSS into a separate file.
  • 2021-07-05: Resurrected RSS feed.
  • 2021-05-22: First steps towards automation and simplification.
  • 2021-01-21: One of the most stable designs; on internet archive.
  • 2016-10-27: A white version; on internet archive.