mirror of https://github.com/sbt/sbt.git
aggregation
This commit is contained in:
parent
02d3c6bcad
commit
218ccc2c9f
|
|
@ -63,36 +63,13 @@ object Act
|
|||
def optProjectRef(index: KeyIndex, currentBuild: URI, currentProject: String) =
|
||||
projectRef(index, currentBuild) ?? ProjectRef(Some(currentBuild), Some(currentProject))
|
||||
|
||||
def valueParser(s: State, structure: BuildStructure, show: Boolean)(key: ScopedKey[_]): Parser[() => State] =
|
||||
structure.data.get(key.scope, key.key) match
|
||||
{
|
||||
case None => failure("Invalid setting or task")
|
||||
case Some(input: InputStatic[_]) => applyTask(s, structure, input.parser(s), show)
|
||||
case Some(input: InputDynamic[_]) => applyDynamicTask(s, structure, input, show)
|
||||
case Some(task: Task[_]) => applyTask(s, structure, success(task), show)
|
||||
case Some(v) => success(() => { logger(s).info(v.toString); s})
|
||||
}
|
||||
def applyDynamicTask[I](s: State, structure: Load.BuildStructure, input: InputDynamic[I], show: Boolean): Parser[() => State] =
|
||||
Command.applyEffect(input parser s) { parsed =>
|
||||
import EvaluateTask._
|
||||
val result = withStreams(structure){ str => runTask(input.task)(nodeView(s, str, parsed)) }
|
||||
processResult(result, logger(s), show)
|
||||
s
|
||||
}
|
||||
def applyTask(s: State, structure: Load.BuildStructure, p: Parser[Task[_]], show: Boolean): Parser[() => State] =
|
||||
Command.applyEffect(p) { t =>
|
||||
import EvaluateTask._
|
||||
val result = withStreams(structure){ str => runTask(t)(nodeView(s, str)) }
|
||||
processResult(result, logger(s), show)
|
||||
s
|
||||
}
|
||||
def actParser(s: State): Parser[() => State] = requireSession(s, actParser0(s))
|
||||
|
||||
private[this] def actParser0(state: State) =
|
||||
{
|
||||
val extracted = Project extract state
|
||||
showParser.flatMap { show =>
|
||||
scopedKeyParser(extracted) flatMap valueParser(state, extracted.structure, show)
|
||||
scopedKeyParser(extracted) flatMap Aggregation.valueParser(state, extracted.structure, show)
|
||||
}
|
||||
}
|
||||
def showParser = token( ("show" ~ Space) ^^^ true) ?? false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2011 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
|
||||
import CommandSupport.logger
|
||||
import Project.ScopedKey
|
||||
import Load.BuildStructure
|
||||
import EvaluateTask.parseResult
|
||||
import Keys.Aggregate
|
||||
import sbt.complete.Parser
|
||||
import Parser._
|
||||
|
||||
sealed trait Aggregation
|
||||
final object Aggregation
|
||||
{
|
||||
def apply(dependencies: Seq[ProjectRef], transitive: Boolean = true): Aggregation = new Explicit(dependencies, transitive)
|
||||
implicit def fromBoolean(b: Boolean): Aggregation = if(b) Enabled else Disabled
|
||||
val Enabled = new Implicit(true)
|
||||
val Disabled = new Implicit(false)
|
||||
final case class Implicit(enabled: Boolean) extends Aggregation
|
||||
final class Explicit(val dependencies: Seq[ProjectRef], val transitive: Boolean) extends Aggregation
|
||||
|
||||
final case class KeyValue[+T](key: ScopedKey[_], value: T)
|
||||
def getTasks[T](key: ScopedKey[T], structure: BuildStructure, transitive: Boolean): Seq[KeyValue[T]] =
|
||||
{
|
||||
val task = structure.data.get(key.scope, key.key).toList.map(t => KeyValue(key,t))
|
||||
if(transitive) aggregate(key, structure) ++ task else task
|
||||
}
|
||||
def projectAggregate(key: ScopedKey[_], structure: BuildStructure): Seq[ProjectRef] =
|
||||
{
|
||||
val project = key.scope.project.toOption.flatMap { p => Project.getProject(p, structure) }
|
||||
project match { case Some(p) => p.aggregate; case None => Nil }
|
||||
}
|
||||
def aggregate[T](key: ScopedKey[T], structure: BuildStructure): Seq[KeyValue[T]] =
|
||||
{
|
||||
val aggregated = Aggregate in Scope.fillTaskAxis(key.scope, key.key) get structure.data getOrElse Enabled
|
||||
val (agg, transitive) =
|
||||
aggregated match
|
||||
{
|
||||
case Implicit(false) => (Nil, false)
|
||||
case Implicit(true) => (projectAggregate(key, structure), true)
|
||||
case e: Explicit => (e.dependencies, e.transitive)
|
||||
}
|
||||
agg flatMap { a =>
|
||||
val newKey = ScopedKey(key.scope.copy(project = Select(a)), key.key)
|
||||
getTasks(newKey, structure, transitive)
|
||||
}
|
||||
}
|
||||
|
||||
def printSettings[T](xs: Seq[KeyValue[T]], log: Logger) =
|
||||
xs match
|
||||
{
|
||||
case KeyValue(_,x) :: Nil => log.info(x.toString)
|
||||
case _ => xs foreach { case KeyValue(key, value) => log.info(Project.display(key) + "\n\t" + value.toString) }
|
||||
}
|
||||
type Values[T] = Seq[KeyValue[T]]
|
||||
def seqParser[T](ps: Values[Parser[T]]): Parser[Seq[KeyValue[T]]] = seq(ps.map { case KeyValue(k,p) => p.map(v => KeyValue(k,v) ) })
|
||||
|
||||
def applyTasks[T](s: State, structure: BuildStructure, ps: Values[Parser[Task[T]]], show: Boolean): Parser[() => State] =
|
||||
Command.applyEffect(seqParser(ps)) { ts =>
|
||||
runTasks(s, structure, ts, Dummies(KNil, HNil), show)
|
||||
s
|
||||
}
|
||||
def runTasks[HL <: HList, T](s: State, structure: Load.BuildStructure, ts: Values[Task[T]], extra: Dummies[HL], show: Boolean)
|
||||
{
|
||||
import EvaluateTask._
|
||||
import std.TaskExtra._
|
||||
val toRun = ts map { case KeyValue(k,t) => t.map(v => KeyValue(k,v)) } join;
|
||||
val result = withStreams(structure){ str => runTask(toRun)(nodeView(s, str, extra.tasks, extra.values)) }
|
||||
val log = logger(s)
|
||||
onResult(result, log)( results => if(show) printSettings(results, log))
|
||||
}
|
||||
final case class Dummies[HL <: HList](tasks: KList[Task,HL], values: HL)
|
||||
private[this] def dummyMap[HL <: HList, I](vs: Values[I], data: Settings[Scope], dummies: Dummies[HL]): Dummies[HL2] forSome { type HL2 <: HList } =
|
||||
vs match
|
||||
{
|
||||
case Seq() => dummies
|
||||
case Seq(kv: KeyValue[t], xs @ _*) =>
|
||||
val dummyParsed = dummyParsedTask(kv.key, data).asInstanceOf[Task[t]]
|
||||
dummyMap(xs, data, Dummies(KCons(dummyParsed, dummies.tasks), HCons(kv.value, dummies.values)))
|
||||
}
|
||||
def applyDynamicTasks[I](s: State, structure: BuildStructure, inputs: Values[InputDynamic[I]], show: Boolean): Parser[() => State] =
|
||||
{
|
||||
val parsers = inputs.map { case KeyValue(k,t) => KeyValue(k, t parser s) }
|
||||
Command.applyEffect(seqParser(parsers)) { parseds =>
|
||||
import EvaluateTask._
|
||||
val dummies = dummyMap(parseds, structure.data, Dummies(KNil, HNil))
|
||||
val roots = inputs.map { case KeyValue(k,t) => KeyValue(k,t.task) }
|
||||
runTasks(s, structure, roots, dummies, show)
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
private[this] def dummyParsedTask(key: ScopedKey[_], data: Settings[Scope]): Task[_] =
|
||||
data.get(Scope.fillTaskAxis(key.scope, key.key), parseResult.key) getOrElse error("Parsed result dummy task not found in " + Project.display(key))
|
||||
|
||||
def valueParser(s: State, structure: BuildStructure, show: Boolean)(key: ScopedKey[_]): Parser[() => State] =
|
||||
getTasks(key, structure, true).toList match
|
||||
{
|
||||
case Nil => failure("Invalid setting or task")
|
||||
case xs @ KeyValue(_, _: InputStatic[t]) :: _ => applyTasks(s, structure, maps(xs.asInstanceOf[Values[InputStatic[t]]])(_.parser(s)), show)
|
||||
case xs @ KeyValue(_, _: InputDynamic[t]) :: _ => applyDynamicTasks(s, structure, xs.asInstanceOf[Values[InputDynamic[t]]], show)
|
||||
case xs @ KeyValue(_, _: Task[t]) :: _ => applyTasks(s, structure, maps(xs.asInstanceOf[Values[Task[t]]])(x => success(x)), show)
|
||||
case xs => success(() => { printSettings(xs, logger(s)); s} )
|
||||
}
|
||||
private[this] def maps[T, S](vs: Values[T])(f: T => S): Values[S] =
|
||||
vs map { case KeyValue(k,v) => KeyValue(k, f(v)) }
|
||||
}
|
||||
|
|
@ -109,10 +109,7 @@ object EvaluateTask
|
|||
val (streamsManager, dummyStreamsManager) = dummy[Streams]("streams-manager")
|
||||
val streams = TaskKey[TaskStreams]("streams")
|
||||
val resolvedScoped = SettingKey[ScopedKey[_]]("resolved-scoped")
|
||||
// will be cast to the appropriate type when passed to an InputTask implementation
|
||||
// this assumes there is only one InputTask finally selected and will need to be
|
||||
// revisited for aggregating InputTasks
|
||||
private[sbt] val (parseResult, dummyParseResult) = dummy[Any]("$parse-result")
|
||||
private[sbt] val parseResult: TaskKey[_] = TaskKey("$parse-result")
|
||||
|
||||
def injectSettings: Seq[Project.Setting[_]] = Seq(
|
||||
(state in Scope.GlobalScope) ::= dummyState,
|
||||
|
|
@ -148,8 +145,8 @@ object EvaluateTask
|
|||
for( t <- structure.data.get(resolvedScope, taskKey.key)) yield
|
||||
(t, nodeView(state, streams))
|
||||
}
|
||||
def nodeView(state: State, streams: Streams, parsed: Any = ()): Execute.NodeView[Task] =
|
||||
Transform(dummyParseResult :^: dummyStreamsManager :^: dummyState :^: KNil, parsed :+: streams :+: state :+: HNil)
|
||||
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))
|
||||
|
||||
def runTask[Task[_] <: AnyRef, T](root: Task[T], checkCycles: Boolean = false, maxWorkers: Int = SystemProcessors)(implicit taskToNode: Execute.NodeView[Task]): Result[T] =
|
||||
{
|
||||
|
|
@ -160,11 +157,11 @@ object EvaluateTask
|
|||
}
|
||||
|
||||
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) =>
|
||||
if(show) println("Result: " + v)
|
||||
v
|
||||
case Value(v) => f(v)
|
||||
case Inc(inc) =>
|
||||
log.error(Incomplete.show(inc, true))
|
||||
error("Task did not complete successfully")
|
||||
|
|
@ -181,7 +178,7 @@ object EvaluateTask
|
|||
else if(scoped.key == resolvedScoped.key)
|
||||
Seq(resolvedScoped in scoped.scope :== scoped)
|
||||
else if(scoped.key == parseResult.key)
|
||||
Seq(parseResult in scoped.scope ::= dummyParseResult)
|
||||
Seq(parseResult in scoped.scope := error("Unsubstituted parse result for " + Project.display(scoped)) )
|
||||
else
|
||||
Nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ sealed trait ScopeAxis[+S] {
|
|||
case Global => ifGlobal
|
||||
case Select(s) => f(s)
|
||||
}
|
||||
def toOption: Option[S] = foldStrict(Some.apply, None, None)
|
||||
def map[T](f: S => T): ScopeAxis[T] = foldStrict(s => Select(f(s)), Global, This)
|
||||
}
|
||||
case object This extends ScopeAxis[Nothing]
|
||||
|
|
|
|||
Loading…
Reference in New Issue