a list of one or more of these symbols.
@end defun
-@defun executable-find program
+@defun executable-find program &optional remote
This function searches for the executable file of the named
@var{program} and returns the absolute file name of the executable,
including its file-name extensions, if any. It returns @code{nil} if
-the file is not found. The functions searches in all the directories
+the file is not found. The function searches in all the directories
in @code{exec-path}, and tries all the file-name extensions in
@code{exec-suffixes} (@pxref{Subprocess Creation}).
+
+If @var{remote} is non-@code{nil}, and @code{default-directory} is a
+remote directory, @var{program} is searched on the respective remote host.
@end defun
@node Changing Files
@code{directory-file-name},
@code{directory-files},
@code{directory-files-and-attributes},
-@code{dired-compress-file}, @code{dired-uncache},@*
-@code{expand-file-name},
+@code{dired-compress-file}, @code{dired-uncache},
+@code{exec-path}, @code{expand-file-name},@*
@code{file-accessible-directory-p},
@code{file-acl},
@code{file-attributes},
@code{directory-files},
@code{directory-files-and-at@discretionary{}{}{}tributes},
@code{dired-compress-file}, @code{dired-uncache},
-@code{expand-file-name},
+@code{exec-path}, @code{expand-file-name},
@code{file-accessible-direc@discretionary{}{}{}tory-p},
@code{file-acl},
@code{file-attributes},
independently of @env{PATH} can lead to confusing results.
@end defopt
+@defun exec-path
+The function @code{exec-path} is an extension of the respective
+variable. If @code{default-directory} indicates a remote directory,
+it returns a list of directories used for searching programs on the
+respective remote host. In case of a local @code{default-directory},
+the function returns just the value of the variable @code{exec-path}.
+@end defun
+
@node Shell Arguments
@section Shell Arguments
@cindex arguments for shell commands
@end defopt
When remote search paths are changed, local @value{tramp} caches must
-be recomputed. To force @value{tramp} to recompute afresh, exit
-Emacs, remove the persistent file (@pxref{Connection caching}), and
-restart Emacs.
+be recomputed. To force @value{tramp} to recompute afresh, call
+@kbd{M-x tramp-cleanup-this-connection @key{RET}} or friends
+(@pxref{Cleanup remote connections}).
@node Remote shell setup
---
** The German prefix and postfix input methods now support Capital sharp S.
++++
+** The new function 'exec-path' returns a directory list from a remote host.
+
++++
+** Function 'executable-find' supports an optional argument REMOTE.
+This triggers to search a program name on the remote host indicated by
+'default-directory'.
+
\f
* Editing Changes in Emacs 27.1
This means that pressing C-M-SPACE now selects the entire tree by
default, and not just the opening element.
-
** Eshell
---
Previously eshell/kill would fail if provided a kill signal to send to the
process. It now accepts signals specified either by name or by its number.
+** Shell
+
+---
+*** Program name completion inside remote shells works now as expected.
+
** Pcomplete
*** The function 'pcomplete-uniquify-list' has been renamed from
'pcomplete-uniqify-list'.
-
** Auth-source
---
overrides all system and Emacs-provided defaults. To get the old
method back, set 'mailcap-prefer-mailcap-viewers' to nil.
-
** URL
*** The file: handler no longer looks for index.html in directories if
such decisions (if they are to be made at all) are left to
higher-level functions.
-
** image-mode
*** image-mode started using ImageMagick by default for all images
some years back. It now respects 'imagemagick-types-inhibit' as a way
to disable that.
-
+++
** The new function 'read-answer' accepts either long or short answers
depending on the new customizable variable 'read-answer-short'.
errtype user-emacs-directory)))))
bestname))))
+(defun exec-path ()
+ "List of directories to search programs to run in remote subprocesses.
+The remote host is identified by `default-directory'. For remote
+hosts which do not support subprocesses, this returns `nil'.
+If `default-directory' is a local directory, the value of the variable
+`exec-path' is returned."
+ (let ((handler (find-file-name-handler default-directory 'exec-path)))
+ (if handler
+ (funcall handler 'exec-path)
+ exec-path)))
-(defun executable-find (command)
+(defun executable-find (command &optional remote)
"Search for COMMAND in `exec-path' and return the absolute file name.
-Return nil if COMMAND is not found anywhere in `exec-path'."
- ;; Use 1 rather than file-executable-p to better match the behavior of
- ;; call-process.
- (locate-file command exec-path exec-suffixes 1))
+Return nil if COMMAND is not found anywhere in `exec-path'. If
+REMOTE is non-nil, search on the remote host indicated by
+`default-directory' instead."
+ (if (and remote (file-remote-p default-directory))
+ (let ((res (locate-file
+ command
+ (mapcar
+ (lambda (x) (concat (file-remote-p default-directory) x))
+ (exec-path))
+ exec-suffixes 'file-executable-p)))
+ (when (stringp res) (file-local-name res)))
+ ;; Use 1 rather than file-executable-p to better match the
+ ;; behavior of call-process.
+ (locate-file command exec-path exec-suffixes 1)))
(defun load-library (library)
"Load the Emacs Lisp library named LIBRARY.
(put 'process-file 'ange-ftp 'ange-ftp-process-file)
(put 'start-file-process 'ange-ftp 'ignore)
(put 'shell-command 'ange-ftp 'ange-ftp-shell-command)
+(put 'exec-path 'ange-ftp 'ignore)
\f
;;; Define ways of getting at unmodified Emacs primitives,
;;; turning off our handler.
. tramp-adb-handle-directory-files-and-attributes)
(dired-compress-file . ignore)
(dired-uncache . tramp-handle-dired-uncache)
+ (exec-path . tramp-adb-handle-exec-path)
(expand-file-name . tramp-adb-handle-expand-file-name)
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . ignore)
(tramp-flush-connection-property v "process-name")
(tramp-flush-connection-property v "process-buffer"))))))
+(defun tramp-adb-handle-exec-path ()
+ "Like `exec-path' for Tramp files."
+ (append
+ (with-parsed-tramp-file-name default-directory nil
+ (with-tramp-connection-property v "remote-path"
+ (tramp-adb-send-command v "echo \\\"$PATH\\\"")
+ (split-string
+ (with-current-buffer (tramp-get-connection-buffer v)
+ ;; Read the expression.
+ (goto-char (point-min))
+ (read (current-buffer)))
+ ":" 'omit)))
+ ;; The equivalent to `exec-directory'.
+ `(,(file-local-name default-directory))))
+
(defun tramp-adb-get-device (vec)
"Return full host name from VEC to be used in shell execution.
E.g. a host name \"192.168.1.1#5555\" returns \"192.168.1.1:5555\"
(tramp-error
vec 'file-error "Cannot switch to user `%s'" user)))
- ;; Set "remote-path" connection property. This is needed
- ;; for eshell.
- (tramp-adb-send-command vec "echo \\\"$PATH\\\"")
- (tramp-set-connection-property
- vec "remote-path"
- (split-string
- (with-current-buffer (tramp-get-connection-buffer vec)
- ;; Read the expression.
- (goto-char (point-min))
- (read (current-buffer)))
- ":" 'omit))
-
;; Set connection-local variables.
(tramp-set-connection-local-variables vec)
. tramp-handle-directory-files-and-attributes)
(dired-compress-file . tramp-archive-handle-not-implemented)
(dired-uncache . tramp-archive-handle-dired-uncache)
+ (exec-path . ignore)
;; `expand-file-name' performed by default handler.
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . ignore)
(defconst tramp-compat-use-url-tramp-p (fboundp 'temporary-file-directory)
"Whether to use url-tramp.el.")
+;; `exec-path' is new in Emacs 27.1.
+(eval-and-compile
+ (if (fboundp 'exec-path)
+ (defalias 'tramp-compat-exec-path 'exec-path)
+ (defun tramp-compat-exec-path ()
+ "List of directories to search programs to run in remote subprocesses."
+ (let ((handler (find-file-name-handler default-directory 'exec-path)))
+ (if handler
+ (funcall handler 'exec-path)
+ exec-path)))))
+
(add-hook 'tramp-unload-hook
(lambda ()
(unload-feature 'tramp-loaddefs 'force)
. tramp-handle-directory-files-and-attributes)
(dired-compress-file . ignore)
(dired-uncache . tramp-handle-dired-uncache)
+ (exec-path . ignore)
(expand-file-name . tramp-gvfs-handle-expand-file-name)
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . ignore)
. tramp-sh-handle-directory-files-and-attributes)
(dired-compress-file . tramp-sh-handle-dired-compress-file)
(dired-uncache . tramp-handle-dired-uncache)
+ (exec-path . tramp-sh-handle-exec-path)
(expand-file-name . tramp-sh-handle-expand-file-name)
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . tramp-sh-handle-file-acl)
(keyboard-quit)
ret))))
+(defun tramp-sh-handle-exec-path ()
+ "Like `exec-path' for Tramp files."
+ (append
+ (tramp-get-remote-path (tramp-dissect-file-name default-directory))
+ ;; The equivalent to `exec-directory'.
+ `(,(file-local-name default-directory))))
+
(defun tramp-sh-handle-file-local-copy (filename)
"Like `file-local-copy' for Tramp files."
(with-parsed-tramp-file-name filename nil
. tramp-handle-directory-files-and-attributes)
(dired-compress-file . ignore)
(dired-uncache . tramp-handle-dired-uncache)
+ (exec-path . ignore)
(expand-file-name . tramp-smb-handle-expand-file-name)
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . tramp-smb-handle-file-acl)
((member operation
'(process-file shell-command start-file-process
;; Emacs 26+ only.
- make-nearby-temp-file temporary-file-directory))
+ make-nearby-temp-file temporary-file-directory
+ ;; Emacs 27+ only.
+ exec-path))
default-directory)
;; PROC.
((member operation
;; when `default-directory' points to another host.
(defun tramp-eshell-directory-change ()
"Set `eshell-path-env' to $PATH of the host related to `default-directory'."
+ ;; Remove last element of `(exec-path)', which is `exec-directory'.
(setq eshell-path-env
- (if (tramp-tramp-file-p default-directory)
- (with-parsed-tramp-file-name default-directory nil
- (mapconcat
- 'identity
- (or
- ;; When `tramp-own-remote-path' is in `tramp-remote-path',
- ;; the remote path is only set in the session cache.
- (tramp-get-connection-property
- (tramp-get-connection-process v) "remote-path" nil)
- (tramp-get-connection-property v "remote-path" nil))
- ":"))
- (getenv "PATH"))))
+ (mapconcat 'identity (butlast (tramp-compat-exec-path)) ":")))
(eval-after-load "esh-util"
'(progn
(set (make-local-variable 'comint-file-name-chars) shell-file-name-chars)
(set (make-local-variable 'comint-file-name-quote-list)
shell-file-name-quote-list)
+ (set (make-local-variable 'comint-file-name-prefix)
+ (file-remote-p default-directory))
(set (make-local-variable 'comint-dynamic-complete-functions)
shell-dynamic-complete-functions)
(setq-local comint-unquote-function #'shell--unquote-argument)
(start (if (zerop (length filename)) (point) (match-beginning 0)))
(end (if (zerop (length filename)) (point) (match-end 0)))
(filenondir (file-name-nondirectory filename))
- ; why cdr? see `shell-dynamic-complete-command'
- (path-dirs (append (cdr (reverse exec-path))
- (if (memq system-type '(windows-nt ms-dos)) '("."))))
+ (path-dirs
+ ;; Ignore `exec-directory', the last entry in `exec-path'.
+ (append (cdr (reverse (exec-path)))
+ (if (and (memq system-type '(windows-nt ms-dos))
+ (not (file-remote-p default-directory)))
+ '("."))))
(cwd (file-name-as-directory (expand-file-name default-directory)))
(ignored-extensions
(and comint-completion-fignore
(tramp-archive-cleanup-hash))))
;; The functions were introduced in Emacs 26.1.
-(ert-deftest tramp-archive-test37-make-nearby-temp-file ()
+(ert-deftest tramp-archive-test38-make-nearby-temp-file ()
"Check `make-nearby-temp-file' and `temporary-file-directory'."
(skip-unless tramp-archive-enabled)
;; Since Emacs 26.1.
(delete-directory tmp-file)
(should-not (file-exists-p tmp-file))))
-(ert-deftest tramp-archive-test40-file-system-info ()
+(ert-deftest tramp-archive-test41-file-system-info ()
"Check that `file-system-info' returns proper values."
(skip-unless tramp-archive-enabled)
;; Since Emacs 27.1.
(zerop (nth 1 fsi))
(zerop (nth 2 fsi))))))
-(ert-deftest tramp-archive-test42-auto-load ()
+(ert-deftest tramp-archive-test43-auto-load ()
"Check that `tramp-archive' autoloads properly."
(skip-unless tramp-archive-enabled)
;; Autoloading tramp-archive works since Emacs 27.1.
(mapconcat 'shell-quote-argument load-path " -L ")
(shell-quote-argument (format code file)))))))))
-(ert-deftest tramp-archive-test42-delay-load ()
+(ert-deftest tramp-archive-test43-delay-load ()
"Check that `tramp-archive' is loaded lazily, only when needed."
(skip-unless tramp-archive-enabled)
;; Autoloading tramp-archive works since Emacs 27.1.
;; remote host, set this environment variable to "/dev/null" or
;; whatever is appropriate on your system.
-;; For slow remote connections, `tramp-test41-asynchronous-requests'
+;; For slow remote connections, `tramp-test42-asynchronous-requests'
;; might be too heavy. Setting $REMOTE_PARALLEL_PROCESSES to a proper
;; value less than 10 could help.
(put 'explicit-shell-file-name 'permanent-local nil)
(kill-buffer "*shell*"))))
-(ert-deftest tramp-test34-vc-registered ()
+;; The function was introduced in Emacs 27.1.
+(ert-deftest tramp-test34-exec-path ()
+ "Check `exec-path' and `executable-find'."
+ (skip-unless (tramp--test-enabled))
+ (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+ ;; Since Emacs 27.1.
+ (skip-unless (boundp 'exec-path))
+
+ (let ((tmp-name (tramp--test-make-temp-name))
+ (default-directory tramp-test-temporary-file-directory))
+ (unwind-protect
+ (progn
+ (should (consp (with-no-warnings (exec-path))))
+ ;; Last element is the `exec-directory'.
+ (should
+ (string-equal
+ (car (last (with-no-warnings (exec-path))))
+ (file-local-name default-directory)))
+ ;; The shell "sh" shall always exist.
+ (should (executable-find "sh" 'remote))
+ ;; Since the last element in `exec-path' is the current
+ ;; directory, an executable file in that directory will be
+ ;; found.
+ (write-region "foo" nil tmp-name)
+ (should (file-exists-p tmp-name))
+ (set-file-modes tmp-name #o777)
+ (should (file-executable-p tmp-name))
+ (should
+ (string-equal
+ (executable-find (file-name-nondirectory tmp-name) 'remote)
+ (file-local-name tmp-name)))
+ (should-not
+ (executable-find
+ (concat (file-name-nondirectory tmp-name) "foo") 'remote)))
+
+ ;; Cleanup.
+ (ignore-errors (delete-file tmp-name)))))
+
+(ert-deftest tramp-test35-vc-registered ()
"Check `vc-registered'."
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
;; Cleanup.
(ignore-errors (delete-directory tmp-name1 'recursive))))))
-(ert-deftest tramp-test35-make-auto-save-file-name ()
+(ert-deftest tramp-test36-make-auto-save-file-name ()
"Check `make-auto-save-file-name'."
(skip-unless (tramp--test-enabled))
(ignore-errors (delete-file tmp-name1))
(ignore-errors (delete-directory tmp-name2 'recursive))))))
-(ert-deftest tramp-test36-find-backup-file-name ()
+(ert-deftest tramp-test37-find-backup-file-name ()
"Check `find-backup-file-name'."
(skip-unless (tramp--test-enabled))
(ignore-errors (delete-directory tmp-name2 'recursive))))))
;; The functions were introduced in Emacs 26.1.
-(ert-deftest tramp-test37-make-nearby-temp-file ()
+(ert-deftest tramp-test38-make-nearby-temp-file ()
"Check `make-nearby-temp-file' and `temporary-file-directory'."
(skip-unless (tramp--test-enabled))
;; Since Emacs 26.1.
(ignore-errors (delete-directory tmp-name2 'recursive))))))
(defun tramp--test-special-characters ()
- "Perform the test in `tramp-test38-special-characters*'."
+ "Perform the test in `tramp-test39-special-characters*'."
;; Newlines, slashes and backslashes in file names are not
;; supported. So we don't test. And we don't test the tab
;; character on Windows or Cygwin, because the backslash is
files (list (mapconcat 'identity files ""))))))
;; These tests are inspired by Bug#17238.
-(ert-deftest tramp-test38-special-characters ()
+(ert-deftest tramp-test39-special-characters ()
"Check special characters in file names."
(skip-unless (tramp--test-enabled))
(skip-unless (not (tramp--test-rsync-p)))
(tramp--test-special-characters))
-(ert-deftest tramp-test38-special-characters-with-stat ()
+(ert-deftest tramp-test39-special-characters-with-stat ()
"Check special characters in file names.
Use the `stat' command."
:tags '(:expensive-test)
tramp-connection-properties)))
(tramp--test-special-characters)))
-(ert-deftest tramp-test38-special-characters-with-perl ()
+(ert-deftest tramp-test39-special-characters-with-perl ()
"Check special characters in file names.
Use the `perl' command."
:tags '(:expensive-test)
tramp-connection-properties)))
(tramp--test-special-characters)))
-(ert-deftest tramp-test38-special-characters-with-ls ()
+(ert-deftest tramp-test39-special-characters-with-ls ()
"Check special characters in file names.
Use the `ls' command."
:tags '(:expensive-test)
(tramp--test-special-characters)))
(defun tramp--test-utf8 ()
- "Perform the test in `tramp-test39-utf8*'."
+ "Perform the test in `tramp-test40-utf8*'."
(let* ((utf8 (if (and (eq system-type 'darwin)
(memq 'utf-8-hfs (coding-system-list)))
'utf-8-hfs 'utf-8))
(replace-regexp-in-string "[\t\n/.?]" "" x)))
language-info-alist)))))))
-(ert-deftest tramp-test39-utf8 ()
+(ert-deftest tramp-test40-utf8 ()
"Check UTF8 encoding in file names and file contents."
(skip-unless (tramp--test-enabled))
(skip-unless (not (tramp--test-docker-p)))
(tramp--test-utf8))
-(ert-deftest tramp-test39-utf8-with-stat ()
+(ert-deftest tramp-test40-utf8-with-stat ()
"Check UTF8 encoding in file names and file contents.
Use the `stat' command."
:tags '(:expensive-test)
tramp-connection-properties)))
(tramp--test-utf8)))
-(ert-deftest tramp-test39-utf8-with-perl ()
+(ert-deftest tramp-test40-utf8-with-perl ()
"Check UTF8 encoding in file names and file contents.
Use the `perl' command."
:tags '(:expensive-test)
tramp-connection-properties)))
(tramp--test-utf8)))
-(ert-deftest tramp-test39-utf8-with-ls ()
+(ert-deftest tramp-test40-utf8-with-ls ()
"Check UTF8 encoding in file names and file contents.
Use the `ls' command."
:tags '(:expensive-test)
tramp-connection-properties)))
(tramp--test-utf8)))
-(ert-deftest tramp-test40-file-system-info ()
+(ert-deftest tramp-test41-file-system-info ()
"Check that `file-system-info' returns proper values."
(skip-unless (tramp--test-enabled))
;; Since Emacs 27.1.
(ert-fail (format "`%s' timed out" (ert-test-name (ert-running-test)))))
;; This test is inspired by Bug#16928.
-(ert-deftest tramp-test41-asynchronous-requests ()
+(ert-deftest tramp-test42-asynchronous-requests ()
"Check parallel asynchronous requests.
Such requests could arrive from timers, process filters and
process sentinels. They shall not disturb each other."
(ignore-errors (delete-directory tmp-name 'recursive)))))))
;; This test is inspired by Bug#29163.
-(ert-deftest tramp-test42-auto-load ()
+(ert-deftest tramp-test43-auto-load ()
"Check that Tramp autoloads properly."
(let ((default-directory (expand-file-name temporary-file-directory))
(code
(mapconcat 'shell-quote-argument load-path " -L ")
(shell-quote-argument code)))))))
-(ert-deftest tramp-test42-delay-load ()
+(ert-deftest tramp-test43-delay-load ()
"Check that Tramp is loaded lazily, only when needed."
;; The autoloaded Tramp objects are different since Emacs 26.1. We
;; cannot test older Emacsen, therefore.
(mapconcat 'shell-quote-argument load-path " -L ")
(shell-quote-argument (format code tm)))))))))
-(ert-deftest tramp-test42-recursive-load ()
+(ert-deftest tramp-test43-recursive-load ()
"Check that Tramp does not fail due to recursive load."
(skip-unless (tramp--test-enabled))
(mapconcat 'shell-quote-argument load-path " -L ")
(shell-quote-argument code))))))))
-(ert-deftest tramp-test42-remote-load-path ()
+(ert-deftest tramp-test43-remote-load-path ()
"Check that Tramp autoloads its packages with remote `load-path'."
;; The autoloaded Tramp objects are different since Emacs 26.1. We
;; cannot test older Emacsen, therefore.
(mapconcat 'shell-quote-argument load-path " -L ")
(shell-quote-argument code)))))))
-(ert-deftest tramp-test43-unload ()
+(ert-deftest tramp-test44-unload ()
"Check that Tramp and its subpackages unload completely.
Since it unloads Tramp, it shall be the last test to run."
:tags '(:expensive-test)
;; * file-name-case-insensitive-p
;; * Work on skipped tests. Make a comment, when it is impossible.
-;; * Revisit expensive tests, once problems in tramp-error are solved.
+;; * Revisit expensive tests, once problems in `tramp-error' are solved.
;; * Fix `tramp-test05-expand-file-name-relative' in `expand-file-name'.
;; * Fix `tramp-test06-directory-file-name' for `ftp'.
;; * Investigate, why `tramp-test11-copy-file' and `tramp-test12-rename-file'
;; do not work properly for `owncloud'.
;; * Fix `tramp-test29-start-file-process' on MS Windows (`process-send-eof'?).
;; * Fix `tramp-test30-interrupt-process', timeout doesn't work reliably.
-;; * Fix Bug#16928 in `tramp-test41-asynchronous-requests'.
+;; * Fix Bug#16928 in `tramp-test42-asynchronous-requests'.
(provide 'tramp-tests)
;;; tramp-tests.el ends here