Commit 21f54fee authored by Michael Albinus's avatar Michael Albinus

Do not hardcode "/bin/sh" in compile. Bug#24338, Bug#29723

* doc/emacs/custom.texi (Connection Variables): New node.

* doc/emacs/emacs.texi (Top): Add entry for Connection Variables.

* doc/emacs/misc.texi (Single Shell): Mention default value for
remote buffers.

* doc/lispref/variables.texi (Connection Local Variables):
Describe `with-connection-local-variables' instead of
`with-connection-local-profiles'.

* doc/misc/tramp.texi (Remote processes): Refer to Emacs manual.
Mention default connection-local settings for `shell-file-name'
and `shell-command-switch'.

* etc/NEWS: Mention connection-local variables changes.

* lisp/files-x.el (hack-connection-local-variables):
Push connection-local variables to `file-local-variables-alist'.
(connection-local-criteria-for-default-directory): New defsubst.
(with-connection-local-variables): Rename from
`with-connection-local-profiles'.  Adapt implementation.

* lisp/files.el (hack-local-variables):
Call `hack-connection-local-variables'.

* lisp/shell.el (shell): Use `with-connection-local-variables'.

* lisp/subr.el (start-file-process-shell-command):
* lisp/progmodes/compile.el (compilation-start):
Use `with-connection-local-variables'.  Do not set "/bin/sh" for
remote buffers, trust settings of `shell-file-name'.  (Bug#24338),
(Bug#29723)

* lisp/net/ange-ftp.el (ange-ftp-compress, ange-ftp-uncompress):
Use `shell-command-switch'.

* lisp/net/tramp-adb.el (tramp-adb-connection-local-default-profile):
New defvar.  Add it to connection-local profiles after loading "shell".

* lisp/net/tramp-integration.el (tramp-compat): Require tramp-compat.
(tramp-compat-exec-path): Do not declare anymore.
(tramp-connection-local-safe-shell-file-names): New defvar.
(tramp-connection-local-default-profile): New defconst.  Activate
it after loading "shell".
(shell-file-name, shell-command-switch): Add safe-local-variable
property.

* lisp/net/tramp-sh.el (tramp-display-escape-sequence-regexp):
Add tramp-autoload cookie.

* test/lisp/files-x-tests.el (remote-shell-file-name):
Add safe-local-variable property to remote-* variables.
(tramp-connection-local-default-profile): Declare.
(files-x-test-with-connection-local-variables):
Rename from `files-x-test-with-connection-local-profiles'.  Adapt
implementation.

* test/lisp/net/tramp-tests.el
(tramp-test34-connection-local-variables): New test.
(tramp-test34-explicit-shell-file-name): Run it also for tramp-adb.
Bind connection-local-{profile,criteria}-alist.  Use tramp-adb
specific `shell-file-name'.  Add safe-local-variable property to
`explicit-shell-file-name' and `explicit-sh-args'.
parent c37bdd00
Pipeline #959 failed with stage
in 60 minutes and 1 second
...@@ -765,6 +765,8 @@ expects (@pxref{Examining}). ...@@ -765,6 +765,8 @@ expects (@pxref{Examining}).
* Locals:: Per-buffer values of variables. * Locals:: Per-buffer values of variables.
* File Variables:: How files can specify variable values. * File Variables:: How files can specify variable values.
* Directory Variables:: How variable values can be specified by directory. * Directory Variables:: How variable values can be specified by directory.
* Connection Variables:: Variables which are valid for buffers with a
remote default directory.
@end menu @end menu
@node Examining @node Examining
...@@ -1421,6 +1423,52 @@ variables are handled in the same way as unsafe file-local variables ...@@ -1421,6 +1423,52 @@ variables are handled in the same way as unsafe file-local variables
do not visit a file directly but perform work within a directory, such do not visit a file directly but perform work within a directory, such
as Dired buffers (@pxref{Dired}). as Dired buffers (@pxref{Dired}).
@node Connection Variables
@subsection Per-Connection Local Variables
@cindex local variables, for all remote connections
@cindex connection-local variables
@cindex per-connection local variables
Most of the variables reflect the situation on the local machine.
Often, they must use a different value when you operate in buffers
with a remote default directory. Think about the shell to be applied
when calling @code{shell} -- it might be @file{/bin/bash} on your
local machine, and @file{/bin/ksh} on a remote machine.
This can be accomplished with @dfn{connection-local variables}.
Directory and file local variables override connection-local
variables. Unsafe connection-local variables are handled in the same
way as unsafe file-local variables (@pxref{Safe File Variables}).
@findex connection-local-set-profile-variables
@findex connection-local-set-profiles
Connection-local variables are declared as a group of
variables/value pairs in a @dfn{profile}, using the
@code{connection-local-set-profile-variables} function. The function
@code{connection-local-set-profiles} activates profiles for a given
criteria, identifying a remote machine:
@example
(connection-local-set-profile-variables 'remote-ksh
'((shell-file-name . "/bin/ksh")
(shell-command-switch . "-c")))
(connection-local-set-profile-variables 'remote-bash
'((shell-file-name . "/bin/bash")
(shell-command-switch . "-c")))
(connection-local-set-profiles
'(:application tramp :machine "remotemachine") 'remote-ksh)
@end example
This code declares two different profiles, @code{remote-ksh} and
@code{remote-bash}. The profile @code{remote-ksh} is applied to all
buffers which have a remote default directory matching the regexp
@code{"remotemachine} as host name. Such a criteria can also
discriminate for the properties @code{:protocol} (this is the Tramp
method) or @code{:user} (a remote user name). The @code{nil} criteria
matches all buffers with a remote default directory.
@node Key Bindings @node Key Bindings
@section Customizing Key Bindings @section Customizing Key Bindings
@cindex key bindings @cindex key bindings
......
...@@ -1135,6 +1135,8 @@ Variables ...@@ -1135,6 +1135,8 @@ Variables
* Locals:: Per-buffer values of variables. * Locals:: Per-buffer values of variables.
* File Variables:: How files can specify variable values. * File Variables:: How files can specify variable values.
* Directory Variables:: How variable values can be specified by directory. * Directory Variables:: How variable values can be specified by directory.
* Connection Variables:: Variables which are valid for buffers with a
remote default directory.
Local Variables in Files Local Variables in Files
......
...@@ -795,6 +795,10 @@ to @command{gpg}. This will output the list of keys to the ...@@ -795,6 +795,10 @@ to @command{gpg}. This will output the list of keys to the
name is relative, Emacs searches the directories listed in name is relative, Emacs searches the directories listed in
@code{exec-path} (@pxref{Shell}). @code{exec-path} (@pxref{Shell}).
If the default directory is remote (@pxref{Remote Files}), the
default value is @file{/bin/sh}. This can be changed by declaring
@code{shell-file-name} connection-local (@pxref{Connection Variables}).
To specify a coding system for @kbd{M-!} or @kbd{M-|}, use the command To specify a coding system for @kbd{M-!} or @kbd{M-|}, use the command
@kbd{C-x @key{RET} c} immediately beforehand. @xref{Communication Coding}. @kbd{C-x @key{RET} c} immediately beforehand. @xref{Communication Coding}.
......
...@@ -2191,9 +2191,9 @@ This function looks for connection-local variables according to ...@@ -2191,9 +2191,9 @@ This function looks for connection-local variables according to
@var{criteria}, and immediately applies them in the current buffer. @var{criteria}, and immediately applies them in the current buffer.
@end defun @end defun
@defmac with-connection-local-profiles profiles &rest body @defmac with-connection-local-variables &rest body
All connection-local variables, which are specified by a connection All connection-local variables, which are specified by
profile in @var{profiles}, are applied. @code{default-directory}, are applied.
After that, @var{body} is executed, and the connection-local variables After that, @var{body} is executed, and the connection-local variables
are unwound. Example: are unwound. Example:
...@@ -2207,8 +2207,15 @@ are unwound. Example: ...@@ -2207,8 +2207,15 @@ are unwound. Example:
@end group @end group
@group @group
(with-connection-local-profiles '(remote-perl) (connection-local-set-profiles
do something useful) '(:application 'tramp :protocol "ssh" :machine "remotehost")
'remote-perl)
@end group
@group
(let ((default-directory "/ssh:remotehost:/working/dir/"))
(with-connection-local-variables
do something useful))
@end group @end group
@end example @end example
@end defmac @end defmac
......
...@@ -2970,7 +2970,7 @@ Starting with Emacs 26, you could use connection-local variables for ...@@ -2970,7 +2970,7 @@ Starting with Emacs 26, you could use connection-local variables for
setting different values of @code{explicit-shell-file-name} for setting different values of @code{explicit-shell-file-name} for
different remote hosts. different remote hosts.
@ifinfo @ifinfo
@pxref{Connection Local Variables, , , elisp} @xref{Connection Variables, , , emacs}
@end ifinfo @end ifinfo
@lisp @lisp
...@@ -3023,6 +3023,14 @@ host. Example: ...@@ -3023,6 +3023,14 @@ host. Example:
@kbd{M-x auto-revert-tail-mode @key{RET}} runs similarly showing @kbd{M-x auto-revert-tail-mode @key{RET}} runs similarly showing
continuous output. continuous output.
@code{shell-command} uses the variables @code{shell-file-name} and
@code{shell-command-switch} in order to determine which shell to run.
For remote hosts, their default values are @file{/bin/sh} and
@option{-c}, respectively (except for the @option{adb} method, which
uses @file{/system/bin/sh}). Like the variables in the previous
section, these variables can be changed via connection-local
variables.
@subsection Running @code{eshell} on a remote host @subsection Running @code{eshell} on a remote host
@cindex @code{eshell} @cindex @code{eshell}
......
...@@ -279,6 +279,17 @@ matches strings where the pattern appears as a subsequence. Put ...@@ -279,6 +279,17 @@ matches strings where the pattern appears as a subsequence. Put
simply, makes "foo" complete to both "barfoo" and "frodo". Add 'flex' simply, makes "foo" complete to both "barfoo" and "frodo". Add 'flex'
to 'completion-styles' or 'completion-category-overrides' to use it. to 'completion-styles' or 'completion-category-overrides' to use it.
** Connection-local variables
+++
*** Connection-local variables are applied by default like file-local
and directory-local variables.
+++
*** The macro 'with-connection-local-variables' has been renamed from
'with-connection-local-profiles'. No argument 'profiles' needed any
longer.
* Editing Changes in Emacs 27.1 * Editing Changes in Emacs 27.1
...@@ -994,7 +1005,12 @@ followed when Emacs writes the relevant history variables to the disk. ...@@ -994,7 +1005,12 @@ followed when Emacs writes the relevant history variables to the disk.
--- ---
*** Program name completion inside remote shells works now as expected. *** Program name completion inside remote shells works now as expected.
+++
*** The variable 'shell-file-name' can be set now as connection-local
variable for remote shells. It still defaults to "/bin/sh".
** Pcomplete ** Pcomplete
*** The function 'pcomplete-uniquify-list' has been renamed from *** The function 'pcomplete-uniquify-list' has been renamed from
'pcomplete-uniqify-list'. 'pcomplete-uniqify-list'.
......
...@@ -582,7 +582,7 @@ changed by the user.") ...@@ -582,7 +582,7 @@ changed by the user.")
(setq ignored-local-variables (setq ignored-local-variables
(cons 'connection-local-variables-alist ignored-local-variables)) (cons 'connection-local-variables-alist ignored-local-variables))
(defvar connection-local-profile-alist '() (defvar connection-local-profile-alist nil
"Alist mapping connection profiles to variable lists. "Alist mapping connection profiles to variable lists.
Each element in this list has the form (PROFILE VARIABLES). Each element in this list has the form (PROFILE VARIABLES).
PROFILE is the name of a connection profile (a symbol). PROFILE is the name of a connection profile (a symbol).
...@@ -590,7 +590,7 @@ VARIABLES is a list that declares connection-local variables for ...@@ -590,7 +590,7 @@ VARIABLES is a list that declares connection-local variables for
PROFILE. An element in VARIABLES is an alist whose elements are PROFILE. An element in VARIABLES is an alist whose elements are
of the form (VAR . VALUE).") of the form (VAR . VALUE).")
(defvar connection-local-criteria-alist '() (defvar connection-local-criteria-alist nil
"Alist mapping connection criteria to connection profiles. "Alist mapping connection criteria to connection profiles.
Each element in this list has the form (CRITERIA PROFILES). Each element in this list has the form (CRITERIA PROFILES).
CRITERIA is a plist identifying a connection and the application CRITERIA is a plist identifying a connection and the application
...@@ -685,7 +685,9 @@ This does nothing if `enable-connection-local-variables' is nil." ...@@ -685,7 +685,9 @@ This does nothing if `enable-connection-local-variables' is nil."
;; Loop over variables. ;; Loop over variables.
(dolist (variable (connection-local-get-profile-variables profile)) (dolist (variable (connection-local-get-profile-variables profile))
(unless (assq (car variable) connection-local-variables-alist) (unless (assq (car variable) connection-local-variables-alist)
(push variable connection-local-variables-alist)))))) (push variable connection-local-variables-alist))))
;; Push them to `file-local-variables-alist'.
(hack-local-variables-filter connection-local-variables-alist nil)))
;;;###autoload ;;;###autoload
(defun hack-connection-local-variables-apply (criteria) (defun hack-connection-local-variables-apply (criteria)
...@@ -697,24 +699,35 @@ will not be changed." ...@@ -697,24 +699,35 @@ will not be changed."
(copy-tree connection-local-variables-alist))) (copy-tree connection-local-variables-alist)))
(hack-local-variables-apply))) (hack-local-variables-apply)))
(defsubst connection-local-criteria-for-default-directory ()
"Return a connection-local criteria, which represents `default-directory'."
(when (file-remote-p default-directory)
`(:application tramp
:protocol ,(file-remote-p default-directory 'method)
:user ,(file-remote-p default-directory 'user)
:machine ,(file-remote-p default-directory 'host))))
;;;###autoload ;;;###autoload
(defmacro with-connection-local-profiles (profiles &rest body) (defmacro with-connection-local-variables (&rest body)
"Apply connection-local variables according to PROFILES in current buffer. "Apply connection-local variables according to `default-directory'.
Execute BODY, and unwind connection-local variables." Execute BODY, and unwind connection-local variables."
(declare (indent 1) (debug t)) (declare (debug t))
`(let ((enable-connection-local-variables t) `(if (file-remote-p default-directory)
(old-buffer-local-variables (buffer-local-variables)) (let ((enable-connection-local-variables t)
connection-local-variables-alist connection-local-criteria-alist) (old-buffer-local-variables (buffer-local-variables))
(apply 'connection-local-set-profiles nil ,profiles) connection-local-variables-alist)
(hack-connection-local-variables-apply nil) (hack-connection-local-variables-apply
(unwind-protect (connection-local-criteria-for-default-directory))
(progn ,@body) (unwind-protect
;; Cleanup. (progn ,@body)
(dolist (variable connection-local-variables-alist) ;; Cleanup.
(let ((elt (assq (car variable) old-buffer-local-variables))) (dolist (variable connection-local-variables-alist)
(if elt (let ((elt (assq (car variable) old-buffer-local-variables)))
(set (make-local-variable (car elt)) (cdr elt)) (if elt
(kill-local-variable (car variable)))))))) (set (make-local-variable (car elt)) (cdr elt))
(kill-local-variable (car variable)))))))
;; No connection-local variables to apply.
,@body))
......
...@@ -3590,6 +3590,11 @@ local variables, but directory-local variables may still be applied." ...@@ -3590,6 +3590,11 @@ local variables, but directory-local variables may still be applied."
result) result)
(unless (eq handle-mode t) (unless (eq handle-mode t)
(setq file-local-variables-alist nil) (setq file-local-variables-alist nil)
(when (file-remote-p default-directory)
(with-demoted-errors "Connection-local variables error: %s"
;; Note this is a no-op if enable-local-variables is nil.
(hack-connection-local-variables
(connection-local-criteria-for-default-directory))))
(with-demoted-errors "Directory-local variables error: %s" (with-demoted-errors "Directory-local variables error: %s"
;; Note this is a no-op if enable-local-variables is nil. ;; Note this is a no-op if enable-local-variables is nil.
(hack-dir-local-variables))) (hack-dir-local-variables)))
......
...@@ -4277,7 +4277,7 @@ NEWNAME should be the name to give the new compressed or uncompressed file.") ...@@ -4277,7 +4277,7 @@ NEWNAME should be the name to give the new compressed or uncompressed file.")
nil nil
t t
nil nil
"-c" shell-command-switch
(format "compress -f -c < %s > %s" tmp1 tmp2)) (format "compress -f -c < %s > %s" tmp1 tmp2))
(and ange-ftp-process-verbose (and ange-ftp-process-verbose
(ange-ftp-message "Compressing %s...done" abbr)) (ange-ftp-message "Compressing %s...done" abbr))
...@@ -4313,7 +4313,7 @@ NEWNAME should be the name to give the new compressed or uncompressed file.") ...@@ -4313,7 +4313,7 @@ NEWNAME should be the name to give the new compressed or uncompressed file.")
nil nil
t t
nil nil
"-c" shell-command-switch
(format "uncompress -c < %s > %s" tmp1 tmp2)) (format "uncompress -c < %s > %s" tmp1 tmp2))
(and ange-ftp-process-verbose (and ange-ftp-process-verbose
(ange-ftp-message "Uncompressing %s...done" abbr)) (ange-ftp-message "Uncompressing %s...done" abbr))
......
...@@ -1370,6 +1370,26 @@ connection if a previous connection has died for some reason." ...@@ -1370,6 +1370,26 @@ connection if a previous connection has died for some reason."
;; Mark it as connected. ;; Mark it as connected.
(tramp-set-connection-property p "connected" t))))))) (tramp-set-connection-property p "connected" t)))))))
;; Default settings for connection-local variables.
(defconst tramp-adb-connection-local-default-profile
'((shell-file-name . "/system/bin/sh")
(shell-command-switch . "-c"))
"Default connection-local variables for remote adb connections.")
(add-to-list 'tramp-connection-local-safe-shell-file-names "/system/bin/sh")
;; `connection-local-set-profile-variables' and
;; `connection-local-set-profiles' exists since Emacs 26.1.
(eval-after-load "shell"
'(progn
(tramp-compat-funcall
'connection-local-set-profile-variables
'tramp-adb-connection-local-default-profile
tramp-adb-connection-local-default-profile)
(tramp-compat-funcall
'connection-local-set-profiles
`(:application tramp :protocol ,tramp-adb-method)
'tramp-adb-connection-local-default-profile)))
(add-hook 'tramp-unload-hook (add-hook 'tramp-unload-hook
(lambda () (lambda ()
(unload-feature 'tramp-adb 'force))) (unload-feature 'tramp-adb 'force)))
......
...@@ -27,9 +27,10 @@ ...@@ -27,9 +27,10 @@
;;; Code: ;;; Code:
(require 'tramp-compat)
;; Pacify byte-compiler. ;; Pacify byte-compiler.
(require 'cl-lib) (require 'cl-lib)
(declare-function tramp-compat-exec-path "tramp")
(declare-function tramp-dissect-file-name "tramp") (declare-function tramp-dissect-file-name "tramp")
(declare-function tramp-file-name-equal-p "tramp") (declare-function tramp-file-name-equal-p "tramp")
(declare-function tramp-tramp-file-p "tramp") (declare-function tramp-tramp-file-p "tramp")
...@@ -170,6 +171,37 @@ NAME must be equal to `tramp-current-connection'." ...@@ -170,6 +171,37 @@ NAME must be equal to `tramp-current-connection'."
(remove-hook 'tramp-cleanup-all-connections-hook (remove-hook 'tramp-cleanup-all-connections-hook
#'tramp-recentf-cleanup-all))))) #'tramp-recentf-cleanup-all)))))
;;; Default connection-local variables for Tramp:
;;;###tramp-autoload
(defvar tramp-connection-local-safe-shell-file-names nil
"List of safe `shell-file-name' values for remote hosts.")
(add-to-list 'tramp-connection-local-safe-shell-file-names "/bin/sh")
(defconst tramp-connection-local-default-profile
'((shell-file-name . "/bin/sh")
(shell-command-switch . "-c"))
"Default connection-local variables for remote connections.")
(put 'shell-file-name 'safe-local-variable
(lambda (item)
(and (stringp item)
(member item tramp-connection-local-safe-shell-file-names))))
(put 'shell-command-switch 'safe-local-variable
(lambda (item) (and (stringp item) (string-equal item "-c"))))
;; `connection-local-set-profile-variables' and
;; `connection-local-set-profiles' exists since Emacs 26.1.
(eval-after-load "shell"
'(progn
(tramp-compat-funcall
'connection-local-set-profile-variables
'tramp-connection-local-default-profile
tramp-connection-local-default-profile)
(tramp-compat-funcall
'connection-local-set-profiles
`(:application tramp)
'tramp-connection-local-default-profile)))
(add-hook 'tramp-unload-hook (add-hook 'tramp-unload-hook
(lambda () (unload-feature 'tramp-integration 'force))) (lambda () (unload-feature 'tramp-integration 'force)))
......
...@@ -81,6 +81,7 @@ the default storage location, e.g. \"$HOME/.sh_history\"." ...@@ -81,6 +81,7 @@ the default storage location, e.g. \"$HOME/.sh_history\"."
(const :tag "Unset HISTFILE" t) (const :tag "Unset HISTFILE" t)
(string :tag "Redirect to a file"))) (string :tag "Redirect to a file")))
;;;###tramp-autoload
(defconst tramp-display-escape-sequence-regexp "\e[[;0-9]+m" (defconst tramp-display-escape-sequence-regexp "\e[[;0-9]+m"
"Terminal control escape sequences for display attributes.") "Terminal control escape sequences for display attributes.")
......
...@@ -1754,15 +1754,16 @@ Returns the compilation buffer created." ...@@ -1754,15 +1754,16 @@ Returns the compilation buffer created."
(if (fboundp 'make-process) (if (fboundp 'make-process)
(let ((proc (let ((proc
(if (eq mode t) (if (eq mode t)
;; comint uses `start-file-process'. ;; On remote hosts, the local `shell-file-name'
(get-buffer-process ;; might be useless.
(with-no-warnings (with-connection-local-variables
(comint-exec ;; comint uses `start-file-process'.
outbuf (downcase mode-name) (get-buffer-process
(if (file-remote-p default-directory) (with-no-warnings
"/bin/sh" (comint-exec
shell-file-name) outbuf (downcase mode-name)
nil `("-c" ,command)))) shell-file-name
nil `(,shell-command-switch ,command)))))
(start-file-process-shell-command (downcase mode-name) (start-file-process-shell-command (downcase mode-name)
outbuf command)))) outbuf command))))
;; Make the buffer's mode line show process state. ;; Make the buffer's mode line show process state.
......
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
(require 'comint) (require 'comint)
(require 'pcomplete) (require 'pcomplete)
(eval-when-compile (require 'files-x)) ;with-connection-local-variables
;;; Customization and Buffer Variables ;;; Customization and Buffer Variables
...@@ -721,23 +722,17 @@ Otherwise, one argument `-i' is passed to the shell. ...@@ -721,23 +722,17 @@ Otherwise, one argument `-i' is passed to the shell.
(with-current-buffer buffer (with-current-buffer buffer
(when (file-remote-p default-directory) (when (file-remote-p default-directory)
;; Apply connection-local variables.
(hack-connection-local-variables-apply
`(:application tramp
:protocol ,(file-remote-p default-directory 'method)
:user ,(file-remote-p default-directory 'user)
:machine ,(file-remote-p default-directory 'host)))
;; On remote hosts, the local `shell-file-name' might be useless. ;; On remote hosts, the local `shell-file-name' might be useless.
(if (and (called-interactively-p 'any) (with-connection-local-variables
(null explicit-shell-file-name) (if (and (called-interactively-p 'any)
(null (getenv "ESHELL"))) (null explicit-shell-file-name)
(set (make-local-variable 'explicit-shell-file-name) (null (getenv "ESHELL")))
(file-local-name (set (make-local-variable 'explicit-shell-file-name)
(expand-file-name (file-local-name
(read-file-name (expand-file-name
"Remote shell path: " default-directory shell-file-name (read-file-name
t shell-file-name))))))) "Remote shell path: " default-directory shell-file-name
t shell-file-name))))))))
;; The buffer's window must be correctly set when we call comint ;; The buffer's window must be correctly set when we call comint
;; (so that comint sets the COLUMNS env var properly). ;; (so that comint sets the COLUMNS env var properly).
......
...@@ -3185,11 +3185,12 @@ discouraged." ...@@ -3185,11 +3185,12 @@ discouraged."
"Start a program in a subprocess. Return the process object for it. "Start a program in a subprocess. Return the process object for it.
Similar to `start-process-shell-command', but calls `start-file-process'." Similar to `start-process-shell-command', but calls `start-file-process'."
(declare (advertised-calling-convention (name buffer command) "23.1")) (declare (advertised-calling-convention (name buffer command) "23.1"))
(start-file-process ;; On remote hosts, the local `shell-file-name' might be useless.
name buffer (with-connection-local-variables
(if (file-remote-p default-directory) "/bin/sh" shell-file-name) (start-file-process
(if (file-remote-p default-directory) "-c" shell-command-switch) name buffer
(mapconcat 'identity args " "))) shell-file-name shell-command-switch
(mapconcat 'identity args " "))))
(defun call-process-shell-command (command &optional infile buffer display (defun call-process-shell-command (command &optional infile buffer display
&rest args) &rest args)
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
'((remote-null-device . "/dev/null"))) '((remote-null-device . "/dev/null")))
(defconst files-x-test--variables4 (defconst files-x-test--variables4
'((remote-null-device . "null"))) '((remote-null-device . "null")))
(put 'remote-shell-file-name 'safe-local-variable #'identity)
(put 'remote-shell-command-switch 'safe-local-variable #'identity)
(put 'remote-shell-interactive-switch 'safe-local-variable #'identity)
(put 'remote-shell-login-switch 'safe-local-variable #'identity)
(put 'remote-null-device 'safe-local-variable #'identity)
(defconst files-x-test--application '(:application 'my-application)) (defconst files-x-test--application '(:application 'my-application))
(defconst files-x-test--another-application (defconst files-x-test--another-application
...@@ -268,7 +273,9 @@ ...@@ -268,7 +273,9 @@
(should-not (local-variable-p 'remote-shell-file-name)) (should-not (local-variable-p 'remote-shell-file-name))
(should-not (boundp 'remote-shell-file-name)))))) (should-not (boundp 'remote-shell-file-name))))))
(ert-deftest files-x-test-with-connection-local-profiles () (defvar tramp-connection-local-default-profile)
(ert-deftest files-x-test-with-connection-local-variables ()
"Test setting connection-local variables." "Test setting connection-local variables."
(let (connection-local-profile-alist connection-local-criteria-alist) (let (connection-local-profile-alist connection-local-criteria-alist)
...@@ -303,46 +310,48 @@ ...@@ -303,46 +310,48 @@
(string-equal (symbol-value 'remote-null-device) "/dev/null")) (string-equal (symbol-value 'remote-null-device) "/dev/null"))
;; A candidate connection-local variable is not bound yet. ;; A candidate connection-local variable is not bound yet.
(should-not (local-variable-p 'remote-shell-command-switch)) (should-not (local-variable-p 'remote-shell-command-switch))))
;; Use the macro.
(with-connection-local-profiles '(remote-bash remote-ksh)
;; All connection-local variables are set. They apply in
;; reverse order in `connection-local-variables-alist'.
;; This variable keeps only the variables to be set inside
;; the macro.
(should
(equal connection-local-variables-alist
(nreverse (copy-tree files-x-test--variables1))))
;; The variables exist also as local variables.
(should (local-variable-p 'remote-shell-file-name))
(should (local-variable-p 'remote-shell-command-switch))
;; The proper variable values are set. The settings from
;; `remote-bash' overwrite the same variables as in
;; `remote-ksh'.
(should
(string-equal (symbol-value 'remote-shell-file-name) "/bin/bash"))
(should
(string-equal (symbol-value 'remote-shell-command-switch) "-c")))
;; Everything is rewound. The old variable values are reset.
(should
(equal connection-local-variables-alist
(append
(nreverse (copy-tree files-x-test--variables3))
(nreverse (copy-tree files-x-test--variables2)))))
;; The variables exist also as local variables.
(should (local-variable-p 'remote-shell-file-name))
(should (local-variable-p 'remote-null-device))
;; The proper variable values are set. The settings from
;; `remote-ksh' are back.
(should
(string-equal (symbol-value 'remote-shell-file-name) "/bin/ksh"))
(should
(string-equal (symbol-value 'remote-null-device) "/dev/null"))
;; The variable set temporarily is not unbound, again. (with-temp-buffer
(should-not (local-variable-p 'remote-shell-command-switch)))))) ;; Use the macro. We need a remote `default-directory'.
(let ((enable-connection-local-variables t)
(default-directory "/method:host:")
(remote-null-device "null"))
(should-not connection-local-variables-alist)
(should-not (local-variable-p 'remote-shell-file-name))
(should-not (local-variable-p 'remote-null-device))
(should-not (boundp 'remote-shell-file-name))
(should (string-equal (symbol-value 'remote-null-device) "null"))
(with-connection-local-variables
;; All connection-local variables are set. They apply in
;; reverse order in `connection-local-variables-alist'.
;; Since we ha a remote default directory, Tramp's settings
;; are appended as well.
(should
(equal
connection-local-variables-alist
(append
(nreverse (copy-tree files-x-test--variables3))
(nreverse (copy-tree files-x-test--variables2))
(nreverse (copy-tree tramp-connection-local-default-profile)))))
;; The variables exist also as local variables.
(should (local-variable-p 'remote-shell-file-name))
(should (local-variable-p 'remote-null-device))
;; The proper variable values are set.
(should
(string-equal (symbol-value 'remote-shell-file-name) "/bin/ksh"))
(should
(string-equal (symbol-value 'remote-null-device) "/dev/null")))
;; Everything is rewound. The old variable values are reset.
(should-not connection-local-variables-alist)
;; The variables don't exist as local variables.
(should-not (local-variable-p 'remote-shell-file-name))
(should-not (local-variable-p 'remote-null-device))
;; The variable values are reset.
(should-not (boundp 'remote-shell-file-name))
(should (string-equal (symbol-value 'remote-null-device) "null"))))))
(provide 'files-x-tests) (provide 'files-x-tests)
;;; files-x-tests.el ends here ;;; files-x-tests.el ends here
...@@ -4274,12 +4274,78 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." ...@@ -4274,12 +4274,78 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(dolist (dir '("/mock:localhost#11111:" "/mock:localhost#22222:")) (dolist (dir '("/mock:localhost#11111:" "/mock:localhost#22222:"))
(tramp-cleanup-connection (tramp-dissect-file-name dir))))) (tramp-cleanup-connection (tramp-dissect-file-name dir)))))
;; Connection-local variables are enabled per default since Emacs 27.1.
(ert-deftest tramp-test34-connection-local-variables ()
"Check that connection-local variables are enabled."
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
;; Since Emacs 27.1.
(skip-unless (fboundp 'with-connection-local-variables))
;; `connection-local-set-profile-variables' and
;; `connection-local-set-profiles' exist since Emacs 26.1. We don't
;; want to see compiler warnings for older Emacsen.
(let* ((default-directory tramp-test-temporary-file-directory)
(tmp-name1 (tramp--test-make-temp-name))
(tmp-name2 (expand-file-name "foo" tmp-name1))
(enable-local-variables :all)
(enable-remote-dir-locals t)
kill-buffer-query-functions
connection-local-profile-alist connection-local-criteria-alist)
(unwind-protect
(progn
(make-directory tmp-name1)
(should (file-directory-p tmp-name1))
;; `local-variable' is buffer-local due to explicit setting.
(with-no-warnings
(defvar-local local-variable 'buffer))
(with-temp-buffer
(should (eq local-variable 'buffer)))
;; `local-variable' is connection-local due to Tramp.
(write-region "foo" nil tmp-name2)
(should (file-exists-p tmp-name2))
(with-no-warnings
(connection-local-set-profile-variables
'local-variable-profile
'((local-variable . connect)))
(connection-local-set-profiles
`(:application tramp
:protocol ,(file-remote-p default-directory 'method)
:user ,(file-remote-p default-directory 'user)
:machine ,(file-remote-p default-directory 'host))
'local-variable-profile))
(with-current-buffer (find-file-noselect tmp-name2)
(should (eq local-variable 'connect))