build.boot 9.79 KB
Newer Older
phil's avatar
phil committed
1 2
(set-env!
 :source-paths #{"src"}
phil's avatar
phil committed
3
 :resource-paths #{"resources" "assets"}
phil's avatar
phil committed
4
 :dependencies '[[org.clojure/clojure "1.8.0"]
5
                 [perun "0.4.2-SNAPSHOT"]
phil's avatar
phil committed
6
                 [hiccup "1.0.5"]
phil's avatar
phil committed
7 8
                 [garden "1.3.2"]
                 [pandeiro/boot-http "0.7.3"]
9
                 [markdown-clj "1.0.1"]
phil's avatar
phil committed
10
                 [jeluard/boot-notify "0.1.2" :scope "test"]
phil's avatar
phil committed
11
                 [clj-http "2.3.0"]
phil's avatar
phil committed
12
                 [org.clojure/data.json "0.2.6"]
phil's avatar
phil committed
13
                 [deraen/boot-sass "0.3.1"]
phil's avatar
phil committed
14
                 [fsdb "0.2.1"]
phil's avatar
phil committed
15
                 [cpmcdaniel/boot-copy "1.0"]
Nick Niles's avatar
Nick Niles committed
16
                 [camel-snake-kebab "0.4.0"]])
phil's avatar
phil committed
17

