]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve make-process in Tramp
authorMichael Albinus <michael.albinus@gmx.de>
Sun, 20 Dec 2020 18:45:11 +0000 (19:45 +0100)
committerMichael Albinus <michael.albinus@gmx.de>
Sun, 20 Dec 2020 18:45:11 +0000 (19:45 +0100)
* doc/misc/tramp.texi (Remote processes): Remove INSIDE_EMACS
restriction.
(Frequently Asked Questions, External packages): Add indices.

* etc/NEWS: 'start-process-shell-command' and
'start-file-process-shell-command' do not support the old calling
conventions any longer.

* lisp/subr.el (start-process-shell-command)
(start-file-process-shell-command): Remove old calling conventions.

* lisp/net/tramp-compat.el (remote-file-error): Remove, it isn't
necessary.

* lisp/net/tramp.el (tramp-handle-make-process): Remove special shell
handling.  Support environment variables.

* test/lisp/net/tramp-tests.el
(tramp--test--deftest-direct-async-process): Skip for mock method.
(tramp--test-async-shell-command): Suppress `shell-command-sentinel'.
(tramp-test32-shell-command, tramp-test33-environment-variables):
Adapt tests.
(tramp-test32-shell-command-direct-async)
(tramp-test33-environment-variables-direct-async): New tests.

doc/misc/tramp.texi
etc/NEWS
lisp/net/tramp-compat.el
lisp/net/tramp.el
lisp/subr.el
test/lisp/net/tramp-tests.el

index 0557ca54695739525e1b5783328dbcfc2042d67d..dd350f10c0bba12b974b7dcde1a20b6f30a9bedc 100644 (file)
@@ -3584,9 +3584,6 @@ It does not set process property @code{remote-pid}.
 @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
@@ -4880,6 +4877,8 @@ In case you have installed it from its Git repository, @ref{Recompilation}.
 @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
@@ -5021,6 +5020,7 @@ bind it to non-@code{nil} value.
 
 @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
@@ -5061,6 +5061,7 @@ root-directory, it is most likely sufficient to make the
 
 @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
index 1b4c21cb45000d72640e2caad6ef1634f3c8a33e..7411295e1b5570201ad39c386a33c72b6e2ff6cf 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1482,7 +1482,7 @@ This new option allows the user to customize how case is converted
 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.
 
 +++
@@ -2170,6 +2170,7 @@ and 'play-sound-file'.
 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'
@@ -2182,6 +2183,7 @@ Until it is solved you could ignore such errors by performing
 
     (setq debug-ignored-errors (cons 'remote-file-error debug-ignored-errors))
 
++++
 ** The error 'ftp-error' belongs also to category 'remote-file-error'.
 
 +++
@@ -2193,6 +2195,10 @@ buffer does not run the hooks 'kill-buffer-hook',
 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
 
index 4c8d37d602c087f469e2a9a4bf7525a40a353f97..b44eabcfa8bac3b07abf79ce9901a8bc673b11ed 100644 (file)
@@ -348,11 +348,6 @@ A nil value for either argument stands for the current time."
     (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)
index 6c1c09bc37133bc6a6baf8171d1d9b023bfc5f8e..4d8118a728b60be51536955835a4b8c90c6e830a 100644 (file)
@@ -3790,23 +3790,31 @@ It does not support `:stderr'."
        (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.
@@ -3861,7 +3869,7 @@ It does not support `:stderr'."
              (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))
 
index 7461fa2a15c015960cc65c7d5780bdbd810efd9c..cb64b3f6e747f6fda0ecc423d1f745b912eb7777 100644 (file)
@@ -3560,7 +3560,7 @@ Do nothing if FACE is nil."
 \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.
@@ -3568,27 +3568,18 @@ 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)
index 0a5931d6893e51879719cb1370c80962c047ff6b..9dd98037a0ed34e2d0b4fab00e5322da0ae823d8 100644 (file)
@@ -4459,6 +4459,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
                (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))
@@ -4483,6 +4484,8 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
           (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.
@@ -4703,12 +4706,14 @@ INPUT, if non-nil, is a string sent to the process."
   (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."
@@ -4762,19 +4767,20 @@ INPUT, if non-nil, is a string sent to the process."
          (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
@@ -4810,6 +4816,9 @@ INPUT, if non-nil, is a string sent to the process."
       (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'."
@@ -4961,7 +4970,7 @@ INPUT, if non-nil, is a string sent to the process."
       (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)))
@@ -4969,7 +4978,7 @@ INPUT, if non-nil, is a string sent to the process."
         (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
@@ -4979,7 +4988,8 @@ INPUT, if non-nil, is a string sent to the process."
         (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
@@ -4989,38 +4999,45 @@ INPUT, if non-nil, is a string sent to the process."
         (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 ()
@@ -6432,6 +6449,9 @@ process sentinels.  They shall not disturb each other."
         (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."