diff --git a/pom.xml b/pom.xml
index 4908a2a3..0ccf6ba1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
net.alchim31.maven
scala-maven-plugin
- 4.6.4-SNAPSHOT
+ 4.8.2-SNAPSHOT
maven-plugin
scala-maven-plugin
@@ -105,7 +105,6 @@
scm:git:git://github.com/davidB/${project.artifactId}.git
scm:git:git@github.com:davidB/${project.artifactId}.git
http://github.com/davidB/${project.artifactId}/
- 4.5.5
@@ -130,10 +129,12 @@
github
1.8
1.8
- 3.0
+ 3.1.1
3.3.9
UTF-8
https://oss.sonatype.org/content/repositories/snapshots/
+ 2.12.18
+ 2.13.11
@@ -144,7 +145,7 @@
org.apache.maven.shared
maven-dependency-tree
- 3.1.1
+ 3.2.1
org.apache.maven.reporting
@@ -154,7 +155,7 @@
org.apache.maven
maven-archiver
- 3.5.2
+ 3.6.0
org.apache.commons
@@ -164,24 +165,24 @@
org.codehaus.plexus
plexus-utils
- 3.4.2
+ 3.5.1
org.codehaus.plexus
plexus-archiver
- 4.4.0
+ 4.7.1
org.codehaus.plexus
plexus-classworlds
- 2.6.0
+ 2.7.0
org.scala-sbt
zinc_2.13
- 1.6.1
+ 1.9.3
org.jline
@@ -268,7 +269,7 @@
org.apache.maven.doxia
doxia-sink-api
- 1.11.1
+ 1.12.0
provided
@@ -293,7 +294,7 @@
org.apache.maven.plugin-tools
maven-plugin-annotations
- 3.6.4
+ 3.9.0
provided
@@ -349,131 +350,171 @@
+
+ maven-clean-plugin
+ 3.3.1
+
+
+ maven-compiler-plugin
+ 3.11.0
+
maven-dependency-plugin
- 3.3.0
+ 3.6.0
- maven-release-plugin
- 2.5.3
+ maven-deploy-plugin
+ 3.1.1
- maven-site-plugin
- 3.12.0
+ maven-gpg-plugin
+ 3.1.0
+
+
+ maven-install-plugin
+ 3.1.1
+
+
+ maven-invoker-plugin
+ 3.5.1
+
+
+ maven-jar-plugin
+ 3.3.0
+
+
+ maven-javadoc-plugin
+ 3.5.0
maven-plugin-plugin
- 3.6.4
+ 3.9.0
maven-project-info-reports-plugin
- 3.3.0
+ 3.4.5
- maven-deploy-plugin
- 2.8.2
+ maven-release-plugin
+ 3.0.1
+
+
+ org.apache.maven.scm
+ maven-scm-api
+ 2.0.1
+
+
+ org.apache.maven.scm
+ maven-scm-provider-gitexe
+ 2.0.1
+
+
- maven-install-plugin
- 2.5.2
+ maven-resources-plugin
+ 3.3.1
- maven-source-plugin
- 3.2.1
+ maven-site-plugin
+ 3.12.1
- maven-javadoc-plugin
- 3.4.0
-
- 128m
- 512m
- true
- ${encoding}
- ${encoding}
- ${encoding}
- true
- true
- true
- true
- true
- false
- -missing
-
- http://java.sun.com/j2se/${maven.compiler.source}/docs/api/
- http://slf4j.org/api/
- http://commons.apache.org/lang/api-release/
- http://commons.apache.org/io/api-release/
- http://junit.sourceforge.net/javadoc/
-
-
-
-
- ${project.groupId}.example*:${project.groupId}.util.internal*
-
+ maven-source-plugin
+ 3.2.1
- maven-compiler-plugin
- 3.10.1
-
- 1.8
- 1.8
-
+ maven-surefire-plugin
+ 3.1.2
com.diffplug.spotless
spotless-maven-plugin
- 2.22.8
-
-
-
- src/main/java/**/*.java
- src/test/java/**/*.java
-
-
- src/main/java/scala_maven/ScalaCompilerLoader.java
-
-
-
- ${project.basedir}/src/etc/header.txt
-
-
-
+ 2.27.2
+
+
+ com.github.github
+ site-maven-plugin
+ 0.12
+
+
+ org.codehaus.mojo
+ animal-sniffer-maven-plugin
+ 1.22
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.13
- com.diffplug.spotless
- spotless-maven-plugin
+ maven-compiler-plugin
+
+ -Xlint:deprecation
+ 1.8
+ 1.8
+
+
+
+ maven-javadoc-plugin
+
+ 128m
+ 512m
+ true
+ ${encoding}
+ ${encoding}
+ ${encoding}
+ true
+ true
+ true
+ true
+ true
+ false
+ -missing
+
+ http://java.sun.com/j2se/${maven.compiler.source}/docs/api/
+ http://slf4j.org/api/
+ http://commons.apache.org/lang/api-release/
+ http://commons.apache.org/io/api-release/
+ http://junit.sourceforge.net/javadoc/
+
+
+
+
+ ${project.groupId}.example*:${project.groupId}.util.internal*
+
- spotless-apply
- process-resources
+ attach-javadocs
- apply
+ jar
+
+
+
+ maven-plugin-plugin
+
- spotless-verify
- verify
+ default-addPluginArtifactMetadata
+ package
- check
+ addPluginArtifactMetadata
+
+
+
+ default-descriptor
+ process-classes
+
+ descriptor
-
- maven-compiler-plugin
- 3.10.1
-
- -Xlint:deprecation
- 1.8
- 1.8
-
-
maven-site-plugin
- 3.12.0
default-site
@@ -491,43 +532,8 @@
-
- maven-javadoc-plugin
-
-
- attach-javadocs
-
- jar
-
-
-
-
-
- org.codehaus.mojo
- animal-sniffer-maven-plugin
- 1.21
-
-
- org.codehaus.mojo.signature
- java18
- 1.0
-
-
-
-
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.13
- true
-
- sonatype-nexus-snapshots
- https://oss.sonatype.org/
- false
-
-
maven-source-plugin
- 3.2.1
attach-sources
@@ -539,21 +545,6 @@
maven-release-plugin
- 2.5.3
-
-
- org.apache.maven.scm
- maven-scm-api
- 1.13.0
- compile
-
-
- org.apache.maven.scm
- maven-scm-provider-gitexe
- 1.13.0
- compile
-
-
release
install animal-sniffer:check site deploy nexus-staging:release
@@ -563,88 +554,69 @@
- maven-clean-plugin
- 3.2.0
-
-
- maven-resources-plugin
- 3.2.0
+ com.diffplug.spotless
+ spotless-maven-plugin
+
+
+
+ src/main/java/**/*.java
+ src/test/java/**/*.java
+
+
+ src/main/java/scala_maven/ScalaCompilerLoader.java
+
+
+
+ ${project.basedir}/src/etc/header.txt
+
+
+
- default-testResources
- process-test-resources
-
- testResources
-
-
-
- default-resources
+ spotless-apply
process-resources
- resources
-
-
-
-
-
- maven-jar-plugin
- 3.2.2
-
-
- default-jar
- package
-
- jar
-
-
-
-
-
- maven-plugin-plugin
-
-
- default-addPluginArtifactMetadata
- package
-
- addPluginArtifactMetadata
+ apply
- default-descriptor
- process-classes
+ spotless-verify
+ verify
- descriptor
+ check
- maven-surefire-plugin
- 2.22.2
+ org.codehaus.mojo
+ animal-sniffer-maven-plugin
+
+
+ org.codehaus.mojo.signature
+ java18
+ 1.0
+
+
- maven-install-plugin
- 2.5.2
-
-
- default-install
- install
-
- install
-
-
-
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ true
+
+ sonatype-nexus-snapshots
+ https://oss.sonatype.org/
+ false
+
- org.apache.maven.plugins
maven-plugin-plugin
- org.apache.maven.plugins
maven-project-info-reports-plugin
@@ -672,7 +644,6 @@
maven-invoker-plugin
- 3.3.0
integration-test
@@ -683,7 +654,7 @@
- 2.12.12
+ ${last.scala2_12.release}
all
@@ -697,7 +668,7 @@
- 2.12.12
+ ${last.scala2_12.release}
incremental
@@ -711,7 +682,7 @@
- 2.13.3
+ ${last.scala2_13.release}
all
@@ -724,7 +695,7 @@
- 2.13.3
+ ${last.scala2_13.release}
incremental
@@ -766,7 +737,6 @@
maven-gpg-plugin
- 3.0.1
sign-artifacts
@@ -783,7 +753,6 @@
com.github.github
site-maven-plugin
- 0.12
site
diff --git a/src/it/test_scaladoc_compiler_plugins/pom.xml b/src/it/test_scaladoc_compiler_plugins/pom.xml
index 32fe2166..26071e6f 100644
--- a/src/it/test_scaladoc_compiler_plugins/pom.xml
+++ b/src/it/test_scaladoc_compiler_plugins/pom.xml
@@ -49,7 +49,7 @@
org.typelevel
kind-projector_${scala.version.lastrelease}
- 0.11.0
+ 0.13.2
diff --git a/src/it/test_scaladoc_compiler_plugins/src/main/scala/MyClass.scala b/src/it/test_scaladoc_compiler_plugins/src/main/scala/MyClass.scala
index f7e4fb86..64e677b5 100644
--- a/src/it/test_scaladoc_compiler_plugins/src/main/scala/MyClass.scala
+++ b/src/it/test_scaladoc_compiler_plugins/src/main/scala/MyClass.scala
@@ -2,8 +2,5 @@ import scala.language.higherKinds
object MyClass {
- class TestKinded[F[_], G]
-
- def testWithHigherKinded[F[_] : TestKinded[?[_], Int]] = ???
-
+ def testWithHigherKinded[Either[Int, +*]] = ???
}
diff --git a/src/main/java/sbt_inc/CompilerBridgeFactory.java b/src/main/java/sbt_inc/CompilerBridgeFactory.java
new file mode 100644
index 00000000..345b7a94
--- /dev/null
+++ b/src/main/java/sbt_inc/CompilerBridgeFactory.java
@@ -0,0 +1,235 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package sbt_inc;
+
+import static scala.jdk.CollectionConverters.IterableHasAsScala;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.logging.Log;
+import sbt.internal.inc.RawCompiler;
+import sbt.internal.inc.ScalaInstance;
+import sbt.io.AllPassFilter$;
+import sbt.io.IO;
+import scala.Tuple2;
+import scala_maven.MavenArtifactResolver;
+import scala_maven.VersionNumber;
+import util.FileUtils;
+import xsbti.compile.ClasspathOptionsUtil;
+
+public final class CompilerBridgeFactory {
+
+ private static final String SBT_GROUP_ID = "org.scala-sbt";
+ private static final String SBT_GROUP_ID_SCALA3 = "org.scala-lang";
+ private static final String JAVA_CLASS_VERSION = System.getProperty("java.class.version");
+
+ private static final File DEFAULT_SECONDARY_CACHE_DIR =
+ Paths.get(System.getProperty("user.home"), ".sbt", "1.0", "zinc", "org.scala-sbt").toFile();
+
+ private CompilerBridgeFactory() {}
+
+ static File getCompiledBridgeJar(
+ VersionNumber scalaVersion,
+ ScalaInstance scalaInstance,
+ File secondaryCacheDir,
+ MavenArtifactResolver resolver,
+ Log mavenLogger)
+ throws Exception {
+ // eg
+ // org.scala-sbt-compiler-bridge_2.12-1.2.4-bin_2.12.10__52.0-1.2.4_20181015T090407.jar
+ String bridgeArtifactId = compilerBridgeArtifactId(scalaVersion.toString());
+
+ if (secondaryCacheDir == null) {
+ secondaryCacheDir = DEFAULT_SECONDARY_CACHE_DIR;
+ }
+ secondaryCacheDir.mkdirs();
+
+ return scalaVersion.major == 3
+ ? getScala3CompilerBridgeJar(scalaVersion, bridgeArtifactId, resolver)
+ : getScala2CompilerBridgeJar(
+ scalaInstance,
+ scalaVersion,
+ bridgeArtifactId,
+ resolver,
+ secondaryCacheDir,
+ mavenLogger);
+ }
+
+ private static String compilerBridgeArtifactId(String scalaVersion) {
+ if (scalaVersion.startsWith("2.10.")) {
+ return "compiler-bridge_2.10";
+ } else if (scalaVersion.startsWith("2.11.")) {
+ return "compiler-bridge_2.11";
+ } else if (scalaVersion.startsWith("2.12.") || scalaVersion.equals("2.13.0-M1")) {
+ return "compiler-bridge_2.12";
+ } else if (scalaVersion.startsWith("2.13.")) {
+ return "compiler-bridge_2.13";
+ } else {
+ return "scala3-sbt-bridge";
+ }
+ }
+
+ private static File getScala3CompilerBridgeJar(
+ VersionNumber scalaVersion, String bridgeArtifactId, MavenArtifactResolver resolver) {
+ return resolver
+ .getJar(SBT_GROUP_ID_SCALA3, bridgeArtifactId, scalaVersion.toString(), "")
+ .getFile();
+ }
+
+ private static File getScala2CompilerBridgeJar(
+ ScalaInstance scalaInstance,
+ VersionNumber scalaVersion,
+ String bridgeArtifactId,
+ MavenArtifactResolver resolver,
+ File secondaryCacheDir,
+ Log mavenLogger)
+ throws IOException {
+ // this file is localed in compiler-interface
+ Properties properties = new Properties();
+ try (InputStream is =
+ CompilerBridgeFactory.class
+ .getClassLoader()
+ .getResourceAsStream("incrementalcompiler.version.properties")) {
+ properties.load(is);
+ }
+
+ String zincVersion = properties.getProperty("version");
+ String timestamp = properties.getProperty("timestamp");
+
+ String cacheFileName =
+ SBT_GROUP_ID
+ + '-'
+ + bridgeArtifactId
+ + '-'
+ + zincVersion
+ + "-bin_"
+ + scalaVersion
+ + "__"
+ + JAVA_CLASS_VERSION
+ + '-'
+ + zincVersion
+ + '_'
+ + timestamp
+ + ".jar";
+
+ File cachedCompiledBridgeJar = new File(secondaryCacheDir, cacheFileName);
+
+ if (mavenLogger.isInfoEnabled()) {
+ mavenLogger.info("Compiler bridge file: " + cachedCompiledBridgeJar);
+ }
+
+ if (!cachedCompiledBridgeJar.exists()) {
+ mavenLogger.info("Compiler bridge file is not installed yet");
+ // compile and install
+ RawCompiler rawCompiler =
+ new RawCompiler(
+ scalaInstance, ClasspathOptionsUtil.auto(), new MavenLoggerSbtAdapter(mavenLogger));
+
+ File bridgeSources =
+ resolver.getJar(SBT_GROUP_ID, bridgeArtifactId, zincVersion, "sources").getFile();
+
+ Set bridgeSourcesDependencies =
+ resolver.getJarAndDependencies(SBT_GROUP_ID, bridgeArtifactId, zincVersion, "sources")
+ .stream()
+ .filter(
+ artifact ->
+ artifact.getScope() != null && !artifact.getScope().equals("provided"))
+ .map(Artifact::getFile)
+ .map(File::toPath)
+ .collect(Collectors.toSet());
+
+ bridgeSourcesDependencies.addAll(
+ Arrays.stream(scalaInstance.allJars())
+ .sequential()
+ .map(File::toPath)
+ .collect(Collectors.toList()));
+
+ Path sourcesDir = Files.createTempDirectory("scala-maven-plugin-compiler-bridge-sources");
+ Path classesDir = Files.createTempDirectory("scala-maven-plugin-compiler-bridge-classes");
+
+ IO.unzip(bridgeSources, sourcesDir.toFile(), AllPassFilter$.MODULE$, true);
+
+ List bridgeSourcesScalaFiles =
+ FileUtils.listDirectoryContent(
+ sourcesDir,
+ file ->
+ Files.isRegularFile(file) && file.getFileName().toString().endsWith(".scala"));
+ List bridgeSourcesNonScalaFiles =
+ FileUtils.listDirectoryContent(
+ sourcesDir,
+ file ->
+ Files.isRegularFile(file)
+ && !file.getFileName().toString().endsWith(".scala")
+ && !file.getFileName().toString().equals("MANIFEST.MF"));
+
+ try {
+ rawCompiler.apply(
+ IterableHasAsScala(bridgeSourcesScalaFiles).asScala().toSeq(), // sources:Seq[File]
+ IterableHasAsScala(bridgeSourcesDependencies).asScala().toSeq(), // classpath:Seq[File],
+ classesDir, // outputDirectory:Path,
+ IterableHasAsScala(Collections.emptyList())
+ .asScala()
+ .toSeq() // options:Seq[String]
+ );
+
+ Manifest manifest = new Manifest();
+ Path sourcesManifestFile = sourcesDir.resolve("META-INF").resolve("MANIFEST.MF");
+ try (InputStream is = Files.newInputStream(sourcesManifestFile)) {
+ manifest.read(is);
+ }
+
+ List> scalaCompiledClasses =
+ computeZipEntries(FileUtils.listDirectoryContent(classesDir, file -> true), classesDir);
+ List> resources =
+ computeZipEntries(bridgeSourcesNonScalaFiles, sourcesDir);
+ List> allZipEntries = new ArrayList<>();
+ allZipEntries.addAll(scalaCompiledClasses);
+ allZipEntries.addAll(resources);
+
+ IO.jar(
+ IterableHasAsScala(
+ allZipEntries.stream()
+ .map(x -> scala.Tuple2.apply(x._1, x._2))
+ .collect(Collectors.toList()))
+ .asScala(),
+ cachedCompiledBridgeJar,
+ manifest);
+
+ mavenLogger.info("Compiler bridge installed");
+
+ } finally {
+ FileUtils.deleteDirectory(sourcesDir);
+ FileUtils.deleteDirectory(classesDir);
+ }
+ }
+
+ return cachedCompiledBridgeJar;
+ }
+
+ private static List> computeZipEntries(List paths, Path rootDir) {
+ int rootDirLength = rootDir.toString().length();
+ Stream> stream =
+ paths.stream()
+ .map(
+ path -> {
+ String zipPath =
+ path.toString().substring(rootDirLength + 1).replace(File.separator, "/");
+ if (Files.isDirectory(path)) {
+ zipPath = zipPath + "/";
+ }
+ return new Tuple2<>(path.toFile(), zipPath);
+ });
+ return stream.collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/sbt_inc/ForkedSbtIncrementalCompilerMain.java b/src/main/java/sbt_inc/ForkedSbtIncrementalCompilerMain.java
new file mode 100644
index 00000000..9f143be6
--- /dev/null
+++ b/src/main/java/sbt_inc/ForkedSbtIncrementalCompilerMain.java
@@ -0,0 +1,190 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package sbt_inc;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import sbt.internal.inc.ScalaInstance;
+import sbt.util.Level;
+import sbt.util.Logger;
+import scala.Enumeration;
+import scala.Function0;
+import scala_maven_executions.ForkLogLevel;
+import xsbti.compile.*;
+
+public final class ForkedSbtIncrementalCompilerMain {
+
+ public static final class Args {
+ public final File javaHome;
+ public final File cacheFile;
+ public final CompileOrder compileOrder;
+ public final File compilerBridgeJar;
+ public final String scalaVersion;
+ public final Collection compilerAndDependencies;
+ public final Collection libraryAndDependencies;
+
+ public final Collection classpathElements;
+ public final Collection sources;
+ public final File classesDirectory;
+ public final Collection scalacOptions;
+ public final Collection javacOptions;
+
+ public final boolean debugEnabled;
+
+ public Args(
+ File javaHome,
+ File cacheFile,
+ CompileOrder compileOrder,
+ File compilerBridgeJar,
+ String scalaVersion,
+ Collection compilerAndDependencies,
+ Collection libraryAndDependencies,
+ Collection classpathElements,
+ Collection sources,
+ File classesDirectory,
+ Collection scalacOptions,
+ Collection javacOptions,
+ boolean debugEnabled) {
+ this.javaHome = javaHome;
+ this.cacheFile = cacheFile;
+ this.compileOrder = compileOrder;
+ this.compilerBridgeJar = compilerBridgeJar;
+ this.scalaVersion = scalaVersion;
+ this.compilerAndDependencies = compilerAndDependencies;
+ this.libraryAndDependencies = libraryAndDependencies;
+ this.classpathElements = classpathElements;
+ this.sources = sources;
+ this.classesDirectory = classesDirectory;
+ this.scalacOptions = scalacOptions;
+ this.javacOptions = javacOptions;
+ this.debugEnabled = debugEnabled;
+ }
+
+ private void writeCollection(
+ List args, Collection collection, Function f) {
+ args.add(String.valueOf(collection.size()));
+ for (T entry : collection) {
+ args.add(f.apply(entry));
+ }
+ }
+
+ public String[] generateArgs() {
+ List args = new ArrayList<>();
+ args.add(javaHome.toString());
+ args.add(cacheFile.getPath());
+ args.add(compileOrder.name());
+ args.add(compilerBridgeJar.getPath());
+ args.add(scalaVersion);
+ writeCollection(args, compilerAndDependencies, File::getPath);
+ writeCollection(args, libraryAndDependencies, File::getPath);
+ writeCollection(args, classpathElements, File::getPath);
+ writeCollection(args, sources, File::getPath);
+ args.add(classesDirectory.toString());
+ writeCollection(args, scalacOptions, Function.identity());
+ writeCollection(args, javacOptions, Function.identity());
+ args.add(String.valueOf(debugEnabled));
+ return args.toArray(new String[] {});
+ }
+
+ private static List readList(String[] args, AtomicInteger index, Function f) {
+ int size = Integer.parseInt(args[index.getAndIncrement()]);
+ List list = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ list.add(f.apply(args[index.getAndIncrement()]));
+ }
+ return list;
+ }
+
+ static Args parseArgs(String[] args) {
+ AtomicInteger index = new AtomicInteger();
+
+ File javaHome = new File(args[index.getAndIncrement()]);
+ File cacheFile = new File(args[index.getAndIncrement()]);
+ CompileOrder compileOrder = CompileOrder.valueOf(args[index.getAndIncrement()]);
+ File compilerBridgeJar = new File(args[index.getAndIncrement()]);
+ String scalaVersion = args[index.getAndIncrement()];
+ List compilerAndDependencies = readList(args, index, File::new);
+ List libraryAndDependencies = readList(args, index, File::new);
+ List classpathElements = readList(args, index, File::new);
+ List sources = readList(args, index, File::new);
+ File classesDirectory = new File(args[index.getAndIncrement()]);
+ List scalacOptions = readList(args, index, Function.identity());
+ List javacOptions = readList(args, index, Function.identity());
+ boolean debugEnabled = Boolean.parseBoolean(args[index.getAndIncrement()]);
+
+ return new Args(
+ javaHome,
+ cacheFile,
+ compileOrder,
+ compilerBridgeJar,
+ scalaVersion,
+ compilerAndDependencies,
+ libraryAndDependencies,
+ classpathElements,
+ sources,
+ classesDirectory,
+ scalacOptions,
+ javacOptions,
+ debugEnabled);
+ }
+ }
+
+ public static void main(String[] args) {
+ Args parsedArgs = Args.parseArgs(args);
+
+ Logger sbtLogger =
+ new Logger() {
+ @Override
+ public void log(Enumeration.Value level, Function0 message) {
+ ForkLogLevel forkLogLevel = null;
+ if (level.equals(Level.Error())) {
+ forkLogLevel = ForkLogLevel.ERROR;
+ } else if (level.equals(Level.Warn())) {
+ forkLogLevel = ForkLogLevel.WARN;
+ } else if (level.equals(Level.Info())) {
+ forkLogLevel = ForkLogLevel.INFO;
+ } else if (level.equals(Level.Debug()) && parsedArgs.debugEnabled) {
+ forkLogLevel = ForkLogLevel.DEBUG;
+ }
+
+ if (forkLogLevel != null) {
+ System.out.println(forkLogLevel.addHeader(message.apply()));
+ }
+ }
+
+ @Override
+ public void success(Function0 message) {
+ log(Level.Info(), message);
+ }
+
+ @Override
+ public void trace(Function0 t) {}
+ };
+
+ ScalaInstance scalaInstance =
+ ScalaInstances.makeScalaInstance(
+ parsedArgs.scalaVersion,
+ parsedArgs.compilerAndDependencies,
+ parsedArgs.libraryAndDependencies);
+
+ SbtIncrementalCompiler incrementalCompiler =
+ SbtIncrementalCompilers.makeInProcess(
+ parsedArgs.javaHome,
+ parsedArgs.cacheFile,
+ parsedArgs.compileOrder,
+ scalaInstance,
+ parsedArgs.compilerBridgeJar,
+ sbtLogger);
+
+ incrementalCompiler.compile(
+ parsedArgs.classpathElements,
+ parsedArgs.sources,
+ parsedArgs.classesDirectory,
+ parsedArgs.scalacOptions,
+ parsedArgs.javacOptions);
+ }
+}
diff --git a/src/main/java/sbt_inc/InProcessSbtIncrementalCompiler.java b/src/main/java/sbt_inc/InProcessSbtIncrementalCompiler.java
new file mode 100644
index 00000000..c16c1f28
--- /dev/null
+++ b/src/main/java/sbt_inc/InProcessSbtIncrementalCompiler.java
@@ -0,0 +1,87 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package sbt_inc;
+
+import java.io.File;
+import java.util.*;
+import sbt.internal.inc.*;
+import xsbti.Logger;
+import xsbti.VirtualFile;
+import xsbti.compile.*;
+
+public final class InProcessSbtIncrementalCompiler implements SbtIncrementalCompiler {
+ private final Compilers compilers;
+ private final AnalysisStore analysisStore;
+ private final Setup setup;
+
+ private final IncrementalCompiler compiler;
+ private final CompileOrder compileOrder;
+ private final Logger sbtLogger;
+
+ public InProcessSbtIncrementalCompiler(
+ Compilers compilers,
+ AnalysisStore analysisStore,
+ Setup setup,
+ IncrementalCompiler compiler,
+ CompileOrder compileOrder,
+ Logger sbtLogger) {
+ this.compilers = compilers;
+ this.analysisStore = analysisStore;
+ this.setup = setup;
+ this.compiler = compiler;
+ this.compileOrder = compileOrder;
+ this.sbtLogger = sbtLogger;
+ }
+
+ @Override
+ public void compile(
+ Collection classpathElements,
+ Collection sources,
+ File classesDirectory,
+ Collection scalacOptions,
+ Collection javacOptions) {
+
+ // incremental compiler needs to add the output dir in the classpath for Java + Scala
+ Collection fullClasspathElements = new ArrayList<>(classpathElements);
+ fullClasspathElements.add(classesDirectory);
+
+ CompileOptions options =
+ CompileOptions.of(
+ fullClasspathElements.stream()
+ .map(file -> new PlainVirtualFile(file.toPath()))
+ .toArray(VirtualFile[]::new), // classpath
+ sources.stream()
+ .map(file -> new PlainVirtualFile(file.toPath()))
+ .toArray(VirtualFile[]::new), // sources
+ classesDirectory.toPath(), //
+ scalacOptions.toArray(new String[] {}), // scalacOptions
+ javacOptions.toArray(new String[] {}), // javacOptions
+ 100, // maxErrors
+ pos -> pos, // sourcePositionMappers
+ compileOrder, // order
+ Optional.empty(), // temporaryClassesDirectory
+ Optional.empty(), // _converter
+ Optional.empty(), // _stamper
+ Optional.empty() // _earlyOutput
+ );
+
+ Inputs inputs = Inputs.of(compilers, options, setup, previousResult());
+
+ CompileResult newResult = compiler.compile(inputs, sbtLogger);
+ analysisStore.set(AnalysisContents.create(newResult.analysis(), newResult.setup()));
+ }
+
+ private PreviousResult previousResult() {
+ Optional analysisContents = analysisStore.get();
+ if (analysisContents.isPresent()) {
+ AnalysisContents analysisContents0 = analysisContents.get();
+ CompileAnalysis previousAnalysis = analysisContents0.getAnalysis();
+ MiniSetup previousSetup = analysisContents0.getMiniSetup();
+ return PreviousResult.of(Optional.of(previousAnalysis), Optional.of(previousSetup));
+ } else {
+ return PreviousResult.of(Optional.empty(), Optional.empty());
+ }
+ }
+}
diff --git a/src/main/java/sbt_inc/SbtLogger.java b/src/main/java/sbt_inc/MavenLoggerSbtAdapter.java
similarity index 93%
rename from src/main/java/sbt_inc/SbtLogger.java
rename to src/main/java/sbt_inc/MavenLoggerSbtAdapter.java
index 0d212b7e..3c00bf0b 100644
--- a/src/main/java/sbt_inc/SbtLogger.java
+++ b/src/main/java/sbt_inc/MavenLoggerSbtAdapter.java
@@ -10,11 +10,11 @@
import scala.Enumeration;
import scala.Function0;
-public class SbtLogger extends Logger {
+public class MavenLoggerSbtAdapter extends Logger {
private final Log log;
- SbtLogger(Log l) {
+ MavenLoggerSbtAdapter(Log l) {
this.log = l;
}
diff --git a/src/main/java/sbt_inc/SbtIncrementalCompiler.java b/src/main/java/sbt_inc/SbtIncrementalCompiler.java
index faf3bd31..3b9adadd 100644
--- a/src/main/java/sbt_inc/SbtIncrementalCompiler.java
+++ b/src/main/java/sbt_inc/SbtIncrementalCompiler.java
@@ -4,342 +4,15 @@
*/
package sbt_inc;
-import static scala.jdk.CollectionConverters.IterableHasAsScala;
-import static scala.jdk.FunctionWrappers.FromJavaConsumer;
-
import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.*;
-import java.util.jar.Manifest;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.logging.Log;
-import sbt.internal.inc.*;
-import sbt.internal.inc.FileAnalysisStore;
-import sbt.internal.inc.ScalaInstance;
-import sbt.io.AllPassFilter$;
-import sbt.io.IO;
-import sbt.util.Logger;
-import scala.Option;
-import scala.Tuple2;
-import scala_maven.MavenArtifactResolver;
-import util.FileUtils;
-import xsbti.PathBasedFile;
-import xsbti.T2;
-import xsbti.VirtualFile;
-import xsbti.compile.*;
-
-public class SbtIncrementalCompiler {
-
- private static final String SBT_GROUP_ID = "org.scala-sbt";
- private static final String SBT_GROUP_ID_SCALA3 = "org.scala-lang";
- private static final String JAVA_CLASS_VERSION = System.getProperty("java.class.version");
- private static final File DEFAULT_SECONDARY_CACHE_DIR =
- Paths.get(System.getProperty("user.home"), ".sbt", "1.0", "zinc", "org.scala-sbt").toFile();
-
- private final IncrementalCompiler compiler = ZincUtil.defaultIncrementalCompiler();
- private final CompileOrder compileOrder;
- private final Logger logger;
- private final Compilers compilers;
- private final Setup setup;
- private final AnalysisStore analysisStore;
- private final MavenArtifactResolver resolver;
- private final File secondaryCacheDir;
-
- public SbtIncrementalCompiler(
- File javaHome,
- MavenArtifactResolver resolver,
- File secondaryCacheDir,
- Log mavenLogger,
- File cacheFile,
- CompileOrder compileOrder,
- ScalaInstance scalaInstance)
- throws Exception {
- this.compileOrder = compileOrder;
- this.logger = new SbtLogger(mavenLogger);
- mavenLogger.info("Using incremental compilation using " + compileOrder + " compile order");
- this.resolver = resolver;
- this.secondaryCacheDir =
- secondaryCacheDir != null ? secondaryCacheDir : DEFAULT_SECONDARY_CACHE_DIR;
- this.secondaryCacheDir.mkdirs();
-
- File compilerBridgeJar = getCompiledBridgeJar(scalaInstance, mavenLogger);
-
- ScalaCompiler scalaCompiler =
- new AnalyzingCompiler(
- scalaInstance, // scalaInstance
- ZincCompilerUtil.constantBridgeProvider(scalaInstance, compilerBridgeJar), // provider
- ClasspathOptionsUtil.auto(), // classpathOptions
- new FromJavaConsumer(noop -> {}), // onArgsHandler
- Option.apply(null) // classLoaderCache
- );
-
- compilers =
- ZincUtil.compilers(
- scalaInstance,
- ClasspathOptionsUtil.boot(),
- Option.apply(javaHome.toPath()),
- scalaCompiler);
-
- PerClasspathEntryLookup lookup =
- new PerClasspathEntryLookup() {
- @Override
- public Optional analysis(VirtualFile classpathEntry) {
- Path path = ((PathBasedFile) classpathEntry).toPath();
-
- String analysisStoreFileName = null;
- if (Files.isDirectory(path)) {
- if (path.getFileName().toString().equals("classes")) {
- analysisStoreFileName = "compile";
-
- } else if (path.getFileName().toString().equals("test-classes")) {
- analysisStoreFileName = "test-compile";
- }
- }
-
- if (analysisStoreFileName != null) {
- File analysisStoreFile =
- path.getParent().resolve("analysis").resolve(analysisStoreFileName).toFile();
- if (analysisStoreFile.exists()) {
- return AnalysisStore.getCachedStore(FileAnalysisStore.binary(analysisStoreFile))
- .get()
- .map(AnalysisContents::getAnalysis);
- }
- }
- return Optional.empty();
- }
-
- @Override
- public DefinesClass definesClass(VirtualFile classpathEntry) {
- return classpathEntry.name().equals("rt.jar")
- ? className -> false
- : Locate.definesClass(classpathEntry);
- }
- };
-
- analysisStore = AnalysisStore.getCachedStore(FileAnalysisStore.binary(cacheFile));
-
- setup =
- Setup.of(
- lookup, // lookup
- false, // skip
- cacheFile, // cacheFile
- CompilerCache.fresh(), // cache
- IncOptions.of(), // incOptions
- new LoggedReporter(100, logger, pos -> pos), // reporter
- Optional.empty(), // optionProgress
- new T2[] {});
- }
-
- private PreviousResult previousResult() {
- Optional analysisContents = analysisStore.get();
- if (analysisContents.isPresent()) {
- AnalysisContents analysisContents0 = analysisContents.get();
- CompileAnalysis previousAnalysis = analysisContents0.getAnalysis();
- MiniSetup previousSetup = analysisContents0.getMiniSetup();
- return PreviousResult.of(Optional.of(previousAnalysis), Optional.of(previousSetup));
- } else {
- return PreviousResult.of(Optional.empty(), Optional.empty());
- }
- }
-
- public void compile(
- Set classpathElements,
- List sources,
- Path classesDirectory,
- List scalacOptions,
- List javacOptions) {
- List fullClasspath = new ArrayList<>();
- fullClasspath.add(classesDirectory);
- fullClasspath.addAll(classpathElements);
-
- CompileOptions options =
- CompileOptions.of(
- fullClasspath.stream()
- .map(PlainVirtualFile::new)
- .toArray(VirtualFile[]::new), // classpath
- sources.stream().map(PlainVirtualFile::new).toArray(VirtualFile[]::new), // sources
- classesDirectory, //
- scalacOptions.toArray(new String[] {}), // scalacOptions
- javacOptions.toArray(new String[] {}), // javacOptions
- 100, // maxErrors
- pos -> pos, // sourcePositionMappers
- compileOrder, // order
- Optional.empty(), // temporaryClassesDirectory
- Optional.empty(), // _converter
- Optional.empty(), // _stamper
- Optional.empty() // _earlyOutput
- );
-
- Inputs inputs = Inputs.of(compilers, options, setup, previousResult());
-
- CompileResult newResult = compiler.compile(inputs, logger);
- analysisStore.set(AnalysisContents.create(newResult.analysis(), newResult.setup()));
- }
-
- private String compilerBridgeArtifactId(String scalaVersion) {
- if (scalaVersion.startsWith("2.10.")) {
- return "compiler-bridge_2.10";
- } else if (scalaVersion.startsWith("2.11.")) {
- return "compiler-bridge_2.11";
- } else if (scalaVersion.startsWith("2.12.") || scalaVersion.equals("2.13.0-M1")) {
- return "compiler-bridge_2.12";
- } else if (scalaVersion.startsWith("2.13.")) {
- return "compiler-bridge_2.13";
- } else {
- return "scala3-sbt-bridge";
- }
- }
-
- private static List> computeZipEntries(List paths, Path rootDir) {
- int rootDirLength = rootDir.toString().length();
- Stream> stream =
- paths.stream()
- .map(
- path -> {
- String zipPath =
- path.toString().substring(rootDirLength + 1).replace(File.separator, "/");
- if (Files.isDirectory(path)) {
- zipPath = zipPath + "/";
- }
- return new Tuple2(path.toFile(), zipPath);
- });
- return stream.collect(Collectors.toList());
- }
-
- private File getCompiledBridgeJar(ScalaInstance scalaInstance, Log mavenLogger) throws Exception {
-
- // eg
- // org.scala-sbt-compiler-bridge_2.12-1.2.4-bin_2.12.10__52.0-1.2.4_20181015T090407.jar
- String bridgeArtifactId = compilerBridgeArtifactId(scalaInstance.actualVersion());
-
- boolean isScala3 = scalaInstance.actualVersion().startsWith("3");
-
- // this file is localed in compiler-interface
- Properties properties = new Properties();
- try (InputStream is =
- getClass().getClassLoader().getResourceAsStream("incrementalcompiler.version.properties")) {
- properties.load(is);
- }
-
- String zincVersion = properties.getProperty("version");
- String timestamp = properties.getProperty("timestamp");
-
- String groupId = isScala3 ? SBT_GROUP_ID_SCALA3 : SBT_GROUP_ID;
- String version = isScala3 ? scalaInstance.actualVersion() : zincVersion;
-
- if (isScala3) {
- return resolver.getJar(groupId, bridgeArtifactId, version, "").getFile();
- }
-
- String cacheFileName =
- groupId
- + '-'
- + bridgeArtifactId
- + '-'
- + version
- + "-bin_"
- + scalaInstance.actualVersion()
- + "__"
- + JAVA_CLASS_VERSION
- + '-'
- + version
- + '_'
- + timestamp
- + ".jar";
-
- File cachedCompiledBridgeJar = new File(secondaryCacheDir, cacheFileName);
-
- if (mavenLogger.isInfoEnabled()) {
- mavenLogger.info("Compiler bridge file: " + cachedCompiledBridgeJar);
- }
-
- if (!cachedCompiledBridgeJar.exists()) {
- mavenLogger.info("Compiler bridge file is not installed yet");
- // compile and install
- RawCompiler rawCompiler = new RawCompiler(scalaInstance, ClasspathOptionsUtil.auto(), logger);
-
- File bridgeSources = resolver.getJar(groupId, bridgeArtifactId, version, "sources").getFile();
-
- Set bridgeSourcesDependencies =
- resolver.getJarAndDependencies(groupId, bridgeArtifactId, version, "sources").stream()
- .filter(
- artifact ->
- artifact.getScope() != null && !artifact.getScope().equals("provided"))
- .map(Artifact::getFile)
- .map(File::toPath)
- .collect(Collectors.toSet());
-
- bridgeSourcesDependencies.addAll(
- Arrays.stream(scalaInstance.allJars())
- .sequential()
- .map(File::toPath)
- .collect(Collectors.toList()));
-
- Path sourcesDir = Files.createTempDirectory("scala-maven-plugin-compiler-bridge-sources");
- Path classesDir = Files.createTempDirectory("scala-maven-plugin-compiler-bridge-classes");
-
- IO.unzip(bridgeSources, sourcesDir.toFile(), AllPassFilter$.MODULE$, true);
-
- List bridgeSourcesScalaFiles =
- FileUtils.listDirectoryContent(
- sourcesDir,
- file ->
- Files.isRegularFile(file) && file.getFileName().toString().endsWith(".scala"));
- List bridgeSourcesNonScalaFiles =
- FileUtils.listDirectoryContent(
- sourcesDir,
- file ->
- Files.isRegularFile(file)
- && !file.getFileName().toString().endsWith(".scala")
- && !file.getFileName().toString().equals("MANIFEST.MF"));
-
- try {
- rawCompiler.apply(
- IterableHasAsScala(bridgeSourcesScalaFiles).asScala().toSeq(), // sources:Seq[File]
- IterableHasAsScala(bridgeSourcesDependencies).asScala().toSeq(), // classpath:Seq[File],
- classesDir, // outputDirectory:Path,
- IterableHasAsScala(Collections.emptyList())
- .asScala()
- .toSeq() // options:Seq[String]
- );
-
- Manifest manifest = new Manifest();
- Path sourcesManifestFile = sourcesDir.resolve("META-INF").resolve("MANIFEST.MF");
- try (InputStream is = new FileInputStream(sourcesManifestFile.toFile())) {
- manifest.read(is);
- }
-
- List> scalaCompiledClasses =
- computeZipEntries(FileUtils.listDirectoryContent(classesDir, file -> true), classesDir);
- List> resources =
- computeZipEntries(bridgeSourcesNonScalaFiles, sourcesDir);
- List> allZipEntries = new ArrayList<>();
- allZipEntries.addAll(scalaCompiledClasses);
- allZipEntries.addAll(resources);
-
- IO.jar(
- IterableHasAsScala(
- allZipEntries.stream()
- .map(x -> scala.Tuple2.apply(x._1, x._2))
- .collect(Collectors.toList()))
- .asScala(),
- cachedCompiledBridgeJar,
- manifest);
-
- mavenLogger.info("Compiler bridge installed");
+import java.util.Collection;
- } finally {
- FileUtils.deleteDirectory(sourcesDir);
- FileUtils.deleteDirectory(classesDir);
- }
- }
+public interface SbtIncrementalCompiler {
- return cachedCompiledBridgeJar;
- }
+ void compile(
+ Collection classpathElements,
+ Collection sources,
+ File classesDirectory,
+ Collection scalacOptions,
+ Collection javacOptions);
}
diff --git a/src/main/java/sbt_inc/SbtIncrementalCompilers.java b/src/main/java/sbt_inc/SbtIncrementalCompilers.java
new file mode 100644
index 00000000..4e931838
--- /dev/null
+++ b/src/main/java/sbt_inc/SbtIncrementalCompilers.java
@@ -0,0 +1,246 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package sbt_inc;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.stream.Collectors;
+import org.apache.commons.exec.LogOutputStream;
+import org.apache.maven.plugin.logging.Log;
+import sbt.internal.inc.*;
+import sbt.internal.inc.FileAnalysisStore;
+import sbt.internal.inc.ScalaInstance;
+import sbt.util.Logger;
+import scala.Option;
+import scala.jdk.FunctionWrappers;
+import scala_maven.MavenArtifactResolver;
+import scala_maven.VersionNumber;
+import scala_maven_executions.Fork;
+import scala_maven_executions.ForkLogger;
+import xsbti.PathBasedFile;
+import xsbti.T2;
+import xsbti.VirtualFile;
+import xsbti.compile.*;
+
+public final class SbtIncrementalCompilers {
+ public static SbtIncrementalCompiler make(
+ File javaHome,
+ MavenArtifactResolver resolver,
+ File secondaryCacheDir,
+ Log mavenLogger,
+ File cacheFile,
+ CompileOrder compileOrder,
+ VersionNumber scalaVersion,
+ Collection compilerAndDependencies,
+ Collection libraryAndDependencies,
+ String[] jvmArgs,
+ File javaExec,
+ List forkBootClasspath)
+ throws Exception {
+
+ ScalaInstance scalaInstance =
+ ScalaInstances.makeScalaInstance(
+ scalaVersion.toString(), compilerAndDependencies, libraryAndDependencies);
+
+ File compilerBridgeJar =
+ CompilerBridgeFactory.getCompiledBridgeJar(
+ scalaVersion, scalaInstance, secondaryCacheDir, resolver, mavenLogger);
+
+ if (jvmArgs == null || jvmArgs.length == 0) {
+ return makeInProcess(
+ javaHome,
+ cacheFile,
+ compileOrder,
+ scalaInstance,
+ compilerBridgeJar,
+ new MavenLoggerSbtAdapter(mavenLogger));
+ } else {
+ return makeForkedProcess(
+ javaHome,
+ cacheFile,
+ compileOrder,
+ compilerBridgeJar,
+ scalaVersion,
+ compilerAndDependencies,
+ libraryAndDependencies,
+ mavenLogger,
+ jvmArgs,
+ javaExec,
+ forkBootClasspath);
+ }
+ }
+
+ static SbtIncrementalCompiler makeInProcess(
+ File javaHome,
+ File cacheFile,
+ CompileOrder compileOrder,
+ ScalaInstance scalaInstance,
+ File compilerBridgeJar,
+ Logger sbtLogger) {
+
+ Compilers compilers = makeCompilers(scalaInstance, javaHome, compilerBridgeJar);
+ AnalysisStore analysisStore = AnalysisStore.getCachedStore(FileAnalysisStore.binary(cacheFile));
+ Setup setup = makeSetup(cacheFile, sbtLogger);
+ IncrementalCompiler compiler = ZincUtil.defaultIncrementalCompiler();
+
+ return new InProcessSbtIncrementalCompiler(
+ compilers, analysisStore, setup, compiler, compileOrder, sbtLogger);
+ }
+
+ private static SbtIncrementalCompiler makeForkedProcess(
+ File javaHome,
+ File cacheFile,
+ CompileOrder compileOrder,
+ File compilerBridgeJar,
+ VersionNumber scalaVersion,
+ Collection compilerAndDependencies,
+ Collection libraryAndDependencies,
+ Log mavenLogger,
+ String[] jvmArgs,
+ File javaExec,
+ List pluginArtifacts) {
+
+ List forkClasspath =
+ pluginArtifacts.stream().map(File::getPath).collect(Collectors.toList());
+
+ return (classpathElements, sources, classesDirectory, scalacOptions, javacOptions) -> {
+ try {
+ String[] args =
+ new ForkedSbtIncrementalCompilerMain.Args(
+ javaHome,
+ cacheFile,
+ compileOrder,
+ compilerBridgeJar,
+ scalaVersion.toString(),
+ compilerAndDependencies,
+ libraryAndDependencies,
+ classpathElements,
+ sources,
+ classesDirectory,
+ scalacOptions,
+ javacOptions,
+ mavenLogger.isDebugEnabled())
+ .generateArgs();
+
+ Fork fork =
+ new Fork(
+ ForkedSbtIncrementalCompilerMain.class.getName(),
+ forkClasspath,
+ jvmArgs,
+ args,
+ javaExec);
+
+ fork.run(
+ new LogOutputStream() {
+ private final ForkLogger forkLogger =
+ new ForkLogger() {
+ @Override
+ public void onException(Exception t) {
+ mavenLogger.error(t);
+ }
+
+ @Override
+ public void onError(String content) {
+ mavenLogger.error(content);
+ }
+
+ @Override
+ public void onWarn(String content) {
+ mavenLogger.warn(content);
+ }
+
+ @Override
+ public void onInfo(String content) {
+ mavenLogger.info(content);
+ }
+
+ @Override
+ public void onDebug(String content) {
+ mavenLogger.debug(content);
+ }
+ };
+
+ @Override
+ protected void processLine(String line, int level) {
+ forkLogger.processLine(line);
+ }
+
+ public void close() throws IOException {
+ forkLogger.forceNextLineToFlush();
+ super.close();
+ }
+ });
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ };
+ }
+
+ private static Compilers makeCompilers(
+ ScalaInstance scalaInstance, File javaHome, File compilerBridgeJar) {
+ ScalaCompiler scalaCompiler =
+ new AnalyzingCompiler(
+ scalaInstance, // scalaInstance
+ ZincCompilerUtil.constantBridgeProvider(scalaInstance, compilerBridgeJar), // provider
+ ClasspathOptionsUtil.auto(), // classpathOptions
+ new FunctionWrappers.FromJavaConsumer<>(noop -> {}), // onArgsHandler
+ Option.apply(null) // classLoaderCache
+ );
+
+ return ZincUtil.compilers(
+ scalaInstance, ClasspathOptionsUtil.boot(), Option.apply(javaHome.toPath()), scalaCompiler);
+ }
+
+ private static Setup makeSetup(File cacheFile, xsbti.Logger sbtLogger) {
+ PerClasspathEntryLookup lookup =
+ new PerClasspathEntryLookup() {
+ @Override
+ public Optional analysis(VirtualFile classpathEntry) {
+ Path path = ((PathBasedFile) classpathEntry).toPath();
+
+ String analysisStoreFileName = null;
+ if (Files.isDirectory(path)) {
+ if (path.getFileName().toString().equals("classes")) {
+ analysisStoreFileName = "compile";
+
+ } else if (path.getFileName().toString().equals("test-classes")) {
+ analysisStoreFileName = "test-compile";
+ }
+ }
+
+ if (analysisStoreFileName != null) {
+ File analysisStoreFile =
+ path.getParent().resolve("analysis").resolve(analysisStoreFileName).toFile();
+ if (analysisStoreFile.exists()) {
+ return AnalysisStore.getCachedStore(FileAnalysisStore.binary(analysisStoreFile))
+ .get()
+ .map(AnalysisContents::getAnalysis);
+ }
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public DefinesClass definesClass(VirtualFile classpathEntry) {
+ return classpathEntry.name().equals("rt.jar")
+ ? className -> false
+ : Locate.definesClass(classpathEntry);
+ }
+ };
+
+ return Setup.of(
+ lookup, // lookup
+ false, // skip
+ cacheFile, // cacheFile
+ CompilerCache.fresh(), // cache
+ IncOptions.of(), // incOptions
+ new LoggedReporter(100, sbtLogger, pos -> pos), // reporter
+ Optional.empty(), // optionProgress
+ new T2[] {});
+ }
+}
diff --git a/src/main/java/sbt_inc/ScalaInstances.java b/src/main/java/sbt_inc/ScalaInstances.java
new file mode 100644
index 00000000..d12a71fb
--- /dev/null
+++ b/src/main/java/sbt_inc/ScalaInstances.java
@@ -0,0 +1,57 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package sbt_inc;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+import sbt.internal.inc.ScalaInstance;
+import scala.Option;
+import scala_maven.ScalaCompilerLoader;
+
+public final class ScalaInstances {
+
+ static ScalaInstance makeScalaInstance(
+ String scalaVersion,
+ Collection compilerAndDependencies,
+ Collection libraryAndDependencies) {
+
+ URL[] compilerJarUrls = toUrls(compilerAndDependencies);
+ URL[] libraryJarUrls = toUrls(libraryAndDependencies);
+
+ SortedSet allJars = new TreeSet<>();
+ allJars.addAll(compilerAndDependencies);
+ allJars.addAll(libraryAndDependencies);
+
+ ClassLoader loaderLibraryOnly =
+ new ScalaCompilerLoader(libraryJarUrls, xsbti.Reporter.class.getClassLoader());
+ ClassLoader loaderCompilerOnly = new URLClassLoader(compilerJarUrls, loaderLibraryOnly);
+
+ return new ScalaInstance(
+ scalaVersion,
+ loaderCompilerOnly,
+ loaderCompilerOnly,
+ loaderLibraryOnly,
+ libraryAndDependencies.toArray(new File[] {}),
+ compilerAndDependencies.toArray(new File[] {}),
+ allJars.toArray(new File[] {}),
+ Option.apply(scalaVersion));
+ }
+
+ private static URL[] toUrls(Collection files) {
+ return files.stream()
+ .map(
+ x -> {
+ try {
+ return x.toURI().toURL();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("failed to convert into url " + x, e);
+ }
+ })
+ .toArray(URL[]::new);
+ }
+}
diff --git a/src/main/java/scala_maven/MavenArtifactResolver.java b/src/main/java/scala_maven/MavenArtifactResolver.java
index 1696fc2c..0b935413 100644
--- a/src/main/java/scala_maven/MavenArtifactResolver.java
+++ b/src/main/java/scala_maven/MavenArtifactResolver.java
@@ -6,6 +6,7 @@
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.execution.MavenSession;
@@ -62,6 +63,8 @@ private Set resolve(Artifact artifact, boolean transitively) {
.setProxies(session.getRequest().getProxies())
.setLocalRepository(session.getLocalRepository())
.setRemoteRepositories(session.getCurrentProject().getRemoteArtifactRepositories());
- return repositorySystem.resolve(request).getArtifacts();
+ return repositorySystem.resolve(request).getArtifacts().stream()
+ .filter(art -> !Artifact.SCOPE_TEST.equals(art.getScope()))
+ .collect(Collectors.toSet());
}
}
diff --git a/src/main/java/scala_maven/ScalaCompilerSupport.java b/src/main/java/scala_maven/ScalaCompilerSupport.java
index 78f10173..4907ba49 100644
--- a/src/main/java/scala_maven/ScalaCompilerSupport.java
+++ b/src/main/java/scala_maven/ScalaCompilerSupport.java
@@ -5,16 +5,13 @@
package scala_maven;
import java.io.File;
-import java.net.URL;
-import java.net.URLClassLoader;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
-import sbt.internal.inc.ScalaInstance;
import sbt_inc.SbtIncrementalCompiler;
-import scala.Option;
+import sbt_inc.SbtIncrementalCompilers;
import scala_maven_dependency.Context;
import scala_maven_executions.JavaMainCaller;
import util.FileUtils;
@@ -216,8 +213,8 @@ private List getFilesToCompile(List sourceRootDirs, long lastSuccess
List files = new ArrayList<>(sourceFiles.size());
if (_lastCompileAt > 0
|| (recompileMode != RecompileMode.all && (lastSuccessfulCompileTime > 0))) {
- ArrayList modifiedScalaFiles = new ArrayList<>(sourceFiles.size());
- ArrayList modifiedJavaFiles = new ArrayList<>(sourceFiles.size());
+ List modifiedScalaFiles = new ArrayList<>(sourceFiles.size());
+ List modifiedJavaFiles = new ArrayList<>(sourceFiles.size());
for (File f : sourceFiles) {
if (f.lastModified() >= lastSuccessfulCompileTime) {
if (f.getName().endsWith(".java")) {
@@ -276,52 +273,12 @@ long getLastSuccessfulTS() {
void setLastSuccessfulTS(long v) throws Exception {
if (!_lastCompileAtFile.exists()) {
- FileUtils.fileWrite(_lastCompileAtFile.getAbsolutePath(), ".");
+ org.codehaus.plexus.util.FileUtils.fileWrite(_lastCompileAtFile.getAbsolutePath(), ".");
}
_lastCompileAtFile.setLastModified(v);
}
}
- private ScalaInstance makeScalaInstance(Context sc) throws Exception {
- File[] compilerJars =
- sc.findCompilerAndDependencies().stream()
- .map(Artifact::getFile)
- .collect(Collectors.toList())
- .toArray(new File[] {});
- URL[] compilerJarUrls = FileUtils.toUrls(compilerJars);
-
- File[] libraryJars =
- sc.findLibraryAndDependencies().stream()
- .map(Artifact::getFile)
- .collect(Collectors.toList())
- .toArray(new File[] {});
- URL[] libraryJarUrls = FileUtils.toUrls(libraryJars);
-
- SortedSet allJars = new TreeSet<>();
- allJars.addAll(Arrays.asList(compilerJars));
- allJars.addAll(Arrays.asList(libraryJars));
- File[] allJarFiles = allJars.toArray(new File[] {});
-
- ClassLoader loaderLibraryOnly =
- new ScalaCompilerLoader(libraryJarUrls, xsbti.Reporter.class.getClassLoader());
- ClassLoader loaderCompilerOnly = new URLClassLoader(compilerJarUrls, loaderLibraryOnly);
-
- if (getLog().isDebugEnabled()) {
- getLog().debug("compilerJars: " + FileUtils.toMultiPath(compilerJars));
- getLog().debug("libraryJars: " + FileUtils.toMultiPath(libraryJars));
- }
-
- return new ScalaInstance(
- sc.version().toString(),
- loaderCompilerOnly,
- loaderCompilerOnly,
- loaderLibraryOnly,
- libraryJars,
- compilerJars,
- allJarFiles,
- Option.apply(sc.version().toString()));
- }
-
// Incremental compilation
private int incrementalCompile(
Set classpathElements,
@@ -343,30 +300,30 @@ private int incrementalCompile(
if (incremental == null) {
Context sc = findScalaContext();
File javaHome = JavaLocator.findHomeFromToolchain(getToolchain());
- ScalaInstance instance = makeScalaInstance(sc);
incremental =
- new SbtIncrementalCompiler(
+ SbtIncrementalCompilers.make(
javaHome,
new MavenArtifactResolver(factory, session),
secondaryCacheDir,
getLog(),
cacheFile,
compileOrder,
- instance);
+ sc.version(),
+ sc.findCompilerAndDependencies().stream()
+ .map(Artifact::getFile)
+ .collect(Collectors.toList()),
+ sc.findLibraryAndDependencies().stream()
+ .map(Artifact::getFile)
+ .collect(Collectors.toList()),
+ jvmArgs,
+ JavaLocator.findExecutableFromToolchain(getToolchain()),
+ pluginArtifacts.stream().map(Artifact::getFile).collect(Collectors.toList()));
}
- classpathElements.remove(outputDir);
- List scalacOptions = getScalacOptions();
- List javacOptions = getJavacOptions();
-
try {
incremental.compile(
- classpathElements.stream().map(File::toPath).collect(Collectors.toSet()),
- sources.stream().map(File::toPath).collect(Collectors.toList()),
- outputDir.toPath(),
- scalacOptions,
- javacOptions);
+ classpathElements, sources, outputDir, getScalacOptions(), getJavacOptions());
} catch (xsbti.CompileFailed e) {
if (compileInLoop) {
compileErrors = true;
diff --git a/src/main/java/scala_maven/ScalaConsoleMojo.java b/src/main/java/scala_maven/ScalaConsoleMojo.java
index 323f3338..0d2839eb 100644
--- a/src/main/java/scala_maven/ScalaConsoleMojo.java
+++ b/src/main/java/scala_maven/ScalaConsoleMojo.java
@@ -215,17 +215,17 @@ private Set setupConsoleClasspaths(final VersionNumber scalaVersion) throw
* JLine.
*/
private Artifact resolveJLine(final Artifact defaultFallback) throws Exception {
- final Set compilerDeps = super.findScalaContext().findCompilerAndDependencies();
+ final Set compilerDeps = findScalaContext().findCompilerAndDependencies();
for (final Artifact a : compilerDeps) {
- if (this.filterForJline(a)) {
+ if (filterForJline(a)) {
return a;
}
}
- super.getLog()
+ getLog()
.warn(
"Unable to determine the required Jline dependency from the POM. Falling back to hard-coded defaults.");
- super.getLog()
+ getLog()
.warn(
"If you get an InvocationTargetException, then this probably means we guessed the wrong version for JLine");
super.getLog().warn(String.format("Guessed JLine: %s", defaultFallback.toString()));
diff --git a/src/main/java/scala_maven/ScalaContinuousCompileMojo.java b/src/main/java/scala_maven/ScalaContinuousCompileMojo.java
index 5b6ae7ed..21cc3e5a 100755
--- a/src/main/java/scala_maven/ScalaContinuousCompileMojo.java
+++ b/src/main/java/scala_maven/ScalaContinuousCompileMojo.java
@@ -226,7 +226,7 @@ private void startNewCompileServer() throws Exception {
jcmd.addJvmArgs(jvmArgs);
jcmd.addArgs(args);
jcmd.spawn(displayCmd);
- FileUtils.fileWrite(serverTagFile.getAbsolutePath(), ".");
+ org.codehaus.plexus.util.FileUtils.fileWrite(serverTagFile.getAbsolutePath(), ".");
Thread.sleep(1000); // HACK To wait startup time of server (avoid first fsc command to failed to
// contact server)
}
diff --git a/src/main/java/scala_maven/ScalaMojoSupport.java b/src/main/java/scala_maven/ScalaMojoSupport.java
index 54983ee8..1ac8cfdd 100644
--- a/src/main/java/scala_maven/ScalaMojoSupport.java
+++ b/src/main/java/scala_maven/ScalaMojoSupport.java
@@ -36,6 +36,7 @@
import scala_maven_executions.JavaMainCallerByFork;
import scala_maven_executions.JavaMainCallerInProcess;
import util.FileUtils;
+import util.JavaLocator;
public abstract class ScalaMojoSupport extends AbstractMojo {
@@ -204,11 +205,11 @@ public abstract class ScalaMojoSupport extends AbstractMojo {
@Component private DependencyGraphBuilder dependencyGraphBuilder;
/** The toolchain manager to use. */
- @Component protected ToolchainManager toolchainManager;
+ @Component private ToolchainManager toolchainManager;
/** List of artifacts to run plugin */
@Parameter(defaultValue = "${plugin.artifacts}")
- private List pluginArtifacts;
+ protected List pluginArtifacts;
private MavenArtifactResolver mavenArtifactResolver;
@@ -263,8 +264,7 @@ protected void addToClasspath(
String version,
String classifier,
Set classpath,
- boolean addDependencies)
- throws Exception {
+ boolean addDependencies) {
MavenArtifactResolver mar = findMavenArtifactResolver();
if (addDependencies) {
for (Artifact a : mar.getJarAndDependencies(groupId, artifactId, version, classifier)) {
@@ -346,8 +346,8 @@ private VersionNumber findScalaVersion0() throws Exception {
throw new UnsupportedOperationException(error);
}
} else {
- // grappy hack to retrieve the SNAPSHOT version without timestamp,...
- // because if version is -SNAPSHOT and artifact is deploy with uniqueValue then
+ // crappy hack to retrieve the SNAPSHOT version without timestamp,...
+ // because if version is -SNAPSHOT and artifact is deployed with uniqueValue then
// the version
// get from dependency is with the timestamp and a build number (the resolved
// version)
@@ -370,10 +370,10 @@ private VersionNumber findScalaVersion0() throws Exception {
if (!scalaVersion.equals(detectedScalaVersion)) {
getLog()
.warn(
- "scala library version define in dependencies doesn't match the scalaVersion of the plugin");
+ "scala library version defined in dependencies doesn't match the scalaVersion of the plugin");
}
// getLog().info("suggestion: remove the scalaVersion from pom.xml");
- // //scalaVersion could be define in a parent pom where lib is not required
+ // //scalaVersion could be defined in a parent pom where lib is not required
}
return new VersionNumber(detectedScalaVersion);
}
@@ -555,12 +555,18 @@ private JavaMainCaller getEmptyScalaCommand(final String mainClass, final boolea
getLog().debug("use java command with args in file forced : " + forceUseArgFile);
cmd =
new JavaMainCallerByFork(
- this, mainClass, cp, null, null, forceUseArgFile, getToolchain());
+ getLog(),
+ mainClass,
+ cp,
+ null,
+ null,
+ forceUseArgFile,
+ JavaLocator.findExecutableFromToolchain(getToolchain()));
if (bootcp) {
cmd.addJvmArgs("-Xbootclasspath/a:" + toolcp);
}
} else {
- cmd = new JavaMainCallerInProcess(this, mainClass, toolcp, null, null);
+ cmd = new JavaMainCallerInProcess(getLog(), mainClass, toolcp, null, null);
}
return cmd;
}
@@ -582,32 +588,61 @@ private String getToolClasspath() throws Exception {
return FileUtils.toMultiPath(classpath);
}
- static String targetOption(String target, VersionNumber scalaVersion) {
- if (scalaVersion.major == 2) {
- if (scalaVersion.minor <= 12) {
- if (target.equals("1.5") || target.equals("5")) {
- return "jvm-1.5";
- } else if (target.equals("1.6") || target.equals("6")) {
- return "jvm-1.6";
- } else if (target.equals("1.7") || target.equals("7")) {
- return "jvm-1.7";
- } else if (target.equals("1.8") || target.equals("8")) {
- return "jvm-1.8";
- } else {
- // invalid or unsupported option, just ignore
- return null;
+ private static String computeTargetOption(String target) {
+ if (target.equals("1.5") || target.equals("5")) {
+ return "jvm-1.5";
+ } else if (target.equals("1.6") || target.equals("6")) {
+ return "jvm-1.6";
+ } else if (target.equals("1.7") || target.equals("7")) {
+ return "jvm-1.7";
+ } else if (target.equals("1.8") || target.equals("8")) {
+ return "jvm-1.8";
+ }
+ return null;
+ }
+
+ private static String computeReleaseOptionFromTarget(String target) {
+ if (target.equals("1.5")) {
+ return "5";
+ } else if (target.equals("1.6")) {
+ return "6";
+ } else if (target.equals("1.7")) {
+ return "7";
+ } else if (target.equals("1.8")) {
+ return "8";
+ }
+ return target;
+ }
+
+ // visible for tests
+ static List computeBytecodeVersionOptions(
+ String target, String release, VersionNumber scalaVersion) {
+ List options = new ArrayList<>();
+ boolean targetIsDefined = StringUtils.isNotEmpty(target);
+ boolean releaseIsDefined = StringUtils.isNotEmpty(release);
+ boolean releaseIsSupported = scalaVersion.compareTo(new VersionNumber("2.12.0")) >= 0;
+ String releaseOrJavaOutputVersionOptionName =
+ scalaVersion.compareTo(new VersionNumber("3.1.2")) >= 0
+ ? "-java-output-version"
+ : "-release";
+
+ if (releaseIsDefined && releaseIsSupported) {
+ // release's default is "maven.compiler.release"'s default, which is null
+ options.add(releaseOrJavaOutputVersionOptionName);
+ options.add(release);
+ } else if (targetIsDefined) {
+ // target's default is "maven.compiler.target"'s default, which is 1.8
+ if (releaseIsSupported) {
+ options.add(releaseOrJavaOutputVersionOptionName);
+ options.add(computeReleaseOptionFromTarget(target));
+ } else {
+ String correctTarget = computeTargetOption(target);
+ if (correctTarget != null) {
+ options.add("-target:" + correctTarget);
}
- } else if (target.equals("1.5")) {
- return "5";
- } else if (target.equals("1.6")) {
- return "6";
- } else if (target.equals("1.7")) {
- return "7";
- } else if (target.equals("1.8")) {
- return "8";
}
}
- return target;
+ return options;
}
protected List getScalacOptions() throws Exception {
@@ -617,20 +652,7 @@ protected List getScalacOptions() throws Exception {
Collections.addAll(options, StringUtils.split(addScalacArgs, "|"));
}
options.addAll(getCompilerPluginOptions());
-
- if (target != null && !target.isEmpty()) {
- String targetOption = targetOption(target, findScalaVersion());
- if (targetOption != null) {
- options.add("-target:" + targetOption);
- }
- }
- if (release != null && !release.isEmpty()) {
- VersionNumber scalaVersion = findScalaVersion();
- if (scalaVersion.major > 2 || (scalaVersion.major == 2 && scalaVersion.minor >= 12)) {
- options.add("-release");
- options.add(release);
- }
- }
+ options.addAll(computeBytecodeVersionOptions(target, release, findScalaVersion()));
return options;
}
@@ -646,15 +668,15 @@ protected List getJavacOptions() {
if (javacGenerateDebugSymbols) {
options.add("-g");
}
- if (release != null && !release.isEmpty()) {
+ if (StringUtils.isNotEmpty(release)) {
options.add("--release");
options.add(release);
} else {
- if (target != null && !target.isEmpty()) {
+ if (StringUtils.isNotEmpty(target)) {
options.add("-target");
options.add(target);
}
- if (source != null && !source.isEmpty()) {
+ if (StringUtils.isNotEmpty(source)) {
options.add("-source");
options.add(source);
}
@@ -667,8 +689,8 @@ protected List getJavacOptions() {
}
/**
- * @return This returns whether or not the scala version can support having java sent into the
- * compiler
+ * @return This returns whether the scala version can support having java sent into the compiler
+ * or not
*/
protected boolean isJavaSupportedByCompiler() throws Exception {
return findScalaVersion().compareTo(new VersionNumber("2.7.2")) >= 0;
diff --git a/src/main/java/scala_maven/ScalaRunMojo.java b/src/main/java/scala_maven/ScalaRunMojo.java
index f57fcf83..e7152008 100644
--- a/src/main/java/scala_maven/ScalaRunMojo.java
+++ b/src/main/java/scala_maven/ScalaRunMojo.java
@@ -4,16 +4,17 @@
*/
package scala_maven;
+import java.io.File;
import org.apache.maven.plugins.annotations.Execute;
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 org.apache.maven.toolchain.Toolchain;
import org.codehaus.plexus.util.StringUtils;
import scala_maven_executions.JavaMainCaller;
import scala_maven_executions.JavaMainCallerByFork;
import util.FileUtils;
+import util.JavaLocator;
/** Run a Scala class using the Scala runtime */
@Mojo(name = "run", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true)
@@ -70,17 +71,17 @@ public class ScalaRunMojo extends ScalaMojoSupport {
@Override
protected void doExecute() throws Exception {
JavaMainCaller jcmd = null;
- Toolchain toolchain = toolchainManager.getToolchainFromBuildContext("jdk", session);
+ File javaExec = JavaLocator.findExecutableFromToolchain(getToolchain());
if (StringUtils.isNotEmpty(mainClass)) {
jcmd =
new JavaMainCallerByFork(
- this,
+ getLog(),
mainClass,
FileUtils.toMultiPath(FileUtils.fromStrings(project.getTestClasspathElements())),
jvmArgs,
args,
forceUseArgFile,
- toolchain);
+ javaExec);
} else if ((launchers != null) && (launchers.length > 0)) {
if (StringUtils.isNotEmpty(launcher)) {
for (int i = 0; (i < launchers.length) && (jcmd == null); i++) {
@@ -89,27 +90,27 @@ protected void doExecute() throws Exception {
.info("launcher '" + launchers[i].id + "' selected => " + launchers[i].mainClass);
jcmd =
new JavaMainCallerByFork(
- this,
+ getLog(),
launchers[i].mainClass,
FileUtils.toMultiPath(
FileUtils.fromStrings(project.getTestClasspathElements())),
launchers[i].jvmArgs,
launchers[i].args,
forceUseArgFile,
- toolchain);
+ javaExec);
}
}
} else {
getLog().info("launcher '" + launchers[0].id + "' selected => " + launchers[0].mainClass);
jcmd =
new JavaMainCallerByFork(
- this,
+ getLog(),
launchers[0].mainClass,
FileUtils.toMultiPath(FileUtils.fromStrings(project.getTestClasspathElements())),
launchers[0].jvmArgs,
launchers[0].args,
forceUseArgFile,
- toolchain);
+ javaExec);
}
}
if (jcmd != null) {
diff --git a/src/main/java/scala_maven/ScalaScriptMojo.java b/src/main/java/scala_maven/ScalaScriptMojo.java
index 725dd74e..50d9fbd1 100644
--- a/src/main/java/scala_maven/ScalaScriptMojo.java
+++ b/src/main/java/scala_maven/ScalaScriptMojo.java
@@ -40,7 +40,6 @@
import scala_maven_dependency.Context;
import scala_maven_executions.JavaMainCaller;
import scala_maven_executions.MainHelper;
-import util.FileUtils;
/**
* Run a scala script.
@@ -150,7 +149,7 @@ protected void doExecute() throws Exception {
String baseName = scriptBaseNameOf(scriptFile, _lastScriptIndex.incrementAndGet());
File destFile = new File(scriptDir, baseName + ".scala");
- Set classpath = new TreeSet();
+ Set classpath = new TreeSet<>();
configureClasspath(classpath);
boolean mavenProjectDependency = includeScopes.contains("plugin");
@@ -355,7 +354,7 @@ private void wrapScript(File destFile, boolean mavenProjectDependency) throws IO
reader = new BufferedReader(new StringReader(script));
}
- String baseName = FileUtils.basename(destFile.getName(), ".scala");
+ String baseName = org.codehaus.plexus.util.FileUtils.basename(destFile.getName(), ".scala");
if (mavenProjectDependency) {
// out.println("import scala.collection.jcl.Conversions._");
out.println(
diff --git a/src/main/java/scala_maven_executions/Fork.java b/src/main/java/scala_maven_executions/Fork.java
new file mode 100644
index 00000000..b40a1e29
--- /dev/null
+++ b/src/main/java/scala_maven_executions/Fork.java
@@ -0,0 +1,152 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package scala_maven_executions;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.*;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+import org.apache.commons.exec.*;
+import org.apache.maven.plugin.MojoFailureException;
+
+/**
+ * Run a forked Java process, based on a generated booter jar. The classpath is passed as a manifest
+ * entry to cope with command length limitation on Windows. The target main class is passed as an
+ * argument. The target arguments are passed as a file inside the jar.
+ */
+public final class Fork {
+
+ private static final boolean IS_WINDOWS =
+ System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("windows");
+
+ private static final String BOOTER_JAR_NAME = "scala-maven-plugin-booter";
+ private final File javaExecutable;
+ private final String mainClassName;
+ private final List classpath;
+
+ private final String[] jvmArgs;
+ private final String[] args;
+
+ public Fork(
+ String mainClassName,
+ List classpath,
+ String[] jvmArgs,
+ String[] args,
+ File javaExecutable) {
+
+ this.mainClassName = mainClassName;
+ this.classpath = classpath;
+ this.jvmArgs = jvmArgs;
+ this.args = args;
+ this.javaExecutable = javaExecutable;
+ }
+
+ private static String toWindowsShortName(String value) {
+ if (IS_WINDOWS) {
+ int programFilesIndex = value.indexOf("Program Files");
+ if (programFilesIndex >= 0) {
+ // Could be "Program Files" or "Program Files (x86)"
+ int firstSeparatorAfterProgramFiles =
+ value.indexOf(File.separator, programFilesIndex + "Program Files".length());
+ File longNameDir =
+ firstSeparatorAfterProgramFiles < 0
+ ? new File(value)
+ : // C:\\Program Files with
+ // trailing separator
+ new File(value.substring(0, firstSeparatorAfterProgramFiles)); // chop child
+ // Some other sibling dir could be PrograXXX and might shift short name index
+ // so, we can't be sure "Program Files" is "Progra~1" and "Program Files (x86)"
+ // is "Progra~2"
+ for (int i = 0; i < 10; i++) {
+ File shortNameDir = new File(longNameDir.getParent(), "Progra~" + i);
+ if (shortNameDir.equals(longNameDir)) {
+ return shortNameDir.toString();
+ }
+ }
+ }
+ }
+
+ return value;
+ }
+
+ public void run(OutputStream os) throws Exception {
+ File booterJar = createBooterJar(classpath, ForkMain.class.getName(), args);
+
+ CommandLine command = new CommandLine(toWindowsShortName(javaExecutable.getCanonicalPath()));
+ command.addArguments(jvmArgs, false);
+ command.addArgument("-jar");
+ command.addArgument(booterJar.getCanonicalPath());
+ command.addArgument(mainClassName);
+
+ Executor exec = new DefaultExecutor();
+ exec.setStreamHandler(new PumpStreamHandler(os));
+
+ int exitValue = exec.execute(command);
+ if (exitValue != 0) {
+ throw new MojoFailureException("command line returned non-zero value:" + exitValue);
+ }
+ }
+
+ /**
+ * Create a jar with just a manifest containing a Main-Class entry and a Class-Path entry for all
+ * classpath elements.
+ *
+ * @param classPath List of all classpath elements.
+ * @param startClassName The classname to start (main-class)
+ * @return The file pointing to the jar
+ * @throws IOException When a file operation fails.
+ */
+ private static File createBooterJar(List classPath, String startClassName, String[] args)
+ throws IOException {
+ File file = File.createTempFile(BOOTER_JAR_NAME, ".jar");
+ file.deleteOnExit();
+
+ String cp =
+ classPath.stream()
+ .map(element -> getURL(new File(element)).toExternalForm())
+ .collect(Collectors.joining(" "));
+
+ Manifest manifest = new Manifest();
+ manifest.getMainAttributes().putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");
+ manifest.getMainAttributes().putValue(Attributes.Name.MAIN_CLASS.toString(), startClassName);
+ manifest.getMainAttributes().putValue(Attributes.Name.CLASS_PATH.toString(), cp);
+
+ try (JarOutputStream jos =
+ new JarOutputStream(new BufferedOutputStream(Files.newOutputStream(file.toPath())))) {
+ jos.setLevel(JarOutputStream.STORED);
+
+ JarEntry manifestJarEntry = new JarEntry("META-INF/MANIFEST.MF");
+ jos.putNextEntry(manifestJarEntry);
+ manifest.write(jos);
+ jos.closeEntry();
+
+ JarEntry argsJarEntry = new JarEntry(ForkMain.ARGS_FILE);
+ jos.putNextEntry(argsJarEntry);
+ jos.write(
+ Arrays.stream(args).collect(Collectors.joining("\n")).getBytes(StandardCharsets.UTF_8));
+ jos.closeEntry();
+ }
+
+ return file;
+ }
+
+ // encode any characters that do not comply with RFC 2396
+ // this is primarily to handle Windows where the user's home directory contains
+ // spaces
+ private static URL getURL(File file) {
+ try {
+ return new URL(file.toURI().toASCIIString());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/scala_maven_executions/ForkLogLevel.java b/src/main/java/scala_maven_executions/ForkLogLevel.java
new file mode 100644
index 00000000..f867d666
--- /dev/null
+++ b/src/main/java/scala_maven_executions/ForkLogLevel.java
@@ -0,0 +1,39 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package scala_maven_executions;
+
+public enum ForkLogLevel {
+ DEBUG,
+ INFO,
+ WARN,
+ ERROR;
+
+ private final String header;
+
+ ForkLogLevel() {
+ this.header = name() + ": ";
+ }
+
+ public static ForkLogLevel level(String line) {
+ if (line.startsWith(DEBUG.header)) {
+ return DEBUG;
+ } else if (line.startsWith(INFO.header)) {
+ return INFO;
+ } else if (line.startsWith(WARN.header)) {
+ return WARN;
+ } else if (line.startsWith(ERROR.header)) {
+ return ERROR;
+ }
+ return null;
+ }
+
+ public String addHeader(String line) {
+ return header + line;
+ }
+
+ public String removeHeader(String line) {
+ return line.substring(header.length());
+ }
+}
diff --git a/src/main/java/scala_maven_executions/ForkLogger.java b/src/main/java/scala_maven_executions/ForkLogger.java
new file mode 100644
index 00000000..cc9d4e13
--- /dev/null
+++ b/src/main/java/scala_maven_executions/ForkLogger.java
@@ -0,0 +1,63 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package scala_maven_executions;
+
+public abstract class ForkLogger {
+ private final StringBuilder buffer = new StringBuilder();
+ private boolean forceFlush;
+ private ForkLogLevel currentLogLevel = null;
+
+ public abstract void onException(Exception t);
+
+ public abstract void onError(String content);
+
+ public abstract void onWarn(String content);
+
+ public abstract void onInfo(String content);
+
+ public abstract void onDebug(String content);
+
+ private void flushBuffer() {
+ if (buffer.length() != 0 && currentLogLevel != null) {
+ switch (currentLogLevel) {
+ case ERROR:
+ onError(buffer.toString());
+ break;
+ case WARN:
+ onWarn(buffer.toString());
+ break;
+ case INFO:
+ onInfo(buffer.toString());
+ break;
+ case DEBUG:
+ onDebug(buffer.toString());
+ break;
+ }
+ buffer.setLength(0);
+ }
+ }
+
+ public final void processLine(String line) {
+ try {
+ ForkLogLevel newLogLevel = ForkLogLevel.level(line);
+ if (newLogLevel != null) {
+ flushBuffer();
+ currentLogLevel = newLogLevel;
+ buffer.append(newLogLevel.removeHeader(line));
+ } else {
+ buffer.append(System.lineSeparator()).append(line);
+ }
+ if (forceFlush) {
+ flushBuffer();
+ }
+ } catch (Exception e) {
+ onException(e);
+ }
+ }
+
+ public final void forceNextLineToFlush() {
+ forceFlush = true;
+ }
+}
diff --git a/src/main/java/scala_maven_executions/ForkMain.java b/src/main/java/scala_maven_executions/ForkMain.java
new file mode 100644
index 00000000..e71aeaf1
--- /dev/null
+++ b/src/main/java/scala_maven_executions/ForkMain.java
@@ -0,0 +1,58 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ * See UNLICENSE.
+ */
+package scala_maven_executions;
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class ForkMain {
+
+ public static final String ARGS_FILE = "META-INF/args.txt";
+
+ public static void main(String[] args) {
+ try {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ String[] argsFromFile = readArgFile(cl);
+ runMain(cl, args[0], argsFromFile);
+ } catch (Throwable t) {
+ PrintWriter stacktrace = new PrintWriter(new StringWriter());
+ t.printStackTrace(stacktrace);
+ System.out.println(ForkLogLevel.ERROR.addHeader(stacktrace.toString()));
+ System.out.flush();
+ System.exit(-1);
+ }
+ }
+
+ private static void runMain(ClassLoader cl, String mainClassName, String[] args)
+ throws Exception {
+ Class> mainClass = cl.loadClass(mainClassName);
+ Method mainMethod = mainClass.getMethod("main", String[].class);
+ int mods = mainMethod.getModifiers();
+ if (mainMethod.getReturnType() != void.class
+ || !Modifier.isStatic(mods)
+ || !Modifier.isPublic(mods)) {
+ throw new NoSuchMethodException("main");
+ }
+
+ mainMethod.invoke(null, new Object[] {args});
+ }
+
+ private static String[] readArgFile(ClassLoader cl) throws IOException {
+ List args = new ArrayList<>();
+ try (BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(cl.getResourceAsStream(ARGS_FILE), StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ args.add(line);
+ }
+ return args.toArray(new String[] {});
+ }
+ }
+}
diff --git a/src/main/java/scala_maven_executions/JavaMainCallerByFork.java b/src/main/java/scala_maven_executions/JavaMainCallerByFork.java
index 57120fcf..06d41f67 100644
--- a/src/main/java/scala_maven_executions/JavaMainCallerByFork.java
+++ b/src/main/java/scala_maven_executions/JavaMainCallerByFork.java
@@ -14,12 +14,10 @@
import org.apache.commons.exec.LogOutputStream;
import org.apache.commons.exec.OS;
import org.apache.commons.exec.PumpStreamHandler;
-import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.toolchain.Toolchain;
+import org.apache.maven.plugin.logging.Log;
import org.codehaus.plexus.util.StringUtils;
import scala_maven_executions.LogProcessorUtils.LevelState;
-import util.JavaLocator;
/**
* forked java commands.
@@ -32,25 +30,24 @@ public class JavaMainCallerByFork extends JavaMainCallerSupport {
private boolean _forceUseArgFile;
/** Location of java executable. */
- private String _javaExec;
+ private final File _javaExec;
private boolean _redirectToLog;
public JavaMainCallerByFork(
- AbstractMojo requester1,
+ Log mavenLogger,
String mainClassName1,
String classpath,
String[] jvmArgs1,
String[] args1,
boolean forceUseArgFile,
- Toolchain toolchain)
- throws Exception {
- super(requester1, mainClassName1, classpath, jvmArgs1, args1);
+ File javaExec) {
+ super(mavenLogger, mainClassName1, classpath, jvmArgs1, args1);
for (String key : System.getenv().keySet()) {
env.add(key + "=" + System.getenv(key));
}
- _javaExec = JavaLocator.findExecutableFromToolchain(toolchain);
+ _javaExec = javaExec;
_forceUseArgFile = forceUseArgFile;
}
@@ -75,14 +72,13 @@ protected void processLine(String line, int level) {
_previous = LogProcessorUtils.levelStateOf(line, _previous);
switch (_previous.level) {
case ERROR:
- requester.getLog().error(line);
+ mavenLogger.error(line);
break;
case WARNING:
- requester.getLog().warn(line);
+ mavenLogger.warn(line);
break;
default:
- requester.getLog().info(line);
- break;
+ mavenLogger.info(line);
}
} catch (Exception e) {
e.printStackTrace();
@@ -148,22 +144,22 @@ public SpawnMonitor spawn(boolean displayCmd) throws Exception {
private void displayCmd(boolean displayCmd, List cmd) {
if (displayCmd) {
- requester.getLog().info("cmd: " + " " + StringUtils.join(cmd.iterator(), " "));
- } else if (requester.getLog().isDebugEnabled()) {
- requester.getLog().debug("cmd: " + " " + StringUtils.join(cmd.iterator(), " "));
+ mavenLogger.info("cmd: " + " " + StringUtils.join(cmd.iterator(), " "));
+ } else if (mavenLogger.isDebugEnabled()) {
+ mavenLogger.debug("cmd: " + " " + StringUtils.join(cmd.iterator(), " "));
}
}
private List buildCommand() throws Exception {
- ArrayList back = new ArrayList<>(2 + jvmArgs.size() + args.size());
- back.add(_javaExec);
+ List back = new ArrayList<>(2 + jvmArgs.size() + args.size());
+ back.add(_javaExec.getPath());
if (!_forceUseArgFile && (lengthOf(args, 1) + lengthOf(jvmArgs, 1) < 400)) {
back.addAll(jvmArgs);
back.add(mainClassName);
back.addAll(args);
} else {
File jarPath = new File(MainHelper.locateJar(MainHelper.class));
- requester.getLog().debug("plugin jar to add :" + jarPath);
+ mavenLogger.debug("plugin jar to add :" + jarPath);
addToClasspath(jarPath);
back.addAll(jvmArgs);
back.add(MainWithArgsInFile.class.getName());
diff --git a/src/main/java/scala_maven_executions/JavaMainCallerInProcess.java b/src/main/java/scala_maven_executions/JavaMainCallerInProcess.java
index 634f3b4f..baf8f7a2 100644
--- a/src/main/java/scala_maven_executions/JavaMainCallerInProcess.java
+++ b/src/main/java/scala_maven_executions/JavaMainCallerInProcess.java
@@ -9,7 +9,7 @@
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
-import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.logging.Log;
import org.codehaus.plexus.util.StringUtils;
/**
@@ -23,13 +23,9 @@ public class JavaMainCallerInProcess extends JavaMainCallerSupport {
private ClassLoader _cl;
public JavaMainCallerInProcess(
- AbstractMojo requester,
- String mainClassName,
- String classpath,
- String[] jvmArgs,
- String[] args)
+ Log mavenLogger, String mainClassName, String classpath, String[] jvmArgs, String[] args)
throws Exception {
- super(requester, mainClassName, "", jvmArgs, args);
+ super(mavenLogger, mainClassName, "", jvmArgs, args);
// Pull out classpath and create class loader
ArrayList urls = new ArrayList<>();
@@ -38,7 +34,7 @@ public JavaMainCallerInProcess(
urls.add(new File(path).toURI().toURL());
} catch (MalformedURLException e) {
// TODO - Do something usefull here...
- requester.getLog().error(e);
+ mavenLogger.error(e);
}
}
_cl = new URLClassLoader(urls.toArray(new URL[] {}), null);
@@ -49,7 +45,7 @@ public void addJvmArgs(String... args0) {
// TODO - Ignore classpath
if (args0 != null) {
for (String arg : args0) {
- requester.getLog().warn("jvmArgs are ignored when run in process :" + arg);
+ mavenLogger.warn("jvmArgs are ignored when run in process :" + arg);
}
}
}
@@ -87,15 +83,13 @@ public SpawnMonitor spawn(final boolean displayCmd) {
private void runInternal(boolean displayCmd) throws Exception {
String[] argArray = args.toArray(new String[] {});
if (displayCmd) {
- requester
- .getLog()
- .info("cmd : " + mainClassName + "(" + StringUtils.join(argArray, ",") + ")");
+ mavenLogger.info("cmd : " + mainClassName + "(" + StringUtils.join(argArray, ",") + ")");
}
MainHelper.runMain(mainClassName, args, _cl);
}
@Override
public void redirectToLog() {
- requester.getLog().warn("redirection to log is not supported for 'inProcess' mode");
+ mavenLogger.warn("redirection to log is not supported for 'inProcess' mode");
}
}
diff --git a/src/main/java/scala_maven_executions/JavaMainCallerSupport.java b/src/main/java/scala_maven_executions/JavaMainCallerSupport.java
index 14c528f2..bf86497d 100644
--- a/src/main/java/scala_maven_executions/JavaMainCallerSupport.java
+++ b/src/main/java/scala_maven_executions/JavaMainCallerSupport.java
@@ -7,7 +7,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.List;
-import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.logging.Log;
import org.codehaus.plexus.util.StringUtils;
/**
@@ -17,19 +17,15 @@
*/
public abstract class JavaMainCallerSupport implements JavaMainCaller {
- protected AbstractMojo requester;
- protected List env = new ArrayList();
+ protected Log mavenLogger;
+ protected List env = new ArrayList<>();
protected String mainClassName;
- protected List jvmArgs = new ArrayList();
- protected List args = new ArrayList();
+ protected List jvmArgs = new ArrayList<>();
+ protected List args = new ArrayList<>();
protected JavaMainCallerSupport(
- AbstractMojo requester1,
- String mainClassName1,
- String classpath,
- String[] jvmArgs1,
- String[] args1) {
- this.requester = requester1;
+ Log mavenLogger, String mainClassName1, String classpath, String[] jvmArgs1, String[] args1) {
+ this.mavenLogger = mavenLogger;
for (String key : System.getenv().keySet()) {
env.add(key + "=" + System.getenv(key));
}
diff --git a/src/main/java/scala_maven_executions/MainHelper.java b/src/main/java/scala_maven_executions/MainHelper.java
index 6b4d71a1..bf871630 100644
--- a/src/main/java/scala_maven_executions/MainHelper.java
+++ b/src/main/java/scala_maven_executions/MainHelper.java
@@ -18,7 +18,6 @@
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -46,7 +45,7 @@ public static String[] findFiles(File dir, String[] includes, String[] excludes)
public static String toClasspathString(ClassLoader cl) {
StringBuilder back = new StringBuilder();
- List cps = new LinkedList<>();
+ List cps = new ArrayList<>();
appendUrlToClasspathCollection(cl, cps);
for (String cp : cps) {
if (back.length() != 0) {
diff --git a/src/main/java/util/FileUtils.java b/src/main/java/util/FileUtils.java
index 1d955949..8b06770e 100644
--- a/src/main/java/util/FileUtils.java
+++ b/src/main/java/util/FileUtils.java
@@ -6,8 +6,6 @@
import java.io.File;
import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -16,10 +14,8 @@
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.codehaus.plexus.util.StringUtils;
-public class FileUtils extends org.codehaus.plexus.util.FileUtils {
+public class FileUtils {
/**
* @param canonical Should use CanonicalPath to normalize path (true => getCanonicalPath, false
@@ -44,24 +40,7 @@ public static Set fromStrings(Collection s) {
}
public static String toMultiPath(Collection paths) {
- return StringUtils.join(paths.iterator(), File.pathSeparator);
- }
-
- public static String toMultiPath(File[] paths) {
- return StringUtils.join(paths, File.pathSeparator);
- }
-
- public static URL[] toUrls(File[] files) throws Exception {
- return Stream.of(files)
- .map(
- x -> {
- try {
- return x.toURI().toURL();
- } catch (MalformedURLException e) {
- throw new RuntimeException("failed to convert into url " + x, e);
- }
- })
- .toArray(URL[]::new);
+ return paths.stream().map(File::getPath).collect(Collectors.joining(File.pathSeparator));
}
public static List listDirectoryContent(Path directory, Function filter)
diff --git a/src/main/java/util/JavaLocator.java b/src/main/java/util/JavaLocator.java
index 3f2c3ae3..4066af38 100644
--- a/src/main/java/util/JavaLocator.java
+++ b/src/main/java/util/JavaLocator.java
@@ -5,6 +5,9 @@
package util;
import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Locale;
import org.apache.maven.toolchain.Toolchain;
/**
@@ -14,31 +17,64 @@
*/
public class JavaLocator {
- public static String findExecutableFromToolchain(Toolchain toolchain) {
- String javaExec = null;
+ private static final boolean IS_WINDOWS =
+ System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("windows");
+
+ // inspired from org.codehaus.plexus.compiler.javac.JavacCompiler#getJavacExecutable
+ public static File findExecutableFromToolchain(Toolchain toolchain) {
if (toolchain != null) {
- javaExec = toolchain.findTool("java");
+ String fromToolChain = toolchain.findTool("java");
+ if (fromToolChain != null) {
+ return new File(fromToolChain);
+ }
}
- if (javaExec == null) {
- String javaHome = System.getenv("JAVA_HOME");
- if (javaHome == null) {
- javaHome = System.getProperty("java.home"); // fallback to JRE
+ String javaCommand = "java" + (IS_WINDOWS ? ".exe" : "");
+
+ String javaHomeSystemProperty = System.getProperty("java.home");
+ if (javaHomeSystemProperty != null) {
+ Path javaHomePath = Paths.get(javaHomeSystemProperty);
+
+ if (javaHomePath.endsWith("jre")) {
+ // Old JDK versions contain a JRE. We might be pointing to that.
+ // We want to try to use the JDK instead as we need javac in order to compile mixed
+ // Java-Scala projects.
+ File javaExecPath = javaHomePath.resolveSibling("bin").resolve(javaCommand).toFile();
+ if (javaExecPath.isFile()) {
+ return javaExecPath;
+ }
}
- if (javaHome == null) {
+
+ // old standalone JRE or modern JDK
+ File javaExecPath = javaHomePath.resolve("bin").resolve(javaCommand).toFile();
+ if (javaExecPath.isFile()) {
+ return javaExecPath;
+ } else {
throw new IllegalStateException(
- "Couldn't locate java, try setting JAVA_HOME environment variable.");
+ "Couldn't locate java in defined java.home system property.");
}
- javaExec = javaHome + File.separator + "bin" + File.separator + "java";
}
- return javaExec;
+ // fallback: try to resolve from JAVA_HOME
+ String javaHomeEnvVar = System.getenv("JAVA_HOME");
+ if (javaHomeEnvVar == null) {
+ throw new IllegalStateException(
+ "Couldn't locate java, try setting JAVA_HOME environment variable.");
+ }
+
+ File javaExecPath = Paths.get(javaHomeEnvVar).resolve("bin").resolve(javaCommand).toFile();
+ if (javaExecPath.isFile()) {
+ return javaExecPath;
+ } else {
+ throw new IllegalStateException(
+ "Couldn't locate java in defined JAVA_HOME environment variable.");
+ }
}
public static File findHomeFromToolchain(Toolchain toolchain) {
- String executable = findExecutableFromToolchain(toolchain);
- File executableParent = new File(executable).getParentFile();
+ File executable = findExecutableFromToolchain(toolchain);
+ File executableParent = executable.getParentFile();
if (executableParent == null) {
return null;
}
diff --git a/src/test/java/scala_maven/ScalaMojoSupportTest.java b/src/test/java/scala_maven/ScalaMojoSupportTest.java
index 6cfffeda..eaf3a21d 100644
--- a/src/test/java/scala_maven/ScalaMojoSupportTest.java
+++ b/src/test/java/scala_maven/ScalaMojoSupportTest.java
@@ -4,8 +4,8 @@
*/
package scala_maven;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static java.util.Arrays.asList;
+import static org.junit.Assert.*;
import org.junit.Test;
@@ -13,51 +13,103 @@ public class ScalaMojoSupportTest {
@Test
public void scala2_11_should_generate_prefixed_target() {
- assertEquals("jvm-1.5", ScalaMojoSupport.targetOption("1.5", new VersionNumber("2.11.12")));
- assertEquals("jvm-1.5", ScalaMojoSupport.targetOption("5", new VersionNumber("2.11.12")));
- assertEquals("jvm-1.6", ScalaMojoSupport.targetOption("1.6", new VersionNumber("2.11.12")));
- assertEquals("jvm-1.6", ScalaMojoSupport.targetOption("6", new VersionNumber("2.11.12")));
- assertEquals("jvm-1.7", ScalaMojoSupport.targetOption("1.7", new VersionNumber("2.11.12")));
- assertEquals("jvm-1.7", ScalaMojoSupport.targetOption("7", new VersionNumber("2.11.12")));
- assertEquals("jvm-1.8", ScalaMojoSupport.targetOption("1.8", new VersionNumber("2.11.12")));
- assertEquals("jvm-1.8", ScalaMojoSupport.targetOption("8", new VersionNumber("2.11.12")));
+ assertEquals(
+ asList("-target:jvm-1.5"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.5", null, new VersionNumber("2.11.12")));
+ assertEquals(
+ asList("-target:jvm-1.5"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("5", null, new VersionNumber("2.11.12")));
+ assertEquals(
+ asList("-target:jvm-1.6"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.6", null, new VersionNumber("2.11.12")));
+ assertEquals(
+ asList("-target:jvm-1.6"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("6", null, new VersionNumber("2.11.12")));
+ assertEquals(
+ asList("-target:jvm-1.7"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.7", null, new VersionNumber("2.11.12")));
+ assertEquals(
+ asList("-target:jvm-1.7"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("7", null, new VersionNumber("2.11.12")));
+ assertEquals(
+ asList("-target:jvm-1.8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", null, new VersionNumber("2.11.12")));
+ assertEquals(
+ asList("-target:jvm-1.8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("8", null, new VersionNumber("2.11.12")));
}
@Test
- public void scala2_11_should_generate_null_for_unsupported_java_versions() {
- assertNull(ScalaMojoSupport.targetOption("11", new VersionNumber("2.11.12")));
- assertNull(ScalaMojoSupport.targetOption("17", new VersionNumber("2.11.12")));
+ public void scala2_11_should_generate_nothing_for_unsupported_java_versions() {
+ assertTrue(
+ ScalaMojoSupport.computeBytecodeVersionOptions("11", null, new VersionNumber("2.11.12"))
+ .isEmpty());
+ assertTrue(
+ ScalaMojoSupport.computeBytecodeVersionOptions("17", null, new VersionNumber("2.11.12"))
+ .isEmpty());
}
@Test
- public void scala2_12_should_generate_prefixed_target() {
- assertEquals("jvm-1.5", ScalaMojoSupport.targetOption("1.5", new VersionNumber("2.12.11")));
- assertEquals("jvm-1.5", ScalaMojoSupport.targetOption("5", new VersionNumber("2.12.11")));
- assertEquals("jvm-1.6", ScalaMojoSupport.targetOption("1.6", new VersionNumber("2.12.11")));
- assertEquals("jvm-1.6", ScalaMojoSupport.targetOption("6", new VersionNumber("2.12.11")));
- assertEquals("jvm-1.7", ScalaMojoSupport.targetOption("1.7", new VersionNumber("2.12.11")));
- assertEquals("jvm-1.7", ScalaMojoSupport.targetOption("7", new VersionNumber("2.12.11")));
- assertEquals("jvm-1.8", ScalaMojoSupport.targetOption("1.8", new VersionNumber("2.12.11")));
- assertEquals("jvm-1.8", ScalaMojoSupport.targetOption("8", new VersionNumber("2.12.11")));
+ public void scala2_12_should_generate_release() {
+ assertEquals(
+ asList("-release", "8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", null, new VersionNumber("2.12.11")));
+ assertEquals(
+ asList("-release", "8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "8", new VersionNumber("2.12.11")));
+ assertEquals(
+ asList("-release", "11"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "11", new VersionNumber("2.12.11")));
+ assertEquals(
+ asList("-release", "17"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "17", new VersionNumber("2.12.11")));
}
@Test
- public void scala2_12_should_generate_null_for_unsupported_java_versions() {
- assertNull(ScalaMojoSupport.targetOption("11", new VersionNumber("2.12.11")));
- assertNull(ScalaMojoSupport.targetOption("17", new VersionNumber("2.12.11")));
+ public void scala2_13_should_generate_release() {
+ assertEquals(
+ asList("-release", "8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", null, new VersionNumber("2.13.10")));
+ assertEquals(
+ asList("-release", "8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "8", new VersionNumber("2.13.10")));
+ assertEquals(
+ asList("-release", "11"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "11", new VersionNumber("2.13.10")));
+ assertEquals(
+ asList("-release", "17"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "17", new VersionNumber("2.13.10")));
}
@Test
- public void scala2_13_should_generate_non_prefixed_target() {
- assertEquals("5", ScalaMojoSupport.targetOption("1.5", new VersionNumber("2.13.8")));
- assertEquals("5", ScalaMojoSupport.targetOption("5", new VersionNumber("2.13.8")));
- assertEquals("6", ScalaMojoSupport.targetOption("1.6", new VersionNumber("2.13.8")));
- assertEquals("6", ScalaMojoSupport.targetOption("6", new VersionNumber("2.13.8")));
- assertEquals("7", ScalaMojoSupport.targetOption("1.7", new VersionNumber("2.13.8")));
- assertEquals("7", ScalaMojoSupport.targetOption("7", new VersionNumber("2.13.8")));
- assertEquals("8", ScalaMojoSupport.targetOption("1.8", new VersionNumber("2.13.8")));
- assertEquals("8", ScalaMojoSupport.targetOption("8", new VersionNumber("2.13.8")));
- assertEquals("11", ScalaMojoSupport.targetOption("11", new VersionNumber("2.13.8")));
- assertEquals("17", ScalaMojoSupport.targetOption("17", new VersionNumber("2.13.8")));
+ public void scala3_1_1_should_generate_release() {
+ assertEquals(
+ asList("-release", "8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", null, new VersionNumber("3.1.1")));
+ assertEquals(
+ asList("-release", "8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "8", new VersionNumber("3.1.1")));
+ assertEquals(
+ asList("-release", "11"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "11", new VersionNumber("3.1.1")));
+ assertEquals(
+ asList("-release", "17"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "17", new VersionNumber("3.1.1")));
+ }
+
+ @Test
+ public void scala3_1_2_should_generate_java_output_version() {
+ assertEquals(
+ asList("-java-output-version", "8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", null, new VersionNumber("3.1.2")));
+ assertEquals(
+ asList("-java-output-version", "8"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "8", new VersionNumber("3.1.2")));
+ assertEquals(
+ asList("-java-output-version", "11"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "11", new VersionNumber("3.1.2")));
+ assertEquals(
+ asList("-java-output-version", "17"),
+ ScalaMojoSupport.computeBytecodeVersionOptions("1.8", "17", new VersionNumber("3.1.2")));
}
}
diff --git a/src/test/java/util/JavaLocatorTest.java b/src/test/java/util/JavaLocatorTest.java
index a8c67fc7..1e9375c2 100644
--- a/src/test/java/util/JavaLocatorTest.java
+++ b/src/test/java/util/JavaLocatorTest.java
@@ -7,7 +7,6 @@
import static org.junit.Assert.*;
import java.io.File;
-import java.nio.file.Paths;
import org.apache.maven.toolchain.Toolchain;
import org.junit.Rule;
import org.junit.Test;
@@ -18,23 +17,20 @@ public class JavaLocatorTest {
@Rule public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
@Test
- public void shouldReturnNullWhenJavaIsNotAvailableOnCommandLineAndJavaHomeIsPresent() {
- Toolchain toolchain = new NullReturningToolChain();
- environmentVariables.set("JAVA_HOME", "test");
- assertEquals(
- Paths.get("test", "bin", "java").toString(),
- JavaLocator.findExecutableFromToolchain(toolchain));
+ public void shouldReturnNotNullWhenJavaIsNotAvailableOnCommandLineAndJavaHomeIsPresent() {
+ Toolchain toolchain = new ReturningToolChain(null);
+ assertNotNull(JavaLocator.findExecutableFromToolchain(toolchain));
}
@Test
- public void shouldReturnPathToJavaWhenJavaIsPresent() throws Exception {
- Toolchain toolchain = new ReturningToolChain();
- assertEquals("my-path-to-java", JavaLocator.findExecutableFromToolchain(toolchain));
+ public void shouldReturnPathToJavaWhenJavaIsPresent() {
+ Toolchain toolchain = new ReturningToolChain("my-path-to-java");
+ assertEquals("my-path-to-java", JavaLocator.findExecutableFromToolchain(toolchain).getPath());
}
@Test
public void shouldThrowExceptionWhenNothingCouldBeFound() {
- Toolchain toolchain = new NullReturningToolChain();
+ Toolchain toolchain = new ReturningToolChain(null);
System.clearProperty("java.home");
environmentVariables.set("JAVA_HOME", null);
try {
@@ -48,43 +44,23 @@ public void shouldThrowExceptionWhenNothingCouldBeFound() {
@Test
public void shouldReturnParentOfChildOfJavaHomeFolder() {
- File home = JavaLocator.findHomeFromToolchain(new TestStringReturningToolChain());
+ File home =
+ JavaLocator.findHomeFromToolchain(new ReturningToolChain("parent/child/my-path-to-java"));
assertEquals("parent", home.getPath());
}
@Test
public void shouldReturnNullWhenFileIsNotPresent() {
- File home = JavaLocator.findHomeFromToolchain(new ReturningToolChain());
+ File home = JavaLocator.findHomeFromToolchain(new ReturningToolChain("my-path-to-java"));
assertNull(home);
}
- class NullReturningToolChain implements Toolchain {
+ static final class ReturningToolChain implements Toolchain {
+ private final String tool;
- @Override
- public String getType() {
- return null;
- }
-
- @Override
- public String findTool(String s) {
- return null;
+ ReturningToolChain(String tool) {
+ this.tool = tool;
}
- }
-
- class TestStringReturningToolChain implements Toolchain {
-
- @Override
- public String getType() {
- return null;
- }
-
- @Override
- public String findTool(String s) {
- return "parent/child/my-path-to-java";
- }
- }
-
- class ReturningToolChain implements Toolchain {
@Override
public String getType() {
@@ -92,8 +68,8 @@ public String getType() {
}
@Override
- public String findTool(String s) {
- return "my-path-to-java";
+ public String findTool(String toolName) {
+ return tool;
}
}
}