work on plugins, added console-project, re-integrated more tests

This commit is contained in:
Mark Harrah 2011-02-24 23:30:06 -05:00
parent 9db4afd222
commit 4f4ae170d3
64 changed files with 226 additions and 409 deletions

View File

@ -42,7 +42,7 @@ class ConsoleInterface
super.createInterpreter()
for( (id, value) <- bindNames zip bindValues)
interpreter.bind(id, value.asInstanceOf[AnyRef].getClass.getName, value)
interpreter.beQuietDuring(interpreter.bind(id, value.asInstanceOf[AnyRef].getClass.getName, value))
if(!initialCommands.isEmpty)
interpreter.interpret(initialCommands)

View File

@ -14,6 +14,7 @@ package sbt
import Project.{AppConfig, Config, ScopedKey, ScopeLocal, Setting, ThisProject, ThisProjectRef}
import TypeFunctions.{Endo,Id}
import tools.nsc.reporters.ConsoleReporter
import Build.{analyzed, data}
// name is more like BuildDefinition, but that is too long
trait Build
@ -29,6 +30,9 @@ object Build
{
def default(base: File): Build = new Build { def projects = defaultProject("default", base) :: Nil }
def defaultProject(id: String, base: File): Project = Project(id, base)
def data[T](in: Seq[Attributed[T]]): Seq[T] = in.map(_.data)
def analyzed(in: Seq[Attributed[_]]): Seq[Analysis] = in.flatMap{ _.metadata.get(Command.Analysis) }
}
object RetrieveUnit
{
@ -102,8 +106,6 @@ object EvaluateTask
import BuildStreams.{Streams, TaskStreams}
val SystemProcessors = Runtime.getRuntime.availableProcessors
// TODO: we should use a Seq[Attributed[File]] so that we don't throw away Analysis information
val PluginDefinition = TaskKey[(Seq[File], Analysis)]("plugin-definition")
val (state, dummyState) = dummy[State]("state")
val (streamsManager, dummyStreamsManager) = dummy[Streams]("streams-manager")
@ -119,11 +121,12 @@ object EvaluateTask
def dummy[T](name: String): (TaskKey[T], Task[T]) = (TaskKey[T](name), dummyTask(name))
def dummyTask[T](name: String): Task[T] = task( error("Dummy task '" + name + "' did not get converted to a full task.") ) named name
def evalPluginDef(log: Logger)(pluginDef: BuildStructure, state: State): (Seq[File], Analysis) =
def evalPluginDef(log: Logger)(pluginDef: BuildStructure, state: State): Seq[Attributed[File]] =
{
val root = ProjectRef(pluginDef.root, Load.getRootProject(pluginDef.units)(pluginDef.root))
val evaluated = evaluateTask(pluginDef, ScopedKey(Scope.ThisScope, PluginDefinition.key), state, root)
val result = evaluated getOrElse error("Plugin task does not exist for plugin definition at " + pluginDef.root)
val pluginKey = Keys.FullClasspath in Configurations.Compile
val evaluated = evaluateTask(pluginDef, ScopedKey(pluginKey.scope, pluginKey.key), state, root)
val result = evaluated getOrElse error("Plugin classpath does not exist for plugin definition at " + pluginDef.root)
processResult(result, log)
}
def evaluateTask[T](structure: BuildStructure, taskKey: ScopedKey[Task[T]], state: State, thisProject: ProjectRef, checkCycles: Boolean = false, maxWorkers: Int = SystemProcessors): Option[Result[T]] =
@ -376,8 +379,11 @@ object Load
def checkBuildBase(base: File) = checkDirectory(base)
def checkDirectory(base: File)
{
assert(base.isDirectory, "Not an existing directory: " + base)
assert(base.isAbsolute, "Not absolute: " + base)
if(base.isFile)
error("Not a directory: " + base)
else if(!base.exists)
IO createDirectory base
}
def checkAll(referenced: Map[URI, List[ProjectRef]], builds: Map[URI, LoadedBuildUnit])
{
@ -470,10 +476,10 @@ object Load
val (eval,pluginDef) = apply(dir, s, config)
val pluginState = Project.setProject(Load.initialSession(pluginDef, eval), pluginDef, s)
val (pluginClasspath, pluginAnalysis) = config.evalPluginDef(pluginDef, pluginState)
val definitionClasspath = (pluginClasspath ++ config.classpath).distinct
val pluginClasspath = config.evalPluginDef(pluginDef, pluginState)
val definitionClasspath = (data(pluginClasspath) ++ config.classpath).distinct
val pluginLoader = ClasspathUtilities.toLoader(definitionClasspath, config.loader)
loadPlugins(definitionClasspath, pluginLoader, pluginAnalysis)
loadPlugins(definitionClasspath, pluginLoader, analyzed(pluginClasspath))
}
def definitions(base: File, targetBase: File, srcs: Seq[File], plugins: LoadedPlugins, compilers: Compilers, log: Logger, buildBase: File): LoadedDefinitions =
@ -498,10 +504,10 @@ object Load
(inputs, analysis)
}
def loadPlugins(classpath: Seq[File], loader: ClassLoader, analysis: Analysis): LoadedPlugins =
def loadPlugins(classpath: Seq[File], loader: ClassLoader, analysis: Seq[Analysis]): LoadedPlugins =
{
val (pluginNames, plugins) = if(classpath.isEmpty) (Nil, Nil) else {
val names = findPlugins(analysis)
val names = analysis flatMap findPlugins
(names, loadPlugins(loader, names) )
}
new LoadedPlugins(classpath, loader, plugins, pluginNames)
@ -557,9 +563,10 @@ object Load
def localBase = unit.localBase
def classpath = unit.definitions.target +: unit.plugins.classpath
def loader = unit.definitions.loader
def imports = baseImports ++ importAll(unit.plugins.pluginNames ++ unit.definitions.buildNames)
def imports = getImports(unit)
override def toString = unit.toString
}
def getImports(unit: BuildUnit) = baseImports ++ importAll(unit.plugins.pluginNames ++ unit.definitions.buildNames)
// these are unresolved references
def referenced(definitions: Seq[Project]): Seq[ProjectRef] = definitions flatMap referenced
@ -567,7 +574,7 @@ object Load
final class BuildStructure(val units: Map[URI, LoadedBuildUnit], val root: URI, val settings: Seq[Setting[_]], val data: Settings[Scope], val index: StructureIndex, val streams: Streams, val delegates: Scope => Seq[Scope], val scopeLocal: ScopeLocal)
final class LoadBuildConfiguration(val stagingDirectory: File, val classpath: Seq[File], val loader: ClassLoader, val compilers: Compilers, val evalPluginDef: (BuildStructure, State) => (Seq[File], Analysis), val delegates: LoadedBuild => Scope => Seq[Scope], val scopeLocal: ScopeLocal, val injectSettings: Seq[Setting[_]], val log: Logger)
final class LoadBuildConfiguration(val stagingDirectory: File, val classpath: Seq[File], val loader: ClassLoader, val compilers: Compilers, val evalPluginDef: (BuildStructure, State) => Seq[Attributed[File]], val delegates: LoadedBuild => Scope => Seq[Scope], val scopeLocal: ScopeLocal, val injectSettings: Seq[Setting[_]], val log: Logger)
// information that is not original, but can be reconstructed from the rest of BuildStructure
final class StructureIndex(val keyMap: Map[String, AttributeKey[_]], val taskToKey: Map[Task[_], ScopedKey[Task[_]]], val keyIndex: KeyIndex)

