com.github.johnpoth.jshell.JShellMojo Maven / Gradle / Ivy
The newest version!
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* 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
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.johnpoth.jshell;
import javax.tools.Tool;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
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
{
@Parameter(defaultValue = "${project.runtimeClasspathElements}", property = "rcp", required = true)
private List runtimeClasspathElements;
@Parameter(defaultValue = "${project.testClasspathElements}", property = "trcp", required = true)
private List testClasspathElements;
@Parameter(property = "plugin.artifacts", required = true, readonly = true)
private List pluginArtifacts;
@Parameter(defaultValue = "false", property = "testClasspath")
private boolean testClasspath;
@Parameter(defaultValue = "true", property = "jshell.useProjectClasspath")
private boolean useProjectClasspath;
@Parameter(property = "jshell.class-path")
private String classpath;
@Parameter(property = "jshell.module-path")
private String modulepath;
@Parameter(property = "jshell.add-modules")
private String addModules;
@Parameter(property = "jshell.add-exports")
private String addExports;
@Parameter(property = "jshell.scripts")
private List scripts = new ArrayList<>();
// additional options that may be added in future Java releases.
@Parameter(property = "jshell.options")
private List options = new ArrayList<>();
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();
// Until https://issues.apache.org/jira/browse/MNG-6371 is resolved
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classLoader);
ServiceLoader sl = ServiceLoader.load(javax.tools.Tool.class);
Tool jshell = sl.stream()
.filter(a -> a.get().name().equals("jshell"))
.findAny()
.orElseThrow(() -> new RuntimeException("No JShell service providers found!"))
.get();
String[] args = addArguments(cp);
int exitCode = jshell.run(System.in, System.out, System.err, args);
if (exitCode != 0) {
throw new MojoExecutionException("An error was encountered while executing. Exit code:" + exitCode);
}
} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
private String buildClasspath() {
final List classpathElements = new ArrayList<>();
if (testClasspath) {
classpathElements.addAll(filterClasspath(testClasspathElements));
} else {
classpathElements.addAll(filterClasspath(runtimeClasspathElements));
}
if (!pluginArtifacts.isEmpty()) {
classpathElements.addAll(
pluginArtifacts.stream()
.map(artifact -> artifact.getFile().getAbsolutePath())
.collect(Collectors.toList())
);
}
return filterClasspath(classpathElements).stream()
.reduce("", (a, b) -> a + File.pathSeparator + b);
}
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 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"
);
return false;
}
if (Files.isDirectory(path)) {
return true;
}
if (s.endsWith(".jar")) {
return true;
}
getLog().debug("Removing: " + s +" from the classpath because it is unsupported in JShell.");
return false;
}).collect(Collectors.toList());
}
private String[] addArguments(String cp) {
List args = new ArrayList<>();
if (useProjectClasspath) {
args.add("--class-path");
args.add(cp);
} else if (classpath != null ){
args.add("--class-path");
args.add(classpath);
}
if (modulepath != null){
args.add("--module-path");
args.add(modulepath);
}
if (addModules!= null){
args.add("--add-modules");
args.add(addModules);
}
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);
}
return args.toArray(new String[0]);
}
}