diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..7dec2d3 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,194 @@ +# Change Log for tools.namespace + + +## 0.3.x series + +### Version 0.3.0 + + * **ClojureScript Analysis Support** [TNS-35] + + * Platform-neutral namespaces were converted to conditional-read + (`.cljc`) files: c.t.n.dependency, c.t.n.track, and + c.t.n.parse. These namespaces can be used in ClojureScript + programs. + + * Added support for finding, parsing, and analyzing + ClojureScript source files (`.cljs` and `.cljc`) in + c.t.n.file, c.t.n.parse, c.t.n.dir, and c.t.n.find with + optional "platform" arguments. These namespaces still only + **run** on the Clojure(JVM) platform. + + * Reloading and interactive features remain Clojure(JVM) only + for now: c.t.n.move, c.t.n.reload, and c.t.n.repl + + * Uses [tools.reader] for platform-independent parsing and + conditional-reader support. + + * Enhancement [TNS-36]: Use java.classpath for better JVM classpath + resolution + + * Minimum Clojure version is 1.7.0 + + * Some definitions deprecated; see source code or Var metadata for + details. + + + +## 0.2.x series + +### Version 0.2.11 on 19-Jun-2015 + + * [TNS-34] Allow reader conditionals in parsed source files + +### Version 0.2.10 on 26-Feb-2015 + + * Widen existing functions to handle both clj and cljc files in + advance of reader conditional support in Clojure 1.7. + +### Version 0.2.9 on 31-Jan-2015 + + * Fix [TNS-20]: Undefined 'unload' order after namespaces are first + added to an new, empty tracker. + + * Improvement [TNS-21]: Support `ns` clauses which use vectors + instead of lists for clauses, contrary to docs. + + * Improvement [TNS-32]: Support `ns` clauses which use symbols as + clause heads instead of keywords, contrary to docs. + +### Version 0.2.8 on 19-Dec-2014 + + * Improvement [TNS-31]: Specific error message when `:after` symbol + passed to `refresh` cannot be resolved. + + * Fix [TNS-26]: namespace alias recovery after failed reload did not + work due to local binding shadowing global Var + +### Version 0.2.7 on 19-Sept-2014 + + * [Revert bad commit](https://github.com/clojure/tools.namespace/commit/27194f2edfe3f5f9e1343f993beca4b43f0bafe8) + mistakenly included in 0.2.6 which could cause the tracker's + 'unload' order to be incorrect. See discussion at [TNS-20]. + +### **BROKEN** Version 0.2.6 on 7-Sept-2014 **DO NOT USE** + + * `clojure.tools.namespace.parse/read-ns-decl` asserts that its + argument is a PushbackReader, instead of silently returning nil + + * Fix [TNS-22]: broken `clojure.string/replace` with Windows path + separator + +### Version 0.2.5 on 15-Jul-2014 + + * New `clojure.tools.namespace.repl/clear` empties the state of the + REPL dependency tracker. This can help repair the dependency + tracker after a failed load or a circular dependency error. + + * Enhancement [TNS-19]: `deps-from-ns-decl` should return an empty + set instead of nil. This may be a breaking change for some but + is consistent with the original docstring. + + * Enhancement [TNS-18]: Compute transitive dependencies in linear time. + + * Enhancement [TNS-17]: The `ns` form doesn't need to be the first + top-level form in a file. + + * Fix [TNS-16]: Don't depend on specific hash ordering in tests. + Exposed by new hash functions in Clojure 1.6.0. + + * Fix [TNS-15]: Handle spaces in classpath directories (old + `clojure.tools.namespace`) + + * Fix [TNS-12]: Duplicate definition of `jar-file?` + +### Version 0.2.4 on 19-Jul-2013 + + * Fix [TNS-10]: Forbid circular dependency when a namespace depends + on itself + + * Fix [TNS-9] and [TNS-11]: support other prefix-list forms + + * Fix [TNS-8]: In `move-ns`, do not modify files whose contents does + not change + +### Version 0.2.3 on 01-Apr-2013 + + * New: Attempt recovery of aliases/refers in REPL after error + +### Version 0.2.2 on 14-Dec-2012 + + * New: Add `:after` option to `refresh` + + * New: Add `clojure.tools.namespace.move` + + * Fix [TNS-4], reflection warnings + +### Version 0.2.1 on 26-Oct-2012 + + * Fix: Restore deprecated 0.1.x APIs in `clojure.tools.namespace` + + * Fix [TNS-3], actually use `refresh-dirs` + +### **BROKEN** Version 0.2.0 on 05-Oct-2012 **DO NOT USE** + + * Not recommended for use: this release introduced breaking API + changes (renaming core namespaces and functions) without + backwards-compatibility. Applications with dependencies on both + the 0.2.x and 0.1.x APIs cannot use this version. + + * New dependency tracking & reloading features + + * Eliminate dependency on [java.classpath] + + + +## 0.1.x series + +### Version 0.1.3 on 24-Apr-2012 + + * Fix [TNS-1] Workaround for Clojure 1.2 reader bug + +### Version 0.1.2 on 10-Feb-2012 + + * Fix: Eliminate reflection warnings + +### Version 0.1.1 on 18-May-2011 + +### Version 0.1.0 on 24-Apr-2011 + + * Source-compatible with clojure.contrib.find-namespaces in old + clojure-contrib 1.2.0 + +[TNS-1]: http://dev.clojure.org/jira/browse/TNS-1 +[TNS-3]: http://dev.clojure.org/jira/browse/TNS-3 +[TNS-4]: http://dev.clojure.org/jira/browse/TNS-4 +[TNS-8]: http://dev.clojure.org/jira/browse/TNS-8 +[TNS-9]: http://dev.clojure.org/jira/browse/TNS-9 +[TNS-10]: http://dev.clojure.org/jira/browse/TNS-10 +[TNS-11]: http://dev.clojure.org/jira/browse/TNS-11 +[TNS-12]: http://dev.clojure.org/jira/browse/TNS-12 +[TNS-15]: http://dev.clojure.org/jira/browse/TNS-15 +[TNS-16]: http://dev.clojure.org/jira/browse/TNS-16 +[TNS-17]: http://dev.clojure.org/jira/browse/TNS-17 +[TNS-18]: http://dev.clojure.org/jira/browse/TNS-18 +[TNS-19]: http://dev.clojure.org/jira/browse/TNS-19 +[TNS-20]: http://dev.clojure.org/jira/browse/TNS-20 +[TNS-21]: http://dev.clojure.org/jira/browse/TNS-21 +[TNS-22]: http://dev.clojure.org/jira/browse/TNS-22 +[TNS-23]: http://dev.clojure.org/jira/browse/TNS-23 +[TNS-24]: http://dev.clojure.org/jira/browse/TNS-24 +[TNS-25]: http://dev.clojure.org/jira/browse/TNS-25 +[TNS-26]: http://dev.clojure.org/jira/browse/TNS-26 +[TNS-27]: http://dev.clojure.org/jira/browse/TNS-27 +[TNS-28]: http://dev.clojure.org/jira/browse/TNS-28 +[TNS-29]: http://dev.clojure.org/jira/browse/TNS-29 +[TNS-30]: http://dev.clojure.org/jira/browse/TNS-30 +[TNS-31]: http://dev.clojure.org/jira/browse/TNS-31 +[TNS-32]: http://dev.clojure.org/jira/browse/TNS-32 +[TNS-33]: http://dev.clojure.org/jira/browse/TNS-33 +[TNS-34]: http://dev.clojure.org/jira/browse/TNS-34 +[TNS-35]: http://dev.clojure.org/jira/browse/TNS-35 +[TNS-36]: http://dev.clojure.org/jira/browse/TNS-36 +[java.classpath]: https://github.com/clojure/java.classpath +[tools.reader]: https://github.com/clojure/tools.reader +[JEP 122]: http://openjdk.java.net/jeps/122 diff --git a/README.md b/README.md index cc7761c..43e1479 100644 --- a/README.md +++ b/README.md @@ -533,165 +533,6 @@ Developer Information -Change Log ----------------------------------------- - -### Version 0.2.12-SNAPSHOT - - * In development, current Git master branch - -### Version 0.2.11 on 19-Jun-2015 - - * [TNS-34] Allow reader conditionals in parsed source files - -### Version 0.2.10 on 26-Feb-2015 - - * Widen existing functions to handle both clj and cljc files in - advance of reader conditional support in Clojure 1.7. - -### Version 0.2.9 on 31-Jan-2015 - - * Fix [TNS-20]: Undefined 'unload' order after namespaces are first - added to an new, empty tracker. - - * Improvement [TNS-21]: Support `ns` clauses which use vectors - instead of lists for clauses, contrary to docs. - - * Improvement [TNS-32]: Support `ns` clauses which use symbols as - clause heads instead of keywords, contrary to docs. - -### Version 0.2.8 on 19-Dec-2014 - - * Improvement [TNS-31]: Specific error message when `:after` symbol - passed to `refresh` cannot be resolved. - - * Fix [TNS-26]: namespace alias recovery after failed reload did not - work due to local binding shadowing global Var - -### Version 0.2.7 on 19-Sept-2014 - - * [Revert bad commit](https://github.com/clojure/tools.namespace/commit/27194f2edfe3f5f9e1343f993beca4b43f0bafe8) - mistakenly included in 0.2.6 which could cause the tracker's - 'unload' order to be incorrect. See discussion at [TNS-20]. - -### **BROKEN** Version 0.2.6 on 7-Sept-2014 **DO NOT USE** - - * `clojure.tools.namespace.parse/read-ns-decl` asserts that its - argument is a PushbackReader, instead of silently returning nil - - * Fix [TNS-22]: broken `clojure.string/replace` with Windows path - separator - -### Version 0.2.5 on 15-Jul-2014 - - * New `clojure.tools.namespace.repl/clear` empties the state of the - REPL dependency tracker. This can help repair the dependency - tracker after a failed load or a circular dependency error. - - * Enhancement [TNS-19]: `deps-from-ns-decl` should return an empty - set instead of nil. This may be a breaking change for some but - is consistent with the original docstring. - - * Enhancement [TNS-18]: Compute transitive dependencies in linear time. - - * Enhancement [TNS-17]: The `ns` form doesn't need to be the first - top-level form in a file. - - * Fix [TNS-16]: Don't depend on specific hash ordering in tests. - Exposed by new hash functions in Clojure 1.6.0. - - * Fix [TNS-15]: Handle spaces in classpath directories (old - `clojure.tools.namespace`) - - * Fix [TNS-12]: Duplicate definition of `jar-file?` - -### Version 0.2.4 on 19-Jul-2013 - - * Fix [TNS-10]: Forbid circular dependency when a namespace depends - on itself - - * Fix [TNS-9] and [TNS-11]: support other prefix-list forms - - * Fix [TNS-8]: In `move-ns`, do not modify files whose contents does - not change - -### Version 0.2.3 on 01-Apr-2013 - - * New: Attempt recovery of aliases/refers in REPL after error - -### Version 0.2.2 on 14-Dec-2012 - - * New: Add `:after` option to `refresh` - - * New: Add `clojure.tools.namespace.move` - - * Fix [TNS-4], reflection warnings - -### Version 0.2.1 on 26-Oct-2012 - - * Fix: Restore deprecated 0.1.x APIs in `clojure.tools.namespace` - - * Fix [TNS-3], actually use `refresh-dirs` - -### Version 0.2.0 on 05-Oct-2012 - - * **Not recommended for use**: this release introduced breaking API - changes (renaming core namespaces and functions) without - backwards-compatibility. Applications with dependencies on both - the 0.2.x and 0.1.x APIs cannot use this version. - - * New dependency tracking & reloading features - - * Eliminate dependency on [java.classpath] - -### Version 0.1.3 on 24-Apr-2012 - - * Fix [TNS-1] Workaround for Clojure 1.2 reader bug - -### Version 0.1.2 on 10-Feb-2012 - - * Fix: Eliminate reflection warnings - -### Version 0.1.1 on 18-May-2011 - -### Version 0.1.0 on 24-Apr-2011 - - * Source-compatible with clojure.contrib.find-namespaces in old - clojure-contrib 1.2.0 - -[TNS-1]: http://dev.clojure.org/jira/browse/TNS-1 -[TNS-3]: http://dev.clojure.org/jira/browse/TNS-3 -[TNS-4]: http://dev.clojure.org/jira/browse/TNS-4 -[TNS-8]: http://dev.clojure.org/jira/browse/TNS-8 -[TNS-9]: http://dev.clojure.org/jira/browse/TNS-9 -[TNS-10]: http://dev.clojure.org/jira/browse/TNS-10 -[TNS-11]: http://dev.clojure.org/jira/browse/TNS-11 -[TNS-12]: http://dev.clojure.org/jira/browse/TNS-12 -[TNS-15]: http://dev.clojure.org/jira/browse/TNS-15 -[TNS-16]: http://dev.clojure.org/jira/browse/TNS-16 -[TNS-17]: http://dev.clojure.org/jira/browse/TNS-17 -[TNS-18]: http://dev.clojure.org/jira/browse/TNS-18 -[TNS-19]: http://dev.clojure.org/jira/browse/TNS-19 -[TNS-20]: http://dev.clojure.org/jira/browse/TNS-20 -[TNS-21]: http://dev.clojure.org/jira/browse/TNS-21 -[TNS-22]: http://dev.clojure.org/jira/browse/TNS-22 -[TNS-23]: http://dev.clojure.org/jira/browse/TNS-23 -[TNS-24]: http://dev.clojure.org/jira/browse/TNS-24 -[TNS-25]: http://dev.clojure.org/jira/browse/TNS-25 -[TNS-26]: http://dev.clojure.org/jira/browse/TNS-26 -[TNS-27]: http://dev.clojure.org/jira/browse/TNS-27 -[TNS-28]: http://dev.clojure.org/jira/browse/TNS-28 -[TNS-29]: http://dev.clojure.org/jira/browse/TNS-29 -[TNS-30]: http://dev.clojure.org/jira/browse/TNS-30 -[TNS-31]: http://dev.clojure.org/jira/browse/TNS-31 -[TNS-32]: http://dev.clojure.org/jira/browse/TNS-32 -[TNS-33]: http://dev.clojure.org/jira/browse/TNS-33 -[TNS-34]: http://dev.clojure.org/jira/browse/TNS-34 -[java.classpath]: https://github.com/clojure/java.classpath -[JEP 122]: http://openjdk.java.net/jeps/122 - - - Copyright and License ---------------------------------------- diff --git a/pom.xml b/pom.xml index 80cc93a..b912e4e 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ 4.0.0 tools.namespace - 0.2.12-SNAPSHOT + 0.3.0-SNAPSHOT ${artifactId} @@ -10,6 +10,25 @@ 0.1.2 + + + org.clojure + clojure + 1.7.0 + provided + + + org.clojure + java.classpath + 0.2.2 + + + org.clojure + tools.reader + 0.9.2 + + + true @@ -26,4 +45,5 @@ git@github.com:clojure/tools.namespace.git HEAD + diff --git a/src/main/clojure/clojure/tools/namespace/dependency.clj b/src/main/clojure/clojure/tools/namespace/dependency.cljc similarity index 97% rename from src/main/clojure/clojure/tools/namespace/dependency.clj rename to src/main/clojure/clojure/tools/namespace/dependency.cljc index 96a5e9e..3c6b54a 100644 --- a/src/main/clojure/clojure/tools/namespace/dependency.clj +++ b/src/main/clojure/clojure/tools/namespace/dependency.cljc @@ -142,6 +142,10 @@ (remove-node g' node) (clojure.set/union (set more) (set add))))))) +(def ^:private max-number + #?(:clj Long/MAX_VALUE + :cljs js/Number.MAX_VALUE)) + (defn topo-comparator "Returns a comparator fn which produces a topological sort based on the dependencies in graph. Nodes not present in the graph will sort @@ -149,6 +153,5 @@ [graph] (let [pos (zipmap (topo-sort graph) (range))] (fn [a b] - (compare (get pos a Long/MAX_VALUE) - (get pos b Long/MAX_VALUE))))) - + (compare (get pos a max-number) + (get pos b max-number))))) diff --git a/src/main/clojure/clojure/tools/namespace/dir.clj b/src/main/clojure/clojure/tools/namespace/dir.clj index 9f9b0f1..e12288d 100644 --- a/src/main/clojure/clojure/tools/namespace/dir.clj +++ b/src/main/clojure/clojure/tools/namespace/dir.clj @@ -11,19 +11,19 @@ file-modification timestamps"} clojure.tools.namespace.dir (:require [clojure.tools.namespace.file :as file] + [clojure.tools.namespace.find :as find] [clojure.tools.namespace.track :as track] + [clojure.java.classpath :refer [classpath-directories]] [clojure.java.io :as io] [clojure.set :as set] [clojure.string :as string]) (:import (java.io File) (java.util.regex Pattern))) -(defn- find-files [dirs] +(defn- find-files [dirs platform] (->> dirs (map io/file) (filter #(.exists ^File %)) - (mapcat file-seq) - (filter file/clojure-file?) - (map #(.getCanonicalFile ^File %)))) + (mapcat #(find/find-sources-in-dir % platform)))) (defn- modified-files [tracker files] (filter #(< (::time tracker 0) (.lastModified ^File %)) files)) @@ -31,43 +31,84 @@ (defn- deleted-files [tracker files] (set/difference (::files tracker #{}) (set files))) -(defn- update-files [tracker deleted modified] +(defn- update-files [tracker deleted modified {:keys [read-opts]}] (let [now (System/currentTimeMillis)] (-> tracker (update-in [::files] #(if % (apply disj % deleted) #{})) (file/remove-files deleted) (update-in [::files] into modified) - (file/add-files modified) + (file/add-files modified read-opts) (assoc ::time now)))) -(defn- dirs-on-classpath [] - (filter #(.isDirectory ^File %) - (map #(File. ^String %) - (string/split - (System/getProperty "java.class.path") - (Pattern/compile (Pattern/quote File/pathSeparator)))))) +(defn scan-files + "Scans files to find those which have changed since the last time + 'scan-files' was run; updates the dependency tracker with + new/changed/deleted files. -(defn scan + files is the collection of files to scan. + + Optional third argument is map of options: + + :platform Either clj (default) or cljs, both defined in + clojure.tools.namespace.find, controls reader options for + parsing files. + + :add-all? If true, assumes all extant files are modified regardless + of filesystem timestamps." + {:added "0.3.0"} + ([tracker files] (scan-files tracker files nil)) + ([tracker files {:keys [platform add-all?]}] + (let [deleted (seq (deleted-files tracker files)) + modified (if add-all? + files + (seq (modified-files tracker files)))] + (if (or deleted modified) + (update-files tracker deleted modified platform) + tracker)))) + +(defn scan-dirs "Scans directories for files which have changed since the last time - 'scan' was run; update the dependency tracker with - new/changed/deleted files. + 'scan-dirs' or 'scan-files' was run; updates the dependency tracker + with new/changed/deleted files. + + dirs is the collection of directories to scan, defaults to all + directories on Clojure's classpath. + + Optional third argument is map of options: + + :platform Either clj (default) or cljs, both defined in + clojure.tools.namespace.find, controls file extensions + and reader options. + + :add-all? If true, assumes all extant files are modified regardless + of filesystem timestamps." + {:added "0.3.0"} + ([tracker] (scan-dirs tracker nil nil)) + ([tracker dirs] (scan-dirs tracker dirs nil)) + ([tracker dirs {:keys [platform add-all?] :as options}] + (let [ds (or (seq dirs) (classpath-directories))] + (scan-files tracker (find-files ds platform) options)))) + +(defn scan + "DEPRECATED: replaced by scan-dirs. + + Scans directories for Clojure (.clj, .cljc) source files which have + changed since the last time 'scan' was run; update the dependency + tracker with new/changed/deleted files. If no dirs given, defaults to all directories on the classpath." + {:added "0.2.0" + :deprecated "0.3.0"} [tracker & dirs] - (let [ds (or (seq dirs) (dirs-on-classpath)) - files (find-files ds) - deleted (seq (deleted-files tracker files)) - modified (seq (modified-files tracker files))] - (if (or deleted modified) - (update-files tracker deleted modified) - tracker))) + (scan-dirs tracker dirs {:platform find/clj})) (defn scan-all - "Scans directories for all Clojure source files and updates the + "DEPRECATED: replaced by scan-dirs. + + Scans directories for all Clojure source files and updates the dependency tracker to reload files. If no dirs given, defaults to all directories on the classpath." + {:added "0.2.0" + :deprecated "0.3.0"} [tracker & dirs] - (let [ds (or (seq dirs) (dirs-on-classpath)) - files (find-files ds) - deleted (seq (deleted-files tracker files))] - (update-files tracker deleted files))) + (scan-dirs tracker dirs {:platform find/clj :add-all? true})) diff --git a/src/main/clojure/clojure/tools/namespace/file.clj b/src/main/clojure/clojure/tools/namespace/file.clj index 2d9c859..da76e97 100644 --- a/src/main/clojure/clojure/tools/namespace/file.clj +++ b/src/main/clojure/clojure/tools/namespace/file.clj @@ -16,26 +16,52 @@ (defn read-file-ns-decl "Attempts to read a (ns ...) declaration from file, and returns the - unevaluated form. Returns nil if read fails, or if the first form - is not a ns declaration." - [file] - (with-open [rdr (PushbackReader. (io/reader file))] - (parse/read-ns-decl rdr))) + unevaluated form. Returns nil if read fails due to invalid syntax or + if a ns declaration cannot be found. read-opts is passed through to + tools.reader/read." + ([file] + (read-file-ns-decl file nil)) + ([file read-opts] + (with-open [rdr (PushbackReader. (io/reader file))] + (parse/read-ns-decl rdr read-opts)))) + +(defn file-with-extension? + "Returns true if the java.io.File represents a file whose name ends + with one of the Strings in extensions." + {:added "0.3.0"} + [^java.io.File file extensions] + (and (.isFile file) + (let [name (.getName file)] + (some #(.endsWith name %) extensions)))) + +(def ^{:added "0.3.0"} + clojure-extensions + "File extensions for Clojure (JVM) files." + (list ".clj" ".cljc")) + +(def ^{:added "0.3.0"} + clojurescript-extensions + "File extensions for ClojureScript files." + (list ".cljs" ".cljc")) (defn clojure-file? - "Returns true if the java.io.File represents a normal Clojure source - file." + "Returns true if the java.io.File represents a file which will be + read by the Clojure (JVM) compiler." [^java.io.File file] - (and (.isFile file) - (or - (.endsWith (.getName file) ".clj") - (.endsWith (.getName file) ".cljc")))) + (file-with-extension? file clojure-extensions)) + +(defn clojurescript-file? + "Returns true if the java.io.File represents a file which will be + read by the ClojureScript compiler." + {:added "0.3.0"} + [^java.io.File file] + (file-with-extension? file clojurescript-extensions)) ;;; Dependency tracker -(defn- files-and-deps [files] +(defn- files-and-deps [files read-opts] (reduce (fn [m file] - (if-let [decl (read-file-ns-decl file)] + (if-let [decl (read-file-ns-decl file read-opts)] (let [deps (parse/deps-from-ns-decl decl) name (second decl)] (-> m @@ -48,12 +74,15 @@ (defn add-files "Reads ns declarations from files; returns an updated dependency - tracker with those files added." - [tracker files] - (let [{:keys [depmap filemap]} (files-and-deps files)] - (-> tracker - (track/add depmap) - (update-in [::filemap] merge-map filemap)))) + tracker with those files added. read-opts is passed through to + tools.reader." + ([tracker files] + (add-files tracker files nil)) + ([tracker files read-opts] + (let [{:keys [depmap filemap]} (files-and-deps files read-opts)] + (-> tracker + (track/add depmap) + (update-in [::filemap] merge-map filemap))))) (defn remove-files "Returns an updated dependency tracker with files removed. The files diff --git a/src/main/clojure/clojure/tools/namespace/find.clj b/src/main/clojure/clojure/tools/namespace/find.clj index e22abbc..9ced9e5 100644 --- a/src/main/clojure/clojure/tools/namespace/find.clj +++ b/src/main/clojure/clojure/tools/namespace/find.clj @@ -10,7 +10,8 @@ ^{:author "Stuart Sierra", :doc "Search for namespace declarations in directories and JAR files."} clojure.tools.namespace.find - (:require [clojure.java.io :as io] + (:require [clojure.java.classpath :as classpath] + [clojure.java.io :as io] [clojure.set :as set] [clojure.tools.namespace.file :as file] [clojure.tools.namespace.parse :as parse]) @@ -18,104 +19,173 @@ InputStreamReader) (java.util.jar JarFile JarEntry))) -;;; JAR-file utilities, adapted from clojure.java.classpath +(def ^{:added "0.3.0"} + clj + "Platform definition of file extensions and reader options for + Clojure (.clj and .cljc) source files." + {:read-opts parse/clj-read-opts + :extensions file/clojure-extensions}) -(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) - (or (.endsWith (.getName file) ".jar") - (.endsWith (.getName file) ".JAR"))))) - -(defn- jar-files - "Given a sequence of File objects, filters it for JAR files, returns - a sequence of java.util.jar.JarFile objects." - [files] - (map #(JarFile. ^File %) (filter jar-file? files))) - -(defn- filenames-in-jar - "Returns a sequence of Strings naming the non-directory entries in - the JAR file." - [^JarFile jar-file] - (map #(.getName ^JarEntry %) - (filter #(not (.isDirectory ^JarEntry %)) - (enumeration-seq (.entries jar-file))))) +(def ^{:added "0.3.0"} + cljs + "Platform definition of file extensions and reader options for + ClojureScript (.cljs and .cljc) source files." + {:read-opts parse/cljs-read-opts + :extensions file/clojurescript-extensions}) ;;; Finding namespaces in a directory tree +(defn- sort-files-breadth-first + [files] + (sort-by #(.getAbsolutePath ^File %) files)) + +(defn find-sources-in-dir + "Searches recursively under dir for source files. Returns a sequence + of File objects, in breadth-first sort order. + + Optional second argument is either clj (default) or cljs, both + defined in clojure.tools.namespace.find." + {:added "0.3.0"} + ([dir] + (find-sources-in-dir dir nil)) + ([^File dir platform] + (let [{:keys [extensions]} (or platform clj)] + (->> (file-seq dir) + (filter #(file/file-with-extension? % extensions)) + sort-files-breadth-first)))) + (defn find-clojure-sources-in-dir - "Searches recursively under dir for Clojure source files (.clj, .cljc). + "DEPRECATED: replaced by find-sources-in-dir + + Searches recursively under dir for Clojure source files (.clj, .cljc). Returns a sequence of File objects, in breadth-first sort order." + {:added "0.2.0" + :deprecated "0.3.0"} [^File dir] - ;; Use sort by absolute path to get breadth-first search. - (sort-by #(.getAbsolutePath ^File %) - (filter file/clojure-file? (file-seq dir)))) + (find-sources-in-dir dir clj)) (defn find-ns-decls-in-dir "Searches dir recursively for (ns ...) declarations in Clojure - source files; returns the unevaluated ns declarations." - [^File dir] - (keep file/read-file-ns-decl (find-clojure-sources-in-dir dir))) + source files; returns the unevaluated ns declarations. + + Optional second argument platform is either clj (default) or cljs, + both defined in clojure.tools.namespace.find." + {:added "0.2.0"} + ([dir] (find-ns-decls-in-dir dir nil)) + ([dir platform] + (keep #(file/read-file-ns-decl % (:read-opts platform)) + (find-sources-in-dir dir platform)))) (defn find-namespaces-in-dir "Searches dir recursively for (ns ...) declarations in Clojure - source files; returns the symbol names of the declared namespaces." - [^File dir] - (map second (find-ns-decls-in-dir dir))) + source files; returns the symbol names of the declared namespaces. + + Optional second argument platform is either clj (default) or cljs, + both defined in clojure.tools.namespace.find." + {:added "0.3.0"} + ([dir] (find-namespaces-in-dir dir nil)) + ([dir platform] + (map second (find-ns-decls-in-dir dir platform)))) ;;; Finding namespaces in JAR files +(defn- ends-with-extension + [^String filename extensions] + (some #(.endsWith filename %) extensions)) + +(defn sources-in-jar + "Returns a sequence of source file names found in the JAR file. + + Optional second argument platform is either clj (default) or cljs, + both defined in clojure.tools.namespace.find." + {:added "0.3.0"} + ([jar-file] + (sources-in-jar jar-file nil)) + ([^JarFile jar-file platform] + (let [{:keys [extensions]} (or platform clj)] + (filter #(ends-with-extension % extensions) + (classpath/filenames-in-jar jar-file))))) + (defn clojure-sources-in-jar - "Returns a sequence of filenames ending in .clj or .cljc found in the JAR file." - [^JarFile jar-file] - (filter #(or (.endsWith ^String % ".clj") (.endsWith ^String % ".cljc")) - (filenames-in-jar jar-file))) + "DEPRECATED: replaced by sources-in-jar + + Returns a sequence of filenames ending in .clj or .cljc found in the + JAR file." + {:added "0.2.0" + :deprecated "0.3.0"} + [jar-file] + (sources-in-jar jar-file clj)) (defn read-ns-decl-from-jarfile-entry "Attempts to read a (ns ...) declaration from the named entry in the - JAR file, and returns the unevaluated form. Returns nil if the read - fails, or if the first form is not a ns declaration." - [^JarFile jarfile ^String entry-name] - (with-open [rdr (PushbackReader. - (io/reader - (.getInputStream jarfile (.getEntry jarfile entry-name))))] - (parse/read-ns-decl rdr))) + JAR file, and returns the unevaluated form. + + Optional third argument platform is either clj (default) or cljs, + both defined in clojure.tools.namespace.find." + ([jarfile entry-name] + (read-ns-decl-from-jarfile-entry jarfile entry-name nil)) + ([^JarFile jarfile ^String entry-name platform] + (let [{:keys [read-opts]} (or platform clj)] + (with-open [rdr (PushbackReader. + (io/reader + (.getInputStream jarfile (.getEntry jarfile entry-name))))] + (parse/read-ns-decl rdr read-opts))))) (defn find-ns-decls-in-jarfile - "Searches the JAR file for Clojure source files containing (ns ...) - declarations; returns the unevaluated ns declarations." - [^JarFile jarfile] - (filter identity - (map #(read-ns-decl-from-jarfile-entry jarfile %) - (clojure-sources-in-jar jarfile)))) + "Searches the JAR file for source files containing (ns ...) + declarations; returns the unevaluated ns declarations. + + Optional second argument platform is either clj (default) or cljs, + both defined in clojure.tools.namespace.find." + ([jarfile] + (find-ns-decls-in-jarfile jarfile nil)) + ([^JarFile jarfile platform] + (keep #(read-ns-decl-from-jarfile-entry jarfile % platform) + (sources-in-jar jarfile platform)))) (defn find-namespaces-in-jarfile - "Searches the JAR file for Clojure source files containing (ns ...) + "Searches the JAR file for platform source files containing (ns ...) declarations. Returns a sequence of the symbol names of the - declared namespaces." - [^JarFile jarfile] - (map second (find-ns-decls-in-jarfile jarfile))) + declared namespaces. + + Optional second argument platform is either clj (default) or cljs, + both defined in clojure.tools.namespace.find." + ([jarfile] + (find-namespaces-in-jarfile jarfile nil)) + ([^JarFile jarfile platform] + (map second (find-ns-decls-in-jarfile jarfile platform)))) ;;; Finding namespaces (defn find-ns-decls "Searches a sequence of java.io.File objects (both directories and - JAR files) for .clj or .cljc source files containing (ns...) declarations. - Returns a sequence of the unevaluated ns declaration forms. Use with - clojure.java.classpath to search Clojure's classpath." - [files] - (concat - (mapcat find-ns-decls-in-dir (filter #(.isDirectory ^File %) files)) - (mapcat find-ns-decls-in-jarfile (jar-files files)))) + JAR files) for platform source files containing (ns...) + declarations. Returns a sequence of the unevaluated ns declaration + forms. Use with clojure.java.classpath to search Clojure's + classpath. + + Optional second argument platform is either clj (default) or cljs, + both defined in clojure.tools.namespace.find." + ([files] + (find-ns-decls files nil)) + ([files platform] + (concat + (mapcat #(find-ns-decls-in-dir % platform) + (filter #(.isDirectory ^File %) files)) + (mapcat #(find-ns-decls-in-jarfile % platform) + (map #(JarFile. %) (filter classpath/jar-file? files)))))) (defn find-namespaces "Searches a sequence of java.io.File objects (both directories and - JAR files) for .clj or .cljc source files containing (ns...) declarations. - Returns a sequence of the symbol names of the declared + JAR files) for platform source files containing (ns...) + declarations. Returns a sequence of the symbol names of the declared namespaces. Use with clojure.java.classpath to search Clojure's - classpath." - [files] - (map second (find-ns-decls files))) - + classpath. + + Optional second argument platform is either clj (default) or cljs, + both defined in clojure.tools.namespace.find." + ([files] + (find-namespaces files nil)) + ([files platform] + (map second (find-ns-decls files platform)))) diff --git a/src/main/clojure/clojure/tools/namespace/parse.clj b/src/main/clojure/clojure/tools/namespace/parse.cljc similarity index 60% rename from src/main/clojure/clojure/tools/namespace/parse.clj rename to src/main/clojure/clojure/tools/namespace/parse.cljc index 78a8fc0..cba124e 100644 --- a/src/main/clojure/clojure/tools/namespace/parse.clj +++ b/src/main/clojure/clojure/tools/namespace/parse.cljc @@ -10,24 +10,9 @@ :doc "Parse Clojure namespace (ns) declarations and extract dependencies."} clojure.tools.namespace.parse - (:require [clojure.set :as set])) - -(defn- read-clj - "Calls clojure.core/read. If reader conditionals are - supported (Clojure 1.7) then adds options {:read-cond :allow}." - [rdr] - (if (resolve 'clojure.core/reader-conditional?) - (read {:read-cond :allow} rdr) - (read rdr))) - -(defn- force-errors - "Forces reader errors to be thrown immediately. Some versions of - Clojure accept invalid forms in the reader and only throw an - exception when they are printed. - See http://dev.clojure.org/jira/browse/TNS-1" - [form] - (str form) ; str forces errors - form) + (:require #?(:clj [clojure.tools.reader :as reader] + :cljs [cljs.tools.reader :as reader]) + [clojure.set :as set])) (defn comment? "Returns true if form is a (comment ...)" @@ -39,22 +24,33 @@ [form] (and (list? form) (= 'ns (first form)))) +(def clj-read-opts + {:read-cond :allow + :features #{:clj}}) + +(def cljs-read-opts + {:read-cond :allow + :features #{:cljs}}) + (defn read-ns-decl - "Attempts to read a (ns ...) declaration from a - java.io.PushbackReader, and returns the unevaluated form. Returns - the first top-level ns form found. Returns nil if read fails or if a - ns declaration cannot be found. Note that read can execute code - (controlled by *read-eval*), and as such should be used only with - trusted sources." - [rdr] - {:pre [(instance? java.io.PushbackReader rdr)]} - (try - (loop [] - (let [form (force-errors (read-clj rdr))] - (if (ns-decl? form) - form - (recur)))) - (catch Exception e nil))) + "Attempts to read a (ns ...) declaration from a reader, and returns + the unevaluated form. Returns the first top-level ns form found. + Returns nil if a ns declaration cannot be found. Note that read can + execute code (controlled by tools.reader/*read-eval*), and as such + should be used only with trusted sources. read-opts is passed + through to tools.reader/read, defaults to allow conditional reader + expressions with :features #{:clj}" + ([rdr] + (read-ns-decl rdr nil)) + ([rdr read-opts] + (let [opts (assoc (or read-opts clj-read-opts) + :eof ::eof)] + (loop [] + (let [form (reader/read opts rdr)] + (cond + (ns-decl? form) form + (= ::eof form) nil + :else (recur))))))) ;;; Parsing dependencies @@ -91,12 +87,25 @@ (keyword? form) ; Some people write (:require ... :reload-all) nil :else - (throw (IllegalArgumentException. - (pr-str "Unparsable namespace form:" form))))) + (throw (ex-info "Unparsable namespace form" + {:reason ::unparsable-ns-form + :form form})))) + +(def ^:private ns-clause-head-names + "Set of symbol/keyword names which can appear as the head of a + clause in the ns form." + #{"use" "require" "use-macros" "require-macros"}) + +(def ^:private ns-clause-heads + "Set of all symbols and keywords which can appear at the head of a + dependency clause in the ns form." + (set (mapcat (fn [name] (list (keyword name) + (symbol name))) + ns-clause-head-names))) (defn- deps-from-ns-form [form] (when (and (sequential? form) ; should be list but sometimes is not - (contains? #{:use :require 'use 'require} (first form))) + (contains? ns-clause-heads (first form))) (mapcat #(deps-from-libspec nil %) (rest form)))) (defn deps-from-ns-decl diff --git a/src/main/clojure/clojure/tools/namespace/repl.clj b/src/main/clojure/clojure/tools/namespace/repl.clj index 5c3dc7b..d75a805 100644 --- a/src/main/clojure/clojure/tools/namespace/repl.clj +++ b/src/main/clojure/clojure/tools/namespace/repl.clj @@ -11,11 +11,12 @@ clojure.tools.namespace.repl (:require [clojure.tools.namespace.track :as track] [clojure.tools.namespace.dir :as dir] + [clojure.tools.namespace.find :as find] [clojure.tools.namespace.reload :as reload])) -(defonce ^:private refresh-tracker (track/tracker)) +(defonce refresh-tracker (track/tracker)) -(defonce ^:private refresh-dirs []) +(defonce refresh-dirs []) (defn- print-and-return [tracker] (if-let [e (::reload/error tracker)] @@ -79,7 +80,7 @@ (when (find-ns ns-name) (alias alias-sym ns-name)))) -(defn- do-refresh [scan-fn after-sym] +(defn- do-refresh [scan-opts after-sym] (when after-sym (assert (symbol? after-sym) ":after value must be a symbol") (assert (namespace after-sym) @@ -87,8 +88,7 @@ (let [current-ns-name (ns-name *ns*) current-ns-refers (referred *ns*) current-ns-aliases (aliased *ns*)] - (alter-var-root #'refresh-tracker - #(apply scan-fn % refresh-dirs)) + (alter-var-root #'refresh-tracker dir/scan-dirs refresh-dirs scan-opts) (alter-var-root #'refresh-tracker remove-disabled) (print-pending-reloads refresh-tracker) (alter-var-root #'refresh-tracker reload/track-reload) @@ -142,7 +142,7 @@ been reloaded." [& options] (let [{:keys [after]} options] - (do-refresh dir/scan after))) + (do-refresh {:platform find/clj} after))) (defn refresh-all "Scans source code directories for all Clojure source files and @@ -159,7 +159,7 @@ been reloaded." [& options] (let [{:keys [after]} options] - (do-refresh dir/scan-all after))) + (do-refresh {:platform find/clj :add-all? true} after))) (defn set-refresh-dirs "Sets the directories which are scanned by 'refresh'. Supports the diff --git a/src/main/clojure/clojure/tools/namespace/track.clj b/src/main/clojure/clojure/tools/namespace/track.cljc similarity index 100% rename from src/main/clojure/clojure/tools/namespace/track.clj rename to src/main/clojure/clojure/tools/namespace/track.cljc pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy