diff --git a/tomitribe-crest/src/test/java/org/tomitribe/crest/Cli.java b/tomitribe-crest/src/test/java/org/tomitribe/crest/Cli.java index 8297476..a5f4701 100644 --- a/tomitribe-crest/src/test/java/org/tomitribe/crest/Cli.java +++ b/tomitribe-crest/src/test/java/org/tomitribe/crest/Cli.java @@ -28,14 +28,14 @@ public class Cli { - private final File jar; + private final Java java; - public Cli(final File jar) { - this.jar = jar; + private Cli(final Java java) { + this.java = java; } public Java.Result run(final String... args) throws Exception { - return Java.jar(jar, args); + return java.run(args); } public static Builder builder() { @@ -44,6 +44,7 @@ public static Builder builder() { public static class Builder { private final Archive archive = Archive.archive(); + private final Java.Builder java = Java.builder(); public Builder() { final List> required = Arrays.asList(Main.class, Command.class, Converter.class); @@ -62,6 +63,20 @@ public Builder() { manifest(manifest); } + public Java.Builder arg(final String arg) { + return java.arg(arg); + } + + public Builder env(final String name, final String value) { + java.env(name, value); + return this; + } + + public Builder debug() { + java.debug(); + return this; + } + public Builder manifest(final Manifest manifest) { archive.add("META-INF/MANIFEST.MF", manifest.write()); return this; @@ -113,7 +128,8 @@ public Builder add(final Class clazz) { } public Cli build() { - return new Cli(archive.asJar()); + final File jar = archive.asJar(); + return new Cli(java.copy().jar(jar).build()); } } } diff --git a/tomitribe-crest/src/test/java/org/tomitribe/crest/CommandNameAndVersionTest.java b/tomitribe-crest/src/test/java/org/tomitribe/crest/CommandNameAndVersionTest.java index 092d0b2..2077730 100644 --- a/tomitribe-crest/src/test/java/org/tomitribe/crest/CommandNameAndVersionTest.java +++ b/tomitribe-crest/src/test/java/org/tomitribe/crest/CommandNameAndVersionTest.java @@ -13,6 +13,7 @@ */ package org.tomitribe.crest; +import org.junit.Ignore; import org.junit.Test; import org.tomitribe.crest.api.Command; import org.tomitribe.crest.api.Loader; @@ -57,14 +58,74 @@ public void manifestImplementationVersion() throws Exception { */ @Test public void manifestCommandName() throws Exception { + Java.Result result = Cli.builder() + .loader(ColorLoader.class) + .manifest(Manifest.builder() + .mainClass(Main.class) + .implementationVersion("5.16.1") + .commandName("blue")) + .add(ColorCommands.class) + .add(ColorLoader.class) + .add(SystemPropertiesInLoader.class) + .build() + .run(); + + assertEquals(String.format("Commands: %n" + + " %n" + + " color %n" + + " help %n" + + "%n" + + "blue 5.16.1%n" + + ""), result.getOut()); } @Test public void manifestCommandVersion() throws Exception { + Java.Result result = Cli.builder() + .loader(ColorLoader.class) + .manifest(Manifest.builder() + .mainClass(Main.class) + .implementationVersion("5.16.1") + .commandName("orange") + .commandVersion("2.4.6") + ) + .add(ColorCommands.class) + .add(ColorLoader.class) + .add(SystemPropertiesInLoader.class) + .build() + .run(); + + assertEquals(String.format("Commands: %n" + + " %n" + + " color %n" + + " help %n" + + "%n" + + "orange 2.4.6%n" + + ""), result.getOut()); } @Test + @Ignore public void systemPropertyCmd() throws Exception { + Java.Result result = Cli.builder() + .loader(SystemPropertiesInLoader.class) + .manifest(Manifest.builder() + .mainClass(Main.class) + ) + .add(ColorCommands.class) + .add(ColorLoader.class) + .add(SystemPropertiesInLoader.class) + .debug() + .build() + .run(); + + assertEquals(String.format("Commands: %n" + + " %n" + + " color %n" + + " help %n" + + "%n" + + "green 5.3.1%n" + + ""), result.getOut()); } @Test diff --git a/tomitribe-crest/src/test/java/org/tomitribe/crest/Java.java b/tomitribe-crest/src/test/java/org/tomitribe/crest/Java.java index 51e9adc..a5d5b5d 100644 --- a/tomitribe-crest/src/test/java/org/tomitribe/crest/Java.java +++ b/tomitribe-crest/src/test/java/org/tomitribe/crest/Java.java @@ -17,23 +17,48 @@ package org.tomitribe.crest; import org.junit.Assert; +import org.tomitribe.util.Join; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; +import java.util.stream.Stream; /** * @version $Revision$ $Date$ */ public class Java { + private final List command = new ArrayList<>(); + private final Map environment = new HashMap<>(); + + private Java(final List command, final Map environment) { + this.command.addAll(command); + this.environment.putAll(environment); + } + + public Result run(final String... args) { + final ProcessBuilder java = javaProcess(); + try { + java.environment().putAll(environment); + java.command().addAll(command); + java.command().addAll(Arrays.asList(args)); + return new Result(java.start()); + } catch (final Exception e) { + throw new JavaExecutionException(java.command(), e); + } + } + public static Result jar(final File jar, final String... args) throws IOException, ExecutionException, InterruptedException { final ProcessBuilder java = javaProcess(); java.command().add("-jar"); @@ -48,6 +73,135 @@ public static Result java(final String... args) throws IOException, ExecutionExc return new Result(java.start()); } + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private final List command = new ArrayList<>(); + private final Map environment = new HashMap<>(); + + public Builder env(final String name, final String value) { + environment.put(name, value); + return this; + } + + public Builder jar(final File jar) { + command.add("-jar"); + command.add(jar.getAbsolutePath()); + return this; + } + + public Builder arg(final String arg) { + command.add(arg); + return this; + } + + public Builder classpath(final File... jars) { + if (jars == null || jars.length == 0) { + throw new IllegalArgumentException("No jars specified"); + } + + final String classpath = Stream.of(jars) + .map(File::getAbsolutePath) + .reduce((s, s2) -> s + File.pathSeparator + s2) + .get(); + + command.add("-classpath"); + command.add(classpath); + return this; + } + + + public Builder debug() { + environment.put("JAVA_OPTS", "-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"); + return this; + } + + public Builder enableAssertions() { + command.add("-ea"); + return this; + } + + public Builder disableAssertions() { + command.add("-da"); + return this; + } + + public Builder ms(final String initial) { + command.add("-Xms" + initial); + return this; + } + + public Builder mx(final String max) { + command.add("-Xmx" + max); + return this; + } + + public Builder client() { + command.add("-client"); + return this; + } + + public Builder server() { + command.add("-server"); + return this; + } + + // Example of adding a generic method for `-XX` options + public Builder xx(final String option, final String value) { + command.add("-XX:" + option + "=" + value); + return this; + } + + public Builder agentlib(final String libName) { + command.add("-agentlib:" + libName); + return this; + } + + public Builder agentlib(final String libName, final String options) { + command.add("-agentlib:" + libName + "=" + options); + return this; + } + + + public Builder agentpath(final String pathName) { + command.add("-agentpath:" + pathName); + return this; + } + + public Builder agentpath(final String pathName, final String options) { + command.add("-agentpath:" + pathName + "=" + options); + return this; + } + + + public Builder javaagent(final String libName) { + command.add("-javaagent:" + libName); + return this; + } + + public Builder javaagent(final String jarPath, final String options) { + command.add("-javaagent:" + jarPath + "=" + options); + return this; + } + + public Builder d(final String name, final String value) { + command.add("-D:" + name + "=" + value); + return this; + } + + public Builder copy() { + final Builder copy = new Builder(); + copy.command.addAll(this.command); + copy.environment.putAll(this.environment); + return copy; + } + + public Java build() { + return new Java(command, environment); + } + } private static ProcessBuilder javaProcess() { final File javaHome = new File(System.getenv("JAVA_HOME")); @@ -146,4 +300,9 @@ public synchronized void run() { } } + public static class JavaExecutionException extends RuntimeException { + public JavaExecutionException(final List command, final Exception e) { + super(String.format("Java command failed:%nargs:%s%nresult:%s", Join.join(" ", command), e)); + } + } }