emacs: cros_sdk tramp integration.

With this, opening files starting with `/cros::` enters cros_sdk chroot.

BUG=None
TEST=(load-file "~/src/cros-work2/src/platform/dev/contrib/emacs/cros-sdk-tramp.el")
  and open /cros::

Change-Id: Iff3962e3793720bb5fe4868e69c19de7faf529af
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/2936169
Commit-Queue: Junichi Uekawa <uekawa@chromium.org>
Tested-by: Junichi Uekawa <uekawa@chromium.org>
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
diff --git a/contrib/emacs/README.md b/contrib/emacs/README.md
index 13b00a3..2a70a4b 100644
--- a/contrib/emacs/README.md
+++ b/contrib/emacs/README.md
@@ -2,7 +2,33 @@
 
 This directory contains projects for using emacs as editor for Chrome OS.
 
-## Gerrit integration
+## Gerrit integration.
 
 See [Chromacs gerrit integration](gerrit/README.md) for how to integrate with
 gerrit.
+
+## `cros_sdk` tramp integration.
+
+In your `.emacs` configuration file, load `cros-sdk-tramp.el`, and set up the
+path to your CrOS checkout.
+
+```lisp
+(setq cros-sdk-tramp-src-path "~/src/path/to/cros")
+(load-file "~/path/to/cros-sdk-tramp.el")
+```
+
+Then find file with path starting `/cros::` would use the right path, things
+like `M-x shell` will start a `cros_sdk`. Because `cros_sdk` invokes sudo you
+will be asked password.
+
+Make sure you ask no when asked to store your corp password.
+
+`M-x compile` for example with `cros_workon_make --test --board=rammus-arc-r
+debugd` will start compilation inside the chroot in the compilation buffer and
+the next-error would find the right source location.
+
+`cros-sdk-tramp-rotate-among-files` utility is provided to switch between inside
+chroot and outside.
+
+To make `cros_sdk` smooth you may want to tweak your
+[sudo configuration](https://chromium.googlesource.com/chromiumos/docs/+/HEAD/tips-and-tricks.md#How-to-make-sudo-a-little-more-permissive)
diff --git a/contrib/emacs/cros-sdk-tramp.el b/contrib/emacs/cros-sdk-tramp.el
new file mode 100644
index 0000000..d0f5151
--- /dev/null
+++ b/contrib/emacs/cros-sdk-tramp.el
@@ -0,0 +1,63 @@
+;; cros-sdk-tramp.el --- TRAMP integration for cros_sdk
+
+(require 'tramp)
+
+(defgroup cros-sdk-tramp nil "TRAMP integration for cros_sdk."
+  :prefix "cros-sdk-tramp-"
+  :group 'applications)
+
+(defcustom cros-sdk-tramp-src-path
+  (locate-dominating-file load-file-name "src/platform/dev/contrib/OWNERS")
+  "Location of chrome OS source tree. Needed for cros_sdk.
+
+Default value is inferred from the location of this file."
+  :type 'string
+  :group 'cros-sdk-tramp)
+
+(defconst cros-sdk-tramp-method "cros")
+
+(defun cros-sdk-tramp-add-method ()
+  "Add cros-sdk tramp method."
+  ;; TODO(uekawa): This asks for username and password and hostname, but only
+  ;; the password (for sudo) is used.
+  (add-to-list 'tramp-methods
+               `(,cros-sdk-tramp-method
+                 (tramp-login-program
+                  ,(concat "/bin/sh -c 'cd " cros-sdk-tramp-src-path " && cros_sdk'"))
+                 (tramp-remote-shell "/bin/sh")
+                 (tramp-remote-shell-args ("-i" "-c")))))
+
+(eval-after-load 'tramp
+  '(progn
+     (cros-sdk-tramp-add-method)))
+
+;; TODO(uekawa): there must be a better per-connection way to set this
+(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
+
+(defun cros-sdk-tramp-rotate-among-files ()
+  "Rotate among same file inside or outside cros_sdk chroot.
+They should be the same file."
+  (interactive)
+  (let* ((current (buffer-file-name))
+         (cros-match (string-match "^/cros:.*:/mnt/host/source/\\(.*\\)$" current)))
+    (if cros-match
+        (let* ((relative-path (match-string 1 current))
+               (abs-path
+                (concat
+                 (file-name-as-directory cros-sdk-tramp-src-path)
+                 relative-path)))
+          ;; was in cros_sdk
+          (find-file abs-path))
+      ;; Was in a regular directory
+      (let* ((old-full-path (expand-file-name current))
+             (old-root-path (expand-file-name cros-sdk-tramp-src-path))
+             (old-relative-path-match-re (concat "^" (regexp-quote old-root-path) "\\(.*\\)$"))
+             (old-relative-path-match
+              (string-match old-relative-path-match-re
+                            old-full-path))
+             (old-relative-path (match-string 1 old-full-path))
+             (new-full-path (concat "/cros::/mnt/host/source/" old-relative-path)))
+        (find-file new-full-path)))))
+
+
+(provide 'cros-sdk-tramp)