Skip to content

First take at upgrading Zinc #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
language: java
sudo: false # faster builds
jdk:
# - oraclejdk7
- oraclejdk8
cache:
directories:
Expand Down
32 changes: 21 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.4.7-SNAPSHOT</version>
<version>4.0.0-SNAPSHOT</version>
<packaging>maven-plugin</packaging>

<name>scala-maven-plugin</name>
Expand Down Expand Up @@ -99,8 +99,8 @@
<properties>
<encoding>UTF-8</encoding>
<github.global.server>github</github.global.server>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.reporting.version>3.0</maven.reporting.version>
<maven.version>3.3.9</maven.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down Expand Up @@ -218,10 +218,14 @@

<!-- sbt incremental compiler -->
<dependency>
<groupId>com.typesafe.zinc</groupId>
<artifactId>zinc</artifactId>
<version>0.3.15</version>
<scope>compile</scope>
<groupId>org.scala-sbt</groupId>
<artifactId>zinc_2.12</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.scala-lang.modules</groupId>
<artifactId>scala-java8-compat_2.12</artifactId>
<version>0.9.0</version>
</dependency>
</dependencies>
<repositories>
Expand Down Expand Up @@ -276,6 +280,13 @@
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
<dependencies>
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
<version>6.3</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<artifactId>maven-jxr-plugin</artifactId>
Expand Down Expand Up @@ -348,7 +359,6 @@
<version>3.8.0</version>
<configuration>
<compilerArgument>-Xlint:deprecation</compilerArgument>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
Expand Down Expand Up @@ -389,7 +399,7 @@
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java15</artifactId>
<artifactId>java18</artifactId>
<version>1.0</version>
</signature>
</configuration>
Expand Down Expand Up @@ -577,8 +587,8 @@
<properties>
<scala.version.27>2.7.7</scala.version.27>
<scala.version.28>2.8.2</scala.version.28>
<scala.version.lastrelease>2.12.6</scala.version.lastrelease>
<scala.version.next>2.12.6</scala.version.next>
<scala.version.lastrelease>2.12.8</scala.version.lastrelease>
<scala.version.next>2.12.8</scala.version.next>
<scala.compat.version>2.12</scala.compat.version>
<scala.macroparadise.version>2.10.2-SNAPSHOT</scala.macroparadise.version>
<scala.macroparadise.organisation>org.scala-lang.macro-paradise</scala.macroparadise.organisation>
Expand Down
274 changes: 118 additions & 156 deletions src/main/java/sbt_inc/SbtIncrementalCompiler.java
Original file line number Diff line number Diff line change
@@ -1,178 +1,140 @@
package sbt_inc;

import com.typesafe.zinc.Compiler;
import com.typesafe.zinc.*;
import scala.compat.java8.functionConverterImpls.*;

import org.apache.maven.plugin.logging.Log;
import org.apache.maven.toolchain.Toolchain;
import sbt.internal.inc.*;
import sbt.internal.inc.FileAnalysisStore;
import sbt.internal.inc.ScalaInstance;
import sbt.internal.inc.classpath.ClasspathUtilities;
import scala.Option;
import scala_maven_executions.MainHelper;
import util.JavaLocator;
import scala_maven.VersionNumber;
import xsbti.Logger;
import xsbti.T2;
import xsbti.compile.*;
import xsbti.compile.AnalysisStore;
import xsbti.compile.CompilerCache;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

