2011-04-09 01:15:13 +02:00
|
|
|
/* sbt -- Simple Build Tool
|
|
|
|
|
* Copyright 2011 Mark Harrah
|
|
|
|
|
*/
|
|
|
|
|
package sbt
|
|
|
|
|
|
|
|
|
|
import java.io.File
|
|
|
|
|
import Project.{ScopedKey, Setting}
|
2011-07-24 23:36:42 +02:00
|
|
|
import Keys.{globalLogging, streams, Streams, TaskStreams}
|
2011-07-22 04:03:56 +02:00
|
|
|
import Keys.{dummyState, dummyStreamsManager, streamsManager, taskDefinitionKey}
|
2011-04-09 01:15:13 +02:00
|
|
|
import Scope.{GlobalScope, ThisScope}
|
2011-05-31 04:10:01 +02:00
|
|
|
import scala.Console.{RED, RESET}
|
2011-04-09 01:15:13 +02:00
|
|
|
|
|
|
|
|
object EvaluateTask
|
|
|
|
|
{
|
2011-09-03 20:59:34 +02:00
|
|
|
import Load.{BuildStructure, PluginData}
|
|
|
|
|
import Project.{display, Initialize}
|
2011-04-09 01:15:13 +02:00
|
|
|
import std.{TaskExtra,Transform}
|
|
|
|
|
import TaskExtra._
|
|
|
|
|
import Keys.state
|
|
|
|
|
|
|
|
|
|
val SystemProcessors = Runtime.getRuntime.availableProcessors
|
|
|
|
|
|
|
|
|
|
def injectSettings: Seq[Setting[_]] = Seq(
|
|
|
|
|
(state in GlobalScope) ::= dummyState,
|
|
|
|
|
(streamsManager in GlobalScope) ::= dummyStreamsManager
|
|
|
|
|
)
|
|
|
|
|
|
2011-09-03 20:59:34 +02:00
|
|
|
def evalPluginDef(log: Logger)(pluginDef: BuildStructure, state: State): PluginData =
|
2011-04-09 01:15:13 +02:00
|
|
|
{
|
2011-09-03 20:59:34 +02:00
|
|
|
import Keys.{fullClasspath, javacOptions, scalacOptions}
|
|
|
|
|
import Configurations.{Compile, Runtime}
|
|
|
|
|
import Scoped._
|
|
|
|
|
|
2011-04-09 01:15:13 +02:00
|
|
|
val root = ProjectRef(pluginDef.root, Load.getRootProject(pluginDef.units)(pluginDef.root))
|
2011-09-03 20:59:34 +02:00
|
|
|
val init = (fullClasspath in Runtime, scalacOptions in Compile, javacOptions in Compile) map { (cp, so, jo) => new PluginData(cp, so, jo) }
|
|
|
|
|
processResult(evaluateInitTask(pluginDef, init, state, root), log)
|
|
|
|
|
}
|
|
|
|
|
def evaluateInitTask[T](structure: BuildStructure, init: Initialize[Task[T]], state: State, ref: ProjectRef, checkCycles: Boolean = false, maxWorkers: Int = SystemProcessors): Result[T] =
|
|
|
|
|
{
|
|
|
|
|
val resolveThis = Project.mapScope( Scope.replaceThis(Load.projectScope(ref)) )
|
|
|
|
|
val task = init mapReferenced resolveThis evaluate structure.data
|
|
|
|
|
withStreams(structure) { str =>
|
|
|
|
|
val toNode = nodeView(state, str)
|
|
|
|
|
runTask(task, str, structure.index.triggers, checkCycles, maxWorkers)(toNode)
|
|
|
|
|
}
|
2011-04-09 01:15:13 +02:00
|
|
|
}
|
|
|
|
|
def evaluateTask[T](structure: BuildStructure, taskKey: ScopedKey[Task[T]], state: State, ref: ProjectRef, checkCycles: Boolean = false, maxWorkers: Int = SystemProcessors): Option[Result[T]] =
|
|
|
|
|
withStreams(structure) { str =>
|
|
|
|
|
for( (task, toNode) <- getTask(structure, taskKey, state, str, ref) ) yield
|
2011-04-23 17:49:58 +02:00
|
|
|
runTask(task, str, structure.index.triggers, checkCycles, maxWorkers)(toNode)
|
2011-04-09 01:15:13 +02:00
|
|
|
}
|
|
|
|
|
def logIncResult(result: Result[_], streams: Streams) = result match { case Inc(i) => logIncomplete(i, streams); case _ => () }
|
|
|
|
|
def logIncomplete(result: Incomplete, streams: Streams)
|
|
|
|
|
{
|
|
|
|
|
val all = Incomplete linearize result
|
|
|
|
|
val keyed = for(Incomplete(Some(key: Project.ScopedKey[_]), _, msg, _, ex) <- all) yield (key, msg, ex)
|
|
|
|
|
val un = all.filter { i => i.node.isEmpty || i.message.isEmpty }
|
|
|
|
|
for( (key, _, Some(ex)) <- keyed)
|
|
|
|
|
getStreams(key, streams).log.trace(ex)
|
2011-06-15 01:31:55 +02:00
|
|
|
|
2011-04-09 01:15:13 +02:00
|
|
|
for( (key, msg, ex) <- keyed if(msg.isDefined || ex.isDefined) )
|
2011-05-31 04:10:01 +02:00
|
|
|
{
|
|
|
|
|
val msgString = (msg.toList ++ ex.toList.map(ErrorHandling.reducedToString)).mkString("\n\t")
|
2011-07-24 23:36:42 +02:00
|
|
|
val log = getStreams(key, streams).log
|
2011-05-31 04:10:01 +02:00
|
|
|
val keyString = if(log.ansiCodesSupported) RED + key.key.label + RESET else key.key.label
|
2011-07-24 23:36:42 +02:00
|
|
|
log.error(Scope.display(key.scope, keyString) + ": " + msgString)
|
2011-05-31 04:10:01 +02:00
|
|
|
}
|
2011-04-09 01:15:13 +02:00
|
|
|
}
|
|
|
|
|
def getStreams(key: ScopedKey[_], streams: Streams): TaskStreams =
|
|
|
|
|
streams(ScopedKey(Project.fillTaskAxis(key).scope, Keys.streams.key))
|
|
|
|
|
def withStreams[T](structure: BuildStructure)(f: Streams => T): T =
|
|
|
|
|
{
|
|
|
|
|
val str = std.Streams.closeable(structure.streams)
|
|
|
|
|
try { f(str) } finally { str.close() }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def getTask[T](structure: BuildStructure, taskKey: ScopedKey[Task[T]], state: State, streams: Streams, ref: ProjectRef): Option[(Task[T], Execute.NodeView[Task])] =
|
|
|
|
|
{
|
|
|
|
|
val thisScope = Load.projectScope(ref)
|
|
|
|
|
val resolvedScope = Scope.replaceThis(thisScope)( taskKey.scope )
|
|
|
|
|
for( t <- structure.data.get(resolvedScope, taskKey.key)) yield
|
|
|
|
|
(t, nodeView(state, streams))
|
|
|
|
|
}
|
|
|
|
|
def nodeView[HL <: HList](state: State, streams: Streams, extraDummies: KList[Task, HL] = KNil, extraValues: HL = HNil): Execute.NodeView[Task] =
|
|
|
|
|
Transform(dummyStreamsManager :^: KCons(dummyState, extraDummies), streams :+: HCons(state, extraValues))
|
|
|
|
|
|
2011-04-23 17:49:58 +02:00
|
|
|
def runTask[Task[_] <: AnyRef, T](root: Task[T], streams: Streams, triggers: Triggers[Task], checkCycles: Boolean = false, maxWorkers: Int = SystemProcessors)(implicit taskToNode: Execute.NodeView[Task]): Result[T] =
|
2011-04-09 01:15:13 +02:00
|
|
|
{
|
|
|
|
|
val (service, shutdown) = CompletionService[Task[_], Completed](maxWorkers)
|
|
|
|
|
|
2011-04-23 17:49:58 +02:00
|
|
|
val x = new Execute[Task](checkCycles, triggers)(taskToNode)
|
2011-04-09 01:15:13 +02:00
|
|
|
val result = try { x.run(root)(service) } finally { shutdown() }
|
|
|
|
|
val replaced = transformInc(result)
|
|
|
|
|
logIncResult(replaced, streams)
|
|
|
|
|
replaced
|
|
|
|
|
}
|
|
|
|
|
def transformInc[T](result: Result[T]): Result[T] =
|
2011-04-10 00:43:21 +02:00
|
|
|
// taskToKey needs to be before liftAnonymous. liftA only lifts non-keyed (anonymous) Incompletes.
|
|
|
|
|
result.toEither.left.map { i => Incomplete.transformBU(i)(convertCyclicInc andThen taskToKey andThen liftAnonymous ) }
|
2011-04-09 01:15:13 +02:00
|
|
|
def taskToKey: Incomplete => Incomplete = {
|
|
|
|
|
case in @ Incomplete(Some(node: Task[_]), _, _, _, _) => in.copy(node = transformNode(node))
|
|
|
|
|
case i => i
|
|
|
|
|
}
|
|
|
|
|
type AnyCyclic = Execute[Task]#CyclicException[_]
|
|
|
|
|
def convertCyclicInc: Incomplete => Incomplete = {
|
|
|
|
|
case in @ Incomplete(_, _, _, _, Some(c: AnyCyclic)) => in.copy(directCause = Some(new RuntimeException(convertCyclic(c))) )
|
|
|
|
|
case i => i
|
|
|
|
|
}
|
|
|
|
|
def convertCyclic(c: AnyCyclic): String =
|
|
|
|
|
(c.caller, c.target) match {
|
|
|
|
|
case (caller: Task[_], target: Task[_]) =>
|
|
|
|
|
c.toString + (if(caller eq target) "(task: " + name(caller) + ")" else "(caller: " + name(caller) + ", target: " + name(target) + ")" )
|
|
|
|
|
case _ => c.toString
|
|
|
|
|
}
|
|
|
|
|
def name(node: Task[_]): String =
|
2011-08-04 13:20:25 +02:00
|
|
|
node.info.name orElse transformNode(node).map(Project.displayFull) getOrElse ("<anon-" + System.identityHashCode(node).toHexString + ">")
|
2011-04-09 01:15:13 +02:00
|
|
|
def liftAnonymous: Incomplete => Incomplete = {
|
|
|
|
|
case i @ Incomplete(node, tpe, None, causes, None) =>
|
2011-04-10 00:43:21 +02:00
|
|
|
causes.find( inc => !inc.node.isDefined && (inc.message.isDefined || inc.directCause.isDefined)) match {
|
2011-04-09 01:15:13 +02:00
|
|
|
case Some(lift) => i.copy(directCause = lift.directCause, message = lift.message)
|
|
|
|
|
case None => i
|
|
|
|
|
}
|
|
|
|
|
case i => i
|
|
|
|
|
}
|
|
|
|
|
def transformNode(node: Task[_]): Option[ScopedKey[_]] =
|
|
|
|
|
node.info.attributes get taskDefinitionKey
|
|
|
|
|
|
|
|
|
|
def processResult[T](result: Result[T], log: Logger, show: Boolean = false): T =
|
|
|
|
|
onResult(result, log) { v => if(show) println("Result: " + v); v }
|
|
|
|
|
def onResult[T, S](result: Result[T], log: Logger)(f: T => S): S =
|
|
|
|
|
result match
|
|
|
|
|
{
|
|
|
|
|
case Value(v) => f(v)
|
|
|
|
|
case Inc(inc) => throw inc
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if the return type Seq[Setting[_]] is not explicitly given, scalac hangs
|
|
|
|
|
val injectStreams: ScopedKey[_] => Seq[Setting[_]] = scoped =>
|
|
|
|
|
if(scoped.key == streams.key)
|
|
|
|
|
Seq(streams in scoped.scope <<= streamsManager map { mgr =>
|
|
|
|
|
val stream = mgr(scoped)
|
|
|
|
|
stream.open()
|
|
|
|
|
stream
|
|
|
|
|
})
|
|
|
|
|
else
|
|
|
|
|
Nil
|
|
|
|
|
}
|