Shell, JVM, and SSH command execution on Linux, MacOS, or Windows for Java 11+ and Kotlin
 
 
Go to file
nathan 19a3ec0f46 Cleaned up license 2020-08-07 23:22:31 +02:00
gradle/wrapper Updated gradle 2020-08-06 11:02:13 +02:00
src/dorkbox/executor Removed dependency on ANSI Console (it's inputstream can be directly used, no need for manipulating inputstreams) 2020-08-07 23:22:14 +02:00
test/dorkbox Cleaned up license 2020-08-07 23:22:31 +02:00
.gitignore Updated to use Gradle Utils for gradle/project update management 2019-05-13 15:18:32 +02:00
LICENSE Cleaned up license 2020-08-07 23:22:31 +02:00
LICENSE.Apachev2 Moved shell executor from utils to it's own project 2017-11-26 21:57:25 +01:00
LICENSE.CC0 Cleaned up license 2020-08-07 23:22:31 +02:00
LICENSE.MIT Added/updated license files 2020-08-06 11:01:57 +02:00
README.md Executor is now merged with ZeroTurnaround Executor, and entirely written in Kotlin with coroutines. The API is similar to the ZT executor, however there are a number a huge changes in the way it works. The design is a lot more fluent, and contains less special-case objects for working with running processes (along with different types, such as jvm-forking and remote ssh processes). 2020-08-06 11:07:25 +02:00
build.gradle.kts Removed dependency on ANSI Console (it's inputstream can be directly used, no need for manipulating inputstreams) 2020-08-07 23:22:14 +02:00
gradlew Updated gradle 2020-08-06 11:02:13 +02:00
gradlew.bat Updated gradle 2020-08-06 11:02:13 +02:00
settings.gradle.kts Build converted to kotlin script 2019-03-17 23:15:21 +01:00

README.md

Executor

Dorkbox Github Gitlab

Shell, JVM, and remote SSH command execution on Linux, MacOS, or Windows for Java 11+

Ironically, there are a considerable number of issues when launching shell/JVM processes via Java. This library solves problems with:

  1. Redirecting in/out/err streams correctly
  2. Enable reading a single-character from the console input-stream
  3. Correctly reading out/err process output streams to prevent memory and threading issues
  4. Executing a JVM process using the same JVM as is currently running
  5. Executing remote processes via SSH
  6. Using and supporting kotlin co-routines for thread suspension
  • This is for cross-platform use, specifically - linux 32/64, mac 32/64, and windows 32/64. Java 11+ and kotlin.

This project is powerful but still simple to use. By using a single class Executor the user gets the functionality from both java.lang.ProcessBuilder and [Apache Commons Exec](http://commons.apache.org/proper/commons -exec/), along with the ability to fork the currently running JVM process and remotely execute commands via SSH.

   

Release Notes

Examples (these are written in kotlin)

  • Easiest, and simplest way to get UTF8 output from running an application. This is VERY simple, and designed for quickly running, small -output applications. For anything just a hint that it might be MORE complex, use the builder pattern with the appropriate configuration.
val output = Executor.run("java", "-version")
  • Output is pumped to NullOutputStream
Executor().command("java", "-version").start()

  • Returning the exit code
  • Output is pumped to NullOutputStream
val exit = new Executor().command("java", "-version").startBlocking().getExitValue()

  • Return output as UTF8 String
val output = new Executor().command("java", "-version").readOutput(true).startBlocking().output.utf8()    

  • Pumping the output to a logger
Executor().command("java", "-version")
    .redirectOutput(Slf4jStream.asInfo(LoggerFactory.getLogger(javaClass.name + ".MyProcess")))
    .start()

  • Pumping the output to a logger (short form for previous)
Executor()
    .command("java", "-version")
    .redirectOutput(Slf4jStream.asInfo())
    .start()

  • Pumping the output to the logger of the caller class
Executor()
    .command("java", "-version")
    .redirectOutput(Slf4jStream.asInfo())
    .start()

  • Pumping the output to a logger
  • Returning output as UTF8 String
val output = Executor()
                .command("java", "-version")
                .redirectOutput(Slf4jStream.asInfo())
                .readOutput()
                .start()
                .output.utf8()

  • Pumping the stderr to a logger
  • Returning the output as UTF8 String
val output = Executor()
                .command("java", "-version")
                .redirectError(Slf4jStream.asInfo())
                .readOutput()
                .start()
                .output.utf8()

  • Running with a timeout of 60 seconds
  • Output pumped to NullOutputStream
try {
    runBlocking {
        Executor()
            .command("java", "-version")
            .timeout(60, TimeUnit.SECONDS)
            .start()
    }
} catch (e: TimeoutException) {
    // process is automatically destroyed
}

  • Pumping output to another OutputStream
Executor()
    .command("java", "-version")
    .redirectOutput(out)
    .start()

  • Handling output line-by-line while process is running (Version 1)
 runBlocking {
    Executor()
        .command("java", "-version")
        .redirectOutput(object : LogOutputStream() {
            override fun processLine(line: String) {
                // ...
            }
        })
        .start()
}

  • Handling output line-by-line while process is running (Version 2)
val result = Executor()
    .command("java", "-version")
    .readOutput()
    .startAsync()

runBlocking {
    val fullOutput = mutableListOf<String>()

    val output = result.output
    while (output.isOpen) {
        fullOutput.add(output.utf8())
    }

    val outputString: String = fullOutput.joinToString()
    Assert.assertFalse(outputString.isEmpty())
}

  • Destroy the running process when VM exits
  • Output pumped to NullOutputStream
Executor().command("java", "-version").destroyOnExit().start()

  • Run process with a specific environment variable
  • Output pumped to NullOutputStream
Executor().command("java", "-version").environment("foo", "bar").start()

  • Run process with a specific environment
  • Output pumped to NullOutputStream
val env = mapOf<String, String>(...)
Executor()
    .command("java", "-version")
    .environment(env)
    .start()

  • Throw exception when wrong exit code
  • Output is pumped to NullOutputStream
try {
    runBlocking {
        Executor()
            .command("java", "-version")
            .exitValues(3)
            .start()
    }
} catch (e: InvalidExitValueException) {
    println("Process exited with " + e.exitValue)
}

  • Throw exception when wrong exit code
  • Return output as UTF8 String
 var output: String
try {
    output = runBlocking {
        Executor()
            .command("java", "-version")
            .readOutput()
            .exitValues(3)
            .start()
            .output.utf8()
    }
} catch (e: InvalidExitValueException) {
    println("Process exited with " + e.exitValue)
    output = (e.result as SyncProcessResult).output.utf8()
}

  • Starting process in the background
  • Output is pumped to NullOutputStream
val deferredProcess = Executor()
    .command("java", "-version")
    .startAsync()

//do some stuff..

deferredProcess.awaitBlocking(60, TimeUnit.SECONDS)

  • Start process in the background
  • Return output as UTF8 String
val deferredProcess = Executor()
    .command("java", "-version")
    .readOutput()
    .startAsync()

//do some stuff

deferredProcess.awaitBlocking(60, TimeUnit.SECONDS)

return runBlocking {
    deferredProcess.output.utf8()
}

Maven Info

<dependencies>
    ...
    <dependency>
      <groupId>com.dorkbox</groupId>
      <artifactId>Executor</artifactId>
      <version>1.0</version>
    </dependency>
</dependencies>

Gradle Info

dependencies {
    ...
    implementation("com.dorkbox:Executor:1.0")
}

License

This project is © 2020 dorkbox llc, with modifications from software copyright 2014 ZeroTurnaround, and 2014 The Apache Software Foundation.

This project is distributed under the terms of the Apache v2.0 License. See file "LICENSE" for further references.