rlm@10
|
1 ;;; find_namespaces.clj: search for ns declarations in dirs, JARs, or CLASSPATH
|
rlm@10
|
2
|
rlm@10
|
3 ;; by Stuart Sierra, http://stuartsierra.com/
|
rlm@10
|
4 ;; April 19, 2009
|
rlm@10
|
5
|
rlm@10
|
6 ;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use
|
rlm@10
|
7 ;; and distribution terms for this software are covered by the Eclipse
|
rlm@10
|
8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
rlm@10
|
9 ;; which can be found in the file epl-v10.html at the root of this
|
rlm@10
|
10 ;; distribution. By using this software in any fashion, you are
|
rlm@10
|
11 ;; agreeing to be bound by the terms of this license. You must not
|
rlm@10
|
12 ;; remove this notice, or any other, from this software.
|
rlm@10
|
13
|
rlm@10
|
14
|
rlm@10
|
15 (ns
|
rlm@10
|
16 ^{:author "Stuart Sierra",
|
rlm@10
|
17 :doc "Search for ns declarations in dirs, JARs, or CLASSPATH"}
|
rlm@10
|
18 clojure.contrib.find-namespaces
|
rlm@10
|
19 (:require [clojure.contrib.classpath :as cp]
|
rlm@10
|
20 [clojure.contrib.jar :as jar])
|
rlm@10
|
21 (import (java.io File FileReader BufferedReader PushbackReader
|
rlm@10
|
22 InputStreamReader)
|
rlm@10
|
23 (java.util.jar JarFile)))
|
rlm@10
|
24
|
rlm@10
|
25
|
rlm@10
|
26 ;;; Finding namespaces in a directory tree
|
rlm@10
|
27
|
rlm@10
|
28 (defn clojure-source-file?
|
rlm@10
|
29 "Returns true if file is a normal file with a .clj extension."
|
rlm@10
|
30 [^File file]
|
rlm@10
|
31 (and (.isFile file)
|
rlm@10
|
32 (.endsWith (.getName file) ".clj")))
|
rlm@10
|
33
|
rlm@10
|
34 (defn find-clojure-sources-in-dir
|
rlm@10
|
35 "Searches recursively under dir for Clojure source files (.clj).
|
rlm@10
|
36 Returns a sequence of File objects, in breadth-first sort order."
|
rlm@10
|
37 [^File dir]
|
rlm@10
|
38 ;; Use sort by absolute path to get breadth-first search.
|
rlm@10
|
39 (sort-by #(.getAbsolutePath %)
|
rlm@10
|
40 (filter clojure-source-file? (file-seq dir))))
|
rlm@10
|
41
|
rlm@10
|
42 (defn comment?
|
rlm@10
|
43 "Returns true if form is a (comment ...)"
|
rlm@10
|
44 [form]
|
rlm@10
|
45 (and (list? form) (= 'comment (first form))))
|
rlm@10
|
46
|
rlm@10
|
47 (defn ns-decl?
|
rlm@10
|
48 "Returns true if form is a (ns ...) declaration."
|
rlm@10
|
49 [form]
|
rlm@10
|
50 (and (list? form) (= 'ns (first form))))
|
rlm@10
|
51
|
rlm@10
|
52 (defn read-ns-decl
|
rlm@10
|
53 "Attempts to read a (ns ...) declaration from rdr, and returns the
|
rlm@10
|
54 unevaluated form. Returns nil if read fails or if a ns declaration
|
rlm@10
|
55 cannot be found. The ns declaration must be the first Clojure form
|
rlm@10
|
56 in the file, except for (comment ...) forms."
|
rlm@10
|
57 [^PushbackReader rdr]
|
rlm@10
|
58 (try (let [form (read rdr)]
|
rlm@10
|
59 (cond
|
rlm@10
|
60 (ns-decl? form) form
|
rlm@10
|
61 (comment? form) (recur rdr)
|
rlm@10
|
62 :else nil))
|
rlm@10
|
63 (catch Exception e nil)))
|
rlm@10
|
64
|
rlm@10
|
65 (defn read-file-ns-decl
|
rlm@10
|
66 "Attempts to read a (ns ...) declaration from file, and returns the
|
rlm@10
|
67 unevaluated form. Returns nil if read fails, or if the first form
|
rlm@10
|
68 is not a ns declaration."
|
rlm@10
|
69 [^File file]
|
rlm@10
|
70 (with-open [rdr (PushbackReader. (BufferedReader. (FileReader. file)))]
|
rlm@10
|
71 (read-ns-decl rdr)))
|
rlm@10
|
72
|
rlm@10
|
73 (defn find-ns-decls-in-dir
|
rlm@10
|
74 "Searches dir recursively for (ns ...) declarations in Clojure
|
rlm@10
|
75 source files; returns the unevaluated ns declarations."
|
rlm@10
|
76 [^File dir]
|
rlm@10
|
77 (filter identity (map read-file-ns-decl (find-clojure-sources-in-dir dir))))
|
rlm@10
|
78
|
rlm@10
|
79 (defn find-namespaces-in-dir
|
rlm@10
|
80 "Searches dir recursively for (ns ...) declarations in Clojure
|
rlm@10
|
81 source files; returns the symbol names of the declared namespaces."
|
rlm@10
|
82 [^File dir]
|
rlm@10
|
83 (map second (find-ns-decls-in-dir dir)))
|
rlm@10
|
84
|
rlm@10
|
85
|
rlm@10
|
86 ;;; Finding namespaces in JAR files
|
rlm@10
|
87
|
rlm@10
|
88 (defn clojure-sources-in-jar
|
rlm@10
|
89 "Returns a sequence of filenames ending in .clj found in the JAR file."
|
rlm@10
|
90 [^JarFile jar-file]
|
rlm@10
|
91 (filter #(.endsWith % ".clj") (jar/filenames-in-jar jar-file)))
|
rlm@10
|
92
|
rlm@10
|
93 (defn read-ns-decl-from-jarfile-entry
|
rlm@10
|
94 "Attempts to read a (ns ...) declaration from the named entry in the
|
rlm@10
|
95 JAR file, and returns the unevaluated form. Returns nil if the read
|
rlm@10
|
96 fails, or if the first form is not a ns declaration."
|
rlm@10
|
97 [^JarFile jarfile ^String entry-name]
|
rlm@10
|
98 (with-open [rdr (PushbackReader.
|
rlm@10
|
99 (BufferedReader.
|
rlm@10
|
100 (InputStreamReader.
|
rlm@10
|
101 (.getInputStream jarfile (.getEntry jarfile entry-name)))))]
|
rlm@10
|
102 (read-ns-decl rdr)))
|
rlm@10
|
103
|
rlm@10
|
104 (defn find-ns-decls-in-jarfile
|
rlm@10
|
105 "Searches the JAR file for Clojure source files containing (ns ...)
|
rlm@10
|
106 declarations; returns the unevaluated ns declarations."
|
rlm@10
|
107 [^JarFile jarfile]
|
rlm@10
|
108 (filter identity
|
rlm@10
|
109 (map #(read-ns-decl-from-jarfile-entry jarfile %)
|
rlm@10
|
110 (clojure-sources-in-jar jarfile))))
|
rlm@10
|
111
|
rlm@10
|
112 (defn find-namespaces-in-jarfile
|
rlm@10
|
113 "Searches the JAR file for Clojure source files containing (ns ...)
|
rlm@10
|
114 declarations. Returns a sequence of the symbol names of the
|
rlm@10
|
115 declared namespaces."
|
rlm@10
|
116 [^JarFile jarfile]
|
rlm@10
|
117 (map second (find-ns-decls-in-jarfile jarfile)))
|
rlm@10
|
118
|
rlm@10
|
119
|
rlm@10
|
120 ;;; Finding namespaces anywhere on CLASSPATH
|
rlm@10
|
121
|
rlm@10
|
122 (defn find-ns-decls-on-classpath
|
rlm@10
|
123 "Searches CLASSPATH (both directories and JAR files) for Clojure
|
rlm@10
|
124 source files containing (ns ...) declarations. Returns a sequence
|
rlm@10
|
125 of the unevaluated ns declaration forms."
|
rlm@10
|
126 []
|
rlm@10
|
127 (concat
|
rlm@10
|
128 (mapcat find-ns-decls-in-dir (cp/classpath-directories))
|
rlm@10
|
129 (mapcat find-ns-decls-in-jarfile (cp/classpath-jarfiles))))
|
rlm@10
|
130
|
rlm@10
|
131 (defn find-namespaces-on-classpath
|
rlm@10
|
132 "Searches CLASSPATH (both directories and JAR files) for Clojure
|
rlm@10
|
133 source files containing (ns ...) declarations. Returns a sequence
|
rlm@10
|
134 of the symbol names of the declared namespaces."
|
rlm@10
|
135 []
|
rlm@10
|
136 (map second (find-ns-decls-on-classpath)))
|