about summary refs log tree commit diff
path: root/ennum.el
diff options
context:
space:
mode:
Diffstat (limited to 'ennum.el')
-rw-r--r--ennum.el143
1 files changed, 97 insertions, 46 deletions
diff --git a/ennum.el b/ennum.el
index 93923d6..cfcc0ef 100644
--- a/ennum.el
+++ b/ennum.el
@@ -240,10 +240,33 @@ respectively by - and _, and the pad character = is optional."
             ((file-executable-p file) executable-file-mode)
             (t file-mode)))))
 
-(defmacro ennum-exp (&rest body)
-  `(ennum-eval (lambda () ,@body)))
+(cl-defstruct (ennum-exp (:constructor ennum-make-exp)
+                         (:copier nil))
+  function sub-expressions)
 
-(defun ennum-eval (closure)
+(defmacro ennum-exp (&rest body)
+  "Wrap BODY in an ennum-exp."
+  (pcase body
+    (`(,expression)
+     `(ennum-make-exp :sub-expressions (list (lambda ()
+                                               ,expression))))
+    (`(,function . ,sub-expressions)
+     `(ennum-make-exp :function #',function
+                      :sub-expressions (list ,@sub-expressions)))))
+
+(defun ennum-exp-apply (function arguments)
+  "Return ennum-exp applying FUNCTION to ARGUMENTS list."
+  (ennum-make-exp :function function
+                  :sub-expressions arguments))
+
+(defun ennum--evaluate-closure (closure)
+  "Evaluate CLOSURE writing its output to the store.
+
+CLOSURE is evaluated in a temporary directory with the expectation that
+it writes its output to paths relative to that temporary directory. If
+CLOSURE returns successfully, its output is moved to the store. The
+resulting store item is prefixed with the hash of the serialization of
+the closure."
   (let ((output
          (expand-file-name
           (with-temp-buffer
@@ -273,17 +296,40 @@ respectively by - and _, and the pad character = is optional."
       (ennum--set-file-modes-recursively output #o555 #o444 #o555))
     output))
 
+(defun ennum-eval (exp)
+  "Evaluate EXP, an ennum-exp."
+  (cond
+   ;; Naked closure; just evaluate it.
+   ((closurep exp)
+    (ennum--evaluate-closure exp))
+   ;; Compound expression with several sub-expressions to be evaluated
+   ;; and passed to function
+   ((ennum-exp-function exp)
+    (ennum--evaluate-closure
+     (apply-partially #'apply
+                      (ennum-exp-function exp)
+                      (seq-map #'ennum-eval
+                               (ennum-exp-sub-expressions exp)))))
+   ;; Simple expression with only a single sub-expression; evaluate
+   ;; the sub-expression and return the result.
+   (t
+    (pcase (ennum-exp-sub-expressions exp)
+      (`(,sub-expression)
+       (ennum-eval sub-expression))))))
+
 (defun ennum-store-item-union (items)
   "Return a store item that is the union of ITEMS."
-  (ennum-exp
-   (dolist (item items)
-     (dolist (destination (reverse (ennum-directory-files item nil t)))
-       ;; TODO: Print warning about overwriting files?
-       (let ((source (expand-file-name destination item)))
-         (unless (file-exists-p destination)
-           (if (file-directory-p source)
-               (make-directory destination)
-             (copy-file source destination t))))))))
+  (ennum-exp-apply
+   (lambda (&rest items)
+     (dolist (item items)
+       (dolist (destination (reverse (ennum-directory-files item nil t)))
+         ;; TODO: Print warning about overwriting files?
+         (let ((source (expand-file-name destination item)))
+           (unless (file-exists-p destination)
+             (if (file-directory-p source)
+                 (make-directory destination)
+               (copy-file source destination t)))))))
+   items))
 
 (defmacro ennum-make-functional-setter (name copier accessor)
   `(defun ,name (object new-value)
@@ -607,9 +653,11 @@ result as a string."
 
 (defun ennum-publish-index-home (first-index-page-output filename-prefix tongue)
   (ennum-exp
-   (ennum-copy (ennum--file-join first-index-page-output
-                                 (ennum-index-filename filename-prefix tongue "html" 1))
-               (ennum-add-tongue-suffix (format "%s.html" filename-prefix) tongue))))
+   (lambda (first-index-page-output)
+     (ennum-copy (ennum--file-join first-index-page-output
+                                   (ennum-index-filename filename-prefix tongue "html" 1))
+                 (ennum-add-tongue-suffix (format "%s.html" filename-prefix) tongue)))
+   first-index-page-output))
 
 (defun ennum-publish-index (filename-prefix title posts-per-page tongue posts)
   (let* ((number-of-pages (ceiling (length posts) posts-per-page))
@@ -648,24 +696,25 @@ result as a string."
                     (ennum-intern (ennum-post-filename post)))
                   posts)))
     (ennum-exp
-     (message "Writing %s" feed-file)
-     (when (file-name-directory feed-file)
-       (ennum-mkdir-p (file-name-directory feed-file)))
-     (with-temp-file feed-file
-       (insert
-        (xmlgen
-         `(feed :xmlns "http://www.w3.org/2005/Atom"
-                (id ,(ennum--absolute-uri ""))
-                (title ,title)
-                (updated ,(ennum--atom-date (ennum-post-date (seq-first posts))))
-                (link :rel "self" :href ,(ennum--absolute-uri feed-file))
-                (generator
-                 ,(format "Emacs %d.%d Org-mode %s ennum %s"
-                          emacs-major-version emacs-minor-version (org-version) ennum-version))
-                (rights ,rights)
-                ,@(seq-mapn (lambda (post interned-post-file)
-                              (ennum--feed-entry post interned-post-file))
-                            posts interned-post-files))))))))
+     (progn
+       (message "Writing %s" feed-file)
+       (when (file-name-directory feed-file)
+         (ennum-mkdir-p (file-name-directory feed-file)))
+       (with-temp-file feed-file
+         (insert
+          (xmlgen
+           `(feed :xmlns "http://www.w3.org/2005/Atom"
+                  (id ,(ennum--absolute-uri ""))
+                  (title ,title)
+                  (updated ,(ennum--atom-date (ennum-post-date (seq-first posts))))
+                  (link :rel "self" :href ,(ennum--absolute-uri feed-file))
+                  (generator
+                   ,(format "Emacs %d.%d Org-mode %s ennum %s"
+                            emacs-major-version emacs-minor-version (org-version) ennum-version))
+                  (rights ,rights)
+                  ,@(seq-mapn (lambda (post interned-post-file)
+                                (ennum--feed-entry post interned-post-file))
+                              posts interned-post-files)))))))))
 
 (defun ennum--feed-entry (post interned-post-file)
   (let ((link (url-encode-url
@@ -738,16 +787,17 @@ result as a string."
 
 (defun ennum-publish-image (image width)
   (ennum-exp
-   (message "Resizing %s to width %s" image width)
-   (ennum-mkdir-p (ennum-setting :images-directory))
-   (ennum-image-optimize-image
-    (ennum-image-resize-image
-     image
-     (ennum--file-join
-      (ennum-setting :images-directory)
-      (ennum-image-output-filename
-       (file-name-nondirectory image) width))
-     width))))
+   (progn
+     (message "Resizing %s to width %s" image width)
+     (ennum-mkdir-p (ennum-setting :images-directory))
+     (ennum-image-optimize-image
+      (ennum-image-resize-image
+       image
+       (ennum--file-join
+        (ennum-setting :images-directory)
+        (ennum-image-output-filename
+         (file-name-nondirectory image) width))
+       width)))))
 
 (defun ennum-publish-copy (file)
   (let ((interned-file (ennum-intern file)))
@@ -788,8 +838,8 @@ recognized as a directory, it should end in a slash. See
 (defun ennum--find-image (path)
   "Find store item for image with PATH."
   (or (seq-find 'file-exists-p
-                (seq-map (apply-partially 'expand-file-name
-                                          path)
+                (seq-map (lambda (exp)
+                           (expand-file-name path (ennum-eval exp)))
                          (ennum-setting :generated-image-paths)))
       (ennum-intern (ennum--file-join (ennum-setting :images-directory)
                                       path))))
@@ -902,7 +952,8 @@ as keys. Keys are compared using `equal'."
       (when (file-exists-p (ennum-setting :output-directory))
         (ennum--set-file-modes-recursively (ennum-setting :output-directory) #o755 #o644 #o755)
         (delete-directory (ennum-setting :output-directory) t))
-      (copy-directory result (ennum-setting :output-directory))
+      (copy-directory (ennum-eval result)
+                      (ennum-setting :output-directory))
       (message "Ennum published to %s" (expand-file-name (ennum-setting :output-directory))))))
 
 ;;; Server