From: Michael Albinus <michael.albinus@gmx.de>
To: Jim Porter <jporterbugs@gmail.com>
Cc: 47861@debbugs.gnu.org
Subject: bug#47861: Starting `jsonrpc-process-connection' over Tramp fails if the process writes to stderr
Date: Sat, 15 May 2021 19:32:59 +0200 [thread overview]
Message-ID: <87mtsvgawk.fsf@gmx.de> (raw)
In-Reply-To: <87y2cyaiwh.fsf@gmx.de> (Michael Albinus's message of "Sat, 01 May 2021 11:43:42 +0200")
[-- Attachment #1: Type: text/plain, Size: 466 bytes --]
Michael Albinus <michael.albinus@gmx.de> writes:
Hi Jim,
> However, handling stderr buffers in Tramp's make-process is still a
> mess. So I've started to reimplement this, using a named pipe on the
> remote machine. make-pipe-process, the natural choice, does not work for
> remote processes.
I've finished a first shot on this, see the appended patch. Would you
mind to test this in your environment, for example with eglot?
Thanks, and best regards, Michael.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 6099 bytes --]
diff --git a/lisp/tramp-sh.el b/lisp/tramp-sh.el
index 60090d31..22d31f82 100644
--- a/lisp/tramp-sh.el
+++ b/lisp/tramp-sh.el
@@ -2723,13 +2723,12 @@ the result will be a local, non-Tramp, file name."
;; We use BUFFER also as connection buffer during setup. Because of
;; this, its original contents must be saved, and restored once
;; connection has been setup.
-;; The complete STDERR buffer is available only when the process has
-;; terminated.
(defun tramp-sh-handle-make-process (&rest args)
"Like `make-process' for Tramp files.
-STDERR can also be a file name. If method parameter `tramp-direct-async'
-and connection property \"direct-async-process\" are non-nil, an
-alternative implementation will be used."
+STDERR can also be a remote file name. If method parameter
+`tramp-direct-async' and connection property
+\"direct-async-process\" are non-nil, an alternative
+implementation will be used."
(if (tramp-direct-async-process-p args)
(apply #'tramp-handle-make-process args)
(when args
@@ -2763,7 +2762,7 @@ alternative implementation will be used."
(signal 'wrong-type-argument (list #'functionp sentinel)))
(unless (or (null stderr) (bufferp stderr) (stringp stderr))
(signal 'wrong-type-argument (list #'bufferp stderr)))
- (when (and (stringp stderr) (tramp-tramp-file-p stderr)
+ (when (and (stringp stderr)
(not (tramp-equal-remote default-directory stderr)))
(signal 'file-error (list "Wrong stderr" stderr)))
@@ -2775,9 +2774,9 @@ alternative implementation will be used."
;; STDERR can also be a file name.
(tmpstderr
(and stderr
- (if (and (stringp stderr) (tramp-tramp-file-p stderr))
- (tramp-unquote-file-local-name stderr)
- (tramp-make-tramp-temp-file v))))
+ (tramp-unquote-file-local-name
+ (if (stringp stderr)
+ stderr (tramp-make-tramp-temp-name v)))))
(remote-tmpstderr
(and tmpstderr (tramp-make-tramp-file-name v tmpstderr)))
(program (car command))
@@ -2786,7 +2785,8 @@ alternative implementation will be used."
;; "-c", it might be that the arguments exceed the
;; command line length. Therefore, we modify the
;; command.
- (heredoc (and (stringp program)
+ (heredoc (and (not (bufferp stderr))
+ (stringp program)
(string-match-p "sh$" program)
(= (length args) 2)
(string-equal "-c" (car args))
@@ -2850,6 +2850,23 @@ alternative implementation will be used."
tramp-current-connection
p)
+ ;; Handle error buffer.
+ (when (bufferp stderr)
+ (with-current-buffer stderr
+ (setq buffer-read-only nil))
+ ;; Create named pipe.
+ (tramp-send-command v (format "mknod %s p" tmpstderr))
+ ;; Create stderr process.
+ (make-process
+ :name (buffer-name stderr)
+ :buffer stderr
+ :command `("cat" ,tmpstderr)
+ :coding coding
+ :noquery t
+ :filter nil
+ :sentinel #'ignore
+ :file-handler t))
+
(while (get-process name1)
;; NAME must be unique as process name.
(setq i (1+ i)
@@ -2912,38 +2929,16 @@ alternative implementation will be used."
(ignore-errors
(set-process-query-on-exit-flag p (null noquery))
(set-marker (process-mark p) (point)))
- ;; We must flush them here already; otherwise
- ;; `rename-file', `delete-file' or
- ;; `insert-file-contents' will fail.
- (tramp-flush-connection-property v "process-name")
- (tramp-flush-connection-property v "process-buffer")
- ;; Copy tmpstderr file.
- (when (and (stringp stderr)
- (not (tramp-tramp-file-p stderr)))
- (add-function
- :after (process-sentinel p)
- (lambda (_proc _msg)
- (rename-file remote-tmpstderr stderr))))
- ;; Provide error buffer. This shows only
- ;; initial error messages; messages arriving
- ;; later on will be inserted when the process
- ;; is deleted. The temporary file will exist
- ;; until the process is deleted.
+ ;; Kill stderr process and named pipe.
(when (bufferp stderr)
- (with-current-buffer stderr
- ;; There's a mysterious error, see
- ;; <https://github.com/joaotavora/eglot/issues/662>.
- (ignore-errors
- (insert-file-contents-literally remote-tmpstderr)))
- ;; Delete tmpstderr file.
(add-function
:after (process-sentinel p)
(lambda (_proc _msg)
- (when (file-exists-p remote-tmpstderr)
- (with-current-buffer stderr
- (ignore-errors
- (insert-file-contents-literally
- remote-tmpstderr nil nil nil 'replace)))
+ (ignore-errors
+ (while (accept-process-output
+ (get-buffer-process stderr) 0 nil t))
+ (delete-process (get-buffer-process stderr)))
+ (ignore-errors
(delete-file remote-tmpstderr)))))
;; Return process.
p)))
@@ -4834,10 +4829,12 @@ connection if a previous connection has died for some reason."
(with-tramp-progress-reporter
vec 3
(if (zerop (length (tramp-file-name-user vec)))
- (format "Opening connection for %s using %s"
+ (format "Opening connection %s for %s using %s"
+ process-name
(tramp-file-name-host vec)
(tramp-file-name-method vec))
- (format "Opening connection for %s@%s using %s"
+ (format "Opening connection %s for %s@%s using %s"
+ process-name
(tramp-file-name-user vec)
(tramp-file-name-host vec)
(tramp-file-name-method vec)))
@@ -5937,8 +5934,6 @@ function cell is returned to be applied on a buffer."
;; session could be reused after a connection loss. Use dtach, or
;; screen, or tmux, or mosh.
;;
-;; * Implement `:stderr' of `make-process' as pipe process.
-
;; * One interesting solution (with other applications as well) would
;; be to stipulate, as a directory or connection-local variable, an
;; additional rc file on the remote machine that is sourced every
next prev parent reply other threads:[~2021-05-15 17:32 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-04-18 3:53 bug#47861: Starting `jsonrpc-process-connection' over Tramp fails if the process writes to stderr Jim Porter
2021-05-01 9:43 ` Michael Albinus
2021-05-15 17:32 ` Michael Albinus [this message]
2021-05-22 4:53 ` Jim Porter
2021-05-22 7:27 ` Michael Albinus
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
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87mtsvgawk.fsf@gmx.de \
--to=michael.albinus@gmx.de \
--cc=47861@debbugs.gnu.org \
--cc=jporterbugs@gmail.com \
/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 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).