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.

>From b4cb455cae55eef48c14dae8fc69f50cd434afb4 Mon Sep 17 00:00:00 2001
From: Gene Goykhman <g...@indigo1.com>
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)

Reply via email to