mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-26 16:28:12 -07:00
NewRunCommand.
This commit is contained in:
parent
bf4b6144c3
commit
64bfcbf12a
1 changed files with 127 additions and 0 deletions
|
@ -0,0 +1,127 @@
|
||||||
|
package com.beust.kobalt.misc
|
||||||
|
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.File
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class RunCommandInfo {
|
||||||
|
lateinit var command: String
|
||||||
|
var args : List<String> = arrayListOf()
|
||||||
|
var directory : File = File("")
|
||||||
|
var env : Map<String, String> = hashMapOf()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* This field is used to specify how errors are caught.
|
||||||
|
*/
|
||||||
|
var useErrorStreamAsErrorIndicator : Boolean = true
|
||||||
|
var useInputStreamAsErrorIndicator : Boolean = false
|
||||||
|
|
||||||
|
var errorCallback: Function1<List<String>, Unit> = NewRunCommand.DEFAULT_ERROR
|
||||||
|
var successCallback: Function1<List<String>, Unit> = NewRunCommand.DEFAULT_SUCCESS
|
||||||
|
|
||||||
|
var isSuccess: (Boolean, List<String>, List<String>) -> Boolean = {
|
||||||
|
isSuccess: Boolean,
|
||||||
|
input: List<String>,
|
||||||
|
error: List<String> ->
|
||||||
|
var hasErrors = ! isSuccess
|
||||||
|
if (useErrorStreamAsErrorIndicator && ! hasErrors) {
|
||||||
|
hasErrors = hasErrors || error.size > 0
|
||||||
|
}
|
||||||
|
if (useInputStreamAsErrorIndicator && ! hasErrors) {
|
||||||
|
hasErrors = hasErrors || input.size > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
! hasErrors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runCommand(init: RunCommandInfo.() -> Unit) = NewRunCommand(RunCommandInfo().apply { init() }).invoke()
|
||||||
|
|
||||||
|
open class NewRunCommand(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> ->
|
||||||
|
kotlin.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("\\", "/"))
|
||||||
|
pb.environment().let { pbEnv ->
|
||||||
|
info.env.forEach {
|
||||||
|
pbEnv.put(it.key, it.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val process = pb.start()
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn the given InputStream into a list of strings.
|
||||||
|
*/
|
||||||
|
private fun fromStream(ins: InputStream) : List<String> {
|
||||||
|
val result = arrayListOf<String>()
|
||||||
|
val br = BufferedReader(InputStreamReader(ins))
|
||||||
|
var line = br.readLine()
|
||||||
|
|
||||||
|
while (line != null) {
|
||||||
|
result.add(line)
|
||||||
|
line = br.readLine()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue