Changes required to use sbt as-is from Scala-IDE.

This commit is contained in:
Eugene Vigdorchik 2012-07-10 21:12:39 +04:00 committed by Mark Harrah
parent e23df839b7
commit b5a29987e6
28 changed files with 316 additions and 157 deletions

View File

@ -5,7 +5,7 @@ package sbt
package compiler
import xsbti.{AnalysisCallback, Logger => xLogger, Reporter}
import xsbti.compile.{CachedCompiler, CachedCompilerProvider, DependencyChanges, GlobalsCache}
import xsbti.compile.{CachedCompiler, CachedCompilerProvider, DependencyChanges, GlobalsCache, CompileProgress, Output}
import java.io.File
import java.net.{URL, URLClassLoader}
@ -16,33 +16,35 @@ package compiler
final class AnalyzingCompiler(val scalaInstance: xsbti.compile.ScalaInstance, val provider: CompilerInterfaceProvider, val cp: xsbti.compile.ClasspathOptions, log: Logger) extends CachedCompilerProvider
{
def this(scalaInstance: ScalaInstance, provider: CompilerInterfaceProvider, log: Logger) = this(scalaInstance, provider, ClasspathOptions.auto, log)
def apply(sources: Seq[File], changes: DependencyChanges, classpath: Seq[File], outputDirectory: File, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, cache: GlobalsCache, log: Logger)
def apply(sources: Seq[File], changes: DependencyChanges, classpath: Seq[File], singleOutput: File, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, cache: GlobalsCache, log: Logger)
{
val arguments = (new CompilerArguments(scalaInstance, cp))(Nil, classpath, outputDirectory, options)
compile(sources, changes, arguments, callback, maximumErrors, cache, log)
val arguments = (new CompilerArguments(scalaInstance, cp))(Nil, classpath, None, options)
val output = CompileOutput(singleOutput)
compile(sources, changes, arguments, output, callback, maximumErrors, cache, log, None)
}
def compile(sources: Seq[File], changes: DependencyChanges, options: Seq[String], callback: AnalysisCallback, maximumErrors: Int, cache: GlobalsCache, log: Logger): Unit =
def compile(sources: Seq[File], changes: DependencyChanges, options: Seq[String], output: Output, callback: AnalysisCallback, maximumErrors: Int, cache: GlobalsCache, log: Logger, progressOpt: Option[CompileProgress]): Unit =
{
val reporter = new LoggerReporter(maximumErrors, log)
val cached = cache(options.toArray, !changes.isEmpty, this, log, reporter)
compile(sources, changes, callback, log, reporter, cached)
val cached = cache(options.toArray, output, !changes.isEmpty, this, log, reporter)
val progress = progressOpt getOrElse IgnoreProgress
compile(sources, changes, callback, log, reporter, progress, cached)
}
def compile(sources: Seq[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, reporter: Reporter, compiler: CachedCompiler)
def compile(sources: Seq[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, reporter: Reporter, progress: CompileProgress, compiler: CachedCompiler)
{
call("xsbt.CompilerInterface", "run", log)(
classOf[Array[File]], classOf[DependencyChanges], classOf[AnalysisCallback], classOf[xLogger], classOf[Reporter], classOf[CachedCompiler]) (
sources.toArray, changes, callback, log, reporter, compiler )
classOf[Array[File]], classOf[DependencyChanges], classOf[AnalysisCallback], classOf[xLogger], classOf[Reporter], classOf[CompileProgress], classOf[CachedCompiler]) (
sources.toArray, changes, callback, log, reporter, progress, compiler )
}
def newCachedCompiler(arguments: Array[String], log: xLogger, reporter: Reporter, resident: Boolean): CachedCompiler =
newCachedCompiler(arguments: Seq[String], log, reporter, resident)
def newCachedCompiler(arguments: Array[String], output: Output, log: xLogger, reporter: Reporter, resident: Boolean): CachedCompiler =
newCachedCompiler(arguments: Seq[String], output, log, reporter, resident)
def newCachedCompiler(arguments: Seq[String], log: xLogger, reporter: Reporter, resident: Boolean): CachedCompiler =
def newCachedCompiler(arguments: Seq[String], output: Output, log: xLogger, reporter: Reporter, resident: Boolean): CachedCompiler =
{
call("xsbt.CompilerInterface", "newCompiler", log)(
classOf[Array[String]], classOf[xLogger], classOf[Reporter], classOf[Boolean] ) (
arguments.toArray[String] : Array[String], log, reporter, resident: java.lang.Boolean ).
classOf[Array[String]], classOf[Output], classOf[xLogger], classOf[Reporter], classOf[Boolean] ) (
arguments.toArray[String] : Array[String], output, log, reporter, resident: java.lang.Boolean ).
asInstanceOf[CachedCompiler]
}
@ -50,7 +52,7 @@ final class AnalyzingCompiler(val scalaInstance: xsbti.compile.ScalaInstance, va
doc(sources, classpath, outputDirectory, options, log, new LoggerReporter(maximumErrors, log))
def doc(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String], log: Logger, reporter: Reporter): Unit =
{
val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, outputDirectory, options)
val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, Some(outputDirectory), options)
call("xsbt.ScaladocInterface", "run", log) (classOf[Array[String]], classOf[xLogger], classOf[Reporter]) (
arguments.toArray[String] : Array[String], log, reporter)
}
@ -124,4 +126,9 @@ object AnalyzingCompiler
}
}
private def isSourceName(name: String): Boolean = name.endsWith(".scala") || name.endsWith(".java")
}
}
private[this] object IgnoreProgress extends CompileProgress {
def startUnit(phase: String, unitPath: String) {}
def advance(current: Int, total: Int) = true
}

View File

