Browse files

Make compatible with Windows systems

This includes the abstraction from path separators and support for
batch-files in Android SDK.
  • Loading branch information...
1 parent 79f0d76 commit 4e0655db066b65d98f0149d6ef615246dfcfd622 @alexander-yakushev alexander-yakushev committed Mar 1, 2013
Showing with 47 additions and 16 deletions.
  1. +1 −1 project.clj
  2. +8 −7 src/leiningen/droid/build.clj
  3. +2 −2 src/leiningen/droid/compile.clj
  4. +36 −6 src/leiningen/droid/utils.clj
@@ -1,4 +1,4 @@
-(defproject lein-droid/lein-droid "0.1.0-beta6"
+(defproject lein-droid/lein-droid "0.1.0-preview1"
:description "Plugin for easy Clojure/Android development and deployment"
:url ""
:license {:name "Eclipse Public License"
@@ -7,9 +7,10 @@
[main :only [debug info]]]
[compile :only [code-gen compile]]
- [utils :only [get-sdk-android-jar first-matched proj sh dev-build?
+ [utils :only [get-sdk-android-jar first-matched sh dev-build?
ensure-paths with-process read-password append-suffix
- create-debug-keystore get-project-file read-project]]
+ create-debug-keystore get-project-file read-project
+ sdk-binary]]
[manifest :only [write-manifest-with-internet-permission]]])
(:require [ :as io]
leiningen.jar leiningen.javac))
@@ -28,7 +29,7 @@
compile-path :compile-path :as project}]
(info "Creating DEX....")
(ensure-paths sdk-path)
- (let [dx-bin (str sdk-path "/platform-tools/dx")
+ (let [dx-bin (sdk-binary sdk-path :dx)
no-optimize (if (and (not force-dex-optimize) (dev-build? project))
"--no-optimize" [])
annotations (str sdk-path "/tools/support/annotations.jar")
@@ -48,7 +49,7 @@
[{{:keys [sdk-path res-path out-res-path]} :android}]
(info "Crunching resources...")
(ensure-paths sdk-path res-path)
- (let [aapt-bin (str sdk-path "/platform-tools/aapt")]
+ (let [aapt-bin (sdk-binary sdk-path :aapt)]
(sh aapt-bin "crunch -v"
"-S" res-path
"-C" out-res-path)))
@@ -100,7 +101,7 @@
:as project}]
(info "Packaging resources...")
(ensure-paths sdk-path manifest-path res-path)
- (let [aapt-bin (str sdk-path "/platform-tools/aapt")
+ (let [aapt-bin (sdk-binary sdk-path :aapt)
android-jar (get-sdk-android-jar sdk-path target-version)
dev-build (dev-build? project)
manifest-file (io/file manifest-path)
@@ -134,7 +135,7 @@
java-only :java-only :as project}]
(info "Creating APK...")
(ensure-paths sdk-path out-res-pkg-path out-dex-path)
- (let [apkbuilder-bin (str sdk-path "/tools/apkbuilder")
+ (let [apkbuilder-bin (sdk-binary sdk-path :apkbuilder)
suffix (if (dev-build? project) "debug-unaligned" "unaligned")
unaligned-path (append-suffix out-apk-path suffix)
clojure-jar (first-matched #(re-find #"android[/\\]clojure" (str %))
@@ -178,7 +179,7 @@
Done by calling `zipalign` binary on APK file."
[{{:keys [sdk-path out-apk-path]} :android :as project}]
(info "Aligning APK...")
- (let [zipalign-bin (str sdk-path "/tools/zipalign")
+ (let [zipalign-bin (sdk-binary sdk-path :zipalign)
unaligned-suffix (if (dev-build? project) "debug-unaligned" "unaligned")
unaligned-path (append-suffix out-apk-path unaligned-suffix)
aligned-path (if (dev-build? project)
@@ -5,7 +5,7 @@
[ :as io]
[clojure.set :as sets]
[leiningen.core.eval :as eval])
- (:use [leiningen.droid.utils :only [get-sdk-android-jar
+ (:use [leiningen.droid.utils :only [get-sdk-android-jar sdk-binary
ensure-paths sh dev-build?]]
[leiningen.droid.manifest :only [get-package-name]]
@@ -23,7 +23,7 @@
[{{:keys [sdk-path target-version manifest-path res-path gen-path
out-res-path external-res-paths library]} :android}]
(info "Generating")
- (let [aapt-bin (str sdk-path "/platform-tools/aapt")
+ (let [aapt-bin (sdk-binary sdk-path :aapt)
android-jar (get-sdk-android-jar sdk-path target-version)
manifest-file (io/file manifest-path)
library-specific (if library "--non-constant-id" "--auto-add-overlay")
@@ -45,7 +45,7 @@
:assets-path "assets"
:out-res-pkg-path (str target-path "/" name ".ap_")
:out-apk-path (str target-path "/" name ".apk")
- :keystore-path (str (System/getenv "HOME") "/.android/debug.keystore")
+ :keystore-path (str (file (System/getProperty "user.home") ".android" "debug.keystore"))
:adb-bin (str sdk-path "/platform-tools/adb")
:key-alias "androiddebugkey"
:repl-device-port 9999
@@ -111,17 +111,17 @@
(defn get-sdk-platform-path
"Returns a version-specific path to the Android platform tools."
[sdk-root version]
- (format "%s/platforms/android-%s" sdk-root version))
+ (str (file sdk-root "platforms" (str "android-" version))))
(defn get-sdk-android-jar
"Returns a version-specific path to the `android.jar` SDK file."
[sdk-root version]
- (str (get-sdk-platform-path sdk-root version) "/android.jar"))
+ (str (file (get-sdk-platform-path sdk-root version) "android.jar")))
(defn get-sdk-google-api-path
"Returns a version-specific path to the Google SDK directory."
[sdk-root version]
- (format "%s/add-ons/addon-google_apis-google-%s" sdk-root version))
+ (str (file sdk-root "add-ons" (str "addon-google_apis-google-" version))))
(defn get-sdk-google-api-jars
"Returns a version-specific paths to all Google SDK jars."
@@ -137,6 +137,29 @@
[pred coll]
(some (fn [item] (when (pred item) item)) coll))
+;; #### Convenient functions to run SDK binaries
+(def sdk-binary-paths
+ "Contains relative paths to different SDK binaries for both Unix and
+ Windows platforms."
+ {:dx {:unix ["platform-tools" "dx"] :win ["platform-tools" "dx.bat"]}
+ :aapt {:unix ["platform-tools" "aapt"] :win ["platform-tools" "aapt.exe"]}
+ :apkbuilder {:unix ["tools" "apkbuilder"] :win ["tools" "apkbuilder.bat"]}
+ :zipalign {:unix ["tools" "zipalign"] :win ["tools" "zipalign.exe"]}})
+(defn sdk-binary
+ "Given the path to SDK and the binary keyword, returns either a full
+ path to the binary as a string, or a vector with call to cmd.exe for
+ batch-files."
+ [sdk-path binary-kw]
+ (let [binary (get-in sdk-binary-paths
+ [binary-kw
+ (if (.startsWith (System/getProperty "") "Windows")
+ :win :unix)])]
+ (if (.endsWith (last binary) ".bat")
+ ["cmd.exe" "/C" (str (apply file sdk-path binary))]
+ (str (apply file sdk-path binary)))))
(defmacro with-process
"Executes the subprocess specified in the binding list and applies
`body` do it while it is running. The binding list consists of a var
@@ -174,14 +197,21 @@
(defmacro ensure-paths
"Checks if the given directories or files exist. Aborts Leiningen
- execution in case either of them doesn't or the value equals nil."
+ execution in case either of them doesn't or the value equals nil.
+ We assume paths to be strings or lists/vectors. The latter case is
+ used exclusively for Windows batch-files which are represented like
+ `cmd.exe /C batch-file`, so we test third element of the list for
+ the existence."
[& paths]
~@(for [p paths]
`(cond (nil? ~p)
(abort "The value of" (str '~p) "is nil. Abort execution.")
- (not (.exists (file ~p)))
+ (or
+ (and (sequential? ~p) (not (.exists (file (nth ~p 2)))))
+ (and (string? ~p) (not (.exists (file ~p)))))
(abort "The path" ~p "doesn't exist. Abort execution.")))))
(defn wrong-usage

0 comments on commit 4e0655d

Please sign in to comment.