diff --git a/main/Command.scala b/main/Command.scala index ba7b84fd2..94fd58887 100644 --- a/main/Command.scala +++ b/main/Command.scala @@ -41,7 +41,18 @@ trait HistoryEnabled { def historyPath: Option[Path] } - +trait Tasked +{ + type Task[T] <: AnyRef + def task(name: String, state: State): Option[Task[State]] + implicit def taskToNode: NodeView[Task] + def help: Seq[(String, String)] +} +trait TaskSetup +{ + def maxThreads = Runtime.getRuntime.availableProcessors + def checkCycles = false +} final case class Input(line: String) { def name: String = error("TODO") diff --git a/main/Main.scala b/main/Main.scala index 580d4e470..c6d450316 100644 --- a/main/Main.scala +++ b/main/Main.scala @@ -3,6 +3,7 @@ */ package sbt +import Execute.NodeView import complete.HistoryCommands import HistoryCommands.{Start => HistoryPrefix} import sbt.build.{AggressiveCompile, Build, BuildException, Parse, ParseException} @@ -76,6 +77,20 @@ object Commands s.exit(true) } } + + def act = Command { case s @ State(p: Tasked) => + new Apply { + def help = p.help + def run = in => { + lazy val (checkCycles, maxThreads) = p match { + case c: TaskSetup => (c.checkCycles, c.maxThreads) + case _ => (false, Runtime.getRuntime.availableProcessors) + } + for(task <- p.task(in.name, s)) yield + processResult(runTask(task, checkCycles, maxThreads)(p.taskToNode), s) + } + } + } def load = Command { case s => Apply(Nil) { case Input(line) if line.startsWith("load") => @@ -95,6 +110,23 @@ object Commands val Exit = "exit" val Quit = "quit" - /** The list of lowercase command names that may be used to terminate the program.*/ + /** The list of command names that may be used to terminate the program.*/ val TerminateActions: Seq[String] = Seq(Exit, Quit) + + + def runTask[Task[_] <: AnyRef](root: Task[State], checkCycles: Boolean, maxWorkers: Int)(implicit taskToNode: NodeView[Task]): Result[State] = + { + val (service, shutdown) = CompletionService[Task[_], Completed](maxWorkers) + + val x = new Execute[Task](checkCycles)(taskToNode) + try { x.run(root)(service) } finally { shutdown() } + } + def processResult[State](result: Result[State], original: State): State = + result match + { + case Value(v) => v + case Inc(Incomplete(tpe, message, causes, directCause)) => // tpe: IValue = Error, message: Option[String] = None, causes: Seq[Incomplete] = Nil, directCause: Option[Throwable] = None) + println("Task did not complete successfully (TODO: error logging)") + original + } } \ No newline at end of file diff --git a/main/build/Build.scala b/main/build/Build.scala index 027c1bba4..ec9656470 100644 --- a/main/build/Build.scala +++ b/main/build/Build.scala @@ -9,6 +9,7 @@ import classpath.ClasspathUtilities.toLoader import ModuleUtilities.getObject import compile.{AnalyzingCompiler, JavaCompiler} import Path._ +import GlobFilter._ final class BuildException(msg: String) extends RuntimeException(msg) @@ -24,8 +25,17 @@ object Build binary(classpath, module, name, loader(configuration)) case SourceLoad(classpath, sourcepath, output, module, auto, name) => source(classpath, sourcepath, output, module, auto, name, configuration) - case _ => error("Not implemented yet") + case ProjectLoad(base, name) => + project(base, name, configuration) } + + def project(base: File, name: String, configuration: xsbti.AppConfiguration): Any = + { + val nonEmptyName = if(name.isEmpty) "Project" else name + val buildDir = base / "project" / "build" + val sources = buildDir * "*.scala" +++ buildDir / "src" / "main" / "scala" ** "*.scala" + source(Nil, sources.get.toSeq, Some(buildDir / "target" asFile), false, Auto.Explicit, nonEmptyName, configuration) + } def binary(classpath: Seq[File], module: Boolean, name: String, parent: ClassLoader): Any = { diff --git a/project/build/XSbt.scala b/project/build/XSbt.scala index 0f5ef57ca..3f314627c 100644 --- a/project/build/XSbt.scala +++ b/project/build/XSbt.scala @@ -44,7 +44,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths classfileSub, classpathSub, compilePersistSub, compilerSub, compileIncrementalSub, interfaceSub, ivySub, launchInterfaceSub, logSub, discoverySub, processSub) val altCompilerSub = project("main", "Alternate Compiler Test", (i: ProjectInfo) => new Base(i) { override def normalizedName = "sbt" }, // temporary - buildSub, compileIncrementalSub, compilerSub, completeSub, discoverySub, ioSub, logSub, processSub) + buildSub, compileIncrementalSub, compilerSub, completeSub, discoverySub, ioSub, logSub, processSub, taskSub) /** following modules are not updated for 2.8 or 0.9 */ /*val testSub = project("scripted", "Test", new TestProject(_), ioSub) diff --git a/tasks/Execute.scala b/tasks/Execute.scala index b471d8aa3..c166b6585 100644 --- a/tasks/Execute.scala +++ b/tasks/Execute.scala @@ -15,6 +15,7 @@ object Execute { trait Part1of2K[M[_[_], _], A[_]] { type Apply[T] = M[A, T] } type NodeT[A[_]] = Part1of2K[Node, A] + type NodeView[A[_]] = A ~> NodeT[A]#Apply def idMap[A,B]: Map[A, B] = JavaConversions.asMap(new java.util.IdentityHashMap[A,B]) def pMap[A[_], B[_]]: PMap[A,B] = new DelegatingPMap[A, B](idMap) @@ -27,7 +28,7 @@ sealed trait Completed { } -final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: A ~> NodeT[A]#Apply ) +final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: NodeView[A] ) { type Strategy = CompletionService[A[_], Completed]