External Tramp methods can be used in multi-hops

* doc/misc/tramp.texi (External methods): Mention, how external
methods are used for multi-hops.
(Ad-hoc multi-hops): Change requirement of method.

* doc/misc/trampver.texi:
* lisp/net/trampver.el: Change version to "2.8.2-pre".

* etc/NEWS: External Tramp methods can be used in multi-hops.
Presentational fixes and improvements.

* lisp/net/tramp-sh.el (tramp-sh-handle-copy-directory): Check for
`tramp-method-out-of-band-p' explicitly. Don't flush directory
properties.
(tramp-method-out-of-band-p): There shouldn't be a multi-hop.

* lisp/net/tramp-smb.el (tramp-smb-handle-copy-directory): Don't
flush directory properties.

* lisp/net/tramp.el (tramp-methods): Adapt docstring.
(tramp-barf-if-file-missing)
(with-parsed-tramp-file-name): Adapt debug spec.
(tramp-skeleton-copy-directory): Flush directory properties.
(tramp-add-hops): Check for `tramp-login-args' property.
This commit is contained in:
Michael Albinus
2026-01-06 15:20:58 +01:00
parent 52e0c9eb2a
commit 8343ce6c52
7 changed files with 104 additions and 95 deletions

View File

@@ -1132,9 +1132,11 @@ an external transfer program.
External methods save on the overhead of encoding and decoding of
inline methods.
@vindex tramp-copy-size-limit
Since external methods have the overhead of opening a new channel,
files smaller than @code{tramp-copy-size-limit} still use inline
methods.
methods. If an external method is used inside a multi-hop connection
(@pxref{Multi-hops}), its inherent inline method is used as well.
@table @asis
@cindex method @option{rcp}
@@ -3891,7 +3893,7 @@ proxy @samp{bird@@bastion} to a remote file on @samp{you@@remotehost}:
ssh@value{postfixhop}you@@remotehost@value{postfix}/path @key{RET}}
@end example
Each involved method must be an inline method (@pxref{Inline methods}).
Each involved method must be handled by @value{tramp}'s @code{tramp-sh} backend.
@value{tramp} adds the ad-hoc definitions as an ephemeral record to
@code{tramp-default-proxies-alist}, which are available for reuse

View File

@@ -7,7 +7,7 @@
@c In the Tramp GIT, the version number and the bug report address
@c are auto-frobbed from configure.ac.
@set trampver 2.8.1
@set trampver 2.8.2-pre
@set trampurl https://www.gnu.org/software/tramp/
@set tramp-bug-report-address tramp-devel@@gnu.org
@set emacsver 28.1

View File

