我如何告诉 Emacs TRAMP 对 ssh 使用特定参数?

我如何告诉 Emacs TRAMP 对 ssh 使用特定参数?

我正在尝试设置我的 Emacs TRAMP 以通过 ssh 访问远程文件,并且我想向 tramp 用于连接的 ssh 命令添加一些附加参数。有办法吗?

我可以通过直接操作变量来做到这一点tramp-methods,但这很麻烦。

答案1

我想出了自己的解决方案,但它有点太复杂了,不适合在这里发布。如果有人感兴趣,请评论这个答案,我会找个地方发布它。


编辑:根据要求,这是我的解决方案。

现在,设置一些函数用于附加到存储在的内置参数列表中tramp-methods

(defun tramp-get-method-parameter (method param)
  "Return the method parameter PARAM.
If the `tramp-methods' entry does not exist, return NIL."
  (let ((entry (assoc param (assoc method tramp-methods))))
    (when entry (cadr entry))))

(defun tramp-set-method-parameter (method param newvalue)
  "Set the method paramter PARAM to VALUE for METHOD.

If METHOD does not yet have PARAM, add it.
If METHOD does not exist, do nothing."
  (let ((method-params (assoc method tramp-methods)))
    (when method-params
          (let ((entry (assoc param method-params)))
        (if entry
            (setcar (cdr entry) newvalue)
          (setcdr (last method-params) '(param newvalue)))))))

(defun tramp-add-args (programs newargs)
  "Append NEWARGS to the argument list for any of PROGRAMS in `tramp-methods'.

PROGRAMS can be a list of strings, or a single string."
  ;; Allow a single program string or a list of matching programs.
  (when (stringp programs)
    (setq programs (list programs)))
  (message "%s" (list programs newargs))
  (loop for method in (mapcar 'car tramp-methods) do
        (let ((login-program (tramp-get-method-parameter method 'tramp-login-program))
              (copy-program (tramp-get-method-parameter method 'tramp-copy-program))
              (login-args (tramp-get-method-parameter method 'tramp-login-args))
              (copy-args (tramp-get-method-parameter method 'tramp-copy-args)))
          (message "Handling %s" method)
          (message "  Handling login program %s" login-program)
          (when (find login-program programs :test 'string=)
            (message "    Adding to login program %s" login-program)
            (tramp-set-method-parameter method 'tramp-login-args (append login-args newargs)))
          (message "  Handling copy program %s" login-program)
          (when (find copy-program programs :test 'string=)
            (message "    Adding to copy program %s" copy-program)
            (tramp-set-method-parameter method 'tramp-copy-args (append copy-args newargs))))))

最后,使用tramp-add-args将您想要的参数添加到所有基于 ssh 的方法中:

(tramp-add-args
 '("scp" "scp1" "scp2" "scp1_old" "scp2_old" "sftp" "rsync" "ssh" "ssh1" "ssh2" "ssh1_old" "ssh2_old" "scpx" "sshx")
 '(("-o" "ControlPath=~/.ssh/control/emacs-master-%%r@%%h:%%p" "-o" "ControlMaster=auto")))

奖励回合

我上面展示的代码设置了 ssh 的连接共享。如果您希望它可靠地工作,则需要在互联网连接断开时清除套接字文件。下面的代码可以实现这一点。

首先,创建一个名为的脚本ssh-cleanup并将其放入您的脚本中$PATH,并在其中输入以下内容:

#!/bin/sh
CONTROL_DIR="$HOME/.ssh/control"
find "$CONTROL_DIR" -type s | xargs --no-run-if-empty -- rm -f

此脚本会清理陈旧的控制文件,因为当您拔掉网线或断开无线连接而导致 ssh 终止时,这些文件将会被遗留。

现在设置 emacs 以在适当的时间运行此脚本:

(defun ssh-cleanup ()
  (ignore-errors
    (call-process "ssh-cleanup")))

(defadvice tramp-cleanup-all-connections (after cleanup-control-files activate)
  (ssh-cleanup))

现在,当您运行 时tramp-cleanup-all-connections,您还将清理 ssh 套接字目录。每次断开并重新连接到互联网时,您都应该运行此命令。

或者,您可以设置您的计算机来自动为您执行此操作。

超级奖励回合

如果您在 Linux 上使用网络管理器,您可以让 emacs 在连接或断开连接时为您执行操作。

(defcustom network-manager-connect-hook nil
  "List of functions to execute upon successful establishment of
  a network connection."
  :type 'hook
  :group 'network-manager)

(defcustom network-manager-disconnect-hook nil
  "List of functions to execute upon disconnection from the
  network."
  :type 'hook
  :group 'network-manager)

;; Only enable all of this if dbus is found
(when (require 'dbus nil nil)

  (defun network-manager-dbus-signal-handler (nmstate)
    "Execute the appropriate hook when Network Manager connects or
  disconnects."
    (case nmstate
      ((4 1) (run-hooks 'network-manager-disconnect-hook))
      (3 (run-hooks 'network-manager-connect-hook))))

  (defvar network-manager-dbus-registration nil)

  (defun network-manager-integration-enable ()
    (interactive)
    (network-manager-integration-disable) ; Make sure to clean up first
    (setq network-manager-dbus-registration
          (dbus-register-signal :system
                                "org.freedesktop.NetworkManager" "/org/freedesktop/NetworkManager"
                                "org.freedesktop.NetworkManager" "StateChanged"
                                'network-manager-dbus-signal-handler)))

  (defun network-manager-integration-disable ()
    (interactive)
    (when network-manager-dbus-registration
      (dbus-unregister-object network-manager-dbus-registration)
      (setq network-manager-dbus-registration nil)))

  ;; Finally, enable it
  (network-manager-integration-enable))

现在添加设置tramp-cleanup-all-connections为在断开连接时运行。

(add-hook 'network-manager-disconnect-hook 'tramp-cleanup-all-connections)

答案2

对于一次性使用,我想不出方便的方法。

对于更永久的设置,请在 ssh 级别进行配置(这样做的好处是也可以在 Emacs 之外工作)。在您的 中~/.ssh/config,使用附加选项定义主机别名,然后使用 Tramp 连接到该别名。例如~/.ssh/config

Host foo
HostName foo.example.com
User rt
ProxyCommand /usr/bin/nc -X connect -x proxy:3128 %h %p

然后/ssh:foo:/path/to/file在 Emacs 中打开。

相关内容