Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Detect nrepl+unix sockets (say via lein nrepl :headless :socket nrepl.sock) #3314

Merged
merged 1 commit into from
Jan 29, 2023
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
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.

### Changes
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 @@ -273,10 +273,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 @@ -290,6 +293,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