mirror of https://github.com/sbt/sbt.git
more refactoring of special settings: input tasks. fixes #114
This commit is contained in:
parent
fb9e3bd516
commit
4ae0ba6b57
|
|
@ -6,7 +6,7 @@ package sbt
|
|||
import CommandSupport.logger
|
||||
import Project.ScopedKey
|
||||
import Load.BuildStructure
|
||||
import Keys.{aggregate, parseResult, showSuccess, showTiming, timingFormat}
|
||||
import Keys.{aggregate, showSuccess, showTiming, timingFormat}
|
||||
import sbt.complete.Parser
|
||||
import java.net.URI
|
||||
import Parser._
|
||||
|
|
@ -129,29 +129,18 @@ final object Aggregation
|
|||
}
|
||||
|
||||
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 inputMap = (Map.empty[AnyRef,Any] /: (inputs zip parseds)) { case (im, (id, v)) => im + ((id.value.defined, v.value)) }
|
||||
val dummies = Dummies( InputTask.inputMap :^: KNil, inputMap :+: 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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ package sbt
|
|||
import java.io.File
|
||||
import Project.{ScopedKey, Setting}
|
||||
import Keys.{streams, Streams, TaskStreams}
|
||||
import Keys.{dummyState, dummyStreamsManager, parseResult, streamsManager, taskDefinitionKey}
|
||||
import Keys.{dummyState, dummyStreamsManager, streamsManager, taskDefinitionKey}
|
||||
import Scope.{GlobalScope, ThisScope}
|
||||
import scala.Console.{RED, RESET}
|
||||
|
||||
|
|
@ -131,8 +131,6 @@ object EvaluateTask
|
|||
stream.open()
|
||||
stream
|
||||
})
|
||||
else if(scoped.key == parseResult.key)
|
||||
Seq(parseResult in scoped.scope := error("Unsubstituted parse result for " + Project.display(scoped)) )
|
||||
else
|
||||
Nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ object Keys
|
|||
val (state, dummyState) = dummy[State]("state", "Current build state.")
|
||||
val (streamsManager, dummyStreamsManager) = dummy[Streams]("streams-manager", "Streams manager, which provides streams for different contexts.")
|
||||
val resolvedScoped = SettingKey[ScopedKey[_]]("resolved-scoped", "The ScopedKey for the referencing setting or task.")
|
||||
private[sbt] val parseResult: TaskKey[_] = TaskKey("$parse-result", "Internal: used to implement input tasks.")
|
||||
private[sbt] val parseResult: TaskKey[Any] = TaskKey("$parse-result", "Internal: used to implement input tasks.")
|
||||
|
||||
val triggeredBy = AttributeKey[Seq[Task[_]]]("triggered-by")
|
||||
val runBefore = AttributeKey[Seq[Task[_]]]("run-before")
|
||||
|
|
|
|||
|
|
@ -123,17 +123,17 @@ object Load
|
|||
(rootEval, new BuildStructure(projects, loaded.root, settings, data, index, streams, delegates, config.scopeLocal))
|
||||
}
|
||||
|
||||
// map dependencies on the special tasks so that the scope is the same as the defining key
|
||||
// additionally, set the task axis to the defining key if it is not set
|
||||
// map dependencies on the special tasks:
|
||||
// 1. the scope of 'streams' is the same as the defining key and has the task axis set to the defining key
|
||||
// 2. the defining key is stored on constructed tasks
|
||||
// 3. resolvedScoped is replaced with the defining key as a value
|
||||
// 4. parseResult is replaced with a task that provides the result of parsing for the defined InputTask
|
||||
// Note: this must be idempotent.
|
||||
def finalTransforms(ss: Seq[Setting[_]]): Seq[Setting[_]] =
|
||||
{
|
||||
def isSpecial(key: AttributeKey[_]) = key == streams.key || key == parseResult.key
|
||||
def mapSpecial(to: ScopedKey[_]) = new (ScopedKey ~> ScopedKey){ def apply[T](key: ScopedKey[T]) =
|
||||
if(isSpecial(key.key))
|
||||
{
|
||||
val replaced = Scope.replaceThis(to.scope)(key.scope)
|
||||
ScopedKey(Scope.fillTaskAxis(replaced, to.key), key.key)
|
||||
}
|
||||
if(key.key == streams.key)
|
||||
ScopedKey(Scope.fillTaskAxis(Scope.replaceThis(to.scope)(key.scope), to.key), key.key)
|
||||
else key
|
||||
}
|
||||
def setDefining[T] = (key: ScopedKey[T], value: T) => value match {
|
||||
|
|
@ -142,9 +142,17 @@ object Load
|
|||
case _ => value
|
||||
}
|
||||
def setResolved(defining: ScopedKey[_]) = new (ScopedKey ~> Option) { def apply[T](key: ScopedKey[T]): Option[T] =
|
||||
if(key.key == resolvedScoped.key) Some(defining.asInstanceOf[T]) else None
|
||||
key.key match
|
||||
{
|
||||
case resolvedScoped.key => Some(defining.asInstanceOf[T])
|
||||
case parseResult.key =>
|
||||
import std.TaskExtra._
|
||||
val getResult = InputTask.inputMap map { m => m get defining getOrElse error("No parsed value for " + Project.display(defining) + "\n" + m) }
|
||||
Some(getResult.asInstanceOf[T])
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
ss.map(s => s mapReferenced mapSpecial(s.key) mapInit setDefining mapConstant setResolved(s.key))
|
||||
ss.map(s => s mapConstant setResolved(s.key) mapReferenced mapSpecial(s.key) mapInit setDefining )
|
||||
}
|
||||
def setDefinitionKey[T](tk: Task[T], key: ScopedKey[_]): Task[T] =
|
||||
if(isDummy(tk)) tk else Task(tk.info.set(Keys.taskDefinitionKey, key), tk.work)
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ private sealed trait InputDynamic[T] extends InputTask[T]
|
|||
{ outer =>
|
||||
type Result
|
||||
def parser: State => Parser[Result]
|
||||
def defined: ScopedKey[_]
|
||||
def task: Task[T]
|
||||
def mapTask[S](f: Task[T] => Task[S]) = new InputDynamic[S] {
|
||||
type Result = outer.Result
|
||||
def parser = outer.parser
|
||||
def task = f(outer.task)
|
||||
def defined = outer.defined
|
||||
}
|
||||
}
|
||||
object InputTask
|
||||
|
|
@ -44,20 +46,23 @@ object InputTask
|
|||
def separate[I,T](p: Initialize[State => Parser[I]])(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] =
|
||||
p.zipWith(action)((parser, act) => free(parser)(act))
|
||||
|
||||
private[sbt] lazy val inputMap: Task[Map[AnyRef,Any]] = mktask { error("Internal sbt error: input map not substituted.") }
|
||||
|
||||
// This interface allows the Parser to be constructed using other Settings, but not Tasks (which is desired).
|
||||
// The action can be constructed using Settings and Tasks and with the parse result injected into a Task.
|
||||
// This is the ugly part, requiring hooks in injectStreams and Act to handle the dummy task for the parse result.
|
||||
// However, this is results in a minimal interface to the full capabilities of an InputTask for users
|
||||
// This is the ugly part, requiring hooks in Load.finalTransforms and Aggregation.applyDynamicTasks
|
||||
// to handle the dummy task for the parse result.
|
||||
// However, this results in a minimal interface to the full capabilities of an InputTask for users
|
||||
def apply[I,T](p: Initialize[State => Parser[I]])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] =
|
||||
{
|
||||
val key = Keys.parseResult.asInstanceOf[TaskKey[I]]
|
||||
p.zipWith(action(key)) { (parserF, act) =>
|
||||
val key: TaskKey[I] = Keys.parseResult.asInstanceOf[TaskKey[I]]
|
||||
(p zip Keys.resolvedScoped.identity zipWith action(key)) { case ((parserF, scoped), act) =>
|
||||
new InputDynamic[T]
|
||||
{
|
||||
type Result = I
|
||||
def parser = parserF
|
||||
def task = act
|
||||
def defined = scoped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue