Compatibility with clojure.tools.namespace.repl/refresh and clojure.java.classpath (#1479)

This commit is contained in:
Michiel Borkent 2023-02-01 21:53:52 +01:00 committed by GitHub
parent bbd1940844
commit 76e779d0d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 109 additions and 59 deletions

View file

@ -10,6 +10,7 @@ A preview of the next release can be installed from
## Unreleased ## Unreleased
- [#1473](https://github.com/babashka/babashka/issues/1473): make relative paths in bb.edn resolve relative to it ([@lispyclouds](https://github.com/lispyclouds)) - [#1473](https://github.com/babashka/babashka/issues/1473): make relative paths in bb.edn resolve relative to it ([@lispyclouds](https://github.com/lispyclouds))
- Compatibility with `clojure.tools.namespace.repl/refresh` and `clojure.java.classpath`
## 1.1.172 (2023-01-23) ## 1.1.172 (2023-01-23)

View file

@ -17,10 +17,10 @@
"depstar/src" "process/src" "depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources" "deps.clj/src" "deps.clj/resources"
"resources" "sci/resources" "resources" "sci/resources"
"reify/src"], "impl-java/src"],
:deps {org.clojure/clojure {:mvn/version "1.11.1"}, :deps {org.clojure/clojure {:mvn/version "1.11.1"},
org.babashka/sci {:local/root "sci"} org.babashka/sci {:local/root "sci"}
org.babashka/babashka.impl.reify {:mvn/version "0.1.5"} org.babashka/babashka.impl.java {:mvn/version "0.1.6"}
org.babashka/sci.impl.types {:mvn/version "0.0.2"} org.babashka/sci.impl.types {:mvn/version "0.0.2"}
babashka/babashka.curl {:local/root "babashka.curl"} babashka/babashka.curl {:local/root "babashka.curl"}
babashka/fs {:local/root "fs"} babashka/fs {:local/root "fs"}

View file

@ -2,8 +2,8 @@
(:require [build.reify2 :as reify2] (:require [build.reify2 :as reify2]
[clojure.tools.build.api :as b])) [clojure.tools.build.api :as b]))
(def lib 'org.babashka/babashka.impl.reify) (def lib 'org.babashka/babashka.impl.java)
(def version "0.1.5") (def version "0.1.6")
(def class-dir "target/classes") (def class-dir "target/classes")
(def basis (b/create-basis {:project "deps.edn"})) (def basis (b/create-basis {:project "deps.edn"}))
(def jar-file (format "target/%s-%s.jar" (name lib) version)) (def jar-file (format "target/%s-%s.jar" (name lib) version))
@ -14,7 +14,13 @@
(defn gen-classes [_] (defn gen-classes [_]
(reify2/gen-classes nil)) (reify2/gen-classes nil))
(defn compile-java [_]
(b/javac {:src-dirs ["src-java"]
:class-dir class-dir
:basis basis}))
(defn jar [_] (defn jar [_]
(compile-java nil)
(gen-classes nil) (gen-classes nil)
(b/write-pom {:class-dir class-dir (b/write-pom {:class-dir class-dir
:lib lib :lib lib

View file

@ -0,0 +1,16 @@
package babashka.impl;
public class URLClassLoader extends java.net.URLClassLoader {
public URLClassLoader(java.net.URL[] urls) {
super(urls);
}
public URLClassLoader(java.net.URL[] urls, java.net.URLClassLoader parent) {
super(urls, parent);
}
public void _addURL(java.net.URL url) {
super.addURL(url);
}
}

View file

@ -11,7 +11,7 @@
"babashka.core/src" "babashka.core/src"
"babashka.nrepl/src" "depstar/src" "process/src" "babashka.nrepl/src" "depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources" "deps.clj/src" "deps.clj/resources"
"reify/src"] "impl-java/src"]
;; for debugging Reflector.java code: ;; for debugging Reflector.java code:
;; :java-source-paths ["sci/reflector/src-java"] ;; :java-source-paths ["sci/reflector/src-java"]
:java-source-paths ["src-java"] :java-source-paths ["src-java"]
@ -26,7 +26,7 @@
[nrepl/bencode "1.1.0"] [nrepl/bencode "1.1.0"]
[borkdude/sci.impl.reflector "0.0.1"] [borkdude/sci.impl.reflector "0.0.1"]
[org.babashka/sci.impl.types "0.0.2"] [org.babashka/sci.impl.types "0.0.2"]
[org.babashka/babashka.impl.reify "0.1.5"] [org.babashka/babashka.impl.java "0.1.6"]
[org.clojure/core.async "1.6.673"] [org.clojure/core.async "1.6.673"]
[org.clojure/test.check "1.1.1"] [org.clojure/test.check "1.1.1"]
[com.github.clj-easy/graal-build-time "0.1.0"] [com.github.clj-easy/graal-build-time "0.1.0"]

View file

@ -17,10 +17,10 @@
"depstar/src" "process/src" "depstar/src" "process/src"
"deps.clj/src" "deps.clj/resources" "deps.clj/src" "deps.clj/resources"
"resources" "sci/resources" "resources" "sci/resources"
"reify/src"], "impl-java/src"],
:deps {org.clojure/clojure {:mvn/version "1.11.1"}, :deps {org.clojure/clojure {:mvn/version "1.11.1"},
org.babashka/sci {:local/root "sci"} org.babashka/sci {:local/root "sci"}
org.babashka/babashka.impl.reify {:mvn/version "0.1.5"} org.babashka/babashka.impl.java {:mvn/version "0.1.6"}
org.babashka/sci.impl.types {:mvn/version "0.0.2"} org.babashka/sci.impl.types {:mvn/version "0.0.2"}
babashka/babashka.curl {:local/root "babashka.curl"} babashka/babashka.curl {:local/root "babashka.curl"}
babashka/fs {:local/root "fs"} babashka/fs {:local/root "fs"}

View file

@ -111,7 +111,9 @@
clojure.lang.RT clojure.lang.RT
{:methods [{:name "aget"} {:methods [{:name "aget"}
{:name "aset"} {:name "aset"}
{:name "aclone"}]} {:name "aclone"}
;; we expose this via the Compiler/LOADER dynamic var
{:name "baseLoader"}]}
clojure.lang.Compiler clojure.lang.Compiler
{:fields [{:name "specials"} {:fields [{:name "specials"}
{:name "CHAR_MAP"}]} {:name "CHAR_MAP"}]}
@ -140,7 +142,18 @@
{:methods [{:name "hasNext"} {:methods [{:name "hasNext"}
{:name "next"}]} {:name "next"}]}
java.util.TimeZone java.util.TimeZone
{:methods [{:name "getTimeZone"}]}}) {:methods [{:name "getTimeZone"}]}
java.net.URLClassLoader
{:methods [{:name "close"}
{:name "findResource"}
{:name "findResources"}
{:name "getResourceAsStream"}
{:name "getURLs"}]}
java.lang.ClassLoader
{:methods [{:name "getResource"}
{:name "getResources"}
{:name "getResourceAsStream"}
{:name "getParent"}]}})
(def custom-map (def custom-map
(cond-> (cond->
@ -561,7 +574,6 @@
java.lang.LinkageError java.lang.LinkageError
java.lang.ThreadDeath java.lang.ThreadDeath
java.lang.VirtualMachineError java.lang.VirtualMachineError
java.net.URLClassLoader
java.sql.Timestamp java.sql.Timestamp
java.util.concurrent.TimeoutException java.util.concurrent.TimeoutException
java.util.Collection java.util.Collection
@ -630,6 +642,10 @@
(instance? sci.impl.types.IReified v) (instance? sci.impl.types.IReified v)
(first (t/getInterfaces v)) (first (t/getInterfaces v))
;; fix for #1061 ;; fix for #1061
(instance? java.net.URLClassLoader v)
java.net.URLClassLoader
(instance? java.lang.ClassLoader v)
java.lang.ClassLoader
(instance? java.io.Closeable v) (instance? java.io.Closeable v)
java.io.Closeable java.io.Closeable
(instance? java.nio.file.attribute.BasicFileAttributes v) (instance? java.nio.file.attribute.BasicFileAttributes v)
@ -765,8 +781,9 @@
(sort-by :name) (sort-by :name)
(vec))) (vec)))
(defn all-classes [] (defn all-classes
"Returns every java.lang.Class instance Babashka supports." "Returns every java.lang.Class instance Babashka supports."
[]
(->> (reflection-file-entries) (->> (reflection-file-entries)
(map :name) (map :name)
(map #(Class/forName %)))) (map #(Class/forName %))))

View file

@ -10,30 +10,46 @@
(set! *warn-on-reflection* true) (set! *warn-on-reflection* true)
(defprotocol IResourceResolver (defn getResource [^babashka.impl.URLClassLoader class-loader resource-paths url?]
(getResource [this paths opts])) (some (fn [resource]
(when-let [^java.net.URL res (.findResource class-loader resource)]
(deftype Loader [class-loader] (if url?
IResourceResolver res
(getResource [_ resource-paths url?] {:file (if (= "jar" (.getProtocol res))
(some (fn [resource] resource
(when-let [^java.net.URL res (.findResource ^java.net.URLClassLoader class-loader resource)] (.getFile res))
(if url? :source (slurp res)})))
res resource-paths))
{:file (if (= "jar" (.getProtocol res))
resource
(.getFile res))
:source (slurp res)})))
resource-paths)))
(def path-sep (System/getProperty "path.separator")) (def path-sep (System/getProperty "path.separator"))
(defn ->url [^String s] (defn ->url ^java.net.URL [^String s]
(.toURL (java.io.File. s))) (.toURL (java.io.File. s)))
(defn loader [^String classpath] (defn new-loader ^babashka.impl.URLClassLoader
(let [parts (.split classpath path-sep)] ([paths]
(Loader. (java.net.URLClassLoader/newInstance (into-array java.net.URL (map ->url parts)))))) (babashka.impl.URLClassLoader. (into-array java.net.URL (map ->url paths)))))
(def ^babashka.impl.URLClassLoader the-url-loader (delay (new-loader [])))
(defn add-classpath
"Adds extra-classpath, a string as for example returned by clojure
-Spath, to the current classpath."
[^String extra-classpath]
(let [paths (.split extra-classpath path-sep)
paths (map ->url paths)
loader @the-url-loader]
(run! (fn [path]
(._addURL ^babashka.impl.URLClassLoader loader path)
loader)
paths)
;; (run! prn (.getURLs the-url-loader))
(System/setProperty "java.class.path"
(let [system-cp (System/getProperty "java.class.path")]
(-> (cond-> system-cp
(not (str/blank? system-cp)) (str path-sep))
(str extra-classpath)))))
nil)
(defn resource-paths [namespace] (defn resource-paths [namespace]
(let [ns-str (name namespace) (let [ns-str (name namespace)
@ -55,21 +71,6 @@
(.getValue "Main-Class") (.getValue "Main-Class")
(demunge)))) (demunge))))
(def cp-state (atom nil))
(defn add-classpath
"Adds extra-classpath, a string as for example returned by clojure
-Spath, to the current classpath."
[extra-classpath]
(swap! cp-state
(fn [{:keys [:cp]}]
(let [new-cp
(if-not cp extra-classpath
(str cp path-sep extra-classpath))]
{:loader (loader new-cp)
:cp new-cp})))
nil)
(defn split-classpath (defn split-classpath
"Returns the classpath as a seq of strings, split by the platform "Returns the classpath as a seq of strings, split by the platform
specific path separator." specific path separator."
@ -78,10 +79,12 @@
(defn get-classpath (defn get-classpath
"Returns the current classpath as set by --classpath, BABASHKA_CLASSPATH and add-classpath." "Returns the current classpath as set by --classpath, BABASHKA_CLASSPATH and add-classpath."
[] []
(:cp @cp-state)) (let [cp (System/getProperty "java.class.path")]
(when-not (str/blank? cp)
cp)))
(defn resource (defn resource
(^URL [path] (when-let [st @cp-state] (resource (:loader st) path))) (^URL [path] (resource @the-url-loader path))
(^URL [loader path] (^URL [loader path]
(if (str/starts-with? path "/") nil ;; non-relative paths always return nil (if (str/starts-with? path "/") nil ;; non-relative paths always return nil
(getResource loader [path] true)))) (getResource loader [path] true))))
@ -101,4 +104,3 @@
(def l (loader cp)) (def l (loader cp))
(source-for-namespace l 'babashka.impl.cheshire nil) (source-for-namespace l 'babashka.impl.cheshire nil)
(time (:file (source-for-namespace l 'cheshire.core nil)))) ;; 20ms -> 2.25ms (time (:file (source-for-namespace l 'cheshire.core nil)))) ;; 20ms -> 2.25ms

View file

@ -781,7 +781,8 @@ Use bb run --help to show this help output.
env-os-arch-present? (not= env-os-arch sys-os-arch)))) env-os-arch-present? (not= env-os-arch sys-os-arch))))
(defn exec [cli-opts] (defn exec [cli-opts]
(binding [*unrestricted* true] (with-bindings {#'*unrestricted* true
clojure.lang.Compiler/LOADER @cp/the-url-loader}
(sci/binding [core/warn-on-reflection @core/warn-on-reflection (sci/binding [core/warn-on-reflection @core/warn-on-reflection
core/unchecked-math @core/unchecked-math core/unchecked-math @core/unchecked-math
core/data-readers @core/data-readers core/data-readers @core/data-readers
@ -837,8 +838,7 @@ Use bb run --help to show this help output.
_ (when jar _ (when jar
(cp/add-classpath jar)) (cp/add-classpath jar))
load-fn (fn [{:keys [:namespace :reload]}] load-fn (fn [{:keys [:namespace :reload]}]
(let [{:keys [loader]} (let [loader @cp/the-url-loader]
@cp/cp-state]
(or (or
(when ;; ignore built-in namespaces when uberscripting, unless with :reload (when ;; ignore built-in namespaces when uberscripting, unless with :reload
(and uberscript (and uberscript
@ -884,7 +884,7 @@ Use bb run --help to show this help output.
nil)))) nil))))
main (if (and jar (not main)) main (if (and jar (not main))
(when-let [res (cp/getResource (when-let [res (cp/getResource
(cp/loader jar) (cp/new-loader [jar])
["META-INF/MANIFEST.MF"] {:url? true})] ["META-INF/MANIFEST.MF"] {:url? true})]
(cp/main-ns res)) (cp/main-ns res))
main) main)
@ -934,7 +934,7 @@ Use bb run --help to show this help output.
:debug debug :debug debug
:preloads preloads :preloads preloads
:init init :init init
:loader (:loader @cp/cp-state)})))) :loader @cp/the-url-loader}))))
expression (str/join " " expressions) ;; this might mess with the locations... expression (str/join " " expressions) ;; this might mess with the locations...
exit-code exit-code
;; handle preloads ;; handle preloads
@ -948,7 +948,7 @@ Use bb run --help to show this help output.
:debug debug :debug debug
:preloads preloads :preloads preloads
:init init :init init
:loader (:loader @cp/cp-state)}))))) :loader @cp/the-url-loader})))))
nil)) nil))
exit-code exit-code
;; handle --init ;; handle --init
@ -961,7 +961,7 @@ Use bb run --help to show this help output.
:debug debug :debug debug
:preloads preloads :preloads preloads
:init init :init init
:loader (:loader @cp/cp-state)})))) :loader @cp/the-url-loader}))))
nil)) nil))
;; socket REPL is start asynchronously. when no other args are ;; socket REPL is start asynchronously. when no other args are
;; provided, a normal REPL will be started as well, which causes the ;; provided, a normal REPL will be started as well, which causes the
@ -1020,7 +1020,7 @@ Use bb run --help to show this help output.
(error-handler e {:expression expression (error-handler e {:expression expression
:debug debug :debug debug
:preloads preloads :preloads preloads
:loader (:loader @cp/cp-state)})))) :loader @cp/the-url-loader}))))
clojure [nil (if-let [proc (bdeps/clojure command-line-args)] clojure [nil (if-let [proc (bdeps/clojure command-line-args)]
(-> @proc :exit) (-> @proc :exit)
0)] 0)]
@ -1080,7 +1080,7 @@ Use bb run --help to show this help output.
abs-path #(-> % io/file .getAbsolutePath) abs-path #(-> % io/file .getAbsolutePath)
bb-edn-file (cond bb-edn-file (cond
config (when (fs/exists? config) (abs-path config)) config (when (fs/exists? config) (abs-path config))
jar (some-> jar cp/loader (cp/resource "META-INF/bb.edn") .toString) jar (some-> [jar] cp/new-loader (cp/resource "META-INF/bb.edn") .toString)
:else (when (fs/exists? "bb.edn") (abs-path "bb.edn"))) :else (when (fs/exists? "bb.edn") (abs-path "bb.edn")))
bb-edn (when (or bb-edn-file merge-deps) bb-edn (when (or bb-edn-file merge-deps)
(when bb-edn-file (System/setProperty "babashka.config" bb-edn-file)) (when bb-edn-file (System/setProperty "babashka.config" bb-edn-file))
@ -1099,6 +1099,7 @@ Use bb run --help to show this help output.
(vreset! common/bb-edn edn))) (vreset! common/bb-edn edn)))
;; _ (.println System/err (str bb-edn)) ;; _ (.println System/err (str bb-edn))
min-bb-version (:min-bb-version bb-edn)] min-bb-version (:min-bb-version bb-edn)]
(System/setProperty "java.class.path" "")
(when min-bb-version (when min-bb-version
(when-not (satisfies-min-version? min-bb-version) (when-not (satisfies-min-version? min-bb-version)
(binding [*out* *err*] (binding [*out* *err*]

View file

@ -70,3 +70,10 @@
(str/trim (str/trim
(tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar" (tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar"
"(pos? (count (slurp (io/resource \"foo.clj\")))) ")))))) "(pos? (count (slurp (io/resource \"foo.clj\")))) "))))))
(deftest classloader-test
(let [url
(tu/bb nil "--classpath" "test-resources/babashka/src_for_classpath_test/foo.jar"
"(first (map str (.getURLs (clojure.lang.RT/baseLoader))))")]
(is (str/includes? url "file:"))
(is (str/includes? url "foo.jar"))))

View file

@ -44,7 +44,7 @@
(System/exit 1))))) (System/exit 1)))))
(defn bb-jvm [input-or-opts & args] (defn bb-jvm [input-or-opts & args]
(reset! cp/cp-state nil) (alter-var-root #'cp/the-url-loader (constantly (delay (cp/new-loader []))))
(reset! main/env {}) (reset! main/env {})
(vreset! common/bb-edn nil) (vreset! common/bb-edn nil)
(System/clearProperty "babashka.config") (System/clearProperty "babashka.config")