diff --git a/clojure/src/firn/build.clj b/clojure/src/firn/build.clj index 9ff57376..f4efeafb 100644 --- a/clojure/src/firn/build.clj +++ b/clojure/src/firn/build.clj @@ -44,6 +44,13 @@ (io/make-parents (:out-name f)) (spit (:out-name f) (:contents f))))))) +(defn copy-static-files + [config] + (when-not (fs/exists? (config :dir-site-attach)) + (fs/copy-dir (config :dir-attach) (config :dir-site-attach))) + (when-not (fs/exists? (config :dir-site-static)) + (fs/copy-dir (config :dir-static) (config :dir-site-static)))) + (defn setup "Creates folders for output, slurps in layouts and partials. NOTE: should slurp/mkdir/copy-dir be wrapped in try-catches? if-err handling?" @@ -58,7 +65,7 @@ (fs/mkdir (config :dir-site)) ;; make _site - ;; copy attachments and static files too final _site dir. + ;; copy attachments and static files to final _site dir. (when-not (fs/exists? (config :dir-site-attach)) (fs/copy-dir (config :dir-attach) (config :dir-site-attach))) (when-not (fs/exists? (config :dir-site-static)) @@ -87,41 +94,53 @@ ;; -- Server -- -(defn file-server-middleware - [{:keys [dir-site dir-files] :as config}] - +(defn handler + "Handles web requests for the development server. + FIXME: Needs a file watcher for determining when to copy files into dir-site" + [{:keys [dir-firn dir-site] :as config}] (fn [request] - ;; This is naive; everytime we visit a page it runs the build step. - (let [res-file-system ((r-file/wrap-file request dir-site) request) - req-uri-file (s/join "" (-> request :uri rest)) ;; we have to trim the requested uri because it comes in as "/my-link"; but they are in memory as "my-link" - file-html (get-in config [:processed-files req-uri-file :as-html]) + (let [; first we try and get the request to load from the files system + res-file-system ((r-file/wrap-file request dir-site) request) + ;; then we pull the uri out of req and format it: `/this-is/my-req` -> `this-is/my-req` + req-uri-file (s/join "" (-> request :uri rest)) + ;; use the uri to pull values out of memory in config + memory-file (get-in config [:processed-files req-uri-file]) + ;; a ring response for when nothing is found. four-oh-four {:status 404 :body "File not found."}] - ;; TODO: - re-process single file when hit by route. - ;; TODO: - all links with .html in them need to be stripped? ;; TODO: - make sure index is rendering from memory? (cond - (some? file-html) (response file-html) - (some? res-file-system) res-file-system - :else four-oh-four)))) + ;; If the request was found to match in the config... + (some? memory-file) + ;; let's re-slurp the file in case it's changed + ;; someday this will be handled by a file watcher. + (let [reloaded-file (file/reload-requested-file memory-file config)] + ;; then we can respones with the reloaded-files's html. + (response (reloaded-file :as-html))) + + ;; If the file isn't found in memory, let's try using a file in the _firn/_site fs. + (some? res-file-system) + res-file-system + + :else + four-oh-four)))) (defstate server :start (let [args (mount/args) dir-files (get args :-path (u/get-cwd)) - path-to-site (str dir-files "_firn/_site") - ;; config (setup (config/prepare dir-files)) - config (-> (config/prepare dir-files) setup file/process-all) ;; basically doing `all-files` + path-to-site (str dir-files "/_firn/_site") + ;; build all files and prepare a config. + config (-> dir-files config/prepare setup file/process-all) port 3333] (println "Building site...") - ;; (all-files {:dir-files dir-files}) ;; we don't need this; we hold files in memory rn (if-not (fs/exists? path-to-site) (println "Couldn't find a _firn/ folder. Have you run `Firn new` and created a site yet?") (do (println "🏔 Starting Firn development server on:" port) - (http/run-server (file-server-middleware config) {:port port})))) + (http/run-server (handler config) {:port port})))) :stop (when server (server :timeout 100))) (defn serve [opts] - ;; TODO: build the whole site before running the server. (mount/start-with-args opts)) -;; (serve {:-path "/Users/tees/Dropbox/wiki/"}) +;; cider won't boot if this is uncommented at jack-in: +(serve {:-path "/Users/tees/Projects/firn/firn/clojure/test/firn/demo_org"}) diff --git a/clojure/src/firn/config.clj b/clojure/src/firn/config.clj index 1d421554..ea5c7c24 100644 --- a/clojure/src/firn/config.clj +++ b/clojure/src/firn/config.clj @@ -27,18 +27,23 @@ (defn default "Assume that files-dir does NOT end in a `/`ex: /Users/tees/Dropbox/wiki" - [dir-files] - (merge starting-config - {:dir-firn (make-dir-firn dir-files) - :dir-attach (str dir-files "/" (starting-config :dir-attach)) - :dir-files dir-files - :dir-layouts (str dir-files "/_firn/layouts/") - :dir-partials (str dir-files "/_firn/partials/") - :dir-site (str dir-files "/_firn/_site/") - :dir-site-attach (str dir-files "/_firn/_site/" (starting-config :dir-attach)) - :dir-site-static (str dir-files "/_firn/_site/static/") - :dir-static (str dir-files "/_firn/static/") - :dirname-files (-> dir-files (s/split #"/") last)})) ;; the name of the dir where files are. + ([dir-files] + (default dir-files {})) + + ([dir-files external-config] + (let [base-config (merge starting-config external-config)] + (merge starting-config + {:dir-firn (make-dir-firn dir-files) + :dir-attach (str dir-files "/" (base-config :dir-attach)) + :dir-files dir-files + :dir-layouts (str dir-files "/_firn/layouts/") + :dir-partials (str dir-files "/_firn/partials/") + ;; all outputted _site directories. + :dir-site (str dir-files "/_firn/_site/") + :dir-site-attach (str dir-files "/_firn/_site/" (base-config :dir-attach)) + :dir-site-static (str dir-files "/_firn/_site/static/") + :dir-static (str dir-files "/_firn/static/") + :dirname-files (-> dir-files (s/split #"/") last)})))) ;; the name of the dir where files are. (defn clean-config "Takes the user config and strips any keys from it that shouldn't be changed @@ -64,13 +69,19 @@ ;; No config found (do (println "Didn't find a _firn site. Have you run `firn new` yet?") - (System/exit 0)) ;; TODO: good place for a "if DEV..." so the repl doesn't close. + #_(System/exit 0)) ;; TODO: good place for a "if DEV..." so the repl doesn't close. ;; try and read the config (try (let [read-config (sci/eval-string (slurp (str (default-config :dir-firn) "/config.edn"))) cleaned-config (clean-config read-config) - merged-config (merge default-config cleaned-config)] - merged-config) + final-config (default wiki-path cleaned-config)] + final-config) + ;; merged-with-sample-config (merge base-config cleaned-config) + ;; final-config (default merged-with-sample-config)] + + ;; merged-config (merge default-config cleaned-config)] + ;; (prn "merged config is " final-config) + ;; final-config) (catch Exception ex (println "Failed to read 'config.edn' file - is it properly formatted?")))))) diff --git a/clojure/src/firn/file.clj b/clojure/src/firn/file.clj index 45df467a..621c071c 100644 --- a/clojure/src/firn/file.clj +++ b/clojure/src/firn/file.clj @@ -8,7 +8,8 @@ [cheshire.core :as json] [firn.util :as u] [firn.org :as org] - [firn.layout :as layout])) + [firn.layout :as layout] + [clojure.java.io :as io])) (defn strip-file-ext "Removes a file extension from a file path string. @@ -156,8 +157,8 @@ (let [layout (keyword (get-keyword f "FIRN_LAYOUT")) as-html (when-not (is-private? config f) (layout/apply-layout config f layout))] - as-html - #_(change f {:as-html as-html}))) + ;; as-html + (change f {:as-html as-html}))) (defn process-one "Munge the 'file' datastructure; slowly filling it up, using let-shadowing. @@ -172,8 +173,8 @@ :org-title (get-keyword new-file "TITLE") :links (file-metadata :links) :logbook (file-metadata :logbook)}) - new-file (change new-file {:as-html (htmlify config new-file)})] - new-file)) + final-file (htmlify config new-file)] + final-file)) (defn process-all "Receives config, processes all files and builds up site-data @@ -187,11 +188,12 @@ (loop [org-files (config :org-files) output {}] (if (empty? org-files) - (assoc config - :processed-files output - :site-map @site-map - :site-links @site-links - :site-logs @site-logs) + ;; LOOP/RECUR: BREAK run one more loop on all files, and create their + ;; html, now ;; that we have processed everything. + (let [config-with-data (assoc config :processed-files output :site-map @site-map :site-links @site-links :site-logs @site-logs) + with-html (into {} (for [[k pf] output] [k (htmlify config-with-data pf)])) + final (assoc config :processed-files with-html)] + final) (let [next-file (first org-files) processed-file (process-one config next-file) @@ -201,11 +203,21 @@ new-site-map (merge keyword-map {:path (processed-file :path-web)}) file-metadata (extract-metadata processed-file)] ;; FIXME: why are we calling this once when we can pull the results out from `processed-file / via procssed one`?! - ;; add to sitemap when file is not private. (when-not (is-private? config processed-file) + ;; (swap! site-map concat @site-map new-site-map) (swap! site-map conj new-site-map) (swap! site-links concat @site-links (:links file-metadata)) (swap! site-logs concat @site-logs (:logbook file-metadata))) ;; add links and logs to site wide data. (recur org-files output)))))) + + + +(defn reload-requested-file + "Take a request to a file, pulls the file out of memory + grabs the path of the original file, reslurps it and reprocesses" + [file config] + (let [re-slurped (-> file :path io/file) + re-processed (process-one config re-slurped)] + re-processed))