Subject: Re: bug#71049: async-shell-command ends with "Process *Async Shell Command* finished" when remote "direct-async-process"

From: Michael Albinus <[email-masked]>
Date: Sat, 25 May 2024 15:03:54 +0200

Dmitry Gutov <[email-masked]> writes:

> When a Tramp connection is configured as "direct-async-process",
>
> 1. If the buffer *Async Shell Command* does not exist, invoking M-& in
> a remote buffer from that connection makes it end with
>
>   Process *Async Shell Command* finished

tramp-handle-make-process must suppress the default sentinel
internal-default-process-sentinel. The counter-part,
tramp-sh-handle-make-process, does it already, that's why you don't see
this message when direct async processes aren't enabled.

> 2. If the buffer such named already exists when command is invoked,
> then this doesn't happen (the output seems correct). But *Messages*
> says
>
>   -l: finished.
>
> ...which is a big puzzling as well.

This is due to shell-command-sentinel. It uses (process-command process)
to determine the finished command. In the local case, this returns
somethiong like ("/usr/bin/sh" "-c" "ls"). In the remote case, it looks
different:

--8<---------------cut here---------------start------------->8---
("ssh" "-q" "-o" "ControlMaster=auto" "-o" "ControlPath=/home/albinus/.cache/emacs/tramp.%C" "-o" "ControlPersist=no" "-e" "none" #("gandalf" 0 7 (tramp-default t)) "cd" "/home/albinus/" "&&" "(" "env" "INSIDE_EMACS\\=30.0.50\\,tramp\\:2.7.1-pre" "PATH\\=/home/albinus\\:/usr/share/Modules/bin\\:/usr/local/bin\\:/usr/bin\\:/usr/local/sbin\\:/usr/sbin\\:/var/lib/snapd/snap/bin\\:/home/albinus/.local/bin\\:/bin\\:/sbin" "ENV\\=\\'\\'" "TMOUT\\=0" "LC_CTYPE\\=\\'\\'" "CDPATH\\=" "HISTORY\\=" "MAIL\\=" "MAILCHECK\\=" "MAILPATH\\=" "PAGER\\=cat" "autocorrect\\=" "correct\\=" "/bin/sh -c ls" ")")
--8<---------------cut here---------------end--------------->8---

So the sentinel must inspect the process property remote-command first.

I've tried to fix both problems. Could you, pls, check the appended
patch?

Best regards, Michael.

diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 18116229337..9385b023392 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -5025,11 +5025,13 @@ tramp-handle-make-process
 	       ?h (or host "") ?u (or user "") ?p (or port "")
 	       ?c (format-spec (or options "") (format-spec-make ?t tmpfile))
 	       ?d (or device "") ?a (or pta "") ?l ""))))
+	   ;; Suppress `internal-default-process-sentinel', which is
+	   ;; set when :sentinel is nil.  (Bug#71049)
 	   p (make-process
 	      :name name :buffer buffer
 	      :command (append `(,login-program) login-args command)
 	      :coding coding :noquery noquery :connection-type connection-type
-	      :sentinel sentinel :stderr stderr))
+	      :sentinel (or sentinel #'ignore) :stderr stderr))
 	  ;; Set filter.  Prior Emacs 29.1, it doesn't work reliably
 	  ;; to provide it as `make-process' argument when filter is
 	  ;; t.  See Bug#51177.
diff --git a/lisp/simple.el b/lisp/simple.el
index bcd26da13ed..714accab1af 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -4863,11 +4863,14 @@ display-message-or-buffer
 ;; We have a sentinel to prevent insertion of a termination message
 ;; in the buffer itself, and to set the point in the buffer when
 ;; `shell-command-dont-erase-buffer' is non-nil.
+;; For remote shells, `process-command' does not serve the proper shell
+;; command.  We use process property `remote-command' instead.  (Bug#71049)
 (defun shell-command-sentinel (process signal)
   (when (memq (process-status process) '(exit signal))
     (shell-command-set-point-after-cmd (process-buffer process))
     (message "%s: %s."
-             (car (cdr (cdr (process-command process))))
+             (car (cdr (cdr (or (process-get process 'remote-command)
+                                (process-command process)))))
              (substring signal 0 -1))))

 (defun shell-command-on-region (start end command