1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-01 03:11:09 -08:00

* net/tramp.el (tramp-methods): New method "rsyncc".

(top): Add completion function for "rsyncc".
(tramp-message-show-message): New defvar.
(tramp-message, tramp-error): Use it.
(tramp-do-copy-or-rename-file-directly): Extend check for direct
remote copying.
(tramp-do-copy-or-rename-file-out-of-band): Handle new
`tramp-methods' entry `copy-env' of "rsyncc".
((tramp-handle-process-file): Do not flush all
caches when `process-file-side-effects' is set.
tramp-vc-registered-read-file-names): New defconst.
(tramp-vc-registered-file-names): New defvar.
(tramp-handle-vc-registered): Implement optimization strategy.
(tramp-run-real-handler): Add `tramp-vc-file-name-handler'.
(tramp-vc-file-name-handler): New defun.
(tramp-get-ls-command, tramp-get-test-command)
(tramp-get-file-exists-command, tramp-get-remote-ln)
(tramp-get-remote-perl, tramp-get-remote-stat)
(tramp-get-remote-id): Remove
superfluous `with-current-buffer'.
This commit is contained in:
Michael Albinus 2009-08-27 13:47:55 +00:00
parent 0ff2d6c28e
commit 946a5aeb7d

View file

@ -375,6 +375,21 @@ files conditionalize this setup based on the TERM environment variable."
(tramp-copy-args (("-e" "ssh") ("-t" "%k")))
(tramp-copy-keep-date t)
(tramp-password-end-of-line nil))
("rsyncc" (tramp-login-program "ssh")
(tramp-login-args (("%h") ("-l" "%u") ("-p" "%p")
("-o" "ControlPath=%t.%%r@%%h:%%p")
("-o" "ControlMaster=yes")
("-e" "none")))
(tramp-remote-sh "/bin/sh")
(tramp-copy-program "rsync")
(tramp-copy-args (("-t" "%k")))
(tramp-copy-env (("RSYNC_RSH")
(,(concat
"ssh"
" -o ControlPath=%t.%%r@%%h:%%p"
" -o ControlMaster=auto"))))
(tramp-copy-keep-date t)
(tramp-password-end-of-line nil))
("remcp" (tramp-login-program "remsh")
(tramp-login-args (("%h") ("-l" "%u")))
(tramp-remote-sh "/bin/sh")
@ -849,6 +864,8 @@ the info pages.")
"scp2_old" tramp-completion-function-alist-ssh)
(tramp-set-completion-function
"rsync" tramp-completion-function-alist-ssh)
(tramp-set-completion-function
"rsyncc" tramp-completion-function-alist-ssh)
(tramp-set-completion-function
"remcp" tramp-completion-function-alist-rsh)
(tramp-set-completion-function
@ -1788,6 +1805,25 @@ while (my $data = <STDIN>) {
Escape sequence %s is replaced with name of Perl binary.
This string is passed to `format', so percent characters need to be doubled.")
(defconst tramp-vc-registered-read-file-names
"echo \"(\"
for file in \"$@\"; do
if %s $file; then
echo \"(\\\"$file\\\" \\\"file-exists-p\\\" t)\"
else
echo \"(\\\"$file\\\" \\\"file-exists-p\\\" nil)\"
fi
if %s $file; then
echo \"(\\\"$file\\\" \\\"file-readable-p\\\" t)\"
else
echo \"(\\\"$file\\\" \\\"file-readable-p\\\" nil)\"
fi
done
echo \")\""
"Script to check existence of VC related files.
It must be send formatted with two strings; the tests for file
existence, and file readability.")
(defconst tramp-file-mode-type-map
'((0 . "-") ; Normal file (SVID-v2 and XPG2)
(1 . "p") ; fifo
@ -1938,6 +1974,11 @@ ARGS to actually emit the message (if applicable)."
;; The message.
(insert (apply 'format fmt-string args)))))
(defvar tramp-message-show-message t
"Show Tramp message in the minibuffer.
This variable is used to disable messages from `tramp-error'.
The messages are visible anyway, because an error is raised.")
(defsubst tramp-message (vec-or-proc level fmt-string &rest args)
"Emit a message depending on verbosity level.
VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
@ -1956,7 +1997,7 @@ applicable)."
;; Match data must be preserved!
(save-match-data
;; Display only when there is a minimum level.
(when (<= level 3)
(when (and tramp-message-show-message (<= level 3))
(apply 'message
(concat
(cond
@ -1987,11 +2028,14 @@ applicable)."
VEC-OR-PROC identifies the connection to use, SIGNAL is the
signal identifier to be raised, remaining args passed to
`tramp-message'. Finally, signal SIGNAL is raised."
(tramp-message
vec-or-proc 1 "%s"
(error-message-string
(list signal (get signal 'error-message) (apply 'format fmt-string args))))
(signal signal (list (apply 'format fmt-string args))))
(let (tramp-message-show-message)
(tramp-message
vec-or-proc 1 "%s"
(error-message-string
(list signal
(get signal 'error-message)
(apply 'format fmt-string args))))
(signal signal (list (apply 'format fmt-string args)))))
(defsubst tramp-error-with-buffer
(buffer vec-or-proc signal fmt-string &rest args)
@ -3298,10 +3342,11 @@ the uid and gid from FILENAME."
'rename-file (list localname1 localname2 ok-if-already-exists))))
;; We can do it directly with `tramp-send-command'
((let (file-name-handler-alist)
(and (file-readable-p (concat prefix localname1))
(file-writable-p
(file-name-directory (concat prefix localname2)))))
((and (file-readable-p (concat prefix localname1))
(file-writable-p
(file-name-directory (concat prefix localname2)))
(or (file-directory-p (concat prefix localname2))
(file-writable-p (concat prefix localname2))))
(tramp-do-copy-or-rename-file-directly
op (concat prefix localname1) (concat prefix localname2)
ok-if-already-exists keep-date t)
@ -3392,7 +3437,7 @@ the uid and gid from FILENAME."
The method used must be an out-of-band method."
(let ((t1 (tramp-tramp-file-p filename))
(t2 (tramp-tramp-file-p newname))
copy-program copy-args copy-keep-date port spec
copy-program copy-args copy-env copy-keep-date port spec
source target)
(with-parsed-tramp-file-name (if t1 filename newname) nil
@ -3445,7 +3490,15 @@ The method used must be an out-of-band method."
;; " " is indication for keep-date argument.
(delete " " (mapcar '(lambda (y) (format-spec y spec)) x)))
(unless (member "" x) (mapconcat 'identity x " ")))
(tramp-get-method-parameter method 'tramp-copy-args))))
(tramp-get-method-parameter method 'tramp-copy-args)))
copy-env
(delq
nil
(mapcar
'(lambda (x)
(setq x (mapcar '(lambda (y) (format-spec y spec)) x))
(unless (member "" x) (mapconcat 'identity x " ")))
(tramp-get-method-parameter method 'tramp-copy-env))))
;; Check for program.
(when (and (fboundp 'executable-find)
@ -3459,12 +3512,16 @@ The method used must be an out-of-band method."
(with-temp-buffer
;; The default directory must be remote.
(let ((default-directory
(file-name-directory (if t1 filename newname))))
(file-name-directory (if t1 filename newname)))
(process-environment (copy-sequence process-environment)))
;; Set the transfer process properties.
(tramp-set-connection-property
v "process-name" (buffer-name (current-buffer)))
(tramp-set-connection-property
v "process-buffer" (current-buffer))
(while copy-env
(tramp-message v 5 "%s=\"%s\"" (car copy-env) (cadr copy-env))
(setenv (pop copy-env) (pop copy-env)))
;; Use an asynchronous process. By this, password can
;; be handled. The default directory must be local, in
@ -4015,7 +4072,15 @@ beginning of local filename are not substituted."
;; Cleanup. We remove all file cache values for the connection,
;; because the remote process could have changed them.
(when tmpinput (delete-file tmpinput))
(tramp-flush-directory-property v "")
;; `process-file-side-effects' has been introduced with GNU
;; Emacs 23.2. If set to `nil', no remote file will be changed
;; by `program'. If it doesn't exist, we assume its default
;; value 't'.
(unless (and (boundp 'process-file-side-effects)
(not (symbol-value 'process-file-side-effects)))
(tramp-flush-directory-property v ""))
;; Return exit status.
(if (equal ret -1)
(keyboard-quit)
@ -4664,12 +4729,61 @@ Returns a file name in `tramp-auto-save-directory' for autosaving this file."
(tramp-message v 0 "Wrote %s" filename))
(run-hooks 'tramp-handle-write-region-hook)))))
(defvar tramp-vc-registered-file-names nil
"List used to collect file names, which are checked during `vc-registered'.")
;; VC backends check for the existence of various different special
;; files. This is very time consuming, because every single check
;; requires a remote command (the file cache must be invalidated).
;; Therefore, we apply a kind of optimization. We install the file
;; name handler `tramp-vc-file-name-handler', which does nothing but
;; remembers all file names for which `file-exists-p' or
;; `file-readable-p' has been applied. A first run of `vc-registered'
;; is performed. Afterwards, a script is applied for all collected
;; file names, using just one remote command. The result of this
;; script is used to fill the file cache with actual values. Now we
;; can reset the file name handlers, and we make a second run of
;; `vc-registered', which returns the expected result without sending
;; any other remote command.
(defun tramp-handle-vc-registered (file)
"Like `vc-registered' for Tramp files."
;; There could be new files, created by the vc backend. We disable
;; the file cache therefore.
(let ((tramp-cache-inhibit-cache t))
(tramp-run-real-handler 'vc-registered (list file))))
;; There could be new files, created by the vc backend. We cannot
;; reuse the old cache entries, therefore.
(with-parsed-tramp-file-name file nil
(let (tramp-vc-registered-file-names
(tramp-cache-inhibit-cache (current-time))
(file-name-handler-alist
`((,tramp-file-name-regexp . tramp-vc-file-name-handler))))
;; Here we collect only file names, which need an operation.
(tramp-run-real-handler 'vc-registered (list file))
(tramp-message v 10 "\n%s" tramp-vc-registered-file-names)
;; Send just one command, in order to fill the cache.
(tramp-maybe-send-script
v
(format tramp-vc-registered-read-file-names
(tramp-get-file-exists-command v)
(format "%s -r" (tramp-get-test-command v)))
"tramp_vc_registered_read_file_names")
(dolist
(elt
(tramp-send-command-and-read
v
(format
"tramp_vc_registered_read_file_names %s"
(mapconcat 'tramp-shell-quote-argument
tramp-vc-registered-file-names
" "))))
(tramp-set-file-property v (car elt) (cadr elt) (cadr (cdr elt)))))
;; Second run. Now all requests shall be answered from the file
;; cache. We unset `process-file-side-effects' in order to keep
;; the cache when `process-file' calls appear.
(let (process-file-side-effects)
(tramp-run-real-handler 'vc-registered (list file)))))
;;;###autoload
(progn (defun tramp-run-real-handler (operation args)
@ -4678,6 +4792,7 @@ First arg specifies the OPERATION, second arg is a list of arguments to
pass to the OPERATION."
(let* ((inhibit-file-name-handlers
`(tramp-file-name-handler
tramp-vc-file-name-handler
tramp-completion-file-name-handler
cygwin-mount-name-hook-function
cygwin-mount-map-drive-hook-function
@ -4881,6 +4996,30 @@ Fall back to normal file name handler if no Tramp handler exists."
(tramp-run-real-handler operation args))))))
(setq tramp-locked tl))))
(defun tramp-vc-file-name-handler (operation &rest args)
"Invoke special file name handler, which collects files to be handled."
(save-match-data
(let ((filename
(tramp-replace-environment-variables
(apply 'tramp-file-name-for-operation operation args)))
(fn (assoc operation tramp-file-name-handler-alist)))
(with-parsed-tramp-file-name filename nil
(cond
;; That's what we want: file names, for which checks are
;; applied. We assume, that VC uses only `file-exists-p' and
;; `file-readable-p' checks; otherwise we must extend the
;; list. We do not perform any action, but return nil, in
;; order to keep `vc-registered' running.
((and fn (memq operation '(file-exists-p file-readable-p)))
(add-to-list 'tramp-vc-registered-file-names localname 'append)
nil)
;; Tramp file name handlers like `expand-file-name'. They
;; must still work.
(fn
(save-match-data (apply (cdr fn) args)))
;; Default file name handlers, we don't care.
(t (tramp-run-real-handler operation args)))))))
;;;###autoload
(progn (defun tramp-completion-file-name-handler (operation &rest args)
"Invoke Tramp file name completion handler.
@ -7369,24 +7508,19 @@ necessary only. This function will be used in file name completion."
(defun tramp-get-ls-command (vec)
(with-connection-property vec "ls"
(with-current-buffer (tramp-get-buffer vec)
(tramp-message vec 5 "Finding a suitable `ls' command")
(or
(catch 'ls-found
(dolist (cmd '("ls" "gnuls" "gls"))
(let ((dl (tramp-get-remote-path vec))
result)
(while
(and
dl
(setq result
(tramp-find-executable vec cmd dl t t)))
;; Check parameter.
(when (zerop (tramp-send-command-and-check
vec (format "%s -lnd /" result)))
(throw 'ls-found result))
(setq dl (cdr dl))))))
(tramp-error vec 'file-error "Couldn't find a proper `ls' command")))))
(tramp-message vec 5 "Finding a suitable `ls' command")
(or
(catch 'ls-found
(dolist (cmd '("ls" "gnuls" "gls"))
(let ((dl (tramp-get-remote-path vec))
result)
(while (and dl (setq result (tramp-find-executable vec cmd dl t t)))
;; Check parameter.
(when (zerop (tramp-send-command-and-check
vec (format "%s -lnd /" result)))
(throw 'ls-found result))
(setq dl (cdr dl))))))
(tramp-error vec 'file-error "Couldn't find a proper `ls' command"))))
(defun tramp-get-ls-command-with-dired (vec)
(save-match-data
@ -7397,11 +7531,10 @@ necessary only. This function will be used in file name completion."
(defun tramp-get-test-command (vec)
(with-connection-property vec "test"
(with-current-buffer (tramp-get-buffer vec)
(tramp-message vec 5 "Finding a suitable `test' command")
(if (zerop (tramp-send-command-and-check vec "test 0"))
"test"
(tramp-find-executable vec "test" (tramp-get-remote-path vec))))))
(tramp-message vec 5 "Finding a suitable `test' command")
(if (zerop (tramp-send-command-and-check vec "test 0"))
"test"
(tramp-find-executable vec "test" (tramp-get-remote-path vec)))))
(defun tramp-get-test-nt-command (vec)
;; Does `test A -nt B' work? Use abominable `find' construct if it
@ -7426,65 +7559,56 @@ necessary only. This function will be used in file name completion."
(defun tramp-get-file-exists-command (vec)
(with-connection-property vec "file-exists"
(with-current-buffer (tramp-get-buffer vec)
(tramp-message vec 5 "Finding command to check if file exists")
(tramp-find-file-exists-command vec))))
(tramp-message vec 5 "Finding command to check if file exists")
(tramp-find-file-exists-command vec)))
(defun tramp-get-remote-ln (vec)
(with-connection-property vec "ln"
(with-current-buffer (tramp-get-buffer vec)
(tramp-message vec 5 "Finding a suitable `ln' command")
(tramp-find-executable vec "ln" (tramp-get-remote-path vec)))))
(tramp-message vec 5 "Finding a suitable `ln' command")
(tramp-find-executable vec "ln" (tramp-get-remote-path vec))))
(defun tramp-get-remote-perl (vec)
(with-connection-property vec "perl"
(with-current-buffer (tramp-get-buffer vec)
(tramp-message vec 5 "Finding a suitable `perl' command")
(or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
(tramp-find-executable vec "perl" (tramp-get-remote-path vec))))))
(tramp-message vec 5 "Finding a suitable `perl' command")
(or (tramp-find-executable vec "perl5" (tramp-get-remote-path vec))
(tramp-find-executable vec "perl" (tramp-get-remote-path vec)))))
(defun tramp-get-remote-stat (vec)
(with-connection-property vec "stat"
(with-current-buffer (tramp-get-buffer vec)
(tramp-message vec 5 "Finding a suitable `stat' command")
(let ((result (tramp-find-executable
vec "stat" (tramp-get-remote-path vec)))
tmp)
;; Check whether stat(1) returns usable syntax. %s does not
;; work on older AIX systems.
(when result
(setq tmp
;; We don't want to display an error message.
(with-temp-message (or (current-message) "")
(condition-case nil
(tramp-send-command-and-read
vec (format "%s -c '(\"%%N\" %%s)' /" result))
(error nil))))
(unless (and (listp tmp) (stringp (car tmp))
(string-match "^./.$" (car tmp))
(integerp (cadr tmp)))
(setq result nil)))
result))))
(tramp-message vec 5 "Finding a suitable `stat' command")
(let ((result (tramp-find-executable
vec "stat" (tramp-get-remote-path vec)))
tmp)
;; Check whether stat(1) returns usable syntax. %s does not
;; work on older AIX systems.
(when result
(setq tmp
;; We don't want to display an error message.
(with-temp-message (or (current-message) "")
(condition-case nil
(tramp-send-command-and-read
vec (format "%s -c '(\"%%N\" %%s)' /" result))
(error nil))))
(unless (and (listp tmp) (stringp (car tmp))
(string-match "^./.$" (car tmp))
(integerp (cadr tmp)))
(setq result nil)))
result)))
(defun tramp-get-remote-id (vec)
(with-connection-property vec "id"
(with-current-buffer (tramp-get-buffer vec)
(tramp-message vec 5 "Finding POSIX `id' command")
(or
(catch 'id-found
(let ((dl (tramp-get-remote-path vec))
result)
(while
(and
dl
(setq result
(tramp-find-executable vec "id" dl t t)))
;; Check POSIX parameter.
(when (zerop (tramp-send-command-and-check
vec (format "%s -u" result)))
(throw 'id-found result))
(setq dl (cdr dl)))))
(tramp-error vec 'file-error "Couldn't find a POSIX `id' command")))))
(tramp-message vec 5 "Finding POSIX `id' command")
(or
(catch 'id-found
(let ((dl (tramp-get-remote-path vec))
result)
(while (and dl (setq result (tramp-find-executable vec "id" dl t t)))
;; Check POSIX parameter.
(when (zerop (tramp-send-command-and-check
vec (format "%s -u" result)))
(throw 'id-found result))
(setq dl (cdr dl)))))
(tramp-error vec 'file-error "Couldn't find a POSIX `id' command"))))
(defun tramp-get-remote-uid (vec id-format)
(with-connection-property vec (format "uid-%s" id-format)
@ -7939,7 +8063,15 @@ Only works for Bourne-like shells."
;; tramp-server-local-variable-alist) to define any such variables
;; that they need to, which would then be let bound as appropriate
;; in tramp functions. (Jason Rumney)
;; * Optimize out-of-band copying, when both methods are scp-like.
;; * Optimize out-of-band copying, when both methods are scp-like (not
;; rsync).
;; * Keep a second connection open for out-of-band methods like scp or
;; rsync.
;; * Partial completion completes word constituents. I find it
;; acceptable if method completion works only after :, so that we
;; have "/s: TAB" offer completion for the method first, filenames
;; afterwards. (David Kastrup)
;; Functions for file-name-handler-alist:
;; diff-latest-backup-file -- in diff.el