Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Fetching contributors…
Cannot retrieve contributors at this time
112 lines (95 sloc) 3.99 KB
;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "Dependency tracker which can compute which namespaces need to be
reloaded after files have changed. This is the low-level
implementation that requires you to find the namespace dependencies
yourself: most uses will interact with the wrappers in and or the
public API in"}
(:refer-clojure :exclude (remove))
(:require [clojure.set :as set]
[ :as dep]))
(defn- remove-deps [deps names]
(reduce dep/remove-node deps names))
(defn- add-deps [deps depmap]
(reduce (fn [ds [name dependencies]]
(reduce (fn [g dep] (dep/depend g name dep))
ds dependencies))
deps depmap))
(defn- update-deps [deps depmap]
(-> deps
(remove-deps (keys depmap))
(add-deps depmap)))
(defn- affected-namespaces [deps names]
(apply set/union
(set names)
(map #(dep/transitive-dependents deps %) names)))
(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 birect 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:
is the list of namespaces that need to be removed
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 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))]
(assoc tracker
::deps new-deps
::unload (distinct
(concat (reverse (sort (dep/topo-comparator deps) changed))
::load (distinct
(concat (sort (dep/topo-comparator new-deps) changed)
(defn remove
"Returns an updated dependency tracker from which the namespaces
(symbols) have been removed. The ::unload and ::load lists are
populated as with 'add'."
[tracker names]
(let [{load ::load
unload ::unload
deps ::deps
:or {load (), unload (), deps (dep/graph)}} tracker
known (set (dep/nodes deps))
removed-names (filter known names)
new-deps (remove-deps deps removed-names)
changed (affected-namespaces deps removed-names)]
(assoc tracker
::deps new-deps
::unload (distinct
(concat (reverse (sort (dep/topo-comparator deps) changed))
::load (distinct
(filter (complement (set removed-names))
(concat (sort (dep/topo-comparator new-deps) changed)
(defn tracker
"Returns a new, empty dependency tracker"
Jump to Line
Something went wrong with that request. Please try again.