прослушивать события Runtime.exe c () - PullRequest
0 голосов
/ 01 мая 2020

У меня есть функция, которая выполняет строку как команду со следующим фрагментом кода:

fun String.runAsCommand() : String {
    val process = Runtime.getRuntime().exec(this)
    if (!process.waitFor(60, TimeUnit.SECONDS)) {
        process.destroy()
        throw RuntimeException("execution timed out: $this")
    }
    if (process.exitValue() != 0) {
        throw RuntimeException("execution failed with code ${process.exitValue()}: $this")
    }

    return process.inputStream.bufferedReader().readText()
}

Однако этот код выводит вывод команды, как только все будет сделано. Но рассматриваемый процесс на самом деле является длительным процессом, который занимает до 40 секунд и постепенно выводит статус на консоль. Как мне перехватить эти логи echo / console с помощью какой-то конструкции слушателя?

1 Ответ

1 голос
/ 01 мая 2020

Стандартным способом является использование ProcessBuilder и запуск другого потока, который читает стандартный вывод процесса (который является вашим входом).

Я не уверен, что это лучший подход, но вот код, который я придумал, чтобы сделать что-то очень похожее. (В моем случае процесс записал в свои stdout и stderr, поэтому мне нужно было прочитать их оба - но мне не нужно было видеть их до завершения процесса. Мне также нужно было возвращать состояние выхода процесса вместе с обоими и для обработки тайм-аута. Мне не нужно было отправлять что-либо в стандартный поток процесса, хотя, если вам это нужно, вам придется его расширить.)

/**
* Runs a system command and captures its output (and stderr).
*
* @param command The program name and any arguments.
* @param workingDir The working directory of the process, or `null` for the same as this process.
* @param timeoutSecs Maximum time to wait for it to finish, in seconds.  (Default is 5 mins.)
* @param throwOnFailure Whether to throw a [ProcessFailedException] if it returns a non-zero exit value.
* @throws IndexOutOfBoundsException if the command is empty.
* @throws SecurityException if a security manager prevented creation of the process or a redirection.
* @throws UnsupportedOperationException if the OS doesn't support process creation.
* @throws IOException if an I/O error occurs.
* @throws ProcessTimedOutException if the timeout expires before the process finishes.
* @throws ProcessFailedException if the process returns a non-zero exit status.
*/
fun runProcess(vararg command: String, workingDir: File? = null, timeoutSecs: Long = 300,
                throwOnFailure: Boolean = true): ProcessResult {
    val proc = ProcessBuilder(*command)
                .directory(workingDir)
                .start()

    // Must read both output and error, else it can deadlock.

    class StreamReader(val stream: InputStream, val result: StringBuilder) : Runnable {
        override fun run() = stream.bufferedReader().use { s ->
            while (true)
                result.appendln(s.readLine() ?: break)
        }
    }

    val output = StringBuilder()
    Thread(StreamReader(proc.inputStream, output)).start()
    val error = StringBuilder()
    Thread(StreamReader(proc.errorStream, error)).start()

    val exited = proc.waitFor(timeoutSecs, TimeUnit.SECONDS)

    if (!exited)
        throw ProcessTimedOutException("${command[0]} timed out!", timeoutSecs, output.toString(), error.toString())
    val exitValue = proc.exitValue()
    if (exitValue != 0 && throwOnFailure)
        throw ProcessFailedException("${command[0]} failed: $error", exitValue, output.toString(), error.toString())
    return ProcessResult(exitValue, output.toString(), error.toString())
}

/** Thrown if a process doesn't finish within the timeout period. */
class ProcessTimedOutException(msg: String, val timeoutSecs: Long, val output: String, val error: String) : Exception(msg)

/** Thrown if a process returns a non-zero code. */
class ProcessFailedException(msg: String, val exitValue: Int, val output: String, val error: String) : Exception(msg)

/** Returned if a process completes. */
class ProcessResult(val exitValue: Int, val output: String, val error: String)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...