* [RFC] Explicity-remote commands in Eshell
@ 2023-03-06 2:35 Jim Porter
2023-03-06 8:09 ` Michael Albinus
0 siblings, 1 reply; 4+ messages in thread
From: Jim Porter @ 2023-03-06 2:35 UTC (permalink / raw)
To: emacs-devel; +Cc: michael.albinus
[-- 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
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [RFC] Explicity-remote commands in Eshell
2023-03-06 2:35 [RFC] Explicity-remote commands in Eshell Jim Porter
@ 2023-03-06 8:09 ` Michael Albinus
2023-03-06 16:10 ` John Wiegley
2023-03-06 22:07 ` Jim Porter
0 siblings, 2 replies; 4+ messages in thread
From: Michael Albinus @ 2023-03-06 8:09 UTC (permalink / raw)
To: Jim Porter; +Cc: emacs-devel
Jim Porter <jporterbugs@gmail.com> writes:
Hi Jim,
> 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.
I've skimmed over the patch, and there's nothing to object from Tramp
pov. I'm not a regular Eshell user, so I don't know how useful it will
be.
One remark: Why don't you allow remoteness everywhere? Sth like
--8<---------------cut here---------------start------------->8---
/ssh:user@somewhere:remote-command | /ssh:another-user@elsewhere:another-remote-command
--8<---------------cut here---------------end--------------->8---
This even with multiple pipes in a row. Mixed with local commands. And
using just the shorter version "command", which means a local or remote
command according to default-directory.
"/:command" is a nice trick, btw :-)
Best regards, Michael.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC] Explicity-remote commands in Eshell
2023-03-06 8:09 ` Michael Albinus
@ 2023-03-06 16:10 ` John Wiegley
2023-03-06 22:07 ` Jim Porter
1 sibling, 0 replies; 4+ messages in thread
From: John Wiegley @ 2023-03-06 16:10 UTC (permalink / raw)
To: Michael Albinus; +Cc: Jim Porter, emacs-devel
>>>>> "MA" == Michael Albinus <michael.albinus@gmx.de> writes:
MA> I've skimmed over the patch, and there's nothing to object from Tramp pov.
MA> I'm not a regular Eshell user, so I don't know how useful it will be.
It looks like it could be useful to me, only needing a subtle addition to the
syntax...
--
John Wiegley GPG fingerprint = 4710 CF98 AF9B 327B B80F
http://newartisans.com 60E1 46C4 BD1A 7AC1 4BA2
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC] Explicity-remote commands in Eshell
2023-03-06 8:09 ` Michael Albinus
2023-03-06 16:10 ` John Wiegley
@ 2023-03-06 22:07 ` Jim Porter
1 sibling, 0 replies; 4+ messages in thread
From: Jim Porter @ 2023-03-06 22:07 UTC (permalink / raw)
To: Michael Albinus; +Cc: emacs-devel
On 3/6/2023 12:09 AM, Michael Albinus wrote:
> One remark: Why don't you allow remoteness everywhere? Sth like
>
> --8<---------------cut here---------------start------------->8---
> /ssh:user@somewhere:remote-command | /ssh:another-user@elsewhere:another-remote-command
> --8<---------------cut here---------------end--------------->8---
>
> This even with multiple pipes in a row. Mixed with local commands. And
> using just the shorter version "command", which means a local or remote
> command according to default-directory.
This is possible too: in fact, explicitly-remote commands should be
usable absolutely anywhere a regular command is: in pipelines,
subshells, conditionals, etc. (My example was just to show how you might
mix an explicitly-remote command with a regular command.)
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2023-03-06 22:07 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-06 2:35 [RFC] Explicity-remote commands in Eshell Jim Porter
2023-03-06 8:09 ` Michael Albinus
2023-03-06 16:10 ` John Wiegley
2023-03-06 22:07 ` Jim Porter
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).