@@ -471,7 +471,7 @@ either resize the frame and change the fullscreen status accordingly or
keep the frame size unchanged. The value t means to first reset the
fullscreen status and then resize the frame.
*** New commands to set frame size and position in one compound step.
*** New functions to set frame size and position in one compound step.
'set-frame-size-and-position' sets the new size and position of a frame
in one compound step. Both, size and position, can be specified as with
the corresponding frame parameters 'width', 'height', 'left' and 'top'.
@@ -493,7 +493,7 @@ an error when a frame of that name already exists.
The frame parameter 'cloned-from' is set to the frame from which the new
frame is cloned using the command 'clone-frame'.
The frame parameter 'undeleted is set to t when a frame is undeleted
The frame parameter 'undeleted' is set to t when a frame is undeleted
using the command 'undelete-frame'.
These are useful if you need to detect a cloned frame or undeleted frame
@@ -1057,11 +1057,11 @@ The new variable 'forward-comment-function' is set to the new function
'treesit-forward-comment' if a major mode defines the thing 'comment'.
+++
*** New function 'treesit-query-eagerly-compiled-p'
*** New function 'treesit-query-eagerly-compiled-p'.
This function returns non-nil if a query was eagerly compiled.
+++
*** New function 'treesit-query-source'
*** New function 'treesit-query-source'.
This function returns the string or sexp source query of a compiled query.
+++
@@ -1153,8 +1153,9 @@ convention. Also, the ':match?' predicate can now take the regexp as
either the first or second argument, so it works with both tree-sitter
convention (regexp arg second) and Emacs convention (regexp arg first).
** Track changes
+++
** Track-changes
*** New variable 'track-changes-undo-only' to distinguish undo changes.
** Hideshow
@@ -1170,7 +1171,7 @@ blocks.
This command hides or shows all the blocks in the current buffer.
---
*** 'hs-hide-level' no longer hide all the blocks in the current buffer.
*** 'hs-hide-level' no longer hides all the blocks in the current buffer.
If 'hs-hide-level' was not inside a code block it would hide all the
blocks in the buffer like 'hs-hide-all'. Now it should only hide all
the second level blocks.
@@ -1229,7 +1230,6 @@ buffer-local variables 'hs-block-start-regexp', 'hs-c-start-regexp',
*** 'hs-hide-level' and 'hs-cycle' can now hide comments too.
This is controlled by 'hs-hide-comments-when-hiding-all'.
** C-ts mode
+++
@@ -1644,7 +1644,6 @@ is the default.
This user option is in sympathy with recentf, and savehist autosave
timers.
** Savehist
---
@@ -2014,7 +2013,7 @@ for docstrings where symbols 'nil' and 't' are in quotes.
In most cases, having it enabled leads to a large amount of false
positives.
*** New file-local variable 'lisp-indent-local-overrides'
*** New file-local variable 'lisp-indent-local-overrides'.
This variable can be used to locally override the indent specification
of symbols.
@@ -2083,6 +2082,10 @@ connections after you close remote-file buffers without having to either
cherry-pick via 'tramp-cleanup-connection' or clear them all via
'tramp-cleanup-all-connections'.
+++
*** External methods can now be used in multi-hop connections.
This is implemented for 'tramp-sh' methods, like "/scp:user@host|sudo::".
+++
*** New command 'tramp-dired-find-file-with-sudo'.
This command, bound to '@' in Dired, visits the file or directory on the
@@ -2463,7 +2466,7 @@ appearance of the list can be customized with the new faces
+++
*** Printing root branch logs has moved to 'C-x v b L'.
Previously the command to print the root log for a branch was bound to
Previously, the command to print the root log for a branch was bound to
'C-x v b l'. It has now been renamed from 'vc-print-branch-log' to
'vc-print-root-branch-log', and bound to 'C-x v b L'. This is more
consistent with the rest of the 'C-x v' keymap, and makes room for a new
@@ -2676,7 +2679,7 @@ bindings:
*** New display of outgoing revisions count in VC Directory.
If there are outgoing revisions, VC Directory now includes a count of
how many in its headers, to remind you to push them.
You can disable this by customizing vc-dir-show-outgoing-count to nil.
You can disable this by customizing 'vc-dir-show-outgoing-count' to nil.
+++
*** New user option 'vc-async-checkin' to enable async checkin operations.
@@ -3312,7 +3315,7 @@ the source, or to 'antlr-v3' otherwise.
*** New command 'antlr-v4-mode' is a derived mode of 'antlr-mode'.
It sets 'antlr-tool-version' to value 'antlr-v4', and is automatically
used for files with extension "g4".
used for files with extension ".g4".
*** The variable 'antlr-language' is now used more generally.
The variable has a symbol as value which determines which of the
@@ -3325,8 +3328,8 @@ ObjC, Python and Ruby, additional to Java and Cpp.
*** New user option 'antlr-run-tool-on-buffer-file'.
Command 'antlr-run-tool' now usually runs on the file for the current
buffer. Customize this user option to have value ' nil' to get the
previous behavior back.
buffer. Customize this user option to nil to get the previous behavior
back.
** Hi Lock
@@ -3497,8 +3500,8 @@ separator, are also supported.
---
** The experimental variable 'binary-as-unsigned' has been removed.
Instead of (let ((binary-as-unsigned t)) (format "%x" N)) you can use
(format "%x" (logand N MASK)) where MASK is for the desired word size,
Instead of '(let ((binary-as-unsigned t)) (format "%x" N))' you can use
'(format "%x" (logand N MASK))' where MASK is for the desired word size,
e.g., #x3fffffffffffffff for typical Emacs fixnums.
+++
@@ -3862,7 +3865,7 @@ called on progress steps, and DONE-CALLBACK, called when the progress
reporter is done. See the 'make-progress-reporter' docstring for a full
specification of these new optional arguments.
** Add binary format specifications '%b' and '%B'.
** Binary format specifications '%b' and '%B' added.
These produce the binary representation of a number.
'%#b' and '%#B' prefix the bits with '0b' and '0B', respectively.

View File

