diff --git a/src/main/kotlin/com/beust/kobalt/misc/RunCommand.kt b/src/main/kotlin/com/beust/kobalt/misc/RunCommand.kt index c619073b..05b00116 100644 --- a/src/main/kotlin/com/beust/kobalt/misc/RunCommand.kt +++ b/src/main/kotlin/com/beust/kobalt/misc/RunCommand.kt @@ -10,8 +10,8 @@ open class RunCommand(val command: String) { val DEFAULT_SUCCESS = { output: List -> } // val DEFAULT_SUCCESS_VERBOSE = { output: List -> log(2, "Success:\n " + output.joinToString("\n"))} val defaultSuccess = DEFAULT_SUCCESS - val defaultError = { - output: List -> error("Error:\n " + output.joinToString("\n")) + val DEFAULT_ERROR = { + output: List -> error(output.joinToString("\n ")) } var directory = File(".") @@ -30,8 +30,8 @@ open class RunCommand(val command: String) { return this } - fun run(args: List, - errorCallback: Function1, Unit> = defaultError, + open fun run(args: List, + errorCallback: Function1, Unit> = DEFAULT_ERROR, successCallback: Function1, Unit> = defaultSuccess) : Int { val allArgs = arrayListOf() allArgs.add(command) @@ -48,27 +48,31 @@ open class RunCommand(val command: String) { } } val callSucceeded = process.waitFor(30, TimeUnit.SECONDS) - val hasErrorStream = process.errorStream.available() > 0 - var hasErrors = ! callSucceeded - if (useErrorStreamAsErrorIndicator && ! hasErrors) { - hasErrors = hasErrors || hasErrorStream - } - if (useInputStreamAsErrorIndicator && ! hasErrors) { - hasErrors = hasErrors || process.inputStream.available() > 0 - } + val input = if (process.inputStream.available() > 0) fromStream(process.inputStream) + else listOf() + val error = if (process.errorStream.available() > 0) fromStream(process.errorStream) + else listOf() + val isSuccess = isSuccess(callSucceeded, input, error) - if (! hasErrors) { + if (isSuccess) { successCallback(fromStream(process.inputStream)) } else { - val stream = if (hasErrorStream) process.errorStream - else if (process.inputStream.available() > 0) process.inputStream - else null - val errorString = - if (stream != null) fromStream(stream).joinToString("\n") - else "" - errorCallback(listOf("$command failed") + errorString) + errorCallback(error + input) } - return if (hasErrors) 1 else 0 + + return if (isSuccess) 0 else 1 + } + + open protected fun isSuccess(callSucceeded: Boolean, input: List, error: List) : Boolean { + var hasErrors = ! callSucceeded + if (useErrorStreamAsErrorIndicator && ! hasErrors) { + hasErrors = hasErrors || error.size > 0 + } + if (useInputStreamAsErrorIndicator && ! hasErrors) { + hasErrors = hasErrors || input.size > 0 + } + + return ! hasErrors } private fun fromStream(ins: InputStream) : List { diff --git a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidBuild.kt b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidBuild.kt index a856a62b..4a72cc15 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidBuild.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidBuild.kt @@ -11,7 +11,8 @@ import com.android.ide.common.blame.Message import com.android.ide.common.process.* import com.android.ide.common.res2.* import com.android.manifmerger.ManifestMerger2 -import com.android.sdklib.repository.FullRevision +import com.android.sdklib.AndroidTargetHash +import com.android.sdklib.SdkManager import com.android.utils.StdLogger import com.beust.kobalt.Variant import com.beust.kobalt.api.Project @@ -70,7 +71,8 @@ class AndroidBuild { val logger = StdLogger(StdLogger.Level.VERBOSE) val processExecutor = DefaultProcessExecutor(logger) val javaProcessExecutor = KobaltJavaProcessExecutor() - val sdkLoader : SdkLoader = DefaultSdkLoader.getLoader(File(AndroidFiles.androidHome(project, config))) + val androidHome = File(AndroidFiles.androidHome(project, config)) + val sdkLoader : SdkLoader = DefaultSdkLoader.getLoader(androidHome) val androidBuilder = AndroidBuilder(project.name, "kobalt-android-plugin", processExecutor, javaProcessExecutor, @@ -83,13 +85,14 @@ class AndroidBuild { val outputDir = AndroidFiles.mergedResources(project, variant) val layout = ProjectLayout() val preprocessor = NoOpResourcePreprocessor() - - // AndroidTargetHash.getTargetHashString(target)) - val targetHash = "android-22" - val buildToolsRevision = FullRevision(23, 0, 1) val libraryRequests = arrayListOf() - androidBuilder.setTargetInfo(sdkLoader.getSdkInfo(logger), - sdkLoader.getTargetInfo(targetHash, buildToolsRevision, logger), + val sdk = sdkLoader.getSdkInfo(logger) + val sdkManager = SdkManager.createManager(androidHome.absolutePath, logger) + val maxPlatformTarget = sdkManager.targets.filter { it.isPlatform }.last() + val maxPlatformTargetHash = AndroidTargetHash.getPlatformHashString(maxPlatformTarget.version) + + androidBuilder.setTargetInfo(sdk, + sdkLoader.getTargetInfo(maxPlatformTargetHash, maxPlatformTarget.buildToolInfo.revision, logger), libraryRequests) val writer = MergedResourceWriter(File(outputDir), @@ -107,6 +110,8 @@ class AndroidBuild { // Manifest // val mainManifest = File("src/main/AndroidManifest.xml") + + val appInfo = AppInfo(mainManifest, config) val manifestOverlays = listOf() val libraries = listOf() val outManifest = AndroidFiles.mergedManifest(project, variant) @@ -114,11 +119,11 @@ class AndroidBuild { val reportFile = File(KFiles.joinDir(project.directory, project.buildDirectory, "manifest-merger-report.txt")) androidBuilder.mergeManifests(mainManifest, manifestOverlays, libraries, null /* package override */, - 23 /* versionCode */, - "23", /* versionName */ - "16", /* minSdk */ - "23" /* targetSdkVersion */, - 23 /* maxSdkVersion */, + appInfo.versionCode, + appInfo.versionName, + appInfo.minSdkVersion, + appInfo.targetSdkVersion, + 23, outManifest, outAaptSafeManifestLocation, ManifestMerger2.MergeType.APPLICATION, diff --git a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt index 565963c8..25f48b34 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt @@ -321,12 +321,20 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v @Task(name = TASK_INSTALL, description = "Install the apk file", runAfter = arrayOf(TASK_GENERATE_DEX, "assemble")) fun taskInstall(project: Project): TaskResult { + + /** + * adb has weird ways of signaling errors, that's the best I've found so far. + */ + class AdbInstall : RunCommand(adb(project)) { + override fun isSuccess(callSucceeded: Boolean, input: List, error: List) + = input.filter { it.contains("Success")}.size > 0 + } + val apk = apk(project, context.variant.shortArchiveName) - RunCommand(adb(project)).useErrorStreamAsErrorIndicator(false).run(args = listOf( - "install", "-r", - apk)) + val result = AdbInstall().useErrorStreamAsErrorIndicator(true).run( + args = listOf("install", "-r", apk)) log(1, "Installed $apk") - return TaskResult() + return TaskResult(result == 0) } private val classpathEntries = HashMultimap.create() @@ -417,8 +425,12 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v } -class AndroidConfig(val project: Project, var compileSdkVersion : String = "23", - var buildToolsVersion : String = "23.0.1", +class AndroidConfig(val project: Project, + var compileSdkVersion : String? = null, + var buildToolsVersion: String? = null, + var minSdkVersion: String? = null, + var versionCode: Int? = null, + var targetSdkVersion: String? = null, var applicationId: String? = null, val androidHome: String? = null) { diff --git a/src/main/kotlin/com/beust/kobalt/plugin/android/AppInfo.kt b/src/main/kotlin/com/beust/kobalt/plugin/android/AppInfo.kt new file mode 100644 index 00000000..4f2b8847 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/plugin/android/AppInfo.kt @@ -0,0 +1,27 @@ +package com.beust.kobalt.plugin.android + +import com.android.io.FileWrapper +import com.android.xml.AndroidManifest +import java.io.File + +/** + * Manage the main application id for the app, based on an overlay of the AndroidManifest.xml and + * values specified in the Android config (in the build file). + */ +class AppInfo(val androidManifest: File, val config: AndroidConfig) { + val abstractManifest = FileWrapper(androidManifest) + + private fun overlay(manifestValue: T, configValue: T?) = configValue ?: manifestValue + + val versionCode : Int + get() = overlay(AndroidManifest.getVersionCode(abstractManifest), config.versionCode) + + val versionName : String + get() = versionCode.toString() + + val minSdkVersion: String? + get() = overlay(AndroidManifest.getMinSdkVersion(abstractManifest), config.minSdkVersion)?.toString() + + val targetSdkVersion: String? + get() = overlay(AndroidManifest.getTargetSdkVersion(abstractManifest), config.targetSdkVersion)?.toString() +}