;; Meant to be run on a REPL, this small script will find all the namespaces that are not transitively required ;; by a parent ns. This may be useful if you need to extract a small application from a huge monolithic project. ;; This code has been adapted from https://github.com/hilverd/lein-ns-dep-graph and distributed under the same license. ;; Note that this only looks at the ns declarations, but has no way to detect dependencies that are dynamically built ;; (e.g. by requiring a symbol created from a string using a plain `require`). (do (import [java.io PushbackReader]) (require '[clojure.java.io :as io]) (require '[clojure.set :as set]) (require '[clojure.edn :as edn]) (require '[clojure.tools.namespace.file :as ns-file]) (require '[clojure.tools.namespace.track :as ns-track]) (require '[clojure.tools.namespace.find :as ns-find]) (require '[clojure.tools.namespace.dependency :as ns-dep])) (defn transitive-deps-of [source-paths, ns-parents] (let [source-files (apply set/union (map #(ns-find/find-sources-in-dir %) (file-seq source-paths))) tracker (ns-file/add-files {} source-files) dep-graph (tracker ::ns-track/deps) ns-names (set (map (comp second ns-file/read-file-ns-decl) source-files)) part-of-project? (partial contains? ns-names) part-of-parents? #(or (empty? ns-parents) (contains? ns-parents %) (boolean (seq (set/intersection ns-parents (ns-dep/transitive-dependents dep-graph %))))) nodes (->> (ns-dep/nodes dep-graph) (filter part-of-project?) (filter part-of-parents?))] nodes)) (let [source-paths (io/file "/path/to/my/project/src/main/clojure/")] (set/difference (set (transitive-deps-of source-paths #{'my.parent.ns})) (set (transitive-deps-of source-paths #{}))))