[PATCH] Provide completion candidates for remote containers over a TRAMP connection

Gene Goykhman <[email protected]>
Newsgroups gmane.emacs.tramp
Message-ID <[email protected]>
Following up on https://lists.gnu.org/archive/html/tramp-devel/2023-08/msg00001.html, I have prepared a patch to add remote container completion support to TRAMP.

A couple of questions/things I'm uncertain of in this patch:

1. I am removing the check for executable-find for the docker and podman programs since they need to be run on the remote system (and executable-find will fail as it only checks the local machine while multi-hopping). I'm not sure if there is a better way to handle this.

2. In tramp-set-completion-function I am short-circuiting the cond check for a valid "file or registry key" since again, file-exists-p will fail when checking for the docker or podman program on a remote system when checking a multi-hop path. I'm open to a better ideas here since my change effectively no-ops the whole cond.

3. (style question) I've added my required variable tramp-last-hop-directory as an autoload in tramp.el but if there's a better place for it I'd be happy to move it.
0001-Provide-completion-candidates-for-remote-containers-.patch (text/x-patch, 4.7 KB)
From b4cb455cae55eef48c14dae8fc69f50cd434afb4 Mon Sep 17 00:00:00 2001
From: Gene Goykhman <[email protected]>
Date: Tue, 22 Aug 2023 12:10:44 -0400
Subject: [PATCH] Provide completion candidates for remote containers over a
 TRAMP connection

* lisp/net/tramp.el (tramp-last-hop-directory): Add new variable.
(tramp-set-completion-function): Don't use executable-find for
container program since it might not be running locally.
(container-host-directory): Determine default directory for container
host.
(tramp-completion-handle-file-name-all-completions): Use container
host directory to execute container program on remote.

* lisp/net/tramp-container.el (tramp-last-hop-directory): Declare variable.
(tramp-container--completion-function): Set default directory to last hop.
---
 lisp/net/tramp-container.el |  9 ++++++---
 lisp/net/tramp.el           | 20 ++++++++++++++++++--
 2 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/lisp/net/tramp-container.el b/lisp/net/tramp-container.el
index 7f8d4473ad7..5ad8a09fd51 100644
--- a/lisp/net/tramp-container.el
+++ b/lisp/net/tramp-container.el
@@ -157,6 +157,8 @@ If it is nil, the default context will be used."
 (defconst tramp-flatpak-method "flatpak"
   "Tramp method name to use to connect to Flatpak sandboxes.")
 
+(defvar tramp-last-hop-directory)
+
 ;;;###tramp-autoload
 (defun tramp-container--completion-function (program)
   "List running containers available for connection.
@@ -165,7 +167,8 @@ PROGRAM is the program to be run for \"ps\", either
 
 This function is used by `tramp-set-completion-function', please
 see its function help for a description of the format."
-  (when-let ((default-directory tramp-compat-temporary-file-directory)
+  (when-let ((default-directory (or tramp-last-hop-directory
+                                    tramp-compat-temporary-file-directory))
 	     (raw-list (shell-command-to-string
 			(concat program " ps --format '{{.ID}}\t{{.Names}}'")))
              (lines (split-string raw-list "\n" 'omit))
@@ -383,12 +386,12 @@ see its function help for a description of the format."
  (tramp-set-completion-function
   tramp-docker-method
   `((tramp-container--completion-function
-     ,(executable-find tramp-docker-program))))
+     ,tramp-docker-program)))
 
  (tramp-set-completion-function
   tramp-podman-method
   `((tramp-container--completion-function
-     ,(executable-find tramp-podman-program))))
+     ,tramp-podman-program)))
 
  (tramp-set-completion-function
   tramp-kubernetes-method
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index a0092a2d706..427c0871310 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -82,6 +82,9 @@
 (defvar tramp-completion-method-regexp)
 (defvar tramp-completion-file-name-regexp)
 
+;;;###tramp-autoload
+(defvar tramp-last-hop-directory nil)
+
 ;; Reload `tramp-compat' when we reload `tramp-autoloads' of the GNU
 ;; ELPA package.
 ;;;###autoload (when (featurep 'tramp-compat)
@@ -2133,8 +2136,8 @@ Example:
 		    ;; DNS-SD service type.
 		    ((string-match-p
 		      tramp-dns-sd-service-regexp (nth 1 (car v))))
-		    ;; Configuration file or empty string.
-		    (t (file-exists-p (nth 1 (car v))))))
+                    ;; Allow arbitrary executable name (for remote systems) too.
+                    (t t)))
 	(setq r (delete (car v) r)))
       (setq v (cdr v)))
 
@@ -2689,12 +2692,25 @@ not in completion mode."
 
       (tramp-run-real-handler #'file-exists-p (list filename))))
 
+(defun container-host-directory (orig)
+  "Strips off the `tramp-docker-program' or `tramp-podman-program' suffix from ORIG."
+  "Returned path can be used to start programs on the container host."
+  (let ((regexp (format "\\(.*\\)|\\(\\(%s\\)\\|\\(%s\\)\\)" tramp-docker-program tramp-podman-program)))
+    (if (string-match regexp orig)
+        (concat (match-string 1 orig) ":/")
+      orig)))
+
 ;; Method, host name and user name completion.
 ;; `tramp-completion-dissect-file-name' returns a list of
 ;; `tramp-file-name' structures.  For all of them we return possible
 ;; completions.
 (defun tramp-completion-handle-file-name-all-completions (filename directory)
   "Like `file-name-all-completions' for partial Tramp files."
+  (let ((use-container-host-directory (container-host-directory directory)))
+    (when (tramp-tramp-file-p use-container-host-directory)
+      (let ((minibuffer-completing-file-name nil))
+        (setq tramp-last-hop-directory (tramp-make-tramp-file-name
+                                         (tramp-dissect-file-name use-container-host-directory))))))
   (let ((fullname
 	 (tramp-drop-volume-letter (expand-file-name filename directory)))
 	;; When `tramp-syntax' is `simplified', we need a default method.
-- 
2.39.2 (Apple Git-143)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.