@@ -2098,66 +2098,67 @@ ID-FORMAT valid values are `string' and `integer'."
"Like `copy-directory' for Tramp files."
(tramp-skeleton-copy-directory
dirname newname keep-date parents copy-contents
(let ((t1 (tramp-tramp-file-p dirname))
(t2 (tramp-tramp-file-p newname))
target)
(with-parsed-tramp-file-name (if t1 dirname newname) nil
(cond
((and copy-directory-create-symlink
(setq target (file-symlink-p dirname))
(tramp-equal-remote dirname newname))
(make-symbolic-link
target
(if (directory-name-p newname)
(concat newname (file-name-nondirectory dirname)) newname)
t))
(let* ((v1 (and (tramp-tramp-file-p dirname)
(tramp-dissect-file-name dirname)))
(v2 (and (tramp-tramp-file-p newname)
(tramp-dissect-file-name newname)))
(v (or v1 v2))
target)
(cond
((and copy-directory-create-symlink
(setq target (file-symlink-p dirname))
(tramp-equal-remote dirname newname))
(make-symbolic-link
target
(if (directory-name-p newname)
(concat newname (file-name-nondirectory dirname)) newname)
t))
;; Shortcut: if method, host, user are the same for both
;; files, we invoke `cp' on the remote host directly.
((and (not copy-contents)
(tramp-equal-remote dirname newname))
(when (and (file-directory-p newname)
(not (directory-name-p newname)))
(tramp-error v 'file-already-exists newname))
(setq dirname (directory-file-name (expand-file-name dirname))
newname (directory-file-name (expand-file-name newname)))
(tramp-do-copy-or-rename-file-directly
'copy dirname newname
'ok-if-already-exists keep-date 'preserve-uid-gid))
;; Shortcut: if method, host, user are the same for both files,
;; we invoke `cp' on the remote host directly.
((and (not copy-contents)
(tramp-equal-remote dirname newname))
(when (and (file-directory-p newname)
(not (directory-name-p newname)))
(tramp-error v 'file-already-exists newname))
(setq dirname (directory-file-name (expand-file-name dirname))
newname (directory-file-name (expand-file-name newname)))
(tramp-do-copy-or-rename-file-directly
'copy dirname newname
'ok-if-already-exists keep-date 'preserve-uid-gid))
;; scp or rsync DTRT.
((and (not copy-contents)
(tramp-get-method-parameter v 'tramp-copy-recursive)
;; When DIRNAME and NEWNAME are remote, they must have
;; the same method.
(or (null t1) (null t2)
(string-equal
(tramp-file-name-method (tramp-dissect-file-name dirname))
(tramp-file-name-method (tramp-dissect-file-name newname)))))
(when (and (file-directory-p newname)
(not (directory-name-p newname)))
(tramp-error v 'file-already-exists newname))
(setq dirname (directory-file-name (expand-file-name dirname))
newname (directory-file-name (expand-file-name newname)))
(when (and (file-directory-p newname)
(not (string-equal (file-name-nondirectory dirname)
(file-name-nondirectory newname))))
(setq newname
(expand-file-name (file-name-nondirectory dirname) newname)))
(unless (file-directory-p (file-name-directory newname))
(make-directory (file-name-directory newname) parents))
(tramp-do-copy-or-rename-file-out-of-band
'copy dirname newname 'ok-if-already-exists keep-date))
;; scp or rsync DTRT.
((and (not copy-contents)
(tramp-get-method-parameter v 'tramp-copy-recursive)
;; When DIRNAME and NEWNAME are remote, they must have
;; the same method. None of them must be multi-hop.
(or (and (null v1) (tramp-method-out-of-band-p v2 0))
(and (null v2) (tramp-method-out-of-band-p v1 0))
(and v1 v2
(tramp-method-out-of-band-p v1 0)
(tramp-method-out-of-band-p v2 0)
(string-equal
(tramp-file-name-method v1)
(tramp-file-name-method v2)))))
(when (and (file-directory-p newname)
(not (directory-name-p newname)))
(tramp-error v 'file-already-exists newname))
(setq dirname (directory-file-name (expand-file-name dirname))
newname (directory-file-name (expand-file-name newname)))
(when (and (file-directory-p newname)
(not (string-equal (file-name-nondirectory dirname)
(file-name-nondirectory newname))))
(setq newname
(expand-file-name (file-name-nondirectory dirname) newname)))
(unless (file-directory-p (file-name-directory newname))
(make-directory (file-name-directory newname) parents))
(tramp-do-copy-or-rename-file-out-of-band
'copy dirname newname 'ok-if-already-exists keep-date))
;; We must do it file-wise.
(t (tramp-run-real-handler
#'copy-directory
(list dirname newname keep-date parents copy-contents))))
;; NEWNAME has wrong cached values.
(when t2
(with-parsed-tramp-file-name (expand-file-name newname) nil
(tramp-flush-file-properties v localname)))))))
;; We must do it file-wise.
(t (tramp-run-real-handler
#'copy-directory
(list dirname newname keep-date parents copy-contents)))))))
(defun tramp-sh-handle-rename-file
(filename newname &optional ok-if-already-exists)
@@ -5679,7 +5680,11 @@ raises an error."
(and
;; It shall be an out-of-band method.
(tramp-get-method-parameter vec 'tramp-copy-program)
;; There must be a size, otherwise the file doesn't exist.
;; There shouldn't be a multi-hop.
(or (not (tramp-multi-hop-p vec))
(null (cdr (tramp-compute-multi-hops vec))))
;; There must be a SIZE, otherwise the file doesn't exist. A zero
;; SIZE is used for directories.
(numberp size)
;; Either the file size is large enough, or (in rare cases) there
;; does not exist a remote encoding.

View File

@@ -577,12 +577,7 @@ arguments to pass to the OPERATION."
;; Set the mode.
(unless keep-date
(set-file-modes newname (tramp-default-file-modes dirname)))
;; When newname did exist, we have wrong cached values.
(when t2
(with-parsed-tramp-file-name newname nil
(tramp-flush-file-properties v localname))))
(set-file-modes newname (tramp-default-file-modes dirname))))
;; We must do it file-wise.
(t

View File

@@ -296,9 +296,8 @@ pair of the form (KEY VALUE). The following KEYs are defined:
- \"%a\" adds the pseudo-terminal allocation argument \"-t\" in
asynchronous processes, if the connection type is not `pipe'.
The existence of `tramp-login-args', combined with the
absence of `tramp-copy-args', is an indication that the
method is capable of multi-hops.
The existence of `tramp-login-args' is an indication that the method
is capable of multi-hops.
* `tramp-async-args'
When an asynchronous process is started, we know already that
@@ -2137,7 +2136,7 @@ of `current-buffer'."
"Execute BODY and return the result.
In case of an error, raise a `file-missing' error if FILENAME
does not exist, otherwise propagate the error."
(declare (indent 2) (debug (tramp-file-name-p form &rest body)))
(declare (indent 2) (debug t))
(let ((err (make-symbol "err")))
`(condition-case ,err
(let (signal-hook-function) ,@body)
@@ -2176,7 +2175,7 @@ Remaining args are Lisp expressions to be evaluated (inside an implicit
If VAR is nil, then we bind `v' to the structure and `method', `user',
`domain', `host', `port', `localname', `hop' to the components."
(declare (indent 2) (debug (form symbolp &rest body)))
(declare (indent 2) (debug t))
(let ((bindings
(mapcar
(lambda (elem)
@@ -3585,7 +3584,7 @@ User is always nil."
;;; Skeleton macros for file name handler functions.
(defmacro tramp-skeleton-copy-directory
(directory _newname &optional _keep-date _parents _copy-contents &rest body)
(directory newname &optional _keep-date _parents _copy-contents &rest body)
"Skeleton for `tramp-*-handle-copy-directory'.
BODY is the backend specific code."
(declare (indent 5) (debug t))
@@ -3596,7 +3595,12 @@ BODY is the backend specific code."
(unless (file-exists-p ,directory)
(tramp-error
(tramp-dissect-file-name ,directory) 'file-missing ,directory))
,@body))
,@body
;; NEWNAME has wrong cached values.
(when (tramp-tramp-file-p ,newname)
(with-parsed-tramp-file-name (expand-file-name ,newname) nil
(tramp-flush-file-properties v localname)))))
(defmacro tramp-skeleton-delete-directory (directory recursive trash &rest body)
"Skeleton for `tramp-*-handle-delete-directory'.
@@ -5148,7 +5152,7 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.")
"Whether the method of VEC is capable of multi-hops."
(let ((tramp-verbose 0))
(and (tramp-sh-file-name-handler-p vec)
(not (tramp-get-method-parameter vec 'tramp-copy-program)))))
(tramp-get-method-parameter vec 'tramp-login-args))))
(defun tramp-add-hops (vec)
"Add ad-hoc proxy definitions to `tramp-default-proxies-alist'."

View File

@@ -7,7 +7,7 @@
;; Maintainer: Michael Albinus <michael.albinus@gmx.de>
;; Keywords: comm, processes
;; Package: tramp
;; Version: 2.8.1
;; Version: 2.8.2-pre
;; Package-Requires: ((emacs "28.1"))
;; Package-Type: multi
;; URL: https://www.gnu.org/software/tramp/
@@ -40,7 +40,7 @@
;; ./configure" to change them.
;;;###tramp-autoload
(defconst tramp-version "2.8.1"
(defconst tramp-version "2.8.2-pre"
"This version of Tramp.")
;;;###tramp-autoload
@@ -76,7 +76,7 @@
;; Check for Emacs version.
(let ((x (if (not (string-version-lessp emacs-version "28.1"))
"ok"
(format "Tramp 2.8.1 is not fit for %s"
(format "Tramp 2.8.2-pre is not fit for %s"
(replace-regexp-in-string "\n" "" (emacs-version))))))
(unless (string-equal "ok" x) (error "%s" x)))