-
-
Notifications
You must be signed in to change notification settings - Fork 54
/
namespace.clj
134 lines (119 loc) · 4.44 KB
/
namespace.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
(ns orchard.namespace
"Utilities for resolving and loading namespaces"
(:require [clojure.java.io :as io]
[clojure.tools.namespace.file :as ns-file]
[clojure.tools.namespace.find :as ns-find]
[orchard.classloader :refer [class-loader]]
[orchard.classpath :as cp]
[clojure.string :as str]
[orchard.misc :as misc])
(:import java.util.jar.JarFile))
;;; Namespace Loading
(defn ensure-namespace
"Require `ns` (no-op if already loaded). Return the symbol if successful,
and `nil` if this fails."
[ns]
(try (doto (symbol ns) require)
(catch Exception _)))
;;; Project Namespaces
;;
;; These methods search project sources on the classpath. Non-classpath source
;; files, documentation code, etc within the project directory are ignored.
(def jar-namespaces
(->> (cp/classpath-jarfiles)
(mapcat ns-find/find-namespaces-in-jarfile)
(into #{})))
(def project-root
(str (System/getProperty "user.dir")
(System/getProperty "file.separator")))
(defn project-namespaces
"Find all namespaces defined in source paths within the current project."
[]
(let [project-pred (if (misc/os-windows?)
;; On Windows we want to do case-insensitive path comparison
#(.startsWith
(str/lower-case (str %))
(str/lower-case project-root))
#(.startsWith (str %) project-root))]
(->> (filter (memfn isDirectory) (cp/classpath (class-loader)))
(filter project-pred)
(mapcat ns-find/find-namespaces-in-dir))))
(defn inlined-dependency?
"Returns true if the namespace matches one of our, or eastwood's,
inlined dependencies."
[namespace]
(let [ns-name (str (ns-name namespace))]
(or
;; rewritten by mranderson
(.startsWith ns-name "deps.")
(.startsWith ns-name "mranderson")
(.startsWith ns-name "cider.inlined-deps")
;; rewritten by dolly
(.startsWith ns-name "eastwood.copieddeps"))))
(defn internal-namespace?
"Returns true if the namespace matches the given prefixes."
[namespace & [prefixes]]
(let [ns-name (str (ns-name namespace))]
(->> prefixes
(map re-pattern)
(map #(re-find % ns-name))
(some (complement nil?)))))
(defn loaded-namespaces
"Return all loaded namespaces, except those coming from inlined dependencies.
`filter-regexps` is used to filter out namespaces matching regexps."
[& [filter-regexps]]
(->> (all-ns)
(remove inlined-dependency?)
(remove #(internal-namespace? % filter-regexps))
(map ns-name)
(map name)
(sort)))
(defn loaded-project-namespaces
"Return all loaded namespaces defined in the current project."
[]
(->> (project-namespaces)
(filter (set (map ns-name (all-ns))))
sort))
(defn load-project-namespaces
"Require and return all namespaces validly defined in the current project."
[]
(->> (project-namespaces)
(map ensure-namespace)
(filter identity)
sort))
;;; Finding a namespace's file.
(defn- jar-file?
"Returns true if file is a normal file with a .jar or .JAR extension."
[f]
(let [file (io/file f)]
(and (.isFile file)
(.endsWith (.. file getName toLowerCase) ".jar"))))
(defn- get-clojure-sources-in-jar
[^JarFile jar]
(let [path-to-jar (.getName jar)]
(map #(str "jar:file:" path-to-jar "!/" %) (ns-find/sources-in-jar jar))))
(defn- all-clj-files-on-cp []
(let [dirs-on-cp (filter #(.isDirectory %) (cp/classpath))
jars-on-cp (map #(JarFile. %) (filter jar-file? (cp/classpath)))]
(concat (->> dirs-on-cp
(mapcat ns-find/find-sources-in-dir)
(map #(.getAbsolutePath %)))
(mapcat get-clojure-sources-in-jar jars-on-cp))))
(defn ns-path
"Return the path to a file containing namespace `ns`.
`ns` can be a Namespace object or the name of a namespace."
[ns]
(try
(let [ns (if (instance? clojure.lang.Namespace ns)
(ns-name ns) (symbol ns))]
(loop [paths (all-clj-files-on-cp)]
(when (seq paths)
(let [file-ns (second (ns-file/read-file-ns-decl (first paths)))]
(if (= file-ns ns)
(first paths)
(recur (rest paths)))))))
(catch Throwable _ nil)))
(defn has-tests?
"Return a truthy value if the namespace has any vars with `:test` metadata."
[ns]
(seq (filter (comp :test meta val) (ns-interns ns))))