Skip to content

Commit 0cb5daa

Browse files
dpsuttonbbatsov
authored andcommitted
Translate paths when cider-path-translations alist is set (#2606)
If you connect to a running docker image, often the source is mounted in the docker image. This breaks navigation as rather than navigating to "/home/me/projects/foo/src/ns.clj" it believes the file is "/src/ns.clj". This allows rewriting of these prefixes so the locations can map back to the local filesystem.
1 parent b58a332 commit 0cb5daa

File tree

4 files changed

+80
-2
lines changed

4 files changed

+80
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### New features
66

77
* New configuration variable `cider-result-overlay-position` determining where debugger and inline eval result overlays should be displayed. Current options are 'at-eol and 'at-point.
8+
* [#2606](https://github.com/clojure-emacs/cider/pull/2606): Defcustom `cider-path-translations` for translating paths from nrepl messages
89

910
### Changes
1011

cider-common.el

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,29 @@ otherwise, nil."
255255
localname)
256256
name))
257257

258+
(defcustom cider-path-translations nil
259+
"Alist of path prefixes to path prefixes.
260+
Useful to intercept the location of a path in a docker image and translate
261+
to the oringal location. If your project is located at \"~/projects/foo\"
262+
and the src directory of foo is mounted at \"/src\" in the docker
263+
container, the alist would be `((\"/src\" \"~/projects/foo/src\"))"
264+
:type '(alist :key-type string :value-type string)
265+
:group 'cider
266+
:package-version '(cider . "0.23.0"))
267+
268+
(defun cider--translate-path (path)
269+
"Attempt to translate the PATH.
270+
Looks at `cider-path-translations' for (docker . host) alist of path
271+
prefixes."
272+
(seq-some (lambda (translation)
273+
(let ((prefix (file-name-as-directory (expand-file-name (car translation)))))
274+
(when (string-prefix-p prefix path)
275+
(replace-regexp-in-string (format "^%s" (regexp-quote prefix))
276+
(file-name-as-directory
277+
(expand-file-name (cdr translation)))
278+
path))))
279+
cider-path-translations))
280+
258281
(defvar cider-from-nrepl-filename-function
259282
(with-no-warnings
260283
(if (eq system-type 'cygwin)
@@ -271,14 +294,16 @@ otherwise, nil."
271294
"Return PATH's local or tramp path using `cider-prefer-local-resources'.
272295
If no local or remote file exists, return nil."
273296
(let* ((local-path (funcall cider-from-nrepl-filename-function path))
274-
(tramp-path (and local-path (cider--client-tramp-filename local-path))))
297+
(tramp-path (and local-path (cider--client-tramp-filename local-path)))
298+
(translated-path (cider--translate-path local-path)))
275299
(cond ((equal local-path "") "")
276300
((and cider-prefer-local-resources (file-exists-p local-path))
277301
local-path)
278302
((and tramp-path (file-exists-p tramp-path))
279303
tramp-path)
280304
((and local-path (file-exists-p local-path))
281-
local-path))))
305+
local-path)
306+
((and translated-path (file-exists-p translated-path)) translated-path))))
282307

283308
(declare-function archive-extract "arc-mode")
284309
(declare-function archive-zip-extract "arc-mode")

doc/modules/ROOT/pages/config/basic_config.adoc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,32 @@ To prefer local resources to remote resources (tramp) when both are available:
8383
(setq cider-prefer-local-resources t)
8484
----
8585

86+
== Translate paths
87+
88+
If you wish to translate paths from your running instance you may use
89+
the `cider-path-translations` defcustom to do so. For instance,
90+
suppose your app is running in a docker container with your source
91+
directories mounted. The navigation paths will be relative to the
92+
source in the docker container rather than the correct path on your
93+
host machine. You can add translations easily by setting the
94+
following, most likely in dir locals:
95+
96+
[source,lisp]
97+
----
98+
((nil
99+
(cider-path-translations . (("/root" . "/Users/foo")
100+
("/src/" . "/Users/foo/projects")))))
101+
---
102+
103+
Each entry will be interpreted as a directory entry so trailing slash
104+
is optional. Navigation will attempt to translate these locations, and
105+
if they exist, navigate there rather than report the file does not
106+
exist. In the example above, the m2 directory is mounted at /root/.m2
107+
and the source at /src. These translations would map these locations
108+
back to the users computer so that navigation would work.
109+
110+
111+
86112
== Auto-Save Clojure Buffers on Load
87113
88114
Normally, CIDER prompts you to save a modified Clojure buffer when you

test/cider-common-tests.el

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,29 @@
7474
:to-equal "/ssh:test.cider.com:")
7575
(expect (cider-make-tramp-prefix "ssh" nil "test.local")
7676
:to-equal "/ssh:test.local:")))
77+
78+
(defun cider--translate-path-test (translations file)
79+
(let ((cider-path-translations translations))
80+
(cider--translate-path file)))
81+
82+
(describe "cider--translate-docker"
83+
(it "translates filepaths from docker location to host location"
84+
(expect (cider--translate-path-test '(("/docker/src" . "/home/host/project/src")) "/docker/src/namespace.clj")
85+
:to-equal "/home/host/project/src/namespace.clj"))
86+
(it "returns nil if no prefixes match"
87+
(expect (cider--translate-path-test '(("/docker/src" . "/home/host/project/src")) "/home/host/random/file.clj")
88+
:to-equal nil))
89+
(it "won't replace a prefix in the middle of the path"
90+
(expect (cider--translate-path-test '(("/src" . "/host")) "/src/project/src/ns.clj")
91+
:to-equal "/host/project/src/ns.clj"))
92+
(it "handles slashes or no slashes in translations"
93+
(expect (cider--translate-path-test '(("/src" . "/host/")) "/src/project/src/ns.clj")
94+
:to-equal "/host/project/src/ns.clj")
95+
(expect (cider--translate-path-test '(("/src/" . "/host")) "/src/project/src/ns.clj")
96+
:to-equal "/host/project/src/ns.clj"))
97+
(it "expands the destination filepaths"
98+
(expect (cider--translate-path-test '(("/src/" . "~/host")) "/src/project/src/ns.clj")
99+
:to-equal (expand-file-name "~/host/project/src/ns.clj")))
100+
(it "ensures the prefix has a slash"
101+
(expect (cider--translate-path-test '(("/docker" . "/host")) "/docker/ns.clj")
102+
:to-equal "/host/ns.clj")))

0 commit comments

Comments
 (0)