18 19
(require '[boot.core :as boot]
         '[io.perun :as perun]
phil's avatar
phil committed
20
         '[io.perun.meta :as meta]
phil's avatar
phil committed
21
         '[io.perun.core :as perun-core]
phil's avatar
phil committed
22 23
         '[ok.index :as index-view]
         '[ok.post :as post-view]
24
         '[ok.data.technology]
Alain M. Lafon's avatar
Alain M. Lafon committed
25
         '[ok.data.project]
phil's avatar
phil committed
26
         '[pandeiro.boot-http :refer [serve]]
phil's avatar
phil committed
27
         '[garden.core :refer [css]]
phil's avatar
phil committed
28
         '[clojure.data.json]
phil's avatar
phil committed
29
         '[clj-http.client]
phil's avatar
phil committed
30
         '[fsdb.core :as fsdb]
phil's avatar
phil committed
31
         '[cpmcdaniel.boot-copy :refer :all]
phil's avatar
phil committed
32 33 34
         '[deraen.boot-sass :refer [sass]]
         '[clojure.string :refer [split]]
         '[clojure.java.shell :as shell])
35
;;'[jeluard.boot-notify :refer [notify]]
Alain M. Lafon's avatar
Alain M. Lafon committed
36

37 38 39 40
(defn is-of-type?
  [{:keys [permalink]} doc-type]
  (.startsWith permalink (str "/" doc-type)))

phil's avatar
phil committed
41
(deftask slack
Alain M. Lafon's avatar
Alain M. Lafon committed
42
  "Post `message` to slack."
phil's avatar
phil committed
43 44 45 46 47 48 49 50 51
  [u url URL str "The slack incoming webhook url"
   m message MESSAGE str "The slack message"]
  (with-post-wrap fileset
    (let [data {:username "GitLab CI"
                :text message
                :icon_emoji ":gitlabci:"}
          json (clojure.data.json/write-str data)]
      (clj-http.client/post url {:body json}))))

phil's avatar
phil committed
52 53 54 55 56 57
(deftask shellout
  "Run a shell command."
  [c cmd CMD str "The shell command to run."]
  (with-post-wrap fileset
    (apply shell/sh (split cmd #" "))))

phil's avatar
phil committed
58
(task-options!
phil's avatar
phil committed
59 60 61
 copy {:output-dir "target/public"
       ;; TODO: Make this regexp more readable. It has three parts:
       ;;       google search console + favicon stuff + other assets.
phil's avatar
phil committed
62
       :matching   #{#"(google.*\.html|safari-pinned-tab\.svg|favicon\.ico|browserconfig\.xml|manifest\.json|\.htaccess)|\.(css|js|png|jpg|svg|gif|pdf|woff|woff2)$" #".well-known"}}
phil's avatar
phil committed
63
 slack {:url "https://hooks.slack.com/services/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"})
phil's avatar
phil committed
64

65
(defn slug-fn
66
  "Slugs are derived from filenames of html files. They can have a
67
  YYYY-MM-DD- prefix or not."
68 69
  [_ {:keys [filename]}]
  (last (re-find #"(\d+-\d+-\d+-|)(.*)\.html" filename)))
Alain M. Lafon's avatar
Alain M. Lafon committed
70

71 72 73 74 75
(deftask set-meta-data
  "Add :key attribute with :val value to each file metadata and also
   to the global meta"
  [k key VAL kw "meta-data key"
   v val VAL str "meta-data value"]
Alain M. Lafon's avatar
Alain M. Lafon committed
76
  (with-pre-wrap fileset
phil's avatar
phil committed
77 78
    (let [files           (meta/get-meta fileset)
          global-meta     (meta/get-global-meta fileset)
79 80
          updated-files   (map #(assoc % key val) files)
          new-global-meta (assoc global-meta key val)
phil's avatar
phil committed
81 82
          updated-fs      (meta/set-meta fileset updated-files)]
      (meta/set-global-meta updated-fs new-global-meta))))
83

84 85 86 87
(deftask categories
  "Add :categories of all posts to the meta-data"
  []
  (with-pre-wrap fileset
88 89
    (let [files           (filter #(is-of-type? % "posts")
                                  (meta/get-meta fileset))
phil's avatar
phil committed
90
          global-meta     (meta/get-global-meta fileset)
91
          categories      (filter #(:category %) files)
92 93
          updated-files   (map #(assoc % :categories categories) files)
          new-global-meta (assoc global-meta :categories categories)
phil's avatar
phil committed
94 95
          updated-fs      (meta/set-meta fileset updated-files)]
      (meta/set-global-meta updated-fs new-global-meta))))
96

97 98 99
(defn category-grouper
  [entries]
  (reduce (fn [result entry]
100 101
            (let [category (clojure.string/lower-case
                            (:category entry))
102 103 104 105 106 107 108
                  path (str category ".html")]
              (-> result
                  (update-in [path :entries] conj entry)
                  (assoc-in [path :entry :category] category))))
          {}
          entries))

phil's avatar
phil committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
(deftask fsdb
  "Loads fsdb and adds it as meta to the fileset."
  [f fsdb FSDB str "fsdb path"]
  (with-pre-wrap fileset
    (->> (fsdb/read-tree "manifest")
         ;; have to use :io.perun.global here to have it merged into
         ;; static's meta
         (assoc-in (meta fileset) [:io.perun.global :fsdb])
         (with-meta fileset))))

(deftask print-global-meta
  []
  (with-pre-wrap fileset
    (perun-core/report-info "print-global-meta" (meta fileset))
    fileset))
phil's avatar
phil committed
124

125 126
(defn my-grouper [group-key global-meta entries]
  (let [items (-> global-meta :fsdb :manifest group-key)]
phil's avatar
phil committed
127
    ;; TODO `apply merge map`, feels like it should use `into`
128
    (apply merge (map (fn [[key item]]
phil's avatar
phil committed
129 130 131
                        {(str (name key) ".html")
                         {:entries []
                          :entry nil
phil's avatar
phil committed
132
                          :meta global-meta
133
                          :meta-entry item}}) items))))
134 135 136 137

(deftask global-assortment
  "Renders an assortment using global metadata"
  [o out-dir    OUTDIR     str   "the output directory"
138 139
   r renderer   RENDERER   sym   "page renderer (fully qualified symbol resolving to a function)"
   k group-key  GROUPKEY   kw    "key on which to group"]
phil's avatar
phil committed
140 141 142 143 144 145 146
  (fn [next-task]
    (fn [fileset]
      (let [global-meta (io.perun.meta/get-global-meta fileset)
            task-fn (perun/assortment-task {:task-name "global-assortment"
                                            :renderer renderer
                                            :out-dir out-dir
                                            :filterer identity
phil's avatar
phil committed
147 148
                                            :sortby :date-created
                                            :comparator compare
149
                                            :grouper (partial my-grouper group-key global-meta)})]
phil's avatar
phil committed
150
        ((task-fn next-task) fileset)))))
151

152 153 154
(deftask check4programs
  "Checks whether externally required binaries are available."
  []
155 156 157 158 159
  (with-pre-wrap fileset
    (if-not (= 0 (:exit (shell/sh "which" "rsync")))
      (throw (Exception. "No rsync installed!"))
      (println "All required programs are installed!"))
    fileset))
160

phil's avatar
phil committed
161
(deftask build
Alain M. Lafon's avatar
Alain M. Lafon committed
162
  "Build the 200ok page."
phil's avatar
phil committed
163
  []
164 165 166 167 168 169 170 171 172
  (comp
   (perun/markdown)
   (perun/draft)
   ;;(print-meta)
   (perun/slug :slug-fn slug-fn)
   (perun/ttr)
   (categories)
   (perun/word-count)
   (perun/build-date)
173 174 175
   ;;(perun/gravatar
   ;; :source-key :author-email
   ;; :target-key :author-gravatar)
phil's avatar
phil committed
176

177
   (perun/paginate
178
    :renderer 'ok.index/render
179 180 181 182 183 184 185
    ;; Pagination numbering starts at `1` in Perun. Don't include
    ;; pagination info on the first page ("blog.html") and then start
    ;; with "blog-2.html".
    :slug-fn (fn [num] (if (= 1 num)
                         "blog"
                         (str "blog-" num)))
    :page-size 10
186
    :sortby :date-created
187
    :filterer #(is-of-type? % "posts"))
phil's avatar
phil committed
188

189 190
   (fsdb)
   ;;(print-global-meta)
phil's avatar
phil committed
191

192 193 194 195 196 197 198 199
   (perun/static :renderer 'ok.data.index/page        :page "index.html")
   (perun/static :renderer 'ok.data.people/page       :page "people.html")
   (perun/static :renderer 'ok.data.technologies/page :page "technologies.html")
   (perun/static :renderer 'ok.data.locations/page    :page "locations.html")
   (perun/static :renderer 'ok.data.clients/page      :page "clients.html")
   (perun/static :renderer 'ok.data.services/page     :page "services.html")
   (perun/static :renderer 'ok.data.projects/page     :page "projects.html")
   (perun/static :renderer 'ok.data.opensourced/page  :page "opensource.html")
200 201
   (perun/static :renderer 'ok.errors/page-old-ie     :page "ie-fallback.html")
   (perun/static :renderer 'ok.errors/page-404        :page "404.html")
202

203 204 205
   (global-assortment :renderer 'ok.data.technology/page
                      :out-dir "public/technology"
                      :group-key :technologies)
206

207 208 209
   (global-assortment :renderer 'ok.data.project/page
                      :out-dir "public/project"
                      :group-key :projects)
210

211
   ;; TODO omit for prod
phil's avatar
phil committed
212
   (perun/static :renderer 'ok.data.debug/page :page "debug.html")
phil's avatar
phil committed
213

214 215 216 217
   (perun/collection
    :renderer 'ok.person/render-collection
    :page "team.html"
    :filterer #(is-of-type? % "team"))
phil's avatar
phil committed
218

219 220 221 222 223 224 225
   ;; Groups all posts that have a :category (yes, only a single one
   ;; atm) into one file. For example a post with a :category of
   ;; "emacs" will be rendered into a file
   ;; "public/category/emacs.html" together with every other post
   ;; with the same tag.
   (perun/assortment :renderer 'ok.index/render
                     :grouper category-grouper
phil's avatar
phil committed
226
                     :sortby :date-created
227 228
                     :out-dir "public/category"
                     :filterer #(is-of-type? % "posts"))
phil's avatar
phil committed
229

phil's avatar
phil committed
230
   ;; renders each md file in `posts` into its own page
231 232
   (perun/render :renderer 'ok.post/render
                 :filterer #(is-of-type? % "posts"))
233

234 235
   (perun/render :renderer 'ok.page/render
                 :filterer #(is-of-type? % "audio-book"))
236

237 238 239 240 241 242
   (perun/sitemap)
   ;;(print-global-meta)
   (perun/atom-feed :filterer #(is-of-type? % "posts")
                    ;; setting base-url explicitly is a quickfix for
                    ;; a perun bug of some sort
                    :base-url "http://200ok.ch/")
phil's avatar
phil committed
243
   (perun/rss :filterer #(is-of-type? % "posts")
244
              :filename "rss.xml")
245

246 247 248 249
   ;;(notify)
   ;;(print-meta)
   (sass)
   (target)
phil's avatar
phil committed
250 251 252 253
   (copy) ; oldschool
   ;; newschool: rsyncs everything in assets/ to target/public/
   ;;(shellout :cmd "rsync -a assets/ target/public/")
   ))
phil's avatar
phil committed
254 255 256

(deftask dev
  []
phil's avatar
phil committed
257
  (comp
258
   (check4programs)
phil's avatar
phil committed
259
   (watch)
phil's avatar
phil committed
260
   (perun/global-metadata)
261 262
   (set-meta-data :key :target
                  :val "dev")
phil's avatar
phil committed
263
   (build)
Nick Niles's avatar
Nick Niles committed
264
   (serve :dir "target/public")))
Alain M. Lafon's avatar
Alain M. Lafon committed
265 266 267 268

(deftask prod
  []
  (comp
269
   (check4programs)
phil's avatar
phil committed
270
   ;;(slack :message "<http://200ok.ch|200ok.ch> has been updated.")
phil's avatar
phil committed
271
   (perun/global-metadata)
272 273
   (set-meta-data :key :target
                  :val "prod")
274
   (build)))