Last active
April 26, 2019 06:47
Star
You must be signed in to star a gist
For toolsmithes really caring about isolation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; Clojure 1.6.0 | |
=> *clojure-version* | |
{:major 1, :minor 6, :incremental 0, :qualifier nil} | |
=> (def env1 (create-clojure-env)) | |
#'net.cgrand.quarantine/env1 | |
=> (env1 *in* *out*) | |
clojure.core=> *clojure-version* | |
{:major 1, :minor 8, :incremental 0, :qualifier nil} | |
clojure.core=> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defproject net.cgrand/quarantine "0.1.0-SNAPSHOT" | |
:description "Clojure in a function." | |
:license {:name "Eclipse Public License" | |
:url "http://www.eclipse.org/legal/epl-v10.html"} | |
:plugins [[com.pupeno/jar-copier "0.4.0"]] | |
:prep-tasks ["javac" "compile" "jar-copier"] | |
:jar-copier {:jars [[org.clojure/clojure "1.8.0"]] | |
:destination "resources/jars"} | |
:dependencies [[org.clojure/clojure "1.6.0"]]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns net.cgrand.quarantine) | |
(defn jar-url [] | |
(with-open [in (.getResourceAsStream (or (.getContextClassLoader (Thread/currentThread)) | |
(ClassLoader/getSystemClassLoader)) | |
"jars/org.clojure/clojure.jar")] | |
(let [bbuf (byte-array (* 4 1024 1024)) | |
tmpfile (java.io.File/createTempFile "isolation-" ".jar")] | |
(with-open [out (java.io.FileOutputStream. tmpfile)] | |
(loop [] | |
(let [got (.read in bbuf)] | |
(when (<= 0 got) | |
(.write out bbuf 0 got))))) | |
(-> tmpfile .toURI .toURL)))) | |
(defn create-clojure-env | |
"Returns a clojure env. A clojure env is a function of two arguments: in and out. | |
When it is called it starts a REPL on these streams. | |
All REPL started from the same Clojure env share the same namespaces. | |
Namespaces are isolated between envs. | |
Envs are sol isolated that they wouldn't recognize a keyword from another env." | |
[] | |
(let [cl (java.net.URLClassLoader. (into-array [(jar-url)]) nil) | |
in-quarantine | |
(fn [stub] | |
(let [ccl (.getContextClassLoader (Thread/currentThread))] | |
(.setContextClassLoader (Thread/currentThread) cl) | |
(try | |
(stub) | |
(finally | |
(.setContextClassLoader (Thread/currentThread) ccl))))) | |
clj (in-quarantine #(Class/forName "clojure.java.api.Clojure" true cl)) | |
IFn (Class/forName "clojure.lang.IFn" true cl) | |
varm (.getMethod clj "var" (into-array [Object])) | |
readm (.getMethod clj "read" (into-array [String])) | |
evalv (.invoke varm clj (to-array ["clojure.core/eval"])) | |
invoke1 (.getMethod IFn "invoke" (into-array [Object])) | |
invoke2 (.getMethod IFn "invoke" (into-array [Object Object])) | |
eval (fn [x] | |
(in-quarantine | |
#(let [form (.invoke readm clj (to-array [(pr-str x)]))] | |
(.invoke invoke1 evalv (to-array [form]))))) | |
repl (eval '(fn [in out] | |
(binding [*in* (clojure.lang.LineNumberingPushbackReader. in) | |
*out* out] | |
(clojure.main/repl))))] | |
(fn [in out] | |
(in-quarantine | |
#(.invoke invoke2 repl (to-array [in out])))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment