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