(defn add
"Returns an updated dependency tracker with new/updated namespaces.
Depmap is a map describing the new or modified namespaces. Keys in
the map are namespace names (symbols). Values in the map are sets of
symbols naming the direct dependencies of each namespace. For
example, assuming these ns declarations:
(ns alpha (:require beta))
(ns beta (:require gamma delta))
the depmap would look like this:
{alpha #{beta}
beta #{gamma delta}}
After adding new/updated namespaces, the dependency tracker will
have two lists associated with the following keys:
:clojure.tools.namespace.track/unload
is the list of namespaces that need to be removed
:clojure.tools.namespace.track/load
is the list of namespaces that need to be reloaded
To reload namespaces in the correct order, first remove/unload all
namespaces in the 'unload' list, then (re)load all namespaces in the
'load' list. The clojure.tools.namespace.reload namespace has
functions to do this."
[tracker depmap]
(let [{load ::load
unload ::unload
deps ::deps
:or {load (), unload (), deps (dep/graph)}} tracker
new-deps (update-deps deps depmap)
changed (affected-namespaces new-deps (keys depmap))
;; With a new tracker, old dependencies are empty, so
;; unload order will be undefined unless we use new
;; dependencies (TNS-20).
old-deps (if (empty? (dep/nodes deps)) new-deps deps)]
(assoc tracker
::deps new-deps
::unload (distinct
(concat (reverse (sort (dep/topo-comparator old-deps) changed))
unload))
::load (distinct
(concat (sort (dep/topo-comparator new-deps) changed)
load)))))