View File

@ -26,7 +26,7 @@ final class Console(compiler: AnalyzingCompiler)
}
object Console
{
val SbtInitial = "import sbt._; import Process._; import current._"
val SbtInitial = "import sbt._, Process._, current._"
def apply(conf: build.Compile)(implicit log: Logger): Console = new Console( compiler(conf) )
def apply(conf: Compile.Inputs): Console = new Console( conf.compilers.scalac )
@ -36,16 +36,16 @@ object Console
val componentManager = new ComponentManager(conf.launcher.globalLock, conf.configuration.provider.components, log)
new AnalyzingCompiler(conf.instance, componentManager, log)
}
def sbtDefault(conf: build.Compile, value: Any)(implicit log: Logger)
def sbt(state: State, extra: String)(implicit log: Logger)
{
val c = new Console(compiler(conf))
val loader = value.asInstanceOf[AnyRef].getClass.getClassLoader
c.apply(conf.compileClasspath, Nil, loader, SbtInitial)("current" -> value)
}
def sbtDefault(conf: Compile.Inputs, value: Any)(implicit log: Logger)
{
val loader = value.asInstanceOf[AnyRef].getClass.getClassLoader
Console(conf)(conf.config.classpath, Nil, loader, SbtInitial)("current" -> value)
val loader = classOf[State].getClassLoader
val extracted = Project extract state
val unit = extracted.currentUnit
val compiler = Compile.compilers(state.configuration, log).scalac
val imports = Load.getImports(unit.unit).mkString("", ";\n", ";\n\n")
val initCommands = imports + extra
val bindings = ("state" -> state) :: ("extracted" -> extracted ) :: Nil
(new Console(compiler))(unit.classpath, Nil, initCommands)(Some(loader), bindings)
}
}

