sbt/project/Sbt.scala

279 lines
17 KiB
Scala
Raw Normal View History

// TODO(low): proper generated API sources caching: doesn't detect output directory change
import sbt._
import Keys._
import Project.Initialize
import Util._
import Common._
import Licensed._
import Scope.ThisScope
import LaunchProguard.{proguard, Proguard}
object Sbt extends Build
{
override lazy val settings = super.settings ++ buildSettings ++ Status.settings ++ nightlySettings
2011-06-26 18:27:07 +02:00
def buildSettings = Seq(
organization := "org.scala-sbt",
version := "0.13.1-SNAPSHOT",
publishArtifact in packageDoc := false,
2013-06-20 20:28:05 +02:00
scalaVersion := "2.10.2",
publishMavenStyle := false,
componentID := None,
2012-02-05 03:10:30 +01:00
crossPaths := false,
2012-12-31 20:06:28 +01:00
resolvers += Resolver.typesafeIvyRepo("releases"),
2012-07-01 21:16:42 +02:00
concurrentRestrictions in Global += Util.testExclusiveRestriction,
2011-11-20 05:56:30 +01:00
testOptions += Tests.Argument(TestFrameworks.ScalaCheck, "-w", "1"),
javacOptions in compile ++= Seq("-target", "6", "-source", "6", "-Xlint", "-Xlint:-serial")
)
lazy val myProvided = config("provided") intransitive;
override def projects = super.projects.map(p => p.copy(configurations = (p.configurations.filter(_ != Provided)) :+ myProvided))
lazy val root: Project = Project("root", file("."), aggregate = nonRoots ) settings( rootSettings : _*) configs( Sxr.sxrConf, Proguard )
lazy val nonRoots = projects.filter(_ != root).map(p => LocalProject(p.id))
/* ** Subproject declarations ** */
// defines the Java interfaces through which the launcher and the launched application communicate
lazy val launchInterfaceSub = minProject(launchPath / "interface", "Launcher Interface") settings(javaOnly : _*)
// the launcher. Retrieves, loads, and runs applications based on a configuration file.
lazy val launchSub = testedBaseProject(launchPath, "Launcher") dependsOn(ioSub % "test->test", interfaceSub % "test", launchInterfaceSub) settings(launchSettings : _*)
// used to test the retrieving and loading of an application: sample app is packaged and published to the local repository
2012-02-05 03:10:30 +01:00
lazy val testSamples = noPublish( baseProject(launchPath / "test-sample", "Launch Test") ) dependsOn(interfaceSub, launchInterfaceSub) settings(scalaCompiler)
// defines Java structures used across Scala versions, such as the API structures and relationships extracted by
// the analysis compiler phases and passed back to sbt. The API structures are defined in a simple
// format from which Java sources are generated by the datatype generator subproject
lazy val interfaceSub = minProject(file("interface"), "Interface") settings(interfaceSettings : _*)
// defines operations on the API of a source, including determining whether it has changed and converting it to a string
// and discovery of subclasses and annotations
lazy val apiSub = testedBaseProject(compilePath / "api", "API") dependsOn(interfaceSub)
/* **** Utilities **** */
lazy val controlSub = baseProject(utilPath / "control", "Control")
lazy val collectionSub = testedBaseProject(utilPath / "collection", "Collections") settings( Util.keywordsSettings: _* )
lazy val applyMacroSub = testedBaseProject(utilPath / "appmacro", "Apply Macro") dependsOn(collectionSub) settings(scalaCompiler)
// The API for forking, combining, and doing I/O with system processes
2013-07-09 20:55:30 +02:00
lazy val processSub = baseProject(utilPath / "process", "Process") dependsOn(ioSub % "test->test") settings(scalaXml)
// Path, IO (formerly FileUtilities), NameFilter and other I/O utility classes
lazy val ioSub = testedBaseProject(utilPath / "io", "IO") dependsOn(controlSub) settings(ioSettings : _ *)
// Utilities related to reflection, managing Scala versions, and custom class loaders
Synchronize ClassLoaderCache and the Scala provider cache. Construction of Scala providers was already properly synchronized jvm and machine-wide. The cache on top of construction was not and neither was the newer ClassLoaderCache. This could cause the same Scala version to be loaded in multiple class loaders, taking up more permgen space and possibly decreasing performance due to less effective jit. The issue is very rare in practice for 0.13 because of the low probability of contention on ClassLoaderCache. This is because the work for a cache miss is mainly the construction of a URLClassLoader. In 0.12, however, the work potentially involved network access and class loading (not just class loader construction), thus greatly increasing the probability of contention and thus duplicate work (i.e. class loader construction). When there is contention, multiple class loaders are constructed and then preserved by the scalaInstance task in each project throughout the first task execution. Only when multiple scalaInstance tasks execute simultaneously and only during the first execution does this occur. (Technically, it could still happen later, but it doesn't in practice.) This means that the number of duplicate class loaders should quickly saturate instead of growing linearly with the number of projects. It also means that the impact depends on the exact tree structure of projects. A linear chain of dependencies will be unaffected, but a build with independent leaves may be limited by the number of cores. The number of cores affects the number of threads typically used by the task engine, which limits the number of concurrently executing scalaInstance tasks. In summary, this might affect the first, cold compilation of a multi-module project with independent leaves on a multi-core machine with Scala version different from the version used for sbt. It might increase the maximum permgen requirements as well as slow the jit compilation by up to one task execution. Subsequent compilations should be unaffected and the permgen utilization return to be as expected.
2013-06-20 01:20:37 +02:00
lazy val classpathSub = testedBaseProject(utilPath / "classpath", "Classpath") dependsOn(launchInterfaceSub, interfaceSub, ioSub) settings(scalaCompiler)
// Command line-related utilities.
lazy val completeSub = testedBaseProject(utilPath / "complete", "Completion") dependsOn(collectionSub, controlSub, ioSub) settings(jline)
// logging
lazy val logSub = testedBaseProject(utilPath / "log", "Logging") dependsOn(interfaceSub, processSub) settings(jline)
// Relation
lazy val relationSub = testedBaseProject(utilPath / "relation", "Relation") dependsOn(interfaceSub, processSub)
// class file reader and analyzer
lazy val classfileSub = testedBaseProject(utilPath / "classfile", "Classfile") dependsOn(ioSub, interfaceSub, logSub)
// generates immutable or mutable Java data types according to a simple input format
lazy val datatypeSub = baseProject(utilPath /"datatype", "Datatype Generator") dependsOn(ioSub)
2013-01-27 02:13:25 +01:00
// cross versioning
lazy val crossSub = baseProject(utilPath / "cross", "Cross") settings(inConfig(Compile)(Transform.crossGenSettings): _*)
/* **** Intermediate-level Modules **** */
// Apache Ivy integration
lazy val ivySub = baseProject(file("ivy"), "Ivy") dependsOn(interfaceSub, launchInterfaceSub, crossSub, logSub % "compile;test->test", ioSub % "compile;test->test", launchSub % "test->test") settings(ivy, jsch, testExclusive)
// Runner for uniform test interface
lazy val testingSub = baseProject(file("testing"), "Testing") dependsOn(ioSub, classpathSub, logSub, launchInterfaceSub, testAgentSub) settings(testInterface)
// Testing agent for running tests in a separate process.
lazy val testAgentSub = minProject(file("testing/agent"), "Test Agent") settings(testInterface)
// Basic task engine
lazy val taskSub = testedBaseProject(tasksPath, "Tasks") dependsOn(controlSub, collectionSub)
// Standard task system. This provides map, flatMap, join, and more on top of the basic task model.
2012-07-01 21:16:42 +02:00
lazy val stdTaskSub = testedBaseProject(tasksPath / "standard", "Task System") dependsOn(taskSub % "compile;test->test", collectionSub, logSub, ioSub, processSub) settings( testExclusive )
// Persisted caching based on SBinary
2013-07-09 20:55:30 +02:00
lazy val cacheSub = baseProject(cachePath, "Cache") dependsOn(ioSub, collectionSub) settings(sbinary, scalaXml)
// Builds on cache to provide caching for filesystem-related operations
lazy val trackingSub = baseProject(cachePath / "tracking", "Tracking") dependsOn(cacheSub, ioSub)
// Embedded Scala code runner
lazy val runSub = baseProject(file("run"), "Run") dependsOn(ioSub, logSub, classpathSub, processSub)
// Compiler-side interface to compiler that is compiled against the compiler being used either in advance or on the fly.
// Includes API and Analyzer phases that extract source API and relationships.
lazy val compileInterfaceSub = baseProject(compilePath / "interface", "Compiler Interface") dependsOn(interfaceSub, ioSub % "test->test", logSub % "test->test", launchSub % "test->test") settings( compileInterfaceSettings : _*)
2012-04-13 23:47:12 +02:00
lazy val precompiled282 = precompiled("2.8.2")
lazy val precompiled292 = precompiled("2.9.2")
2013-03-18 15:06:24 +01:00
lazy val precompiled293 = precompiled("2.9.3")
// 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
lazy val compileIncrementalSub = testedBaseProject(compilePath / "inc", "Incremental Compiler") dependsOn(apiSub, ioSub, logSub, classpathSub, relationSub)
// Persists the incremental data structures using SBinary
2012-12-31 20:06:28 +01:00
lazy val compilePersistSub = baseProject(compilePath / "persist", "Persist") dependsOn(compileIncrementalSub, apiSub) settings(sbinary)
// sbt-side interface to compiler. Calls compiler-side interface reflectively
2012-04-18 14:07:53 +02:00
lazy val compilerSub = testedBaseProject(compilePath, "Compile") dependsOn(launchInterfaceSub, interfaceSub % "compile;test->test", logSub, ioSub, classpathSub,
logSub % "test->test", launchSub % "test->test", apiSub % "test") settings( compilerSettings : _*)
lazy val compilerIntegrationSub = baseProject(compilePath / "integration", "Compiler Integration") dependsOn(
compileIncrementalSub, compilerSub, compilePersistSub, apiSub, classfileSub)
2012-04-18 14:07:53 +02:00
lazy val compilerIvySub = baseProject(compilePath / "ivy", "Compiler Ivy Integration") dependsOn(ivySub, compilerSub )
2013-07-09 20:55:30 +02:00
lazy val scriptedBaseSub = baseProject(scriptedPath / "base", "Scripted Framework") dependsOn(ioSub, processSub) settings(scalaParsers)
lazy val scriptedSbtSub = baseProject(scriptedPath / "sbt", "Scripted sbt") dependsOn(ioSub, logSub, processSub, scriptedBaseSub, launchInterfaceSub % "provided")
lazy val scriptedPluginSub = baseProject(scriptedPath / "plugin", "Scripted Plugin") dependsOn(sbtSub, classpathSub)
// Implementation and support code for defining actions.
2012-12-19 16:17:56 +01:00
lazy val actionsSub = testedBaseProject(mainPath / "actions", "Actions") dependsOn(
2012-04-18 14:07:53 +02:00
classpathSub, completeSub, apiSub, compilerIntegrationSub, compilerIvySub,
interfaceSub, ioSub, ivySub, logSub, processSub, runSub, relationSub, stdTaskSub, taskSub, trackingSub, testingSub)
// General command support and core commands not specific to a build system
2013-01-27 02:13:25 +01:00
lazy val commandSub = testedBaseProject(mainPath / "command", "Command") dependsOn(interfaceSub, ioSub, launchInterfaceSub, logSub, completeSub, classpathSub, crossSub)
// Fixes scope=Scope for Setting (core defined in collectionSub) to define the settings system used in build definitions
lazy val mainSettingsSub = testedBaseProject(mainPath / "settings", "Main Settings") dependsOn(applyMacroSub, interfaceSub, ivySub, relationSub, logSub, ioSub, commandSub,
2012-12-31 20:06:28 +01:00
completeSub, classpathSub, stdTaskSub, processSub) settings( sbinary )
2012-01-29 20:36:27 +01:00
// The main integration project for sbt. It brings all of the subsystems together, configures them, and provides for overriding conventions.
2013-07-09 20:55:30 +02:00
lazy val mainSub = testedBaseProject(mainPath, "Main") dependsOn(actionsSub, mainSettingsSub, interfaceSub, ioSub, ivySub, launchInterfaceSub, logSub, processSub, runSub, commandSub) settings(scalaXml)
2012-01-29 20:36:27 +01:00
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
// technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project
// with the sole purpose of providing certain identifiers without qualification (with a package object)
2013-03-18 15:06:24 +01:00
lazy val sbtSub = baseProject(sbtPath, "Simple Build Tool") dependsOn(mainSub, compileInterfaceSub, precompiled282, precompiled292, precompiled293, scriptedSbtSub % "test->test") settings(sbtSettings : _*)
/* Nested subproject paths */
def sbtPath = file("sbt")
def cachePath = file("cache")
def tasksPath = file("tasks")
def launchPath = file("launch")
def utilPath = file("util")
def compilePath = file("compile")
def mainPath = file("main")
def scriptedPath = file("scripted")
def sbtSettings = Seq(
normalizedName := "sbt"
)
2012-05-20 00:20:20 +02:00
def scriptedTask: Initialize[InputTask[Unit]] = InputTask(scriptedSource(dir => (s: State) => scriptedParser(dir))) { result =>
(proguard in Proguard, fullClasspath in scriptedSbtSub in Test, scalaInstance in scriptedSbtSub, publishAll, scriptedSource, result) map {
(launcher, scriptedSbtClasspath, scriptedSbtInstance, _, sourcePath, args) =>
val noJLine = new classpath.FilteredLoader(scriptedSbtInstance.loader, "jline." :: Nil)
val loader = classpath.ClasspathUtilities.toLoader(scriptedSbtClasspath.files, noJLine)
val m = ModuleUtilities.getObject("sbt.test.ScriptedTests", loader)
val r = m.getClass.getMethod("run", classOf[File], classOf[Boolean], classOf[Array[String]], classOf[File], classOf[Array[String]])
val launcherVmOptions = Array("-XX:MaxPermSize=256M") // increased after a failure in scripted source-dependencies/macro
try { r.invoke(m, sourcePath, true: java.lang.Boolean, args.toArray[String], launcher, launcherVmOptions) }
2011-07-24 05:07:54 +02:00
catch { case ite: java.lang.reflect.InvocationTargetException => throw ite.getCause }
}
}
2012-05-20 00:20:20 +02:00
import sbt.complete._
import DefaultParsers._
def scriptedParser(scriptedBase: File): Parser[Seq[String]] =
{
val pairs = (scriptedBase * AllPassFilter * AllPassFilter * "test").get map { (f: File) =>
val p = f.getParentFile
(p.getParentFile.getName, p.getName)
};
val pairMap = pairs.groupBy(_._1).mapValues(_.map(_._2).toSet) ;
val id = charClass(c => !c.isWhitespace && c != '/').+.string
val groupP = token(id.examples(pairMap.keySet.toSet)) <~ token('/')
def nameP(group: String) = token("*".id | id.examples(pairMap(group)))
2012-05-20 00:20:20 +02:00
val testID = for( group <- groupP; name <- nameP(group) ) yield (group, name)
(token(Space) ~> matched(testID)).*
}
lazy val scripted = InputKey[Unit]("scripted")
lazy val scriptedSource = SettingKey[File]("scripted-source")
lazy val publishAll = TaskKey[Unit]("publish-all")
lazy val publishLauncher = TaskKey[Unit]("publish-launcher")
def deepTasks[T](scoped: TaskKey[Seq[T]]): Initialize[Task[Seq[T]]] = deep(scoped.task) { _.join.map(_.flatten.distinct) }
def deep[T](scoped: SettingKey[T]): Initialize[Seq[T]] =
2011-09-26 14:20:07 +02:00
Util.inAllProjects(projects filterNot Set(root, sbtSub, scriptedBaseSub, scriptedSbtSub, scriptedPluginSub) map { p => LocalProject(p.id) }, scoped)
2013-01-27 02:13:25 +01:00
def launchSettings =
2013-07-19 04:36:40 +02:00
Seq(ivy,
2013-01-27 02:13:25 +01:00
compile in Test <<= compile in Test dependsOn(publishLocal in interfaceSub, publishLocal in testSamples, publishLocal in launchInterfaceSub)
) ++
inConfig(Compile)(Transform.configSettings) ++
inConfig(Compile)(Transform.transSourceSettings ++ Seq(
Transform.inputSourceDirectory <<= (sourceDirectory in crossSub) / "input_sources",
Transform.sourceProperties := Map("cross.package0" -> "xsbt", "cross.package1" -> "boot")
))
2011-06-26 18:27:07 +02:00
import Sxr.sxr
2011-06-26 18:27:07 +02:00
def releaseSettings = Release.settings(nonRoots, proguard in Proguard)
def rootSettings = releaseSettings ++ Docs.settings ++ LaunchProguard.settings ++ LaunchProguard.specific(launchSub) ++
Sxr.settings ++ docSetting ++ Util.publishPomSettings ++ otherRootSettings ++ proguardedLauncherSettings ++
Transform.conscriptSettings(launchSub)
def otherRootSettings = Seq(
scripted <<= scriptedTask,
scriptedSource <<= (sourceDirectory in sbtSub) / "sbt-test",
sources in sxr <<= deepTasks(sources in Compile),
2011-09-26 14:20:07 +02:00
Sxr.sourceDirectories <<= deep(sourceDirectories in Compile).map(_.flatten),
2011-11-10 11:11:16 +01:00
fullClasspath in sxr <<= (externalDependencyClasspath in Compile in sbtSub),
compileInputs in (Compile,sxr) <<= (sources in sxr, compileInputs in (sbtSub, Compile, compile), fullClasspath in sxr, scalacOptions) map { (srcs, in, cp, opts) =>
in.copy(config = in.config.copy(sources = srcs, classpath = cp.files))
},
2013-02-13 14:13:50 +01:00
compileInputs in (Compile,doc) <<= (compileInputs in (Compile,sxr), scalacOptions in doc) map { (ci, opts) =>
ci.copy(config = ci.config.copy(options = opts))
},
2011-06-26 18:27:07 +02:00
publishAll <<= inAll(nonRoots, publishLocal.task),
publishAll <<= (publishAll, publishLocal).map((x,y)=> ()), // publish all normal deps as well as the sbt-launch jar
TaskKey[Unit]("build-all") <<= Seq(publishLocal, /*sxr,*/ doc).dependOn
)
// the launcher is published with metadata so that the scripted plugin can pull it in
// being proguarded, it shouldn't ever be on a classpath with other jars, however
def proguardedLauncherSettings = Seq(
publishArtifact in packageSrc := false,
moduleName := "sbt-launch",
autoScalaLibrary := false,
description := "sbt application launcher",
publishLauncher <<= publish,
packageBin in Compile <<= (proguard in Proguard, Transform.conscriptConfigs).map( (x,y) => x)
)
2012-02-20 04:41:26 +01:00
def docSetting = inConfig(Compile)(inTask(sxr)(Defaults.docSetting(doc in ThisScope.copy(task = Global, config = Global))))
def interfaceSettings = javaOnly ++ Seq(
projectComponent,
exportJars := true,
componentID := Some("xsbti"),
2011-11-10 11:11:16 +01:00
watchSources <++= apiDefinitions,
resourceGenerators in Compile <+= (version, resourceManaged, streams, compile in Compile) map generateVersionFile,
apiDefinitions <<= baseDirectory map { base => (base / "definition") :: (base / "other") :: (base / "type") :: Nil },
sourceGenerators in Compile <+= (cacheDirectory, apiDefinitions, fullClasspath in Compile in datatypeSub, sourceManaged in Compile, mainClass in datatypeSub in Compile, runner, streams) map generateAPICached
)
def precompiledSettings = Seq(
2011-09-26 14:20:07 +02:00
artifact in packageBin <<= (appConfiguration, scalaVersion) { (app, sv) =>
val launcher = app.provider.scalaProvider.launcher
val bincID = binID + "_" + ScalaInstance(sv, launcher).actualVersion
Artifact(binID) extra("e:component" -> bincID)
},
target <<= (target, scalaVersion) { (base, sv) => base / ("precompiled_" + sv) },
scalacOptions := Nil,
2012-02-22 04:47:07 +01:00
ivyScala ~= { _.map(_.copy(checkExplicit = false, overrideScalaVersion = false)) },
exportedProducts in Compile := Nil,
exportedProducts in Test := Nil,
libraryDependencies <+= scalaVersion( "org.scala-lang" % "scala-compiler" % _ % "provided")
)
2011-06-12 02:09:15 +02:00
//
2013-07-19 04:36:40 +02:00
def compileInterfaceSettings: Seq[Setting[_]] = precompiledSettings ++ Seq[Setting[_]](
exportJars := true,
artifact in (Compile, packageSrc) := Artifact(srcID).copy(configurations = Compile :: Nil).extra("e:component" -> srcID)
)
def compilerSettings = Seq(
libraryDependencies <+= scalaVersion( "org.scala-lang" % "scala-compiler" % _ % "test"),
unmanagedJars in Test <<= (packageSrc in compileInterfaceSub in Compile).map(x => Seq(x).classpath)
)
def precompiled(scalav: String): Project = baseProject(compilePath / "interface", "Precompiled " + scalav.replace('.', '_')) dependsOn(interfaceSub) settings(precompiledSettings : _*) settings(
scalaHome := None,
scalaVersion <<= (scalaVersion in ThisBuild) { sbtScalaV =>
assert(sbtScalaV != scalav, "Precompiled compiler interface cannot have the same Scala version (" + scalav + ") as sbt.")
scalav
}
)
def ioSettings: Seq[Setting[_]] = Seq(
libraryDependencies <+= scalaVersion("org.scala-lang" % "scala-compiler" % _ % "test")
)
}