Bad-ptr / persp-mode.el

named perspectives(set of buffers/window configs) for emacs
401 stars 44 forks source link

Tramp with multihop #16

Closed farosas closed 9 years ago

farosas commented 9 years ago

When using tramp with multihop (local host --> intermediate host --> remote host):

C-x C-f /ssh:intermediate_user@intermediate_host|ssh:remote_user@remote_host:path/filename

the persp-auto-save file gets written with:

(def-buffer "filename" "/ssh:remote_user@remote_host:path/filename" mode)

when restoring persp contents, tramp will timeout because remote_user@remote_host is not accessible.

Is there a way to restore these tramp buffers?

EDIT: I just noticed that after tramp times out, persp-mode will output a warning saying that the file no longer exists.

farosas commented 9 years ago

Just found out about tramp-default-proxies-alist:

tramp-default-proxies-alist is a variable defined in `tramp.el'.
Its value is
(("192\\.168\\.123\\.29" "root" "/ssh:user@host.com:"))

Original value was nil

Documentation:
Route to be followed for specific host/user pairs.
This is an alist of items (HOST USER PROXY).  The first matching
item specifies the proxy to be passed for a file name located on
a remote target matching USER@HOST.  HOST and USER are regular
expressions.  PROXY must be a Tramp filename without a localname
part.  Method and user name on PROXY are optional, which is
interpreted with the default values.  PROXY can contain the
patterns %h and %u, which are replaced by the strings matching
HOST or USER, respectively.

HOST, USER or PROXY could also be Lisp forms, which will be
evaluated.  The result must be a string or nil, which is
interpreted as a regular expression which always matches.

Linking this with my previous comment we have:

(def-buffer "filename" "/ssh:root@192.168.123.29:path/filename" mode)

If I edit persp-auto-save by hand to make it look like this:

(def-buffer "filename" "/ssh:user@host.com|root@192.168.123.29:path/filename" mode)

It works.

So I think it would be just a matter of checking the tramp-default-proxies-alist and concatenating the corresponding hosts to the path of the file.

What do you think?

Bad-ptr commented 9 years ago

What do you think?

But how will we know which item from proxies-alist to concatenate? Hm...

I can not check that by myself, so could you post here a value of the tramp-current-connection variable when you edit such a file? C-x C-f /ssh:intermediate_user@intermediate_host|ssh:remote_user@remote_host:path/filename RET M-: (message "TCC: %s" tramp-current-connection) RET

Bad-ptr commented 9 years ago

But how will we know which item from proxies-alist to concatenate?

heh nevermind, I misunderstood you. Just realised that the tramp-default-proxies-alist is an alist.)

farosas commented 9 years ago

Yes, but I still didn't find a way to know for sure that the buffer is a tramp buffer. I don't think checking the start of the buffer name for '/ssh:' is very reliable.

And btw, tramp-current-connection will not help us very much because it just shows the latest connection stabilished.

I'll look further into this today. Perhaps there is a 'trampp' predicate. =)

farosas commented 9 years ago

Hi, just an update on this. There really is a tramp-p predicate: tramp-tramp-file-p. And after almost writing it from scratch, I found a very handy function called: tramp-compute-multi-hops. I think these two will be enough. However, the return of tramp-compute-multi-hops is a list, so there is still a bit of work to do to produce a suitable file name.

I'll get back to you when I have something.

Bad-ptr commented 9 years ago

Ok, then something like this should work for you, I think:

(with-eval-after-load "persp-mode-autoloads"
  (defun persp-tramp-multi-hop-save-buffer-file-name (b)
    (let ((ret (buffer-file-name b))
          (tmh (tramp-compute-multi-hops
                (tramp-dissect-file-name (buffer-file-name b)))))
      (when tmh
        (let* (method user host filename proxy (out "")
                      (temp-out
                       (concat "/"
                               (dolist (item tmh out)
                                 (setq method   (aref item 0)
                                       user     (aref item 1)
                                       host     (aref item 2)
                                       filename (aref item 3)
                                       proxy    (aref item 4))
                                 (setq out
                                       (concat proxy
                                               out method ":" user "@" host
                                               (if (= (string-width filename) 0)
                                                   "|"
                                                 (concat ":" filename))))))))
          (setq ret
                (if (yes-or-no-p (concat
                                  "You are about to save a tramp file. Is it a correct file name to save?"
                                  "(" temp-out ")"))
                    temp-out
                  (read-string "Please enter a correct file name: " temp-out nil ret)))))
      ret))

  (add-to-list 'persp-save-buffer-functions
               #'(lambda (b)
                   (when (tramp-tramp-file-p (buffer-file-name b))
                     `(def-buffer ,(buffer-name b)
                        ,(persp-tramp-multi-hop-save-buffer-file-name b)
                        ,(buffer-local-value 'major-mode b))))))
farosas commented 9 years ago

Cool, it worked!

I used a slightly different function though (but it does the same):

(with-eval-after-load "persp-mode-autoloads"
  (defun persp-tramp-save-buffer-file-name (b)
    (let ((persp-tramp-file-name tramp-prefix-format)
          (tmh (tramp-compute-multi-hops (tramp-dissect-file-name (buffer-file-name b)))))
      (while tmh
        (let* ((hop (car tmh))
               (method   (tramp-file-name-method hop))
               (user     (tramp-file-name-user hop))
               (host     (tramp-file-name-host hop))
               (filename (tramp-file-name-localname hop)))
          (setq persp-tramp-file-name (concat
                                       persp-tramp-file-name
                                       method tramp-postfix-method-format
                                       user tramp-postfix-user-format
                                       host (if (= (string-width filename) 0)
                                                tramp-postfix-hop-format
                                              (concat tramp-postfix-host-format filename)))
                tmh (cdr tmh))
          persp-tramp-file-name))))

    (add-to-list 'persp-save-buffer-functions
               #'(lambda (b)
                   (when (tramp-tramp-file-p (buffer-file-name b))
                     `(def-buffer ,(buffer-name b)
                        ,(persp-tramp-save-buffer-file-name b)
                        ,(buffer-local-value 'major-mode b))))))

Do you intend to merge this? I could send a pull request with the new function.

Anyway, I think we can close this, thanks! =)

Bad-ptr commented 9 years ago

I could send a pull request with the new function.

It would be great.