From 605a20a98823768578d6faed5f04cb00e57da2bb Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Tue, 24 Nov 2009 10:25:54 +0000 Subject: [PATCH] Improve handling of processes on remote hosts. * eshell/esh-util.el (eshell-path-env): New defvar. (eshell-parse-colon-path): New defun. (eshell-file-attributes): Use `eshell-parse-colon-path'. * eshell/esh-ext.el (eshell-search-path): Use `eshell-parse-colon-path'. (eshell-remote-command): Remove argument HANDLER. (eshell-external-command): Check for FTP remote connection. * eshell/esh-proc.el (eshell-gather-process-output): Use `file-truename', in order to start also symlinked files. Apply `start-file-process' instead of `start-process'. Shorten `command' to the local file name part. * eshell/em-cmpl.el (eshell-complete-commands-list): Use `eshell-parse-colon-path'. * eshell/em-unix.el (eshell/du): Check for FTP remote connection. * net/tramp.el (tramp-eshell-directory-change): New defun. Add it to `eshell-directory-change-hook'. --- lisp/ChangeLog | 26 +++++++++++++++++++++ lisp/eshell/em-cmpl.el | 2 +- lisp/eshell/em-unix.el | 5 ++-- lisp/eshell/esh-ext.el | 37 +++++++++++------------------ lisp/eshell/esh-proc.el | 9 +++---- lisp/eshell/esh-util.el | 52 ++++++++++++++++++++++++----------------- lisp/net/tramp.el | 29 +++++++++++++++++++++++ 7 files changed, 108 insertions(+), 52 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 054ff8d268b..03fdcf9a1bc 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,29 @@ +2009-11-24 Michael Albinus + + Improve handling of processes on remote hosts. + + * eshell/esh-util.el (eshell-path-env): New defvar. + (eshell-parse-colon-path): New defun. + (eshell-file-attributes): Use `eshell-parse-colon-path'. + + * eshell/esh-ext.el (eshell-search-path): Use + `eshell-parse-colon-path'. + (eshell-remote-command): Remove argument HANDLER. + (eshell-external-command): Check for FTP remote connection. + + * eshell/esh-proc.el (eshell-gather-process-output): Use + `file-truename', in order to start also symlinked files. Apply + `start-file-process' instead of `start-process'. Shorten `command' + to the local file name part. + + * eshell/em-cmpl.el (eshell-complete-commands-list): Use + `eshell-parse-colon-path'. + + * eshell/em-unix.el (eshell/du): Check for FTP remote connection. + + * net/tramp.el (tramp-eshell-directory-change): New defun. Add it + to `eshell-directory-change-hook'. + 2009-11-24 Tassilo Horn * doc-view.el (doc-view-mode): Switch off view-mode explicitly, diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el index 8e650ce16ee..fbef32a1a66 100644 --- a/lisp/eshell/em-cmpl.el +++ b/lisp/eshell/em-cmpl.el @@ -402,7 +402,7 @@ to writing a completion function." (setq filename (substring filename 1) pcomplete-stub filename glob-name t)) - (let* ((paths (split-string (getenv "PATH") path-separator)) + (let* ((paths (eshell-parse-colon-path eshell-path-env)) (cwd (file-name-as-directory (expand-file-name default-directory))) (path "") (comps-in-path ()) diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el index dab1ab8f955..d6ba970b6bb 100644 --- a/lisp/eshell/em-unix.el +++ b/lisp/eshell/em-unix.el @@ -859,9 +859,8 @@ external command." (if (and ext-du (not (catch 'have-ange-path (eshell-for arg args - (if (eq (find-file-name-handler (expand-file-name arg) - 'directory-files) - 'ange-ftp-hook-function) + (if (string-equal + (file-remote-p (expand-file-name arg) 'method) "ftp") (throw 'have-ange-path t)))))) (throw 'eshell-replace-command (eshell-parse-command ext-du args)) diff --git a/lisp/eshell/esh-ext.el b/lisp/eshell/esh-ext.el index 9fc7d86b328..f32ab7917ae 100644 --- a/lisp/eshell/esh-ext.el +++ b/lisp/eshell/esh-ext.el @@ -73,7 +73,7 @@ since nothing else but Eshell will be able to understand "Search the environment path for NAME." (if (file-name-absolute-p name) name - (let ((list (parse-colon-path (getenv "PATH"))) + (let ((list (eshell-parse-colon-path eshell-path-env)) suffixes n1 n2 file) (while list (setq n1 (concat (car list) name)) @@ -176,7 +176,7 @@ This bypasses all Lisp functions and aliases." (error "%s: external command not found" (substring command 1)))))) -(defun eshell-remote-command (handler command args) +(defun eshell-remote-command (command args) "Insert output from a remote COMMAND, using ARGS. A remote command is something that executes on a different machine. An external command simply means external to Emacs. @@ -190,10 +190,10 @@ causing the user to wonder if anything's really going on..." (unwind-protect (progn (setq exitcode - (funcall handler 'shell-command - (mapconcat 'shell-quote-argument - (append (list command) args) " ") - outbuf errbuf)) + (shell-command + (mapconcat 'shell-quote-argument + (append (list command) args) " ") + outbuf errbuf)) (eshell-print (with-current-buffer outbuf (buffer-string))) (eshell-error (with-current-buffer errbuf (buffer-string)))) (eshell-close-handles exitcode 'nil) @@ -203,23 +203,14 @@ causing the user to wonder if anything's really going on..." (defun eshell-external-command (command args) "Insert output from an external COMMAND, using ARGS." (setq args (eshell-stringify-list (eshell-flatten-list args))) - (let ((handler - (unless (or (equal default-directory "/") - (and (eshell-under-windows-p) - (string-match "\\`[A-Za-z]:[/\\\\]\\'" - default-directory))) - (find-file-name-handler default-directory - 'shell-command)))) - (if (and handler - (not (and (featurep 'xemacs) - (eq handler 'dired-handler-fn)))) - (eshell-remote-command handler command args)) - (let ((interp (eshell-find-interpreter command))) - (assert interp) - (if (functionp (car interp)) - (apply (car interp) (append (cdr interp) args)) - (eshell-gather-process-output - (car interp) (append (cdr interp) args)))))) + (if (string-equal (file-remote-p default-directory 'method) "ftp") + (eshell-remote-command command args)) + (let ((interp (eshell-find-interpreter command))) + (assert interp) + (if (functionp (car interp)) + (apply (car interp) (append (cdr interp) args)) + (eshell-gather-process-output + (car interp) (append (cdr interp) args))))) (defun eshell/addpath (&rest args) "Add a set of paths to PATH." diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index 0aa7d44190c..dac7b58dc9a 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -261,7 +261,7 @@ See `eshell-needs-pipe'." (defun eshell-gather-process-output (command args) "Gather the output from COMMAND + ARGS." (unless (and (file-executable-p command) - (file-regular-p command)) + (file-regular-p (file-truename command))) (error "%s: not an executable file" command)) (let* ((delete-exited-processes (if eshell-current-subjob-p @@ -270,12 +270,13 @@ See `eshell-needs-pipe'." (process-environment (eshell-environment-variables)) proc decoding encoding changed) (cond - ((fboundp 'start-process) + ((fboundp 'start-file-process) (setq proc (let ((process-connection-type (unless (eshell-needs-pipe-p command) - process-connection-type))) - (apply 'start-process + process-connection-type)) + (command (or (file-remote-p command 'localname) command))) + (apply 'start-file-process (file-name-nondirectory command) nil ;; `start-process' can't deal with relative filenames. (append (list (expand-file-name command)) args)))) diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index 4c5ecb4617a..37802a412b5 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -237,6 +237,21 @@ If N or M is nil, it means the end of the list." a (last a))) a)) +(defvar eshell-path-env (getenv "PATH") + "Content of $PATH. +It might be different from \(getenv \"PATH\"\), when +`default-directory' points to a remote host.") + +(defun eshell-parse-colon-path (path-env) + "Split string with `parse-colon-path'. +Prepend remote identification of `default-directory', if any." + (let ((remote (file-remote-p default-directory))) + (if remote + (mapcar + (lambda (x) (concat remote x)) + (parse-colon-path path-env)) + (parse-colon-path path-env)))) + (defun eshell-split-path (path) "Split a path into multiple subparts." (let ((len (length path)) @@ -682,29 +697,24 @@ If NOSORT is non-nil, the list is not sorted--its order is unpredictable. (defun eshell-file-attributes (file) "Return the attributes of FILE, playing tricks if it's over ange-ftp." (let* ((file (expand-file-name file)) - (handler (find-file-name-handler file 'file-attributes)) entry) - (if (not handler) - (file-attributes file) - (if (eq (find-file-name-handler (file-name-directory file) - 'directory-files) - 'ange-ftp-hook-function) - (let ((base (file-name-nondirectory file)) - (dir (file-name-directory file))) + (if (string-equal (file-remote-p file 'method) "ftp") + (let ((base (file-name-nondirectory file)) + (dir (file-name-directory file))) + (if (boundp 'ange-cache) + (setq entry (cdr (assoc base (cdr (assoc dir ange-cache)))))) + (unless entry + (setq entry (eshell-parse-ange-ls dir)) (if (boundp 'ange-cache) - (setq entry (cdr (assoc base (cdr (assoc dir ange-cache)))))) - (unless entry - (setq entry (eshell-parse-ange-ls dir)) - (if (boundp 'ange-cache) - (setq ange-cache - (cons (cons dir entry) - ange-cache))) - (if entry - (let ((fentry (assoc base (cdr entry)))) - (if fentry - (setq entry (cdr fentry)) - (setq entry nil))))))) - (or entry (funcall handler 'file-attributes file))))) + (setq ange-cache + (cons (cons dir entry) + ange-cache))) + (if entry + (let ((fentry (assoc base (cdr entry)))) + (if fentry + (setq entry (cdr fentry)) + (setq entry nil)))))) + (file-attributes file)))) (defalias 'eshell-copy-tree 'copy-tree) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index d6b59341772..795c7eefc38 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -2383,6 +2383,35 @@ been set up by `rfn-eshadow-setup-minibuffer'." 'tramp-rfn-eshadow-update-overlay)))) +;;; Integration of eshell.el: + +(eval-when-compile + (defvar eshell-path-env)) + +;; eshell.el keeps the path in `eshell-path-env'. We must change it +;; 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'." + (setq eshell-path-env + (if (file-remote-p default-directory) + (with-parsed-tramp-file-name default-directory nil + (mapconcat + 'identity + (tramp-get-remote-path v) + ":")) + (getenv "PATH")))) + +(eval-after-load "esh-util" + '(progn + (tramp-eshell-directory-change) + (add-hook 'eshell-directory-change-hook + 'tramp-eshell-directory-change) + (add-hook 'tramp-unload-hook + (lambda () + (remove-hook 'eshell-directory-change-hook + 'tramp-eshell-directory-change))))) + + ;;; File Name Handler Functions: (defun tramp-handle-make-symbolic-link