Blob


1 (ns blog.core
2 (:require [blog.time :as time]
3 [blog.templates :as templates]
4 [blog.rss :as rss]
5 [boot.core :as core]
6 [boot.task.built-in :as task]
7 [ring.adapter.jetty :as jetty]
8 [ring.middleware.resource :refer [wrap-resource]]
9 [ring.middleware.content-type :refer [wrap-content-type]]
10 [clojure.java.io :as io]
11 [clojure.java.shell :refer [sh]])
12 (:import (java.io File)))
14 (defn copy-file [src dst]
15 (with-open [in (io/input-stream (io/file src))
16 out (io/output-stream (io/file dst))]
17 (io/copy in out)))
19 (defn post [{:keys [slug title short date tags]}]
20 (let [f (io/resource (str "posts/" slug ".md"))]
21 {:slug slug
22 :title title
23 :short short
24 :date (time/parse date)
25 :body (slurp f)
26 :tags tags}))
28 (def per-tag (atom {}))
29 (def posts (atom []))
31 (defn add-post! [m]
32 (let [p (post m)]
33 (swap! posts conj p)
34 (doseq [t (:tags m)]
35 (swap! per-tag update t conj p))))
37 (load "posts")
39 (defn create-dirs! []
40 (doseq [d ["resources/out"
41 "resources/out/css"
42 "resources/out/post"
43 "resources/out/tag"
44 "resources/out/img"]]
45 (.. (File. d) mkdirs)))
47 (defn post-pages []
48 (let [tags (keys @per-tag)]
49 (map-indexed (fn [i posts]
50 {:filename (if (= i 0)
51 "index.html"
52 (str (inc i) ".html"))
53 :tags tags
54 :nth (inc i)
55 :posts posts
56 :has-next true
57 :has-prev true})
58 (partition-all 6 @posts))))
60 (defn fix-next-last
61 "Fix the :has-prev/:has-next for the post pages. This assumes
62 that `(not (empty? post-pages))`"
63 [post-pages]
64 (-> post-pages
65 (->> (into []))
66 (update 0 assoc :has-prev false)
67 (update (dec (count post-pages)) assoc :has-next false)))
69 (defn render-post-list []
70 (doseq [p (fix-next-last (post-pages))
71 :let [{:keys [filename]} p]]
72 (spit (str "resources/out/" filename)
73 (templates/home-page p))))
75 (defn render-post [{s :slug, :as post}]
76 (spit (str "resources/out/post/" s ".html")
77 (templates/post-page post)))
79 (defn render-tags [tags]
80 (spit (str "resources/out/tags.html")
81 (templates/tags-page tags)))
83 (defn render-tag [tag posts]
84 (spit (str "resources/out/tag/" tag ".html")
85 (templates/tag-page tag posts)))
87 (defn render-rss []
88 (spit (str "resources/out/rss.xml")
89 (rss/feed @posts)))
91 (defn copy-dir
92 "Copy the content of resources/`dir` to resources/out/`dir`, assuming
93 these two directories exists. It does not copy recursively."
94 [dir]
95 (let [in (io/file (str "resources/" dir "/"))
96 out (str "resources/out/" dir "/")]
97 (doseq [f (->> in file-seq (filter #(.isFile %)))]
98 (io/copy f (io/file (str out (.getName f)))))))
100 (comment
101 (copy-dir "img")
102 (io/copy (io/file "resources/img/unbound-dashboard.png")
103 (io/file "resources/out/img/unbound-dashboard.png"))
106 (defn copy-assets
107 "Copy css and images to their places"
108 []
109 (copy-dir "img")
110 (copy-file "resources/favicon.ico" "resources/out/favicon.ico")
111 (copy-file "resources/css/style.css" "resources/out/css/style.css"))
113 (core/deftask build
114 "Build the blog"
115 []
116 (create-dirs!)
117 (copy-assets)
118 (render-rss)
119 (render-post-list)
120 (doseq [p @posts]
121 (render-post p))
122 (render-tags (keys @per-tag))
123 (doseq [t @per-tag
124 :let [[tag posts] t]]
125 (render-tag (name tag) posts)))
127 (def j (atom nil))
129 (core/deftask serve
130 "Serve a preview"
131 []
132 (reset!
134 (jetty/run-jetty (-> (fn [_] {:status 404, :body "not found"})
135 (wrap-resource "out")
136 (wrap-content-type))
137 {:port 3000
138 :join? false})))
140 (core/deftask clean
141 "clean the output directory"
142 []
143 (sh "rm" "-rf" "resources/out/"))
145 (core/deftask deploy
146 "Copy the files to the server"
147 []
148 (sh "openrsync" "-r" "--delete" "resources/out/" "op:sites/www.omarpolo.com/"))
150 (defn stop-jetty []
151 (.stop @j)
152 (reset! j nil))
154 (comment
155 (build)
156 (serve)
157 (stop-jetty)