Website Publishing: Build config
Table of Contents
Emacs Build Configuration
Save package in local .packages
folder
This will set a local package initialisation directory so that packages are downloaded and saved locally and not in users or systems .emacs.d folder
(require 'package) (setq package-user-dir (expand-file-name "./.packages"))
Package archive path
This add package archives path, the location where package manager will search for the required packages.
(setq package-archives '(("melpa" . "https://melpa.org/packages/") ("elpa" . "https://elpa.gnu.org/packages/")))
Initialize package system
(package-initialize ) (unless package-archive-contents (package-refresh-contents))
Adding usepackage package
For nicer imports of packages
(unless (package-installed-p 'use-package) (package-install 'use-package)) (require 'use-package) (setq use-package-always-ensure t)
Raimbow delimiters
(use-package rainbow-delimiters :ensure t :hook ((prog-mode . rainbow-delimiters-mode) (org-mode . rainbow-delimiters-mode)))
No backups or temp files
(setq make-backup-files nil)
URL handeler mode to include external files
(url-handler-mode 1)
Install dependencies
; (use-package ox-slimhtml ; :ensure t) (package-install 'htmlize)
Load publishing system
(require 'ox-publish)
Evaluate lisp code without confirmation
(defun my-org-confirm-babel-evaluate (lang body) (not (member lang '("emacs-lisp" )))) (setq org-confirm-babel-evaluate 'my-org-confirm-babel-evaluate)
Custom Backend
Markup alist
(assq-delete-all 'verbatim org-html-text-markup-alist) (add-to-list 'org-html-text-markup-alist '(verbatim . "<mark>%s</mark>"))
Sitemap or Index page
A function to format the publication date as a string which will be shown below the entry on index page.
(defun sr/format-date-subtitle (file project) "Format publication date. Use (org-publish-find-property file :title project) to add other properties" (capitalize (format-time-string "%B %d, %Y" (org-publish-find-date file project))))
A function to get the description of the entry.
(defun sr/format-description (file project) "Format publication date. Use (org-publish-find-property file :title project) to add other properties This works with some specific properties and not all custom property so the following hack." (concat "" (with-temp-buffer (insert-file-contents (concat "./content/" file) ) (cdr (assoc "DESCRIPTION" (org-element-map (org-element-parse-buffer 'element) 'keyword (lambda (keyword) (cons (org-element-property :key keyword) (org-element-property :value keyword)))))))))
Thanks to The Kitchin Research Group Blog for the solution.
TODO: Replace ./content
in above with something like (plist-get project :base-directory)
but that works.
Now I need a function that will format the sitemap/index page entries in a specified way.
(defun sr/org-publish-sitemap-entry (entry style project) "Format for sitemap ENTRY, as a string. ENTRY is a file name. STYLE is the style of the sitemap. PROJECT is the current project." (unless (equal entry "404.org") (format "[[file:%s][%s]] \n %s \n /%s/" entry (org-publish-find-title entry project) (sr/format-description entry project) (sr/format-date-subtitle entry project) )))
And finally, a function to generate sitemap.org
file.
(defun sr/org-publish-sitemap (title list) "Generate sitemap as a string, having TITLE. LIST is an internal representation for the files to include, as returned by `org-list-to-lisp'." (let ((filtered-list (cl-remove-if (lambda (x) (and (sequencep x) (null (car x)))) list))) (concat "#+TITLE: " title "\n" "#+OPTIONS: tex:t toc:nil\n" "#+META_TYPE: website\n" "#+DESCRIPTION: Personal Blog of Shriram Ashirgade\n" "\n#+ATTR_HTML: :class sitemap\n" (org-list-to-org filtered-list) )))
The above piece of code was borrowed from writepermission.com.
Derived backend
(org-export-define-derived-backend 'shrirambo-site-html 'html :translate-alist '((headline . my-latex-headline-translator) (template . my-latex-template)))
*ambles
Function to retrieve template html
(defun sa/get-template (type) "Return the content for the pre/postamble of TYPE." `(("en" ,(with-temp-buffer (insert-file-contents (expand-file-name (format "%s.html" type) "resources/templates/")) (buffer-string)))))
Publish
Customize HTML output
;; Customize the HTML output (setq org-html-validation-link nil ;; Don't show validation link org-html-head-include-scripts nil ;; Use our own scripts org-html-head-include-default-style nil ;; Use our own styles org-export-use-babel t ;; Do(not) use babel to execute src blocks org-html-htmlize-output-type 'css ;; Instead of using inline css for each element org-export-with-todo-keywords nil ;; Ignore TODO keywords org-html-doctype "html5" org-html-html5-fancy nil org-html-head (concat "<link rel='stylesheet' href='./css/code.css' />\n" "<link rel='stylesheet' href='./css/simple.css' />\n" "<link rel='shortcut icon' href='./img/favicon.ico' type='image/x-icon' />\n" "<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css' integrity='sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=' crossorigin='anonymous'>\n") org-html-self-link-headlines t org-html-container-element "section" org-publish-timestamp-directory "./.timestamps/" org-html-divs '((preamble "header" "top") (content "main" "content") (postamble "footer" "postamble")) )
Publishing project properties
;; Define the publishing project (setq org-publish-project-alist (list (list "blog" :recursive t :base-directory "./content" :base-extension "org" :exclude ".*\.\\(setup\\|draft\\)\.org" ;; This ignores all the setup and draft files :publishing-function 'org-html-publish-to-html :publishing-directory "./public" :with-author nil ;; Don't include author name :with-creator nil ;; Include Emacs and Org versions in footer :with-date nil :with-toc t ;; Include a table of contents :section-numbers nil ;; Don't include section numbers :time-stamp-file nil ;; Don't include time stamp in file :auto-sitemap t :sitemap-filename "index.org" :sitemap-style 'list :sitemap-title "Blog Posts" :sitemap-function 'sr/org-publish-sitemap :sitemap-sort-files 'anti-chronologically :sitemap-format-entry 'sr/org-publish-sitemap-entry :html-preamble-format (sa/get-template 'preamble) :html-postamble t :html-postamble-format (sa/get-template 'postamble) ) (list "microblog" :recursive t :base-directory "./microblog" :base-extension "org" :publishing-function 'org-html-publish-to-html :publishing-directory "./public" :with-author nil ;; Don't include author name :with-creator nil ;; Include Emacs and Org versions in footer :with-date nil :with-toc t ;; Include a table of contents :section-numbers nil ;; Don't include section numbers :time-stamp-file nil ;; Don't include time stamp in file :auto-sitemap nil ;:sitemap-filename "index.org" ;:sitemap-style 'list ;:sitemap-title "Blog Posts" ;:sitemap-function 'sr/org-publish-sitemap ;:sitemap-sort-files 'anti-chronologically ;:sitemap-format-entry 'sr/org-publish-sitemap-entry :html-preamble-format (sa/get-template 'preamble) :html-postamble t :html-postamble-format (sa/get-template 'postamble) ) (list "mail-site" :components '("blog" "microblog")) ))
Generate Output
;; Generate the site output (org-publish-all t) (message "Build complete!")
Build
First line evaluates thin org file and creates a build.el
file which contains all the publishing configuration. The second line evaluates build.el
file itself and publish the web pages. And the final line removes build.el
file.
#!/bin/bash emacs -Q --batch --eval "(require 'org)" --eval '(org-babel-tangle-file "build.org")' emacs -Q --script build.el rm build.el
One step less
Make emacs evaluate build.org
itself, rahter than tangling build.el
first. This will remove one step from the deployment.