branch: externals/ssh-deploy commit 4a9dfb604b04e26871ac81bfafe564d0ea153ac8 Author: Christian Johansson <christ...@cvj.se> Commit: Christian Johansson <christ...@cvj.se>
Added feature to open corresponding file on remote --- README.md | 11 +++++--- ssh-deploy-diff-mode.el | 38 +++++++++++++++++++++++---- ssh-deploy.el | 70 ++++++++++++++++++++++++++++--------------------- 3 files changed, 80 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 7429025..798cdf5 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,12 @@ The `ssh-deploy` plug-in for Emacs makes it possible to effortlessly deploy loca * Launch difference sessions for directories using a custom implementation of recursive directory differences over TRAMP based on `ediff` * Rename files and directories on local host and have it mirrored on the remote * Delete files and directories on local host and have it mirrored on the remote -* All operations support asynchronous mode if `async.el` is installed. (You need to setup an automatic authorization for this, i.e. `~/.netrc` and/or key-based password-less authorization) +* Open corresponding file on the remote host +* All operations support asynchronous mode if `async.el` is installed. (You need to setup an automatic authorization for this, i.e. `~/.netrc`, `~/.authinfo` or `~/.authinfo.gpg` and/or key-based password-less authorization) The idea for this plug-in was to mimic the behavior of **PhpStorm** deployment functionality. -This application is made by Christian Johansson <christ...@cvj.se> 2016-2017 and is licensed under GNU General Public License 3 (GNU GPL 3). +This application is made by Christian Johansson <christ...@cvj.se> 2016-2018 and is licensed under GNU General Public License 3 (GNU GPL 3). ## Configuration @@ -97,7 +98,7 @@ Host remote-host ## Interaction-free password-based setup on *NIX systems -For automatic **FTP** connections you need to setup `~/.netrc` with your login credentials. An example: +For automatic **FTP** connections you need to setup `~/.netrc`, `~/.authinfo` or `~/.authinfo.gpg` with your login credentials. An example: `~/.netrc` contents: ``` shell @@ -110,7 +111,7 @@ Set your user and group as owner and file permissions to `600`. Emacs should now ## Interaction-free SSH setup using public-key password-based authorization -By combining a `~/.netrc` setup and a `public-key` setup you should be able to have a interaction-free public-key password-based authorization that can be used asynchronously. +By combining a `~/.netrc`, `~/.authinfo` or `~/.authinfo.gpg` setup and a `public-key` setup you should be able to have a interaction-free public-key password-based authorization that can be used asynchronously. ## Emacs configuration example @@ -132,6 +133,7 @@ By combining a `~/.netrc` setup and a `public-key` setup you should be able to h (global-set-key (kbd "C-c C-z R") (lambda() (interactive)(ssh-deploy-rename-handler) )) (global-set-key (kbd "C-c C-z e") (lambda() (interactive)(ssh-deploy-remote-changes-handler) )) (global-set-key (kbd "C-c C-z b") (lambda() (interactive)(ssh-deploy-browse-remote-base-handler) )) +(global-set-key (kbd "C-c C-z o") (lambda() (interactive)(ssh-deploy-open-remote-file-handler) )) ``` * Or use the `use-package` and `hydra-script` I'm using: @@ -154,6 +156,7 @@ By combining a `~/.netrc` setup and a `public-key` setup you should be able to h _e_: Detect Remote Changes _R_: Rename _b_: Browse Base _B_: Browse Relative + _o_; Open current file on remote " ("f" ssh-deploy-upload-handler-forced) ("u" ssh-deploy-upload-handler) diff --git a/ssh-deploy-diff-mode.el b/ssh-deploy-diff-mode.el index def8cf0..581cbb0 100644 --- a/ssh-deploy-diff-mode.el +++ b/ssh-deploy-diff-mode.el @@ -3,8 +3,8 @@ ;; Author: Christian Johansson <github.com/cjohansson> ;; Maintainer: Christian Johansson <github.com/cjohansson> ;; Created: 1 Feb 2018 -;; Modified: 15 Feb 2018 -;; Version: 1.0 +;; Modified: 16 Feb 2018 +;; Version: 1.1 ;; Keywords: tools, convenience ;; URL: https://github.com/cjohansson/emacs-ssh-deploy @@ -35,6 +35,10 @@ ;;; Code: +;; TODO: Must explicitly send global variables, seems like settings are lost sometimes? +;; TODO: Downloading and deletion of remote files that does not exist on local root does not work? +;; TODO: Pressing return on a file in both roots should show some kind of message +;; TODO: Pressing action at first line causing endless loop (defvar ssh-deploy-diff-mode nil) @@ -51,6 +55,7 @@ (defconst ssh-deploy-diff-mode--action-delete 3 "Action for delete.") (defconst ssh-deploy-diff-mode--action-difference 4 "Action for difference.") (defconst ssh-deploy-diff-mode--action-refresh 5 "Action for refreshing differences.") +(defconst ssh-deploy-diff-mode--action-open 6 "Action for open file.") (defconst ssh-deploy-diff-mode--keywords (list @@ -78,8 +83,9 @@ (define-key map "a" 'ssh-deploy-diff-mode-copy-a-handler) (define-key map "b" 'ssh-deploy-diff-mode-copy-b-handler) (define-key map "d" 'ssh-deploy-diff-mode-delete-handler) - (define-key map "\t" 'ssh-deploy-diff-mode-difference-handler) + (define-key map (kbd "<tab>") 'ssh-deploy-diff-mode-difference-handler) (define-key map "g" 'ssh-deploy-diff-mode-refresh-handler) + (define-key map (kbd "<return>") 'ssh-deploy-diff-mode-open-handler) map) "Key-map for SSH Deploy Diff major mode.") @@ -89,6 +95,7 @@ (defun ssh-deploy-diff-mode-delete-handler() "Start the delete action." (interactive)(ssh-deploy-diff-mode--action-handler ssh-deploy-diff-mode--action-delete)) (defun ssh-deploy-diff-mode-difference-handler() "Start the difference action." (interactive)(ssh-deploy-diff-mode--action-handler ssh-deploy-diff-mode--action-difference)) (defun ssh-deploy-diff-mode-refresh-handler() "Start the refresh action." (interactive)(ssh-deploy-diff-mode--action-handler ssh-deploy-diff-mode--action-refresh)) +(defun ssh-deploy-diff-mode-open-handler() "Start the open action." (interactive)(ssh-deploy-diff-mode--action-handler ssh-deploy-diff-mode--action-open)) (defun ssh-deploy-diff-mode--get-parts () "Return current file and section if any." @@ -141,14 +148,14 @@ (let ((parts (ssh-deploy-diff-mode--get-parts))) (if (not (eq parts nil)) (progn - ;; (message "Parts %s %s" action parts) (cond ((and (not (null (nth 0 parts))) (= action ssh-deploy-diff-mode--action-copy)) (ssh-deploy-diff-mode--copy parts)) ((and (not (null (nth 0 parts))) (= action ssh-deploy-diff-mode--action-copy-a)) (ssh-deploy-diff-mode--copy-a parts)) ((and (not (null (nth 0 parts))) (= action ssh-deploy-diff-mode--action-copy-b)) (ssh-deploy-diff-mode--copy-b parts)) ((and (not (null (nth 0 parts))) (= action ssh-deploy-diff-mode--action-delete)) (ssh-deploy-diff-mode--delete parts)) ((and (not (null (nth 0 parts))) (= action ssh-deploy-diff-mode--action-difference)) (ssh-deploy-diff-mode--difference parts)) + ((and (not (null (nth 0 parts))) (= action ssh-deploy-diff-mode--action-open)) (ssh-deploy-diff-mode--open parts)) ((= action ssh-deploy-diff-mode--action-refresh) (ssh-deploy-diff-mode--refresh parts)) - (t (message "Found no function for %s" action)))) + (t (message "Found nothing to do in the section for action %s" action)))) (message "Found nothing to do")))) (defun ssh-deploy-diff-mode--refresh (parts) @@ -259,6 +266,27 @@ (display-warning "ssh-deploy" "Function ssh-deploy-diff-files is missing" :warning)) (message "File must exists in both roots to perform a difference action.")))) +(defun ssh-deploy-diff-mode--open (parts) + "Perform a open file action based on PARTS from section A or section B." + (require 'ssh-deploy) + (let* ((section (nth 1 parts)) + (file-name (nth 0 parts)) + (root-local (nth 2 parts)) + (root-remote (nth 3 parts)) + (path-local (concat root-local file-name)) + (path-remote (concat root-remote file-name))) + (let* ((path-local (file-truename path-local)) + (root-local (file-truename root-local))) + (cond ((= section ssh-deploy-diff-mode--section-only-in-a) + (progn + (message "Opening file '%s'" path-local) + (find-file path-local))) + ((= section ssh-deploy-diff-mode--section-only-in-b) + (progn + (message "Opening file '%s'" path-remote) + (find-file path-remote))) + (t (message "Open is not available in this section")))))) + (defun ssh-deploy-diff-mode () "Major mode for SSH Deploy interactive directory differences." (interactive) diff --git a/ssh-deploy.el b/ssh-deploy.el index 6b03db0..e454ee0 100644 --- a/ssh-deploy.el +++ b/ssh-deploy.el @@ -3,8 +3,8 @@ ;; Author: Christian Johansson <github.com/cjohansson> ;; Maintainer: Christian Johansson <github.com/cjohansson> ;; Created: 5 Jul 2016 -;; Modified: 15 Feb 2018 -;; Version: 1.74 +;; Modified: 16 Feb 2018 +;; Version: 1.75 ;; Keywords: tools, convenience ;; URL: https://github.com/cjohansson/emacs-ssh-deploy @@ -41,9 +41,9 @@ ;; ssh-deploy-root-local,ssh-deploy-root-remote, ssh-deploy-on-explicit-save ;; you can setup a directory for TRAMP deployment. ;; -;; For asynchronous transfers you need to setup ~/.netrc or key-based authorization or equivalent for automatic authentication. +;; For asynchronous transfers you need to setup ~/.netrc, ~/.authinfo or ~/.authinfo.gpg or key-based authorization or equivalent for automatic authentication. ;; -;; Example contents of ~/.netrc for password-based interaction-free authentication: +;; Example contents of ~/.netrc, ~/.authinfo or ~/.authinfo.gpg for password-based interaction-free authentication: ;; machine myserver.com login myuser port ftp password mypassword ;; machine myserver2.com login myuser2 port ssh password mypassword2 ;; machine myserver3.com login myuser3 port sftp password mypassword3 @@ -68,6 +68,7 @@ ;; (global-set-key (kbd "C-c C-z e") (lambda() (interactive)(ssh-deploy-remote-changes-handler) )) ;; (global-set-key (kbd "C-c C-z b") (lambda() (interactive)(ssh-deploy-browse-remote-base-handler) )) ;; (global-set-key (kbd "C-c C-z B") (lambda() (interactive)(ssh-deploy-browse-remote-handler) )) +;; (global-set-key (kbd "C-c C-z o") (lambda() (interactive)(ssh-deploy-open-remote-file-handler) )) ;; ;; - To install and set-up using use-package and hydra do this: ;; (use-package ssh-deploy @@ -87,6 +88,7 @@ ;; _e_: Detect Remote Changes ;; _R_: Rename ;; _b_: Browse Base _B_: Browse Relative +;; _o_: Open current file on remote ;; " ;; ("f" ssh-deploy-upload-handler-forced) ;; ("u" ssh-deploy-upload-handler) @@ -98,7 +100,8 @@ ;; ("e" ssh-deploy-remote-changes-handler) ;; ("R" ssh-deploy-rename-handler) ;; ("b" ssh-deploy-browse-remote-base-handler) -;; ("B" ssh-deploy-browse-remote-handler))) +;; ("B" ssh-deploy-browse-remote-handler) +;; ("o" ssh-deploy-open-remote-file-handler))) ;; ;; ;; Here is an example for SSH deployment, /Users/Chris/Web/Site1/.dir-locals.el: @@ -302,31 +305,24 @@ "Download PATH-REMOTE to PATH-LOCAL via TRAMP asynchronously and make a copy in REVISION-FOLDER." (if (fboundp 'async-start) (progn - (let ((file-or-directory (file-regular-p path-local))) - (if file-or-directory - (progn - (let ((revision-path (ssh-deploy--get-revision-path path-local revision-folder))) - (message "Downloading file '%s' to '%s'.. (asynchronously)" path-remote path-local) - (async-start - `(lambda() - (copy-file ,path-remote ,path-local t t t t) - (copy-file ,path-local ,revision-path t t t t) - ,path-local) - (lambda(return-path) - (message "Download of file '%s' finished. (asynchronously)" return-path))))) - (progn - (message "Downloading directory '%s' to '%s'.. (asynchronously)" path-remote path-local) - (async-start - `(lambda() - (copy-directory ,path-remote ,path-local t t t) - ,path-local) - (lambda(return-path) - (message "Download of directory '%s' finished. (asynchronously)" return-path))))))) + (message "Downloading '%s' to '%s'.. (asynchronously)" path-remote path-local) + (async-start + `(lambda() + (let ((file-or-directory (file-regular-p ,path-remote)) + (revision-path (ssh-deploy--get-revision-path ,path-local ,revision-folder))) + (if file-or-directory + (progn + (copy-file ,path-remote ,path-local t t t t) + (copy-file ,path-local ,revision-path t t t t)) + (copy-directory ,path-remote ,path-local t t t)) + ,path-local)) + (lambda(return-path) + (message "Download of '%s' finished. (asynchronously)" return-path)))) (display-warning "ssh-deploy" "async.el is not installed" :warning))) (defun ssh-deploy--download-via-tramp (path-remote path-local revision-folder) "Download PATH-REMOTE to PATH-LOCAL via TRAMP synchronously and store a copy in REVISION-FOLDER." - (let ((file-or-directory (file-regular-p path-local))) + (let ((file-or-directory (file-regular-p path-remote))) (if file-or-directory (progn (message "Downloading file '%s' to '%s'.. (synchronously)" path-remote path-local) @@ -338,6 +334,7 @@ (copy-directory path-remote path-local t t t) (message "Download of directory '%s' finished. (synchronously)" path-local))))) +;; TODO Support cases where directory-a or directory-b does not exist (defun ssh-deploy--diff-directories-data (directory-a directory-b exclude-list) "Find difference between DIRECTORY-A and DIRECTORY-B but exclude paths matching EXCLUDE-LIST." ;; (message "Comparing a: %s to b: %s" directory-a directory-b) @@ -461,7 +458,7 @@ (ssh-deploy--insert-keyword "DIRECTORY B: ") (insert (nth 1 diff) "\n") - (if (length (nth 2 diff)) + (if (> (length (nth 2 diff)) 0) (progn (insert "\n") (ssh-deploy--insert-keyword (format "EXCLUDE-LIST: (%d)" (length (nth 2 diff)))) @@ -471,21 +468,21 @@ (insert "\n") - (if (length (nth 4 diff)) + (if (> (length (nth 4 diff)) 0) (progn (ssh-deploy--insert-keyword (format "FILES ONLY IN A: (%d)" (length (nth 4 diff)))) (dolist (element (nth 4 diff)) (insert "\n- " element)) (insert "\n\n"))) - (if (length (nth 5 diff)) + (if (> (length (nth 5 diff)) 0) (progn (ssh-deploy--insert-keyword (format "FILES ONLY IN B: (%d)" (length (nth 5 diff)))) (dolist (element (nth 5 diff)) (insert "\n- " element)) (insert "\n\n"))) - (if (length (nth 7 diff)) + (if (> (length (nth 7 diff)) 0) (progn (ssh-deploy--insert-keyword (format "FILES IN BOTH BUT DIFFERS: (%d)" (length (nth 7 diff)))) (dolist (element (nth 7 diff)) @@ -848,6 +845,19 @@ (ssh-deploy-remote-changes (file-truename buffer-file-name) (file-truename ssh-deploy-root-local) ssh-deploy-root-remote ssh-deploy-async ssh-deploy-revision-folder ssh-deploy-exclude-list))) ;;;### autoload +(defun ssh-deploy-open-remote-file-handler() + "Check if local revision exists or remote file has changed if path is configured for deployment." + (interactive) + (if (and (ssh-deploy--is-not-empty-string ssh-deploy-root-local) + (ssh-deploy--is-not-empty-string ssh-deploy-root-remote) + (ssh-deploy--is-not-empty-string buffer-file-name)) + (let* ((root-local (file-truename ssh-deploy-root-local)) + (path-local (file-truename buffer-file-name)) + (path-remote (concat ssh-deploy-root-remote (ssh-deploy--get-relative-path root-local path-local)))) + (message "Opening file on remote '%s'" path-remote) + (find-file path-remote)))) + +;;;### autoload (defun ssh-deploy-download-handler () "Download current path from remote if it is configured for deployment." (interactive)