mirror of https://github.com/sbt/sbt.git
233 lines
11 KiB
Scala
233 lines
11 KiB
Scala
/* sbt -- Simple Build Tool
|
|
* Copyright 2010 Mark Harrah
|
|
*/
|
|
package sbt
|
|
|
|
import std._
|
|
import compile.{Discovered,Discovery}
|
|
import inc.Analysis
|
|
import TaskExtra._
|
|
import Path.fileToPath
|
|
import Configurations.{Compile => CompileConfig, Test => TestConfig, Runtime => RunConfig, Default => DefaultConfig, IntegrationTest => ITestConfig}
|
|
import ClasspathProject._
|
|
import Types._
|
|
import xsbti.api.Definition
|
|
|
|
import org.scalatools.testing.Framework
|
|
import java.io.File
|
|
|
|
class DefaultProject(val info: ProjectInfo) extends BasicProject
|
|
{
|
|
override def name = "test"
|
|
}
|
|
trait IntegrationTest extends BasicProject
|
|
{
|
|
override def productsTask(conf: Configuration): Task[Seq[Attributed[File]]] =
|
|
conf match {
|
|
case ITestConfig => makeProducts(integrationTestCompile.compile, integrationTestCompile.compileInputs, name, "it-")
|
|
case _ => super.productsTask(conf)
|
|
}
|
|
|
|
override def configurations: Seq[Configuration] = super.configurations :+ Configurations.IntegrationTest
|
|
|
|
lazy val integrationTestOptions: Task[Seq[TestOption]] = testOptions
|
|
lazy val integrationTest = testTasks(Some("it"), Configurations.IntegrationTest, integrationTestOptions, integrationTestCompile.compile, buildScalaInstance)
|
|
lazy val integrationTestCompile = compileTasks(Some("it"), Configurations.IntegrationTest, "src" / "it", Path.emptyPathFinder, buildScalaInstance)
|
|
}
|
|
abstract class BasicProject extends TestProject with MultiClasspathProject with ReflectiveClasspathProject
|
|
{
|
|
// easier to demo for now
|
|
override def organization = "org.example"
|
|
override def version = "1.0"
|
|
|
|
override def watchPaths: PathFinder = (info.projectDirectory: Path) * sourceFilter +++ descendents("src","*")
|
|
|
|
def javacOptions: Seq[String] = Nil
|
|
def scalacOptions: Seq[String] = Nil
|
|
def consoleOptions: Seq[String] = scalacOptions
|
|
def initialCommands: String = ""
|
|
|
|
def outputDirectory = "target": Path
|
|
def cacheDirectory = outputDirectory / "cache"
|
|
def mainResources = descendents("src" / "main" / "resources" ###, "*")
|
|
def testResources = descendents("src" / "test" / "resources" ###, "*")
|
|
|
|
def classesDirectory(configuration: Configuration): File =
|
|
configuration match {
|
|
case CompileConfig => outputDirectory / "classes"
|
|
case c => outputDirectory / (c.name + "-classes")
|
|
}
|
|
|
|
lazy val products: Classpath = TaskMap(productsTask)
|
|
|
|
// TODO: include resources, perhaps handle jars v. directories
|
|
def productsTask(conf: Configuration): Task[Seq[Attributed[File]]] =
|
|
conf match {
|
|
case CompileConfig | DefaultConfig => makeProducts(compile.compile, compile.compileInputs, name, "")
|
|
case TestConfig => makeProducts(testCompile.compile, testCompile.compileInputs, name, "test-")
|
|
case x => task { Nil }
|
|
}
|
|
|
|
lazy val buildScalaVersions: Task[String] = task { info.app.scalaProvider.version }//cross(MultiProject.ScalaVersion)(info.app.scalaProvider.version)
|
|
lazy val buildScalaInstance: Task[ScalaInstance] =
|
|
buildScalaVersions map { version => ScalaInstance(version, info.app.scalaProvider) }
|
|
|
|
lazy val discoverMain: Task[Seq[(Definition,Discovered)]] =
|
|
compile.compile map { analysis => Discovery.applications(Test.allDefs(analysis)) }
|
|
|
|
lazy val discoveredMainClasses: Task[Seq[String]] =
|
|
discoverMain map { _ collect { case (definition, discovered) if(discovered.hasMain) => definition.name } }
|
|
|
|
lazy val pkgMainClass: Task[Option[String]] =
|
|
discoveredMainClasses map { classes => SelectMainClass(None, classes) }
|
|
|
|
lazy val runner: Task[ScalaRun] =
|
|
buildScalaInstance map { si => new Run(si) }
|
|
|
|
lazy val run = runTasks(None, RunConfig, discoveredMainClasses)
|
|
lazy val testRun = runTasks(Some("test"), TestConfig, test.testDiscoveredMainClasses)
|
|
|
|
lazy val testFrameworks: Task[Seq[TestFramework]] = task {
|
|
import TestFrameworks._
|
|
Seq(ScalaCheck, Specs, ScalaTest, ScalaCheckCompat, ScalaTestCompat, SpecsCompat, JUnit)
|
|
}
|
|
|
|
lazy val testOptions: Task[Seq[TestOption]] = task { Nil }
|
|
|
|
lazy val test = testTasks(None, TestConfig, testOptions, testCompile.compile, buildScalaInstance)
|
|
|
|
lazy val compile = compileTasks(None, CompileConfig, "src" / "main", info.projectDirectory : Path, buildScalaInstance)
|
|
lazy val testCompile = compileTasks(Some("test"), TestConfig, "src" / "test", Path.emptyPathFinder, buildScalaInstance)
|
|
|
|
lazy val consoleQuick = consoleTask(dependencyClasspath(CompileConfig), consoleOptions, initialCommands, compile.compileInputs)
|
|
lazy val console = consoleTask(CompileConfig, consoleOptions, initialCommands, compile.compileInputs)
|
|
lazy val testConsole = consoleTask(TestConfig, consoleOptions, initialCommands, testCompile.compileInputs)
|
|
|
|
lazy val clean = task { IO.delete(outputDirectory) }
|
|
|
|
// lazy val doc, test-only, test-quick, test-failed, publish(-local), deliver(-local), make-pom, package-*, javap, copy-resources
|
|
|
|
lazy val set = input map { in =>
|
|
val Seq(name, value) = in.splitArgs.take(2)
|
|
println(name + "=" + value)
|
|
java.lang.System.setProperty(name, value)
|
|
}
|
|
|
|
def sourceFilter: FileFilter = "*.java" | "*.scala"
|
|
|
|
def compileTask(inputs: Task[Compile.Inputs]): Task[Analysis] =
|
|
inputs :^: streams :^: KNil map { case i :+: s :+: HNil => Compile(i, s.log) }
|
|
|
|
def compileInputsTask(configuration: Configuration, bases: PathFinder, shallow: PathFinder, scalaInstance: Task[ScalaInstance]): Task[Compile.Inputs] =
|
|
{
|
|
val dep = dependencyClasspath(configuration)
|
|
(dep, scalaInstance) map { case (cp :+: si :+: HNil) =>
|
|
val log = ConsoleLogger()
|
|
val compilers = Compile.compilers(si)(info.configuration, log)
|
|
val javaSrc = base / "java"
|
|
val scalaSrc = base / "scala"
|
|
val out = "target" / si.actualVersion
|
|
import Path._
|
|
val deepBases = (bases / "java") +++ (bases / "scala")
|
|
val allBases = deepBases +++ shallow
|
|
val sources = descendents(deepBases, sourceFilter) +++ shallow * (sourceFilter -- defaultExcludes)
|
|
val classes = classesDirectory(configuration)
|
|
val classpath = classes +: data(cp)
|
|
val analysis = analysisMap(cp)
|
|
val cache = cacheDirectory / "compile" / configuration.toString
|
|
Compile.inputs(classpath, sources.getFiles.toSeq, classes, scalacOptions, javacOptions, allBases.getFiles.toSeq, analysis, cache, 100)(compilers, log)
|
|
}
|
|
}
|
|
|
|
def copyResourcesTask(resources: PathFinder, config: Configuration): Task[Relation[File,File]] =
|
|
streams map { s =>
|
|
val target = classesDirectory(config)
|
|
val cacheFile = cacheDirectory / config.name / "copy-resources"
|
|
val mappings = resources.get.map(path => (path.asFile, new File(target, path.relativePath)))
|
|
s.log.debug("Copy resource (" + config.name + ") mappings: " + mappings.mkString("\n\t"))
|
|
Sync(cacheFile)( mappings )
|
|
}
|
|
|
|
lazy val copyResources = copyResourcesTask(mainResources, CompileConfig)
|
|
lazy val copyTestResources = copyResourcesTask(testResources, TestConfig)
|
|
|
|
def syncTask(cacheFile: File, mappings: Iterable[(File, File)]): Task[Relation[File,File]] =
|
|
task { Sync(cacheFile)(mappings) }
|
|
|
|
def consoleTask(config: Configuration, options: Seq[String], initialCommands: String, compilers: Task[Compile.Inputs]): Task[Unit] =
|
|
consoleTask(fullClasspath(config), options, initialCommands, compilers)
|
|
def consoleTask(classpath: Task[Seq[Attributed[File]]], options: Seq[String], initialCommands: String, compilers: Task[Compile.Inputs]): Task[Unit] =
|
|
consoleTask(compilers.map(_.compilers), classpath, options, initialCommands)
|
|
def consoleTask(compilers: Task[Compile.Compilers], classpath: Task[Seq[Attributed[File]]], options: Seq[String], initialCommands: String): Task[Unit] =
|
|
compilers :^: classpath :^: streams :^: KNil map { case cs :+: cp :+: s :+: HNil =>
|
|
(new Console(cs.scalac))(data(cp), options, initialCommands, s.log)
|
|
}
|
|
|
|
def compileTasks(prefix: Option[String], config: Configuration, base: PathFinder, shallow: PathFinder, si: Task[ScalaInstance]): CompileTasks =
|
|
{
|
|
val confStr = if(config == Configurations.Compile) "" else config.name + "-"
|
|
val compileInputs: Task[Compile.Inputs] = compileInputsTask(config, base, shallow, buildScalaInstance) named(confStr + "compile-inputs")
|
|
val compile: Task[Analysis] = compileTask(compileInputs) named(confStr + "compile")
|
|
new CompileTasks(prefix, compile, compileInputs)
|
|
}
|
|
|
|
def testTasks(prefix: Option[String], config: Configuration, options: Task[Seq[TestOption]], compile: Task[Analysis], instance: Task[ScalaInstance]): TestTasks =
|
|
new TestTasks(prefix, this, testFrameworks, config, options, compile, instance)
|
|
|
|
def runTasks(prefix: Option[String], config: Configuration, discoveredMainClasses: Task[Seq[String]]): RunTasks =
|
|
new RunTasks(prefix, this, config, discoveredMainClasses, runner)
|
|
|
|
}
|
|
|
|
// TODO: move these to separate file. The main problem with this approach is modifying dependencies and otherwise overriding a task.
|
|
final class CompileTasks(val prefix: Option[String], val compile: Task[Analysis], val compileInputs: Task[Compile.Inputs]) extends TaskGroup
|
|
|
|
class RunTasks(val prefix: Option[String], val project: ClasspathProject with Project, val config: Configuration, discoveredMainClasses: Task[Seq[String]], runner: Task[ScalaRun]) extends TaskGroup
|
|
{
|
|
def selectRunMain(allMainClasses: Task[Seq[String]]): Task[Option[String]] =
|
|
allMainClasses map { classes => SelectMainClass(Some(SimpleReader readLine _), classes) }
|
|
|
|
def runTask(fullcp: Task[Seq[Attributed[File]]], mainClass: Task[Option[String]]): Task[Unit] =
|
|
runTask(project.input, fullcp, mainClass, project.streams, runner)
|
|
|
|
def runTask(input: Task[Input], fullcp: Task[Seq[Attributed[File]]], mainClass: Task[Option[String]], streams: Task[TaskStreams], runner: Task[ScalaRun]): Task[Unit] =
|
|
(input :^: fullcp :^: mainClass :^: streams :^: runner :^: KNil) map { case in :+: cp :+: main :+: s :+: r :+: HNil => run0(in.splitArgs, cp, main, s.log, r) }
|
|
|
|
def run0(args: Seq[String], cp: Seq[Attributed[File]], main: Option[String], log: Logger, r: ScalaRun)
|
|
{
|
|
val mainClass = main getOrElse error("No main class detected.")
|
|
val classpath = cp.map(x => Path.fromFile(x.data))
|
|
r.run(mainClass, classpath, args, log) foreach error
|
|
}
|
|
|
|
lazy val runMainClass: Task[Option[String]] = selectRunMain(discoveredMainClasses)
|
|
lazy val run = runTask(project.fullClasspath(config), runMainClass)
|
|
}
|
|
|
|
class TestTasks(val prefix: Option[String], val project: ClasspathProject with Project, testFrameworks: Task[Seq[TestFramework]], val config: Configuration, options: Task[Seq[TestOption]], compile: Task[Analysis], scalaInstance: Task[ScalaInstance]) extends TaskGroup
|
|
{
|
|
lazy val testLoader: Task[ClassLoader] =
|
|
project.fullClasspath(config) :^: scalaInstance :^: KNil map { case classpath :+: instance :+: HNil =>
|
|
TestFramework.createTestLoader(data(classpath), instance)
|
|
}
|
|
|
|
lazy val loadedTestFrameworks: Task[Map[TestFramework,Framework]] =
|
|
testFrameworks :^: project.streams :^: testLoader :^: KNil map { case frameworks :+: s :+: loader :+: HNil =>
|
|
frameworks.flatMap( f => f.create(loader, s.log).map( x => (f, x)).toIterable ).toMap
|
|
}
|
|
|
|
lazy val discoverTest: Task[(Seq[TestDefinition], Set[String])] =
|
|
loadedTestFrameworks :^: compile :^: KNil map { case frameworkMap :+: analysis :+: HNil =>
|
|
Test.discover(frameworkMap.values.toSeq, analysis)
|
|
}
|
|
lazy val definedTests: Task[Seq[TestDefinition]] = discoverTest.map(_._1)
|
|
lazy val testDiscoveredMainClasses: Task[Seq[String]] = discoverTest.map(_._2.toSeq)
|
|
|
|
lazy val executeTests = (loadedTestFrameworks :^: options :^: testLoader :^: definedTests :^: project.streams :^: KNil) flatMap {
|
|
case frameworkMap :+: options :+: loader :+: discovered :+: s :+: HNil =>
|
|
|
|
Test(frameworkMap, loader, discovered, options, s.log)
|
|
}
|
|
lazy val test = (project.streams, executeTests) map { case s :+: results :+: HNil => Test.showResults(s.log, results) }
|
|
}
|