fix tests, discovery

updated compile tests for new minimal AnalysisCallback
moved discovery to discovery/ subproject and updated for new approach
fixed discovery to only find public methods when searching for annotated definitions
extracting inherited definitions unimplemented in api/, so some discovery tests fail
moved discovery classes from sbt.inc package to sbt.compile
This commit is contained in:
Mark Harrah 2010-10-06 08:24:13 -04:00
parent b6ff9d8661
commit a3f1b9c22f
19 changed files with 219 additions and 187 deletions

View File

@ -2,7 +2,7 @@
* Copyright 2010 Mark Harrah
*/
package sbt
package inc
package compile
final case class Discovered(baseClasses: Set[String], annotations: Set[String], hasMain: Boolean, isModule: Boolean)
{

View File

@ -2,7 +2,7 @@
* Copyright 2010 Mark Harrah
*/
package sbt
package inc
package compile
import xsbti.api.{Path => APath, _}
@ -23,14 +23,14 @@ class Discovery(baseClasses: Set[String], annotations: Set[String])
val onClass = findAnnotations(c.annotations)
val onDefs = defAnnotations(c.structure.declared) ++ defAnnotations(c.structure.inherited)
val module = isModule(c)
new Discovered( bases(c.structure.parents), onClass ++ onDefs, module && hasMainMethod(c), module )
new Discovered( bases(c.name, c.structure.parents), onClass ++ onDefs, module && hasMainMethod(c), module )
}
def bases(c: Seq[Type]): Set[String] =
c.flatMap(simpleName).filter(baseClasses).toSet
def bases(own: String, c: Seq[Type]): Set[String] =
(own +: c.flatMap(simpleName)).filter(baseClasses).toSet
def findAnnotations(as: Seq[Annotation]): Set[String] =
as.flatMap { a => simpleName(a.base).filter(annotations) }.toSet
def defAnnotations(defs: Seq[Definition]): Set[String] =
findAnnotations( defs.flatMap { case d: Def => d.annotations.toSeq; case _ => Nil } )
findAnnotations( defs.flatMap { case d: Def if isPublic(d) => d.annotations.toSeq; case _ => Nil } )
}
object Discovery
{
@ -39,6 +39,8 @@ object Discovery
val d = new Discovery(subclasses, annotations)
d(definitions)
}
def applications(definitions: Seq[Definition]): Seq[(Definition, Discovered)] =
apply(Set.empty, Set.empty)( definitions )
def isConcrete(a: Definition): Boolean = isConcrete(a.modifiers)
def isConcrete(m: Modifiers) = !m.isAbstract && !m.isDeferred

View File

