mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-25 12:28:09 +01:00
emacs: Use make-process when available
make-process is a new function introduced in Emacs 25, which provides greater control over process creation. Crucially, it allows separately redirecting stderr directly to a buffer, which allows us to avoid needing to use the shell to redirect to a temporary file in order to correctly distinguish stdout and stderr. * notmuch-lib.el: Use make-process when it is available; fall back to the previous method when not.
This commit is contained in:
parent
69946c47c9
commit
fdf2b3007a
1 changed files with 44 additions and 22 deletions
|
@ -909,21 +909,42 @@ invoke `set-process-sentinel' directly on the returned process,
|
||||||
as that will interfere with the handling of stderr and the exit
|
as that will interfere with the handling of stderr and the exit
|
||||||
status."
|
status."
|
||||||
|
|
||||||
;; There is no way (as of Emacs 24.3) to capture stdout and stderr
|
(let (err-file err-buffer proc
|
||||||
;; separately for asynchronous processes, or even to redirect stderr
|
|
||||||
;; to a file, so we use a trivial shell wrapper to send stderr to a
|
|
||||||
;; temporary file and clean things up in the sentinel.
|
|
||||||
(let* ((err-file (make-temp-file "nmerr"))
|
|
||||||
;; Use a pipe
|
|
||||||
(process-connection-type nil)
|
|
||||||
;; Find notmuch using Emacs' `exec-path'
|
;; Find notmuch using Emacs' `exec-path'
|
||||||
(command (or (executable-find notmuch-command)
|
(command (or (executable-find notmuch-command)
|
||||||
(error "command not found: %s" notmuch-command)))
|
(error "Command not found: %s" notmuch-command))))
|
||||||
(proc (apply #'start-process name buffer
|
(if (fboundp 'make-process)
|
||||||
|
(progn
|
||||||
|
(setq err-buffer (generate-new-buffer " *notmuch-stderr*"))
|
||||||
|
;; Emacs 25 and newer has `make-process', which allows
|
||||||
|
;; redirecting stderr independently from stdout to a
|
||||||
|
;; separate buffer. As this allows us to avoid using a
|
||||||
|
;; temporary file and shell invocation, use it when
|
||||||
|
;; available.
|
||||||
|
(setq proc (make-process
|
||||||
|
:name name
|
||||||
|
:buffer buffer
|
||||||
|
:command (cons command args)
|
||||||
|
:connection-type 'pipe
|
||||||
|
:stderr err-buffer))
|
||||||
|
(process-put proc 'err-buffer err-buffer)
|
||||||
|
;; Silence "Process NAME stderr finished" in stderr by adding a
|
||||||
|
;; no-op sentinel to the fake stderr process object
|
||||||
|
(set-process-sentinel (get-buffer-process err-buffer) #'ignore))
|
||||||
|
|
||||||
|
;; On Emacs versions before 25, there is no way to capture
|
||||||
|
;; stdout and stderr separately for asynchronous processes, or
|
||||||
|
;; even to redirect stderr to a file, so we use a trivial shell
|
||||||
|
;; wrapper to send stderr to a temporary file and clean things
|
||||||
|
;; up in the sentinel.
|
||||||
|
(setq err-file (make-temp-file "nmerr"))
|
||||||
|
(let ((process-connection-type nil)) ;; Use a pipe
|
||||||
|
(setq proc (apply #'start-process name buffer
|
||||||
"/bin/sh" "-c"
|
"/bin/sh" "-c"
|
||||||
"exec 2>\"$1\"; shift; exec \"$0\" \"$@\""
|
"exec 2>\"$1\"; shift; exec \"$0\" \"$@\""
|
||||||
command err-file args)))
|
command err-file args)))
|
||||||
(process-put proc 'err-file err-file)
|
(process-put proc 'err-file err-file))
|
||||||
|
|
||||||
(process-put proc 'sub-sentinel sentinel)
|
(process-put proc 'sub-sentinel sentinel)
|
||||||
(process-put proc 'real-command (cons notmuch-command args))
|
(process-put proc 'real-command (cons notmuch-command args))
|
||||||
(set-process-sentinel proc #'notmuch-start-notmuch-sentinel)
|
(set-process-sentinel proc #'notmuch-start-notmuch-sentinel)
|
||||||
|
@ -932,10 +953,10 @@ status."
|
||||||
(defun notmuch-start-notmuch-sentinel (proc event)
|
(defun notmuch-start-notmuch-sentinel (proc event)
|
||||||
"Process sentinel function used by `notmuch-start-notmuch'."
|
"Process sentinel function used by `notmuch-start-notmuch'."
|
||||||
(let* ((err-file (process-get proc 'err-file))
|
(let* ((err-file (process-get proc 'err-file))
|
||||||
(err (with-temp-buffer
|
(err-buffer (or (process-get proc 'err-buffer)
|
||||||
(insert-file-contents err-file)
|
(find-file-noselect err-file)))
|
||||||
(unless (eobp)
|
(err (when (not (zerop (buffer-size err-buffer)))
|
||||||
(buffer-string))))
|
(with-current-buffer err-buffer (buffer-string))))
|
||||||
(sub-sentinel (process-get proc 'sub-sentinel))
|
(sub-sentinel (process-get proc 'sub-sentinel))
|
||||||
(real-command (process-get proc 'real-command)))
|
(real-command (process-get proc 'real-command)))
|
||||||
(condition-case err
|
(condition-case err
|
||||||
|
@ -953,8 +974,8 @@ status."
|
||||||
;; If that didn't signal an error, then any error output was
|
;; If that didn't signal an error, then any error output was
|
||||||
;; really warning output. Show warnings, if any.
|
;; really warning output. Show warnings, if any.
|
||||||
(let ((warnings
|
(let ((warnings
|
||||||
(with-temp-buffer
|
(when err
|
||||||
(unless (= (second (insert-file-contents err-file)) 0)
|
(with-current-buffer err-buffer
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(end-of-line)
|
(end-of-line)
|
||||||
;; Show first line; stuff remaining lines in the
|
;; Show first line; stuff remaining lines in the
|
||||||
|
@ -969,7 +990,8 @@ status."
|
||||||
;; Emacs behaves strangely if an error escapes from a sentinel,
|
;; Emacs behaves strangely if an error escapes from a sentinel,
|
||||||
;; so turn errors into messages.
|
;; so turn errors into messages.
|
||||||
(message "%s" (error-message-string err))))
|
(message "%s" (error-message-string err))))
|
||||||
(ignore-errors (delete-file err-file))))
|
(when err-buffer (kill-buffer err-buffer))
|
||||||
|
(when err-file (ignore-errors (delete-file err-file)))))
|
||||||
|
|
||||||
;; This variable is used only buffer local, but it needs to be
|
;; This variable is used only buffer local, but it needs to be
|
||||||
;; declared globally first to avoid compiler warnings.
|
;; declared globally first to avoid compiler warnings.
|
||||||
|
|
Loading…
Reference in a new issue