Static Websites Management Functions
Introduction
These functions complement org-mode
publishing features by adding
a local preview and a deploy function using rsync
:
website-server-start
(and corresponding stop function)website-deploy
Projects managed with these functions need to be declared in a association list using:
website-add
Project Specification Association List
Previewing and deploying are managed with emacs-lisp functions which allows to select the project to preview or publish.
The following code builds an association list with all the information required to preview and publish a website, namely:
( project-name (:port project-port :dir project-dir :deploy-dir deploy-cmd :no-sources no-sources) )
Note that since project-name
is a reference to a project defined
in org-publish-project-alist
(and, as such, it allows us to get
information about source directory, etc.)
(defvar website-alist nil "List of websites managed with functions defined in this file") (defun website-add (name preview-port local-dest deploy-dest &optional no-sources) "Add a website specification to the list of managed websites. Arguments: - name (name of project) - preview-port (local port used for previewing) - local-dest (directory in which html files are placed) - deploy-dest (directory where html files are deployed)" (setq website-alist (cons (cons name `(:port ,preview-port :dir ,local-dest :deploy-dir ,deploy-dest :no-sources ,no-sources)) website-alist))) (defun website-remove (name) "Delete website specification =name= from the list of managed websites. Useful if you want to reload a configuration." (setq website-alist (assoc-delete-all name website-alist))) ;; (boundp (quote website-alist))
Building
This is syntactic sugar, since org-mode
already provides these
functions.
(defun website-build (project &optional force async) "Build a website (invoke org-publish)" (interactive (list (assoc (completing-read "Publish project: " website-alist nil t) website-alist) current-prefix-arg)) (org-publish (car project) force async))
Previewing
Define two functions which start and stop a webserver serving
website whose specification is stored in website-alist
.
The elnode tutorial provides the example code for starting and
stopping the server.
These functions can be safely moved to the Emacs initialization file, especially when there is more than one project:
(require 'elnode nil t) (defun website-server-start () "Ask for a project name and start previewing it" (interactive) (let* ( (project-name (completing-read "Website to start previewing: " (mapcar (lambda (x) (car x)) website-alist))) ) (website-server-start-ll project-name))) (defalias 'website-preview 'website-server-start) (defun website-server-start-ll (project-name) "Start previewing a project whose name is passed as argument" (let ( (port (plist-get (cdr (assoc project-name website-alist)) :port)) (dir (plist-get (cdr (assoc project-name website-alist)) :dir)) ) (progn (elnode-start (elnode-webserver-handler-maker dir) :port port :host "localhost") (message "Started serving directory %s on port %s" dir port)))) (defun website-server-stop () "Stop previewing a project" (interactive) (let* ( (project-name (completing-read "Website to stop previewing: " (mapcar (lambda (x) (car x)) website-alist))) ) (website-server-stop-ll project-name))) (defun website-server-stop-ll (project-name) "Stop previewing a project passed as argument" (let ( (port (plist-get (cdr (assoc project-name website-alist)) :port)) ) (elnode-stop port)))
Deploying
Define a function which invokes the deploy command for the project.
All project specifications are stored in website-alist
.
The code for deploying has been taken from:
https://stackoverflow.com/questions/1453956/which-shell-command-in-emacs-lisp.
A more structured solution probably uses call-process
, but I did not
want to have to manage shell expansions.
This function can be safely moved to the Emacs initialization file, especially when there is more than one project:
(defun website-deploy () (interactive) (let* ( (webserver (completing-read "Website to deploy: " (mapcar (lambda (x) (car x)) website-alist))) (local-dir (plist-get (cdr (assoc webserver website-alist)) :dir)) (deploy-dir (plist-get (cdr (assoc webserver website-alist)) :deploy-dir)) (exclude-sources (plist-get (cdr (assoc webserver website-alist)) :no-sources)) (buffer (get-buffer-create (concat "*rsync-buffer for " webserver "*"))) ) (if deploy-dir (progn (display-buffer buffer) (start-process "process-name" buffer "/usr/bin/rsync" "-crvz" "--exclude=*~" "--exclude=.git" "--exclude=_*" (if exclude-sources "--exclude=*.org" "--include=*.org") "--delete" "--delete-excluded" (file-name-as-directory local-dir) ; add a final slash (otherwise local-dir might be created on the server instead) deploy-dir)) (message "No deployment command specified for %s" webserver))))
What do we provide?
(provide 'website)