Skip to content

Commit

Permalink
Detect nrepl+unix:socket.file configurations
Browse files Browse the repository at this point in the history
"leiningen ... :socket nrepl.sock" reports the unix domain socket on
stdout like this:

  nREPL server listening on  nrepl+unix:nrepl.sock

Detect that in nrepl-server-filter and when found, set the
nrepl-endpoint to a suitable "local-unix-domain-socket" host-based
entry.
  • Loading branch information
rlbdv authored and bbatsov committed Jan 29, 2023
1 parent 944c07b commit 71a319e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### New features

- [#3314](https://github.com/clojure-emacs/cider/issues/3314): Detect `nrepl+unix` sockets (say via `lein nrepl :headless :socket nrepl.sock`).
- [#3262](https://github.com/clojure-emacs/cider/issues/3262): Add navigation functionality to `npfb` keys inside the data inspector's buffer.
- [#3310](https://github.com/clojure-emacs/cider/issues/3310): Add ability to use custom coordinates in jack-in-dependecies

Expand Down
17 changes: 13 additions & 4 deletions doc/modules/ROOT/pages/basics/up_and_running.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,13 @@ CIDER's support for Unix sockets is considered experimental and its
interface might change in future CIDER releases.

When locally running nREPL servers, there is the option to listen on a
socket file instead of opening a network port. This can have
advantages in some use cases, e.g. when working with virtual networks
(containers) where sharing a file socket can be vastly simpler than
managing bridge networks and firewall setups.
socket file instead of opening a network port. As long as access to
the parent directory of the socket is sufficiently protected, this is
much more secure than the network port, since any local user can
access the port-provided REPL. It can also be be helpful in other
cases, e.g. when working with virtual networks (containers) where
sharing a file socket can be vastly simpler than managing bridge
networks and firewall setups.

After having started an nREPL server on a file socket, e.g. with the
`clj` command (see https://nrepl.org/nrepl/usage/server.html for other
Expand All @@ -297,6 +300,12 @@ $ clj -R:nREPL -m nrepl.cmdline --socket nrepl.sock
you can then connect CIDER by using the `local-unix-domain-socket`
special hostname with `cider-connect`: kbd:[M-x] `cider-connect` kbd:[RET] `local-unix-domain-socket` kbd:[RET] `nrepl.sock` kbd:[RET].

At the moment only with `leiningen`, commands like `cider-jack-in`
will detect and use the unix domain socket if one is requested via the
`:socket` argument. This can be arranged by specifying a prefix
argument to `cider-jack-in`, e.g. kbd:[C-u] kbd:[M-x] `cider-jack-in`,
or by adjusting `cider-lein-parameters`.

== What's Next?

So, what to do next now that CIDER's ready for action? Here are a few ideas:
Expand Down
39 changes: 26 additions & 13 deletions nrepl-client.el
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,12 @@ been determined."
(propertize cmd 'face 'font-lock-keyword-face))
serv-proc)))

(defconst nrepl-listening-address-regexp
(defconst nrepl-listening-unix-address-regexp
(rx
(and "nREPL server listening on" (+ " ")
"nrepl+unix:" (group-n 1 (+ not-newline)))))

(defconst nrepl-listening-inet-address-regexp
(rx (or
;; standard
(and "nREPL server started on port " (group-n 1 (+ (any "0-9"))))
Expand Down Expand Up @@ -1155,18 +1160,26 @@ up."
(when-let* ((win (get-buffer-window)))
(set-window-point win (point)))))
;; detect the port the server is listening on from its output
(when (and (null nrepl-endpoint)
(string-match nrepl-listening-address-regexp output))
(let ((host (or (match-string 2 output)
(file-remote-p default-directory 'host)
"localhost"))
(port (string-to-number (match-string 1 output))))
(setq nrepl-endpoint (list :host host
:port port))
(message "[nREPL] server started on %s" port)
(cider--process-plist-put process :cider--nrepl-server-ready t)
(when nrepl-on-port-callback
(funcall nrepl-on-port-callback (process-buffer process)))))))))
(when (null nrepl-endpoint)
(let ((end (cond
((string-match nrepl-listening-unix-address-regexp output)
(let ((path (match-string 1 output)))
(message "[nREPL] server started on nrepl+unix:%s" path)
(list :host "local-unix-domain-socket"
:port path
:socket-file path)))
((string-match nrepl-listening-inet-address-regexp output)
(let ((host (or (match-string 2 output)
(file-remote-p default-directory 'host)
"localhost"))
(port (string-to-number (match-string 1 output))))
(message "[nREPL] server started on %s" port)
(list :host host :port port))))))
(when end
(setq nrepl-endpoint end)
(cider--process-plist-put process :cider--nrepl-server-ready t)
(when nrepl-on-port-callback
(funcall nrepl-on-port-callback (process-buffer process))))))))))

(defmacro emacs-bug-46284/when-27.1-windows-nt (&rest body)
"Only evaluate BODY when Emacs bug #46284 has been detected."
Expand Down
14 changes: 11 additions & 3 deletions test/nrepl-client-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -114,29 +114,37 @@
(describe "nrepl-parse-port"
(it "standard"
(let ((msg "nREPL server started on port 58882 on host kubernetes.docker.internal - nrepl://kubernetes.docker.internal:58882"))
(expect (string-match nrepl-listening-address-regexp msg)
(expect (string-match nrepl-listening-inet-address-regexp msg)
:not :to-be nil)
(expect (match-string 1 msg)
:to-equal "58882")
(expect (match-string 2 msg)
:to-be nil)))
(it "babashka"
(let ((msg "Started nREPL server at 127.0.0.1:1667"))
(expect (string-match nrepl-listening-address-regexp msg)
(expect (string-match nrepl-listening-inet-address-regexp msg)
:not :to-be nil)
(expect (match-string 1 msg)
:to-equal "1667")
(expect (match-string 2 msg)
:to-equal "127.0.0.1")))
(it "shadow"
(let ((msg "shadow-cljs - nREPL server started on port 50999"))
(expect (string-match nrepl-listening-address-regexp msg)
(expect (string-match nrepl-listening-inet-address-regexp msg)
:not :to-be nil)
(expect (match-string 1 msg)
:to-equal "50999")
(expect (match-string 2 msg)
:to-be nil))))

(describe "nrepl-parse-sock"
(it "standard"
(let ((msg "nREPL server listening on nrepl+unix:nrepl.sock"))
(expect (string-match nrepl-listening-unix-address-regexp msg)
:not :to-be nil)
(expect (match-string 1 msg)
:to-equal "nrepl.sock"))))

(describe "nrepl-client-lifecycle"
(it "start and stop nrepl client process"

Expand Down

0 comments on commit 71a319e

Please sign in to comment.