summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Albinus <michael.albinus@gmx.de>2019-03-09 16:44:24 +0100
committerMichael Albinus <michael.albinus@gmx.de>2019-03-09 16:44:24 +0100
commit21f54feee8c83e2c5fd8eeb6741cbd479a7b19eb (patch)
tree3edf223c49dfedf09ec93804856954a9554a93cd
parentc37bdd00c7dcabaa3ca8405d9dc5122ed36f27e0 (diff)
downloademacs-21f54feee8c83e2c5fd8eeb6741cbd479a7b19eb.tar.gz
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'.
-rw-r--r--doc/emacs/custom.texi48
-rw-r--r--doc/emacs/emacs.texi2
-rw-r--r--doc/emacs/misc.texi4
-rw-r--r--doc/lispref/variables.texi17
-rw-r--r--doc/misc/tramp.texi10
-rw-r--r--etc/NEWS16
-rw-r--r--lisp/files-x.el51
-rw-r--r--lisp/files.el5
-rw-r--r--lisp/net/ange-ftp.el4
-rw-r--r--lisp/net/tramp-adb.el20
-rw-r--r--lisp/net/tramp-integration.el34
-rw-r--r--lisp/net/tramp-sh.el1
-rw-r--r--lisp/progmodes/compile.el19
-rw-r--r--lisp/shell.el27
-rw-r--r--lisp/subr.el11
-rw-r--r--test/lisp/files-x-tests.el89
-rw-r--r--test/lisp/net/tramp-tests.el77
17 files changed, 334 insertions, 101 deletions
diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi
index 474149fcae6..c649c170293 100644
--- a/doc/emacs/custom.texi
+++ b/doc/emacs/custom.texi
@@ -765,6 +765,8 @@ expects (@pxref{Examining}).
* Locals:: Per-buffer values of variables.
* File Variables:: How files can specify variable values.
* 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
@node Examining
@@ -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
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
@section Customizing Key Bindings
@cindex key bindings
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index 950ddc01123..7edc1a5fae1 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -1135,6 +1135,8 @@ Variables
* Locals:: Per-buffer values of variables.
* File Variables:: How files can specify variable values.
* 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
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index a3aa71e2672..7d7065a441a 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -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
@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
@kbd{C-x @key{RET} c} immediately beforehand. @xref{Communication Coding}.
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index f1e0e37e6d6..aca7d2f5e93 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -2191,9 +2191,9 @@ This function looks for connection-local variables according to
@var{criteria}, and immediately applies them in the current buffer.
@end defun
-@defmac with-connection-local-profiles profiles &rest body
-All connection-local variables, which are specified by a connection
-profile in @var{profiles}, are applied.
+@defmac with-connection-local-variables &rest body
+All connection-local variables, which are specified by
+@code{default-directory}, are applied.
After that, @var{body} is executed, and the connection-local variables
are unwound. Example:
@@ -2207,8 +2207,15 @@ are unwound. Example:
@end group
@group
-(with-connection-local-profiles '(remote-perl)
- do something useful)
+(connection-local-set-profiles
+ '(: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 example
@end defmac
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi
index db3b3f7fee5..ea6ad15dc3d 100644
--- a/doc/misc/tramp.texi
+++ b/doc/misc/tramp.texi
@@ -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
different remote hosts.
@ifinfo
-@pxref{Connection Local Variables, , , elisp}
+@xref{Connection Variables, , , emacs}
@end ifinfo
@lisp
@@ -3023,6 +3023,14 @@ host. Example:
@kbd{M-x auto-revert-tail-mode @key{RET}} runs similarly showing
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
@cindex @code{eshell}
diff --git a/etc/NEWS b/etc/NEWS
index 1095ecc7e5e..0a1d9ea2220 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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'
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
@@ -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.
++++
+*** The variable 'shell-file-name' can be set now as connection-local
+variable for remote shells. It still defaults to "/bin/sh".
+
** Pcomplete
+
*** The function 'pcomplete-uniquify-list' has been renamed from
'pcomplete-uniqify-list'.
diff --git a/lisp/files-x.el b/lisp/files-x.el
index c9abb695700..eedf630b71f 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -582,7 +582,7 @@ changed by the user.")
(setq 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.
Each element in this list has the form (PROFILE VARIABLES).
PROFILE is the name of a connection profile (a symbol).
@@ -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
of the form (VAR . VALUE).")
-(defvar connection-local-criteria-alist '()
+(defvar connection-local-criteria-alist nil
"Alist mapping connection criteria to connection profiles.
Each element in this list has the form (CRITERIA PROFILES).
CRITERIA is a plist identifying a connection and the application
@@ -685,7 +685,9 @@ This does nothing if `enable-connection-local-variables' is nil."
;; Loop over variables.
(dolist (variable (connection-local-get-profile-variables profile))
(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
(defun hack-connection-local-variables-apply (criteria)
@@ -697,24 +699,35 @@ will not be changed."
(copy-tree connection-local-variables-alist)))
(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
-(defmacro with-connection-local-profiles (profiles &rest body)
- "Apply connection-local variables according to PROFILES in current buffer.
+(defmacro with-connection-local-variables (&rest body)
+ "Apply connection-local variables according to `default-directory'.
Execute BODY, and unwind connection-local variables."
- (declare (indent 1) (debug t))
- `(let ((enable-connection-local-variables t)
- (old-buffer-local-variables (buffer-local-variables))
- connection-local-variables-alist connection-local-criteria-alist)
- (apply 'connection-local-set-profiles nil ,profiles)
- (hack-connection-local-variables-apply nil)
- (unwind-protect
- (progn ,@body)
- ;; Cleanup.
- (dolist (variable connection-local-variables-alist)
- (let ((elt (assq (car variable) old-buffer-local-variables)))
- (if elt
- (set (make-local-variable (car elt)) (cdr elt))
- (kill-local-variable (car variable))))))))
+ (declare (debug t))
+ `(if (file-remote-p default-directory)
+ (let ((enable-connection-local-variables t)
+ (old-buffer-local-variables (buffer-local-variables))
+ connection-local-variables-alist)
+ (hack-connection-local-variables-apply
+ (connection-local-criteria-for-default-directory))
+ (unwind-protect
+ (progn ,@body)
+ ;; Cleanup.
+ (dolist (variable connection-local-variables-alist)
+ (let ((elt (assq (car variable) old-buffer-local-variables)))
+ (if elt
+ (set (make-local-variable (car elt)) (cdr elt))
+ (kill-local-variable (car variable)))))))
+ ;; No connection-local variables to apply.
+ ,@body))
diff --git a/lisp/files.el b/lisp/files.el
index 9948bd4a034..77a194b085d 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -3590,6 +3590,11 @@ local variables, but directory-local variables may still be applied."
result)
(unless (eq handle-mode t)
(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"
;; Note this is a no-op if enable-local-variables is nil.
(hack-dir-local-variables)))
diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el
index 428bf32947b..5af9ea75ed1 100644
--- a/lisp/net/ange-ftp.el
+++ b/lisp/net/ange-ftp.el
@@ -4277,7 +4277,7 @@ NEWNAME should be the name to give the new compressed or uncompressed file.")
nil
t
nil
- "-c"
+ shell-command-switch
(format "compress -f -c < %s > %s" tmp1 tmp2))
(and ange-ftp-process-verbose
(ange-ftp-message "Compressing %s...done" abbr))
@@ -4313,7 +4313,7 @@ NEWNAME should be the name to give the new compressed or uncompressed file.")
nil
t
nil
- "-c"
+ shell-command-switch
(format "uncompress -c < %s > %s" tmp1 tmp2))
(and ange-ftp-process-verbose
(ange-ftp-message "Uncompressing %s...done" abbr))
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index eb3295ee352..b40e69ef634 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -1370,6 +1370,26 @@ connection if a previous connection has died for some reason."
;; Mark it as connected.
(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
(lambda ()
(unload-feature 'tramp-adb 'force)))
diff --git a/lisp/net/tramp-integration.el b/lisp/net/tramp-integration.el
index 2a461763480..946d7f8cbab 100644
--- a/lisp/net/tramp-integration.el
+++ b/lisp/net/tramp-integration.el
@@ -27,9 +27,10 @@
;;; Code:
+(require 'tramp-compat)
+
;; Pacify byte-compiler.
(require 'cl-lib)
-(declare-function tramp-compat-exec-path "tramp")
(declare-function tramp-dissect-file-name "tramp")
(declare-function tramp-file-name-equal-p "tramp")
(declare-function tramp-tramp-file-p "tramp")
@@ -170,6 +171,37 @@ NAME must be equal to `tramp-current-connection'."
(remove-hook 'tramp-cleanup-all-connections-hook
#'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
(lambda () (unload-feature 'tramp-integration 'force)))
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index ee16138f700..d9edcb14198 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -81,6 +81,7 @@ the default storage location, e.g. \"$HOME/.sh_history\"."
(const :tag "Unset HISTFILE" t)
(string :tag "Redirect to a file")))
+;;;###tramp-autoload
(defconst tramp-display-escape-sequence-regexp "\e[[;0-9]+m"
"Terminal control escape sequences for display attributes.")
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index b3f32c82316..3650b05607c 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -1754,15 +1754,16 @@ Returns the compilation buffer created."
(if (fboundp 'make-process)
(let ((proc
(if (eq mode t)
- ;; comint uses `start-file-process'.
- (get-buffer-process
- (with-no-warnings
- (comint-exec
- outbuf (downcase mode-name)
- (if (file-remote-p default-directory)
- "/bin/sh"
- shell-file-name)
- nil `("-c" ,command))))
+ ;; On remote hosts, the local `shell-file-name'
+ ;; might be useless.
+ (with-connection-local-variables
+ ;; comint uses `start-file-process'.
+ (get-buffer-process
+ (with-no-warnings
+ (comint-exec
+ outbuf (downcase mode-name)
+ shell-file-name
+ nil `(,shell-command-switch ,command)))))
(start-file-process-shell-command (downcase mode-name)
outbuf command))))
;; Make the buffer's mode line show process state.
diff --git a/lisp/shell.el b/lisp/shell.el
index 524a8848840..8a2d4489b8a 100644
--- a/lisp/shell.el
+++ b/lisp/shell.el
@@ -99,6 +99,7 @@
(require 'comint)
(require 'pcomplete)
+(eval-when-compile (require 'files-x)) ;with-connection-local-variables
;;; Customization and Buffer Variables
@@ -721,23 +722,17 @@ Otherwise, one argument `-i' is passed to the shell.
(with-current-buffer buffer
(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.
- (if (and (called-interactively-p 'any)
- (null explicit-shell-file-name)
- (null (getenv "ESHELL")))
- (set (make-local-variable 'explicit-shell-file-name)
- (file-local-name
- (expand-file-name
- (read-file-name
- "Remote shell path: " default-directory shell-file-name
- t shell-file-name)))))))
+ (with-connection-local-variables
+ (if (and (called-interactively-p 'any)
+ (null explicit-shell-file-name)
+ (null (getenv "ESHELL")))
+ (set (make-local-variable 'explicit-shell-file-name)
+ (file-local-name
+ (expand-file-name
+ (read-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
;; (so that comint sets the COLUMNS env var properly).
diff --git a/lisp/subr.el b/lisp/subr.el
index 5b0330745fa..4024c68e68d 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3185,11 +3185,12 @@ discouraged."
"Start a program in a subprocess. Return the process object for it.
Similar to `start-process-shell-command', but calls `start-file-process'."
(declare (advertised-calling-convention (name buffer command) "23.1"))
- (start-file-process
- name buffer
- (if (file-remote-p default-directory) "/bin/sh" shell-file-name)
- (if (file-remote-p default-directory) "-c" shell-command-switch)
- (mapconcat 'identity args " ")))
+ ;; On remote hosts, the local `shell-file-name' might be useless.
+ (with-connection-local-variables
+ (start-file-process
+ name buffer
+ shell-file-name shell-command-switch
+ (mapconcat 'identity args " "))))
(defun call-process-shell-command (command &optional infile buffer display
&rest args)
diff --git a/test/lisp/files-x-tests.el b/test/lisp/files-x-tests.el
index d678be409d1..568a8984479 100644
--- a/test/lisp/files-x-tests.el
+++ b/test/lisp/files-x-tests.el
@@ -35,6 +35,11 @@
'((remote-null-device . "/dev/null")))
(defconst files-x-test--variables4
'((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--another-application
@@ -268,7 +273,9 @@
(should-not (local-variable-p '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."
(let (connection-local-profile-alist connection-local-criteria-alist)
@@ -303,46 +310,48 @@
(string-equal (symbol-value 'remote-null-device) "/dev/null"))
;; A candidate connection-local variable is not bound yet.
- (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"))
+ (should-not (local-variable-p 'remote-shell-command-switch))))
- ;; The variable set temporarily is not unbound, again.
- (should-not (local-variable-p 'remote-shell-command-switch))))))
+ (with-temp-buffer
+ ;; 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)
;;; files-x-tests.el ends here
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 69d5ba8b7df..bf7cdfafabe 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -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:"))
(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))
+ (kill-buffer (current-buffer)))
+
+ ;; `local-variable' is dir-local due to existence of .dir-locals.el.
+ (write-region
+ "((nil . ((local-variable . dir))))" nil
+ (expand-file-name ".dir-locals.el" tmp-name1))
+ (should (file-exists-p (expand-file-name ".dir-locals.el" tmp-name1)))
+ (with-current-buffer (find-file-noselect tmp-name2)
+ (should (eq local-variable 'dir))
+ (kill-buffer (current-buffer)))
+
+ ;; `local-variable' is file-local due to specifying as file variable.
+ (write-region
+ "-*- mode: comint; local-variable: file; -*-" nil tmp-name2)
+ (should (file-exists-p tmp-name2))
+ (with-current-buffer (find-file-noselect tmp-name2)
+ (should (eq local-variable 'file))
+ (kill-buffer (current-buffer))))
+
+ ;; Cleanup.
+ (ignore-errors (delete-directory tmp-name1 'recursive)))))
+
;; The functions were introduced in Emacs 26.1.
(ert-deftest tramp-test34-explicit-shell-file-name ()
"Check that connection-local `explicit-shell-file-name' is set."
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
- (skip-unless (tramp--test-sh-p))
+ (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
;; Since Emacs 26.1.
(skip-unless (and (fboundp 'connection-local-set-profile-variables)
(fboundp 'connection-local-set-profiles)))
@@ -4288,7 +4354,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
;; `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)
- explicit-shell-file-name kill-buffer-query-functions)
+ explicit-shell-file-name kill-buffer-query-functions
+ connection-local-profile-alist connection-local-criteria-alist)
(unwind-protect
(progn
;; `shell-mode' would ruin our test, because it deletes all
@@ -4298,7 +4365,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(with-no-warnings
(connection-local-set-profile-variables
'remote-sh
- '((explicit-shell-file-name . "/bin/sh")
+ `((explicit-shell-file-name
+ . ,(if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh"))
(explicit-sh-args . ("-i"))))
(connection-local-set-profiles
`(:application tramp
@@ -4306,6 +4374,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
:user ,(file-remote-p default-directory 'user)
:machine ,(file-remote-p default-directory 'host))
'remote-sh))
+ (put 'explicit-shell-file-name 'safe-local-variable #'identity)
+ (put 'explicit-sh-args 'safe-local-variable #'identity)
;; Run interactive shell. Since the default directory is
;; remote, `explicit-shell-file-name' shall be set in order
@@ -4316,6 +4386,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(call-interactively #'shell)
(should explicit-shell-file-name)))
+ ;; Cleanup.
(put 'explicit-shell-file-name 'permanent-local nil)
(kill-buffer "*shell*"))))