Skip to content
This repository has been archived by the owner on Apr 25, 2024. It is now read-only.

Commit

Permalink
Choose device interactively if more than one is available
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-yakushev committed Jun 5, 2012
1 parent ab7b385 commit a3c4181
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 75 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -8,4 +8,4 @@ pom.xml
*.class
.lein-deps-sum
.lein-failures
.lein-plugins
.lein-plugins
2 changes: 1 addition & 1 deletion project.clj
@@ -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"
Expand Down
26 changes: 15 additions & 11 deletions src/leiningen/droid.clj
Expand Up @@ -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."
Expand All @@ -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."
Expand Down Expand Up @@ -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
Expand Down
28 changes: 3 additions & 25 deletions src/leiningen/droid/build.clj
Expand Up @@ -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
Expand Down Expand Up @@ -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)))
86 changes: 86 additions & 0 deletions src/leiningen/droid/device.clj
@@ -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)}))
32 changes: 0 additions & 32 deletions src/leiningen/droid/run.clj

This file was deleted.

20 changes: 15 additions & 5 deletions src/leiningen/droid/utils.clj
Expand Up @@ -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"
Expand All @@ -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
Expand All @@ -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))))
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.