Recently Written · git

coleslaw

Emacs mode for the "Coleslaw" site generator written in Common Lisp.

git clone https://github.com/equwal/coleslaw

Log | Files | Refs


src/coleslaw.lisp (3310 bytes)

1 (in-package :coleslaw)
2 
3 (defvar *last-revision* nil
4   "The git revision prior to the last push. For use with GET-UPDATED-FILES.")
5 
6 (defun main (repo-dir &key oldrev (deploy t))
7   "Load the user's config file, compile the blog in REPO-DIR into STAGING-DIR,
8  and optionally deploy the blog to DEPLOY-DIR.
9   OLDREV -- the git revision prior to the last push.
10   DEPLOY -- when non-nil, perform the deploy. (default: t)"
11   (load-config repo-dir)
12   (setf *last-revision* oldrev)
13   (load-content)
14   (compile-theme (theme *config*))
15   (let ((dir (staging-dir *config*)))
16     (compile-blog dir)
17     (when deploy
18       (deploy dir))))
19 
20 (defun load-content ()
21   "Load all content stored in the blog's repo."
22   (do-subclasses (ctype content)
23     (discover ctype))
24   (update-content-metadata)
25   (do-subclasses (itype index)
26     (discover itype)))
27 
28 (defun compile-blog (staging)
29   "Compile the blog to a STAGING directory as specified in .coleslawrc."
30   (ensure-directories-exist staging)
31   (with-current-directory staging
32     (let ((theme-dir (find-theme (theme *config*))))
33       (dolist (dir (list (merge-pathnames "css" theme-dir)
34                          (merge-pathnames "img" theme-dir)
35                          (merge-pathnames "js" theme-dir)
36                          (repo-path "static")))
37         (when (probe-file dir)
38           (if (uiop:os-windows-p)
39               (run-program "(robocopy ~a ~a /MIR /IS) ^& IF %ERRORLEVEL% LEQ 1 exit 0" dir (path:basename dir))
40               (run-program "rsync --delete -raz ~a ." dir)))))
41     (do-subclasses (ctype content)
42       (publish ctype))
43     (do-subclasses (itype index)
44       (publish itype))
45     (let ((recent-posts (reduce #'(lambda (a b)
46                                     (if (< (index-name a) (index-name b))
47                                         a b))
48                                 (find-all 'numeric-index))))
49       (update-symlink "index.html" (page-url recent-posts)))))
50 
51 (defgeneric deploy (staging)
52   (:documentation "Deploy the STAGING build to the directory specified in the config.")
53   (:method (staging)
54     "By default, do nothing"
55     (declare)))
56 
57 (defun update-symlink (path target)
58   "Update the symlink at PATH to point to TARGET."
59   (run-program "ln -sfn ~a ~a" target path))
60 
61 (defun preview (path &optional (content-type 'post))
62   "Render the content at PATH under user's configured repo and save it to
63 ~/tmp.html. Load the user's config and theme if necessary."
64   (let ((current-working-directory (cl-fad:pathname-directory-pathname path)))
65     (unless *config*
66       (load-config (namestring current-working-directory))
67       (compile-theme (theme *config*)))
68     (let* ((file (rel-path (repo-dir *config*) path))
69            (content (construct content-type (read-content file))))
70       (write-file "tmp.html" (render-page content)))))
71 
72 (defun render-page (content &optional theme-fn &rest render-args)
73   "Render the given CONTENT to HTML using THEME-FN if supplied.
74 Additional args to render CONTENT can be passed via RENDER-ARGS."
75   (funcall (or theme-fn (theme-fn 'base))
76            (list :config *config*
77                  :content content
78                  :raw (apply 'render content render-args)
79                  :pubdate (format-rfc1123-timestring nil (local-time:now))
80                  :injections (find-injections content))))