From: Jim Porter <jporterbugs@gmail.com>
To: emacs-devel@gnu.org
Cc: michael.albinus@gmx.de
Subject: [RFC] Explicity-remote commands in Eshell
Date: Sun, 5 Mar 2023 18:35:43 -0800 [thread overview]
Message-ID: <0298a618-645c-a0c0-172b-9a0491462959@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1565 bytes --]
One of the nice features of Eshell is that since it's aware of Tramp,
connecting to a different machine (or changing users on a machine) is
just a matter of cd'ing into a remote directory:
cd /ssh:user@somewhere:~/some/dir
In addition, Eshell routes data in pipelines through buffers. In
principle, this means it should be easy to build cross-host pipelines in
Eshell, where the output of a command on host A is piped into the input
of a command on host B. However, it's not easy to spell this in Eshell;
the best I can come up with is to use a subshell like this:
{cd /ssh:user@somewhere: && remote-command} | local-command
Instead, I think we could make this easier:
/ssh:user@somewhere:remote-command | local-command
What do people think of the above syntax? It's a little bit different
from the usual Tramp syntax, since the local part shouldn't be expanded
using 'expand-file-name'; it's an executable somewhere on the remote
$PATH. I can't think of any problems with supporting this syntax in
Eshell[1], but I'm interested to hear others' thoughts.
Attached is a patch demonstrating this. The only non-Eshell change I had
to make was to enhance 'file-remote-p' so that I can tell Tramp not to
call 'expand-file-name'.
As a footnote: you might wonder how to execute a program on your local
host when the current Eshell directory is remote. In my patch, I chose
to do this via quoted file names:
/:local-command
[1] Tramp shouldn't need to know about this syntax in other places. It
can just be something Eshell understands.
[-- Attachment #2: 0001-Add-support-for-explicitly-remote-commands-in-Eshell.patch --]
[-- Type: text/plain, Size: 6000 bytes --]
From 676659ebcbf2cabc5e606620fdd58e3f498225f9 Mon Sep 17 00:00:00 2001
From: Jim Porter <jporterbugs@gmail.com>
Date: Sun, 22 Jan 2023 22:45:40 -0800
Subject: [PATCH] Add support for explicitly-remote commands in Eshell
* lisp/files.el (file-remote-p): Document 'never' for CONNECTED
argument.
* lisp/net/tramp.el (tramp-handle-file-remote-p): Handle CONNECTED
value of 'never'.
* lisp/eshell/esh-ext.el (eshell-explicit-remote-commands): New
option.
(eshell-ext-initialize): Apply 'eshell-handle-remote-command' when
requested.
(eshell-handle-remote-command): New function.
(eshell-remote-command): Reimplement this function and dispatch to
'eshell-external-command', which can handle remote processes on its
own.
---
lisp/eshell/esh-ext.el | 58 ++++++++++++++++++++++++++----------------
lisp/files.el | 4 ++-
lisp/net/tramp.el | 5 ++--
3 files changed, 42 insertions(+), 25 deletions(-)
diff --git a/lisp/eshell/esh-ext.el b/lisp/eshell/esh-ext.el
index f350622e78c..d720cde0dd2 100644
--- a/lisp/eshell/esh-ext.el
+++ b/lisp/eshell/esh-ext.el
@@ -168,11 +168,23 @@ eshell-explicit-command-char
:type 'character
:group 'eshell-ext)
+(defcustom eshell-explicit-remote-commands t
+ "If non-nil, support explicitly-remote commands.
+These are commands with a full remote file name, such as
+\"/ssh:host:whoami\". If this is enabled, you can also run
+explicitly-local commands by using a quoted file name, like
+\"/:whoami\"."
+ :type 'boolean
+ :group 'eshell-ext)
+
;;; Functions:
(defun eshell-ext-initialize () ;Called from `eshell-mode' via intern-soft!
"Initialize the external command handling code."
- (add-hook 'eshell-named-command-hook #'eshell-explicit-command nil t))
+ (add-hook 'eshell-named-command-hook #'eshell-explicit-command nil t)
+ (when eshell-explicit-remote-commands
+ (add-hook 'eshell-named-command-hook
+ #'eshell-handle-remote-command nil t)))
(defun eshell-explicit-command (command args)
"If a command name begins with `*', call it externally always.
@@ -186,30 +198,32 @@ eshell-explicit-command
(error "%s: external command not found"
(substring command 1))))))
+(defun eshell-handle-remote-command (command args)
+ "Handle remote (or quoted) COMMAND names, using ARGS.
+This calls the appropriate function for commands that aren't on
+the connection associated with `default-directory'. (See
+`eshell-explicit-remote-commands'.)"
+ (if (file-name-quoted-p command)
+ (let ((default-directory (if (file-remote-p default-directory)
+ (expand-file-name "~")
+ default-directory)))
+ (eshell-external-command (file-name-unquote command) args))
+ (when (file-remote-p command)
+ (eshell-remote-command command args))))
+
(defun eshell-remote-command (command args)
"Insert output from a remote COMMAND, using ARGS.
A remote command is something that executes on a different machine.
-An external command simply means external to Emacs.
-
-Note that this function is very crude at the moment. It gathers up
-all the output from the remote command, and sends it all at once,
-causing the user to wonder if anything's really going on..."
- (let ((outbuf (generate-new-buffer " *eshell remote output*"))
- (errbuf (generate-new-buffer " *eshell remote error*"))
- (command (file-local-name command))
- (exitcode 1))
- (unwind-protect
- (progn
- (setq exitcode
- (shell-command
- (mapconcat #'shell-quote-argument
- (append (list command) args) " ")
- outbuf errbuf))
- (eshell-print (with-current-buffer outbuf (buffer-string)))
- (eshell-error (with-current-buffer errbuf (buffer-string))))
- (eshell-close-handles exitcode 'nil)
- (kill-buffer outbuf)
- (kill-buffer errbuf))))
+An external command simply means external to Emacs."
+ (let* ((cwd-connection (file-remote-p default-directory))
+ (command-connection (file-remote-p command))
+ (default-directory (if (equal cwd-connection command-connection)
+ default-directory
+ command-connection))
+ (command-localname (file-remote-p command 'localname 'never)))
+ (unless command-connection
+ (error "%s: not a remote command" command))
+ (eshell-external-command command-localname args)))
(defun eshell-external-command (command args)
"Insert output from an external COMMAND, using ARGS."
diff --git a/lisp/files.el b/lisp/files.el
index 387a3b5dc66..e5cb775eb6d 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1267,7 +1267,9 @@ file-remote-p
If CONNECTED is non-nil, return an identification only if FILE is
located on a remote system and a connection is established to
-that remote system.
+that remote system. If CONNECTED is `never', never use an
+existing connection to return the identification (this is
+otherwise like a value of nil).
Tip: You can use this expansion of remote identifier components
to derive a new remote file name from an existing one. For
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 47173b95bea..e2b0e6bffa0 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -4269,13 +4269,14 @@ tramp-handle-file-remote-p
(let ((tramp-verbose (min tramp-verbose 3)))
(when (tramp-tramp-file-p filename)
(let* ((o (tramp-dissect-file-name filename))
- (p (tramp-get-connection-process o))
+ (p (and (not (eq connected 'never))
+ (tramp-get-connection-process o)))
(c (and (process-live-p p)
(tramp-get-connection-property p "connected"))))
;; We expand the file name only, if there is already a connection.
(with-parsed-tramp-file-name
(if c (expand-file-name filename) filename) nil
- (and (or (not connected) c)
+ (and (or (memq connected '(nil never)) c)
(cond
((eq identification 'method) method)
;; Domain and port are appended to user and host,
--
2.25.1
next reply other threads:[~2023-03-06 2:35 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-06 2:35 Jim Porter [this message]
2023-03-06 8:09 ` [RFC] Explicity-remote commands in Eshell Michael Albinus
2023-03-06 16:10 ` John Wiegley
2023-03-06 22:07 ` Jim Porter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0298a618-645c-a0c0-172b-9a0491462959@gmail.com \
--to=jporterbugs@gmail.com \
--cc=emacs-devel@gnu.org \
--cc=michael.albinus@gmx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.