Refactor Tramp async process code

* lisp/net/tramp-adb.el (tramp-adb-handle-make-process):
* lisp/net/tramp-sh.el (tramp-sh-handle-make-process):
Update stderr buffer when process has finished.  Do not call
`auto-revert'.

* test/lisp/net/tramp-tests.el (tramp-test31-interrupt-process):
Tag it :unstable.  Change `accept-process-output' arguments.
(tramp--test-async-shell-command): New defun.
(tramp--test-shell-command-to-string-asynchronously): Use it.
(tramp-test32-shell-command): Refactor code.
This commit is contained in:
Michael Albinus 2020-01-14 11:46:42 +01:00
parent 88efc736f5
commit 06caa3b7e5
3 changed files with 82 additions and 109 deletions

View file

@ -935,6 +935,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
;; 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-adb-handle-make-process (&rest args)
"Like `make-process' for Tramp files."
(when args
@ -983,6 +985,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(if (and (stringp stderr) (tramp-tramp-file-p stderr))
(tramp-unquote-file-local-name stderr)
(tramp-make-tramp-temp-file v))))
(remote-tmpstderr
(and tmpstderr (tramp-make-tramp-file-name v tmpstderr)))
(program (car command))
(args (cdr command))
(command
@ -1049,9 +1053,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(add-function
:after (process-sentinel p)
(lambda (_proc _msg)
(rename-file
(tramp-make-tramp-file-name v tmpstderr)
stderr))))
(rename-file remote-tmpstderr stderr))))
;; Read initial output. Remove the first line,
;; which is the command echo.
(while
@ -1062,20 +1064,19 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(delete-region (point-min) (point))
;; Provide error buffer. This shows only
;; initial error messages; messages arriving
;; later on shall be inserted by
;; `auto-revert'. The temporary file will
;; exist until the process is deleted.
;; later on will be inserted when the process
;; is deleted. The temporary file will exist
;; until the process is deleted.
(when (bufferp stderr)
(with-current-buffer stderr
(insert-file-contents
(tramp-make-tramp-file-name v tmpstderr) 'visit)
(auto-revert-mode))
(insert-file-contents remote-tmpstderr 'visit))
;; Delete tmpstderr file.
(add-function
:after (process-sentinel p)
(lambda (_proc _msg)
(delete-file
(tramp-make-tramp-file-name v tmpstderr)))))
(with-current-buffer stderr
(insert-file-contents remote-tmpstderr 'visit))
(delete-file remote-tmpstderr))))
;; Return process.
p))))

View file

@ -2806,6 +2806,8 @@ 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."
@ -2855,6 +2857,8 @@ STDERR can also be a file name."
(if (and (stringp stderr) (tramp-tramp-file-p stderr))
(tramp-unquote-file-local-name stderr)
(tramp-make-tramp-temp-file v))))
(remote-tmpstderr
(and tmpstderr (tramp-make-tramp-file-name v tmpstderr)))
(program (car command))
(args (cdr command))
;; When PROGRAM matches "*sh", and the first arg is
@ -2994,24 +2998,22 @@ STDERR can also be a file name."
(add-function
:after (process-sentinel p)
(lambda (_proc _msg)
(rename-file
(tramp-make-tramp-file-name v tmpstderr) stderr))))
(rename-file remote-tmpstderr stderr))))
;; Provide error buffer. This shows only
;; initial error messages; messages arriving
;; later on shall be inserted by `auto-revert'.
;; The temporary file will exist until the
;; process is deleted.
;; later on will be inserted when the process is
;; deleted. The temporary file will exist until
;; the process is deleted.
(when (bufferp stderr)
(with-current-buffer stderr
(insert-file-contents
(tramp-make-tramp-file-name v tmpstderr) 'visit)
(auto-revert-mode))
(insert-file-contents remote-tmpstderr 'visit))
;; Delete tmpstderr file.
(add-function
:after (process-sentinel p)
(lambda (_proc _msg)
(delete-file
(tramp-make-tramp-file-name v tmpstderr)))))
(with-current-buffer stderr
(insert-file-contents remote-tmpstderr 'visit))
(delete-file remote-tmpstderr))))
;; Return process.
p)))

View file