@ -16,7 +16,7 @@ package compiler
* this would lead to compiling against the wrong library jar.*/
final class CompilerArguments(scalaInstance: xsbti.compile.ScalaInstance, cp: xsbti.compile.ClasspathOptions)
{
def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String]): Seq[String] =
def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: Option[File], options: Seq[String]): Seq[String] =
{
checkScalaHomeUnset()
val cpWithCompiler = finishClasspath(classpath)
@ -24,7 +24,7 @@ final class CompilerArguments(scalaInstance: xsbti.compile.ScalaInstance, cp: xs
// We append a random dummy element as workaround.
val dummy = "dummy_" + Integer.toHexString(util.Random.nextInt)
val classpathOption = Seq("-classpath", if(cpWithCompiler.isEmpty) dummy else absString(cpWithCompiler))
val outputOption = Seq("-d", outputDirectory.getAbsolutePath)
val outputOption = outputDirectory map {out => Seq("-d", out.getAbsolutePath)} getOrElse Seq()
options ++ outputOption ++ bootClasspathOption(hasLibrary(classpath)) ++ classpathOption ++ abs(sources)
}
def finishClasspath(classpath: Seq[File]): Seq[File] =

View File

@ -2,7 +2,7 @@ package sbt
package compiler
import xsbti.{Logger => xLogger, Reporter}
import xsbti.compile.{CachedCompiler, CachedCompilerProvider, GlobalsCache}
import xsbti.compile.{CachedCompiler, CachedCompilerProvider, GlobalsCache, Output}
import Logger.f0
import java.io.File
import java.util.{LinkedHashMap,Map}
@ -13,14 +13,14 @@ private final class CompilerCache(val maxInstances: Int) extends GlobalsCache
private[this] def lru[A,B](max: Int) = new LinkedHashMap[A,B](8, 0.75f, true) {
override def removeEldestEntry(eldest: Map.Entry[A,B]): Boolean = size > max
}
def apply(args: Array[String], forceNew: Boolean, c: CachedCompilerProvider, log: xLogger, reporter: Reporter): CachedCompiler = synchronized
def apply(args: Array[String], output: Output, forceNew: Boolean, c: CachedCompilerProvider, log: xLogger, reporter: Reporter): CachedCompiler = synchronized
{
val key = CompilerKey(dropSources(args.toList), c.scalaInstance.actualVersion)
if(forceNew) cache.remove(key)
cache.get(key) match {
case null =>
log.debug(f0("Compiler cache miss. " + key.toString))
put(key, c.newCachedCompiler(args, log, reporter, /* resident = */ !forceNew))
put(key, c.newCachedCompiler(args, output, log, reporter, /* resident = */ !forceNew))
case cc =>
log.debug(f0("Compiler cache hit (" + cc.hashCode.toHexString + "). " + key.toString))
cc
@ -46,7 +46,7 @@ object CompilerCache
val fresh: GlobalsCache = new GlobalsCache {
def clear() {}
def apply(args: Array[String], forceNew: Boolean, c: CachedCompilerProvider, log: xLogger, reporter: Reporter): CachedCompiler =
c.newCachedCompiler(args, log, reporter, /*resident = */ false)
def apply(args: Array[String], output: Output, forceNew: Boolean, c: CachedCompilerProvider, log: xLogger, reporter: Reporter): CachedCompiler =
c.newCachedCompiler(args, output, log, reporter, /*resident = */ false)
}
}
}

24
compile/CompilerOutput.scala Executable file
View File

@ -0,0 +1,24 @@
/* sbt -- Simple Build Tool
* Copyright 2012 Eugene Vigdorchik
*/
package sbt
package compiler
import xsbti.compile.{Output, SingleOutput, MultipleOutput}
import java.io.File
object CompileOutput {
def apply(dir: File): Output = new SingleOutput {
def outputDirectory = dir
}
def apply(groups: (File, File)*): Output = new MultipleOutput {
def outputGroups = groups.toArray map {
case (src, out) => new MultipleOutput.OutputGroup {
def sourceDirectory = src
def outputDirectory = out
}
}
}
}

View File

@ -13,8 +13,13 @@ trait JavaCompiler extends xsbti.compile.JavaCompiler
{
def apply(sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger)
def compile(sources: Array[File], classpath: Array[File], outputDirectory: File, options: Array[String], maxErrors: Int, log: xsbti.Logger): Unit =
def compile(sources: Array[File], classpath: Array[File], output: xsbti.compile.Output, options: Array[String], maxErrors: Int, log: xsbti.Logger): Unit = {
val outputDirectory = output match {
case single: xsbti.compile.SingleOutput => single.outputDirectory
case _ => throw new RuntimeException("Javac doesn't support multiple output directories")
}
apply(sources, classpath, outputDirectory, options)(log)
}
}
trait Javadoc
{
@ -52,7 +57,7 @@ object JavaCompiler
def compile(contract: JavacContract, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger) {
val augmentedClasspath = if(cp.autoBoot) classpath ++ Seq(scalaInstance.libraryJar) else classpath
val javaCp = ClasspathOptions.javac(cp.compiler)
val arguments = (new CompilerArguments(scalaInstance, javaCp))(sources, augmentedClasspath, outputDirectory, options)
val arguments = (new CompilerArguments(scalaInstance, javaCp))(sources, augmentedClasspath, Some(outputDirectory), options)
log.debug("Calling " + contract.name.capitalize + " with arguments:\n\t" + arguments.mkString("\n\t"))
val code: Int = f(contract, arguments, log)
log.debug(contract.name + " returned exit code: " + code)
@ -106,4 +111,4 @@ object JavaCompiler
// javac's argument file seems to allow naive space escaping with quotes. escaping a quote with a backslash does not work
def escapeSpaces(s: String): String = '\"' + normalizeSlash(s) + '\"'
def normalizeSlash(s: String) = s.replace(File.separatorChar, '/')
}
}

View File

@ -19,7 +19,7 @@ class RawCompiler(val scalaInstance: xsbti.compile.ScalaInstance, cp: ClasspathO
// but should not be otherwise directly referenced
import scala.tools.nsc.Main.{process => _}
val arguments = compilerArguments(sources, classpath, outputDirectory, options)
val arguments = compilerArguments(sources, classpath, Some(outputDirectory), options)
log.debug("Plain interface to Scala compiler " + scalaInstance.actualVersion + " with arguments: " + arguments.mkString("\n\t", "\n\t", ""))
val mainClass = Class.forName("scala.tools.nsc.Main", true, scalaInstance.loader)
val process = mainClass.getMethod("process", classOf[Array[String]])

View File

@ -37,7 +37,7 @@ object APIs
def empty: APIs = apply(Map.empty, Map.empty)
val emptyAPI = new xsbti.api.SourceAPI(Array(), Array())
val emptyCompilation = new xsbti.api.Compilation(-1, "")
val emptyCompilation = new xsbti.api.Compilation(-1, Array())
val emptySource = new xsbti.api.Source(emptyCompilation, Array(), emptyAPI, 0, false)
def getAPI[T](map: Map[T, Source], src: T): Source = map.getOrElse(src, emptySource)
}
@ -61,4 +61,4 @@ private class MAPIs(val internal: Map[File, Source], val external: Map[String, S
def internalAPI(src: File) = getAPI(internal, src)
def externalAPI(ext: String) = getAPI(external, ext)
}
}

View File

@ -4,23 +4,23 @@
package sbt
package inc
import xsbti.api.{Source, SourceAPI}
import xsbti.compile.DependencyChanges
import xsbti.api.{Source, SourceAPI, Compilation, OutputSetting}
import xsbti.compile.{DependencyChanges, Output, SingleOutput, MultipleOutput}
import xsbti.{Position,Problem,Severity}
import Logger.{m2o, problem}
import java.io.File
object IncrementalCompile
{
def apply(sources: Set[File], entry: String => Option[File], compile: (Set[File], DependencyChanges, xsbti.AnalysisCallback) => Unit, previous: Analysis, forEntry: File => Option[Analysis], outputPath: File, log: Logger): (Boolean, Analysis) =
def apply(sources: Set[File], entry: String => Option[File], compile: (Set[File], DependencyChanges, xsbti.AnalysisCallback) => Unit, previous: Analysis, forEntry: File => Option[Analysis], output: Output, log: Logger): (Boolean, Analysis) =
{
val current = Stamps.initial(Stamp.exists, Stamp.hash, Stamp.lastModified)
val internalMap = (f: File) => previous.relations.produced(f).headOption
val externalAPI = getExternalAPI(entry, forEntry)
Incremental.compile(sources, entry, previous, current, forEntry, doCompile(compile, internalMap, externalAPI, current, outputPath), log)
Incremental.compile(sources, entry, previous, current, forEntry, doCompile(compile, internalMap, externalAPI, current, output), log)
}
def doCompile(compile: (Set[File], DependencyChanges, xsbti.AnalysisCallback) => Unit, internalMap: File => Option[File], externalAPI: (File, String) => Option[Source], current: ReadStamps, outputPath: File) = (srcs: Set[File], changes: DependencyChanges) => {
val callback = new AnalysisCallback(internalMap, externalAPI, current, outputPath)
def doCompile(compile: (Set[File], DependencyChanges, xsbti.AnalysisCallback) => Unit, internalMap: File => Option[File], externalAPI: (File, String) => Option[Source], current: ReadStamps, output: Output) = (srcs: Set[File], changes: DependencyChanges) => {
val callback = new AnalysisCallback(internalMap, externalAPI, current, output)
compile(srcs, changes, callback)
callback.get
}
@ -37,10 +37,16 @@ object IncrementalCompile
}
}
}
private final class AnalysisCallback(internalMap: File => Option[File], externalAPI: (File, String) => Option[Source], current: ReadStamps, outputPath: File) extends xsbti.AnalysisCallback
private final class AnalysisCallback(internalMap: File => Option[File], externalAPI: (File, String) => Option[Source], current: ReadStamps, output: Output) extends xsbti.AnalysisCallback
{
val time = System.currentTimeMillis
val compilation = new xsbti.api.Compilation(time, outputPath.getAbsolutePath)
val compilation = {
val outputSettings = output match {
case single: SingleOutput => Array(new OutputSetting("/", single.outputDirectory.getAbsolutePath))
case multi: MultipleOutput =>
multi.outputGroups.map(out => new OutputSetting(out.sourceDirectory.getAbsolutePath, out.outputDirectory.getAbsolutePath)).toArray
}
new Compilation(System.currentTimeMillis, outputSettings)
}
override def toString = ( List("APIs", "Binary deps", "Products", "Source deps") zip List(apis, binaryDeps, classes, sourceDeps)).map { case (label, map) => label + "\n\t" + map.mkString("\n\t") }.mkString("\n")
@ -146,4 +152,4 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
} }
def beginSource(source: File) {}
}
}