@ -1,8 +1,9 @@
package xsbt
package sbt
package compile
import java.io.File
import java.net.URLClassLoader
import org.specs.Specification
import java.io.File
import java.net.URLClassLoader
import org.specs.Specification
/** Verifies that the analyzer plugin properly detects main methods. The main method must be
* public with the right signature and be defined on a public, top-level module.*/
@ -104,16 +105,24 @@ object ApplicationsTest extends Specification
"Analysis plugin should detect applications" in {
WithFiles(sources : _*) { case files @ Seq(main, main2, main3, main4, main5, main6, main7, main8, main9, mainA, mainB, mainC, mainD, mainE, mainF) =>
for(scalaVersion <- TestCompile.allVersions)
CallbackTest(scalaVersion, files, Nil, Nil) { (callback, file, scalaInstance, log) =>
val expected = Seq( main -> "Main", main4 -> "Main4", main8 -> "Main8", main9 -> "Main9", mainB -> "MainB",
CallbackTest.full(scalaVersion, files) { (callback, file, scalaInstance, log) =>
val expected = Set( main -> "Main", main4 -> "Main4", main8 -> "Main8", main9 -> "Main9", mainB -> "MainB",
mainE -> "MainE1", mainE -> "MainE2", mainE -> "MainE3", mainE -> "MainE4", mainE -> "MainE5",
mainF -> "MainF1", mainF -> "MainF2", mainF -> "MainF4")
(callback.applications) must haveTheSameElementsAs(expected)
val actual = applications(callback).toSet
(actual -- expected) must beEmpty
(expected -- actual) must beEmpty
val loader = new URLClassLoader(Array(file.toURI.toURL), scalaInstance.loader)
for( (_, className) <- expected) testRun(loader, className)
}
}
}
def applications(callback: xsbti.TestCallback): Seq[(File, String)] =
for( (file, api) <- callback.apis.toSeq; application <- applications(api))
yield (file, application)
def applications(src: xsbti.api.Source): Seq[String] =
Discovery.applications(src.definitions) collect { case (definition, Discovered(_, _, true, _)) => definition.name }
private def testRun(loader: ClassLoader, className: String)
{
val obj = Class.forName(className, true, loader)

View File

@ -1,7 +1,8 @@
package xsbt
package sbt
package compile
import java.io.File
import org.specs.Specification
import java.io.File
import org.specs.Specification
object DetectAnnotations extends Specification
{
@ -32,20 +33,30 @@ object DetectAnnotations extends Specification
{
case files @ Seq(a, b, c, sup1File, sup2File, sup3File, sup4File, midFile, sub1File, sub2File, sub3File, sub4File, sub5File, sub6File, sub7File, sub8File, sub9File, subAFile, subBFile) =>
for(scalaVersion <- TestCompile.allVersions)
CallbackTest(scalaVersion, files, Nil, Seq("c.A", "B", "d.C") ) { (callback, _, _, _) =>
CallbackTest.simple(scalaVersion, files) { callback =>
val expected =
(sup3File, "Super3", "B", false) ::
(sub3File, "Sub3", "B", false) ::
(sub3File, "Sub3", "c.A", false) ::
(sub7File, "Sub7", "d.C", false) ::
(sub8File, "Sub8", "c.A", false) ::
(sub9File, "Sub9", "B", true) ::
(subAFile, "SubA", "c.A", true) ::
(subBFile, "SubB", "c.A", true) ::
(subBFile, "SubB", "d.C", false) ::
(sup3File, "Super3", Set("B"), false) ::
(sub3File, "Sub3", Set("B", "c.A"), false) ::
(sub7File, "Sub7", Set("d.C"), false) ::
(sub8File, "Sub8", Set("c.A"), false) ::
(sub9File, "Sub9", Set("B"), true) ::
(subAFile, "SubA", Set("c.A"), true) ::
(subBFile, "SubB", Set("c.A"), true) ::
(subBFile, "SubB", Set("d.C"), false) ::
Nil
(callback.foundAnnotated) must haveTheSameElementsAs(expected)
val actual = subclasses(callback).toSet
val actualOnly = (actual -- expected)
println("Actual: " + actualOnly)
val expectedOnly = (expected.toSet -- actual)
println("Expected: " + expectedOnly)
expectedOnly must beEmpty
actualOnly must beEmpty
}
}
}
def subclasses(callback: xsbti.TestCallback): Seq[(File, String, Set[String], Boolean)] =
for( (file, src) <- callback.apis.toSeq; (definition, discovered) <- Discovery(Set.empty, annotationNames)(src.definitions) if !discovered.isEmpty ) yield
(file, definition.name, discovered.annotations, discovered.isModule)
def annotationNames = Set("c.A", "B", "d.C")
}

View File

@ -0,0 +1,42 @@
package sbt
package compile
import java.io.File
import org.specs.Specification
object DetectSubclasses extends Specification
{
val sources =
("a/Super.scala" -> "package a; trait Super") ::
("a/Super2.scala" -> "class Super2") ::
("b/Middle.scala" -> "package y.w; trait Mid extends a.Super") ::
("b/Sub1.scala" -> "package a; class Sub1 extends y.w.Mid") ::
("b/Sub2.scala" -> "final class Sub2 extends a.Super") ::
("Sub3.scala" -> "private class F extends a.Super; package c { object Sub3 extends Super2 }") ::
Nil
"Analysis plugin should detect subclasses" in {
WithFiles(sources.map{case (file, content) => (new File(file), content)} : _*)
{
case files @ Seq(supFile, sup2File, midFile, sub1File, sub2File, sub3File) =>
for(scalaVersion <- TestCompile.allVersions)
CallbackTest.simple(scalaVersion, files) { callback =>
val expected =
(sub1File, "a.Sub1", Set("a.Super"), false) ::
(sub2File, "Sub2", Set("a.Super"), false) ::
(sup2File, "Super2", Set("Super2"), false) ::
(sub3File, "c.Sub3", Set("Super2"), true) ::
Nil
val actual = subclasses(callback).toSet
val actualOnly = actual -- expected
val expectedOnly = expected.toSet -- actual
assert(actualOnly.isEmpty, "Actual only: " + actualOnly)
assert(expectedOnly.isEmpty , "Expected only: " + expectedOnly)
}
}
}
def subclasses(callback: xsbti.TestCallback): Seq[(File, String, Set[String], Boolean)] =
for( (file, src) <- callback.apis.toSeq; (definition, discovered) <- Discovery(subclassNames, Set.empty)(src.definitions) if !discovered.isEmpty ) yield
(file, definition.name, discovered.baseClasses, discovered.isModule)
def subclassNames = Set( "a.Super", "Super2", "x.Super3", "Super4")
}

View File

@ -1,7 +1,8 @@
package xsbt
package sbt
package compile
import java.io.File
import org.specs.Specification
import java.io.File
import org.specs.Specification
object CheckBasic extends Specification
{
@ -21,9 +22,9 @@ object CheckBasic extends Specification
WithFiles(basicName -> basicSource){ files =>
for(scalaVersion <- TestCompile.allVersions)
{
FileUtilities.withTemporaryDirectory { outputDirectory =>
IO.withTemporaryDirectory { outputDirectory =>
WithCompiler(scalaVersion) { (compiler, log) =>
compiler.doc(Set() ++ files, Set.empty, outputDirectory, Nil, 5, log)
compiler.doc(files.toSeq, Nil, outputDirectory, Nil, 5, log)
}
}
true must beTrue // don't know how to just check that previous line completes without exception
@ -33,7 +34,7 @@ object CheckBasic extends Specification
"Analyzer plugin should send source begin and end" in {
WithFiles(basicName -> basicSource) { files =>
for(scalaVersion <- TestCompile.allVersions)
CallbackTest(scalaVersion, files) { callback =>
CallbackTest.simple(scalaVersion, files) { callback =>
(callback.beganSources) must haveTheSameElementsAs(files)
(callback.endedSources) must haveTheSameElementsAs(files)
}

View File

@ -1,10 +1,9 @@
package xsbt
package sbt
package compile
import sbt.{ComponentManager, TestIvyLogger}
import java.io.File
import FileUtilities.withTemporaryDirectory
import org.specs._
import java.io.File
import IO.withTemporaryDirectory
import org.specs._
object CompileTest extends Specification
{
@ -15,8 +14,8 @@ object CompileTest extends Specification
WithCompiler( "2.7.4" )(testCompileAnalysis)
WithCompiler( "2.7.5" )(testCompileAnalysis)
WithCompiler( "2.7.7" )(testCompileAnalysis)
WithCompiler( "2.8.0.Beta1" )(testCompileAnalysis)
WithCompiler( "2.8.0-SNAPSHOT" )(testCompileAnalysis)
WithCompiler( "2.8.0" )(testCompileAnalysis)
WithCompiler( "2.8.1.RC2" )(testCompileAnalysis)
}
}
@ -24,16 +23,17 @@ object CompileTest extends Specification
"Properly handle classpaths" in {
testClasspath("2.7.2")
testClasspath("2.7.7")
testClasspath("2.8.0.Beta1")
testClasspath("2.8.0")
testClasspath("2.8.1.RC2")
}
}
private def testCompileAnalysis(compiler: AnalyzingCompiler, log: CompileLogger)
private def testCompileAnalysis(compiler: AnalyzingCompiler, log: Logger)
{
WithFiles( new File("Test.scala") -> "object Test" ) { sources =>
withTemporaryDirectory { temp =>
val callback = new xsbti.TestCallback(Array(), Array())
compiler(Set() ++ sources, Set.empty, temp, Nil, callback, 10, log)
val callback = new xsbti.TestCallback
compiler(sources, Nil, temp, Nil, callback, 10, log)
(callback.beganSources) must haveTheSameElementsAs(sources)
}
}
@ -52,66 +52,31 @@ object CompileTest extends Specification
def compiler(autoBoot: Boolean, compilerOnClasspath: Boolean): RawCompiler =
new RawCompiler(ScalaInstance(scalaVersion, launch), new ClasspathOptions(autoBoot, compilerOnClasspath, true), log)
val callback = new xsbti.TestCallback(Array(), Array())
val callback = new xsbti.TestCallback
val standard = compiler(true, true)
val noCompiler = compiler(true, false)
val fullExplicit = compiler(false, false)
val fullBoot = "-bootclasspath" :: fullExplicit.compilerArguments.createBootClasspath :: Nil
val withCompiler = Set() + noCompiler.scalaInstance.compilerJar
val withCompiler = noCompiler.scalaInstance.compilerJar :: Nil
WithFiles( new File("Test.scala") -> "object Test", new File("Test2.scala") -> UsingCompiler ) { case Array(plain, useCompiler) =>
val plainSrcs = Set[File](plain)
val compSrcs = Set[File](useCompiler)
FileUtilities.withTemporaryDirectory { out =>
standard(plainSrcs, Set.empty, out, Nil) //success
standard(compSrcs, Set.empty, out, Nil) //success
WithFiles( new File("Test.scala") -> "object Test", new File("Test2.scala") -> UsingCompiler ) { case Seq(plain, useCompiler) =>
val plainSrcs = Seq[File](plain)
val compSrcs = Seq[File](useCompiler)
withTemporaryDirectory { out =>
standard(plainSrcs, Nil, out, Nil) //success
standard(compSrcs, Nil, out, Nil) //success
noCompiler(plainSrcs, Set.empty, out, Nil) //success
shouldFail( noCompiler(compSrcs, Set.empty, out, Nil) )
noCompiler(compSrcs, withCompiler, out, Nil) //success
noCompiler(plainSrcs, Nil, out, Nil) //success
shouldFail( noCompiler(compSrcs, Nil, out, Nil) )
noCompiler(compSrcs, withCompiler, out, Nil) //success
shouldFail( fullExplicit(plainSrcs, Set.empty, out, Nil) )// failure
shouldFail( fullExplicit(compSrcs, Set.empty, out, Nil) )// failure
fullExplicit(plainSrcs, Set.empty, out, fullBoot) // success
shouldFail( fullExplicit(plainSrcs, Nil, out, Nil) )// failure
shouldFail( fullExplicit(compSrcs, Nil, out, Nil) )// failure
fullExplicit(plainSrcs, Nil, out, fullBoot) // success
fullExplicit(compSrcs, withCompiler, out, fullBoot) // success
}
}
}
}
object WithCompiler
{
def apply[T](scalaVersion: String)(f: (AnalyzingCompiler, CompileLogger) => T): T =
{
launcher { (launch, log) =>
FileUtilities.withTemporaryDirectory { componentDirectory =>
val manager = new ComponentManager(xsbt.boot.Locks, new boot.ComponentProvider(componentDirectory), log)
val compiler = new AnalyzingCompiler(ScalaInstance(scalaVersion, launch), manager, log)
compiler.newComponentCompiler(log).clearCache(ComponentCompiler.compilerInterfaceID)
define(manager, ComponentCompiler.compilerInterfaceSrcID, getResource("CompilerInterface.scala"), getClassResource(classOf[jline.Completor]))
define(manager, ComponentCompiler.xsbtiID, getClassResource(classOf[xsbti.AnalysisCallback]))
f(compiler, log)
}
}
}
def launcher[T](f: (xsbti.Launcher, TestIvyLogger with CompileLogger) => T): T =
{
val log = new TestIvyLogger with CompileLogger
log.setLevel(Level.Debug)
log.bufferQuietly {
boot.LaunchTest.withLauncher { launch => f(launch, log) }
}
}
def getClassResource(resource: Class[_]): File = FileUtilities.classLocationFile(resource)
def getResource(resource: String): File =
{
val src = getClass.getClassLoader.getResource(resource)
if(src ne null) FileUtilities.asFile(src) else error("Resource not found: " + resource)
}
def define(manager: ComponentManager, id: String, files: File*)
{
manager.clearCache(id)
manager.define(id, files)
}
}

View File

@ -1,34 +0,0 @@
package xsbt
import java.io.File
import org.specs.Specification
object DetectSubclasses extends Specification
{
val sources =
("a/Super.scala" -> "package a; trait Super") ::
("a/Super2.scala" -> "class Super2") ::
("b/Middle.scala" -> "package y.w; trait Mid extends a.Super") ::
("b/Sub1.scala" -> "package a; class Sub1 extends y.w.Mid") ::
("b/Sub2.scala" -> "final class Sub2 extends a.Super") ::
("Sub3.scala" -> "private class F extends a.Super; package c { object Sub3 extends Super2 }") ::
Nil
"Analysis plugin should detect subclasses" in {
WithFiles(sources.map{case (file, content) => (new File(file), content)} : _*)
{
case files @ Seq(supFile, sup2File, midFile, sub1File, sub2File, sub3File) =>
for(scalaVersion <- TestCompile.allVersions)
CallbackTest(scalaVersion, files, Seq( "a.Super", "Super2", "x.Super3", "Super4"), Nil ) { (callback, _, _, _) =>
val expected =
(sub1File, "a.Sub1", "a.Super", false) ::
(sub2File, "Sub2", "a.Super", false) ::
(sup2File, "Super2", "Super2", false) ::
(sub3File, "c.Sub3", "Super2", true) ::
Nil
(callback.foundSubclasses) must haveTheSameElementsAs(expected)
(callback.invalidSuperclasses) must haveTheSameElementsAs(Seq("x.Super3", "Super4"))
}
}
}
}

View File

@ -1,36 +1,37 @@
package xsbt
package sbt
package compile
import java.io.File
import java.net.URLClassLoader
import xsbti.TestCallback
import FileUtilities.withTemporaryDirectory
import java.io.File
import java.net.URLClassLoader
import xsbti.TestCallback
import IO.withTemporaryDirectory
object TestCompile
{
// skip 2.7.3 and 2.7.4 for speed
def allVersions = List("2.7.2", "2.7.5", "2.7.7", "2.8.0.Beta1", "2.8.0-SNAPSHOT")//List("2.7.2", "2.7.3", "2.7.4", "2.7.5", "2.8.0-SNAPSHOT")
def allVersions = List("2.8.0")//List("2.7.2", "2.7.5", "2.7.7", "2.8.0", "2.8.1.RC1")
/** Tests running the compiler interface with the analyzer plugin with a test callback. The test callback saves all information
* that the plugin sends it for post-compile analysis by the provided function.*/
def apply[T](scalaVersion: String, sources: Set[File], outputDirectory: File, options: Seq[String], superclassNames: Seq[String], annotationNames: Seq[String])
(f: (TestCallback, ScalaInstance, CompileLogger) => T): T =
def apply[T](scalaVersion: String, sources: Seq[File], outputDirectory: File, options: Seq[String])
(f: (TestCallback, ScalaInstance, Logger) => T): T =
{
val testCallback = new TestCallback(superclassNames.toArray, annotationNames.toArray)
val testCallback = new TestCallback
WithCompiler(scalaVersion) { (compiler, log) =>
compiler(sources, Set.empty, outputDirectory, options, testCallback, 5, log)
compiler(sources, Nil, outputDirectory, options, testCallback, 5, log)
f(testCallback, compiler.scalaInstance, log)
}
}
/** Tests running the compiler interface with the analyzer plugin. The provided function is given a ClassLoader that can
* load the compiled classes..*/
def apply[T](scalaVersion: String, sources: Seq[File])(f: ClassLoader => T): T =
CallbackTest.apply(scalaVersion, sources, Nil, Nil){ case (_, outputDir, _, _) => f(new URLClassLoader(Array(outputDir.toURI.toURL))) }
CallbackTest.full(scalaVersion, sources){ case (_, outputDir, _, _) => f(new URLClassLoader(Array(outputDir.toURI.toURL))) }
}
object CallbackTest
{
def apply[T](scalaVersion: String, sources: Iterable[File])(f: TestCallback => T): T =
apply(scalaVersion, sources.toSeq, Nil, Nil){ case (callback, _, _, _) => f(callback) }
def apply[T](scalaVersion: String, sources: Seq[File], superclassNames: Seq[String], annotationNames: Seq[String])(f: (TestCallback, File, ScalaInstance, CompileLogger) => T): T =
def simple[T](scalaVersion: String, sources: Seq[File])(f: TestCallback => T): T =
full(scalaVersion, sources){ case (callback, _, _, _) => f(callback) }
def full[T](scalaVersion: String, sources: Seq[File])(f: (TestCallback, File, ScalaInstance, Logger) => T): T =
withTemporaryDirectory { outputDir =>
TestCompile(scalaVersion, Set() ++ sources, outputDir, Nil, superclassNames, annotationNames) { case (callback, instance, log) => f(callback, outputDir, instance, log) }
TestCompile(scalaVersion, sources, outputDir, Nil) { case (callback, instance, log) => f(callback, outputDir, instance, log) }
}
}

View File

@ -0,0 +1,39 @@
package sbt
package compile
import xsbt.boot
import java.io.File
import IO.withTemporaryDirectory
object WithCompiler
{
def apply[T](scalaVersion: String)(f: (AnalyzingCompiler, Logger) => T): T =
{
launcher { (launch, log) =>
withTemporaryDirectory { componentDirectory =>
val manager = new ComponentManager(xsbt.boot.Locks, new boot.ComponentProvider(componentDirectory), log)
val compiler = new AnalyzingCompiler(ScalaInstance(scalaVersion, launch), manager, log)
compiler.newComponentCompiler(log).clearCache(ComponentCompiler.compilerInterfaceID)
define(manager, ComponentCompiler.compilerInterfaceSrcID, getResource("CompilerInterface.scala"), getClassResource(classOf[jline.Completor]))
define(manager, ComponentCompiler.xsbtiID, getClassResource(classOf[xsbti.AnalysisCallback]))
f(compiler, log)
}
}
}
def launcher[T](f: (xsbti.Launcher, Logger) => T): T =
TestLogger { log =>
boot.LaunchTest.withLauncher { launch => f(launch, log) }
}
def getClassResource(resource: Class[_]): File = IO.classLocationFile(resource)
def getResource(resource: String): File =
{
val src = getClass.getClassLoader.getResource(resource)
if(src ne null) IO.asFile(src) else error("Resource not found: " + resource)
}
def define(manager: ComponentManager, id: String, files: File*)
{
manager.clearCache(id)
manager.define(id, files)
}
}

View File

@ -1,34 +1,23 @@
package xsbti
import java.io.File
import scala.collection.mutable.ArrayBuffer
import java.io.File
import scala.collection.mutable.ArrayBuffer
class TestCallback(val superclassNames: Array[String], val annotationNames: Array[String]) extends AnalysisCallback
class TestCallback extends AnalysisCallback
{
val invalidSuperclasses = new ArrayBuffer[String]
val beganSources = new ArrayBuffer[File]
val endedSources = new ArrayBuffer[File]
val foundSubclasses = new ArrayBuffer[(File, String, String, Boolean)]
val foundAnnotated = new ArrayBuffer[(File, String, String, Boolean)]
val sourceDependencies = new ArrayBuffer[(File, File)]
val jarDependencies = new ArrayBuffer[(File, File)]
val classDependencies = new ArrayBuffer[(File, File)]
val productDependencies = new ArrayBuffer[(File, File)]
val binaryDependencies = new ArrayBuffer[(File, String, File)]
val products = new ArrayBuffer[(File, File)]
val applications = new ArrayBuffer[(File, String)]
val apis = new ArrayBuffer[(File, xsbti.api.Source)]
def superclassNotFound(superclassName: String) { invalidSuperclasses += superclassName }
def beginSource(source: File) { beganSources += source }
def foundSubclass(source: File, subclassName: String, superclassName: String, isModule: Boolean): Unit =
foundSubclasses += ((source, subclassName, superclassName, isModule))
def foundAnnotated(source: File, className: String, annotationName: String, isModule: Boolean): Unit =
foundAnnotated += ((source, className, annotationName, isModule))
def sourceDependency(dependsOn: File, source: File) { sourceDependencies += ((dependsOn, source)) }
def jarDependency(jar: File, source: File) { jarDependencies += ((jar, source)) }
def classDependency(clazz: File, source: File) { classDependencies += ((clazz, source)) }
def productDependency(clazz: File, source: File) { productDependencies += ((clazz, source)) }
def binaryDependency(binary: File, name: String, source: File) { binaryDependencies += ((binary, name, source)) }
def generatedClass(source: File, module: File) { products += ((source, module)) }
def endSource(source: File) { endedSources += source }
def foundApplication(source: File, className: String) { applications += ((source, className)) }
def api(source: File, sourceAPI: xsbti.api.Source) = ()
def api(source: File, sourceAPI: xsbti.api.Source) { apis += ((source, sourceAPI)) }
}

View File

@ -77,5 +77,5 @@ object ComponentManagerTest extends Specification
private def writeRandomContent(file: File) = IO.write(file, randomString)
private def randomString = "asdf"
private def withManager[T](f: ComponentManager => T): T =
TestIvyLogger( logger => withTemporaryDirectory { temp => f(new ComponentManager(xsbt.boot.Locks, new xsbt.boot.ComponentProvider(temp), logger)) } )
TestLogger( logger => withTemporaryDirectory { temp => f(new ComponentManager(xsbt.boot.Locks, new xsbt.boot.ComponentProvider(temp), logger)) } )
}

View File

@ -1,12 +0,0 @@
package sbt
class TestIvyLogger extends BufferedLogger(new ConsoleLogger) with IvyLogger
object TestIvyLogger
{
def apply[T](f: IvyLogger => T): T =
{
val log = new TestIvyLogger
log.setLevel(Level.Debug)
log.bufferQuietly(f(log))
}
}

View File

@ -4,7 +4,8 @@
package sbt
import std._
import inc.{Analysis,Discovered,Discovery}
import compile.{Discovered,Discovery}
import inc.Analysis
import TaskExtra._
import Configurations.{Compile => CompileConfig, Test => TestConfig, Runtime => RunConfig}
import ClasspathProject._

View File

@ -7,7 +7,7 @@ package build
import java.io.File
import classpath.ClasspathUtilities.toLoader
import ModuleUtilities.getObject
import compile.{AnalyzingCompiler, JavaCompiler}
import compile.{AnalyzingCompiler, Discovery, JavaCompiler}
import inc.Analysis
import Path._
import GlobFilter._
@ -91,14 +91,14 @@ object Build
import Auto.{Annotation, Explicit, Subclass}
auto match {
case Explicit => if(name.isEmpty) error("No name specified to load explicitly.") else Seq(new ToLoad(name))
case Subclass => discover(analysis, module, new inc.Discovery(Set(name), Set.empty))
case Annotation => discover(analysis, module, new inc.Discovery(Set.empty, Set(name)))
case Subclass => discover(analysis, module, new Discovery(Set(name), Set.empty))
case Annotation => discover(analysis, module, new Discovery(Set.empty, Set(name)))
}
}
def discover(analysis: inc.Analysis, command: DiscoverCommand): Seq[ToLoad] =
discover(analysis, command.module, command.discovery)
def discover(analysis: inc.Analysis, module: Option[Boolean], discovery: inc.Discovery): Seq[ToLoad] =
def discover(analysis: inc.Analysis, module: Option[Boolean], discovery: Discovery): Seq[ToLoad] =
{
for(src <- analysis.apis.internal.values.toSeq;
(df, found) <- discovery(src.definitions) if !found.isEmpty && moduleMatches(found.isModule, module))

View File

@ -4,7 +4,8 @@
package sbt
package build
import java.io.File
import java.io.File
import compile.Discovery
sealed trait LoadCommand
final case class BinaryLoad(classpath: Seq[File], module: Boolean, name: String) extends LoadCommand
@ -17,7 +18,7 @@ object Auto extends Enumeration
}
final case class CompileCommand(classpath: Seq[File], sources: Seq[File], output: Option[File], options: Seq[String])
final case class DiscoverCommand(module: Option[Boolean], discovery: inc.Discovery)
final case class DiscoverCommand(module: Option[Boolean], discovery: Discovery)
final case class ToLoad(name: String, isModule: Boolean = false)
{

View File

@ -4,7 +4,8 @@
package sbt
package build
import java.io.File
import compile.Discovery
import java.io.File
final class ParseException(msg: String) extends RuntimeException(msg)
@ -72,7 +73,7 @@ The command has the following syntax:
val args = arguments(commandString)
val subs = names("sub", args)
val annots = names("annot", args)
DiscoverCommand(module(args), new inc.Discovery(subs, annots))
DiscoverCommand(module(args), new Discovery(subs, annots))
}
def auto(args: Seq[String]): Auto.Value =

View File

@ -66,13 +66,14 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
// Implements the core functionality of detecting and propagating changes incrementally.
// Defines the data structures for representing file fingerprints and relationships and the overall source analysis
val compileIncrementalSub = testedBase(compilePath / "inc", "Incremental Compiler", collectionSub, apiSub, ioSub)
// Searches the source API data structures, currently looks for subclasses and annotations
val discoverySub = testedBase(compilePath / "discover", "Discovery", compileIncrementalSub, apiSub)
// Persists the incremental data structures using SBinary
val compilePersistSub = project(compilePath / "persist", "Persist", new PersistProject(_), compileIncrementalSub, apiSub)
// sbt-side interface to compiler. Calls compiler-side interface reflectively
val compilerSub = project(compilePath, "Compile", new CompileProject(_),
launchInterfaceSub, interfaceSub, ivySub, ioSub, classpathSub, compileInterfaceSub, logSub)
// Searches the source API data structures, currently looks for subclasses and annotations
val discoverySub = project(compilePath / "discover", "Discovery", new DiscoveryProject(_), compileIncrementalSub, apiSub)
// mostly for implementing 'load' command, could perhaps be trimmed and merged into 'main'
val buildSub = baseProject("main" / "build", "Project Builder",
@ -216,6 +217,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
{
val testInterface = "org.scala-tools.testing" % "test-interface" % "0.5"
}
class DiscoveryProject(info: ProjectInfo) extends TestedBase(info) with TestWithCompile
class CompileProject(info: ProjectInfo) extends Base(info) with TestWithLog with TestWithLaunch
{
override def testCompileAction = super.testCompileAction dependsOn(compileInterfaceSub.`package`, interfaceSub.`package`)
@ -322,6 +324,9 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
override def projectClasspath(config: Configuration) = Path.emptyPathFinder
}
}
trait TestWithCompile extends TestWith {
override def testWithTestClasspath = super.testWithTestClasspath ++ Seq(compilerSub)
}
trait TestWithIO extends TestWith {
override def testWithTestClasspath = super.testWithTestClasspath ++ Seq(ioSub)
}

View File

@ -0,0 +1,11 @@
package sbt
object TestLogger
{
def apply[T](f: Logger => T): T =
{
val log = new BufferedLogger(ConsoleLogger())
log.setLevel(Level.Debug)
log.bufferQuietly(f(log))
}
}