< 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/")
        ("org" . "http://orgmode.org/elpa/")))
(package-initialize)
(unless localp (package-refresh-contents))
(package-install 'htmlize)
(package-install 'org-plus-contrib)

(require 'org)
(require 'ox-rss)
(require 'ox-publish)
(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 id='#preamble'>&lt; <a href='"
         (repeat-string "../" current-file-depth)
         "index.html'>expLog</a></div>"))))

;; 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 "
<style type='text/css'>

/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}

/* Custom styles */
body { font-family: helvetica, arial, sans; line-height: 1.5em; margin: -1px 0; padding: 1px 1em; }
#content .title { margin: 1em 0; text-align: left; }
#content .notice { display: block; padding: 1em; background-color: #fffdd8; }
#content { max-width: 600px; margin: 0; }
#content p { position: relative; }
#content p img { max-width: 750px; }
#content li p { margin: 0; }
a:visited, a:link { color: rgb(175, 0, 0); }
#content span.margin { color: #222; font-size: .9em; line-height: 1.2em; }
::selection { background-color: #fff86d }

/* Larger screens */
@media screen and (min-width: 1000px) {
    body { border-left: solid 20px #970000; padding: 1em 2em 1px 3em; border-top: solid 20px #970000; }
    #content .title { width: 800px; }
}
@media screen and (min-width: 800px) {
  #content .example, #content .src { display: block; width: 720px; }
  #content span.margin { position: absolute; top: .2em; right: -220px; width: 200px; }
}

/* Smaller screens */
@media screen and (max-width: 800px) {
  #content span.margin { display: block; }
  #content span.margin::before { content: '('; }
  #content span.margin::after { content: ')'; }
}

</style>
<script async src='https://www.googletagmanager.com/gtag/js?id=UA-143791509-1'></script>
<script>
if (window.doNotTrack || navigator.doNotTrack || navigator.msDoNotTrack ||
    'msTrackingProtectionEnabled' in window.external) {
  if (window.doNotTrack == '1' || navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' ||
      navigator.msDoNotTrack == '1' || window.external.msTrackingProtectionEnabled()) {
    window['ga-disable-UA-143791509-1'] = true;
  }
}

window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-143791509-1');
</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]

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

  • 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.