Factor out :repl-options handling into its own function.
This commit is contained in:
parent
b5002a23c2
commit
4b994497ee
1 changed files with 64 additions and 58 deletions
|
@ -10,62 +10,69 @@
|
|||
|
||||
(def *retry-limit* 100)
|
||||
|
||||
(defn repl-server [project host port & repl-options]
|
||||
(let [init-form [:init `#(let [is# ~(:repl-init-script project)
|
||||
in# ~(:repl-init project)
|
||||
mn# '~(:main project)]
|
||||
(when (and is# (.exists (File. (str is#))))
|
||||
(println (str "Warning: :repl-init-script is "
|
||||
"deprecated; use :repl-init."))
|
||||
(load-file is#))
|
||||
(when in#
|
||||
(doto in# require in-ns))
|
||||
(if mn#
|
||||
(doto mn# require in-ns)
|
||||
(in-ns '~'user)))]
|
||||
repl-options (concat init-form repl-options)]
|
||||
`(do (try ;; transitive requires don't work for stuff on bootclasspath
|
||||
(require '~'clojure.java.shell)
|
||||
(require '~'clojure.java.browse)
|
||||
;; these are new in clojure 1.2, so swallow exceptions for 1.1
|
||||
(catch Exception _#))
|
||||
(let [server# (ServerSocket. ~port 0 (InetAddress/getByName ~host))
|
||||
acc# (fn [s#]
|
||||
(let [ins# (.getInputStream s#)
|
||||
outs# (.getOutputStream s#)
|
||||
skip-whitespace# @(ns-resolve '~'clojure.main
|
||||
'~'skip-whitespace)
|
||||
;; Suppress socket closed exceptions since
|
||||
;; they are part of normal operation
|
||||
caught# (fn [t#]
|
||||
(when-not (instance? SocketException t#)
|
||||
(throw t#)))]
|
||||
(doto (Thread.
|
||||
#(binding [*in* (-> ins# InputStreamReader.
|
||||
LineNumberingPushbackReader.)
|
||||
*out* (OutputStreamWriter. outs#)
|
||||
*err* *err*
|
||||
;; TODO: bugger; can't rebind in 1.3
|
||||
;; clojure.main/repl has no way
|
||||
;; to exit without signalling EOF,
|
||||
;; which we can't do with a socket.
|
||||
clojure.main/skip-whitespace
|
||||
(fn [s#]
|
||||
(try (skip-whitespace# s#)
|
||||
(catch java.io.IOException _#
|
||||
:stream-end)))]
|
||||
(clojure.main/repl :caught caught#
|
||||
~@repl-options)))
|
||||
.start)))]
|
||||
(doto (Thread. #(when-not (.isClosed server#)
|
||||
(try
|
||||
(acc# (.accept server#))
|
||||
(catch SocketException e#
|
||||
(.printStackTrace e#)))
|
||||
(recur)))
|
||||
.start)
|
||||
(symbol (format "REPL started; server listening on %s:%s."
|
||||
~host ~port))))))
|
||||
;; TODO: test custom options, repl in interactive
|
||||
(defn repl-options [project options]
|
||||
(let [options (apply hash-map options)
|
||||
init `#(let [is# ~(:repl-init-script project)
|
||||
in# ~(:repl-init project)
|
||||
mn# '~(:main project)]
|
||||
~(:init options)
|
||||
(when (and is# (.exists (File. (str is#))))
|
||||
(println (str "Warning: :repl-init-script is "
|
||||
"deprecated; use :repl-init."))
|
||||
(load-file is#))
|
||||
(when in#
|
||||
(doto in# require in-ns))
|
||||
(if mn#
|
||||
(doto mn# require in-ns)
|
||||
(in-ns '~'user)))
|
||||
;; Suppress socket closed since it's part of normal operation
|
||||
caught `(fn [t#]
|
||||
(when-not (instance? SocketException t#)
|
||||
(~(:caught options 'clojure.main/repl-caught) t#)))
|
||||
;; clojure.main/repl has no way to exit without signalling EOF,
|
||||
;; which we can't do with a socket. We can't rebind skip-whitespace
|
||||
;; in Clojure 1.3, so we have to duplicate the function
|
||||
read `(fn [request-prompt# request-exit#]
|
||||
(or ({:line-start request-prompt# :stream-end request-exit#}
|
||||
(try (clojure.main/skip-whitespace *in*)
|
||||
(catch java.io.IOException _#
|
||||
:stream-end)))
|
||||
(let [input# (read)]
|
||||
(clojure.main/skip-if-eol *in*)
|
||||
input#)))]
|
||||
(concat [:init init :caught caught :read read]
|
||||
(flatten (seq (dissoc options :caught :init :read))))))
|
||||
|
||||
(defn repl-server [project host port & options]
|
||||
`(do (try ;; transitive requires don't work for stuff on bootclasspath
|
||||
(require '~'clojure.java.shell)
|
||||
(require '~'clojure.java.browse)
|
||||
;; these are new in clojure 1.2, so swallow exceptions for 1.1
|
||||
(catch Exception _#))
|
||||
(let [server# (ServerSocket. ~port 0 (InetAddress/getByName ~host))
|
||||
acc# (fn [s#]
|
||||
(let [ins# (.getInputStream s#)
|
||||
outs# (.getOutputStream s#)
|
||||
skip-whitespace# @(ns-resolve '~'clojure.main
|
||||
'~'skip-whitespace)]
|
||||
(doto (Thread.
|
||||
#(binding [*in* (-> ins# InputStreamReader.
|
||||
LineNumberingPushbackReader.)
|
||||
*out* (OutputStreamWriter. outs#)
|
||||
*err* *err*]
|
||||
(clojure.main/repl
|
||||
~@(repl-options project options))))
|
||||
.start)))]
|
||||
(doto (Thread. #(when-not (.isClosed server#)
|
||||
(try
|
||||
(acc# (.accept server#))
|
||||
(catch SocketException e#
|
||||
(.printStackTrace e#)))
|
||||
(recur)))
|
||||
.start)
|
||||
(symbol (format "REPL started; server listening on %s:%s."
|
||||
~host ~port)))))
|
||||
|
||||
(defn copy-out-loop [reader]
|
||||
(let [buffer (make-array Character/TYPE 1000)]
|
||||
|
@ -126,5 +133,4 @@ Running outside a project directory will start a standalone repl session."
|
|||
(clojure.main/with-bindings (println (eval server-form)))
|
||||
(eval-in-project project server-form)))
|
||||
(poll-repl-connection port retries repl-client)
|
||||
(exit))))
|
||||
|
||||
0)))
|
||||
|
|
Loading…
Reference in a new issue