-
Notifications
You must be signed in to change notification settings - Fork 8
/
namespace_deps.clj
80 lines (72 loc) · 3.17 KB
/
namespace_deps.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
(ns mount.extensions.namespace-deps
"This extension offers more advanced up-to starting and down-to
stopping, by calculating a dependency graph of defstates. It does
this by looking at the namespace dependencies where the defstates
are defined. Using this graph, mount will only start or stop the
transitive dependencies or dependents.
Using these functions, your project *must* include the
org.clojure/tools.namespace library. This extension has been tested
with version 0.2.11, 0.3.1 and 1.1.0 of that library."
{:clojure.tools.namespace.repl/load false
:clojure.tools.namespace.repl/unload false}
(:require [mount.extensions.common-deps :as common-deps]
[mount.lite :as mount]))
(def ^:private deps-tracker {})
(def ^:private scan-all
(try
(require 'clojure.tools.namespace.dir)
(resolve 'clojure.tools.namespace.dir/scan-all)
(catch Exception _e)))
(def ^:private dependency
(try
(require 'clojure.tools.namespace.dependency)
{:graph (resolve 'clojure.tools.namespace.dependency/graph)
:transitive-dependencies (resolve 'clojure.tools.namespace.dependency/transitive-dependencies)
:depend (resolve 'clojure.tools.namespace.dependency/depend)}
(catch Exception _e)))
(defn- ns-graph->state-graph
"Take two graphs with namespace-to-namespace `:dependencies` and
`:dependents` in the `ns-deps` map, and a namespace-to-states map,
and generate a state-to-state dependencies graph (where states are
represented by keywords). The direction argument should be one of
`:dependencies` or `:dependents`."
[ns-deps ns-states]
(let [{:keys [graph transitive-dependencies depend]} dependency
g (atom (graph))]
(doseq [[ns states] ns-states
dep-ns (transitive-dependencies ns-deps ns)
state states
dep-state (get ns-states dep-ns)]
(swap! g depend state dep-state))
(doseq [[_ states] ns-states
state states
dep-state (take-while #(not= state %) states)]
(swap! g depend state dep-state))
@g))
(defn build-graphs
"Build two graphs of state keywords, represented as maps where the
values are the dependencies or dependents of the keys. See also
`mount.extensions.common-deps/with-transitives`."
[]
(when-not scan-all
(throw (UnsupportedOperationException. "Could not find tools.namespace dependency")))
(alter-var-root #'deps-tracker scan-all)
(let [ns-deps (:clojure.tools.namespace.track/deps deps-tracker)
ns-states (group-by (comp symbol namespace) @mount/*states*)]
(ns-graph->state-graph ns-deps ns-states)))
(defn start
"Just like the core `start`, except with an `up-to-var`, it only
starts the transitive dependencies of that state."
([]
(mount/start))
([up-to-var]
(common-deps/with-transitives up-to-var (build-graphs)
(mount/start up-to-var))))
(defn stop
"Just like the core `stop`, except with a `down-to-var`, it only
stops the transitive dependents of that state."
([]
(mount/stop))
([down-to-var]
(common-deps/with-transitives down-to-var (build-graphs)
(mount/stop down-to-var))))