Function: eshell-gather-process-output
eshell-gather-process-output is a byte-compiled function defined in
esh-proc.el.gz.
Signature
(eshell-gather-process-output COMMAND ARGS)
Documentation
Gather the output from COMMAND + ARGS.
Source Code
;; Defined in /usr/src/emacs/lisp/eshell/esh-proc.el.gz
(defun eshell-gather-process-output (command args)
"Gather the output from COMMAND + ARGS."
(require 'esh-var)
(declare-function eshell-environment-variables "esh-var" ())
(unless (and (file-executable-p command)
(file-regular-p (file-truename command)))
(error "%s: not an executable file" command))
(let* ((real-path (getenv "PATH"))
(tramp-remote-path (bound-and-true-p tramp-remote-path))
(delete-exited-processes
(if eshell-current-subjob-p
eshell-delete-exited-processes
delete-exited-processes))
(process-environment (eshell-environment-variables))
(coding-system-for-read coding-system-for-read)
(coding-system-for-write coding-system-for-write)
proc stderr-proc decoding encoding changed)
;; HACK: We want to supply our subprocess with the all the
;; environment variables we've set in Eshell. However, supplying
;; a remote PATH this way can break Tramp, which needs the *local*
;; PATH for calling "ssh", etc. Instead, set the local path in
;; our `process-environment' and pass the remote PATH via
;; `tramp-remote-path'. (If we handle this some better way in the
;; future, remember to remove `tramp-remote-path' above, too.)
(when (file-remote-p default-directory)
(push (concat "PATH=" real-path) process-environment)
(setq tramp-remote-path (eshell-get-path t)))
;; MS-Windows needs special setting of encoding/decoding, because
;; (a) non-ASCII text in command-line arguments needs to be
;; encoded in the system's codepage; and (b) because many Windows
;; programs will always interpret any non-ASCII input as encoded
;; in the system codepage.
(when (eq system-type 'windows-nt)
(or coding-system-for-read ; Honor manual decoding settings
(setq coding-system-for-read
(coding-system-change-eol-conversion locale-coding-system
'dos)))
(or coding-system-for-write ; Honor manual encoding settings
(setq coding-system-for-write
(coding-system-change-eol-conversion locale-coding-system
'unix))))
(cond
(eshell-supports-asynchronous-processes
(unless (or ;; FIXME: It's not currently possible to use a
;; stderr process for remote files.
(file-remote-p default-directory)
(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-interactive-process-filter
#'eshell-insertion-filter)
:sentinel #'eshell-sentinel))
(eshell-record-process-properties stderr-proc eshell-error-handle))
(eshell-protect-handles eshell-current-handles)
(setq proc
(let ((command (file-local-name (expand-file-name command)))
(conn-type (pcase (bound-and-true-p eshell-in-pipeline-p)
('first '(nil . pipe))
('last '(pipe . nil))
('t 'pipe)
('nil nil))))
(make-process
:name (file-name-nondirectory command)
:buffer (current-buffer)
:command (cons command args)
:filter (if (eshell-interactive-output-p)
#'eshell-interactive-process-filter
#'eshell-insertion-filter)
:sentinel #'eshell-sentinel
:connection-type conn-type
:stderr stderr-proc
:file-handler t)))
(eshell-debug-command 'process
"started external process `%s'\n\n%s" proc
(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
;; until stderr is totally finished (see `eshell-sentinel').
(let ((stderr-live (list t)))
(process-put proc :eshell-stderr-live stderr-live)
(process-put stderr-proc :eshell-stderr-live stderr-live)))
(run-hook-with-args 'eshell-exec-hook proc)
(when (fboundp 'process-coding-system)
(let ((coding-systems (process-coding-system proc)))
(setq decoding (car coding-systems)
encoding (cdr coding-systems)))
;; If `make-process' decided to use some coding system for
;; decoding data sent from the process and the coding system
;; doesn't specify EOL conversion, we had better convert CRLF
;; to LF.
(if (vectorp (coding-system-eol-type decoding))
(setq decoding (coding-system-change-eol-conversion decoding 'dos)
changed t))
;; Even if `make-process' left the coding system for encoding
;; data sent to the process undecided, we had better use the
;; same one as what we use for decoding. But, we should
;; suppress EOL conversion.
(if (and decoding (not encoding))
(setq encoding (coding-system-change-eol-conversion decoding 'unix)
changed t))
(if changed
(set-process-coding-system proc decoding encoding))))
(t
;; No async subprocesses...
(let ((oldbuf (current-buffer))
(interact-p (eshell-interactive-output-p))
lbeg lend line proc-buf exit-status)
(and (not (markerp eshell-last-sync-output-start))
(setq eshell-last-sync-output-start (point-marker)))
(setq proc-buf
(set-buffer (get-buffer-create eshell-scratch-buffer)))
(erase-buffer)
(set-buffer oldbuf)
(run-hook-with-args 'eshell-exec-hook command)
;; XXX: This doesn't support sending stdout and stderr to
;; separate places.
(setq exit-status
(apply #'call-process-region
(append (list eshell-last-sync-output-start (point)
command t
eshell-scratch-buffer nil)
args)))
;; When in a pipeline, record the place where the output of
;; this process will begin.
(and (bound-and-true-p eshell-in-pipeline-p)
(set-marker eshell-last-sync-output-start (point)))
;; Simulate the effect of the process filter.
(when (numberp exit-status)
(set-buffer proc-buf)
(goto-char (point-min))
(setq lbeg (point))
(while (eq 0 (forward-line 1))
(setq lend (point)
line (buffer-substring-no-properties lbeg lend))
(set-buffer oldbuf)
(if interact-p
(eshell-interactive-process-filter nil line)
(eshell-output-object line))
(setq lbeg lend)
(set-buffer proc-buf))
(set-buffer oldbuf))
;; Simulate the effect of `eshell-sentinel'.
(eshell-set-exit-info
(if (numberp exit-status) exit-status -1)
(and (numberp exit-status) (= exit-status 0)))
(run-hook-with-args 'eshell-kill-hook command exit-status)
(or (bound-and-true-p eshell-in-pipeline-p)
(setq eshell-last-sync-output-start nil))
(if (not (numberp exit-status))
(error "%s: external command failed: %s" command exit-status))
(setq proc t))))
proc))