1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-27 08:38:13 -07:00

Checkpoint.

This commit is contained in:
Cedric Beust 2015-12-06 10:37:53 -08:00
parent e93f4ba85f
commit 8882c1cae5
4 changed files with 143 additions and 75 deletions

View file

@ -6,65 +6,28 @@ import java.io.InputStream
import java.io.InputStreamReader import java.io.InputStreamReader
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
open class RunCommand(val command: String) { class RunCommandInfo {
val DEFAULT_SUCCESS = { output: List<String> -> } lateinit var command: String
// val DEFAULT_SUCCESS_VERBOSE = { output: List<String> -> log(2, "Success:\n " + output.joinToString("\n"))} var args : List<String> = arrayListOf()
val defaultSuccess = DEFAULT_SUCCESS var directory : File = File("")
val DEFAULT_ERROR = { var env : Map<String, String> = hashMapOf()
output: List<String> -> error(output.joinToString("\n "))
}
var directory = File(".")
var env = hashMapOf<String, String>()
/** /**
* Some commands fail but return 0, so the only way to find out if they failed is to look * Some commands fail but return 0, so the only way to find out if they failed is to look
* at the error stream. However, some commands succeed but output text on the error stream. * at the error stream. However, some commands succeed but output text on the error stream.
* This field is used to specify how errors are caught. * This field is used to specify how errors are caught.
*/ */
var useErrorStreamAsErrorIndicator = true var useErrorStreamAsErrorIndicator : Boolean = true
var useInputStreamAsErrorIndicator = false var useInputStreamAsErrorIndicator : Boolean = false
fun useErrorStreamAsErrorIndicator(f: Boolean) : RunCommand { var errorCallback: Function1<List<String>, Unit> = RunCommand.DEFAULT_ERROR
useErrorStreamAsErrorIndicator = f var successCallback: Function1<List<String>, Unit> = RunCommand.DEFAULT_SUCCESS
return this
}
open fun run(args: List<String>, var isSuccess: (Boolean, List<String>, List<String>) -> Boolean = {
errorCallback: Function1<List<String>, Unit> = DEFAULT_ERROR, isSuccess: Boolean,
successCallback: Function1<List<String>, Unit> = defaultSuccess) : Int { input: List<String>,
val allArgs = arrayListOf<String>() error: List<String> ->
allArgs.add(command) var hasErrors = ! isSuccess
allArgs.addAll(args)
val pb = ProcessBuilder(allArgs)
pb.directory(directory)
log(2, "Running command in directory ${directory.absolutePath}" +
"\n " + allArgs.joinToString(" ").replace("\\", "/"))
val process = pb.start()
pb.environment().let { pbEnv ->
env.forEach {
pbEnv.put(it.key, it.value)
}
}
val callSucceeded = process.waitFor(30, TimeUnit.SECONDS)
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 (isSuccess) {
successCallback(fromStream(process.inputStream))
} else {
errorCallback(error + input)
}
return if (isSuccess) 0 else 1
}
open protected fun isSuccess(callSucceeded: Boolean, input: List<String>, error: List<String>) : Boolean {
var hasErrors = ! callSucceeded
if (useErrorStreamAsErrorIndicator && ! hasErrors) { if (useErrorStreamAsErrorIndicator && ! hasErrors) {
hasErrors = hasErrors || error.size > 0 hasErrors = hasErrors || error.size > 0
} }
@ -72,9 +35,83 @@ open class RunCommand(val command: String) {
hasErrors = hasErrors || input.size > 0 hasErrors = hasErrors || input.size > 0
} }
! hasErrors
}
}
fun runCommand(init: RunCommandInfo.() -> Unit) = RunCommand(RunCommandInfo().apply { init() }).invoke()
open class RunCommand(val info: RunCommandInfo) {
companion object {
val DEFAULT_SUCCESS = { output: List<String> -> }
// val DEFAULT_SUCCESS_VERBOSE = { output: List<String> -> log(2, "Success:\n " + output.joinToString("\n"))}
// val defaultSuccess = DEFAULT_SUCCESS
val DEFAULT_ERROR = {
output: List<String> ->
error(output.joinToString("\n "))
}
}
// fun useErrorStreamAsErrorIndicator(f: Boolean) : RunCommand {
// useErrorStreamAsErrorIndicator = f
// return this
// }
fun invoke() : Int {
val allArgs = arrayListOf<String>()
allArgs.add(info.command)
allArgs.addAll(info.args)
val pb = ProcessBuilder(allArgs)
pb.directory(info.directory)
log(2, "Running command in directory ${info.directory.absolutePath}" +
"\n " + allArgs.joinToString(" ").replace("\\", "/"))
val process = pb.start()
pb.environment().let { pbEnv ->
info.env.forEach {
pbEnv.put(it.key, it.value)
}
}
// Run the command and collect the return code and streams
val returnCode = process.waitFor(30, TimeUnit.SECONDS)
val input = if (process.inputStream.available() > 0) fromStream(process.inputStream)
else listOf()
val error = if (process.errorStream.available() > 0) fromStream(process.errorStream)
else listOf()
// Check to see if the command succeeded
val isSuccess = isSuccess(returnCode, input, error)
if (isSuccess) {
info.successCallback(input)
} else {
info.errorCallback(error + input)
}
return if (isSuccess) 0 else 1
}
/**
* Subclasses can override this method to do their own error handling, since commands can
* have various ways to signal errors.
*/
open protected fun isSuccess(isSuccess: Boolean, input: List<String>, error: List<String>) : Boolean {
var hasErrors = ! isSuccess
if (info.useErrorStreamAsErrorIndicator && ! hasErrors) {
hasErrors = hasErrors || error.size > 0
}
if (info.useInputStreamAsErrorIndicator && ! hasErrors) {
hasErrors = hasErrors || input.size > 0
}
return ! hasErrors return ! hasErrors
} }
/**
* Turn the given InputStream into a list of strings.
*/
private fun fromStream(ins: InputStream) : List<String> { private fun fromStream(ins: InputStream) : List<String> {
val result = arrayListOf<String>() val result = arrayListOf<String>()
val br = BufferedReader(InputStreamReader(ins)) val br = BufferedReader(InputStreamReader(ins))

View file

@ -1,24 +1,54 @@
package com.beust.kobalt.plugin.android package com.beust.kobalt.plugin.android
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.misc.RunCommand
import com.beust.kobalt.misc.log import com.beust.kobalt.misc.log
import com.beust.kobalt.misc.runCommand
import java.io.File import java.io.File
open class AndroidCommand(project: Project, androidHome: String, command: String, cwd: File = File(project.directory)) open class AndroidCommand(project: Project, val androidHome: String, val command: String,
: RunCommand(command) { val directory: File = File(project.directory),
init { val useErrorStreamAsErrorIndicator : Boolean = true,
env.put("ANDROID_HOME", androidHome) val args: List<String>)
directory = cwd // : RunCommand(command, directory = cwd, args = args
} // ,
// successCallback = { output ->
// log(1, "$command succeeded:")
// output.forEach {
// log(1, " $it")
// }
// }
{
open fun call(args: List<String>) = run(args,
// val SUCCESS_CALLBACK : (List<String>) -> Unit = { output ->
// log(1, "$command succeeded:")
// output.forEach {
// log(1, " $it")
// }
// }
//
// val ERROR_CALLBACK : (List<String>) -> Unit = { output ->
// with(StringBuilder()) {
// append("Error running $command:")
// output.forEach {
// append(" $it")
// }
// error(this.toString())
// }
// }nComman
open fun call(theseArgs: List<String>) : Int {
val rc = runCommand {
args = theseArgs
useErrorStreamAsErrorIndicator = useErrorStreamAsErrorIndicator
directory = directory
env = hashMapOf("ANDROID_HOME" to androidHome)
successCallback = { output -> successCallback = { output ->
log(1, "$command succeeded:") log(1, "$command succeeded:")
output.forEach { output.forEach {
log(1, " $it") log(1, " $it")
} }
}, }
errorCallback = { output -> errorCallback = { output ->
with(StringBuilder()) { with(StringBuilder()) {
append("Error running $command:") append("Error running $command:")
@ -27,7 +57,10 @@ open class AndroidCommand(project: Project, androidHome: String, command: String
} }
error(this.toString()) error(this.toString())
} }
}) }
}
return rc
}
} }

View file

@ -107,15 +107,12 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
* aapt returns 0 even if it fails, so in order to detect whether it failed, we are checking * aapt returns 0 even if it fails, so in order to detect whether it failed, we are checking
* if its error stream contains anything. * if its error stream contains anything.
*/ */
inner class AaptCommand(project: Project, aapt: String, val aaptCommand: String, inner class AaptCommand(project: Project, aapt: String, val aaptCommand: String, cwd: File = File("."),
cwd: File = File(".")) : AndroidCommand(project, androidHome(project), aapt) { args: List<String>)
init { : AndroidCommand(project, androidHome(project), aapt,
directory = cwd directory = cwd,
useErrorStreamAsErrorIndicator = true useErrorStreamAsErrorIndicator = true,
} args = arrayListOf(aaptCommand) + args)
override fun call(args: List<String>) = super.run(arrayListOf(aaptCommand) + args)
}
private fun generateR(project: Project, generated: String, aapt: String) : Boolean { private fun generateR(project: Project, generated: String, aapt: String) : Boolean {
val compileSdkVersion = compileSdkVersion(project) val compileSdkVersion = compileSdkVersion(project)
@ -132,7 +129,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
val variantDir = context.variant.toIntermediateDir() val variantDir = context.variant.toIntermediateDir()
val rDirectory = KFiles.joinAndMakeDir(generated, "source", "r", variantDir).toString() val rDirectory = KFiles.joinAndMakeDir(generated, "source", "r", variantDir).toString()
val result = AaptCommand(project, aapt, "package").call(listOf( val result = AaptCommand(project, aapt, "package", args = listOf(
"-f", "-f",
"--no-crunch", "--no-crunch",
"-I", androidJar.toString(), "-I", androidJar.toString(),
@ -358,7 +355,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v
* adb has weird ways of signaling errors, that's the best I've found so far. * adb has weird ways of signaling errors, that's the best I've found so far.
*/ */
class AdbInstall : RunCommand(adb(project)) { class AdbInstall : RunCommand(adb(project)) {
override fun isSuccess(callSucceeded: Boolean, input: List<String>, error: List<String>) override fun isSuccess(isSuccess: Boolean, input: List<String>, error: List<String>)
= input.filter { it.contains("Success")}.size > 0 = input.filter { it.contains("Success")}.size > 0
} }

View file

@ -55,9 +55,10 @@ class RetrolambdaPlugin @Inject constructor(val dependencyManager: DependencyMan
"-Dretrolambda.bytecodeVersion=${config.byteCodeVersion}", "-Dretrolambda.bytecodeVersion=${config.byteCodeVersion}",
"-jar", JAR.jarFile.get().path) "-jar", JAR.jarFile.get().path)
val result = RunCommand("java").apply { val result = RunCommand("java",
directory = File(project.directory) directory = File(project.directory),
}.run(args) args = args)
.run()
TaskResult(result == 0) TaskResult(result == 0)
} else { } else {
TaskResult() TaskResult()