@ -4403,7 +4403,9 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(ert-deftest tramp-test31-interrupt-process ()
"Check `interrupt-process'."
:tags '(:expensive-test)
;; The test fails from time to time, w/o a reproducible pattern. So
;; we mark it as unstable.
:tags '(:expensive-test :unstable)
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
;; Since Emacs 26.1.
@ -4424,7 +4426,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(should (interrupt-process proc))
;; Let the process accept the interrupt.
(with-timeout (10 (tramp--test-timeout-handler))
(while (accept-process-output proc nil nil 0)))
(while (process-live-p proc)
(while (accept-process-output proc 0 nil t))))
(should-not (process-live-p proc))
;; An interrupted process cannot be interrupted, again.
(should-error
@ -4434,14 +4437,27 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
;; Cleanup.
(ignore-errors (delete-process proc)))))
(defun tramp--test-async-shell-command
(command output-buffer &optional error-buffer input)
"Like `async-shell-command', reading the output.
INPUT, if non-nil, is a string sent to the process."
(let ((proc (async-shell-command command output-buffer error-buffer)))
(when (stringp input)
(process-send-string proc input))
(with-timeout
((if (getenv "EMACS_EMBA_CI") 30 10) (tramp--test-timeout-handler))
(while (accept-process-output proc nil nil t))
(should-not (process-live-p proc)))
;; `ls' could produce colorized output.
(with-current-buffer output-buffer
(goto-char (point-min))
(while (re-search-forward tramp-display-escape-sequence-regexp nil t)
(replace-match "" nil nil)))))
(defun tramp--test-shell-command-to-string-asynchronously (command)
"Like `shell-command-to-string', but for asynchronous processes."
(with-temp-buffer
(async-shell-command command (current-buffer))
(with-timeout
((if (getenv "EMACS_EMBA_CI") 30 10) (tramp--test-timeout-handler))
(while (accept-process-output
(get-buffer-process (current-buffer)) nil nil t)))
(tramp--test-async-shell-command command (current-buffer))
(buffer-substring-no-properties (point-min) (point-max))))
(ert-deftest tramp-test32-shell-command ()
@ -4460,101 +4476,55 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(inhibit-message t)
kill-buffer-query-functions)
;; Test ordinary `shell-command'.
(unwind-protect
(with-temp-buffer
(write-region "foo" nil tmp-name)
(should (file-exists-p tmp-name))
(shell-command
(format "ls %s" (file-name-nondirectory tmp-name))
(current-buffer))
;; `ls' could produce colorized output.
(goto-char (point-min))
(while
(re-search-forward tramp-display-escape-sequence-regexp nil t)
(replace-match "" nil nil))
(should
(string-equal
(format "%s\n" (file-name-nondirectory tmp-name))
(buffer-string))))
(dolist (this-shell-command
'(;; Synchronously.
shell-command
;; Asynchronously.
tramp--test-async-shell-command))
;; Cleanup.
(ignore-errors (delete-file tmp-name)))
;; Test `shell-command' with error buffer.
(let ((stderr (generate-new-buffer "*stderr*")))
;; Test ordinary `{async-}shell-command'.
(unwind-protect
(with-temp-buffer
(shell-command "cat /" (current-buffer) stderr)
(should (= (point-min) (point-max)))
(with-current-buffer stderr
(should
(string-match "cat:.* Is a directory" (buffer-string)))))
(write-region "foo" nil tmp-name)
(should (file-exists-p tmp-name))
(funcall
this-shell-command
(format "ls %s" (file-name-nondirectory tmp-name))
(current-buffer))
(should
(string-equal
(format "%s\n" (file-name-nondirectory tmp-name))
(buffer-string))))
;; Cleanup.
(ignore-errors (kill-buffer stderr))))
(ignore-errors (delete-file tmp-name)))
;; Test ordinary `async-shell-command'.
(unwind-protect
(with-temp-buffer
(write-region "foo" nil tmp-name)
(should (file-exists-p tmp-name))
(async-shell-command
(format "ls %s" (file-name-nondirectory tmp-name))
(current-buffer))
;; Read output.
(with-timeout (10 (tramp--test-timeout-handler))
(while (accept-process-output
(get-buffer-process (current-buffer)) nil nil t)))
;; `ls' could produce colorized output.
(goto-char (point-min))
(while
(re-search-forward tramp-display-escape-sequence-regexp nil t)
(replace-match "" nil nil))
(should
(string-equal
(format "%s\n" (file-name-nondirectory tmp-name))
(buffer-string))))
;; Cleanup.
(ignore-errors (delete-file tmp-name)))
;; Test `async-shell-command' with error buffer.
(let ((stderr (generate-new-buffer "*stderr*")) proc)
(unwind-protect
(with-temp-buffer
(async-shell-command "cat /; sleep 1" (current-buffer) stderr)
(setq proc (get-buffer-process (current-buffer)))
;; Read stderr.
(when (processp proc)
(with-timeout (10 (tramp--test-timeout-handler))
(while (accept-process-output proc nil nil t)))
(delete-process proc))
(with-current-buffer stderr
(should
(string-match "cat:.* Is a directory" (buffer-string)))))
;; Test `{async-}shell-command' with error buffer.
(let ((stderr (generate-new-buffer "*stderr*")))
(unwind-protect
(with-temp-buffer
(funcall
this-shell-command "cat /; sleep 1" (current-buffer) stderr)
;; Check stderr.
(when (eq this-shell-command #'tramp--test-async-shell-command)
(ignore-errors
(delete-process (get-buffer-process (current-buffer)))))
(should (zerop (buffer-size)))
(with-current-buffer stderr
(should
(string-match "cat:.* Is a directory" (buffer-string)))))
;; Cleanup.
(ignore-errors (kill-buffer stderr))))
(ignore-errors (kill-buffer stderr)))))
;; Test sending string to `async-shell-command'.
(unwind-protect
(with-temp-buffer
(write-region "foo" nil tmp-name)
(should (file-exists-p tmp-name))
(async-shell-command "read line; ls $line" (current-buffer))
(process-send-string
(get-buffer-process (current-buffer))
(tramp--test-async-shell-command
"read line; ls $line" (current-buffer) nil
(format "%s\n" (file-name-nondirectory tmp-name)))
;; Read output.
(with-timeout (10 (tramp--test-timeout-handler))
(while (accept-process-output
(get-buffer-process (current-buffer)) nil nil t)))
;; `ls' could produce colorized output.
(goto-char (point-min))
(while
(re-search-forward tramp-display-escape-sequence-regexp nil t)
(replace-match "" nil nil))
(should
(string-equal
;; tramp-adb.el echoes, so we must add the string.
@ -6239,7 +6209,7 @@ If INTERACTIVE is non-nil, the tests are run interactively."
;; do not work properly for `nextcloud'.
;; * Fix `tramp-test29-start-file-process' and
;; `tramp-test30-make-process' on MS Windows (`process-send-eof'?).
;; * Implement `tramp-test31-interrupt-process' for `adb'.
;; * Implement `tramp-test31-interrupt-process' for `adb'. Fix `:unstable'.
;; * Fix Bug#16928 in `tramp-test43-asynchronous-requests'. A remote
;; file name operation cannot run in the timer. Remove `:unstable' tag?