Skip to content
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
36 changes: 27 additions & 9 deletions src/cider_nrepl/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,35 @@
[middleware-var-strs]
(into [] mw-xf middleware-var-strs))

(defn- build-handler
Copy link
Member

Choose a reason for hiding this comment

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

I think that build handler should just take a list of middlewares and be invoked only if a handler wasn't passed to start-nrepl.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, so that implies that either a handler or middleware is expected, but not both. I can make that change.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, exactly. Normally you'd just use a predefined handler, but in some cases you might opt to build the handler yourself by supplying some list of middlewares instead.

Copy link
Member

Choose a reason for hiding this comment

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

(e.g. because some middleware is problematic in your setup or something like this)

[middleware]
(apply nrepl.server/default-handler (->mw-list middleware)))

(defn start-nrepl
[opts]
(let [{:keys [handler middleware bind port] :or {port 0 bind "::"}} opts
"Starts a socket-based nREPL server. Accepts a map with the following keys:

* :port — defaults to 0, which autoselects an open port

* :bind — bind address, by default \"::\" (falling back to \"localhost\" if
\"::\" isn't resolved by the underlying network stack)

* :handler — the nREPL message handler to use for each incoming connection;
defaults to the result of `(nrepl.server/default-handler)`

handler (cond-> (or handler nrepl.server/default-handler)
middleware (apply (->mw-list middleware)))
* :middleware - a sequence of vars or string which can be resolved to vars,
representing middleware you wish to mix in to the nREPL handler. Vars can
resolve to a sequence of vars, in which case they'll be flattened into the
list of middleware."
[{:keys [handler middleware bind port] :as opts}]
(let [handler
(if handler
(handler)
(build-handler middleware))

{:keys [server-socket port] :as server}
(nrepl.server/start-server :handler handler
:bind bind
:port port)
:bind (or bind "localhost")
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't bind work with nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, I think what will happen here is an exception when this goes through travis. From clojure.tools.nrepl.server:

 (let [bind-addr (if bind
                    (InetSocketAddress. ^String bind ^Integer port)
                    (let [local (InetSocketAddress. "::" port)]
                      (if (.isUnresolved local)
                        (InetSocketAddress. "localhost" port)
                        local)))

nil causes (InetSocketAddress. "::" port) to be invoked, which throws an exception in travis - I presume due to IPv6 not being enabled. If we default to localhost, we dodge that particular idiosyncrasy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry I should clarify: I made this change after experiencing the exception in travis. Not a thought experiment, but an observation :)

Copy link
Member

Choose a reason for hiding this comment

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

I see. I was just wondering if this won't message up something for people who have disabled IPv4. Probably not a big deal now, I'll fixed this once we finally move the project to https://github.com/nrepl/nREPL

Copy link
Member

Choose a reason for hiding this comment

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

(tools.nrepl is practically dead, so we've migrated the project out of clojure contrib to revive it)

:port (or port 0))

bind
(-> server-socket (.getInetAddress) (.getHostName))]
Expand All @@ -50,8 +68,8 @@

(defn init
([]
(init nil))
([handlers]
(start-nrepl {:handler handlers})
(start-nrepl {}))
([middleware]
(start-nrepl {:middleware middleware})
;; Return nil so the value doesn't print
nil))
43 changes: 43 additions & 0 deletions test/clj/cider/nrepl/main_test.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
(ns cider.nrepl.main-test
(:require [cider.nrepl :refer [wrap-debug cider-middleware]]
[cider-nrepl.main :as m]
[clojure.test :refer :all]
[clojure.tools.nrepl :as nrepl]
[clojure.tools.nrepl.server :as nrepl.server]
[clojure.tools.nrepl.transport :as transport]))

(defn start-stop-nrepl-session [opts]
Copy link
Member

Choose a reason for hiding this comment

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

I don't see where you stop the server in each test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding was that the with-open macro would suffice to close the server. I borrowed much of this from cider.nrepl.middleware.debug-integration-test/with-nrepl-session*

Copy link
Member

Choose a reason for hiding this comment

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

Ah, ok.

(with-open [server (#'m/start-nrepl opts)
transport (nrepl/connect :port (:port server))]
(transport/send transport {:op "clone" :id 1})
(let [session-id (:new-session (transport/recv transport 1000))]
(assert session-id)
(transport/send transport {:session session-id
:id 2
:op "clone"})
(is (= (:status (transport/recv transport 1000)) ["done"])))))

(deftest start-nrepl-test
(testing "passing a specific handler should work"
(let [opts {:handler nrepl.server/default-handler}]
(start-stop-nrepl-session opts)))

(testing "passing a sequence instead of a map shouldn't crash"
(let [opts ["cider.nrepl/cider-middleware"]]
(start-stop-nrepl-session opts)))

(testing "passing nil shouldn't crash"
(let [opts nil]
(start-stop-nrepl-session opts)))

(testing "passing valid middleware should work"
(let [opts {:middleware ["cider.nrepl/cider-middleware"]}]
(start-stop-nrepl-session opts)))

(testing "passing options as given by boot task middleware should work"
(let [opts {:middleware '(cider.nrepl.middleware.version/wrap-version
cider.nrepl.middleware.apropos/wrap-apropos)
:port nil
:bind nil}]
(start-stop-nrepl-session opts))))