Skip to content

Commit 424bf35

Browse files
mkzampino
andauthored
Allow to disable welcome page (#561)
When passing the same `:paths` or `:paths-fn` arg as for `build!` to `serve!` Clerk will no longer the built-in welcome page and instead serve the generated or user-specified index page on root. This is a first step towards enabling easy sharing fully interactive Clerk documents including pagination &c. Co-authored-by: Andrea Amantini <[email protected]>
1 parent 3fce7ea commit 424bf35

File tree

13 files changed

+348
-224
lines changed

13 files changed

+348
-224
lines changed

deps.edn

+4
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@
7373
:exclusions [org.babashka/sci]}
7474
io.github.nextjournal/clerk-slideshow {:git/sha "11a83fea564da04b9d17734f2031a4921d917893"}}}
7575

76+
:nextjournal/garden {:exec-fn nextjournal.clerk/serve!
77+
:exec-args {:index "book.clj"}
78+
:nextjournal.garden/aliases [:demo]}
79+
7680
:build {:deps {io.github.nextjournal/clerk {:local/root "."}
7781
io.github.nextjournal/cas-client {:git/sha "22ef8360689cd3938e43a3223023ab1b9711818f"}
7882
io.github.clojure/tools.build {:git/tag "v0.6.1" :git/sha "515b334"}

garden.edn

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{:project "book-of-clerk"}

notebooks/intern.clj

-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ c
3333
(ns-unmap *ns* 'variable)
3434
(ns-unmap (find-ns 'foreign) 'variable)
3535

36-
(reset! nextjournal.clerk.webserver/!doc nextjournal.clerk.webserver/help-doc)
37-
3836
;; inspect recorded interns
3937
(-> @nextjournal.clerk.webserver/!doc
4038
:blocks (->> (mapcat (comp :nextjournal/interned :result))))

src/nextjournal/clerk.clj

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
[nextjournal.clerk.config :as config]
1212
[nextjournal.clerk.eval :as eval]
1313
[nextjournal.clerk.parser :as parser]
14+
[nextjournal.clerk.paths :as paths]
1415
[nextjournal.clerk.viewer :as v]
1516
[nextjournal.clerk.webserver :as webserver]))
1617

@@ -51,7 +52,10 @@
5152

5253
:else
5354
file-or-ns)
54-
doc (try (merge opts
55+
doc (try (merge (webserver/get-build-opts)
56+
opts
57+
(when-let [path (paths/path-in-cwd file-or-ns)]
58+
{:file-path path})
5559
{:nav-path (webserver/->nav-path file-or-ns)}
5660
(parser/parse-file {:doc? true} file))
5761
(catch java.io.FileNotFoundException _e
@@ -63,7 +67,8 @@
6367
e))))
6468
_ (reset! !last-file file)
6569
{:keys [blob->result]} @webserver/!doc
66-
{:keys [result time-ms]} (try (eval/time-ms (eval/+eval-results blob->result (assoc doc :set-status-fn webserver/set-status!)))
70+
{:keys [result time-ms]} (try (eval/time-ms (binding [paths/*build-opts* (webserver/get-build-opts)]
71+
(eval/+eval-results blob->result (assoc doc :set-status-fn webserver/set-status!))))
6772
(catch Exception e
6873
(throw (ex-info (str "`nextjournal.clerk/show!` encountered an eval error with: `" (pr-str file-or-ns) "`") {::doc (assoc doc :blob->result blob->result)} e))))]
6974
(println (str "Clerk evaluated '" file "' in " time-ms "ms."))

src/nextjournal/clerk/builder.clj

+6-113
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@
22
"Clerk's Static App Builder."
33
(:require [babashka.fs :as fs]
44
[babashka.process :refer [sh]]
5-
[clojure.edn :as edn]
65
[clojure.java.browse :as browse]
76
[clojure.java.io :as io]
87
[clojure.string :as str]
98
[nextjournal.clerk.analyzer :as analyzer]
109
[nextjournal.clerk.builder-ui :as builder-ui]
10+
[nextjournal.clerk.config :as config]
1111
[nextjournal.clerk.eval :as eval]
1212
[nextjournal.clerk.parser :as parser]
13+
[nextjournal.clerk.paths :as paths]
1314
[nextjournal.clerk.view :as view]
1415
[nextjournal.clerk.viewer :as viewer]
15-
[nextjournal.clerk.webserver :as webserver]
16-
[nextjournal.clerk.config :as config])
17-
(:import (java.net URL)))
16+
[nextjournal.clerk.webserver :as webserver]))
1817

1918
(def clerk-docs
2019
(into ["CHANGELOG.md"
@@ -127,84 +126,6 @@
127126
(def default-out-path
128127
(str "public" fs/file-separator "build"))
129128

130-
(defn ^:private ensure-not-empty [build-opts {:as opts :keys [error expanded-paths]}]
131-
(if error
132-
opts
133-
(if (empty? expanded-paths)
134-
(merge {:error "nothing to build" :expanded-paths expanded-paths} (select-keys build-opts [:paths :paths-fn :index]))
135-
opts)))
136-
137-
(defn ^:private maybe-add-index [{:as build-opts :keys [index]} {:as opts :keys [expanded-paths]}]
138-
(if-not (contains? build-opts :index)
139-
opts
140-
(if (and (not (instance? URL index))
141-
(not (symbol? index))
142-
(or (not (string? index)) (not (fs/exists? index))))
143-
{:error "`:index` must be either an instance of java.net.URL or a string and point to an existing file"
144-
:index index}
145-
(cond-> opts
146-
(and index (not (contains? (set expanded-paths) index)))
147-
(update :expanded-paths conj index)))))
148-
149-
#_(maybe-add-index {:index "book.clj"} {:expanded-paths ["README.md"]})
150-
#_(maybe-add-index {:index 'book.clj} {:expanded-paths ["README.md"]})
151-
152-
(defn resolve-paths [{:as build-opts :keys [paths paths-fn index]}]
153-
(when (and paths paths-fn)
154-
(binding [*out* *err*]
155-
(println "[info] both `:paths` and `:paths-fn` are set, `:paths` will take precendence.")))
156-
(if (not (or paths paths-fn index))
157-
{:error "must set either `:paths`, `:paths-fn` or `:index`."
158-
:build-opts build-opts}
159-
(cond paths (if (sequential? paths)
160-
{:resolved-paths paths}
161-
{:error "`:paths` must be sequential" :paths paths})
162-
paths-fn (let [ex-msg "`:path-fn` must be a qualified symbol pointing at an existing var."]
163-
(if-not (qualified-symbol? paths-fn)
164-
{:error ex-msg :paths-fn paths-fn}
165-
(if-some [resolved-var (try (requiring-resolve paths-fn)
166-
(catch Exception _e nil))]
167-
(let [{:as opts :keys [error paths]}
168-
(try {:paths (cond-> @resolved-var (fn? @resolved-var) (apply []))}
169-
(catch Exception e
170-
{:error (str "An error occured invoking `" (pr-str resolved-var) "`: " (ex-message e))
171-
:paths-fn paths-fn}))]
172-
(if error
173-
opts
174-
(if-not (sequential? paths)
175-
{:error (str "`:paths-fn` must compute to a sequential value.")
176-
:paths-fn paths-fn :resolved-paths paths}
177-
{:resolved-paths paths})))
178-
{:error ex-msg :paths-fn paths-fn})))
179-
index {:resolved-paths []})))
180-
181-
#_(resolve-paths {:paths ["notebooks/di*.clj"]})
182-
#_(resolve-paths {:paths-fn 'clojure.core/inc})
183-
#_(resolve-paths {:paths-fn 'nextjournal.clerk.builder/clerk-docs})
184-
185-
(defn expand-paths [build-opts]
186-
(let [{:as opts :keys [error resolved-paths]} (resolve-paths build-opts)]
187-
(if error
188-
opts
189-
(->> resolved-paths
190-
(mapcat (fn [path] (if (fs/exists? path)
191-
[path]
192-
(fs/glob "." path))))
193-
(filter (complement fs/directory?))
194-
(mapv (comp str fs/file))
195-
(hash-map :expanded-paths)
196-
(maybe-add-index build-opts)
197-
(ensure-not-empty build-opts)))))
198-
199-
#_(expand-paths {:paths ["notebooks/di*.clj"] :index "src/nextjournal/clerk/index.clj"})
200-
#_(expand-paths {:paths ['notebooks/rule_30.clj]})
201-
#_(expand-paths {:index "book.clj"})
202-
#_(expand-paths {:paths-fn `clerk-docs})
203-
#_(expand-paths {:paths-fn `clerk-docs-2})
204-
#_(do (defn my-paths [] ["notebooks/h*.clj"])§
205-
(expand-paths {:paths-fn `my-paths}))
206-
#_(expand-paths {:paths ["notebooks/viewers**"]})
207-
208129
(def builtin-index
209130
(io/resource "nextjournal/clerk/index.clj"))
210131

@@ -216,17 +137,15 @@
216137
(let [opts+index (cond-> opts
217138
index (assoc :index (str index)))
218139
{:as opts' :keys [expanded-paths]} (cond-> opts+index
219-
expand-paths? (merge (expand-paths opts+index)))]
140+
expand-paths? (merge (paths/expand-paths opts+index)))]
220141
(-> opts'
221142
(update :resource->url #(merge {} %2 %1) @config/!resource->url)
222143
(cond-> #_opts'
223144
expand-paths?
224145
(dissoc :expand-paths?)
225-
(and (not index) (= 1 (count expanded-paths)))
226-
(assoc :index (first expanded-paths))
227146
(and (not index) (< 1 (count expanded-paths)) (every? (complement viewer/index-path?) expanded-paths))
228147
(as-> opts
229-
(-> opts (assoc :index builtin-index) (update :expanded-paths conj builtin-index))))))))
148+
(-> opts (assoc :index builtin-index) (update :expanded-paths conj builtin-index))))))))
230149

231150
#_(process-build-opts {:index 'book.clj :expand-paths? true})
232151
#_(process-build-opts {:paths ["notebooks/rule_30.clj"] :expand-paths? true})
@@ -336,31 +255,6 @@
336255
(str (viewer/relative-root-prefix-from (viewer/map-index opts file)) path
337256
(when fragment (str "#" fragment))))))
338257

339-
(defn read-opts-from-deps-edn! []
340-
(if (fs/exists? "deps.edn")
341-
(let [deps-edn (edn/read-string (slurp "deps.edn"))]
342-
(if-some [clerk-alias (get-in deps-edn [:aliases :nextjournal/clerk])]
343-
(get clerk-alias :exec-args
344-
{:error (str "No `:exec-args` found in `:nextjournal/clerk` alias.")})
345-
{:error (str "No `:nextjournal/clerk` alias found in `deps.edn`.")}))
346-
{:error (str "No `deps.edn` found in project.")}))
347-
348-
(def ^:dynamic ^:private *build-opts* nil)
349-
(def build-help-link "\n\nLearn how to [set up your static build](https://book.clerk.vision/#static-building).")
350-
(defn index-paths
351-
([] (index-paths (or *build-opts* (read-opts-from-deps-edn!))))
352-
([{:as opts :keys [index error]}]
353-
(if error
354-
(update opts :error str build-help-link)
355-
(let [{:as result :keys [expanded-paths error]} (expand-paths opts)]
356-
(if error
357-
(update result :error str build-help-link)
358-
{:paths (remove #{index "index.clj"} expanded-paths)})))))
359-
360-
#_(index-paths)
361-
#_(index-paths {:paths ["CHANGELOG.md"]})
362-
#_(index-paths {:paths-fn "boom"})
363-
364258
(defn build-static-app! [{:as opts :keys [bundle?]}]
365259
(let [{:as opts :keys [download-cache-fn upload-cache-fn report-fn compile-css? expanded-paths error]}
366260
(process-build-opts (assoc opts :expand-paths? true))
@@ -391,11 +285,10 @@
391285
(let [{result :result duration :time-ms} (eval/time-ms
392286
(try
393287
(binding [*ns* *ns*
394-
*build-opts* opts
288+
paths/*build-opts* opts
395289
viewer/doc-url (partial doc-url opts file)]
396290
(let [doc (eval/eval-analyzed-doc doc)]
397291
(assoc doc :viewer (view/doc->viewer (assoc opts
398-
:static-build? true
399292
:nav-path (if (instance? java.net.URL file)
400293
(str "'" (:ns doc))
401294
(str file)))

src/nextjournal/clerk/git.clj

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
(ns nextjournal.clerk.git
2+
"Clerk's Git integration for backlinks to source code repos."
3+
(:require [babashka.process :as p]
4+
[clojure.string :as str]))
5+
6+
(defn ^:private shell-out-str
7+
"Shell helper, calls a cmd and returns it output string trimmed."
8+
[cmd]
9+
(str/trim (:out (p/shell {:out :string} cmd))))
10+
11+
#_(shell-out-str "git rev-parse HEAD")
12+
#_(shell-out-str "zonk")
13+
14+
(defn ->github-project [remote-url]
15+
(second (re-find #"^git@github\.com:(.*)\.git$" remote-url)))
16+
17+
(defn ->https-git-url
18+
"Takes a git `remote-url` and tries to convert it into a https url for
19+
backlinks. Currently only works for github, should be extended for
20+
gitlab, etc."
21+
[remote-url]
22+
(cond
23+
(str/starts-with? remote-url "https://")
24+
(str/replace remote-url #"\.git$" "")
25+
26+
(->github-project remote-url)
27+
(str "https://github.com/%s" (->github-project remote-url))))
28+
29+
#_(->https-git-url "https://github.com/nextjournal/clerk.git")
30+
#_(->https-git-url "[email protected]:nextjournal/clerk.git")
31+
32+
(defn read-git-attrs []
33+
(try {:git/sha (shell-out-str "git rev-parse HEAD")
34+
:git/url (some ->https-git-url
35+
(map #(shell-out-str (str "git remote get-url " %))
36+
(str/split-lines (shell-out-str "git remote"))))}
37+
(catch Exception _
38+
{})))
39+
40+
#_(read-git-attrs)

src/nextjournal/clerk/home.clj

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
(ns nextjournal.clerk.home
22
{:nextjournal.clerk/visibility {:code :hide :result :hide}}
3-
(:require [clojure.string :as str]
4-
[babashka.fs :as fs]
3+
(:require [babashka.fs :as fs]
4+
[clojure.string :as str]
55
[nextjournal.clerk :as clerk]
6-
[nextjournal.clerk.builder :as builder]
6+
[nextjournal.clerk.paths :as paths]
77
[nextjournal.clerk.viewer :as v]))
88

99
(defn glob-notebooks []
@@ -192,7 +192,7 @@
192192
(when-not (seq (:query @!filter))
193193
[:div {:class "w-1/2 pt-6 pl-6"}
194194
[:h4.text-lg "Static Build Index"]
195-
(let [{:keys [paths error]} (builder/index-paths)]
195+
(let [{:keys [paths error]} (paths/index-paths)]
196196
(cond
197197
error [:div {:class "-mx-8"} (clerk/md error)]
198198
paths (let [{:keys [query]} @!filter]

src/nextjournal/clerk/index.clj

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
(ns nextjournal.clerk.index
2-
{:nextjournal.clerk/visibility {:code :hide :result :hide}}
2+
{:nextjournal.clerk/visibility {:code :hide :result :hide}
3+
:nextjournal.clerk/no-cache true}
34
(:require [babashka.fs :as fs]
45
[clojure.string :as str]
56
[nextjournal.clerk :as clerk]
6-
[nextjournal.clerk.viewer :as v]
7-
[nextjournal.clerk.builder :as builder]))
7+
[nextjournal.clerk.paths :as paths]
8+
[nextjournal.clerk.viewer :as v]))
89

9-
(def !paths (delay (builder/index-paths)))
10+
(def !paths (delay (paths/index-paths)))
1011

1112
(def index-item-viewer
1213
{:pred string?
@@ -41,4 +42,4 @@
4142
(clerk/html
4243
[:div.text-xs.text-slate-400.font-sans.mb-8.not-prose
4344
[:span.block.font-medium "This index page was automatically generated by Clerk."]
44-
"You can customize it by adding a index.clj file to your project’s root directory. See " [:a.text-blue-600.dark:text-blue-300.hover:underline {:href "https://book.clerk.vision/#static-building"} "Static Publishing"] " in the " [:a.text-blue-600.dark:text-blue-300.hover:underline {:href "http://book.clerk.vision"} "Book of Clerk"] "."])
45+
"You can customize it by adding an index.clj file to your project’s root directory. See " [:a.text-blue-600.dark:text-blue-300.hover:underline {:href "https://book.clerk.vision/#static-building"} "Static Publishing"] " in the " [:a.text-blue-600.dark:text-blue-300.hover:underline {:href "http://book.clerk.vision"} "Book of Clerk"] "."])

0 commit comments

Comments
 (0)