mirror of https://github.com/sbt/sbt.git
Mostly working cross-compile task.
Analyzer plugin is now a proper internal phase to get around bootstrapping issues. Correctly handle source tags.
This commit is contained in:
parent
edca6620e4
commit
12c5f5a0d5
|
|
@ -6,6 +6,15 @@ import scala.reflect.Manifest
|
||||||
|
|
||||||
object CacheIO
|
object CacheIO
|
||||||
{
|
{
|
||||||
|
def toBytes[T](format: Format[T])(value: T)(implicit mf: Manifest[Format[T]]): Array[Byte] =
|
||||||
|
toBytes[T](value)(format, mf)
|
||||||
|
def toBytes[T](value: T)(implicit format: Format[T], mf: Manifest[Format[T]]): Array[Byte] =
|
||||||
|
Operations.toByteArray(value)(stampedFormat(format))
|
||||||
|
def fromBytes[T](format: Format[T], default: => T)(bytes: Array[Byte])(implicit mf: Manifest[Format[T]]): T =
|
||||||
|
fromBytes(default)(bytes)(format, mf)
|
||||||
|
def fromBytes[T](default: => T)(bytes: Array[Byte])(implicit format: Format[T], mf: Manifest[Format[T]]): T =
|
||||||
|
if(bytes.isEmpty) default else Operations.fromByteArray(bytes)(stampedFormat(format))
|
||||||
|
|
||||||
def fromFile[T](format: Format[T], default: => T)(file: File)(implicit mf: Manifest[Format[T]]): T =
|
def fromFile[T](format: Format[T], default: => T)(file: File)(implicit mf: Manifest[Format[T]]): T =
|
||||||
fromFile(file, default)(format, mf)
|
fromFile(file, default)(format, mf)
|
||||||
def fromFile[T](file: File, default: => T)(implicit format: Format[T], mf: Manifest[Format[T]]): T =
|
def fromFile[T](file: File, default: => T)(implicit format: Format[T], mf: Manifest[Format[T]]): T =
|
||||||
|
|
|
||||||
|
|
@ -37,17 +37,17 @@ class AnalyzeCompiler(scalaVersion: String, scalaLoader: ClassLoader, manager: C
|
||||||
* and used to load the class that actually interfaces with Global.*/
|
* and used to load the class that actually interfaces with Global.*/
|
||||||
def apply(arguments: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger)
|
def apply(arguments: Seq[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger)
|
||||||
{
|
{
|
||||||
|
println("Compiling: " + arguments)
|
||||||
// this is the instance used to compile the analysis
|
// this is the instance used to compile the analysis
|
||||||
val componentCompiler = new ComponentCompiler(scalaVersion, new RawCompiler(scalaLoader), manager)
|
val componentCompiler = new ComponentCompiler(scalaVersion, new RawCompiler(scalaLoader), manager)
|
||||||
val interfaceJar = componentCompiler(ComponentCompiler.compilerInterfaceID)
|
val interfaceJar = componentCompiler(ComponentCompiler.compilerInterfaceID)
|
||||||
val argsWithPlugin = ("-Xplugin:" + interfaceJar.getAbsolutePath) :: arguments.toList
|
|
||||||
val dual = createDualLoader(scalaLoader, getClass.getClassLoader) // this goes to scalaLoader for scala classes and sbtLoader for xsbti classes
|
val dual = createDualLoader(scalaLoader, getClass.getClassLoader) // this goes to scalaLoader for scala classes and sbtLoader for xsbti classes
|
||||||
val interfaceLoader = new URLClassLoader(Array(interfaceJar.toURI.toURL), dual)
|
val interfaceLoader = new URLClassLoader(Array(interfaceJar.toURI.toURL), dual)
|
||||||
val interface = Class.forName("xsbt.CompilerInterface", true, interfaceLoader).newInstance
|
val interface = Class.forName("xsbt.CompilerInterface", true, interfaceLoader).newInstance
|
||||||
val runnable = interface.asInstanceOf[{ def run(args: Array[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger): Unit }]
|
val runnable = interface.asInstanceOf[{ def run(args: Array[String], callback: AnalysisCallback, maximumErrors: Int, log: Logger): Unit }]
|
||||||
// these arguments are safe to pass across the ClassLoader boundary because the types are defined in Java
|
// these arguments are safe to pass across the ClassLoader boundary because the types are defined in Java
|
||||||
// so they will be binary compatible across all versions of Scala
|
// so they will be binary compatible across all versions of Scala
|
||||||
runnable.run(argsWithPlugin.toArray, callback, maximumErrors, log)
|
runnable.run(arguments.toArray, callback, maximumErrors, log)
|
||||||
}
|
}
|
||||||
private def createDualLoader(scalaLoader: ClassLoader, sbtLoader: ClassLoader): ClassLoader =
|
private def createDualLoader(scalaLoader: ClassLoader, sbtLoader: ClassLoader): ClassLoader =
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,46 +10,21 @@ import symtab.Flags
|
||||||
import scala.collection.mutable.{HashMap, HashSet, Map, Set}
|
import scala.collection.mutable.{HashMap, HashSet, Map, Set}
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import xsbti.{AnalysisCallback, AnalysisCallbackContainer}
|
import xsbti.AnalysisCallback
|
||||||
|
|
||||||
class Analyzer(val global: Global) extends Plugin
|
object Analyzer
|
||||||
|
{
|
||||||
|
def name = "xsbt-analyzer"
|
||||||
|
}
|
||||||
|
final class Analyzer(val global: Global, val callback: AnalysisCallback) extends NotNull
|
||||||
{
|
{
|
||||||
val callback = global.asInstanceOf[AnalysisCallbackContainer].analysisCallback
|
|
||||||
|
|
||||||
import global._
|
import global._
|
||||||
|
|
||||||
val name = "xsbt-analyze"
|
def newPhase(prev: Phase): Phase = new AnalyzerPhase(prev)
|
||||||
val description = "A plugin to find all concrete instances of a given class and extract dependency information."
|
|
||||||
val components = List[PluginComponent](Component)
|
|
||||||
|
|
||||||
/* ================================================== */
|
|
||||||
// These two templates abuse scope for source compatibility between Scala 2.7.x and 2.8.x so that a single
|
|
||||||
// sbt codebase compiles with both series of versions.
|
|
||||||
// In 2.8.x, PluginComponent.runsAfter has type List[String] and the method runsBefore is defined on
|
|
||||||
// PluginComponent with default value Nil.
|
|
||||||
// In 2.7.x, runsBefore does not exist on PluginComponent and PluginComponent.runsAfter has type String.
|
|
||||||
//
|
|
||||||
// Therefore, in 2.8.x, object runsBefore is shadowed by PluginComponent.runsBefore (which is Nil) and so
|
|
||||||
// afterPhase :: runsBefore
|
|
||||||
// is equivalent to List[String](afterPhase)
|
|
||||||
// In 2.7.x, object runsBefore is not shadowed and so runsAfter has type String.
|
|
||||||
private object runsBefore { def :: (s: String) = s }
|
|
||||||
private abstract class CompatiblePluginComponent(afterPhase: String) extends PluginComponent
|
|
||||||
{
|
|
||||||
override val runsAfter = afterPhase :: runsBefore
|
|
||||||
}
|
|
||||||
/* ================================================== */
|
|
||||||
|
|
||||||
private object Component extends CompatiblePluginComponent("jvm")
|
|
||||||
{
|
|
||||||
val global = Analyzer.this.global
|
|
||||||
val phaseName = Analyzer.this.name
|
|
||||||
def newPhase(prev: Phase) = new AnalyzerPhase(prev)
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AnalyzerPhase(prev: Phase) extends Phase(prev)
|
private class AnalyzerPhase(prev: Phase) extends Phase(prev)
|
||||||
{
|
{
|
||||||
def name = Analyzer.this.name
|
override def description = "A plugin to find all concrete instances of a given class and extract dependency information."
|
||||||
|
def name = Analyzer.name
|
||||||
def run
|
def run
|
||||||
{
|
{
|
||||||
val outputDirectory = new File(global.settings.outdir.value)
|
val outputDirectory = new File(global.settings.outdir.value)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
*/
|
*/
|
||||||
package xsbt
|
package xsbt
|
||||||
|
|
||||||
import xsbti.{AnalysisCallback,AnalysisCallbackContainer,Logger}
|
import xsbti.{AnalysisCallback,Logger}
|
||||||
|
import scala.tools.nsc.{Phase, SubComponent}
|
||||||
|
|
||||||
class CompilerInterface
|
class CompilerInterface
|
||||||
{
|
{
|
||||||
|
|
@ -14,10 +15,28 @@ class CompilerInterface
|
||||||
val reporter = new LoggerReporter(maximumErrors, log)
|
val reporter = new LoggerReporter(maximumErrors, log)
|
||||||
val settings = new Settings(reporter.error)
|
val settings = new Settings(reporter.error)
|
||||||
val command = new CompilerCommand(args.toList, settings, error, false)
|
val command = new CompilerCommand(args.toList, settings, error, false)
|
||||||
|
|
||||||
object compiler extends Global(command.settings, reporter) with AnalysisCallbackContainer
|
object compiler extends Global(command.settings, reporter)
|
||||||
{
|
{
|
||||||
def analysisCallback = callback
|
object sbtAnalyzer extends
|
||||||
|
{
|
||||||
|
val global: compiler.type = compiler
|
||||||
|
val phaseName = Analyzer.name
|
||||||
|
val runsAfter = List("jvm")
|
||||||
|
val runsRightAfter = None
|
||||||
|
}
|
||||||
|
with SubComponent
|
||||||
|
{
|
||||||
|
val analyzer = new Analyzer(global, callback)
|
||||||
|
def newPhase(prev: Phase) = analyzer.newPhase(prev)
|
||||||
|
def name = phaseName
|
||||||
|
}
|
||||||
|
override protected def builtInPhaseDescriptors() = (super.builtInPhaseDescriptors ++ Seq(sbtAnalyzer))
|
||||||
|
/*override protected def computeInternalPhases()
|
||||||
|
{
|
||||||
|
super.computeInternalPhases()
|
||||||
|
phasesSet += sbtAnalyzer
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
if(!reporter.hasErrors)
|
if(!reporter.hasErrors)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<plugin>
|
|
||||||
<name>xsbt-analyze</name>
|
|
||||||
<classname>xsbt.Analyzer</classname>
|
|
||||||
</plugin>
|
|
||||||
|
|
@ -3,7 +3,7 @@ package xsbt
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import xsbti.{Logger, TestCallback, TestLogger}
|
import xsbti.{Logger, TestCallback, TestLogger}
|
||||||
import FileUtilities.{classLocationFile, withTemporaryDirectory, write}
|
import FileUtilities.withTemporaryDirectory
|
||||||
|
|
||||||
object TestCompile
|
object TestCompile
|
||||||
{
|
{
|
||||||
|
|
@ -11,15 +11,10 @@ object TestCompile
|
||||||
* that the plugin sends it for post-compile analysis by the provided function.*/
|
* that the plugin sends it for post-compile analysis by the provided function.*/
|
||||||
def apply[T](arguments: Seq[String], superclassNames: Seq[String])(f: (TestCallback, Logger) => T): T =
|
def apply[T](arguments: Seq[String], superclassNames: Seq[String])(f: (TestCallback, Logger) => T): T =
|
||||||
{
|
{
|
||||||
val pluginLocation = classLocationFile[Analyzer]
|
|
||||||
assert(pluginLocation.exists)
|
|
||||||
val path = pluginLocation.getAbsolutePath
|
|
||||||
val pluginArg = if(pluginLocation.getName.endsWith(".jar")) List("-Xplugin:" + path) else List("-Xpluginsdir", path)
|
|
||||||
val testCallback = new TestCallback(superclassNames.toArray)
|
val testCallback = new TestCallback(superclassNames.toArray)
|
||||||
val i = new CompilerInterface
|
val i = new CompilerInterface
|
||||||
val newArgs = "-Xplugin-require:xsbt-analyze" :: pluginArg ::: arguments.toList
|
|
||||||
TestLogger { log =>
|
TestLogger { log =>
|
||||||
i.run(newArgs.toArray, testCallback, 5, log)
|
i.run(arguments.toArray, testCallback, 5, log)
|
||||||
f(testCallback, log)
|
f(testCallback, log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
/* sbt -- Simple Build Tool
|
|
||||||
* Copyright 2009 Mark Harrah
|
|
||||||
*/
|
|
||||||
package xsbti;
|
|
||||||
|
|
||||||
/** Provides access to an AnalysisCallback. This is used by the plugin to
|
|
||||||
* get the callback to use. The scalac Global instance it is passed must
|
|
||||||
* implement this interface. */
|
|
||||||
public interface AnalysisCallbackContainer
|
|
||||||
{
|
|
||||||
public AnalysisCallback analysisCallback();
|
|
||||||
}
|
|
||||||
|
|
@ -24,7 +24,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
||||||
val trackingSub = project(cachePath / "tracking", "Tracking", new Base(_), cacheSub)
|
val trackingSub = project(cachePath / "tracking", "Tracking", new Base(_), cacheSub)
|
||||||
val compilerSub = project(compilePath, "Compile", new CompileProject(_),
|
val compilerSub = project(compilePath, "Compile", new CompileProject(_),
|
||||||
launchInterfaceSub, interfaceSub, ivySub, ioSub, classpathSub, compileInterfaceSub)
|
launchInterfaceSub, interfaceSub, ivySub, ioSub, classpathSub, compileInterfaceSub)
|
||||||
val stdTaskSub = project(tasksPath / "standard", "Standard Tasks", new Base(_), trackingSub, compilerSub)
|
val stdTaskSub = project(tasksPath / "standard", "Standard Tasks", new StandardTaskProject(_), trackingSub, compilerSub)
|
||||||
|
|
||||||
/* Multi-subproject paths */
|
/* Multi-subproject paths */
|
||||||
|
|
||||||
|
|
@ -56,6 +56,10 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
||||||
val sp = "org.scala-tools.testing" % "specs" % "1.5.0" % "test->default"
|
val sp = "org.scala-tools.testing" % "specs" % "1.5.0" % "test->default"
|
||||||
val ju = "junit" % "junit" % "4.5" % "test->default" // required by specs to compile properly
|
val ju = "junit" % "junit" % "4.5" % "test->default" // required by specs to compile properly
|
||||||
}
|
}
|
||||||
|
class StandardTaskProject(info: ProjectInfo) extends Base(info)
|
||||||
|
{
|
||||||
|
override def testClasspath = super.testClasspath +++ compilerSub.testClasspath
|
||||||
|
}
|
||||||
|
|
||||||
class IOProject(info: ProjectInfo) extends Base(info) with TestDependencies
|
class IOProject(info: ProjectInfo) extends Base(info) with TestDependencies
|
||||||
class TaskProject(info: ProjectInfo) extends Base(info) with TestDependencies
|
class TaskProject(info: ProjectInfo) extends Base(info) with TestDependencies
|
||||||
|
|
@ -67,6 +71,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
||||||
class Base(info: ProjectInfo) extends DefaultProject(info) with ManagedBase
|
class Base(info: ProjectInfo) extends DefaultProject(info) with ManagedBase
|
||||||
{
|
{
|
||||||
override def scratch = true
|
override def scratch = true
|
||||||
|
override def consoleClasspath = testClasspath
|
||||||
}
|
}
|
||||||
class CompileProject(info: ProjectInfo) extends Base(info)
|
class CompileProject(info: ProjectInfo) extends Base(info)
|
||||||
{
|
{
|
||||||
|
|
@ -86,17 +91,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
||||||
override def mainSources = descendents(mainSourceRoots, "*.java")
|
override def mainSources = descendents(mainSourceRoots, "*.java")
|
||||||
override def compileOrder = CompileOrder.JavaThenScala
|
override def compileOrder = CompileOrder.JavaThenScala
|
||||||
}
|
}
|
||||||
class CompilerInterfaceProject(info: ProjectInfo) extends Base(info) with SourceProject
|
class CompilerInterfaceProject(info: ProjectInfo) extends Base(info) with SourceProject with TestWithIO
|
||||||
{
|
|
||||||
// these set up the test environment so that the classes and resources are both in the output resource directory
|
|
||||||
// the main compile path is removed so that the plugin (xsbt.Analyzer) is found in the output resource directory so that
|
|
||||||
// the tests can configure that directory as -Xpluginsdir (which requires the scalac-plugin.xml and the classes to be together)
|
|
||||||
override def testCompileAction = super.testCompileAction dependsOn(packageForTest, ioSub.testCompile)
|
|
||||||
override def mainResources = super.mainResources +++ "scalac-plugin.xml"
|
|
||||||
override def testClasspath = (super.testClasspath --- super.mainCompilePath) +++ ioSub.testClasspath +++ testPackagePath
|
|
||||||
def testPackagePath = outputPath / "test.jar"
|
|
||||||
lazy val packageForTest = packageTask(mainClasses +++ mainResources, testPackagePath, packageOptions).dependsOn(compile)
|
|
||||||
}
|
|
||||||
trait TestWithIO extends BasicScalaProject
|
trait TestWithIO extends BasicScalaProject
|
||||||
{
|
{
|
||||||
// use IO from tests
|
// use IO from tests
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ trait Compile extends TrackedTaskDefinition[CompileReport]
|
||||||
val newOpts = (opts: Seq[String]) => (opts, rawSourceChanges.markAllModified, rawClasspathChanges.markAllModified) // if options changed, mark everything changed
|
val newOpts = (opts: Seq[String]) => (opts, rawSourceChanges.markAllModified, rawClasspathChanges.markAllModified) // if options changed, mark everything changed
|
||||||
val sameOpts = (opts: Seq[String]) => (opts, rawSourceChanges, rawClasspathChanges)
|
val sameOpts = (opts: Seq[String]) => (opts, rawSourceChanges, rawClasspathChanges)
|
||||||
trackedOptions(newOpts, sameOpts) bind { // detect changes to options
|
trackedOptions(newOpts, sameOpts) bind { // detect changes to options
|
||||||
case (options, classpathChanges, sourceChanges) =>
|
case (options, sourceChanges, classpathChanges) =>
|
||||||
invalidation( classpathChanges +++ sourceChanges ) { (report, tracking) => // invalidation based on changes
|
invalidation( classpathChanges +++ sourceChanges ) { (report, tracking) => // invalidation based on changes
|
||||||
compile(sourceChanges, classpathChanges, options, report, tracking)
|
compile(sourceChanges, classpathChanges, options, report, tracking)
|
||||||
}
|
}
|
||||||
|
|
@ -40,26 +40,27 @@ class StandardCompile(val sources: Task[Set[File]], val classpath: Task[Set[File
|
||||||
val superclassNames: Task[Set[String]], val compilerTask: Task[AnalyzeCompiler], val cacheDirectory: File, val log: xsbti.Logger) extends Compile
|
val superclassNames: Task[Set[String]], val compilerTask: Task[AnalyzeCompiler], val cacheDirectory: File, val log: xsbti.Logger) extends Compile
|
||||||
{
|
{
|
||||||
import Task._
|
import Task._
|
||||||
import sbinary.{DefaultProtocol, Format, Operations}
|
|
||||||
import DefaultProtocol._
|
|
||||||
import Operations.{fromByteArray, toByteArray}
|
|
||||||
import scala.collection.mutable.{ArrayBuffer, Buffer, HashMap, HashSet, Map, Set => mSet}
|
import scala.collection.mutable.{ArrayBuffer, Buffer, HashMap, HashSet, Map, Set => mSet}
|
||||||
|
|
||||||
private implicit val subclassFormat: Format[DetectedSubclass] =
|
|
||||||
asProduct4(DetectedSubclass.apply)( ds => Some(ds.source, ds.subclassName, ds.superclassName, ds.isModule))
|
|
||||||
|
|
||||||
override def create = super.create dependsOn(superclassNames, compilerTask) // raise these dependencies to the top for parallelism
|
override def create = super.create dependsOn(superclassNames, compilerTask) // raise these dependencies to the top for parallelism
|
||||||
def compile(sourceChanges: ChangeReport[File], classpathChanges: ChangeReport[File], options: Seq[String], report: InvalidationReport[File], tracking: UpdateTracking[File]): Task[CompileReport] =
|
def compile(sourceChanges: ChangeReport[File], classpathChanges: ChangeReport[File], options: Seq[String], report: InvalidationReport[File], tracking: UpdateTracking[File]): Task[CompileReport] =
|
||||||
{
|
{
|
||||||
val sources = report.invalid ** sourceChanges.checked // determine the sources that need recompiling (report.invalid also contains classes and libraries)
|
val sources = report.invalid ** sourceChanges.checked // determine the sources that need recompiling (report.invalid also contains classes and libraries)
|
||||||
val classpath = classpathChanges.checked
|
val classpath = classpathChanges.checked
|
||||||
|
compile(sources, classpath, options, tracking)
|
||||||
|
}
|
||||||
|
def compile(sources: Set[File], classpath: Set[File], options: Seq[String], tracking: UpdateTracking[File]): Task[CompileReport] =
|
||||||
|
{
|
||||||
(compilerTask, superclassNames) map { (compiler, superClasses) =>
|
(compilerTask, superclassNames) map { (compiler, superClasses) =>
|
||||||
val callback = new CompileAnalysisCallback(superClasses.toArray, tracking)
|
if(!sources.isEmpty)
|
||||||
val arguments = Seq("-cp", abs(classpath).mkString(File.pathSeparator)) ++ options ++ abs(sources).toSeq
|
{
|
||||||
|
val callback = new CompileAnalysisCallback(superClasses.toArray, tracking)
|
||||||
compiler(arguments, callback, 100, log)
|
val classpathString = abs(classpath).mkString(File.pathSeparator)
|
||||||
|
val classpathOption = if(classpathString.isEmpty) Seq.empty else Seq("-cp", classpathString)
|
||||||
|
val arguments = classpathOption ++ options ++ abs(sources).toSeq
|
||||||
|
|
||||||
|
compiler(arguments, callback, 100, log)
|
||||||
|
}
|
||||||
val readTracking = tracking.read
|
val readTracking = tracking.read
|
||||||
val applicationSet = new HashSet[String]
|
val applicationSet = new HashSet[String]
|
||||||
val subclassMap = new HashMap[String, Buffer[DetectedSubclass]]
|
val subclassMap = new HashMap[String, Buffer[DetectedSubclass]]
|
||||||
|
|
@ -78,14 +79,14 @@ class StandardCompile(val sources: Task[Set[File]], val classpath: Task[Set[File
|
||||||
{
|
{
|
||||||
for((source, tag) <- readTracking.allTags) if(tag.length > 0)
|
for((source, tag) <- readTracking.allTags) if(tag.length > 0)
|
||||||
{
|
{
|
||||||
val (applications, subclasses) = fromByteArray[(List[String], List[DetectedSubclass])](tag)
|
val (applications, subclasses) = Tag.fromBytes(tag)
|
||||||
allApplications ++= applications
|
allApplications ++= applications
|
||||||
subclasses.foreach(subclass => subclassMap.getOrElseUpdate(subclass.superclassName, new ArrayBuffer[DetectedSubclass]) += subclass)
|
subclasses.foreach(subclass => subclassMap.getOrElseUpdate(subclass.superclassName, new ArrayBuffer[DetectedSubclass]) += subclass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private final class CompileAnalysisCallback(superClasses: Array[String], tracking: UpdateTracking[File]) extends xsbti.AnalysisCallback
|
private final class CompileAnalysisCallback(superClasses: Array[String], tracking: UpdateTracking[File]) extends xsbti.AnalysisCallback
|
||||||
{
|
{
|
||||||
private var applications = List[(File,String)]()
|
private var applications = List[String]()
|
||||||
private var subclasses = List[DetectedSubclass]()
|
private var subclasses = List[DetectedSubclass]()
|
||||||
def superclassNames = superClasses
|
def superclassNames = superClasses
|
||||||
def superclassNotFound(superclassName: String) = error("Superclass not found: " + superclassName)
|
def superclassNotFound(superclassName: String) = error("Superclass not found: " + superclassName)
|
||||||
|
|
@ -94,12 +95,12 @@ class StandardCompile(val sources: Task[Set[File]], val classpath: Task[Set[File
|
||||||
{
|
{
|
||||||
if(!applications.isEmpty || !subclasses.isEmpty)
|
if(!applications.isEmpty || !subclasses.isEmpty)
|
||||||
{
|
{
|
||||||
tracking.tag(source, toByteArray( (applications, subclasses) ) )
|
tracking.tag(source, Tag.toBytes(applications, subclasses) )
|
||||||
applications = Nil
|
applications = Nil
|
||||||
subclasses = Nil
|
subclasses = Nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def foundApplication(source: File, className: String) { applications ::= ( (source, className) ) }
|
def foundApplication(source: File, className: String) { applications ::= className }
|
||||||
def foundSubclass(source: File, subclassName: String, superclassName: String, isModule: Boolean): Unit =
|
def foundSubclass(source: File, subclassName: String, superclassName: String, isModule: Boolean): Unit =
|
||||||
subclasses ::= DetectedSubclass(source, subclassName, superclassName, isModule)
|
subclasses ::= DetectedSubclass(source, subclassName, superclassName, isModule)
|
||||||
def sourceDependency(dependsOn: File, source: File) { tracking.dependency(source, dependsOn) }
|
def sourceDependency(dependsOn: File, source: File) { tracking.dependency(source, dependsOn) }
|
||||||
|
|
@ -109,6 +110,15 @@ class StandardCompile(val sources: Task[Set[File]], val classpath: Task[Set[File
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Tag
|
||||||
|
{
|
||||||
|
import sbinary.{DefaultProtocol, Format, Operations}
|
||||||
|
import DefaultProtocol._
|
||||||
|
private implicit val subclassFormat: Format[DetectedSubclass] =
|
||||||
|
asProduct4(DetectedSubclass.apply)( ds => Some(ds.source, ds.subclassName, ds.superclassName, ds.isModule))
|
||||||
|
def toBytes(applications: List[String], subclasses: List[DetectedSubclass]) = CacheIO.toBytes((applications, subclasses))
|
||||||
|
def fromBytes(bytes: Array[Byte]) = CacheIO.fromBytes( ( List[String](), List[DetectedSubclass]() ) )(bytes)
|
||||||
|
}
|
||||||
trait CompileReport extends NotNull
|
trait CompileReport extends NotNull
|
||||||
{
|
{
|
||||||
def classes: Set[File]
|
def classes: Set[File]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package xsbt
|
||||||
|
|
||||||
|
import FileUtilities.{read, withTemporaryDirectory => temp, write}
|
||||||
|
|
||||||
|
object SyncTest
|
||||||
|
{
|
||||||
|
import Paths._
|
||||||
|
def apply(content: String)
|
||||||
|
{
|
||||||
|
try { test(content) }
|
||||||
|
catch { case e: TasksFailed => e.failures.foreach(_.exception.printStackTrace) }
|
||||||
|
}
|
||||||
|
def test(content: String)
|
||||||
|
{
|
||||||
|
temp { fromDir => temp { toDir => temp { cacheDir =>
|
||||||
|
val from = fromDir / "test"
|
||||||
|
val to = toDir / "test-2"
|
||||||
|
write(from, content)
|
||||||
|
val sync = Sync(cacheDir)( Task( (from, to) :: Nil ))
|
||||||
|
val result = TaskRunner(sync.task)
|
||||||
|
println(result + " ::: " +read(to) + "\n\n")
|
||||||
|
to.delete
|
||||||
|
val result2 = TaskRunner(sync.task)
|
||||||
|
println(result2 + " ::: " +read(to) + "\n\n")
|
||||||
|
write(from, content.reverse)
|
||||||
|
TaskRunner(sync.clean)
|
||||||
|
println(from.exists + " " + fromDir.exists + " " + to.exists + " " + toDir.exists)
|
||||||
|
} } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object CompileTest
|
||||||
|
{
|
||||||
|
def apply(dir: String, scalaVersion: String, opts: Seq[String], supers: Set[String])
|
||||||
|
{
|
||||||
|
def test()
|
||||||
|
{
|
||||||
|
import Paths._
|
||||||
|
import GlobFilter._
|
||||||
|
val base = new java.io.File(dir)
|
||||||
|
val sources = Task(((base / "src" / "main" / "scala") ** "*.scala") ++ (base * "*.scala"))
|
||||||
|
val classpath = Task( dir / "lib" * "*.jar" )
|
||||||
|
WithCompiler(scalaVersion) { (compiler, log) =>
|
||||||
|
temp { cacheDir => temp { outDir =>
|
||||||
|
val options = Task(opts ++ Seq("-d", outDir.getAbsolutePath) )
|
||||||
|
val compile = new StandardCompile(sources, classpath, options, Task(supers), Task(compiler), cacheDir, log)
|
||||||
|
TaskRunner(compile.task)
|
||||||
|
readLine("Press enter to continue...")
|
||||||
|
TaskRunner(compile.task)
|
||||||
|
readLine("Press enter to continue...")
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try { test() }
|
||||||
|
catch { case e: TasksFailed => e.failures.foreach(_.exception.printStackTrace); case e: Exception => e.printStackTrace }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue