Skip to content

Instantly share code, notes, and snippets.

@Deraen
Created April 26, 2017 17:05
Show Gist options
  • Select an option

  • Save Deraen/bd82e3a785e33aecc411c4911f7b4d81 to your computer and use it in GitHub Desktop.

Select an option

Save Deraen/bd82e3a785e33aecc411c4911f7b4d81 to your computer and use it in GitHub Desktop.
boot_static.clj
(ns site.build
(:require [boot.core :as boot]
[boot.pod :as pod]
[boot.util :as util]
[clojure.string :as string]
[clojure.java.io :as io]
[clojure.tools.namespace.dir :as dir]
[clojure.tools.namespace.track :as track]
[clojure.tools.namespace.reload :as reload]))
(def tracker (atom nil))
;; Super simple, no pods
;; Only single task in the same clojure env ever
(defn page-name [ns-sym]
(second (re-find #"^site\.static\.(.+)$" (name ns-sym))))
(defn filter-load
"Only load namespaces that are already loaded, or those that define
static pages."
[{load ::track/load :as tracker}]
(assoc tracker ::track/load (filter #(or (find-ns %) (page-name %)) load)))
(defn setup-render-queue
"Copy static page namespaces from load queue into render queue.
Namespaces are only removed from render queue when they are successfully
rendered, due to this distinct is used to prevent duplicates in queue."
[{render ::render, load ::track/load :as tracker}]
(assoc tracker ::render (distinct (into render (filter page-name load)))))
(defn render-one
[tracker tmp fileset]
(let [{render ::render} tracker]
(if (seq render)
(let [n (first render)]
(try
(require n)
(if-let [render-fn (resolve (symbol (name n) "render"))]
(do
(util/info "Render %s\n" (name n))
(let [parts (string/split (page-name n) #"\.")
parts (if (= "index" (last parts))
(conj (vec (butlast parts)) "index.html")
(conj parts "index.html"))]
(doto (apply io/file tmp "public" parts)
io/make-parents
(spit (render-fn fileset))))
(update-in tracker [::render] rest))
(throw (ex-info "No render fn on namespace %s (or errors loading the ns?)\n" {:n n})))
(catch Throwable t
(assoc tracker ::render-error t ::render-error-ns n))))
tracker)))
(defn render
[tracker tmp fileset]
(util/info "Building %d static pages...\n" (count (::render tracker)))
(loop [tracker (dissoc tracker ::render-error)]
(let [{render-error ::render-error, render ::render} tracker]
(if (and (not render-error)
(seq render))
(recur (render-one tracker tmp fileset))
tracker))))
(boot/deftask static
"Render e.g. site.static.foo namespace -> foo/index.html"
[]
(let [tmp (boot/tmp-dir!)]
(fn [next-handler]
(fn [fileset]
(swap! tracker (fn [tracker]
(util/dbug "Scan directories: %s\n" (pr-str (:directories pod/env)))
(dir/scan-dirs (or tracker (track/tracker)) (:directories pod/env))))
(util/dbug "Unload: %s\n" (pr-str (::track/unload @tracker)))
(util/dbug "Load: %s\n" (pr-str (::track/load @tracker)))
(swap! tracker filter-load)
(swap! tracker setup-render-queue)
(swap! tracker reload/track-reload)
(try
(when (::reload/error @tracker)
(util/fail "Error reloading: %s\n" (name (::reload/error-ns @tracker)))
(throw (::reload/error @tracker)))
(catch java.io.FileNotFoundException e
(util/info "Reseting tracker due to file not found exception, all namespaces will be reloaded next time.\n")
(reset! tracker (track/tracker))
(throw e)))
(swap! tracker render tmp fileset)
(when (::render-error @tracker)
(util/fail "Error rendering: %s\n" (::render-error-ns @tracker))
(throw (::render-error @tracker)))
(-> fileset
(boot/add-resource tmp)
boot/commit!
next-handler)))))
(ns site.static.index
(:require [hiccup.core :refer [html]]
[hiccup.page :refer [html5]]
[io.perun.core :as perun]))
(defn render [fileset]
(let [meta (perun/get-global-meta fileset)
entries (perun/get-meta fileset)]
(html5
(common/head {})
[:body
(common/header {})
[:div.container ...]])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment