diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-10-11 17:28:39 +0200 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2016-11-22 01:35:06 +0100 |
commit | 2d10c87ce537fb42fdb134efcae53dca7305a7b7 (patch) | |
tree | a3629c9a3ad6db3e9d07df8fa8621f8c8211076c /bridge/src/main/scala | |
parent | 34d64f381362b12a595fd26690c7c9b1c26d16f7 (diff) | |
download | dotty-2d10c87ce537fb42fdb134efcae53dca7305a7b7.tar.gz dotty-2d10c87ce537fb42fdb134efcae53dca7305a7b7.tar.bz2 dotty-2d10c87ce537fb42fdb134efcae53dca7305a7b7.zip |
Move sbt-bridge
Diffstat (limited to 'bridge/src/main/scala')
-rw-r--r-- | bridge/src/main/scala/xsbt/CompilerClassLoader.scala | 90 | ||||
-rw-r--r-- | bridge/src/main/scala/xsbt/CompilerInterface.scala | 72 | ||||
-rw-r--r-- | bridge/src/main/scala/xsbt/ConsoleInterface.scala | 73 | ||||
-rw-r--r-- | bridge/src/main/scala/xsbt/DelegatingReporter.scala | 48 | ||||
-rw-r--r-- | bridge/src/main/scala/xsbt/Log.scala | 10 | ||||
-rw-r--r-- | bridge/src/main/scala/xsbt/Message.scala | 8 | ||||
-rw-r--r-- | bridge/src/main/scala/xsbt/ScaladocInterface.scala | 72 |
7 files changed, 0 insertions, 373 deletions
diff --git a/bridge/src/main/scala/xsbt/CompilerClassLoader.scala b/bridge/src/main/scala/xsbt/CompilerClassLoader.scala deleted file mode 100644 index 3cb3f344f..000000000 --- a/bridge/src/main/scala/xsbt/CompilerClassLoader.scala +++ /dev/null @@ -1,90 +0,0 @@ -package xsbt - -import java.net.{URL, URLClassLoader} - -/** 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 { - /** 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) = 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/bridge/src/main/scala/xsbt/CompilerInterface.scala b/bridge/src/main/scala/xsbt/CompilerInterface.scala deleted file mode 100644 index bf1488dad..000000000 --- a/bridge/src/main/scala/xsbt/CompilerInterface.scala +++ /dev/null @@ -1,72 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -import xsbti.{ AnalysisCallback, Logger, Problem, Reporter, Severity, DependencyContext } -import xsbti.api.SourceAPI -import xsbti.compile._ -import Log.debug -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: Logger, - initialDelegate: Reporter, resident: Boolean): 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, resident) - - val bridgeLoader = getClass.getClassLoader - val fixedLoader = CompilerClassLoader.fixBridgeLoader(bridgeLoader) - val cciClass = fixedLoader.loadClass("xsbt.CachedCompilerImpl") - cciClass.getConstructors.head - .newInstance(options, output, resident: java.lang.Boolean) - .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, resident: Boolean) extends CachedCompiler { - val outputArgs = - output match { - case multi: MultipleOutput => - ??? - case single: SingleOutput => - List("-d", single.outputDirectory.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 = { - debug(log, 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[Problem]) extends xsbti.CompileFailed { - override val toString = "Compilation failed" -} diff --git a/bridge/src/main/scala/xsbt/ConsoleInterface.scala b/bridge/src/main/scala/xsbt/ConsoleInterface.scala deleted file mode 100644 index f56918113..000000000 --- a/bridge/src/main/scala/xsbt/ConsoleInterface.scala +++ /dev/null @@ -1,73 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -import xsbti.Logger -import scala.tools.nsc.{ GenericRunnerCommand, Interpreter, InterpreterLoop, ObjectRunner, Settings } -import scala.tools.nsc.interpreter.InteractiveReader -import scala.tools.nsc.reporters.Reporter -import scala.tools.nsc.util.ClassPath - -import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.repl.REPL -import dotty.tools.dotc.repl.REPL.Config - -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 :+ - "-bootclasspath" :+ bootClasspathString :+ - "-classpath" :+ classpathString - - println("Starting dotty interpreter...") - val repl = ConsoleInterface.customRepl( - initialCommands :: Nil, - cleanupCommands :: Nil, - bindNames zip bindValues, - loader - ) - repl.process(completeArgs) - } -} - -object ConsoleInterface { - def customConfig( - initCmds: List[String], - cleanupCmds: List[String], - boundVals: Array[(String, Any)], - loader: ClassLoader - ) = new Config { - override val initialCommands: List[String] = initCmds - override val cleanupCommands: List[String] = cleanupCmds - override val boundValues: Array[(String, Any)] = boundVals - override val classLoader: Option[ClassLoader] = Option(loader) - } - - def customRepl(cfg: Config): REPL = new REPL { - override lazy val config = cfg - } - - def customRepl( - initCmds: List[String], - cleanupCmds: List[String], - boundVals: Array[(String, Any)], - loader: ClassLoader - ): REPL = customRepl(customConfig(initCmds, cleanupCmds, boundVals, loader)) -} diff --git a/bridge/src/main/scala/xsbt/DelegatingReporter.scala b/bridge/src/main/scala/xsbt/DelegatingReporter.scala deleted file mode 100644 index 770d6b2c7..000000000 --- a/bridge/src/main/scala/xsbt/DelegatingReporter.scala +++ /dev/null @@ -1,48 +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.{Maybe, Position} - -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 => xsbti.Severity.Error - case _: messages.Warning => xsbti.Severity.Warn - case _ => xsbti.Severity.Info - } - - val position = new Position { - def line: Maybe[Integer] = Maybe.nothing() - def lineContent: String = "" - def offset: Maybe[Integer] = Maybe.nothing() - def pointer: Maybe[Integer] = Maybe.nothing() - def pointerSpace: Maybe[String] = Maybe.nothing() - def sourceFile: Maybe[java.io.File] = Maybe.nothing() - def sourcePath: Maybe[String] = Maybe.nothing() - } - - val sb = new StringBuilder() - sb.append(messageAndPos(cont.contained, cont.pos, diagnosticLevel(cont))) - if (ctx.shouldExplain(cont) && cont.contained.explanation.nonEmpty) { - sb.append(explanation(cont.contained)) - } - - delegate.log(position, sb.toString(), severity) - } -} diff --git a/bridge/src/main/scala/xsbt/Log.scala b/bridge/src/main/scala/xsbt/Log.scala deleted file mode 100644 index e514d7abb..000000000 --- a/bridge/src/main/scala/xsbt/Log.scala +++ /dev/null @@ -1,10 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -object Log { - def debug(log: xsbti.Logger, msg: => String) = log.debug(Message(msg)) - def settingsError(log: xsbti.Logger): String => Unit = - s => log.error(Message(s)) -} diff --git a/bridge/src/main/scala/xsbt/Message.scala b/bridge/src/main/scala/xsbt/Message.scala deleted file mode 100644 index 48f24f533..000000000 --- a/bridge/src/main/scala/xsbt/Message.scala +++ /dev/null @@ -1,8 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -object Message { - def apply[T](s: => T) = new xsbti.F0[T] { def apply() = s } -} diff --git a/bridge/src/main/scala/xsbt/ScaladocInterface.scala b/bridge/src/main/scala/xsbt/ScaladocInterface.scala deleted file mode 100644 index 3ad9c7941..000000000 --- a/bridge/src/main/scala/xsbt/ScaladocInterface.scala +++ /dev/null @@ -1,72 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2008, 2009 Mark Harrah - */ -package xsbt - -import xsbti.Logger -import dotty.tools.dottydoc.api.scala.Dottydoc -import java.net.URL - -class ScaladocInterface { - def run(args: Array[String], log: Logger, delegate: xsbti.Reporter) = - (new DottydocRunner(args, log, delegate)).run() -} - -class DottydocRunner(args: Array[String], log: Logger, delegate: xsbti.Reporter) extends Dottydoc { - def run(): Unit = getOutputFolder(args).map { outputFolder => - val index = createIndex(args) - val resources = getResources(args) - val template = getTemplate(resources) - - template.fold(writeJson(index, outputFolder)) { tpl => - buildDocs(outputFolder, tpl, resources, index) - } - } getOrElse { - delegate.log( - NoPosition, - "No output folder set for API documentation (\"-d\" parameter should be passed to the documentation tool)", - xsbti.Severity.Error - ) - } - - private[this] val NoPosition = new xsbti.Position { - val line = xsbti.Maybe.nothing[Integer] - val lineContent = "" - val offset = xsbti.Maybe.nothing[Integer] - val sourcePath = xsbti.Maybe.nothing[String] - val sourceFile = xsbti.Maybe.nothing[java.io.File] - val pointer = xsbti.Maybe.nothing[Integer] - val pointerSpace = xsbti.Maybe.nothing[String] - } - - private def getStringSetting(name: String): Option[String] = - args find (_.startsWith(name)) map (_.drop(name.length)) - - private def getOutputFolder(args: Array[String]): Option[String] = - args sliding(2) find { case Array(x, _) => x == "-d" } map (_.tail.head.trim) - - private def getTemplate(resources: List[URL]): Option[URL] = - resources.find(_.getFile.endsWith("template.html")) - - private def getResources(args: Array[String]): List[URL] = { - val cp = args sliding (2) find { case Array(x, _) => x == "-classpath" } map (_.tail.head.trim) getOrElse "" - - cp.split(":").find(_.endsWith("dottydoc-client.jar")).map { resourceJar => - import java.util.jar.JarFile - val jarEntries = (new JarFile(resourceJar)).entries - var entries: List[URL] = Nil - - while (jarEntries.hasMoreElements) { - val entry = jarEntries.nextElement() - - if (!entry.isDirectory()) { - val path = s"jar:file:$resourceJar!/${entry.getName}" - val url = new URL(path) - entries = url :: entries - } - } - - entries - } getOrElse (Nil) - } -} |