public class SbtIncrementalCompiler {

public static final String SBT_GROUP_ID = "com.typesafe.sbt";
public static final String COMPILER_INTEGRATION_ARTIFACT_ID = "incremental-compiler";
public static final String COMPILER_INTERFACE_ARTIFACT_ID = "compiler-interface";
public static final String COMPILER_INTERFACE_CLASSIFIER = "sources";
public static final String XSBTI_ARTIFACT_ID = "sbt-interface";

private static final String ANALYSIS_MAP_ARG_SEPARATOR = ",";
private static final String ANALYSIS_MAP_PAIR_SEPARATOR = File.pathSeparator;

private Log log;

private ZincClient zinc;

private boolean useServer = false;

private File compilerJar;

private File libraryJar;

private List<File> extraJars;

private List<String> extraArgs;

private xsbti.Logger logger;

private Compiler compiler;

public SbtIncrementalCompiler(boolean useZincServer, String zincHost, int zincPort, File libraryJar, File compilerJar, List<File> extraJars, File xsbtiJar, File interfaceJar, Log l, List<String> args) throws Exception {
this.log = l;
if (useZincServer) {
this.zinc = new ZincClient(zincHost, zincPort);
if (zinc.serverAvailable()) {
l.info("Using zinc server for incremental compilation");
this.useServer = true;
this.compilerJar = compilerJar;
this.libraryJar = libraryJar;
this.extraJars = extraJars;
this.extraArgs = args;
} else {
l.warn("Zinc server is not available at port " + zincPort + " - reverting to normal incremental compile");
this.useServer = false;
public static final String SBT_GROUP_ID = "org.scala-sbt";
public static final String ZINC_ARTIFACT_ID = "zinc";
public static final String COMPILER_BRIDGE_ARTIFACT_ID = "compiler-bridge";

private final Logger logger;
private final IncrementalCompilerImpl compiler;
private final Compilers compilers;
private final Setup setup;
private final AnalysisStore analysisStore;

public SbtIncrementalCompiler(File libraryJar, File reflectJar, File compilerJar, VersionNumber scalaVersion, List<File> extraJars, File compilerBridgeJar, Log l, List<String> args, File cacheFile) throws Exception {
l.info("Using incremental compilation");
if (args.size() > 0) l.warn("extra args for zinc are ignored in non-server mode");
this.logger = new SbtLogger(l);

List<File> allJars = new ArrayList<>(extraJars);
allJars.add(libraryJar);
allJars.add(reflectJar);
allJars.add(compilerJar);

ScalaInstance scalaInstance = new ScalaInstance(
scalaVersion.toString(), // version
new URLClassLoader(new URL[]{libraryJar.toURI().toURL(), reflectJar.toURI().toURL(), compilerJar.toURI().toURL()}), // loader
ClasspathUtilities.rootLoader(), // loaderLibraryOnly
libraryJar, // libraryJar
compilerJar, // compilerJar
allJars.toArray(new File[]{}), // allJars
Option.apply(scalaVersion.toString()) // explicitActual
);

compiler = new IncrementalCompilerImpl();

AnalyzingCompiler scalaCompiler = new AnalyzingCompiler(
scalaInstance, // scalaInstance
ZincCompilerUtil.constantBridgeProvider(scalaInstance, compilerBridgeJar), //provider
ClasspathOptionsUtil.auto(), // classpathOptions
new FromJavaConsumer<>(noop -> {
}), //FIXME foo -> {}, // onArgsHandler
Option.apply(null) // classLoaderCache
);

compilers = compiler.compilers(scalaInstance, ClasspathOptionsUtil.boot(), Option.apply(null), scalaCompiler);

PerClasspathEntryLookup lookup = new PerClasspathEntryLookup() {
@Override
public Optional<CompileAnalysis> analysis(File classpathEntry) {
return Optional.empty();
}
}
if (!useServer) {
l.info("Using incremental compilation");
if (args.size() > 0) l.warn("extra args for zinc are ignored in non-server mode");
this.logger = new SbtLogger(l);
Setup setup = Setup.create(compilerJar, libraryJar, extraJars, xsbtiJar, interfaceJar, null, false);
if (l.isDebugEnabled()) Setup.debug(setup, logger);
this.compiler = Compiler.create(setup, logger);
}
}

private IncOptions defaultOptions() {
sbt.inc.IncOptions defaultSbtOptions = sbt.inc.IncOptions.Default();
return new IncOptions(
defaultSbtOptions.transitiveStep(),
defaultSbtOptions.recompileAllFraction(),
defaultSbtOptions.relationsDebug(),
defaultSbtOptions.apiDebug(),
defaultSbtOptions.apiDiffContextSize(),
defaultSbtOptions.apiDumpDirectory(),
false,
Option.<File>empty(),
defaultSbtOptions.recompileOnMacroDef(),
defaultSbtOptions.nameHashing());
}

public void compile(File baseDir, List<String> classpathElements, List<File> sources, File classesDirectory, List<String> scalacOptions, List<String> javacOptions, File cacheFile, Map<File, File> cacheMap, String compileOrder, Toolchain toolchain) throws Exception {
if (useServer) {
zincCompile(baseDir, classpathElements, sources, classesDirectory, scalacOptions, javacOptions, cacheFile, cacheMap, compileOrder, toolchain);
} else {
if (log.isDebugEnabled()) log.debug("Incremental compiler = " + compiler + " [" + Integer.toHexString(compiler.hashCode()) + "]");
List<File> classpath = pathsToFiles(classpathElements);
Inputs inputs = Inputs.create(classpath, sources, classesDirectory, scalacOptions, javacOptions, cacheFile, cacheMap, compileOrder, defaultOptions(), true);
if (log.isDebugEnabled()) Inputs.debug(inputs, logger);
compiler.compile(inputs, logger);
}
}

private void zincCompile(File baseDir, List<String> classpathElements, List<File> sources, File classesDirectory, List<String> scalacOptions, List<String> javacOptions, File cacheFile, Map<File, File> cacheMap, String compileOrder, Toolchain toolchain) throws Exception {
List<String> arguments = new ArrayList<String>(extraArgs);
arguments.add("-log-level");
arguments.add(logLevelToString(log));
arguments.add("-scala-compiler");
arguments.add(compilerJar.getAbsolutePath());
arguments.add("-scala-library");
arguments.add(libraryJar.getAbsolutePath());
arguments.add("-scala-extra");
List<String> extraPaths = new ArrayList<String>();
for (File extraJar : extraJars) {
extraPaths.add(extraJar.getAbsolutePath());
}
arguments.add(MainHelper.toMultiPath(extraPaths));
if (!classpathElements.isEmpty()) {
arguments.add("-classpath");
arguments.add(MainHelper.toMultiPath(classpathElements));
}
arguments.add("-d");
arguments.add(classesDirectory.getAbsolutePath());
for (String scalacOption : scalacOptions) {
arguments.add("-S" + scalacOption);
}

String javaHome = JavaLocator.findHomeFromToolchain(toolchain);
if (javaHome != null) {
log.info("Toolchain in scala-maven-plugin: " + javaHome);
arguments.add("-java-home");
arguments.add(javaHome);
}

for (String javacOption : javacOptions) {
arguments.add("-C" + javacOption);
}
arguments.add("-compile-order");
arguments.add(compileOrder);
arguments.add("-analysis-cache");
arguments.add(cacheFile.getAbsolutePath());
arguments.add("-analysis-map");
arguments.add(cacheMapToString(cacheMap));
for (File source : sources) {
arguments.add(source.getAbsolutePath());
}

int exitCode = zinc.run(arguments, baseDir, System.out, System.err);

if (exitCode != 0) {
xsbti.Problem[] problems = null;
throw new sbt.compiler.CompileFailed(arguments.toArray(new String[arguments.size()]), "Compile failed via zinc server", problems);
}
@Override
public DefinesClass definesClass(File classpathEntry) {
return Locate.definesClass(classpathEntry);
}
};

LoggedReporter reporter = new LoggedReporter(100, logger, pos -> pos);

analysisStore = AnalysisStore.getCachedStore(FileAnalysisStore.binary(cacheFile));

setup =
compiler.setup(
lookup, // lookup
false, // skip
cacheFile, // cacheFile
CompilerCache.fresh(), // cache
IncOptions.of(), // incOptions
reporter, // reporter
Option.apply(null), // optionProgress
new T2[]{}
);
}

private List<File> pathsToFiles(List<String> paths) {
List<File> files = new ArrayList<File>(paths.size());
for (String path : paths) {
files.add(new File(path));
public void compile(List<String> classpathElements, List<File> sources, File classesDirectory, List<String> scalacOptions, List<String> javacOptions, String compileOrder) {

Inputs inputs = compiler.inputs(
classpathElements.stream().map(File::new).toArray(size -> new File[size]), //classpath
sources.toArray(new File[]{}), // sources
classesDirectory, // classesDirectory
scalacOptions.toArray(new String[]{}), // scalacOptions
javacOptions.toArray(new String[]{}), // javacOptions
100, // maxErrors
new Function[]{}, // sourcePositionMappers
toCompileOrder(compileOrder), // order
compilers,
setup,
compiler.emptyPreviousResult()
);

Optional<AnalysisContents> analysisContents = analysisStore.get();
if (analysisContents.isPresent()) {
AnalysisContents analysisContents0 = analysisContents.get();
CompileAnalysis previousAnalysis = analysisContents0.getAnalysis();
MiniSetup previousSetup = analysisContents0.getMiniSetup();
PreviousResult previousResult = PreviousResult.of(Optional.of(previousAnalysis), Optional.of(previousSetup));
inputs = inputs.withPreviousResult(previousResult);
}
return files;
}

private String logLevelToString(Log l) {
if (l.isDebugEnabled()) return "debug";
else if (l.isInfoEnabled()) return "info";
else if (l.isWarnEnabled()) return "warn";
else if (l.isErrorEnabled()) return "error";
else return "info";
CompileResult newResult = compiler.compile(inputs, logger);
analysisStore.set(AnalysisContents.create(newResult.analysis(), newResult.setup()));
}

private String cacheMapToString(Map<File, File> cacheMap) throws Exception {
String analysisMap = "";
boolean addArgSeparator = false;
for (Map.Entry<File, File> entry : cacheMap.entrySet()) {
if (addArgSeparator) analysisMap += ANALYSIS_MAP_ARG_SEPARATOR;
analysisMap += entry.getKey().getAbsolutePath();
analysisMap += ANALYSIS_MAP_PAIR_SEPARATOR;
analysisMap += entry.getValue().getAbsolutePath();
addArgSeparator = true;
private CompileOrder toCompileOrder(String name) {
if (name.equalsIgnoreCase(CompileOrder.Mixed.name())) {
return CompileOrder.Mixed;
} else if (name.equalsIgnoreCase(CompileOrder.JavaThenScala.name())) {
return CompileOrder.JavaThenScala;
} else if (name.equalsIgnoreCase(CompileOrder.ScalaThenJava.name())) {
return CompileOrder.ScalaThenJava;
} else {
throw new IllegalArgumentException("Unknown compileOrder: " + name);
}
return analysisMap;
}
}
Loading