diff --git a/README.adoc b/README.adoc index b9527b4..1cee707 100644 --- a/README.adoc +++ b/README.adoc @@ -53,11 +53,13 @@ add-modules|Add modules from JShell's module path|| add-exports|Explicitly add exports|| -scripts|Add startup scripts to JShell ',' delimited|| +scripts / script|Add startup scripts to JShell|| -useProjectClasspath|Use project class path in JShell|True| +useProjectClasspath|Use project class path in JShell|`true`| -options| Add other options to JShell. See https://docs.oracle.com/javase/9/tools/jshell.htm#GUID-C337353B-074A-431C-993F-60C226163F00__OPTIONSFORJSHELL-AF4AC615[docs]|| +options / option| Add other options to JShell. See https://docs.oracle.com/javase/9/tools/jshell.htm#GUID-C337353B-074A-431C-993F-60C226163F00__OPTIONSFORJSHELL-AF4AC615[docs]|| + +non-interactive| If `true` execute scripts and exit|`false`| |=== Reminder: plugin parameters when passed through the command line should be prefixed with 'jshell.' e.g: @@ -91,4 +93,4 @@ jshell> ---- -Works on Java 9, 10 and 11+ Enjoy! \ No newline at end of file +Works on Java 9, 10 and 11+ Enjoy! diff --git a/pom.xml b/pom.xml index f49fafb..8dcc6a8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.johnpoth jshell-maven-plugin - 1.5-SNAPSHOT + 2.0.0-SNAPSHOT maven-plugin jshell-maven-plugin Maven Plugin diff --git a/src/main/java/com/github/johnpoth/jshell/JShellMojo.java b/src/main/java/com/github/johnpoth/jshell/JShellMojo.java index 16cdedd..1555f62 100644 --- a/src/main/java/com/github/johnpoth/jshell/JShellMojo.java +++ b/src/main/java/com/github/johnpoth/jshell/JShellMojo.java @@ -5,9 +5,9 @@ * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,28 +16,34 @@ */ package com.github.johnpoth.jshell; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; + import javax.tools.Tool; +import java.io.BufferedInputStream; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.ServiceLoader; import java.util.stream.Collectors; -import org.apache.maven.artifact.Artifact; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; -@Mojo( name = "run", defaultPhase = LifecyclePhase.INSTALL, requiresDependencyResolution = ResolutionScope.TEST, requiresDependencyCollection = ResolutionScope.TEST ) -public class JShellMojo extends AbstractMojo -{ +@Mojo(name = "run", defaultPhase = LifecyclePhase.INSTALL, requiresDependencyResolution = ResolutionScope.TEST, requiresDependencyCollection = ResolutionScope.TEST) +public class JShellMojo extends AbstractMojo { @Parameter(defaultValue = "${project.runtimeClasspathElements}", property = "rcp", required = true) private List runtimeClasspathElements; @@ -73,15 +79,18 @@ public class JShellMojo extends AbstractMojo @Parameter(property = "jshell.options") private List options = new ArrayList<>(); + @Parameter(property = "jshell.non-interactive") + private boolean nonInteractive = false; + public void execute() throws MojoExecutionException { String cp = buildClasspath(); getLog().debug("Using classpath: " + cp); Optional module = ModuleLayer.boot().findModule("jdk.jshell"); - ClassLoader classLoader = module.get().getClassLoader(); + Optional classLoader = module.map(Module::getClassLoader); // Until https://issues.apache.org/jira/browse/MNG-6371 is resolved ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - try { - Thread.currentThread().setContextClassLoader(classLoader); + try (InputStream input = getInputStream()) { + classLoader.ifPresent(cl -> Thread.currentThread().setContextClassLoader(cl)); ServiceLoader sl = ServiceLoader.load(javax.tools.Tool.class); Tool jshell = sl.stream() .filter(a -> a.get().name().equals("jshell")) @@ -89,15 +98,49 @@ public void execute() throws MojoExecutionException { .orElseThrow(() -> new RuntimeException("No JShell service providers found!")) .get(); String[] args = addArguments(cp); - int exitCode = jshell.run(System.in, System.out, System.err, args); + + int exitCode = jshell.run(input, System.out, System.err, args); if (exitCode != 0) { throw new MojoExecutionException("An error was encountered while executing. Exit code:" + exitCode); } + } catch (IOException e) { + throw new MojoExecutionException("Unable to read input script file(s)", e); } finally { Thread.currentThread().setContextClassLoader(contextClassLoader); } } + private InputStream getInputStream() { + if (nonInteractive) { + if (getLog().isDebugEnabled()) { + getLog().debug("Non-interactive mode. inject script in stdin:" + String.join(", ", scripts)); + } + return new SequenceInputStream(Collections.enumeration( + scripts.stream() + .map(this::scriptToInputStream) + .filter(Objects::nonNull) + .collect(Collectors.toList()) + )); + } else { + return System.in; + } + } + + private InputStream scriptToInputStream(String scriptPath) { + final Path path = Paths.get(scriptPath); + if (!Files.isRegularFile(path)) { + if (getLog().isDebugEnabled()) { + getLog().debug("Not a regular file: " + scriptPath); + } + return null; + } + try { + return new BufferedInputStream(Files.newInputStream(path)); + } catch (IOException e) { + throw new IllegalArgumentException("Unable to read input script file(s)", e); + } + } + private String buildClasspath() { final List classpathElements = new ArrayList<>(); if (testClasspath) { @@ -121,8 +164,8 @@ private List filterClasspath(List cp) { return cp.stream() .filter(s -> { Path path = Paths.get(s); - if (Files.notExists(path)){ - getLog().warn("Removing: " + s +" from the classpath." + System.lineSeparator() + + if (Files.notExists(path)) { + getLog().warn("Removing: " + s + " from the classpath." + System.lineSeparator() + "If this is unexpected, please make sure you correctly build the project beforehand by invoking the correct Maven build phase (usually `install`, `test-compile` or `compile`). For example:" + System.lineSeparator() + "mvn test-compile com.github.johnpoth:jshell-maven-plugin:1.3:run" + System.lineSeparator() + "For more information visit https://github.com/johnpoth/jshell-maven-plugin" @@ -135,7 +178,7 @@ private List filterClasspath(List cp) { if (s.endsWith(".jar")) { return true; } - getLog().debug("Removing: " + s +" from the classpath because it is unsupported in JShell."); + getLog().debug("Removing: " + s + " from the classpath because it is unsupported in JShell."); return false; }).collect(Collectors.toList()); } @@ -145,27 +188,32 @@ private String[] addArguments(String cp) { if (useProjectClasspath) { args.add("--class-path"); args.add(cp); - } else if (classpath != null ){ + } else if (classpath != null) { args.add("--class-path"); args.add(classpath); } - if (modulepath != null){ + if (modulepath != null) { args.add("--module-path"); args.add(modulepath); } - if (addModules!= null){ + if (addModules != null) { args.add("--add-modules"); args.add(addModules); } - if (addExports!= null){ + if (addExports != null) { args.add("--add-exports"); args.add(addExports); } for (String option : this.options) { args.add(option); } - for (String script : scripts) { - args.add(script); + if (nonInteractive) { + args.add("-"); + } + else { + for (String script : scripts) { + args.add(script); + } } return args.toArray(new String[0]); }