From ada9b095695012776c483e671d90b3b9c5942447 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Fri, 19 Jul 2024 09:34:03 -0700 Subject: [PATCH] Don't set exit info in Eshell if the command is being piped elsewhere Previously, the exit info in Eshell was that of the last command that finished, rather than the last command in a pipeline. * lisp/eshell/esh-cmd.el (eshell-exec-lisp) (eshell-lisp-command): Check whether the command is being piped. * lisp/eshell/esh-proc.el (eshell-gather-process-output): Record whether the command is being piped... (eshell-sentinel): ... and do the right thing with that info. * test/lisp/eshell/esh-proc-tests.el (esh-proc-test/sigpipe-exits-process): Check the exit status to ensure we don't report the first process's SIGPIPE exit. (cherry picked from commit b7893e73878df83043e05dc8cb811971c0e99f03) --- lisp/eshell/esh-cmd.el | 30 +++++++++++++++++------------- lisp/eshell/esh-proc.el | 6 +++++- test/lisp/eshell/esh-proc-tests.el | 5 ++++- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index d21ac850c02..2b47962735a 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -1425,10 +1425,12 @@ case." ;; command status to some non-zero value to indicate an error; to ;; match GNU/Linux, we use 141, which the numeric value of ;; SIGPIPE on GNU/Linux (13) with the high bit (2^7) set. - (eshell-set-exit-info 141) + (when (memq eshell-in-pipeline-p '(nil last)) + (eshell-set-exit-info 141)) nil) (error - (eshell-set-exit-info 1) + (when (memq eshell-in-pipeline-p '(nil last)) + (eshell-set-exit-info 1)) (let ((msg (error-message-string err))) (if (and (not form-p) (string-match "^Wrong number of arguments" msg) @@ -1507,7 +1509,8 @@ a string naming a Lisp function." (unless eshell-allow-commands (signal 'eshell-commands-forbidden '(lisp))) (catch 'eshell-external ; deferred to an external command - (eshell-set-exit-info 0) + (when (memq eshell-in-pipeline-p '(nil last)) + (eshell-set-exit-info 0)) (setq eshell-last-arguments args) (let* ((eshell-ensure-newline-p t) (command-form-p (functionp object)) @@ -1543,16 +1546,17 @@ a string naming a Lisp function." (eshell-eval* #'eshell-print-maybe-n #'eshell-error-maybe-n object)))) - (eshell-set-exit-info - ;; If `eshell-lisp-form-nil-is-failure' is non-nil, Lisp forms - ;; that succeeded but have a nil result should have an exit - ;; status of 2. - (when (and eshell-lisp-form-nil-is-failure - (not command-form-p) - (= eshell-last-command-status 0) - (not result)) - 2) - result) + (when (memq eshell-in-pipeline-p '(nil last)) + (eshell-set-exit-info + ;; If `eshell-lisp-form-nil-is-failure' is non-nil, Lisp forms + ;; that succeeded but have a nil result should have an exit + ;; status of 2. + (when (and eshell-lisp-form-nil-is-failure + (not command-form-p) + (= eshell-last-command-status 0) + (not result)) + 2) + result)) (eshell-close-handles)))) (define-obsolete-function-alias 'eshell-lisp-command* #'eshell-lisp-command diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index 2735be882b6..dc7b497666b 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -394,6 +394,9 @@ Used only on systems which do not support async subprocesses.") (mapconcat #'shell-quote-argument (process-command proc) " ")) (eshell-record-process-object proc) (eshell-record-process-properties proc) + ;; Don't set exit info for processes being piped elsewhere. + (when (memq (bound-and-true-p eshell-in-pipeline-p) '(nil last)) + (process-put proc :eshell-set-exit-info t)) (when stderr-proc ;; Provide a shared flag between the primary and stderr ;; processes. This lets the primary process wait to clean up @@ -546,6 +549,7 @@ PROC is the process that's exiting. STRING is the exit message." (let* ((handles (process-get proc :eshell-handles)) (index (process-get proc :eshell-handle-index)) (primary (= index eshell-output-handle)) + (set-exit-info (process-get proc :eshell-set-exit-info)) (data (process-get proc :eshell-pending)) (stderr-live (process-get proc :eshell-stderr-live))) ;; Write the exit message for the last process in the @@ -576,7 +580,7 @@ PROC is the process that's exiting. STRING is the exit message." (ignore-error eshell-pipe-broken (eshell-output-object data index handles))) - (when primary + (when set-exit-info (let ((status (process-exit-status proc))) (eshell-set-exit-info status (= status 0)))) (eshell-close-handles handles) diff --git a/test/lisp/eshell/esh-proc-tests.el b/test/lisp/eshell/esh-proc-tests.el index d46004688f9..3121e751006 100644 --- a/test/lisp/eshell/esh-proc-tests.el +++ b/test/lisp/eshell/esh-proc-tests.el @@ -167,7 +167,10 @@ See bug#71778." "sh -c 'read NAME; echo ${NAME}'") "y\n") (eshell-wait-for-subprocess t) - (should (equal (process-list) starting-process-list))))) + (should (equal (process-list) starting-process-list)) + ;; Make sure the exit status is from the last command in the + ;; pipeline. + (should (= eshell-last-command-status 0))))) (ert-deftest esh-proc-test/pipeline-connection-type/no-pipeline () "Test that all streams are PTYs when a command is not in a pipeline." -- 2.39.2