This is a small library allowing to launch external processes from Java code in the background, and conveniently correctly pipe their output e.g. into slf4j, await either their termination or specific output, etc.
If you like/use this project, Sponsoring me or a Star / Watch / Follow me on GitHub is very much appreciated!
Release Notes are in CHANGES.md.
Launching external processes from Java using the raw java.lang.ProcessBuilder API directly can be a little cumbersome. Apache Commons Exec makes it a bit easier, but lacks some convenience. This library makes it truly convenient:
ManagedProcessBuilder pb = new ManagedProcessBuilder("someExec")
.addArgument("arg1")
.setWorkingDirectory(new File("/tmp"))
.getEnvironment().put("ENV_VAR", "...")
.setDestroyOnShutdown(true)
.addStdOut(new BufferedOutputStream(new FileOutputStream(outputFile)))
.setConsoleBufferMaxLines(7000); // used by startAndWaitForConsoleMessageMaxMs
ManagedProcess p = pb.build();
p.start();
p.isAlive();
p.waitForExit();
// OR: p.waitForExitMaxMsOrDestroy(5000);
// OR: p.startAndWaitForConsoleMessageMaxMs("Successfully started", 3000);
p.exitValue();
// OR: p.destroy();
// This works even while it's running, not just when it exited
String output = p.getConsole();
If you need to, you can also attach a listener to get notified when the external process ends, by using setProcessListener()
on the ManagedProcessBuilder
with a ManagedProcessListener
that implements onProcessComplete()
and onProcessFailed()
.
We currently internally use Apache Commons Exec by building on top, extending and wrapping it, but without exposing this in its API, so that theoretically in the future this implementation detail could be changed.
- automatically logs external process's STDOUT and STDERR using SLF4j out of the box (can be customized)
- automatically logs and throws for common errors (e.g. executable not found), instead of silently ignoring like j.l.Process
- automatically destroys external process with JVM shutdown hook (can be disabled)
- lets you await appearance of certain messages on the console
- lets you write tests against the expected output
Historically, this code was part of MariaDB4j (and this is why it's initial version was 3.0.0), but was it later split into a separate project. This was done to make it usable in separate projects (originally to launch Ansible Networking CLI commands from OpenDaylight, later to manage etcd servers in tests, both from OpenDaylight); later for use in https://enola.dev.
dev.enola.common.exec
has the possible NextGen API; watch #285Pty4j
executes under a PTY:- use it with JLine to
terminal.enterRawMode()
(if needed) jansi
(in [newer] JLine and [older] fusesource) can filter out ANSI escapes from exec output
- use it with JLine to
NuProcess
is another similar library in the same space, using native binding.jnr-process
is yet another such library, also with native binding.fleipold/jproc
is yet another similar library, also native.zt-exec
(with zt-process-killer) is also similar (but refused to backlink us).os-lib
is a Scala library including functionality like this.- Apache Commons Exec: See above.
For the expect-like functionality, from https://en.wikipedia.org/wiki/Expect#Java, note (in no particular order):
- https://github.com/vorburger/vexpect
- http://expectj.sourceforge.net
- https://github.com/cverges/expect4j
- https://github.com/Alexey1Gavrilov/ExpectIt
- https://github.com/iTransformers/expect4java
- https://github.com/ronniedong/Expect-for-Java
First test that GPG is set up correctly (gpg: no default secret key: No secret key gpg: signing failed: No secret key
), and that the settings.xml
has the credz
for oss.sonatype.org
(status: 401 unauthorized
):
git checkout main
./mvnw verify -Pgpg
./mvnw deploy
Once that works, the next release can be done similarly similarly to https://github.com/vorburger/MariaDB4j#release:
git checkout main
./mvnw release:prepare
./mvnw release:perform -Pgpg
./mvnw release:clean
git push
If ./mvnw release:prepare
fails with the following error, then comment out forceSignAnnotated = true
under [tag]
in ~/.gitconfig
:
The git-tag command failed.
[ERROR] Command output:
[ERROR] error: gpg failed to sign the data
[ERROR] error: unable to sign the tag
This library is currently used to control daemon style external executables. To launch a process which returns binary (or massive textual) output to its STDOUT (and, presumably, have that piped into a java.io.OutputStream), it would need some tweaks. This would include making the enabled-by-default logging into slf4j, and the built-in startAndWaitForConsoleMessageMaxMs which collects output, a more configurable option.
Contributions & patches more than welcome!