1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-04 08:47:11 +00:00

Let external Eshell processes send stdout and stderr to different places

* lisp/eshell/esh-proc.el (eshell-put-process-properties): Pass INDEX.
(eshell-gather-process-output): Create a pipe process for stderr when
stderr goes somewhere different than stdout.
(eshell-insertion-filter, eshell-sentinel): Consult
':eshell-handle-index' property.

* test/lisp/eshell/esh-proc-tests.el
(esh-proc-test/output/stdout-to-buffer)
(esh-proc-test/output/stderr-to-buffer)
(esh-proc-test/exit-status/with-stderr-pipe): New tests (bug#21605).
This commit is contained in:
Jim Porter 2022-08-28 11:53:07 -07:00
parent a87c7aff55
commit f07505d1ec
2 changed files with 62 additions and 9 deletions

View File

@ -247,11 +247,15 @@ The prompt will be set to PROMPT."
(setq eshell-process-list
(delq entry eshell-process-list)))
(defun eshell-record-process-properties (process)
(defun eshell-record-process-properties (process &optional index)
"Record Eshell bookkeeping properties for PROCESS.
`eshell-insertion-filter' and `eshell-sentinel' will use these to
do their jobs."
do their jobs.
INDEX is the index of the output handle to use for writing; if
nil, write to `eshell-output-handle'."
(process-put process :eshell-handles eshell-current-handles)
(process-put process :eshell-handle-index (or index eshell-output-handle))
(process-put process :eshell-pending nil)
(process-put process :eshell-busy nil))
@ -273,9 +277,21 @@ Used only on systems which do not support async subprocesses.")
eshell-delete-exited-processes
delete-exited-processes))
(process-environment (eshell-environment-variables))
proc decoding encoding changed)
proc stderr-proc decoding encoding changed)
(cond
((fboundp 'make-process)
(unless (equal (car (aref eshell-current-handles eshell-output-handle))
(car (aref eshell-current-handles eshell-error-handle)))
(eshell-protect-handles eshell-current-handles)
(setq stderr-proc
(make-pipe-process
:name (concat (file-name-nondirectory command) "-stderr")
:buffer (current-buffer)
:filter (if (eshell-interactive-output-p eshell-error-handle)
#'eshell-output-filter
#'eshell-insertion-filter)
:sentinel #'eshell-sentinel))
(eshell-record-process-properties stderr-proc eshell-error-handle))
(setq proc
(let ((command (file-local-name (expand-file-name command)))
(conn-type (pcase (bound-and-true-p eshell-in-pipeline-p)
@ -292,6 +308,7 @@ Used only on systems which do not support async subprocesses.")
#'eshell-insertion-filter)
:sentinel #'eshell-sentinel
:connection-type conn-type
:stderr stderr-proc
:file-handler t)))
(eshell-record-process-object proc)
(eshell-record-process-properties proc)
@ -381,12 +398,13 @@ output."
(unless (process-get proc :eshell-busy) ; Already being handled?
(while (process-get proc :eshell-pending)
(let ((handles (process-get proc :eshell-handles))
(index (process-get proc :eshell-handle-index))
(data (process-get proc :eshell-pending)))
(process-put proc :eshell-pending nil)
(process-put proc :eshell-busy t)
(unwind-protect
(condition-case nil
(eshell-output-object data nil handles)
(eshell-output-object data index handles)
;; FIXME: We want to send SIGPIPE to the process
;; here. However, remote processes don't currently
;; support that, and not all systems have SIGPIPE in
@ -418,9 +436,13 @@ PROC is the process that's exiting. STRING is the exit message."
(not (string-match "^\\(finished\\|exited\\)"
string)))
(funcall (process-filter proc) proc string))
(let ((handles (process-get proc :eshell-handles))
(data (process-get proc :eshell-pending))
(status (process-exit-status proc)))
(let* ((handles (process-get proc :eshell-handles))
(index (process-get proc :eshell-handle-index))
(data (process-get proc :eshell-pending))
;; Only get the status for the primary subprocess,
;; not the pipe process (if any).
(status (when (= index eshell-output-handle)
(process-exit-status proc))))
(process-put proc :eshell-pending nil)
;; If we're in the middle of handling output from this
;; process then schedule the EOF for later.
@ -431,9 +453,10 @@ PROC is the process that's exiting. STRING is the exit message."
(when data
(ignore-error 'eshell-pipe-broken
(eshell-output-object
data nil handles)))
data index handles)))
(eshell-close-handles
status (list 'quote (= status 0))
status
(when status (list 'quote (= status 0)))
handles)))))
(funcall finish-io))))
(when-let ((entry (assq proc eshell-process-list)))

View File

@ -55,6 +55,26 @@
(eshell-match-command-output esh-proc-test--output-cmd
"stdout\nstderr\n")))
(ert-deftest esh-proc-test/output/stdout-to-buffer ()
"Check that redirecting only stdout works."
(skip-unless (executable-find "sh"))
(eshell-with-temp-buffer bufname "old"
(with-temp-eshell
(eshell-match-command-output
(format "%s > #<%s>" esh-proc-test--output-cmd bufname)
"stderr\n"))
(should (equal (buffer-string) "stdout\n"))))
(ert-deftest esh-proc-test/output/stderr-to-buffer ()
"Check that redirecting only stderr works."
(skip-unless (executable-find "sh"))
(eshell-with-temp-buffer bufname "old"
(with-temp-eshell
(eshell-match-command-output
(format "%s 2> #<%s>" esh-proc-test--output-cmd bufname)
"stdout\n"))
(should (equal (buffer-string) "stderr\n"))))
(ert-deftest esh-proc-test/output/stdout-and-stderr-to-buffer ()
"Check that redirecting stdout and stderr works."
(skip-unless (executable-find "sh"))
@ -86,6 +106,16 @@
(should (= eshell-last-command-status 1))
(should (eq eshell-last-command-result nil))))
(ert-deftest esh-proc-test/exit-status/with-stderr-pipe ()
"Check that failed execution is properly recorded even with a pipe process."
(skip-unless (executable-find "sh"))
(eshell-with-temp-buffer bufname "old"
(with-temp-eshell
(eshell-insert-command (format "sh -c 'exit 1' > #<%s>" bufname))
(eshell-wait-for-subprocess)
(should (= eshell-last-command-status 1))
(should (eq eshell-last-command-result nil)))))
;; Pipelines