Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Dynamically add gen-path to classloader #31

Merged
merged 1 commit into from
Jun 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,6 @@ To use Closure Compiler advanced optimisation levels you will need to create an
{:optimizations :advanced}
```

The Closure Compiler then requires the generated test runner to be on the path so you'll need to add this to your `:paths` key in your `deps.edn`:

```edn
:paths ["src" "test" "cljs-test-runner-out/gen"]
```

It will fail the first time you run this, that's because that directory doesn't exist yet so it'll be removed from the path on startup. To fix this you can run the following before executing your tests:

```bash
mkdir -p cljs-test-runner-out/gen
```

Now when you run the following, your tests will be executed with advanced compilation:

```bash
Expand Down
19 changes: 18 additions & 1 deletion src/cljs_test_runner/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
[clojure.edn :as edn]
[clojure.tools.cli :as cli]
[cljs.build.api :as cljs]
[doo.core :as doo]))
[doo.core :as doo])
(:import (clojure.lang DynamicClassLoader)))

(def ns-filter-cljs
"Namespace filtering code from cognitect-labs/test-runner but modified and as a string. Inserted into the test runner ClojureScript code when it's rendered. Forgive me performing string based meta programming."
Expand Down Expand Up @@ -106,6 +107,19 @@
:else
(edn/read-string (slurp path-or-data))))

(defn add-loader-url
"Add url string or URL to the highest level DynamicClassLoader url set."
[url]
(let [u (if (string? url) (java.net.URL. url) url)
loader (loop [loader (.getContextClassLoader (Thread/currentThread))]
(let [parent (.getParent loader)]
(if (instance? DynamicClassLoader parent)
(recur parent)
loader)))]
(if (instance? DynamicClassLoader loader)
(.addURL ^DynamicClassLoader loader u)
(throw (IllegalAccessError. "Context classloader is not a DynamicClassLoader")))))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty cool stuff, will definitely be making use of this in other projects. Adding deps at runtime will be super handy with a Clojure plugin system I'll need soon. Thanks for a good example!


(defn test-cljs-namespaces-in-dir
"Execute all ClojureScript tests in a directory."
[{:keys [env dir out watch ns-symbols ns-regexs var include exclude verbose compile-opts doo-opts]}]
Expand All @@ -130,6 +144,7 @@
:planck {:doo-env :planck})]
(io/make-parents src-path)
(spit src-path test-runner-cljs)
(add-loader-url (io/as-url (io/file gen-path)))
(try
(let [build-opts (merge {:output-to out-path
:output-dir out
Expand Down Expand Up @@ -203,6 +218,8 @@
(defn -main
"Creates a ClojureScript test runner and executes it with node (by default)."
[& args]
(let [cl (.getContextClassLoader (Thread/currentThread))]
(.setContextClassLoader (Thread/currentThread) (clojure.lang.DynamicClassLoader. cl)))
(let [{:keys [options errors summary]} (cli/parse-opts args cli-options)]
(cond
(:help options) (exit 0 summary)
Expand Down