1;;; android-common.el --- Common functions/variables to dev Android in Emacs.
2;;
3;; Copyright (C) 2009 The Android Open Source Project
4;;
5;; Licensed under the Apache License, Version 2.0 (the "License");
6;; you may not use this file except in compliance with the License.
7;; You may obtain a copy of the License at
8;;
9;;      http://www.apache.org/licenses/LICENSE-2.0
10;;
11;; Unless required by applicable law or agreed to in writing, software
12;; distributed under the License is distributed on an "AS IS" BASIS,
13;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14;; See the License for the specific language governing permissions and
15;; limitations under the License.
16
17;;; Commentary:
18;;
19;; Variables to customize and common functions for the Android build
20;; support in Emacs.
21;; There should be no interactive function in this module.
22;;
23;; You need to have a proper buildspec.mk file in your root directory
24;; for this module to work (see $TOP/build/buildspec.mk.default).
25;; If the path the product's files/image uses an a product alias, you
26;; need to add a mapping in `android-product-alias-map'. For instance
27;; if TARGET_PRODUCT is foo but the build directory is out/target/product/bar,
28;; you need to add a mapping Target:foo -> Alias:bar
29;;
30
31;;; Code:
32
33(defgroup android nil
34  "Support for android development in Emacs."
35  :prefix "android-"                    ; Currently unused.
36  :tag    "Android"
37  :group  'tools)
38
39;;;###autoload
40(defcustom android-compilation-jobs 2
41  "Number of jobs used to do a compilation (-j option of make)."
42  :type 'integer
43  :group 'android)
44
45;;;###autoload
46(defcustom android-compilation-no-buildenv-warning t
47  "If not nil, suppress warnings from the build env (Makefile,
48bash) from the compilation output since they interfere with
49`next-error'."
50  :type 'boolean
51  :group 'android)
52
53;;;###autoload
54(defcustom android-product-alias-map nil
55  "Alist between product targets (declared in buildspec.mk) and actual
56 product build directory used by `android-product'.
57
58For instance if TARGET_PRODUCT is 'foo' but the build directory
59 is 'out/target/product/bar', you need to add a mapping Target:foo -> Alias:bar."
60  :type '(repeat (list (string :tag "Target")
61                       (string :tag "Alias")))
62  :group 'android)
63
64(defconst android-output-buffer-name "*Android Output*"
65  "Name of the default buffer for the output of the commands.
66There is only one instance of such a buffer.")
67
68(defun android-find-build-tree-root ()
69  "Ascend the current path until the root of the android build tree is found.
70Similarly to the shell functions in envsetup.sh, for the root both ./Makefile
71and ./build/core/envsetup.mk are exiting files.
72Return the root of the build tree.  Signal an error if not found."
73  (let ((default-directory default-directory))
74    (while (and (> (length default-directory) 2)
75                (not (file-exists-p (concat default-directory
76                                            "Makefile")))
77                (not (file-exists-p (concat default-directory
78                                            "build/core/envsetup.mk"))))
79      (setq default-directory
80            (substring default-directory 0
81                       (string-match "[^/]+/$" default-directory))))
82    (if (> (length default-directory) 2)
83        default-directory
84      (error "Not in a valid android tree"))))
85
86(defun android-project-p ()
87  "Return nil if not in an android build tree."
88  (condition-case nil
89      (android-find-build-tree-root)
90    (error nil)))
91
92(defun android-host ()
93  "Return the <system>-<arch> string (e.g linux-x86).
94Only linux and darwin on x86 architectures are supported."
95  (or (string-match "x86" system-configuration)
96      (string-match "i386" system-configuration)
97      (error "Unknown arch"))
98  (or (and (string-match "darwin" system-configuration) "darwin-x86")
99      (and (string-match "linux" system-configuration) "linux-x86")
100      (error "Unknown system")))
101
102(defun android-product ()
103  "Return the product built according to the buildspec.mk.
104You must have buildspec.mk file in the top directory.
105
106Additional product aliases can be listed in `android-product-alias-map'
107if the product actually built is different from the one listed
108in buildspec.mk"
109  (save-excursion
110    (let* ((buildspec (concat (android-find-build-tree-root) "buildspec.mk"))
111           (product (with-current-buffer (find-file-noselect buildspec)
112                      (goto-char (point-min))
113                      (search-forward "TARGET_PRODUCT:=")
114                      (buffer-substring-no-properties (point)
115                                                      (scan-sexps (point) 1))))
116           (alias (assoc product android-product-alias-map)))
117      ; Post processing, adjust the names.
118      (if (not alias)
119          product
120        (nth 1 alias)))))
121
122(defun android-product-path ()
123  "Return the full path to the product directory.
124
125Additional product aliases can be added in `android-product-alias-map'
126if the product actually built is different from the one listed
127in buildspec.mk"
128  (let ((path (concat (android-find-build-tree-root) "out/target/product/"
129                      (android-product))))
130    (when (not (file-exists-p path))
131      (error (format "%s does not exist. If product %s maps to another one,
132add an entry to android-product-map." path (android-product))))
133    path))
134
135(defun android-find-host-bin (binary)
136  "Return the full path to the host BINARY.
137Binaries don't depend on the device, just on the host type.
138Try first to locate BINARY in the out/host tree.  Fallback using
139the shell exec PATH setup."
140  (if (android-project-p)
141      (let ((path (concat (android-find-build-tree-root) "out/host/"
142                          (android-host) "/bin/" binary)))
143        (if (file-exists-p path)
144            path
145          (error (concat binary " is missing."))))
146    (executable-find binary)))
147
148(defun android-adb ()
149  "Return the path to the adb executable.
150If not in the build tree use the PATH env variable."
151  (android-find-host-bin "adb"))
152
153(defun android-fastboot ()
154  "Return the path to the fastboot executable.
155If not in the build tree use the PATH env variable."
156  ; For fastboot -p is the name of the product, *not* the full path to
157  ; its directory like adb requests sometimes.
158  (concat (android-find-host-bin "fastboot") " -p " (android-product)))
159
160(defun android-adb-command (command &optional product)
161  "Execute 'adb COMMAND'.
162If the optional PRODUCT is not nil, -p (android-product-path) is used
163when adb is invoked."
164  (when (get-buffer android-output-buffer-name)
165    (with-current-buffer android-output-buffer-name
166      (erase-buffer)))
167  (if product
168      (shell-command (concat (android-adb) " -p " (android-product-path)
169                             " " command)
170                     android-output-buffer-name)
171    (shell-command (concat (android-adb) " " command)
172                   android-output-buffer-name)))
173
174(defun android-adb-shell-command (command)
175  "Execute 'adb shell COMMAND'."
176  (android-adb-command (concat " shell " command)
177                       android-output-buffer-name))
178
179(provide 'android-common)
180
181;;; android-common.el ends here
182