Subject: Re: bug#18623: 24.3; tramp: unhelpful error message when copy program is unavailable

From: Michael Albinus <[email-masked]>
Date: Sun, 21 Dec 2014 12:18:17 +0100

Zack Weinberg <[email-masked]> writes:

> `Cannot find copy program: rsync' is a perfectly sensible error message;
> this bug would be resolved if _that_ were what showed up in the echo area.

I've committed the following patch to the Tramp repo as well as to the
Emacs repo (branch emacs-24):

--8<---------------cut here---------------start------------->8---
*** /tmp/ediff13503WDN	2014-12-21 12:15:48.715138335 +0100
--- /home/albinus/src/tramp/lisp/tramp.el	2014-12-21 11:30:14.424791817 +0100
***************
*** 3086,3200 ****
    (setq filename (expand-file-name filename))
    (let (result local-copy remote-copy)
      (with-parsed-tramp-file-name filename nil
!       (with-tramp-progress-reporter
! 	  v 3 (format "Inserting `%s'" filename)
! 	(unwind-protect
! 	    (if (not (file-exists-p filename))
! 		(progn
! 		  ;; We don't raise a Tramp error, because it might be
! 		  ;; suppressed, like in `find-file-noselect-1'.
! 		  (tramp-message
! 		   v 1 "File not `%s' found on remote host" filename)
! 		  (signal 'file-error
! 			  (list "File not found on remote host" filename)))
! 
! 	      (if (and (tramp-local-host-p v)
! 		       (let (file-name-handler-alist)
! 			 (file-readable-p localname)))
! 		  ;; Short track: if we are on the local host, we can
! 		  ;; run directly.
! 		  (setq result
! 			(tramp-run-real-handler
! 			 'insert-file-contents
! 			 (list localname visit beg end replace)))
! 
! 		;; When we shall insert only a part of the file, we
! 		;; copy this part.  This works only for the shell file
! 		;; name handlers.
! 		(when (and (or beg end)
! 			   (tramp-get-method-parameter
! 			    (tramp-file-name-method v) 'tramp-login-program))
! 		  (setq remote-copy (tramp-make-tramp-temp-file v))
! 		  ;; This is defined in tramp-sh.el.  Let's assume
! 		  ;; this is loaded already.
! 		  (tramp-compat-funcall
! 		   'tramp-send-command
! 		   v
! 		   (cond
! 		    ((and beg end)
! 		     (format "dd bs=1 skip=%d if=%s count=%d of=%s"
! 			     beg (tramp-shell-quote-argument localname)
! 			     (- end beg) remote-copy))
! 		    (beg
! 		     (format "dd bs=1 skip=%d if=%s of=%s"
! 			     beg (tramp-shell-quote-argument localname)
! 			     remote-copy))
! 		    (end
! 		     (format "dd bs=1 count=%d if=%s of=%s"
! 			     end (tramp-shell-quote-argument localname)
! 			     remote-copy))))
! 		  (setq tramp-temp-buffer-file-name nil beg nil end nil))
! 
! 		;; `insert-file-contents-literally' takes care to
! 		;; avoid calling jka-compr.  By let-binding
! 		;; `inhibit-file-name-operation', we propagate that
! 		;; care to the `file-local-copy' operation.
! 		(setq local-copy
! 		      (let ((inhibit-file-name-operation
! 			     (when (eq inhibit-file-name-operation
! 				       'insert-file-contents)
! 			       'file-local-copy)))
! 			(cond
! 			 ((stringp remote-copy)
! 			  (file-local-copy
! 			   (tramp-make-tramp-file-name
! 			    method user host remote-copy)))
! 			 ((stringp tramp-temp-buffer-file-name)
! 			  (copy-file filename tramp-temp-buffer-file-name 'ok)
! 			  tramp-temp-buffer-file-name)
! 			 (t (file-local-copy filename)))))
! 
! 		;; When the file is not readable for the owner, it
! 		;; cannot be inserted, even if it is readable for the
! 		;; group or for everybody.
! 		(set-file-modes
! 		 local-copy (tramp-compat-octal-to-decimal "0600"))
! 
! 		(when (and (null remote-copy)
! 			   (tramp-get-method-parameter
! 			    method 'tramp-copy-keep-tmpfile))
! 		  ;; We keep the local file for performance reasons,
! 		  ;; useful for "rsync".
! 		  (setq tramp-temp-buffer-file-name local-copy))
! 
! 		;; We must ensure that `file-coding-system-alist'
! 		;; matches `local-copy'.  We must also use `visit',
! 		;; otherwise there might be an error in the
! 		;; `revert-buffer' function under XEmacs.
! 		(let ((file-coding-system-alist
! 		       (tramp-find-file-name-coding-system-alist
! 			filename local-copy)))
! 		  (setq result
! 			(insert-file-contents
! 			 local-copy visit beg end replace)))))
! 
! 	  ;; Save exit.
! 	  (progn
! 	    (when visit
! 	      (setq buffer-file-name filename)
! 	      (setq buffer-read-only (not (file-writable-p filename)))
! 	      (set-visited-file-modtime)
! 	      (set-buffer-modified-p nil))
! 	    (when (and (stringp local-copy)
! 		       (or remote-copy (null tramp-temp-buffer-file-name)))
! 	      (delete-file local-copy))
! 	    (when (stringp remote-copy)
! 	      (delete-file
! 	       (tramp-make-tramp-file-name method user host remote-copy)))))))
! 
!     ;; Result.
!     (list (expand-file-name filename)
! 	  (cadr result))))
  
  (defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
    "Like `load' for Tramp files."
--- 3086,3202 ----
    (setq filename (expand-file-name filename))
    (let (result local-copy remote-copy)
      (with-parsed-tramp-file-name filename nil
!       (unwind-protect
! 	  (if (not (file-exists-p filename))
! 	      (tramp-message v 0 "(New file)")
! 
! 	    (with-tramp-progress-reporter
! 		v 3 (format "Inserting `%s'" filename)
! 	      (condition-case err
! 		  (if (and (tramp-local-host-p v)
! 			   (let (file-name-handler-alist)
! 			     (file-readable-p localname)))
! 		      ;; Short track: if we are on the local host, we can
! 		      ;; run directly.
! 		      (setq result
! 			    (tramp-run-real-handler
! 			     'insert-file-contents
! 			     (list localname visit beg end replace)))
! 
! 		    ;; When we shall insert only a part of the file, we
! 		    ;; copy this part.  This works only for the shell file
! 		    ;; name handlers.
! 		    (when (and (or beg end)
! 			       (tramp-get-method-parameter
! 				(tramp-file-name-method v)
! 				'tramp-login-program))
! 		      (setq remote-copy (tramp-make-tramp-temp-file v))
! 		      ;; This is defined in tramp-sh.el.  Let's assume
! 		      ;; this is loaded already.
! 		      (tramp-compat-funcall
! 		       'tramp-send-command
! 		       v
! 		       (cond
! 			((and beg end)
! 			 (format "dd bs=1 skip=%d if=%s count=%d of=%s"
! 				 beg (tramp-shell-quote-argument localname)
! 				 (- end beg) remote-copy))
! 			(beg
! 			 (format "dd bs=1 skip=%d if=%s of=%s"
! 				 beg (tramp-shell-quote-argument localname)
! 				 remote-copy))
! 			(end
! 			 (format "dd bs=1 count=%d if=%s of=%s"
! 				 end (tramp-shell-quote-argument localname)
! 				 remote-copy))))
! 		      (setq tramp-temp-buffer-file-name nil beg nil end nil))
! 
! 		    ;; `insert-file-contents-literally' takes care to
! 		    ;; avoid calling jka-compr.  By let-binding
! 		    ;; `inhibit-file-name-operation', we propagate that
! 		    ;; care to the `file-local-copy' operation.
! 		    (setq local-copy
! 			  (let ((inhibit-file-name-operation
! 				 (when (eq inhibit-file-name-operation
! 					   'insert-file-contents)
! 				   'file-local-copy)))
! 			    (cond
! 			     ((stringp remote-copy)
! 			      (file-local-copy
! 			       (tramp-make-tramp-file-name
! 				method user host remote-copy)))
! 			     ((stringp tramp-temp-buffer-file-name)
! 			      (copy-file
! 			       filename tramp-temp-buffer-file-name 'ok)
! 			      tramp-temp-buffer-file-name)
! 			     (t (file-local-copy filename)))))
! 
! 		    ;; When the file is not readable for the owner, it
! 		    ;; cannot be inserted, even if it is readable for the
! 		    ;; group or for everybody.
! 		    (set-file-modes
! 		     local-copy (tramp-compat-octal-to-decimal "0600"))
! 
! 		    (when (and (null remote-copy)
! 			       (tramp-get-method-parameter
! 				method 'tramp-copy-keep-tmpfile))
! 		      ;; We keep the local file for performance reasons,
! 		      ;; useful for "rsync".
! 		      (setq tramp-temp-buffer-file-name local-copy))
! 
! 		    ;; We must ensure that `file-coding-system-alist'
! 		    ;; matches `local-copy'.  We must also use `visit',
! 		    ;; otherwise there might be an error in the
! 		    ;; `revert-buffer' function under XEmacs.
! 		    (let ((file-coding-system-alist
! 			   (tramp-find-file-name-coding-system-alist
! 			    filename local-copy)))
! 		      (setq result
! 			    (insert-file-contents
! 			     local-copy visit beg end replace))))
! 		(error
! 		 (add-hook 'find-file-not-found-functions
! 			   `(lambda () (signal ',(car err) ',(cdr err)))
! 			   nil t)
! 		 (signal (car err) (cdr err))))))
! 
! 	;; Save exit.
! 	(progn
! 	  (when visit
! 	    (setq buffer-file-name filename)
! 	    (setq buffer-read-only (not (file-writable-p filename)))
! 	    (set-visited-file-modtime)
! 	    (set-buffer-modified-p nil))
! 	  (when (and (stringp local-copy)
! 		     (or remote-copy (null tramp-temp-buffer-file-name)))
! 	    (delete-file local-copy))
! 	  (when (stringp remote-copy)
! 	    (delete-file
! 	     (tramp-make-tramp-file-name method user host remote-copy)))))
! 
!       ;; Result.
!       (list (expand-file-name filename)
! 	    (cadr result)))))
  
  (defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
    "Like `load' for Tramp files."
--8<---------------cut here---------------end--------------->8---

Could you, please, check whether it fits your needs?

Best regards, Michael.