View File

@ -4,6 +4,7 @@
package sbt
import java.io.File
import Build.data
import Scope.{GlobalScope,ThisScope}
import Project.{AppConfig, Config, Initialize, ScopedKey, Setting, ThisProject, ThisProjectRef}
import Configurations.{Compile => CompileConf, Test => TestConf}
@ -57,6 +58,7 @@ object Keys
val Clean = TaskKey[Unit]("clean")
val ConsoleTask = TaskKey[Unit]("console")
val ConsoleQuick = TaskKey[Unit]("console-quick")
val ConsoleProject = TaskKey[Unit]("console-project")
val CompileTask = TaskKey[Analysis]("compile")
val Compilers = TaskKey[Compile.Compilers]("compilers")
val DocTask = TaskKey[File]("doc")
@ -200,8 +202,6 @@ object Default
def analysisMap[T](cp: Seq[Attributed[T]]): Map[T, Analysis] =
(cp map extractAnalysis).toMap
def data[T](in: Seq[Attributed[T]]): Seq[T] = in.map(_.data)
def core = Seq(
CrossPaths :== true,
ShellPrompt in GlobalScope :== (_ => "> "),
@ -275,7 +275,8 @@ object Default
lazy val projectTasks = Seq(
CleanFiles <<= (Target, SourceManaged) { _ :: _ :: Nil },
Clean <<= CleanFiles map IO.delete
Clean <<= CleanFiles map IO.delete,
ConsoleProject <<= consoleProject
)
lazy val testTasks = Seq(
@ -388,7 +389,8 @@ object Default
def discoverMainClasses(analysis: Analysis): Seq[String] =
compile.Discovery.applications(Test.allDefs(analysis)) collect { case (definition, discovered) if(discovered.hasMain) => definition.name }
def consoleProject = (EvaluateTask.state, streams, InitialCommands in ConsoleProject) map { (state, s, extra) => Console.sbt(state, extra)(s.log) }
def console = consoleTask(FullClasspath, ConsoleTask)
def consoleQuick = consoleTask(ExternalDependencyClasspath, ConsoleQuick)
def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[_]) = (Compilers, classpath, ScalacOptions in task, InitialCommands in task, streams) map {
@ -410,7 +412,7 @@ object Default
def copyResources =
(ClassDirectory, CacheDirectory, Resources, ResourceDirectories, streams) map { (target, cache, resources, dirs, s) =>
val cacheFile = cache / "copy-resources"
val mappings = resources x rebase(dirs, target)
val mappings = (resources --- dirs) x rebase(dirs, target)
s.log.debug("Copy resource mappings: " + mappings.mkString("\n\t","\n\t",""))
Sync(cacheFile)( mappings )
mappings
@ -439,8 +441,6 @@ object Default
val CompletionsID = "completions"
// lazy val projectConsole = task { Console.sbtDefault(info.compileInputs, this)(ConsoleLogger()) }
def inConfig(conf: Configuration)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
inScope(ThisScope.copy(config = Select(conf)) )( (Config :== conf) +: ss)
def inTask(t: Scoped)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
@ -464,17 +464,13 @@ object Default
lazy val defaultWebTasks = Nil
def pluginDefinition = Seq(
EvaluateTask.PluginDefinition <<= (FullClasspath in CompileConf,CompileTask in CompileConf) map ( (c,a) => (data(c),a) )
)
lazy val defaultClasspaths =
Classpaths.publishSettings ++ Classpaths.baseSettings ++
inConfig(CompileConf)(Classpaths.configSettings) ++
inConfig(TestConf)(Classpaths.configSettings)
lazy val defaultSettings = core ++ defaultPaths ++ defaultClasspaths ++ defaultTasks ++ compileBase ++ disableAggregation ++ pluginDefinition
lazy val defaultSettings = core ++ defaultPaths ++ defaultClasspaths ++ defaultTasks ++ compileBase ++ disableAggregation
lazy val defaultWebSettings = defaultSettings ++ defaultWebPaths ++ defaultWebTasks
}
object Classpaths

View File

@ -23,6 +23,11 @@ final case class Project(id: String, base: File, aggregate: Seq[ProjectRef] = Ni
def uses = aggregate ++ dependencies.map(_.project)
}
final case class Extracted(structure: Load.BuildStructure, session: SessionSettings, curi: URI, cid: String, rootProject: URI => String)
{
lazy val currentUnit = structure units curi
lazy val currentProject = currentUnit defined cid
lazy val currentRef = ProjectRef(Some(curi), Some(cid))
}
object Project extends Init[Scope]
{

View File

@ -9,4 +9,6 @@ package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtr
if(m.isDefined) Some(m.get) else None
def uri(s: String): URI = new URI(s)
def file(s: String): File = new File(s)
implicit def globFilter(expression: String): NameFilter = GlobFilter(expression)
}

View File

@ -0,0 +1,5 @@
CrossPaths :== false
Name :== "definition-lib-forname-test"
Version :== "1.0"

View File

@ -1,7 +0,0 @@
import sbt._
class LibTestProject(info: ProjectInfo) extends DefaultProject(info)
{
lazy val useJar = task { injar.Test.other; None }
override def disableCrossPaths = true
}

View File

@ -0,0 +1,3 @@
CrossPaths :== false
TaskKey("use-jar") := { injar.Test.other; () }

View File

@ -1,5 +0,0 @@
#Project properties
#Mon Mar 23 16:23:49 EDT 2009
project.organization=empty
project.name=definition-lib-forname-test
project.version=1.0

View File

@ -1,7 +0,0 @@
import sbt._
class LibTestProject(info: ProjectInfo) extends DefaultProject(info)
{
override def disableCrossPaths = true
override def buildScalaVersion = defScalaVersion.value
}

View File

@ -1,14 +1,14 @@
# this step builds a test jar for use by the project definition
> package
$ delete project/build
$ copy-file target/definition-lib-forname-test-1.0.jar project/build/lib/test.jar
$ copy-file changes/LibTestProject.scala project/build/src/LibTestProject.scala
$ delete build.sbt
$ copy-file target/definition-lib-forname-test-1.0.jar project/plugins/lib/test.jar
$ copy-file changes/build2.sbt build.sbt
# the copied project definition depends on the Test module in test.jar and will
# fail to compile if sbt did not put the jars in project/build/lib/ on the compile classpath
# fail to compile if sbt did not put the jars in project/plugins/lib/ on the compile classpath
> reload
# The project definition uses the class in test.jar and will fail here if sbt did not put the
# jars in project/build/lib on the runtime classpath
# jars in project/plugins/lib on the runtime classpath
> use-jar

View File

@ -0,0 +1,11 @@
import sbt._
object B extends Build
{
lazy val projects = Seq(root, sub1, sub2, sub3)
lazy val root = Project("root", file("."))
lazy val sub1 = Project("sub1", file("sub1"))
lazy val sub2 = Project("sub2", file("sub2"))
lazy val sub3 = Project("sub3", file("sub3"))
}

View File

@ -1,2 +0,0 @@
project.name=test
project.version=1.0

View File

@ -1,10 +0,0 @@
import sbt._
class Root(info: ProjectInfo) extends ParentProject(info)
{
lazy val sub1 = project("sub1", "sub1")
lazy val sub2 = project("sub2", "sub2", new Sub2(_))
lazy val sub3 = project("sub3", "sub3", new DefaultProject(_))
class Sub2(info: ProjectInfo) extends DefaultProject(info)
}

View File

@ -1,3 +0,0 @@
import sbt._
class TestSub(info: ProjectInfo) extends DefaultProject(info)

View File

@ -1,7 +1,6 @@
$ mkdir sub3 sub1 sub2
> console-project
> project sub3
> console-project
> project sub1
> console-project
> 'sub3/console-project'
> 'sub1/console-project'
> project sub2
> console-project

View File

@ -1 +0,0 @@
first.property=set-first

View File

@ -1,2 +0,0 @@
first.property=set-first
second.property=set-second

View File

@ -1,2 +0,0 @@
project.name=test-env
project.version=1.0

View File

@ -1,29 +0,0 @@
import sbt._
class Test(info: ProjectInfo) extends DefaultProject(info)
{
lazy val FirstDefault = "a"
lazy val SecondDefault = "b"
lazy val FirstSet = "set-first"
lazy val SecondSet = "set-second"
lazy val extra = new BasicEnvironment
{
def log = Test.this.log
def envBackingPath = info.builderPath / "extra.properties"
lazy val firstProperty = propertyOptional[String](FirstDefault)
lazy val secondProperty = propertyOptional[String](SecondDefault)
}
import extra.{firstProperty, secondProperty}
lazy val checkFirstUnset = checkTask(firstProperty, FirstDefault, "first.property")
lazy val checkFirstSet = checkTask(firstProperty, FirstSet, "first.property")
lazy val checkSecondUnset = checkTask(secondProperty, SecondDefault, "second.property")
lazy val checkSecondSet = checkTask(secondProperty, SecondSet, "second.property")
def checkTask[T](property: extra.Property[T], expected: T, name: String): Task =
task { if(property.value == expected) None else Some("Expected "+name+" to be '" + expected + "', was: " + property.value) }
}

View File

@ -1,26 +0,0 @@
# check that both properties are unset
> check-first-unset
->check-first-set
> check-second-unset
->check-second-set
# create the extra properties file with only the first property set
$ copy-file changes/first.properties project/extra.properties
> reload
-> check-first-unset
>check-first-set
> check-second-unset
->check-second-set
# create the extra properties file with both properties set
$ copy-file changes/second.properties project/extra.properties
> reload
-> check-first-unset
>check-first-set
-> check-second-unset
>check-second-set

View File

@ -0,0 +1,32 @@
import sbt._
import Keys._
import Configurations.{Compile, Test}
object Flat extends Build
{
lazy val projects = Seq(root)
lazy val root = Project("root", file("."),
settings = Default.defaultSettings ++ forConfig(Compile, "src") ++ forConfig(Test, "test-src") ++ baseSettings
)
def baseSettings = Seq(
LibraryDependencies += "org.scala-tools.testing" %% "scalacheck" % "1.8" % "test",
SourceFilter := "*.java" | "*.scala"
)
def forConfig(conf: Configuration, name: String) = Default.inConfig(conf)( unpackage(name) )
def unpackage(name: String) = Seq(
SourceDirectories := file(name) :: Nil,
ResourceDirectories :== SourceDirectories,
Keys.Resources <<= (SourceDirectories, SourceFilter, DefaultExcludes) map {
(srcs, filter, excl) => srcs.descendentsExcept(-filter,excl).getFiles.toSeq
},
Unpackage <<= (JarPath in PackageSrc, Base) map { (jar, base) =>
IO.unzip(jar, base / name)
}
)
val Unpackage = TaskKey[Unit]("unpackage-src")
}

View File

@ -1,5 +0,0 @@
#Project properties
#Fri May 15 12:14:00 EDT 2009
project.organization=test
project.name=Flatten Source Hierarchy
project.version=1.0

View File

@ -1,23 +0,0 @@
import sbt._
class FlatProject(info: ProjectInfo) extends DefaultProject(info)
{
override def useMavenConfigurations = true
val sc = "org.scalacheck" % "scalacheck" % "1.5" % "test"
def sourceFilter = "*.java" | "*.scala"
override def mainSources = descendents(sourcePath ###, sourceFilter)
override def mainResources = descendents(sourcePath ###, -sourceFilter)
override def testSourcePath = "test-src"
override def testSources = descendents(testSourcePath ###, sourceFilter)
override def testResources = descendents(testSourcePath ###, -sourceFilter)
lazy val unpackageProject =
task
{
FileUtilities.unzip(outputPath / (artifactBaseName + "-project.zip"), info.projectPath, "src/*", log).left.toOption
} dependsOn(cleanSrc)
lazy val cleanSrc = cleanTask(sourcePath +++ testSourcePath)
}

View File

@ -1,19 +1,21 @@
> ++2.7.7
# This test verifies that sbt works after the source hierarchy has been flattened and merged
# so that resources and Java and Scala sources are side by side under src/
> update
> test
> test:test
> test:run
# This part verifies that the package-src action works properly under a flattened/merged source hierarchy
> package-project
> package-src
> test:package-src
$ delete src
$ delete test-src
-> test
-> test:run
> unpackage-project
> unpackage-src
> test:unpackage-src
> test
> test:test
> test:run

View File

@ -1,10 +1,15 @@
import org.scalacheck._
import org.scalacheck._
import Prop._
class SimpleTest extends Properties("Simple")
{
specify("increment scala", (i: Int) => (new a.b.ScalaA).increment(i) == i+1)
specify("increment java", (i: Int) => (new JavaA).inc(i) == i+1)
property("increment scala") = forAll( (i: Int) => (new a.b.ScalaA).increment(i) == i+1)
property("increment java") = forAll( (i: Int) => (new JavaA).inc(i) == i+1)
specify("decrement scala", (i: Int) => (new b.ScalaB).decrement(i) == i+1)
specify("decrement java", (i: Int) => (new a.JavaB).dec(i) == i+1)
property("decrement scala") = forAll( (i: Int) => (new b.ScalaB).decrement(i) == i+1)
property("decrement java") = forAll( (i: Int) => (new a.JavaB).dec(i) == i+1)
}
object MainTest
{
def main(args: Array[String]) {}
}

View File

@ -1,11 +1,12 @@
package d
import org.scalacheck._
import org.scalacheck._
import Prop._
class ResourcesTest extends Properties("Resources")
{
specify("load main resources ok", (a: Boolean) => { b.ScalaC.loadResources(); true })
specify("load test resources ok", (a: Boolean) => { ScalaD.loadResources(); true })
property("load main resources ok") = forAll( (a: Boolean) => { b.ScalaC.loadResources(); true })
property("load test resources ok") = forAll( (a: Boolean) => { ScalaD.loadResources(); true })
}
object ScalaD
{

View File

@ -0,0 +1,5 @@
CrossPaths :== false
Name :== "definition-lib-test"
Version :== "1.0"

View File

@ -1,8 +0,0 @@
import sbt._
class LibTestProject(info: ProjectInfo) extends DefaultProject(info)
{
override def disableCrossPaths = true
override def buildScalaVersion = defScalaVersion.value
lazy val useJar = task { injar.Test.foo }
}

View File

@ -0,0 +1,3 @@
CrossPaths :== false
TaskKey("use-jar") := { injar.Test.foo }

View File

@ -1,5 +0,0 @@
#Project properties
#Mon Mar 23 16:23:49 EDT 2009
project.organization=empty
project.name=definition-lib-test
project.version=1.0

View File

@ -1,7 +0,0 @@
import sbt._
class Test(info: ProjectInfo) extends DefaultProject(info)
{
override def disableCrossPaths = true
override def buildScalaVersion = defScalaVersion.value
}

View File

@ -1,14 +1,14 @@
# this step builds a test jar for use by the project definition
> package
$ delete project/build
$ copy-file target/definition-lib-test-1.0.jar project/build/lib/test.jar
$ copy-file changes/LibTestProject.scala project/build/src/LibTestProject.scala
$ delete build.sbt
$ copy-file target/definition-lib-test-1.0.jar project/plugins/lib/test.jar
$ copy-file changes/build2.sbt build.sbt
# the copied project definition depends on the Test module in test.jar and will
# fail to compile if sbt did not put the jars in project/build/lib/ on the compile classpath
# fail to compile if sbt did not put the jar in project/plugins/lib/ on the compile classpath
> reload
# The project definition uses the class in test.jar and will fail here if sbt did not put the
# jars in project/build/lib on the runtime classpath
> use-jar
# jar in project/plugins/lib on the runtime classpath
> use-jar

View File

@ -0,0 +1,11 @@
import sbt._
import Keys.Name
object TestBuild extends Build
{
lazy val projects = Seq(
proj("a", "."),
proj("b", "b")
)
def proj(id: String, dir: String) = Project(id, file(dir), settings = Seq( Name :== id ) )
}

View File

@ -0,0 +1,15 @@
import sbt._
import Keys.Name
object TestBuild extends MakeBuild
{
lazy val projects = Seq( proj("a", ".") )
}
object SecondBuild extends MakeBuild
{
lazy val projects = Seq( proj("b", "b") )
}
trait MakeBuild extends Build
{
def proj(id: String, dir: String) = Project(id, file(dir), settings = Seq( Name :== id ) )
}

View File

@ -1,6 +0,0 @@
package test
import sbt._
class TestProject(info: ProjectInfo) extends DefaultProject(info)
class AnotherProject(info: ProjectInfo) extends DefaultProject(info)

View File

@ -1,9 +0,0 @@
package test
import sbt._
class TestProject(info: ProjectInfo) extends DefaultProject(info)
trait NotAProject extends Project
abstract class AnotherNonProject extends Project
object YetAnotherNonProject extends DefaultProject(error("Shouldn't be called"))

View File

@ -1,5 +0,0 @@
package test
import sbt._
class TestProject(info: ProjectInfo) extends DefaultProject(info)

View File

@ -1,7 +0,0 @@
package test
import sbt._
class TestProject(info: ProjectInfo) extends DefaultProject(info)
protected class NotMainProject(info: ProjectInfo) extends DefaultProject(info)
private class AnotherNotMainProject(info: ProjectInfo) extends DefaultProject(info)

View File

@ -0,0 +1 @@
TaskKey("example") := ()

View File

@ -0,0 +1 @@
TaskKey("sample") := ()

View File

@ -0,0 +1 @@
TaskKey("sample2") := ()

View File

@ -1,2 +0,0 @@
project.name=Test
project.version=1.0

View File

@ -1,16 +1,29 @@
# There should be no ambiguity with a single project definition
# A single project definition with projects only defining a name
$ copy-file changes/Build1.scala project/Build.scala
> reload
> a/name
-> a/compile
> b/name
-> b/compile
$ delete project/Build.scala
$ copy-file changes/SingleProject.scala project/build/src/TestProject.scala
# Two separate project definitions, implemented using a trait
# Only the modules should be discovered.
# A .sbt file should be used in each
$ copy-file changes/Build2.scala project/Build.scala
$ copy-file changes/a.sbt a.sbt
$ copy-file changes/b.sbt b/b.sbt
$ copy-file changes/b2.sbt b/b2.sbt
> reload
# Again, no ambiguity with a single project definition and any number of abstract classes/traits implementing Project
$ copy-file changes/SingleAndTraitProject.scala project/build/src/TestProject.scala
> reload
> a/name
-> a/compile
> a/example
-> a/sample
-> a/sample2
# One public project and any number of non-public projects should not be an error
$ copy-file changes/SinglePublicProject.scala project/build/src/TestProject.scala
> reload
# Multiple public projects should be an error
$ copy-file changes/MultiProject.scala project/build/src/TestProject.scala
-> reload
> b/name
-> b/compile
> b/sample
> b/sample2
-> b/example

View File

@ -0,0 +1,5 @@
TaskKey("check") := {
import antlr.Tool // verify that antlr is on compile classpath
Class.forName("antlr.Tool") // verify antlr is on runtime classpath
()
}

View File

@ -1,7 +0,0 @@
import sbt._
class UsePlugin(info: ProjectInfo) extends DefaultProject(info)
{
import antlr.Tool // verify that antlr is on compile classpath
lazy val check = task { Class.forName("antlr.Tool"); None } // verify antlr is on runtime classpath
}

View File

@ -1,5 +0,0 @@
import sbt._
class Plugins(info: ProjectInfo) extends PluginDefinition(info)
{
val a = "antlr" % "antlr" % "2.7.7"
}

View File

@ -0,0 +1 @@
LibraryDependencies += "antlr" % "antlr" % "2.7.7"

View File

@ -1,2 +0,0 @@
project.name=Processor Test
project.version=1.0

View File

@ -1,8 +0,0 @@
import sbt._
class PTest(info: ProjectInfo) extends ProcessorProject(info)
{
val launcherJar = "org.scala-tools.sbt" % "launcher" % info.app.id.version % "test"
val specs = "org.scala-tools.testing" % "specs" % "1.6.0" % "test"
override def testClasspath = super.testClasspath +++ info.sbtClasspath
}

View File

@ -1,74 +0,0 @@
package ptest
import sbt._
import Path.fromFile
import org.specs._
class ProcessorTest extends Specification
{
"basic processor " should {
def success(f: processor.Success => Unit) = successOrFail(basicProcessorResult)(f)
"succeed" in {
success(_ => ())
}
"not insert any arguments" in {
success(_.insertArguments must_== Nil)
}
"preserve the fail handler" in {
success(_.onFailure must_== basicFail)
}
}
"full processor " should {
def success(f: processor.Success => Unit) = successOrFail(fullProcessorResult)(f)
"succeed" in {
success(_ => ())
}
"insert correct arguments" in {
success(_.insertArguments must_== testArgs)
}
"preserve the fail handler" in {
success(_.onFailure must_== testFail)
}
}
def successOrFail(r: processor.ProcessorResult)(f: processor.Success => Unit) =
r match
{
case s: processor.Success => f(s)
case _ => error("Processor failed: " + r)
}
def withProject[T](f: Project => T): T =
{
val log = new ConsoleLogger
xsbt.FileUtilities.withTemporaryDirectory { tmp =>
val app = xsbt.boot.Launcher.defaultAppProvider(tmp)
val info = new ProjectInfo(tmp, Nil, None)(log, app, None)
val project = new DefaultProject(info)
f(project)
}
}
def basicProcessorResult =
{
var ranBasicArgs: Option[String] = None
val basic = new processor.BasicProcessor {
def apply(p: Project, args: String) = { ranBasicArgs = Some(args) }
}
val result = withProject { project => basic("basic", project, basicFail, basicArgs) }
ranBasicArgs must_== Some(basicArgs)
result
}
def fullProcessorResult =
{
val full = new processor.Processor {
def apply(label: String, p: Project, failAction: Option[String], args: String) = new processor.Success(p, failAction, args.split("""\s+"""): _*)
}
withProject { project => full("full", project, testFail, testArgs.mkString(" ")) }
}
lazy val testFail = Some("fail")
lazy val testArgs = List("a", "b")
lazy val basicArgs = " a b c "
lazy val basicFail = Some("basic-fail")
}

View File

@ -1,2 +0,0 @@
> update
> test

View File

@ -1,4 +0,0 @@
// should not be interpreted as a source file
public class JavaTest {
}

View File

@ -1,12 +0,0 @@
import sbt._
class Plugins(info: ProjectInfo) extends PluginDefinition(info)
{
override def ivyCacheDirectory = Some(outputPath / "ivy-cache")
override def managedStyle = ManagedStyle.Ivy
def projectRoot = Path.fromFile(info.projectPath.asFile.getParentFile.getParentFile)
val local = Resolver.file("test-repo", (projectRoot /"repo" / "test").asFile)
val plug = "test" % "plugins-test" % "1.0"
}

View File

@ -1,20 +0,0 @@
import sbt._
trait TestPlugin extends DefaultProject
{
lazy val check =
task
{
try
{
Class.forName("JavaTest")
Some("Java source should not be compiled as part of the plugin")
}
catch
{
case _: ClassNotFoundException =>
log.info("Test action")
None
}
}
}

View File

@ -1,3 +0,0 @@
import sbt._
class UsePlugin(info: ProjectInfo) extends DefaultProject(info) with TestPlugin

View File

@ -0,0 +1,5 @@
public class JavaTest {
public static final int X = 9;
}

View File

@ -0,0 +1,9 @@
import sbt._
object TestPlugin extends Plugin
{
val Check = TaskKey[Unit]("check")
def settings = Seq(
Check := assert(JavaTest.X == 9)
)
}

View File

@ -0,0 +1,3 @@
LibraryDependencies <<= (LibraryDependencies, Project.AppConfig) { (deps, conf) =>
deps :+ ("org.scala-tools.sbt" %% "sbt" % conf.provider.id.version)
}

View File

@ -1,3 +0,0 @@
project.version=1.0
project.name=Plugins Test
project.organization=test

View File

@ -1,9 +0,0 @@
import sbt._
class DefinePlugin(info: ProjectInfo) extends PluginProject(info)
{
override def ivyCacheDirectory = Some(outputPath / "ivy-cache")
override def managedStyle = ManagedStyle.Ivy
val publishTo = Resolver.file("test-repo", ("repo" / "test").asFile)
}

View File

@ -0,0 +1,6 @@
import sbt._
object B extends Build
{
lazy val projects = Project("root", file(".")).dependsOn( file("../../plugin") ) :: Nil
}

View File

@ -1,11 +1 @@
$ copy-file changes/TestPlugin.scala src/main/scala/TestPlugin.scala
$ copy-file changes/JavaTest.java src/main/java/JavaTest.java
> publish
> set project.name use-plugin-test
$ delete project/build
$ copy-file changes/Plugins.scala project/plugins/Plugins.scala
$ copy-file changes/UsePlugin.scala project/build/UsePlugin.scala
> reload
> check