@item
It does not use @code{tramp-remote-path} and
@code{tramp-remote-process-environment}.
-
-@item
-It does not set environment variable @env{INSIDE_EMACS}.
@end itemize
In order to gain even more performance, it is recommended to bind
@item
I get an error @samp{Remote file error: Forbidden reentrant call of Tramp}
+@vindex remote-file-error
+@vindex debug-ignored-errors
Timers, process filters and sentinels, and other event based functions
can run at any time, when a remote file operation is still running.
This can cause @value{tramp} to block. When such a situation is
@subsection File attributes cache
+@vindex process-file-side-effects
Keeping a local cache of remote file attributes in sync with the
remote host is a time-consuming operation. Flushing and re-querying
these attributes can tax @value{tramp} to a grinding halt on busy
@subsection Timers
+@vindex remote-file-error
Timers run asynchronously at any time when Emacs is waiting for
sending a string to a process, or waiting for process output. They
can run any remote file operation, which would conflict with the
when unifying entries.
---
-*** The user option `bibtex-maintain-sorted-entries' now permits
+*** The user option 'bibtex-maintain-sorted-entries' now permits
user-defined sorting schemes.
+++
If this variable is non-nil, character syntax is used for printing
numbers when this makes sense, such as '?A' for 65.
++++
** New error 'remote-file-error', a subcategory of 'file-error'.
It is signaled if a remote file operation fails due to internal
reasons, and could block Emacs. It does not replace 'file-error'
(setq debug-ignored-errors (cons 'remote-file-error debug-ignored-errors))
++++
** The error 'ftp-error' belongs also to category 'remote-file-error'.
+++
avoids slowing down internal or temporary buffers that are never
presented to users or passed on to other applications.
+---
+** 'start-process-shell-command' and 'start-file-process-shell-command'
+do not support the old calling conventions any longer.
+
\f
* Changes in Emacs 28.1 on Non-Free Operating Systems
(lambda (fromstring tostring instring)
(replace-regexp-in-string (regexp-quote fromstring) tostring instring))))
-;; Error symbol `remote-file-error' is defined in Emacs 28.1. We use
-;; an adapted error message in order to see that compatible symbol.
-(unless (get 'remote-file-error 'error-conditions)
- (define-error 'remote-file-error "Remote file error (compat)" 'file-error))
-
(add-hook 'tramp-unload-hook
(lambda ()
(unload-feature 'tramp-loaddefs 'force)
(unless (or (null stderr) (bufferp stderr))
(signal 'wrong-type-argument (list #'bufferp stderr)))
- ;; Quote shell command.
- (when (and (= (length command) 3)
- (stringp (nth 0 command))
- (string-match-p "sh$" (nth 0 command))
- (stringp (nth 1 command))
- (string-equal "-c" (nth 1 command))
- (stringp (nth 2 command)))
- (setcar (cddr command) (tramp-shell-quote-argument (nth 2 command))))
-
(let* ((buffer
(if buffer
(get-buffer-create buffer)
;; BUFFER can be nil. We use a temporary buffer.
(generate-new-buffer tramp-temp-buffer-name)))
+ ;; We use as environment the difference to toplevel
+ ;; `process-environment'.
+ (env (mapcar
+ (lambda (elt)
+ (unless
+ (member
+ elt (default-toplevel-value 'process-environment))
+ (when (string-match-p "=" elt) elt)))
+ process-environment))
+ (env (setenv-internal
+ env "INSIDE_EMACS"
+ (concat (or (getenv "INSIDE_EMACS") emacs-version)
+ ",tramp:" tramp-version)
+ 'keep))
+ (env (mapcar #'tramp-shell-quote-argument (delq nil env)))
+ ;; Quote command.
+ (command (mapconcat #'tramp-shell-quote-argument command " "))
+ ;; Set cwd and environment variables.
(command
- (mapconcat
- #'identity (append `("cd" ,localname "&&") command) " ")))
+ (append `("cd" ,localname "&&" "(" "env") env `(,command ")"))))
;; Check for `tramp-sh-file-name-handler', because something
;; is different between tramp-adb.el and tramp-sh.el.
(mapcar (lambda (x) (split-string x " ")) login-args))
p (make-process
:name name :buffer buffer
- :command (append `(,login-program) login-args `(,command))
+ :command (append `(,login-program) login-args command)
:coding coding :noquery noquery :connection-type connection-type
:filter filter :sentinel sentinel :stderr stderr))
\f
;;;; Synchronous shell commands.
-(defun start-process-shell-command (name buffer &rest args)
+(defun start-process-shell-command (name buffer command)
"Start a program in a subprocess. Return the process object for it.
NAME is name for process. It is modified if necessary to make it unique.
BUFFER is the buffer (or buffer name) to associate with the process.
an output stream or filter function to handle the output.
BUFFER may be also nil, meaning that this process is not associated
with any buffer
-COMMAND is the shell command to run.
-
-An old calling convention accepted any number of arguments after COMMAND,
-which were just concatenated to COMMAND. This is still supported but strongly
-discouraged."
- (declare (advertised-calling-convention (name buffer command) "23.1"))
+COMMAND is the shell command to run."
;; We used to use `exec' to replace the shell with the command,
;; but that failed to handle (...) and semicolon, etc.
- (start-process name buffer shell-file-name shell-command-switch
- (mapconcat 'identity args " ")))
+ (start-process name buffer shell-file-name shell-command-switch command))
-(defun start-file-process-shell-command (name buffer &rest args)
+(defun start-file-process-shell-command (name buffer command)
"Start a program in a subprocess. Return the process object for it.
Similar to `start-process-shell-command', but calls `start-file-process'."
- (declare (advertised-calling-convention (name buffer command) "23.1"))
;; On remote hosts, the local `shell-file-name' might be useless.
(with-connection-local-variables
(start-file-process
- name buffer
- shell-file-name shell-command-switch
- (mapconcat 'identity args " "))))
+ name buffer shell-file-name shell-command-switch command)))
(defun call-process-shell-command (command &optional infile buffer display
&rest args)
(should-error
(start-file-process "test4" (current-buffer) nil)
:type 'wrong-type-argument)
+
(setq proc (start-file-process "test4" (current-buffer) nil))
(should (processp proc))
(should (equal (process-status proc) 'run))
(tramp-connection-properties
(cons '(nil "direct-async-process" t) tramp-connection-properties)))
(skip-unless (tramp-direct-async-process-p))
+ ;; For whatever reason, it doesn't cooperate with the "mock" method.
+ (skip-unless (not (tramp--test-mock-p)))
;; We do expect an established connection already,
;; `file-truename' does it by side-effect. Suppress
;; `tramp--test-enabled', in order to keep the connection.
(async-shell-command command output-buffer error-buffer)
(let ((proc (get-buffer-process output-buffer))
(delete-exited-processes t))
- (when (stringp input)
- (process-send-string proc input))
- (with-timeout
- ((if (getenv "EMACS_EMBA_CI") 30 10) (tramp--test-timeout-handler))
- (while (or (accept-process-output proc nil nil t) (process-live-p proc))))
- (accept-process-output proc nil nil t)))
+ (cl-letf (((symbol-function #'shell-command-sentinel) #'ignore))
+ (when (stringp input)
+ (process-send-string proc input))
+ (with-timeout
+ ((if (getenv "EMACS_EMBA_CI") 30 10) (tramp--test-timeout-handler))
+ (while
+ (or (accept-process-output proc nil nil t) (process-live-p proc))))
+ (accept-process-output proc nil nil t))))
(defun tramp--test-shell-command-to-string-asynchronously (command)
"Like `shell-command-to-string', but for asynchronous processes."
(ignore-errors (delete-file tmp-name)))
;; Test `{async-}shell-command' with error buffer.
- (let ((stderr (generate-new-buffer "*stderr*")))
- (unwind-protect
- (with-temp-buffer
- (funcall
- this-shell-command
- "echo foo >&2; echo bar" (current-buffer) stderr)
- (should (string-equal "bar\n" (buffer-string)))
- ;; Check stderr.
- (with-current-buffer stderr
- (should (string-equal "foo\n" (buffer-string)))))
+ (unless (tramp-direct-async-process-p)
+ (let ((stderr (generate-new-buffer "*stderr*")))
+ (unwind-protect
+ (with-temp-buffer
+ (funcall
+ this-shell-command
+ "echo foo >&2; echo bar" (current-buffer) stderr)
+ (should (string-equal "bar\n" (buffer-string)))
+ ;; Check stderr.
+ (with-current-buffer stderr
+ (should (string-equal "foo\n" (buffer-string)))))
- ;; Cleanup.
- (ignore-errors (kill-buffer stderr)))))
+ ;; Cleanup.
+ (ignore-errors (kill-buffer stderr))))))
;; Test sending string to `async-shell-command'.
(unwind-protect
(when (natnump cols)
(should (= cols async-shell-command-width))))))
+(tramp--test--deftest-direct-async-process tramp-test32-shell-command
+ "Check direct async `shell-command'.")
+
;; This test is inspired by Bug#39067.
(ert-deftest tramp-test32-shell-command-dont-erase-buffer ()
"Check `shell-command-dont-erase-buffer'."
(should
(string-equal
(format "%s,tramp:%s\n" emacs-version tramp-version)
- (funcall this-shell-command-to-string "echo ${INSIDE_EMACS:-bla}")))
+ (funcall this-shell-command-to-string "echo \"${INSIDE_EMACS:-bla}\"")))
(let ((process-environment
(cons (format "INSIDE_EMACS=%s,foo" emacs-version)
process-environment)))
(string-equal
(format "%s,foo,tramp:%s\n" emacs-version tramp-version)
(funcall
- this-shell-command-to-string "echo ${INSIDE_EMACS:-bla}"))))
+ this-shell-command-to-string "echo \"${INSIDE_EMACS:-bla}\""))))
;; Set a value.
(let ((process-environment
(string-match
"foo"
(funcall
- this-shell-command-to-string (format "echo ${%s:-bla}" envvar)))))
+ this-shell-command-to-string
+ (format "echo \"${%s:-bla}\"" envvar)))))
;; Set the empty value.
(let ((process-environment
(string-match
"bla"
(funcall
- this-shell-command-to-string (format "echo ${%s:-bla}" envvar))))
+ this-shell-command-to-string (format "echo \"${%s:-bla}\"" envvar))))
;; Variable is set.
(should
(string-match
(regexp-quote envvar)
(funcall this-shell-command-to-string "set"))))
- ;; We force a reconnect, in order to have a clean environment.
- (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
- ;; Unset the variable.
- (let ((tramp-remote-process-environment
- (cons (concat envvar "=foo") tramp-remote-process-environment)))
- ;; Set the initial value, we want to unset below.
- (should
- (string-match
- "foo"
- (funcall
- this-shell-command-to-string (format "echo ${%s:-bla}" envvar))))
- (let ((process-environment (cons envvar process-environment)))
- ;; Variable is unset.
+ (unless (tramp-direct-async-process-p)
+ ;; We force a reconnect, in order to have a clean environment.
+ (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
+ ;; Unset the variable.
+ (let ((tramp-remote-process-environment
+ (cons (concat envvar "=foo") tramp-remote-process-environment)))
+ ;; Set the initial value, we want to unset below.
(should
(string-match
- "bla"
- (funcall
- this-shell-command-to-string (format "echo ${%s:-bla}" envvar))))
- ;; Variable is unset.
- (should-not
- (string-match
- (regexp-quote envvar)
- ;; We must remove PS1, the output is truncated otherwise.
+ "foo"
(funcall
- this-shell-command-to-string "printenv | grep -v PS1"))))))))
+ this-shell-command-to-string
+ (format "echo \"${%s:-bla}\"" envvar))))
+ (let ((process-environment (cons envvar process-environment)))
+ ;; Variable is unset.
+ (should
+ (string-match
+ "bla"
+ (funcall
+ this-shell-command-to-string
+ (format "echo \"${%s:-bla}\"" envvar))))
+ ;; Variable is unset.
+ (should-not
+ (string-match
+ (regexp-quote envvar)
+ ;; We must remove PS1, the output is truncated otherwise.
+ (funcall
+ this-shell-command-to-string "printenv | grep -v PS1")))))))))
+
+(tramp--test--deftest-direct-async-process tramp-test33-environment-variables
+ "Check that remote processes set / unset environment variables properly.
+Use direct async.")
;; This test is inspired by Bug#27009.
(ert-deftest tramp-test33-environment-variables-and-port-numbers ()
(ignore-errors (cancel-timer timer))
(ignore-errors (delete-directory tmp-name 'recursive))))))
+;; (tramp--test--deftest-direct-async-process tramp-test43-asynchronous-requests
+;; "Check parallel direct asynchronous requests.")
+
;; This test is inspired by Bug#29163.
(ert-deftest tramp-test44-auto-load ()
"Check that Tramp autoloads properly."