]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve Tramp's process-file implementations
authorMichael Albinus <michael.albinus@gmx.de>
Sun, 13 Feb 2022 19:50:51 +0000 (20:50 +0100)
committerMichael Albinus <michael.albinus@gmx.de>
Sun, 13 Feb 2022 19:50:51 +0000 (20:50 +0100)
* lisp/net/tramp-adb.el (tramp-adb-handle-process-file)
* lisp/net/tramp-sh.el (tramp-sh-handle-process-file):
* lisp/net/tramp-smb.el (tramp-smb-handle-process-file):
* lisp/net/tramp-sshfs.el (tramp-sshfs-handle-process-file):
Improve implementation.  (Bug#53854)

* test/lisp/net/tramp-tests.el (tramp-test28-process-file)
(tramp--test-check-files, tramp-test47-unload): Extend tests.

lisp/net/tramp-adb.el
lisp/net/tramp-sh.el
lisp/net/tramp-smb.el
lisp/net/tramp-sshfs.el
test/lisp/net/tramp-tests.el

index 85cd2d9bc1eb5b7db24bec45a209b1af4e6ad7f3..c683f4c6e8ac6d992c7a110f410d6317ca360b5f 100644 (file)
@@ -818,7 +818,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
        (setq infile (tramp-compat-file-name-unquote (expand-file-name infile)))
        (if (tramp-equal-remote default-directory infile)
            ;; INFILE is on the same remote host.
-           (setq input (tramp-file-local-name infile))
+           (setq input (tramp-unquote-file-local-name infile))
          ;; INFILE must be copied to remote host.
          (setq input (tramp-make-tramp-temp-file v)
                tmpinput (tramp-make-tramp-file-name v input))
@@ -849,7 +849,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
          (setcar (cdr destination) (expand-file-name (cadr destination)))
          (if (tramp-equal-remote default-directory (cadr destination))
              ;; stderr is on the same remote host.
-             (setq stderr (tramp-file-local-name (cadr destination)))
+             (setq stderr (tramp-unquote-file-local-name (cadr destination)))
            ;; stderr must be copied to remote host.  The temporary
            ;; file must be deleted after execution.
            (setq stderr (tramp-make-tramp-temp-file v)
@@ -1264,7 +1264,7 @@ connection if a previous connection has died for some reason."
        (if (zerop (length device))
            (tramp-error vec 'file-error "Device %s not connected" host))
        (with-tramp-progress-reporter vec 3 "Opening adb shell connection"
-         (let* ((coding-system-for-read 'utf-8-dos) ;is this correct?
+         (let* ((coding-system-for-read 'utf-8-dos)  ; Is this correct?
                 (process-connection-type tramp-process-connection-type)
                 (args (if (> (length host) 0)
                           (list "-s" device "shell")
index ea089224aefe965c1632b490ee56bf5215c95a0e..40ddf106c999a6af2bec7898f47c8e63fb9d9920 100644 (file)
@@ -3118,7 +3118,7 @@ implementation will be used."
        (setq infile (tramp-compat-file-name-unquote (expand-file-name infile)))
        (if (tramp-equal-remote default-directory infile)
            ;; INFILE is on the same remote host.
-           (setq input (tramp-file-local-name infile))
+           (setq input (tramp-unquote-file-local-name infile))
          ;; INFILE must be copied to remote host.
          (setq input (tramp-make-tramp-temp-file v)
                tmpinput (tramp-make-tramp-file-name v input))
@@ -3149,7 +3149,7 @@ implementation will be used."
          (setcar (cdr destination) (expand-file-name (cadr destination)))
          (if (tramp-equal-remote default-directory (cadr destination))
              ;; stderr is on the same remote host.
-             (setq stderr (tramp-file-local-name (cadr destination)))
+             (setq stderr (tramp-unquote-file-local-name (cadr destination)))
            ;; stderr must be copied to remote host.  The temporary
            ;; file must be deleted after execution.
            (setq stderr (tramp-make-tramp-temp-file v)
index 6515519680c27f1c3b0d4d1be9a229a438b7c8ef..f52fa0a93be403e089d62fa9baf045cedb42692b 100644 (file)
@@ -1284,7 +1284,7 @@ component is used as the target of the symlink."
        (setq infile (tramp-compat-file-name-unquote (expand-file-name infile)))
        (if (tramp-equal-remote default-directory infile)
            ;; INFILE is on the same remote host.
-           (setq input (tramp-file-local-name infile))
+           (setq input (tramp-unquote-file-local-name infile))
          ;; INFILE must be copied to remote host.
          (setq input (tramp-make-tramp-temp-file v)
                tmpinput (tramp-make-tramp-file-name v input))
index 664dbc31b1490bd1aa0ed6db730c4ea06b25262b..3f23b1a87865e4bb02794cbe4781fc8047677d56 100644 (file)
@@ -240,12 +240,13 @@ arguments to pass to the OPERATION."
     (error "Implementation does not handle immediate return"))
 
   (with-parsed-tramp-file-name (expand-file-name default-directory) nil
-    (let ((command
+    (let ((coding-system-for-read 'utf-8-dos)  ; Is this correct?
+         (command
           (format
            "cd %s && exec %s"
            (tramp-unquote-shell-quote-argument localname)
            (mapconcat #'tramp-shell-quote-argument (cons program args) " ")))
-         input tmpinput)
+         input tmpinput stderr tmpstderr outbuf)
 
       ;; Determine input.
       (if (null infile)
@@ -253,18 +254,55 @@ arguments to pass to the OPERATION."
        (setq infile (tramp-compat-file-name-unquote (expand-file-name infile)))
        (if (tramp-equal-remote default-directory infile)
            ;; INFILE is on the same remote host.
-           (setq input (tramp-file-local-name infile))
+           (setq input (tramp-unquote-file-local-name infile))
          ;; INFILE must be copied to remote host.
          (setq input (tramp-make-tramp-temp-file v)
                tmpinput (tramp-make-tramp-file-name v input))
          (copy-file infile tmpinput t)))
       (when input (setq command (format "%s <%s" command input)))
 
+      ;; Determine output.
+      (cond
+       ;; Just a buffer.
+       ((bufferp destination)
+       (setq outbuf destination))
+       ;; A buffer name.
+       ((stringp destination)
+       (setq outbuf (get-buffer-create destination)))
+       ;; (REAL-DESTINATION ERROR-DESTINATION)
+       ((consp destination)
+       ;; output.
+       (cond
+        ((bufferp (car destination))
+         (setq outbuf (car destination)))
+        ((stringp (car destination))
+         (setq outbuf (get-buffer-create (car destination))))
+        ((car destination)
+         (setq outbuf (current-buffer))))
+       ;; stderr.
+       (cond
+        ((stringp (cadr destination))
+         (setcar (cdr destination) (expand-file-name (cadr destination)))
+         (if (tramp-equal-remote default-directory (cadr destination))
+             ;; stderr is on the same remote host.
+             (setq stderr (tramp-unquote-file-local-name (cadr destination)))
+           ;; stderr must be copied to remote host.  The temporary
+           ;; file must be deleted after execution.
+           (setq stderr (tramp-make-tramp-temp-file v)
+                 tmpstderr (tramp-make-tramp-file-name v stderr))))
+        ;; stderr to be discarded.
+        ((null (cadr destination))
+         (setq stderr (tramp-get-remote-null-device v)))))
+       ;; 't
+       (destination
+       (setq outbuf (current-buffer))))
+      (when stderr (setq command (format "%s 2>%s" command stderr)))
+
       (unwind-protect
          (apply
           #'tramp-call-process
           v (tramp-get-method-parameter v 'tramp-login-program)
-          nil destination display
+          nil outbuf display
           (tramp-expand-args
            v 'tramp-login-args
            ?h (or (tramp-file-name-host v) "")
@@ -272,6 +310,15 @@ arguments to pass to the OPERATION."
            ?p (or (tramp-file-name-port v) "")
            ?l command))
 
+       ;; Synchronize stderr.
+       (when tmpstderr
+         (tramp-cleanup-connection v 'keep-debug 'keep-password)
+         (tramp-fuse-unmount v))
+
+       ;; Provide error file.
+       (when tmpstderr
+         (rename-file tmpstderr (cadr destination) t))
+
        ;; Cleanup.  We remove all file cache values for the
        ;; connection, because the remote process could have changed
        ;; them.
index d78e8815b25a7d3b765516038806354f35763e9a..baddcd2d7ac7fab5b0fb20e28fe607576f227b1d 100644 (file)
@@ -4398,6 +4398,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
     (let* ((tmp-name (tramp--test-make-temp-name nil quoted))
           (fnnd (file-name-nondirectory tmp-name))
           (default-directory tramp-test-temporary-file-directory)
+          (buffer (get-buffer-create "*tramp-tests*"))
           kill-buffer-query-functions)
       (unwind-protect
          (progn
@@ -4430,31 +4431,47 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
                   (tramp--test-shell-file-name)
                   nil nil nil "-c" "kill -2 $$")))))
 
-           (with-temp-buffer
-             (write-region "foo" nil tmp-name)
-             (should (file-exists-p tmp-name))
-             (should (zerop (process-file "ls" nil t nil fnnd)))
-             ;; "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" fnnd) (buffer-string)))
-             (should-not (get-buffer-window (current-buffer) t))
+           ;; Check DESTINATION.
+           (dolist (destination `(nil t ,buffer))
+             (when (bufferp destination)
+               (with-current-buffer destination
+                 (delete-region (point-min) (point-max))))
+             (with-temp-buffer
+               (write-region "foo" nil tmp-name)
+               (should (file-exists-p tmp-name))
+               (should (zerop (process-file "ls" nil destination nil fnnd)))
+               (with-current-buffer
+                   (if (bufferp destination) destination (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 (if destination (format "%s\n" fnnd) "")
+                                (buffer-string)))
+                 (should-not (get-buffer-window (current-buffer) t))
+                 (goto-char (point-max)))
+
+               ;; Second run.  The output must be appended.
+               (should (zerop (process-file "ls" nil destination t fnnd)))
+               (with-current-buffer
+                   (if (bufferp destination) destination (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
+                   (if destination (format "%s\n%s\n" fnnd fnnd) "")
+                   (buffer-string))))
 
-             ;; Second run.  The output must be appended.
-             (goto-char (point-max))
-             (should (zerop (process-file "ls" nil t t fnnd)))
-             ;; "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%s\n" fnnd fnnd) (buffer-string)))
-             ;; A non-nil DISPLAY must not raise the buffer.
-             (should-not (get-buffer-window (current-buffer) t))
-             (delete-file tmp-name))
+               (unless (eq destination t)
+                 (should (string-empty-p (buffer-string))))
+               ;; A non-nil DISPLAY must not raise the buffer.
+               (should-not (get-buffer-window (current-buffer) t))
+               (delete-file tmp-name)))
 
            ;; Check remote and local INFILE.
            (dolist (local '(nil t))
@@ -4464,10 +4481,37 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
                (should (file-exists-p tmp-name))
                (should (zerop (process-file "cat" tmp-name t)))
                (should (string-equal "foo" (buffer-string)))
-               (should-not (get-buffer-window (current-buffer) t)))
-             (delete-file tmp-name)))
+               (should-not (get-buffer-window (current-buffer) t))
+               (delete-file tmp-name)))
+
+           ;; Check remote and local DESTNATION file.  This isn't
+           ;; implemented yet ina all file name handler backends.
+           ;; (dolist (local '(nil t))
+           ;;   (setq tmp-name (tramp--test-make-temp-name local quoted))
+           ;;   (should
+           ;;    (zerop (process-file "echo" nil `(:file ,tmp-name) nil "foo")))
+           ;;   (with-temp-buffer
+           ;;  (insert-file-contents tmp-name)
+           ;;  (should (string-equal "foo" (buffer-string)))
+           ;;  (should-not (get-buffer-window (current-buffer) t))
+           ;;  (delete-file tmp-name)))
+
+           ;; Check remote and local STDERR.
+           (dolist (local '(nil t))
+             (setq tmp-name (tramp--test-make-temp-name local quoted))
+             (should-not
+              (zerop
+               (process-file "cat" nil `(t ,tmp-name) nil "/does-not-exist")))
+             (with-temp-buffer
+               (insert-file-contents tmp-name)
+               (should
+                (string-match-p
+                 "cat:.* No such file or directory" (buffer-string)))
+               (should-not (get-buffer-window (current-buffer) t))
+               (delete-file tmp-name))))
 
        ;; Cleanup.
+       (ignore-errors (kill-buffer buffer))
        (ignore-errors (delete-file tmp-name))))))
 
 ;; Must be a command, because used as `sigusr1' handler.
@@ -6479,7 +6523,13 @@ This requires restrictions of file name syntax."
                ;; `default-directory' with special characters.  See
                ;; Bug#53846.
                (when (and (tramp--test-expensive-test-p)
-                          (tramp--test-supports-processes-p))
+                          (tramp--test-supports-processes-p)
+                          ;; Prior Emacs 27, `shell-file-name' was
+                          ;; hard coded as "/bin/sh" for remote
+                          ;; processes in Emacs.  That doesn't work
+                          ;; for tramp-adb.el.
+                          (or (not (tramp--test-adb-p))
+                              (tramp--test-emacs27-p)))
                  (let ((default-directory file1))
                    (dolist (this-shell-command
                             (append
@@ -7207,17 +7257,20 @@ Since it unloads Tramp, it shall be the last test to run."
   (should (featurep 'tramp-archive))
   ;; This unloads also tramp-archive.el and tramp-theme.el if needed.
   (unload-feature 'tramp 'force)
-  ;; No Tramp feature must be left.
+
+  ;; No Tramp feature must be left except the test packages.
   (should-not (featurep 'tramp))
   (should-not (featurep 'tramp-archive))
   (should-not (featurep 'tramp-theme))
   (should-not
    (all-completions
     "tramp" (delq 'tramp-tests (delq 'tramp-archive-tests features))))
+
   ;; `file-name-handler-alist' must be clean.
   (should-not (all-completions "tramp" (mapcar #'cdr file-name-handler-alist)))
+
   ;; There shouldn't be left a bound symbol, except buffer-local
-  ;; variables, and autoload functions.  We do not regard our test
+  ;; variables, and autoloaded functions.  We do not regard our test
   ;; symbols, and the Tramp unload hooks.
   (mapatoms
    (lambda (x)
@@ -7231,6 +7284,7 @@ Since it unloads Tramp, it shall be the last test to run."
          (not (string-match-p "unload-hook$" (symbol-name x)))
          (not (get x 'tramp-autoload))
          (ert-fail (format "`%s' still bound" x)))))
+
   ;; The defstruct `tramp-file-name' and all its internal functions
   ;; shall be purged.
   (should-not (cl--find-class 'tramp-file-name))
@@ -7239,6 +7293,7 @@ Since it unloads Tramp, it shall be the last test to run."
      (and (functionp x)
           (string-match-p "tramp-file-name" (symbol-name x))
           (ert-fail (format "Structure function `%s' still exists" x)))))
+
   ;; There shouldn't be left a hook function containing a Tramp
   ;; function.  We do not regard the Tramp unload hooks.
   (mapatoms
@@ -7248,7 +7303,18 @@ Since it unloads Tramp, it shall be the last test to run."
          (not (string-match-p "unload-hook$" (symbol-name x)))
          (consp (symbol-value x))
          (ignore-errors (all-completions "tramp" (symbol-value x)))
-         (ert-fail (format "Hook `%s' still contains Tramp function" x))))))
+         (ert-fail (format "Hook `%s' still contains Tramp function" x)))))
+
+  ;; There shouldn't be left an advice function from Tramp.
+  (mapatoms
+   (lambda (x)
+     (and (functionp x)
+         (advice-mapc
+          (lambda (fun _symbol)
+            (and (string-match-p "^tramp" (symbol-name fun))
+                 (ert-fail
+                  (format "Function `%s' still contains Tramp advice" x))))
+          x)))))
 
 (defun tramp-test-all (&optional interactive)
   "Run all tests for \\[tramp].