View File

@ -3,7 +3,7 @@
*/
package sbt
import xsbti.compile.CompileOrder
import xsbti.compile.{ CompileOrder, Output, SingleOutput, MultipleOutput }
import java.io.File
// this class exists because of Scala's restriction on implicit parameter search.
@ -11,21 +11,32 @@ package sbt
// because complexity(Equiv[Seq[String]]) > complexity(Equiv[CompileSetup])
// (6 > 4)
final class CompileOptions(val options: Seq[String], val javacOptions: Seq[String])
final class CompileSetup(val outputDirectory: File, val options: CompileOptions, val compilerVersion: String, val order: CompileOrder)
final class CompileSetup(val output: Output, val options: CompileOptions, val compilerVersion: String, val order: CompileOrder)
object CompileSetup
{
// Equiv[CompileOrder.Value] dominates Equiv[CompileSetup]
implicit def equivCompileSetup(implicit equivFile: Equiv[File], equivOpts: Equiv[CompileOptions], equivComp: Equiv[String]/*, equivOrder: Equiv[CompileOrder]*/): Equiv[CompileSetup] = new Equiv[CompileSetup] {
implicit def equivCompileSetup(implicit equivOutput: Equiv[Output], equivOpts: Equiv[CompileOptions], equivComp: Equiv[String]/*, equivOrder: Equiv[CompileOrder]*/): Equiv[CompileSetup] = new Equiv[CompileSetup] {
def equiv(a: CompileSetup, b: CompileSetup) =
equivFile.equiv(a.outputDirectory, b.outputDirectory) &&
equivOutput.equiv(a.output, b.output) &&
equivOpts.equiv(a.options, b.options) &&
equivComp.equiv(a.compilerVersion, b.compilerVersion) &&
a.order == b.order // equivOrder.equiv(a.order, b.order)
}
implicit val equivOutputDirectory: Equiv[File] = new Equiv[File] {
implicit val equivFile: Equiv[File] = new Equiv[File] {
def equiv(a: File, b: File) = a.getAbsoluteFile == b.getAbsoluteFile
}
implicit val equivOutput: Equiv[Output] = new Equiv[Output] {
def equiv(out1: Output, out2: Output) = (out1, out2) match {
case (m1: MultipleOutput, m2: MultipleOutput) =>
m1.outputGroups zip (m2.outputGroups) forall {
case (a,b) =>
equivFile.equiv(a.sourceDirectory, b.sourceDirectory) && equivFile.equiv(a.outputDirectory, b.outputDirectory)
}
case (s1: SingleOutput, s2: SingleOutput) => equivFile.equiv(s1.outputDirectory, s2.outputDirectory)
case _ => false
}
}
implicit val equivOpts: Equiv[CompileOptions] = new Equiv[CompileOptions] {
def equiv(a: CompileOptions, b: CompileOptions) =
(a.options sameElements b.options) &&
@ -38,4 +49,4 @@ object CompileSetup
implicit val equivOrder: Equiv[CompileOrder] = new Equiv[CompileOrder] {
def equiv(a: CompileOrder, b: CompileOrder) = a == b
}
}
}

View File

@ -77,7 +77,9 @@ object Incremental
}
def shortcutSameSource(a: Source, b: Source): Boolean = !a.hash.isEmpty && !b.hash.isEmpty && sameCompilation(a.compilation, b.compilation) && (a.hash.deep equals b.hash.deep)
def sameCompilation(a: Compilation, b: Compilation): Boolean = a.startTime == b.startTime && a.target == b.target
def sameCompilation(a: Compilation, b: Compilation): Boolean = a.startTime == b.startTime && a.outputs.corresponds(b.outputs){
case (co1, co2) => co1.sourceDirectory == co2.sourceDirectory && co1.outputDirectory == co2.outputDirectory
}
def changedInitial(entry: String => Option[File], sources: Set[File], previousAnalysis: Analysis, current: ReadStamps, forEntry: File => Option[Analysis])(implicit equivS: Equiv[Stamp]): InitialChanges =
{

View File

@ -6,6 +6,7 @@ package compiler
import inc._
import scala.annotation.tailrec
import java.io.File
import classpath.ClasspathUtilities
import classfile.Analyze
@ -15,31 +16,31 @@ import inc._
import xsbti.AnalysisCallback
import xsbti.api.Source
import xsbti.compile.{CompileOrder, DependencyChanges, GlobalsCache}
import xsbti.compile.{CompileOrder, DependencyChanges, GlobalsCache, Output, SingleOutput, MultipleOutput, CompileProgress}
import CompileOrder.{JavaThenScala, Mixed, ScalaThenJava}
final class CompileConfiguration(val sources: Seq[File], val classpath: Seq[File],
val previousAnalysis: Analysis, val previousSetup: Option[CompileSetup], val currentSetup: CompileSetup, val getAnalysis: File => Option[Analysis], val definesClass: DefinesClass,
val previousAnalysis: Analysis, val previousSetup: Option[CompileSetup], val currentSetup: CompileSetup, val progress: Option[CompileProgress], val getAnalysis: File => Option[Analysis], val definesClass: DefinesClass,
val maxErrors: Int, val compiler: AnalyzingCompiler, val javac: xsbti.compile.JavaCompiler, val cache: GlobalsCache)
class AggressiveCompile(cacheFile: File)
{
def apply(compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, sources: Seq[File], classpath: Seq[File], outputDirectory: File, cache: GlobalsCache, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, analysisMap: File => Option[Analysis] = { _ => None }, definesClass: DefinesClass = Locate.definesClass _, maxErrors: Int = 100, compileOrder: CompileOrder = Mixed, skip: Boolean = false)(implicit log: Logger): Analysis =
def apply(compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, sources: Seq[File], classpath: Seq[File], output: Output, cache: GlobalsCache, progress: Option[CompileProgress] = None, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, analysisMap: File => Option[Analysis] = { _ => None }, definesClass: DefinesClass = Locate.definesClass _, maxErrors: Int = 100, compileOrder: CompileOrder = Mixed, skip: Boolean = false)(implicit log: Logger): Analysis =
{
val setup = new CompileSetup(outputDirectory, new CompileOptions(options, javacOptions), compiler.scalaInstance.actualVersion, compileOrder)
compile1(sources, classpath, setup, store, analysisMap, definesClass, compiler, javac, maxErrors, skip, cache)
val setup = new CompileSetup(output, new CompileOptions(options, javacOptions), compiler.scalaInstance.actualVersion, compileOrder)
compile1(sources, classpath, setup, progress, store, analysisMap, definesClass, compiler, javac, maxErrors, skip, cache)
}
def withBootclasspath(args: CompilerArguments, classpath: Seq[File]): Seq[File] =
args.bootClasspathFor(classpath) ++ args.finishClasspath(classpath)
def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: File => Option[Analysis], definesClass: DefinesClass, compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, maxErrors: Int, skip: Boolean, cache: GlobalsCache)(implicit log: Logger): Analysis =
def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, progress: Option[CompileProgress], store: AnalysisStore, analysis: File => Option[Analysis], definesClass: DefinesClass, compiler: AnalyzingCompiler, javac: xsbti.compile.JavaCompiler, maxErrors: Int, skip: Boolean, cache: GlobalsCache)(implicit log: Logger): Analysis =
{
val (previousAnalysis, previousSetup) = extract(store.get())
if(skip)
previousAnalysis
else {
val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, analysis, definesClass, maxErrors, compiler, javac, cache)
val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, progress, analysis, definesClass, maxErrors, compiler, javac, cache)
val (modified, result) = compile2(config)
if(modified)
store.set(result, setup)
@ -51,36 +52,60 @@ class AggressiveCompile(cacheFile: File)
import config._
import currentSetup._
val absClasspath = classpath.map(_.getCanonicalFile)
val apiOption= (api: Either[Boolean, Source]) => api.right.toOption
val apiOption = (api: Either[Boolean, Source]) => api.right.toOption
val cArgs = new CompilerArguments(compiler.scalaInstance, compiler.cp)
val searchClasspath = explicitBootClasspath(options.options) ++ withBootclasspath(cArgs, absClasspath)
val entry = Locate.entry(searchClasspath, definesClass)
val compile0 = (include: Set[File], changes: DependencyChanges, callback: AnalysisCallback) => {
IO.createDirectory(outputDirectory)
val outputDirs = outputDirectories(output)
outputDirs foreach (IO.createDirectory)
val incSrc = sources.filter(include)
val (javaSrcs, scalaSrcs) = incSrc partition javaOnly
logInputs(log, javaSrcs.size, scalaSrcs.size, outputDirectory)
logInputs(log, javaSrcs.size, scalaSrcs.size, outputDirs)
def compileScala() =
if(!scalaSrcs.isEmpty)
{
val sources = if(order == Mixed) incSrc else scalaSrcs
val arguments = cArgs(Nil, absClasspath, outputDirectory, options.options)
val arguments = cArgs(Nil, absClasspath, None, options.options)
timed("Scala compilation", log) {
compiler.compile(sources, changes, arguments, callback, maxErrors, cache, log)
compiler.compile(sources, changes, arguments, output, callback, maxErrors, cache, log, progress)
}
}
def compileJava() =
if(!javaSrcs.isEmpty)
{
import Path._
val loader = ClasspathUtilities.toLoader(searchClasspath)
def readAPI(source: File, classes: Seq[Class[_]]) { callback.api(source, ClassToAPI(classes)) }
timed("Java compilation and analysis", log) {
Analyze(outputDirectory, javaSrcs, log)(callback, loader, readAPI) {
timed("Java compilation", log) {
javac.compile(javaSrcs.toArray, absClasspath.toArray, outputDirectory, options.javacOptions.toArray, maxErrors, log)
@tailrec def ancestor(f1: File, f2: File): Boolean =
if (f2 eq null) false else
if (f1 == f2) true else ancestor(f1, f2.getParentFile)
val chunks: Map[Option[File], Seq[File]] = output match {
case single: SingleOutput => Map(Some(single.outputDirectory) -> javaSrcs)
case multi: MultipleOutput =>
javaSrcs groupBy { src =>
multi.outputGroups find {out => ancestor(out.sourceDirectory, src)} map (_.outputDirectory)
}
}
chunks.get(None) foreach { srcs =>
log.error("No output directory mapped for: " + srcs.map(_.getAbsolutePath).mkString(","))
}
val memo = for ((Some(outputDirectory), srcs) <- chunks) yield {
val classesFinder = PathFinder(outputDirectory) ** "*.class"
(classesFinder, classesFinder.get, srcs)
}
val loader = ClasspathUtilities.toLoader(searchClasspath)
timed("Java compilation", log) {
javac.compile(javaSrcs.toArray, absClasspath.toArray, output, options.javacOptions.toArray, maxErrors, log)
}
def readAPI(source: File, classes: Seq[Class[_]]) { callback.api(source, ClassToAPI(classes)) }
timed("Java analysis", log) {
for ((classesFinder, oldClasses, srcs) <- memo) {
val newClasses = Set(classesFinder.get: _*) -- oldClasses
Analyze(newClasses.toSeq, srcs, log)(callback, loader, readAPI)
}
}
}
@ -92,7 +117,11 @@ class AggressiveCompile(cacheFile: File)
case Some(previous) if equiv.equiv(previous, currentSetup) => previousAnalysis
case _ => Incremental.prune(sourcesSet, previousAnalysis)
}
IncrementalCompile(sourcesSet, entry, compile0, analysis, getAnalysis, outputDirectory, log)
IncrementalCompile(sourcesSet, entry, compile0, analysis, getAnalysis, output, log)
}
private[this] def outputDirectories(output: Output): Seq[File] = output match {
case single: SingleOutput => List(single.outputDirectory)
case mult: MultipleOutput => mult.outputGroups map (_.outputDirectory)
}
private[this] def timed[T](label: String, log: Logger)(t: => T): T =
{
@ -102,13 +131,13 @@ class AggressiveCompile(cacheFile: File)
log.debug(label + " took " + (elapsed/1e9) + " s")
result
}
private[this] def logInputs(log: Logger, javaCount: Int, scalaCount: Int, out: File)
private[this] def logInputs(log: Logger, javaCount: Int, scalaCount: Int, outputDirs: Seq[File])
{
val scalaMsg = Analysis.counted("Scala source", "", "s", scalaCount)
val javaMsg = Analysis.counted("Java source", "", "s", javaCount)
val combined = scalaMsg ++ javaMsg
if(!combined.isEmpty)
log.info(combined.mkString("Compiling ", " and ", " to " + out.getAbsolutePath + "..."))
log.info(combined.mkString("Compiling ", " and ", " to " + outputDirs.map(_.getAbsolutePath).mkString(",") + "..."))
}
private def extract(previous: Option[(Analysis, CompileSetup)]): (Analysis, Option[CompileSetup]) =
previous match

View File

@ -17,7 +17,7 @@ object IC extends IncrementalCompiler[Analysis, AnalyzingCompiler]
val agg = new AggressiveCompile(setup.cacheFile)
val aMap = (f: File) => m2o(analysisMap(f))
val defClass = (f: File) => { val dc = definesClass(f); (name: String) => dc.apply(name) }
agg(scalac, javac, sources, classpath, classesDirectory, cache, scalacOptions, javacOptions, aMap, defClass, maxErrors, order, skip)(log)
agg(scalac, javac, sources, classpath, output, cache, m2o(progress), scalacOptions, javacOptions, aMap, defClass, maxErrors, order, skip)(log)
}
private[this] def m2o[S](opt: Maybe[S]): Option[S] = if(opt.isEmpty) None else Some(opt.get)

View File

@ -28,8 +28,6 @@ final class Analyzer(val global: CallbackGlobal) extends Compat
def name = Analyzer.name
def run
{
val outputDirectory = new File(global.settings.outdir.value)
for(unit <- currentRun.units if !unit.isJava)
{
// build dependencies structure
@ -64,8 +62,7 @@ final class Analyzer(val global: CallbackGlobal) extends Compat
val sym = iclass.symbol
def addGenerated(separatorRequired: Boolean)
{
val classFile = fileForClass(outputDirectory, sym, separatorRequired)
if(classFile.exists)
for(classFile <- outputDirs map (fileForClass(_, sym, separatorRequired)) find (_.exists))
callback.generatedClass(sourceFile, classFile, className(sym, '.', separatorRequired))
}
if(sym.isModuleClass && !sym.isImplClass)
@ -152,4 +149,4 @@ abstract class Compat
private[this] def sourceCompatibilityOnly: Nothing = throw new RuntimeException("For source compatibility only: should not get here.")
private[this] final implicit def miscCompat(n: AnyRef): MiscCompat = new MiscCompat
}
}

View File

@ -4,7 +4,7 @@
package xsbt
import xsbti.{AnalysisCallback,Logger,Problem,Reporter,Severity}
import xsbti.compile.{CachedCompiler, DependencyChanges}
import xsbti.compile._
import scala.tools.nsc.{backend, io, reporters, symtab, util, Phase, Global, Settings, SubComponent}
import backend.JavaPlatform
import scala.tools.util.PathResolver
@ -19,19 +19,25 @@ import java.io.File
final class CompilerInterface
{
def newCompiler(options: Array[String], initialLog: Logger, initialDelegate: Reporter, resident: Boolean): CachedCompiler =
new CachedCompiler0(options, new WeakLog(initialLog, initialDelegate), resident)
def newCompiler(options: Array[String], output: Output, initialLog: Logger, initialDelegate: Reporter, resident: Boolean): CachedCompiler =
new CachedCompiler0(options, output, new WeakLog(initialLog, initialDelegate), resident)
def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, cached: CachedCompiler): Unit =
cached.run(sources, changes, callback, log, delegate)
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)
}
// for compatibility with Scala versions without Global.registerTopLevelSym (2.8.1 and earlier)
sealed trait GlobalCompat { self: Global =>
def registerTopLevelSym(sym: Symbol): Unit
}
sealed abstract class CallbackGlobal(settings: Settings, reporter: reporters.Reporter) extends Global(settings, reporter) with GlobalCompat {
sealed abstract class CallbackGlobal(settings: Settings, reporter: reporters.Reporter, output: Output) extends Global(settings, reporter) with GlobalCompat {
def callback: AnalysisCallback
def findClass(name: String): Option[(AbstractFile,Boolean)]
lazy val outputDirs: Iterable[File] = {
output match {
case single: SingleOutput => List(single.outputDirectory)
case multi: MultipleOutput => multi.outputGroups.toStream map (_.outputDirectory)
}
}
}
class InterfaceCompileFailed(val arguments: Array[String], val problems: Array[Problem], override val toString: String) extends xsbti.CompileFailed
@ -49,9 +55,17 @@ private final class WeakLog(private[this] var log: Logger, private[this] var del
}
}
private final class CachedCompiler0(args: Array[String], initialLog: WeakLog, resident: Boolean) extends CachedCompiler
private final class CachedCompiler0(args: Array[String], output: Output, initialLog: WeakLog, resident: Boolean) extends CachedCompiler
{
val settings = new Settings(s => initialLog(s))
output match {
case multi: MultipleOutput =>
for (out <- multi.outputGroups)
settings.outputDirs.add(out.sourceDirectory.getAbsolutePath, out.outputDirectory.getAbsolutePath)
case single: SingleOutput =>
settings.outputDirs.setSingleOutput(single.outputDirectory.getAbsolutePath)
}
val command = Command(args.toList, settings)
private[this] val dreporter = DelegatingReporter(settings, initialLog.reporter)
try {
@ -65,14 +79,14 @@ private final class CachedCompiler0(args: Array[String], initialLog: WeakLog, re
def noErrors(dreporter: DelegatingReporter) = !dreporter.hasErrors && command.ok
def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter): Unit = synchronized
def run(sources: Array[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, delegate: Reporter, progress: CompileProgress): Unit = synchronized
{
debug(log, "Running cached compiler " + hashCode.toHexString + ", interfacing (CompilerInterface) with Scala compiler " + scala.tools.nsc.Properties.versionString)
val dreporter = DelegatingReporter(settings, delegate)
try { run(sources.toList, changes, callback, log, dreporter) }
try { run(sources.toList, changes, callback, log, dreporter, progress) }
finally { dreporter.dropDelegate() }
}
private[this] def run(sources: List[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, dreporter: DelegatingReporter)
private[this] def run(sources: List[File], changes: DependencyChanges, callback: AnalysisCallback, log: Logger, dreporter: DelegatingReporter, compileProgress: CompileProgress)
{
if(command.shouldStopWithInfo)
{
@ -84,8 +98,16 @@ private final class CachedCompiler0(args: Array[String], initialLog: WeakLog, re
debug(log, args.mkString("Calling Scala compiler with arguments (CompilerInterface):\n\t", "\n\t", ""))
compiler.set(callback, dreporter)
try {
val run = new compiler.Run
if(resident) compiler.reload(changes)
val run = new compiler.Run {
override def informUnitStarting(phase: Phase, unit: compiler.CompilationUnit) {
compileProgress.startUnit(phase.name, unit.source.path)
}
override def progress(current: Int, total: Int) {
if (!compileProgress.advance(current, total))
cancel
}
}
if (resident) compiler.reload(changes)
val sortedSourceFiles = sources.map(_.getAbsolutePath).sortWith(_ < _)
run compile sortedSourceFiles
processUnreportedWarnings(run)
@ -113,7 +135,7 @@ private final class CachedCompiler0(args: Array[String], initialLog: WeakLog, re
if(!warnings.isEmpty)
compiler.logUnreportedWarnings(warnings.map(cw => ("" /*cw.what*/, cw.warnings.toList)))
}
object compiler extends CallbackGlobal(command.settings, dreporter)
object compiler extends CallbackGlobal(command.settings, dreporter, output)
{
object dummy // temporary fix for #4426
object sbtAnalyzer extends
@ -145,7 +167,6 @@ private final class CachedCompiler0(args: Array[String], initialLog: WeakLog, re
def name = phaseName
}
val out = new File(settings.outdir.value)
override lazy val phaseDescriptors =
{
phasesSet += sbtAnalyzer
@ -187,8 +208,9 @@ private final class CachedCompiler0(args: Array[String], initialLog: WeakLog, re
def getOutputClass(name: String): Option[AbstractFile] =
{
val f = new File(out, name.replace('.', '/') + ".class")
if(f.exists) Some(AbstractFile.getFile(f)) else None
// This could be improved if a hint where to look is given.
val className = name.replace('.', '/') + ".class"
outputDirs map (new File(_, className)) find (_.exists) map (AbstractFile.getFile(_))
}
def findOnClassPath(name: String): Option[AbstractFile] =
@ -213,7 +235,7 @@ private final class CachedCompiler0(args: Array[String], initialLog: WeakLog, re
// must drop whole CachedCompiler when !changes.isEmpty
def reload(changes: DependencyChanges)
{
inv(settings.outdir.value)
for ((_,out) <- settings.outputDirs.outputs) inv(out.path)
}
private[this] var toForget = mutable.Set[Symbol]()
@ -358,4 +380,4 @@ private final class CachedCompiler0(args: Array[String], initialLog: WeakLog, re
def sourcepaths = delegate.sourcepaths
}
}
}
}

View File

@ -6,10 +6,12 @@ package inc
import xsbti.api.Source
import xsbti.{Position,Problem,Severity}
import xsbti.compile.CompileOrder
import xsbti.compile.{CompileOrder, Output => APIOutput, SingleOutput, MultipleOutput}
import MultipleOutput.OutputGroup
import java.io.File
import sbinary._
import DefaultProtocol._
import DefaultProtocol.tuple2Format
import Logger.{m2o, position, problem}
object AnalysisFormats
@ -63,8 +65,22 @@ object AnalysisFormats
wrap[Severity, Byte]( _.ordinal.toByte, b => Severity.values.apply(b.toInt) )
implicit def setupFormat(implicit outDirF: Format[File], optionF: Format[CompileOptions], compilerVersion: Format[String], orderF: Format[CompileOrder]): Format[CompileSetup] =
asProduct4[CompileSetup, File, CompileOptions, String, CompileOrder]( (a,b,c,d) => new CompileSetup(a,b,c,d) )(s => (s.outputDirectory, s.options, s.compilerVersion, s.order))(outDirF, optionF, compilerVersion, orderF)
implicit def setupFormat(implicit outputF: Format[APIOutput], optionF: Format[CompileOptions], compilerVersion: Format[String], orderF: Format[CompileOrder]): Format[CompileSetup] =
asProduct4[CompileSetup, APIOutput, CompileOptions, String, CompileOrder]( (a,b,c,d) => new CompileSetup(a,b,c,d) )(s => (s.output, s.options, s.compilerVersion, s.order))(outputF, optionF, compilerVersion, orderF)
implicit val outputGroupFormat: Format[OutputGroup] =
asProduct2((a: File,b: File) => new OutputGroup{def sourceDirectory = a; def outputDirectory = b}) { out => (out.sourceDirectory, out.outputDirectory) }(fileFormat, fileFormat)
implicit val multipleOutputFormat: Format[MultipleOutput] =
wrap[MultipleOutput, Array[OutputGroup]](
(_.outputGroups),
{ groups => new MultipleOutput { def outputGroups = groups } }
)
implicit val singleOutputFormat: Format[SingleOutput] =
wrap[SingleOutput, File](
(_.outputDirectory),
{out => new SingleOutput{def outputDirectory = out}}
)(fileFormat)
implicit val outputFormat: Format[APIOutput] = asUnion(singleOutputFormat, multipleOutputFormat)
implicit def stampsFormat(implicit prodF: Format[Map[File, Stamp]], srcF: Format[Map[File, Stamp]], binF: Format[Map[File, Stamp]], nameF: Format[Map[File, String]]): Format[Stamps] =
asProduct4( Stamps.apply _ )( s => (s.products, s.sources, s.binaries, s.classNames) )(prodF, srcF, binF, nameF)

View File

@ -9,9 +9,13 @@ SourceAPI
packages : Package*
definitions: Definition*
OutputSetting
sourceDirectory: String
outputDirectory: String
Compilation
startTime: Long
target: String
outputs: OutputSetting*
Package
name: String

View File

@ -7,5 +7,5 @@ import java.io.File;
public interface CachedCompiler
{
public void run(File[] sources, DependencyChanges cpChanges, AnalysisCallback callback, Logger log, Reporter delegate);
public void run(File[] sources, DependencyChanges cpChanges, AnalysisCallback callback, Logger log, Reporter delegate, CompileProgress progress);
}

View File

@ -6,5 +6,5 @@ import xsbti.Reporter;
public interface CachedCompilerProvider
{
ScalaInstance scalaInstance();
CachedCompiler newCachedCompiler(String[] arguments, Logger log, Reporter reporter, boolean resident);
CachedCompiler newCachedCompiler(String[] arguments, Output output, Logger log, Reporter reporter, boolean resident);
}

View File

@ -0,0 +1,7 @@
package xsbti.compile;
public interface CompileProgress {
void startUnit(String phase, String unitPath);
boolean advance(int current, int total);
}

View File

@ -5,6 +5,6 @@ import xsbti.Reporter;
public interface GlobalsCache
{
public CachedCompiler apply(String[] args, boolean forceNew, CachedCompilerProvider provider, Logger log, Reporter reporter);
public CachedCompiler apply(String[] args, Output output, boolean forceNew, CachedCompilerProvider provider, Logger log, Reporter reporter);
public void clear();
}

View File

@ -11,5 +11,5 @@ public interface JavaCompiler
/** Compiles Java sources using the provided classpath, output directory, and additional options.
* If supported, the number of reported errors should be limited to `maximumErrors`.
* Output should be sent to the provided logger.*/
void compile(File[] sources, File[] classpath, File outputDirectory, String[] options, int maximumErrors, Logger log);
void compile(File[] sources, File[] classpath, Output output, String[] options, int maximumErrors, Logger log);
}

View File

@ -0,0 +1,20 @@
package xsbti.compile;
import java.io.File;
public interface MultipleOutput extends Output {
interface OutputGroup {
/** The directory where source files are stored for this group.
* Source directories should uniquely identify the group for a source file. */
File sourceDirectory();
/** The directory where class files should be generated.
* Incremental compilation will manage the class files in this directory.
* In particular, outdated class files will be deleted before compilation.
* It is important that this directory is exclusively used for one set of sources. */
File outputDirectory();
}
OutputGroup[] outputGroups();
}

View File

@ -13,11 +13,8 @@ public interface Options
* This should include Scala and Java sources, which are identified by their extension. */
File[] sources();
/** The directory where class files should be generated.
* Incremental compilation will manage the class files in this directory.
* In particular, outdated class files will be deleted before compilation.
* It is important that this directory is exclusively used for one set of sources. */
File classesDirectory();
/** Output for the compilation. */
Output output();
/** The options to pass to the Scala compiler other than the sources and classpath to use. */
String[] options();

View File

@ -0,0 +1,9 @@
package xsbti.compile;
import java.io.File;
/** Abstract interface denoting the output of the compilation. Inheritors are SingleOutput with a global output directory and
* MultipleOutput that specifies the output directory per source file.
*/
public interface Output
{
}

View File

@ -23,4 +23,7 @@ public interface Setup<Analysis>
File cacheFile();
GlobalsCache cache();
/** If returned, the progress that should be used to report scala compilation to. */
Maybe<CompileProgress> progress();
}

View File

@ -0,0 +1,12 @@
package xsbti.compile;
import java.io.File;
public interface SingleOutput extends Output {
/** The directory where class files should be generated.
* Incremental compilation will manage the class files in this directory.
* In particular, outdated class files will be deleted before compilation.
* It is important that this directory is exclusively used for one set of sources. */
File outputDirectory();
}

View File

@ -76,6 +76,6 @@ object Compiler
import in.incSetup._
val agg = new AggressiveCompile(cacheFile)
agg(scalac, javac, sources, classpath, classesDirectory, cache, options, javacOptions, analysisMap, definesClass, maxErrors, order, skip)(log)
agg(scalac, javac, sources, classpath, CompileOutput(classesDirectory), cache, None, options, javacOptions, analysisMap, definesClass, maxErrors, order, skip)(log)
}
}

View File

@ -14,76 +14,64 @@ import java.lang.reflect.Modifier.{STATIC, PUBLIC, ABSTRACT}
private[sbt] object Analyze
{
def apply[T](outputDirectory: File, sources: Seq[File], log: Logger)(analysis: xsbti.AnalysisCallback, loader: ClassLoader, readAPI: (File,Seq[Class[_]]) => Unit)(compile: => Unit)
def apply[T](newClasses: Seq[File], sources: Seq[File], log: Logger)(analysis: xsbti.AnalysisCallback, loader: ClassLoader, readAPI: (File,Seq[Class[_]]) => Unit)
{
val sourceMap = sources.toSet[File].groupBy(_.getName)
val classesFinder = PathFinder(outputDirectory) ** "*.class"
val existingClasses = classesFinder.get
def load(tpe: String, errMsg: => Option[String]): Option[Class[_]] =
try { Some(Class.forName(tpe, false, loader)) }
catch { case e => errMsg.foreach(msg => log.warn(msg + " : " +e.toString)); None }
// runs after compilation
def analyze()
{
val allClasses = Set(classesFinder.get: _*)
val newClasses = allClasses -- existingClasses
val productToSource = new mutable.HashMap[File, File]
val sourceToClassFiles = new mutable.HashMap[File, Buffer[ClassFile]]
val productToSource = new mutable.HashMap[File, File]
val sourceToClassFiles = new mutable.HashMap[File, Buffer[ClassFile]]
// parse class files and assign classes to sources. This must be done before dependencies, since the information comes
// as class->class dependencies that must be mapped back to source->class dependencies using the source+class assignment
for(newClass <- newClasses;
classFile = Parser(newClass);
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.getName);
source <- guessSourcePath(sourceMap, classFile, log))
{
analysis.beginSource(source)
analysis.generatedClass(source, newClass, classFile.className)
productToSource(newClass) = source
sourceToClassFiles.getOrElseUpdate(source, new ArrayBuffer[ClassFile]) += classFile
}
// parse class files and assign classes to sources. This must be done before dependencies, since the information comes
// as class->class dependencies that must be mapped back to source->class dependencies using the source+class assignment
for(newClass <- newClasses;
classFile = Parser(newClass);
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.getName);
source <- guessSourcePath(sourceMap, classFile, log))
{
analysis.beginSource(source)
analysis.generatedClass(source, newClass, classFile.className)
productToSource(newClass) = source
sourceToClassFiles.getOrElseUpdate(source, new ArrayBuffer[ClassFile]) += classFile
}
// get class to class dependencies and map back to source to class dependencies
for( (source, classFiles) <- sourceToClassFiles )
// get class to class dependencies and map back to source to class dependencies
for( (source, classFiles) <- sourceToClassFiles )
{
def processDependency(tpe: String)
{
def processDependency(tpe: String)
trapAndLog(log)
{
trapAndLog(log)
for (url <- Option(loader.getResource(tpe.replace('.', '/') + ClassExt)); file <- IO.urlAsFile(url))
{
for (url <- Option(loader.getResource(tpe.replace('.', '/') + ClassExt)); file <- IO.urlAsFile(url))
if(url.getProtocol == "jar")
analysis.binaryDependency(file, tpe, source)
else
{
if(url.getProtocol == "jar")
analysis.binaryDependency(file, tpe, source)
else
assume(url.getProtocol == "file")
productToSource.get(file) match
{
assume(url.getProtocol == "file")
productToSource.get(file) match
{
case Some(dependsOn) => analysis.sourceDependency(dependsOn, source)
case None => analysis.binaryDependency(file, tpe, source)
}
case Some(dependsOn) => analysis.sourceDependency(dependsOn, source)
case None => analysis.binaryDependency(file, tpe, source)
}
}
}
}
}
classFiles.flatMap(_.types).toSet.foreach(processDependency)
readAPI(source, classFiles.toSeq.flatMap(c => load(c.className, Some("Error reading API from class file") )))
analysis.endSource(source)
}
for( source <- sources filterNot sourceToClassFiles.keySet ) {
analysis.beginSource(source)
analysis.api(source, new xsbti.api.SourceAPI(Array(), Array()))
analysis.endSource(source)
}
classFiles.flatMap(_.types).toSet.foreach(processDependency)
readAPI(source, classFiles.toSeq.flatMap(c => load(c.className, Some("Error reading API from class file") )))
analysis.endSource(source)
}
for( source <- sources filterNot sourceToClassFiles.keySet ) {
analysis.beginSource(source)
analysis.api(source, new xsbti.api.SourceAPI(Array(), Array()))
analysis.endSource(source)
}
compile
analyze()
}
private def trapAndLog(log: Logger)(execute: => Unit)
{