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


plugins/import.lisp (3012 bytes)

1 (eval-when (:compile-toplevel :load-toplevel)
2   (ql:quickload '(coleslaw cxml cl-ppcre local-time)))
3 
4 (defpackage :coleslaw-import
5   (:use :cl :cxml)
6   (:export #:enable)
7   (:import-from :coleslaw #:slugify
8                           #:load-config
9                           #:*config*
10                           #:repo
11                           #:repo-dir
12                           #:separator)
13   (:import-from :local-time #:+short-month-names+)
14   (:import-from :cl-ppcre #:regex-replace-all))
15 
16 (in-package :coleslaw-import)
17 
18 (defun node-val (name post)
19   (flet ((value (node)
20            (let ((child (dom:last-child node)))
21              (when child (dom:data child)))))
22     (let ((nodes (dom:get-elements-by-tag-name post name)))
23       (if (string= "category" name)
24           (loop for node across nodes collecting (value node))
25           (when (plusp (length nodes)) (value (elt nodes 0)))))))
26 
27 (defun get-timestamp (post)
28   (destructuring-bind (day date month year time tz)
29       (cl-ppcre:split " " (node-val "pubDate" post))
30     (format nil "~a-~2,'0d-~2,'0d ~a" year (position month +short-month-names+
31                                                      :test #'string=) date time)))
32 
33 (defun import-post (post output &optional since)
34   (when (and (string= "publish" (node-val "wp:status" post)) ; is it public?
35              (string= "post" (node-val "wp:post_type" post)) ; is it a post?
36              (or (null since) (string>= (get-timestamp post) since)))
37     (let ((slug (slugify (node-val "title" post))))
38       (when (string= "" slug)
39         (error "No valid slug-title for post ~a." (get-timestamp post)))
40       (export-post (node-val "title" post) (node-val "category" post)
41                    (get-timestamp post) (node-val "content:encoded" post)
42                    (format nil "~a.post" slug) output))))
43 
44 (defun export-post (title tags date content path output)
45   (with-open-file (out (merge-pathnames path (or output (repo-dir *config*)))
46                    :direction :output
47                    :if-exists :supersede
48                    :if-does-not-exist :create
49                    :external-format :utf-8)
50     ;; TODO: What other data/metadata should we write out?
51     (format out "~A~%" (separator *config*))
52     (format out "title: ~A~%" title)
53     (format out "tags: ~A~%" (format nil "~{~A~^, ~}" tags))
54     (format out "date: ~A~%" date)
55     (format out "format: html~%") ; post format: html, md, rst, etc
56     (format out "~A~%" (separator *config*))
57     (format out "~A~%" (regex-replace-all (string #\Newline) content "<br>"))))
58 
59 (defun import-posts (filepath output &optional since)
60   (when (probe-file filepath)
61     (ensure-directories-exist (or output (repo-dir *config*)))
62     (let* ((xml (cxml:parse-file filepath (cxml-dom:make-dom-builder)))
63            (posts (dom:get-elements-by-tag-name xml "item")))
64       (loop for post across posts do (import-post post output since))
65       (delete-file filepath))))
66 
67 (defun enable (&key filepath output)
68   (import-posts filepath output))