From aab1f18fa459eb288710940ff750276e2c5f8f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Tue, 11 Dec 2018 17:48:07 +0100 Subject: [PATCH 1/6] Translate the sbt-bridge to Java. Only the files in the Compile configuration are translated. Tests are kept in Scala. --- .../dotc/reporting/AbstractReporter.scala | 8 ++ .../dotc/reporting/ConsoleReporter.scala | 2 +- sbt-bridge/src/xsbt/CachedCompilerImpl.java | 76 +++++++++++ sbt-bridge/src/xsbt/CompilerClassLoader.java | 122 +++++++++++++++++ sbt-bridge/src/xsbt/CompilerClassLoader.scala | 104 -------------- sbt-bridge/src/xsbt/CompilerInterface.java | 43 ++++++ sbt-bridge/src/xsbt/CompilerInterface.scala | 70 ---------- sbt-bridge/src/xsbt/ConsoleInterface.java | 55 ++++++++ sbt-bridge/src/xsbt/ConsoleInterface.scala | 47 ------- sbt-bridge/src/xsbt/DelegatingReporter.java | 129 ++++++++++++++++++ sbt-bridge/src/xsbt/DelegatingReporter.scala | 73 ---------- sbt-bridge/src/xsbt/DottydocRunner.java | 88 ++++++++++++ .../src/xsbt/InterfaceCompileFailed.java | 30 ++++ sbt-bridge/src/xsbt/Problem.java | 45 ++++++ sbt-bridge/src/xsbt/Problem.scala | 12 -- sbt-bridge/src/xsbt/ScaladocInterface.java | 13 ++ sbt-bridge/src/xsbt/ScaladocInterface.scala | 46 ------- 17 files changed, 610 insertions(+), 353 deletions(-) create mode 100644 compiler/src/dotty/tools/dotc/reporting/AbstractReporter.scala create mode 100644 sbt-bridge/src/xsbt/CachedCompilerImpl.java create mode 100644 sbt-bridge/src/xsbt/CompilerClassLoader.java delete mode 100644 sbt-bridge/src/xsbt/CompilerClassLoader.scala create mode 100644 sbt-bridge/src/xsbt/CompilerInterface.java delete mode 100644 sbt-bridge/src/xsbt/CompilerInterface.scala create mode 100644 sbt-bridge/src/xsbt/ConsoleInterface.java delete mode 100644 sbt-bridge/src/xsbt/ConsoleInterface.scala create mode 100644 sbt-bridge/src/xsbt/DelegatingReporter.java delete mode 100644 sbt-bridge/src/xsbt/DelegatingReporter.scala create mode 100644 sbt-bridge/src/xsbt/DottydocRunner.java create mode 100644 sbt-bridge/src/xsbt/InterfaceCompileFailed.java create mode 100644 sbt-bridge/src/xsbt/Problem.java delete mode 100644 sbt-bridge/src/xsbt/Problem.scala create mode 100644 sbt-bridge/src/xsbt/ScaladocInterface.java delete mode 100644 sbt-bridge/src/xsbt/ScaladocInterface.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/AbstractReporter.scala b/compiler/src/dotty/tools/dotc/reporting/AbstractReporter.scala new file mode 100644 index 000000000000..630df31014f7 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/reporting/AbstractReporter.scala @@ -0,0 +1,8 @@ +package dotty.tools +package dotc +package reporting + +/** + * This class mixes in a few standard traits, so that it is easier to extend from Java. + */ +abstract class AbstractReporter extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with MessageRendering diff --git a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 4d775eaa3bc5..8eb9dda8f7b1 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -13,7 +13,7 @@ import diagnostic.messages.{ Error, ConditionalWarning } class ConsoleReporter( reader: BufferedReader = Console.in, writer: PrintWriter = new PrintWriter(Console.err, true) -) extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with MessageRendering { +) extends AbstractReporter { import MessageContainer._ diff --git a/sbt-bridge/src/xsbt/CachedCompilerImpl.java b/sbt-bridge/src/xsbt/CachedCompilerImpl.java new file mode 100644 index 000000000000..e0d8b14533e1 --- /dev/null +++ b/sbt-bridge/src/xsbt/CachedCompilerImpl.java @@ -0,0 +1,76 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt; + +import xsbti.AnalysisCallback; +import xsbti.Logger; +import xsbti.Reporter; +import xsbti.Severity; +import xsbti.compile.*; + +import java.io.File; + +import dotty.tools.dotc.core.Contexts.Context; +import dotty.tools.dotc.core.Contexts.ContextBase; +import dotty.tools.dotc.Main; +import dotty.tools.dotc.interfaces.*; + +import java.net.URLClassLoader; + +public class CachedCompilerImpl implements CachedCompiler { + private final String[] args; + private final Output output; + private final String[] outputArgs; + + public CachedCompilerImpl(String[] args, Output output) { + super(); + this.args = args; + this.output = output; + + if (!(output instanceof SingleOutput)) + throw new IllegalArgumentException("output should be a SingleOutput, was a " + output.getClass().getName()); + + this.outputArgs = + new String[] { "-d", ((SingleOutput) output).getOutputDirectory().getAbsolutePath().toString() }; + } + + public String[] commandArguments(File[] sources) { + String[] sortedSourcesAbsolute = new String[sources.length]; + for (int i = 0; i < sources.length; i++) + sortedSourcesAbsolute[i] = sources[i].getAbsolutePath(); + java.util.Arrays.sort(sortedSourcesAbsolute); + + // Concatenate outputArgs, args and sortedSourcesAbsolute + String[] result = new String[outputArgs.length + args.length + sortedSourcesAbsolute.length]; + int j = 0; + for (int i = 0; i < outputArgs.length; i++, j++) + result[j] = outputArgs[i]; + for (int i = 0; i < args.length; i++, j++) + result[j] = args[i]; + for (int i = 0; i < sortedSourcesAbsolute.length; i++, j++) + result[j] = sortedSourcesAbsolute[i]; + + return result; + } + + synchronized public void run(File[] sources, DependencyChanges changes, AnalysisCallback callback, Logger log, Reporter delegate, CompileProgress progress) { + log.debug(() -> { + String msg = "Calling Dotty compiler with arguments (CompilerInterface):"; + for (String arg : args) + msg = msg + "\n\t" + arg; + return msg; + }); + + Context ctx = new ContextBase().initialCtx().fresh() + .setSbtCallback(callback) + .setReporter(new DelegatingReporter(delegate)); + + URLClassLoader cl = (URLClassLoader) this.getClass().getClassLoader(); + + dotty.tools.dotc.reporting.Reporter reporter = Main.process(commandArguments(sources), ctx); + if (reporter.hasErrors()) { + throw new InterfaceCompileFailed(args, new Problem[0]); + } + } +} diff --git a/sbt-bridge/src/xsbt/CompilerClassLoader.java b/sbt-bridge/src/xsbt/CompilerClassLoader.java new file mode 100644 index 000000000000..ec0e32049f97 --- /dev/null +++ b/sbt-bridge/src/xsbt/CompilerClassLoader.java @@ -0,0 +1,122 @@ +package xsbt; + +import java.lang.reflect.Field; + +import java.net.URL; +import java.net.URLClassLoader; + +import java.util.WeakHashMap; + +/** + * A classloader to run the compiler + *

+ * A CompilerClassLoader is constructed from a list of `urls` that need to be on + * the classpath to run the compiler and the classloader used by sbt. + *

+ * To understand why a custom classloader is needed for the compiler, let us + * describe some alternatives that wouldn't work. + *

+ *

+ * Our solution is to implement a subclass of URLClassLoader with no parent, instead + * we override `loadClass` to load the `xsbti.*` interfaces from `sbtLoader`. + */ +public class CompilerClassLoader extends URLClassLoader { + private final ClassLoader sbtLoader; + + public CompilerClassLoader(URL[] urls, ClassLoader sbtLoader) { + super(urls, null); + this.sbtLoader = sbtLoader; + } + + @Override + public Class loadClass(String className, boolean resolve) throws ClassNotFoundException { + if (className.startsWith("xsbti.")) { + // We can't use the loadClass overload with two arguments because it's + // protected, but we can do the same by hand (the classloader instance + // from which we call resolveClass does not matter). + Class c = sbtLoader.loadClass(className); + if (resolve) + resolveClass(c); + return c; + } else { + return super.loadClass(className, resolve); + } + } + + /** + * Cache the result of `fixBridgeLoader`. + *

+ * Reusing ClassLoaders is important for warm performance since otherwise the + * JIT code cache for the compiler will be discarded between every call to + * the sbt `compile` task. + */ + private static WeakHashMap fixedLoaderCache = new WeakHashMap<>(); + + /** + * Fix the compiler bridge ClassLoader + *

+ * Soundtrack: https://www.youtube.com/watch?v=imamcajBEJs + *

+ * The classloader that we get from sbt looks like: + *

+ * URLClassLoader(bridgeURLs, + * DualLoader(scalaLoader, notXsbtiFilter, sbtLoader, xsbtiFilter)) + *

+ * DualLoader will load the `xsbti.*` interfaces using `sbtLoader` and + * everything else with `scalaLoader`. Once we have loaded the dotty Main + * class using `scalaLoader`, subsequent classes in the dotty compiler will + * also be loaded by `scalaLoader` and _not_ by the DualLoader. But the sbt + * compiler phases are part of dotty and still need access to the `xsbti.*` + * interfaces in `sbtLoader`, therefore DualLoader does not work for us + * (this issue is not present with scalac because the sbt phases are + * currently defined in the compiler bridge itself, not in scalac). + *

+ * CompilerClassLoader is a replacement for DualLoader. Until we can fix + * this in sbt proper, we need to use reflection to construct our own + * fixed classloader: + *

+ * URLClassLoader(bridgeURLs, + * CompilerClassLoader(scalaLoader.getURLs, sbtLoader)) + * + * @param bridgeLoader The classloader that sbt uses to load the compiler bridge + * @return A fixed classloader that works with dotty + */ + synchronized public static ClassLoader fixBridgeLoader(ClassLoader bridgeLoader) { + return fixedLoaderCache.computeIfAbsent(bridgeLoader, k -> computeFixedLoader(k)); + } + + private static ClassLoader computeFixedLoader(ClassLoader bridgeLoader) { + URLClassLoader urlBridgeLoader = (URLClassLoader) bridgeLoader; + ClassLoader dualLoader = urlBridgeLoader.getParent(); + Class dualLoaderClass = dualLoader.getClass(); + + try { + // DualLoader.parentA and DualLoader.parentB are private + Field parentAField = dualLoaderClass.getDeclaredField("parentA"); + parentAField.setAccessible(true); + Field parentBField = dualLoaderClass.getDeclaredField("parentB"); + parentBField.setAccessible(true); + URLClassLoader scalaLoader = (URLClassLoader) parentAField.get(dualLoader); + URLClassLoader sbtLoader = (URLClassLoader) parentBField.get(dualLoader); + + URL[] bridgeURLs = urlBridgeLoader.getURLs(); + return new URLClassLoader(bridgeURLs, + new CompilerClassLoader(scalaLoader.getURLs(), sbtLoader)); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/sbt-bridge/src/xsbt/CompilerClassLoader.scala b/sbt-bridge/src/xsbt/CompilerClassLoader.scala deleted file mode 100644 index 071141dcfac3..000000000000 --- a/sbt-bridge/src/xsbt/CompilerClassLoader.scala +++ /dev/null @@ -1,104 +0,0 @@ -package xsbt - -import java.net.{URL, URLClassLoader} - -import scala.collection.mutable - -/** A classloader to run the compiler - * - * A CompilerClassLoader is constructed from a list of `urls` that need to be on - * the classpath to run the compiler and the classloader used by sbt. - * - * To understand why a custom classloader is needed for the compiler, let us - * describe some alternatives that wouldn't work. - * - `new URLClassLoader(urls)`: - * The compiler contains sbt phases that callback to sbt using the `xsbti.*` - * interfaces. If `urls` does not contain the sbt interfaces we'll get a - * `ClassNotFoundException` in the compiler when we try to use them, if - * `urls` does contain the interfaces we'll get a `ClassCastException` or a - * `LinkageError` because if the same class is loaded by two different - * classloaders, they are considered distinct by the JVM. - * - `new URLClassLoader(urls, sbtLoader)`: - * Because of the JVM delegation model, this means that we will only load - * a class from `urls` if it's not present in the parent `sbtLoader`, but - * sbt uses its own version of the scala compiler and scala library which - * is not the one we need to run the compiler. - * - * Our solution is to implement a subclass of URLClassLoader with no parent, instead - * we override `loadClass` to load the `xsbti.*` interfaces from `sbtLoader`. - */ -class CompilerClassLoader(urls: Array[URL], sbtLoader: ClassLoader) - extends URLClassLoader(urls, null) { - override def loadClass(className: String, resolve: Boolean): Class[_] = - if (className.startsWith("xsbti.")) { - // We can't use the loadClass overload with two arguments because it's - // protected, but we can do the same by hand (the classloader instance - // from which we call resolveClass does not matter). - val c = sbtLoader.loadClass(className) - if (resolve) - resolveClass(c) - c - } else { - super.loadClass(className, resolve) - } -} - -object CompilerClassLoader { - /** Cache the result of `fixBridgeLoader`. - * - * Reusing ClassLoaders is important for warm performance since otherwise the - * JIT code cache for the compiler will be discarded between every call to - * the sbt `compile` task. - */ - private[this] val fixedLoaderCache = new mutable.WeakHashMap[ClassLoader, ClassLoader] - - /** Fix the compiler bridge ClassLoader - * - * Soundtrack: https://www.youtube.com/watch?v=imamcajBEJs - * - * The classloader that we get from sbt looks like: - * - * URLClassLoader(bridgeURLs, - * DualLoader(scalaLoader, notXsbtiFilter, sbtLoader, xsbtiFilter)) - * - * DualLoader will load the `xsbti.*` interfaces using `sbtLoader` and - * everything else with `scalaLoader`. Once we have loaded the dotty Main - * class using `scalaLoader`, subsequent classes in the dotty compiler will - * also be loaded by `scalaLoader` and _not_ by the DualLoader. But the sbt - * compiler phases are part of dotty and still need access to the `xsbti.*` - * interfaces in `sbtLoader`, therefore DualLoader does not work for us - * (this issue is not present with scalac because the sbt phases are - * currently defined in the compiler bridge itself, not in scalac). - * - * CompilerClassLoader is a replacement for DualLoader. Until we can fix - * this in sbt proper, we need to use reflection to construct our own - * fixed classloader: - * - * URLClassLoader(bridgeURLs, - * CompilerClassLoader(scalaLoader.getURLs, sbtLoader)) - * - * @param bridgeLoader The classloader that sbt uses to load the compiler bridge - * @return A fixed classloader that works with dotty - */ - def fixBridgeLoader(bridgeLoader: ClassLoader): ClassLoader = synchronized { - fixedLoaderCache.getOrElseUpdate(bridgeLoader, computeFixedLoader(bridgeLoader)) - } - - private[this] def computeFixedLoader(bridgeLoader: ClassLoader) = bridgeLoader match { - case bridgeLoader: URLClassLoader => - val dualLoader = bridgeLoader.getParent - val dualLoaderClass = dualLoader.getClass - - // DualLoader#parentA and DualLoader#parentB are private - val parentAField = dualLoaderClass.getDeclaredField("parentA") - parentAField.setAccessible(true) - val parentBField = dualLoaderClass.getDeclaredField("parentB") - parentBField.setAccessible(true) - val scalaLoader = parentAField.get(dualLoader).asInstanceOf[URLClassLoader] - val sbtLoader = parentBField.get(dualLoader).asInstanceOf[URLClassLoader] - - val bridgeURLs = bridgeLoader.getURLs - new URLClassLoader(bridgeURLs, - new CompilerClassLoader(scalaLoader.getURLs, sbtLoader)) - } -} diff --git a/sbt-bridge/src/xsbt/CompilerInterface.java b/sbt-bridge/src/xsbt/CompilerInterface.java new file mode 100644 index 000000000000..10b90adbb0e3 --- /dev/null +++ b/sbt-bridge/src/xsbt/CompilerInterface.java @@ -0,0 +1,43 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt; + +import xsbti.AnalysisCallback; +import xsbti.Logger; +import xsbti.Reporter; +import xsbti.Severity; +import xsbti.compile.*; + +import java.io.File; + +import dotty.tools.dotc.core.Contexts.ContextBase; +import dotty.tools.dotc.Main; +import dotty.tools.dotc.interfaces.*; + +import java.lang.reflect.InvocationTargetException; +import java.net.URLClassLoader; + +public final class CompilerInterface { + public CachedCompiler newCompiler(String[] options, Output output, Logger initialLog, Reporter initialDelegate) { + // The classloader that sbt uses to load the compiler bridge is broken + // (see CompilerClassLoader#fixBridgeLoader for details). To workaround + // this we construct our own ClassLoader and then run the following code + // with it: + // new CachedCompilerImpl(options, output) + + try { + ClassLoader bridgeLoader = this.getClass().getClassLoader(); + ClassLoader fixedLoader = CompilerClassLoader.fixBridgeLoader(bridgeLoader); + Class cciClass = fixedLoader.loadClass("xsbt.CachedCompilerImpl"); + return (CachedCompiler) cciClass.getConstructors()[0].newInstance(options, output); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public void run(File[] sources, DependencyChanges changes, AnalysisCallback callback, Logger log, + Reporter delegate, CompileProgress progress, CachedCompiler cached) { + cached.run(sources, changes, callback, log, delegate, progress); + } +} diff --git a/sbt-bridge/src/xsbt/CompilerInterface.scala b/sbt-bridge/src/xsbt/CompilerInterface.scala deleted file mode 100644 index ac828b996957..000000000000 --- a/sbt-bridge/src/xsbt/CompilerInterface.scala +++ /dev/null @@ -1,70 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -import xsbti.{ AnalysisCallback, Logger, Reporter, Severity } -import xsbti.compile._ -import java.io.File - -import dotty.tools.dotc.core.Contexts.ContextBase -import dotty.tools.dotc.{ Main => DottyMain } -import dotty.tools.dotc.interfaces._ - -import java.net.URLClassLoader - -final class CompilerInterface { - def newCompiler(options: Array[String], output: Output, initialLog: xsbti.Logger, - initialDelegate: xsbti.Reporter): CachedCompiler = { - // The classloader that sbt uses to load the compiler bridge is broken - // (see CompilerClassLoader#fixBridgeLoader for details). To workaround - // this we construct our own ClassLoader and then run the following code - // with it: - // new CachedCompilerImpl(options, output) - - val bridgeLoader = getClass.getClassLoader - val fixedLoader = CompilerClassLoader.fixBridgeLoader(bridgeLoader) - val cciClass = fixedLoader.loadClass("xsbt.CachedCompilerImpl") - cciClass.getConstructors.head - .newInstance(options, output) - .asInstanceOf[CachedCompiler] - } - - def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, - delegate: Reporter, progress: CompileProgress, cached: CachedCompiler): Unit = - cached.run(sources, changes, callback, log, delegate, progress) -} - -class CachedCompilerImpl(args: Array[String], output: Output) extends CachedCompiler { - val outputArgs = - output match { - case multi: MultipleOutput => - ??? - case single: SingleOutput => - List("-d", single.getOutputDirectory.getAbsolutePath.toString) - } - - def commandArguments(sources: Array[File]): Array[String] = - (outputArgs ++ args.toList ++ sources.map(_.getAbsolutePath).sortWith(_ < _)).toArray[String] - - def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, progress: CompileProgress): Unit = synchronized { - run(sources.toList, changes, callback, log, delegate, progress) - } - private[this] def run(sources: List[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, compileProgress: CompileProgress): Unit = { - log.debug(() => args.mkString("Calling Dotty compiler with arguments (CompilerInterface):\n\t", "\n\t", "")) - val ctx = (new ContextBase).initialCtx.fresh - .setSbtCallback(callback) - .setReporter(new DelegatingReporter(delegate)) - - val cl = getClass.getClassLoader.asInstanceOf[URLClassLoader] - - val reporter = DottyMain.process(commandArguments(sources.toArray), ctx) - if (reporter.hasErrors) { - throw new InterfaceCompileFailed(args, Array()) - } - } -} - -class InterfaceCompileFailed(override val arguments: Array[String], override val problems: Array[xsbti.Problem]) extends xsbti.CompileFailed { - override val toString = "Compilation failed" -} diff --git a/sbt-bridge/src/xsbt/ConsoleInterface.java b/sbt-bridge/src/xsbt/ConsoleInterface.java new file mode 100644 index 000000000000..3467e6abc226 --- /dev/null +++ b/sbt-bridge/src/xsbt/ConsoleInterface.java @@ -0,0 +1,55 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt; + +import java.util.ArrayList; + +import scala.Some; + +import xsbti.Logger; + +import dotty.tools.dotc.core.Contexts.Context; +import dotty.tools.repl.ReplDriver; +import dotty.tools.repl.State; + +public class ConsoleInterface { + public String[] commandArguments(String[] args, String bootClasspathString, String classpathString, Logger log) { + return args; + } + + public void run( + String[] args, + String bootClasspathString, + String classpathString, + String initialCommands, + String cleanupCommands, + ClassLoader loader, + String[] bindNames, + Object[] bindValues, + Logger log + ) { + ArrayList completeArgsList = new ArrayList<>(); + for (String arg : args) + completeArgsList.add(arg); + if (!bootClasspathString.isEmpty()) { + completeArgsList.add("-bootclasspath"); + completeArgsList.add(bootClasspathString); + } + completeArgsList.add("-classpath"); + completeArgsList.add(classpathString); + String[] completeArgs = completeArgsList.toArray(args); + + ReplDriver driver = new ReplDriver(completeArgs, System.out, Some.apply(loader)); + + State state = driver.initialState(); + assert bindNames.length == bindValues.length; + for (int i = 0; i < bindNames.length; i++) + state = driver.bind(bindNames[i], bindValues[i], state); + + state = driver.run(initialCommands, state); + // TODO handle failure during initialisation + state = driver.runUntilQuit(state); + driver.run(cleanupCommands, state); + } +} diff --git a/sbt-bridge/src/xsbt/ConsoleInterface.scala b/sbt-bridge/src/xsbt/ConsoleInterface.scala deleted file mode 100644 index 34004528fea4..000000000000 --- a/sbt-bridge/src/xsbt/ConsoleInterface.scala +++ /dev/null @@ -1,47 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -import xsbti.Logger - -import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.repl.ReplDriver - -class ConsoleInterface { - def commandArguments( - args: Array[String], - bootClasspathString: String, - classpathString: String, - log: Logger - ): Array[String] = args - - def run(args: Array[String], - bootClasspathString: String, - classpathString: String, - initialCommands: String, - cleanupCommands: String, - loader: ClassLoader, - bindNames: Array[String], - bindValues: Array[Any], - log: Logger - ): Unit = { - val completeArgs = - args ++ { - if (bootClasspathString.isEmpty) Array.empty[String] - else Array("-bootclasspath", bootClasspathString) - } ++ - Array("-classpath", classpathString) - - val driver = new ReplDriver(completeArgs, classLoader = Some(loader)) - - val s0 = (bindNames, bindValues).zipped.foldLeft(driver.initialState) { - case (state, (name, value)) => driver.bind(name, value)(state) - } - - val s1 = driver.run(initialCommands)(s0) - // TODO handle failure during initialisation - val s2 = driver.runUntilQuit(s1) - driver.run(cleanupCommands)(s2) - } -} diff --git a/sbt-bridge/src/xsbt/DelegatingReporter.java b/sbt-bridge/src/xsbt/DelegatingReporter.java new file mode 100644 index 000000000000..98671a9aff24 --- /dev/null +++ b/sbt-bridge/src/xsbt/DelegatingReporter.java @@ -0,0 +1,129 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt; + +import java.util.Optional; + +import xsbti.Position; +import xsbti.Severity; + +import dotty.tools.*; +import dotty.tools.dotc.*; +import dotty.tools.dotc.interfaces.Diagnostic; +import dotty.tools.dotc.util.SourceFile; +import dotty.tools.dotc.util.SourcePosition; +import dotty.tools.dotc.reporting.*; +import dotty.tools.dotc.reporting.diagnostic.Message; +import dotty.tools.dotc.reporting.diagnostic.MessageContainer; +import dotty.tools.dotc.reporting.diagnostic.messages; +import dotty.tools.dotc.core.Contexts.*; + +import static dotty.tools.dotc.reporting.diagnostic.MessageContainer.*; + +final public class DelegatingReporter extends AbstractReporter { + private final xsbti.Reporter delegate; + + private static final Position noPosition = new Position() { + public Optional sourceFile() { + return Optional.empty(); + } + public Optional sourcePath() { + return Optional.empty(); + } + public Optional line() { + return Optional.empty(); + } + public String lineContent() { + return ""; + } + public Optional offset() { + return Optional.empty(); + } + public Optional pointer() { + return Optional.empty(); + } + public Optional pointerSpace() { + return Optional.empty(); + } + }; + + public DelegatingReporter(xsbti.Reporter delegate) { + super(); + this.delegate = delegate; + } + + @Override + public void printSummary(Context ctx) { + delegate.printSummary(); + } + + public void doReport(MessageContainer cont, Context ctx) { + Severity severity; + switch (cont.level()) { + case Diagnostic.ERROR: + severity = Severity.Error; + break; + case Diagnostic.WARNING: + severity = Severity.Warn; + break; + case Diagnostic.INFO: + severity = Severity.Info; + break; + default: + throw new IllegalArgumentException("Bad diagnostic level: " + cont.level()); + } + + Position position; + if (cont.pos().exists()) { + SourcePosition pos = cont.pos(); + SourceFile src = pos.source(); + position = new Position() { + public Optional sourceFile() { + return Optional.ofNullable(src.file().file()); + } + public Optional sourcePath() { + return Optional.ofNullable(src.file().path()); + } + public Optional line() { + return Optional.of(pos.line()); + } + public String lineContent() { + String line = pos.lineContent(); + if (line.endsWith("\r\n")) + return line.substring(0, line.length() - 2); + else if (line.endsWith("\n") || line.endsWith("\u000c")) + return line.substring(0, line.length() - 1); + else + return line; + } + public Optional offset() { + return Optional.of(pos.point()); + } + public Optional pointer() { + return Optional.of(pos.point() - src.startOfLine(pos.point())); + } + public Optional pointerSpace() { + String lineContent = this.lineContent(); + int pointer = this.pointer().get(); + StringBuilder result = new StringBuilder(); + for (int i = 0; i < pointer; i++) + result.append(lineContent.charAt(i) == '\t' ? '\t' : ' '); + return Optional.of(result.toString()); + } + }; + } else { + position = noPosition; + } + + Message message = cont.contained(); + StringBuilder rendered = new StringBuilder(); + rendered.append(messageAndPos(message, cont.pos(), diagnosticLevel(cont), ctx)); + boolean shouldExplain = new MessageContainer.MessageContext(ctx).shouldExplain(cont); + if (shouldExplain && !message.explanation().isEmpty()) { + rendered.append(explanation(message, ctx)); + } + + delegate.log(new Problem(position, message.msg(), severity, rendered.toString())); + } +} diff --git a/sbt-bridge/src/xsbt/DelegatingReporter.scala b/sbt-bridge/src/xsbt/DelegatingReporter.scala deleted file mode 100644 index d97af019837d..000000000000 --- a/sbt-bridge/src/xsbt/DelegatingReporter.scala +++ /dev/null @@ -1,73 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -import dotty.tools._ -import dotc._ -import reporting._ -import reporting.diagnostic.MessageContainer -import reporting.diagnostic.messages -import core.Contexts._ -import xsbti.{Position, Severity} -import java.util.Optional - -final class DelegatingReporter(delegate: xsbti.Reporter) extends Reporter - with UniqueMessagePositions - with HideNonSensicalMessages - with MessageRendering { - import MessageContainer._ - - override def printSummary(implicit ctx: Context): Unit = delegate.printSummary() - - def doReport(cont: MessageContainer)(implicit ctx: Context): Unit = { - val severity = - cont match { - case _: messages.Error => Severity.Error - case _: messages.Warning => Severity.Warn - case _ => Severity.Info - } - - val position = - if (cont.pos.exists) { - val pos = cont.pos - val src = pos.source - new Position { - val sourceFile: Optional[java.io.File] = maybe(Option(src.file.file)) - val sourcePath: Optional[String] = maybe(Option(src.file.path)) - val line: Optional[Integer] = Optional.of(pos.line) - val lineContent: String = pos.lineContent.stripLineEnd - val offset: Optional[Integer] = Optional.of(pos.point) - val pointer: Optional[Integer] = Optional.of(pos.point - src.startOfLine(pos.point)) - val pointerSpace: Optional[String] = Optional.of( - ((lineContent: Seq[Char]).take(pointer.get).map { case '\t' => '\t'; case x => ' ' }).mkString - ) - } - } else - noPosition - - val message = cont.contained() - val rendered = new StringBuilder() - rendered.append(messageAndPos(message, cont.pos, diagnosticLevel(cont))) - if (ctx.shouldExplain(cont) && message.explanation.nonEmpty) { - rendered.append(explanation(message)) - } - - delegate.log(Problem(position, message.msg, severity, rendered.toString)) - } - - private[this] def maybe[T](opt: Option[T]): Optional[T] = opt match { - case None => Optional.empty[T] - case Some(s) => Optional.of[T](s) - } - - private[this] val noPosition = new Position { - val line: Optional[Integer] = Optional.empty[Integer] - val lineContent: String = "" - val offset: Optional[Integer] = Optional.empty[Integer] - val pointer: Optional[Integer] = Optional.empty[Integer] - val pointerSpace: Optional[String] = Optional.empty[String] - val sourceFile: Optional[java.io.File] = Optional.empty[java.io.File] - val sourcePath: Optional[String] = Optional.empty[String] - } -} diff --git a/sbt-bridge/src/xsbt/DottydocRunner.java b/sbt-bridge/src/xsbt/DottydocRunner.java new file mode 100644 index 000000000000..48883ab13e3c --- /dev/null +++ b/sbt-bridge/src/xsbt/DottydocRunner.java @@ -0,0 +1,88 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt; + +import xsbti.Logger; +import xsbti.Severity; + +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.ArrayList; + +import dotty.tools.dotc.core.Contexts.Context; +import dotty.tools.dotc.core.Contexts.ContextBase; +import dotty.tools.dotc.reporting.Reporter; + +public class DottydocRunner { + private final String[] args0; + private final Logger log; + private final xsbti.Reporter delegate; + + public DottydocRunner(String[] args0, Logger log, xsbti.Reporter delegate) { + super(); + this.args0 = args0; + this.log = log; + this.delegate = delegate; + } + + public void run() { + log.debug(() -> { + StringBuilder msg = + new StringBuilder("Calling Dottydoc with arguments (ScaladocInterface):"); + for (String arg : args0) { + msg.append("\n\t"); + msg.append(arg); + } + return msg.toString(); + }); + + // When running with `-from-tasty`, remove the source files from arg list. + String[] args; + boolean fromTasty = false; + for (String arg : args0) { + if ("-from-tasty".equals(arg)) { + fromTasty = true; + break; + } + } + if (fromTasty) { + ArrayList excluded = new ArrayList<>(args0.length); + ArrayList retained = new ArrayList<>(args0.length); + for (String arg : args0) { + if ((arg.endsWith(".scala") || arg.endsWith(".java")) && Files.exists(Paths.get(arg))) + excluded.add(arg); + else + retained.add(arg); + } + log.debug(() -> { + StringBuilder msg = + new StringBuilder("Running `-from-tasty`, excluding source files:"); + for (String arg : excluded) { + msg.append("\n\t"); + msg.append(arg); + } + return msg.toString(); + }); + args = retained.toArray(args0); + } else { + args = args0; + } + + Context ctx = new ContextBase().initialCtx().fresh() + .setReporter(new DelegatingReporter(delegate)); + + try { + Class dottydocMainClass = Class.forName("dotty.tools.dottydoc.Main"); + Method processMethod = dottydocMainClass.getMethod("process", args.getClass(), Context.class); // args.getClass() is String[] + Reporter reporter = (Reporter) processMethod.invoke(null, args, ctx); + if (reporter.hasErrors()) + throw new InterfaceCompileFailed(args, new xsbti.Problem[0]); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } +} diff --git a/sbt-bridge/src/xsbt/InterfaceCompileFailed.java b/sbt-bridge/src/xsbt/InterfaceCompileFailed.java new file mode 100644 index 000000000000..1bc8056b053d --- /dev/null +++ b/sbt-bridge/src/xsbt/InterfaceCompileFailed.java @@ -0,0 +1,30 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt; + +import xsbti.Problem; + +public class InterfaceCompileFailed extends xsbti.CompileFailed { + private final String[] _arguments; + private final Problem[] _problems; + + public InterfaceCompileFailed(String[] arguments, Problem[] problems) { + super(); + this._arguments = arguments; + this._problems = problems; + } + + public String[] arguments() { + return _arguments; + } + + public Problem[] problems() { + return _problems; + } + + @Override + public String toString() { + return "Compilation failed"; + } +} diff --git a/sbt-bridge/src/xsbt/Problem.java b/sbt-bridge/src/xsbt/Problem.java new file mode 100644 index 000000000000..7594476a29cf --- /dev/null +++ b/sbt-bridge/src/xsbt/Problem.java @@ -0,0 +1,45 @@ +package xsbt; + +import java.util.Optional; +import xsbti.Position; +import xsbti.Severity; + +final public class Problem implements xsbti.Problem { + private final Position _position; + private final String _message; + private final Severity _severity; + private final Optional _rendered; + + public Problem(Position position, String message, Severity severity, String rendered) { + super(); + this._position = position; + this._message = message; + this._severity = severity; + this._rendered = Optional.of(rendered); + } + + public String category() { + return ""; + } + + public Position position() { + return _position; + } + + public String message() { + return _message; + } + + public Severity severity() { + return _severity; + } + + public Optional rendered() { + return _rendered; + } + + @Override + public String toString() { + return "Problem(" + _position + ", " + _message + ", " + _severity + ", " + _rendered + ")"; + } +} diff --git a/sbt-bridge/src/xsbt/Problem.scala b/sbt-bridge/src/xsbt/Problem.scala deleted file mode 100644 index 991dbc2bf308..000000000000 --- a/sbt-bridge/src/xsbt/Problem.scala +++ /dev/null @@ -1,12 +0,0 @@ -package xsbt - -import java.util.Optional -import xsbti.{Position, Severity} - -final case class Problem(override val position: Position, - override val message: String, - override val severity: Severity, - rendered0: String) extends xsbti.Problem { - override val category = "" - override val rendered = Optional.of(rendered0) -} diff --git a/sbt-bridge/src/xsbt/ScaladocInterface.java b/sbt-bridge/src/xsbt/ScaladocInterface.java new file mode 100644 index 000000000000..7b47a7feb1aa --- /dev/null +++ b/sbt-bridge/src/xsbt/ScaladocInterface.java @@ -0,0 +1,13 @@ +/* sbt -- Simple Build Tool + * Copyright 2008, 2009 Mark Harrah + */ +package xsbt; + +import xsbti.Logger; +import xsbti.Reporter; + +public class ScaladocInterface { + public void run(String[] args, Logger log, xsbti.Reporter delegate) { + new DottydocRunner(args, log, delegate).run(); + } +} diff --git a/sbt-bridge/src/xsbt/ScaladocInterface.scala b/sbt-bridge/src/xsbt/ScaladocInterface.scala deleted file mode 100644 index 09e785f3c4a6..000000000000 --- a/sbt-bridge/src/xsbt/ScaladocInterface.scala +++ /dev/null @@ -1,46 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -import xsbti.{ Logger, Severity } -import java.net.URL -import java.util.Optional -import java.nio.file.{Files, Paths} - -import dotty.tools.dotc.core.Contexts.{ Context, ContextBase } -import dotty.tools.dotc.reporting.Reporter - -class ScaladocInterface { - def run(args: Array[String], log: Logger, delegate: xsbti.Reporter) = { - new DottydocRunner(args, log, delegate).run() - } -} - -class DottydocRunner(args0: Array[String], log: Logger, delegate: xsbti.Reporter) { - def run(): Unit = { - log.debug(() => args0.mkString("Calling Dottydoc with arguments (ScaladocInterface):\n\t", "\n\t", "")) - - val args = { - // When running with `-from-tasty`, remove the source files from arg list. - if (args0.contains("-from-tasty")) { - val (excluded, retained) = - args0.partition { arg => - (arg.endsWith(".scala") || arg.endsWith(".java")) && Files.exists(Paths.get(arg)) - } - log.debug(() => excluded.mkString("Running `-from-tasty`, excluding source files:\n\t", "\n\t", "")) - retained - } else args0 - } - - val ctx = (new ContextBase).initialCtx.fresh - .setReporter(new DelegatingReporter(delegate)) - - val dottydocMainClass = Class.forName("dotty.tools.dottydoc.Main") - val processMethod = dottydocMainClass.getMethod("process", classOf[Array[String]], classOf[Context]) - val reporter = processMethod.invoke(null, args, ctx).asInstanceOf[Reporter] - if (reporter.hasErrors) { - throw new InterfaceCompileFailed(args, Array()) - } - } -} From 22f21c4fe7af143ba133d34b5ae1bf523f350813 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sat, 19 Jan 2019 19:01:21 +0100 Subject: [PATCH 2/6] Install the sbt bridge from a binary jar instead of from sources Normally, the source of the sbt bridge is fetched from scalaCompilerBridgeSource, compiled, then cached by sbt. Unfortunately the logic in sbt to do this does not take .java source files into account, so the previous commit broke our bridge. Thankfully, it turns out that I have amazing foresight ;). In https://github.com/sbt/sbt/pull/4332 I added scalaCompilerBridgeBinaryJar to sbt, which bypasses the whole bridge compilation and caching logic which is not needed when the bridge is Java-only and thus binary-compatible across Scala releases. So just using this setting is enough to make everything work! --- project/Build.scala | 22 ++++--------- .../dotty/tools/sbtplugin/DottyPlugin.scala | 31 ++++++++++++------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 67882cb4f2b7..df9a6c20dcb0 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -226,17 +226,9 @@ object Build { version := dottyVersion, scalaVersion := dottyNonBootstrappedVersion, - // Avoid having to run `dotty-sbt-bridge/publishLocal` before compiling a bootstrapped project - scalaCompilerBridgeSource := - (dottyOrganization %% "dotty-sbt-bridge" % dottyVersion) - .artifacts(Artifact.sources("dotty-sbt-bridge").withUrl( - // We cannot use the `packageSrc` task because a setting cannot depend - // on a task. Instead, we make `compile` below depend on the bridge `packageSrc` - Some((artifactPath in (`dotty-sbt-bridge`, Compile, packageSrc)).value.toURI.toURL))), - compile in Compile := (compile in Compile) - .dependsOn(packageSrc in (`dotty-sbt-bridge`, Compile)) - .dependsOn(compile in (`dotty-sbt-bridge`, Compile)) - .value, + scalaCompilerBridgeBinaryJar := { + Some((packageBin in (`dotty-sbt-bridge`, Compile)).value) + }, // Use the same name as the non-bootstrapped projects for the artifacts moduleName ~= { _.stripSuffix("-bootstrapped") }, @@ -830,12 +822,10 @@ object Build { Dependencies.`compiler-interface` % Provided, (Dependencies.`zinc-api-info` % Test).withDottyCompat(scalaVersion.value) ), - // The sources should be published with crossPaths := false since they - // need to be compiled by the project using the bridge. - crossPaths := false, - // Don't publish any binaries for the bridge because of the above - publishArtifact in (Compile, packageBin) := false, + // sources are Java-only, tests are in Scala + crossPaths in Compile := false, + autoScalaLibrary in Compile := false, fork in Test := true, parallelExecution in Test := false diff --git a/sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala b/sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala index fcd52a3ff815..593867b58b31 100644 --- a/sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala +++ b/sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala @@ -163,14 +163,21 @@ object DottyPlugin extends AutoPlugin { inc }, - scalaCompilerBridgeSource := { - val scalaBridge = scalaCompilerBridgeSource.value - val dottyBridge = (scalaOrganization.value % "dotty-sbt-bridge" % scalaVersion.value).withConfigurations(Some(Configurations.Compile.name)).sources() - if (isDotty.value) - dottyBridge - else - scalaBridge - }, + scalaCompilerBridgeBinaryJar := Def.taskDyn { + if (isDotty.value) Def.task { + val dottyBridgeArtifacts = fetchArtifactsOf("dotty-sbt-bridge", CrossVersion.disabled).value + val jars = dottyBridgeArtifacts.filter(art => art.getName.startsWith("dotty-sbt-bridge") && art.getName.endsWith(".jar")).toArray + if (jars.size == 0) + throw new MessageOnlyException("No jar found for dotty-sbt-bridge") + else if (jars.size > 1) + throw new MessageOnlyException(s"Multiple jars found for dotty-sbt-bridge: ${jars.toList}") + else + jars.headOption + } + else Def.task { + None: Option[File] + } + }.value, // Needed for RCs publishing scalaBinaryVersion := { @@ -184,7 +191,7 @@ object DottyPlugin extends AutoPlugin { val si = scalaInstance.value if (isDotty.value) { Def.task { - val dottydocArtifacts = fetchArtifactsOf("dotty-doc").value + val dottydocArtifacts = fetchArtifactsOf("dotty-doc", CrossVersion.binary).value val includeArtifact = (f: File) => f.getName.endsWith(".jar") val dottydocJars = dottydocArtifacts.filter(includeArtifact).toArray val allJars = (si.allJars ++ dottydocJars).distinct @@ -229,15 +236,15 @@ object DottyPlugin extends AutoPlugin { scalacOptions += "-from-tasty" )) - /** Fetch artefacts for scalaOrganization.value %% moduleName % scalaVersion.value */ - private def fetchArtifactsOf(moduleName: String) = Def.task { + /** Fetch artifacts for scalaOrganization.value %% moduleName % scalaVersion.value */ + private def fetchArtifactsOf(moduleName: String, crossVersion: CrossVersion) = Def.task { val dependencyResolution = Keys.dependencyResolution.value val log = streams.value.log val scalaInfo = scalaModuleInfo.value val updateConfiguration = Keys.updateConfiguration.value val warningConfiguration = (unresolvedWarningConfiguration in update).value - val moduleID = (scalaOrganization.value %% moduleName % scalaVersion.value).cross(CrossVersion.binary) + val moduleID = (scalaOrganization.value % moduleName % scalaVersion.value).cross(crossVersion) val descriptor = dependencyResolution.wrapDependencyInModule(moduleID, scalaInfo) dependencyResolution.update(descriptor, updateConfiguration, warningConfiguration, log) match { From 0685e50d864aa99a05cd5834ce419f318f00dace Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Tue, 22 Jan 2019 23:07:11 +0100 Subject: [PATCH 3/6] Get rid of dotty-sbt-bridge-bootstrapped Not needed now that the project is Java-only. --- build.sbt | 1 - project/Build.scala | 106 ++++++++++++++++++++------------------------ 2 files changed, 49 insertions(+), 58 deletions(-) diff --git a/build.sbt b/build.sbt index eb222f5d9ffa..ddb2d0273300 100644 --- a/build.sbt +++ b/build.sbt @@ -8,7 +8,6 @@ val `dotty-compiler-bootstrapped` = Build.`dotty-compiler-bootstrapped` val `dotty-library` = Build.`dotty-library` val `dotty-library-bootstrapped` = Build.`dotty-library-bootstrapped` val `dotty-sbt-bridge` = Build.`dotty-sbt-bridge` -val `dotty-sbt-bridge-bootstrapped` = Build.`dotty-sbt-bridge-bootstrapped` val `dotty-language-server` = Build.`dotty-language-server` val `dotty-bench` = Build.`dotty-bench` val `dotty-bench-bootstrapped` = Build.`dotty-bench-bootstrapped` diff --git a/project/Build.scala b/project/Build.scala index df9a6c20dcb0..464abd4aca44 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -134,7 +134,7 @@ object Build { "-language:existentials,higherKinds,implicitConversions" ), - javacOptions ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"), + javacOptions in (Compile, compile) ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"), // Change this to true if you want to bootstrap using a published non-bootstrapped compiler bootstrapFromPublishedJars := false, @@ -209,10 +209,14 @@ object Build { testOptions in Test += Tests.Argument(TestFrameworks.JUnit, "-a", "-v") ) - // Settings used for projects compiled only with Scala 2 - lazy val commonScala2Settings = commonSettings ++ Seq( + // Settings used for projects compiled only with Java + lazy val commonJavaSettings = commonSettings ++ Seq( version := dottyVersion, - scalaVersion := scalacVersion + scalaVersion := scalacVersion, + // Do not append Scala versions to the generated artifacts + crossPaths := false, + // Do not depend on the Scala library + autoScalaLibrary := false ) // Settings used when compiling dotty using Scala 2 @@ -351,13 +355,6 @@ object Build { // currently refers to dotty in its scripted task and "aggregate" does not take by-name // parameters: https://github.com/sbt/sbt/issues/2200 lazy val dottySbtBridgeRef = LocalProject("dotty-sbt-bridge") - // Same thing for the bootstrapped version - lazy val dottySbtBridgeBootstrappedRef = LocalProject("dotty-sbt-bridge-bootstrapped") - - def dottySbtBridgeReference(implicit mode: Mode): LocalProject = mode match { - case NonBootstrapped => dottySbtBridgeRef - case _ => dottySbtBridgeBootstrappedRef - } // The root project: // - aggregates other projects so that "compile", "test", etc are run on all projects at once. @@ -367,15 +364,7 @@ object Build { lazy val `dotty-bootstrapped` = project.asDottyRoot(Bootstrapped) lazy val `dotty-interfaces` = project.in(file("interfaces")). - settings(commonScala2Settings). // Java-only project, so this is fine - settings( - // Do not append Scala versions to the generated artifacts - crossPaths := false, - // Do not depend on the Scala library - autoScalaLibrary := false, - //Remove javac invalid options in Compile doc - javacOptions in (Compile, doc) --= Seq("-Xlint:unchecked", "-Xlint:deprecation") - ) + settings(commonJavaSettings) private lazy val dottydocClasspath = Def.task { val jars = (packageAll in `dotty-compiler`).value @@ -790,18 +779,6 @@ object Build { case Bootstrapped => `dotty-library-bootstrapped` } - // until sbt/sbt#2402 is fixed (https://github.com/sbt/sbt/issues/2402) - lazy val cleanSbtBridge = TaskKey[Unit]("cleanSbtBridge", "delete dotty-sbt-bridge cache") - - def cleanSbtBridgeImpl(): Unit = { - val home = System.getProperty("user.home") - val sbtOrg = "org.scala-sbt" - val bridgePattern = s"*dotty-sbt-bridge*$dottyVersion*" - - IO.delete((file(home) / ".sbt" / "1.0" / "zinc" / sbtOrg * bridgePattern).get) - IO.delete((file(home) / ".sbt" / "boot" * "scala-*" / sbtOrg / "sbt" * "*" * bridgePattern).get) - } - lazy val dottySbtBridgeSettings = Seq( cleanSbtBridge := { cleanSbtBridgeImpl() @@ -831,24 +808,44 @@ object Build { parallelExecution in Test := false ) - lazy val `dotty-sbt-bridge` = project.in(file("sbt-bridge")).asDottySbtBridge(NonBootstrapped) - lazy val `dotty-sbt-bridge-bootstrapped` = project.in(file("sbt-bridge")).asDottySbtBridge(Bootstrapped) - .settings( - // Tweak -Yscala2-unpickler to allow some sbt dependencies used in tests - /* - scalacOptions in Test := { - val oldOptions = (scalacOptions in Test).value - val i = oldOptions.indexOf("-Yscala2-unpickler") - assert(i != -1) - val oldValue = oldOptions(i + 1) - - val attList = (dependencyClasspath in Test).value - val sbtIo = findLib(attList, "org.scala-sbt/io") - val zincApiInfo = findLib(attList, "zinc-apiinfo") - - oldOptions.updated(i + 1, s"$sbtIo:$zincApiInfo:$oldValue") - } - */ + // Needed until https://github.com/sbt/sbt/issues/2402 is fixed. + lazy val cleanSbtBridge = TaskKey[Unit]("cleanSbtBridge", "delete dotty-sbt-bridge cache") + + def cleanSbtBridgeImpl(): Unit = { + val home = System.getProperty("user.home") + val sbtOrg = "org.scala-sbt" + val bridgePattern = s"*dotty-sbt-bridge*$dottyVersion*" + + IO.delete((file(home) / ".sbt" / "1.0" / "zinc" / sbtOrg * bridgePattern).get) + IO.delete((file(home) / ".sbt" / "boot" * "scala-*" / sbtOrg / "sbt" * "*" * bridgePattern).get) + } + + lazy val `dotty-sbt-bridge` = project.in(file("sbt-bridge")). + dependsOn(dottyCompiler(NonBootstrapped) % Provided). + dependsOn(dottyDoc(NonBootstrapped) % Provided). + settings(commonJavaSettings). + settings( + cleanSbtBridge := { + cleanSbtBridgeImpl() + }, + compile in Compile := { + val log = streams.value.log + val prev = (previousCompile in Compile).value.analysis.orElse(null) + val cur = (compile in Compile).value + if (prev != cur) { + log.info("Cleaning the dotty-sbt-bridge cache because it was recompiled.") + cleanSbtBridgeImpl() + } + cur + }, + description := "sbt compiler bridge for Dotty", + libraryDependencies ++= Seq( + Dependencies.`compiler-interface` % Provided, + (Dependencies.`zinc-api-info` % Test).withDottyCompat(scalaVersion.value) + ), + + fork in Test := true, + parallelExecution in Test := false ) lazy val `dotty-language-server` = project.in(file("language-server")). @@ -1007,7 +1004,7 @@ object Build { scriptedLaunchOpts ++= ivyPaths.value.ivyHome.map("-Dsbt.ivy.home=" + _.getAbsolutePath).toList, scriptedBufferLog := true, scripted := scripted.dependsOn( - publishLocal in `dotty-sbt-bridge-bootstrapped`, + publishLocal in `dotty-sbt-bridge`, publishLocal in `dotty-interfaces`, publishLocal in `dotty-compiler-bootstrapped`, publishLocal in `dotty-library-bootstrapped`, @@ -1275,7 +1272,7 @@ object Build { // FIXME: we do not aggregate `bin` because its tests delete jars, thus breaking other tests def asDottyRoot(implicit mode: Mode): Project = project.withCommonSettings. - aggregate(`dotty-interfaces`, dottyLibrary, dottyCompiler, dottyDoc, dottySbtBridgeReference). + aggregate(`dotty-interfaces`, dottyLibrary, dottyCompiler, dottyDoc, `dotty-sbt-bridge`). bootstrappedAggregate(`scala-library`, `scala-compiler`, `scala-reflect`, scalap, `dotty-language-server`). dependsOn(dottyCompiler). dependsOn(dottyLibrary). @@ -1299,11 +1296,6 @@ object Build { dependsOn(dottyCompiler, dottyCompiler % "test->test"). settings(dottyDocSettings) - def asDottySbtBridge(implicit mode: Mode): Project = project.withCommonSettings. - dependsOn(dottyCompiler % Provided). - dependsOn(dottyDoc % Provided). - settings(dottySbtBridgeSettings) - def asDottyBench(implicit mode: Mode): Project = project.withCommonSettings. dependsOn(dottyCompiler). settings(commonBenchmarkSettings). From 2cd2dc6cb67bc7a2156537ad42c54e964253ea03 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 25 Jan 2019 23:01:17 +0100 Subject: [PATCH 4/6] sbt-bridge: remove dead code --- sbt-bridge/src/xsbt/CachedCompilerImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/sbt-bridge/src/xsbt/CachedCompilerImpl.java b/sbt-bridge/src/xsbt/CachedCompilerImpl.java index e0d8b14533e1..caaecf8ca732 100644 --- a/sbt-bridge/src/xsbt/CachedCompilerImpl.java +++ b/sbt-bridge/src/xsbt/CachedCompilerImpl.java @@ -66,8 +66,6 @@ synchronized public void run(File[] sources, DependencyChanges changes, Analysis .setSbtCallback(callback) .setReporter(new DelegatingReporter(delegate)); - URLClassLoader cl = (URLClassLoader) this.getClass().getClassLoader(); - dotty.tools.dotc.reporting.Reporter reporter = Main.process(commandArguments(sources), ctx); if (reporter.hasErrors()) { throw new InterfaceCompileFailed(args, new Problem[0]); From 0bd225f6f57e13d688cb6b67e311f8814ac5634f Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 25 Jan 2019 23:02:58 +0100 Subject: [PATCH 5/6] Remove manual sbt-bridge cache invalidation These caches are only used with scalaCompilerBridgeSource, so we don't need them now that we switched to scalaCompilerBridgeBinaryJar --- project/Build.scala | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 464abd4aca44..250611051d6b 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -780,19 +780,6 @@ object Build { } lazy val dottySbtBridgeSettings = Seq( - cleanSbtBridge := { - cleanSbtBridgeImpl() - }, - compile in Compile := { - val log = streams.value.log - val prev = (previousCompile in Compile).value.analysis.orElse(null) - val cur = (compile in Compile).value - if (prev != cur) { - log.info("Cleaning the dotty-sbt-bridge cache because it was recompiled.") - cleanSbtBridgeImpl() - } - cur - }, description := "sbt compiler bridge for Dotty", resolvers += Resolver.typesafeIvyRepo("releases"), // For org.scala-sbt:api libraryDependencies ++= Seq( @@ -808,36 +795,11 @@ object Build { parallelExecution in Test := false ) - // Needed until https://github.com/sbt/sbt/issues/2402 is fixed. - lazy val cleanSbtBridge = TaskKey[Unit]("cleanSbtBridge", "delete dotty-sbt-bridge cache") - - def cleanSbtBridgeImpl(): Unit = { - val home = System.getProperty("user.home") - val sbtOrg = "org.scala-sbt" - val bridgePattern = s"*dotty-sbt-bridge*$dottyVersion*" - - IO.delete((file(home) / ".sbt" / "1.0" / "zinc" / sbtOrg * bridgePattern).get) - IO.delete((file(home) / ".sbt" / "boot" * "scala-*" / sbtOrg / "sbt" * "*" * bridgePattern).get) - } - lazy val `dotty-sbt-bridge` = project.in(file("sbt-bridge")). dependsOn(dottyCompiler(NonBootstrapped) % Provided). dependsOn(dottyDoc(NonBootstrapped) % Provided). settings(commonJavaSettings). settings( - cleanSbtBridge := { - cleanSbtBridgeImpl() - }, - compile in Compile := { - val log = streams.value.log - val prev = (previousCompile in Compile).value.analysis.orElse(null) - val cur = (compile in Compile).value - if (prev != cur) { - log.info("Cleaning the dotty-sbt-bridge cache because it was recompiled.") - cleanSbtBridgeImpl() - } - cur - }, description := "sbt compiler bridge for Dotty", libraryDependencies ++= Seq( Dependencies.`compiler-interface` % Provided, From 6da66c2396eb314becb7335b68a9a9ac01436f89 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 25 Jan 2019 23:50:51 +0100 Subject: [PATCH 6/6] Remove dead code in the build --- project/Build.scala | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 250611051d6b..7bbc21f1f01c 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -779,22 +779,6 @@ object Build { case Bootstrapped => `dotty-library-bootstrapped` } - lazy val dottySbtBridgeSettings = Seq( - description := "sbt compiler bridge for Dotty", - resolvers += Resolver.typesafeIvyRepo("releases"), // For org.scala-sbt:api - libraryDependencies ++= Seq( - Dependencies.`compiler-interface` % Provided, - (Dependencies.`zinc-api-info` % Test).withDottyCompat(scalaVersion.value) - ), - - // sources are Java-only, tests are in Scala - crossPaths in Compile := false, - autoScalaLibrary in Compile := false, - - fork in Test := true, - parallelExecution in Test := false - ) - lazy val `dotty-sbt-bridge` = project.in(file("sbt-bridge")). dependsOn(dottyCompiler(NonBootstrapped) % Provided). dependsOn(dottyDoc(NonBootstrapped) % Provided).