Permalink
Browse files

Choose device interactively if more than one is available

  • Loading branch information...
1 parent ab7b385 commit a3c41811b27d1a4f3f426ad02167573bdbd1c032 @alexander-yakushev alexander-yakushev committed Jun 5, 2012
Showing with 121 additions and 75 deletions.
  1. +1 −1 .gitignore
  2. +1 −1 project.clj
  3. +15 −11 src/leiningen/droid.clj
  4. +3 −25 src/leiningen/droid/build.clj
  5. +86 −0 src/leiningen/droid/device.clj
  6. +0 −32 src/leiningen/droid/run.clj
  7. +15 −5 src/leiningen/droid/utils.clj
View
@@ -8,4 +8,4 @@ pom.xml
*.class
.lein-deps-sum
.lein-failures
-.lein-plugins
+.lein-plugins
View
@@ -1,4 +1,4 @@
-(defproject lein-droid/lein-droid "0.0.1"
+(defproject lein-droid/lein-droid "0.0.2"
:description "Plugin for easy Clojure/Android development and deployment"
:url "https://github.com/alexander-yakushev/lein-droid"
:license {:name "Eclipse Public License"
View
@@ -11,11 +11,10 @@
[leiningen.droid.compile :only (compile)]
[leiningen.droid
[build :only [create-dex crunch-resources package-resources create-apk
- sign-apk zipalign-apk install apk build]]
- [run :only [run forward-port repl]]
+ sign-apk zipalign-apk apk build]]
+ [device :only [get-device-args install run forward-port repl]]
[new :only [new]]
- [utils :only [proj wrong-usage android-parameters]]]))
-
+ [utils :only [proj wrong-usage android-parameters ensure-paths]]]))
(defn help
"Show the list of possible lein droid subtasks."
@@ -29,9 +28,14 @@
(defn doall
"Performs all Android tasks from compilation to the deployment."
- [project]
- (doto project
- build apk install run))
+ [{{:keys [adb-bin]} :android :as project} & device-args]
+ (println device-args)
+ (doto project build apk)
+ (ensure-paths adb-bin)
+ (let [device (get-device-args adb-bin device-args)]
+ (apply install project device)
+ (apply run project device)
+ (apply forward-port project device)))
(defn release
"Builds, packs and deploys the release version of the project."
@@ -67,15 +71,15 @@
"create-apk" (create-apk project)
"sign-apk" (sign-apk project)
"zipalign-apk" (zipalign-apk project)
- "install" (install project)
- "run" (run project)
- "forward-port" (forward-port project)
+ "install" (apply install project args)
+ "run" (apply run project args)
+ "forward-port" (apply forward-port project args)
"repl" (repl project)
;; Meta tasks
"build" (build project)
"apk" (apk project)
- "doall" (doall project)
+ "doall" (apply doall project)
"release" (release project)
;; Help tasks
@@ -8,20 +8,11 @@
[leiningen.droid
[compile :only [compile]]
[utils :only [get-sdk-android-jar unique-jars first-matched proj sh
- dev-build? ensure-paths with-process read-password]]
- [manifest :only [write-manifest-with-internet-permission
- get-package-name]]])
+ dev-build? ensure-paths with-process read-password
+ append-suffix]]
+ [manifest :only [write-manifest-with-internet-permission]]])
(:require [clojure.java.io :as io]))
-;; ### Helper functions
-
-(defn- append-suffix
- "Appends a suffix to a filename, e.g. transforming `sample.apk` into
- `sample-signed.apk`"
- [filename suffix]
- (let [[_ without-ext ext] (re-find #"(.+)(\.\w+)" filename)]
- (str without-ext "-" suffix ext)))
-
;; ### Subtasks
;; Since the execution of `dx` takes a pretty lot of time we need to
@@ -151,16 +142,3 @@
(doto project
crunch-resources package-resources
create-apk sign-apk zipalign-apk))
-
-(defn install
- "Installs the current debug APK to the connected device."
- [{{:keys [sdk-path out-apk-path manifest-path]} :android :as project}]
- (info "Installing APK...")
- (let [adb-bin (str sdk-path "/platform-tools/adb")
- apk-path (if (dev-build? project)
- (append-suffix out-apk-path "debug")
- out-apk-path)]
- (ensure-paths sdk-path apk-path)
- ;; Uninstall old APK first.
- (sh adb-bin "uninstall" (get-package-name manifest-path))
- (sh adb-bin "-d" "install" "-r" apk-path)))
@@ -0,0 +1,86 @@
+(ns leiningen.droid.device
+ "Functions and subtasks that install and run the application on the
+ device and manage its runtime."
+ (:use [leiningen.core.main :only (debug info abort)]
+ [leiningen.droid.manifest :only (get-launcher-activity
+ get-package-name)]
+ [leiningen.droid.utils :only (sh ensure-paths dev-build? append-suffix)]
+ [reply.main :only (launch-nrepl)]))
+
+(defn- device-list
+ "Returns the list of currently attached devices."
+ [adb-bin]
+ (let [output (rest (sh adb-bin "devices"))] ;; Ignore the first line
+ (remove nil?
+ (map #(let [[_ serial type] (re-find #"([^\t]+)\t([^\t]+)" %)]
+ (when serial
+ {:serial serial, :type type}))
+ output))))
+
+(defn- choose-device
+ "If there is only one device attached returns its serial number,
+ otherwise prompts user to choose the device to work with. If no
+ devices are attached aborts the execution."
+ [adb-bin]
+ (let [devices (device-list adb-bin)]
+ (case (count devices)
+ 0 (abort "No devices are attached..")
+ 1 (:serial (first devices))
+ (do
+ (dotimes [i (count devices)]
+ (println (format "%d. %s\t\t%s" (+ i 1) (:serial (nth devices i)))
+ (:type (nth devices i))))
+ (print (format "Enter the number 1..%d to choose the device: "
+ (count devices)))
+ (flush)
+ (let [answer (- (Integer/parseInt (read-line)) 1)]
+ (:serial (nth devices answer)))))))
+
+(defn get-device-args
+ "Returns a list of adb arguments that specify the device adb should be
+ working against. Calls `choose-device` if `adb-args` parameter is
+ nil."
+ [adb-bin device-args]
+ (or device-args
+ (list "-s" (choose-device adb-bin))))
+
+(defn install
+ "Installs the APK on the only (or specified) device or emulator."
+ [{{:keys [adb-bin out-apk-path manifest-path]} :android :as project}
+ & device-args]
+ (info "Installing APK...")
+ (ensure-paths adb-bin)
+ (let [apk-path (if (dev-build? project)
+ (append-suffix out-apk-path "debug")
+ out-apk-path)
+ device (get-device-args adb-bin device-args)]
+ (ensure-paths apk-path)
+ ;; Uninstall old APK first.
+ (sh adb-bin device "uninstall" (get-package-name manifest-path))
+ (sh adb-bin device "install" "-r" apk-path)))
+
+(defn run
+ "Launches the installed APK on the connected device."
+ [{{:keys [adb-bin manifest-path]} :android} & device-args]
+ (info "Launching APK...")
+ (ensure-paths adb-bin manifest-path)
+ (let [device (get-device-args adb-bin device-args)]
+ (sh adb-bin device "shell" "am" "start" "-n"
+ (get-launcher-activity manifest-path))))
+
+(defn forward-port
+ "Binds a port on the local machine to the port on the device
+ allowing to connect to the remote REPL."
+ [{{:keys [adb-bin repl-device-port repl-local-port]} :android} & device-args]
+ (info "Binding device port" repl-device-port
+ "to local port" repl-local-port "...")
+ (ensure-paths adb-bin)
+ (let [device (get-device-args adb-bin device-args)]
+ (sh adb-bin device "forward"
+ (str "tcp:" repl-local-port)
+ (str "tcp:" repl-device-port))))
+
+(defn repl
+ "Connects to a remote nREPL server on the device using REPLy."
+ [{{:keys [repl-local-port]} :android}]
+ (launch-nrepl {:attach (str "localhost:" repl-local-port)}))
@@ -1,32 +0,0 @@
-(ns leiningen.droid.run
- "Functions and subtasks that run the application on the device and
- manage its runtime. "
- (:use [leiningen.core.main :only (debug info) :rename {debug print-debug}]
- [leiningen.droid.manifest :only (get-launcher-activity)]
- [leiningen.droid.utils :only (sh ensure-paths)]
- [reply.main :only (launch-nrepl)]))
-
-(defn run
- "Launches the installed APK on the connected device."
- [{{:keys [sdk-path manifest-path]} :android}]
- (info "Launching APK...")
- (ensure-paths sdk-path manifest-path)
- (let [adb-bin (str sdk-path "/platform-tools/adb")]
- (sh adb-bin "shell" "am" "start" "-n" (get-launcher-activity manifest-path))))
-
-(defn forward-port
- "Binds a port on the local machine to the port on the device
- allowing to connect to the remote REPL."
- [{{:keys [sdk-path repl-device-port repl-local-port]} :android}]
- (info "Binding device port" repl-device-port
- "to local port" repl-local-port "...")
- (ensure-paths sdk-path)
- (let [adb-bin (str sdk-path "/platform-tools/adb")]
- (sh adb-bin "forward"
- (str "tcp:" repl-local-port)
- (str "tcp:" repl-device-port))))
-
-(defn repl
- "Connects to a remote nREPL server on the device using REPLy."
- [{{:keys [repl-local-port]} :android}]
- (launch-nrepl {:attach (str "localhost:" repl-local-port)}))
@@ -36,7 +36,7 @@
(defn get-default-android-params
"Returns a map of the default android-specific parameters."
- [project-name target-path]
+ [project-name target-path sdk-path]
{:out-dex-path (str target-path "/classes.dex")
:manifest-path "AndroidManifest.xml"
:res-path "res"
@@ -45,6 +45,7 @@
:out-res-pkg-path (str target-path "/" project-name ".ap_")
:out-apk-path (str target-path "/" project-name ".apk")
:keystore-path (str (System/getenv "HOME") "/.android/debug.keystore")
+ :adb-bin (str sdk-path "/platform-tools/adb")
:key-alias "androiddebugkey"
:repl-device-port 9999
:repl-local-port 9999
@@ -55,7 +56,8 @@
"Merges project's `:android` map with the default parameters map and
absolutizes paths in the `android` map."
[{:keys [name target-path android] :as project}]
- (let [android-params (merge (get-default-android-params name target-path)
+ (let [android-params (merge (get-default-android-params name target-path
+ (:sdk-path android))
android)]
(absolutize-android-paths
(assoc project :android android-params))))
@@ -132,7 +134,8 @@ This function should be rewritten in future."
(.waitFor ~process-name)
(if-not (= (.exitValue ~process-name) 0)
(apply abort output#)
- (apply debug output#)))))
+ (apply debug output#))
+ output#)))
(defn sh
"Executes the command given by `args` in a subprocess. Flattens the
@@ -177,7 +180,14 @@ This function should be rewritten in future."
task-name (join (interpose " " arglist))))))
(defn read-password
- "Reads the password from the standard input stream without echoing
- the characters."
+ "Reads the password from the console without echoing the
+ characters."
[prompt]
(join (.readPassword (System/console) prompt nil)))
+
+(defn append-suffix
+ "Appends a suffix to a filename, e.g. transforming `sample.apk` into
+ `sample-signed.apk`"
+ [filename suffix]
+ (let [[_ without-ext ext] (re-find #"(.+)(\.\w+)" filename)]
+ (str without-ext "-" suffix ext)))

0 comments on commit a3c4181

Please sign in to comment.