mirror of https://github.com/sbt/sbt.git
Merge pull request #5260 from eatkins/state-transform
Improve StateTransform
This commit is contained in:
commit
21f09e6025
|
|
@ -515,17 +515,14 @@ object EvaluateTask {
|
|||
state: State,
|
||||
root: Task[T]
|
||||
): (State, Result[T]) = {
|
||||
val newState = results(root) match {
|
||||
case Value(KeyValue(_, st: StateTransform) :: Nil) => st.state
|
||||
case _ => stateTransform(results)(state)
|
||||
}
|
||||
(newState, results(root))
|
||||
(stateTransform(results)(state), results(root))
|
||||
}
|
||||
def stateTransform(results: RMap[Task, Result]): State => State =
|
||||
Function.chain(
|
||||
results.toTypedSeq flatMap {
|
||||
case results.TPair(Task(info, _), Value(v)) => info.post(v) get transformState
|
||||
case _ => Nil
|
||||
case results.TPair(_, Value(KeyValue(_, st: StateTransform))) => Some(st.transform)
|
||||
case results.TPair(Task(info, _), Value(v)) => info.post(v) get transformState
|
||||
case _ => Nil
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,14 +7,43 @@
|
|||
|
||||
package sbt
|
||||
|
||||
final class StateTransform(val state: State) {
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case that: StateTransform => this.state == that.state
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = state.hashCode
|
||||
override def toString: String = s"StateTransform($state)"
|
||||
/**
|
||||
* Provides a mechanism for a task to transform the state based on the result of the task. For
|
||||
* example:
|
||||
* {{{
|
||||
* val foo = AttributeKey[String]("foo")
|
||||
* val setFoo = taskKey[StateTransform]("")
|
||||
* setFoo := {
|
||||
* state.value.get(foo) match {
|
||||
* case None => StateTransform(_.put(foo, "foo"))
|
||||
* case _ => StateTransform(identity)
|
||||
* }
|
||||
* }
|
||||
* val getFoo = taskKey[Option[String]]
|
||||
* getFoo := state.value.get(foo)
|
||||
* }}}
|
||||
* Prior to a call to `setFoo`, `getFoo` will return `None`. After a call to `setFoo`, `getFoo` will
|
||||
* return `Some("foo")`.
|
||||
*/
|
||||
final class StateTransform private (val transform: State => State, stateProxy: () => State) {
|
||||
@deprecated("Exists only for binary compatibility with 1.3.x.", "1.4.0")
|
||||
private[sbt] def state: State = stateProxy()
|
||||
@deprecated("1.4.0", "Use the constructor that takes a transform function.")
|
||||
private[sbt] def this(state: State) = this((_: State) => state, () => state)
|
||||
}
|
||||
|
||||
object StateTransform {
|
||||
@deprecated("Exists only for binary compatibility with 1.3.x", "1.4.0")
|
||||
def apply(state: State): State = state
|
||||
|
||||
/**
|
||||
* Create an instance of [[StateTransform]].
|
||||
* @param transform the transformation to apply after task evaluation has completed
|
||||
* @return the [[StateTransform]].
|
||||
*/
|
||||
def apply(transform: State => State) =
|
||||
new StateTransform(
|
||||
transform,
|
||||
() => throw new IllegalStateException("No state was added to the StateTransform.")
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,8 @@ private[sbt] object Continuous extends DeprecatedContinuous {
|
|||
private[sbt] def continuousTask: Def.Initialize[InputTask[StateTransform]] =
|
||||
Def.inputTask {
|
||||
val (initialCount, commands) = continuousParser.parsed
|
||||
new StateTransform(runToTermination(state.value, commands, initialCount, isCommand = false))
|
||||
val newState = runToTermination(state.value, commands, initialCount, isCommand = false)
|
||||
StateTransform(_ => newState)
|
||||
}
|
||||
|
||||
private[sbt] val dynamicInputs = taskKey[Option[mutable.Set[DynamicInput]]](
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ private[sbt] object CheckBuildSources {
|
|||
val st: State = state.value
|
||||
val firstTime = st.get(hasCheckedMetaBuild).fold(true)(_.compareAndSet(false, true))
|
||||
(onChangedBuildSource in Scope.Global).value match {
|
||||
case IgnoreSourceChanges => new StateTransform(st)
|
||||
case IgnoreSourceChanges => StateTransform(identity)
|
||||
case o =>
|
||||
import sbt.nio.FileStamp.Formats._
|
||||
logger.debug("Checking for meta build source updates")
|
||||
|
|
@ -47,16 +47,16 @@ private[sbt] object CheckBuildSources {
|
|||
logger.info(s"$prefix\nReloading sbt...")
|
||||
val remaining =
|
||||
Exec("reload", None, None) :: st.currentCommand.toList ::: st.remainingCommands
|
||||
new StateTransform(st.copy(currentCommand = None, remainingCommands = remaining))
|
||||
StateTransform(_.copy(currentCommand = None, remainingCommands = remaining))
|
||||
} else {
|
||||
val tail = "Apply these changes by running `reload`.\nAutomatically reload the " +
|
||||
"build when source changes are detected by setting " +
|
||||
"`Global / onChangedBuildSource := ReloadOnSourceChanges`.\nDisable this " +
|
||||
"warning by setting `Global / onChangedBuildSource := IgnoreSourceChanges`."
|
||||
logger.warn(s"$prefix\n$tail")
|
||||
new StateTransform(st)
|
||||
StateTransform(identity)
|
||||
}
|
||||
case _ => new StateTransform(st)
|
||||
case _ => StateTransform(identity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
import complete.DefaultParsers._
|
||||
import complete.Parser
|
||||
import sbt.Def.Initialize
|
||||
|
||||
val keep = taskKey[Int]("")
|
||||
val checkKeep = inputKey[Unit]("")
|
||||
|
||||
keep := (getPrevious(keep) map { case None => 3; case Some(x) => x + 1 } keepAs keep).value
|
||||
checkKeep := inputCheck((ctx, s) => Space ~> str(getFromContext(keep, ctx, s))).evaluated
|
||||
|
||||
val foo = AttributeKey[Int]("foo")
|
||||
val transform = taskKey[StateTransform]("")
|
||||
transform := {
|
||||
keep.value
|
||||
StateTransform(_.put(foo, 1))
|
||||
}
|
||||
|
||||
def inputCheck[T](f: (ScopedKey[_], State) => Parser[T]): Initialize[InputTask[Unit]] =
|
||||
InputTask(resolvedScoped(ctx => (s: State) => f(ctx, s)))(dummyTask)
|
||||
|
||||
val checkTransform = taskKey[Unit]("")
|
||||
checkTransform := {
|
||||
assert(state.value.get(foo).contains(1))
|
||||
}
|
||||
|
||||
def dummyTask: Any => Initialize[Task[Unit]] =
|
||||
(_: Any) =>
|
||||
maxErrors map { _ =>
|
||||
()
|
||||
}
|
||||
def str(o: Option[Int]) = o match { case None => "blue"; case Some(i) => i.toString }
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
> checkKeep blue
|
||||
|
||||
-> checkTransform
|
||||
|
||||
> transform
|
||||
|
||||
> checkKeep 3
|
||||
|
||||
> checkTransform
|
||||
|
||||
> transform
|
||||
|
||||
> checkKeep 4
|
||||
|
|
@ -38,8 +38,8 @@ object Build {
|
|||
checkStringValue := checkStringValueImpl.evaluated,
|
||||
watchOnFileInputEvent := { (_, _) => Watch.CancelWatch },
|
||||
watchTasks := Def.inputTask {
|
||||
val prev = watchTasks.evaluated
|
||||
new StateTransform(prev.state.fail)
|
||||
watchTasks.evaluated
|
||||
StateTransform(_.fail)
|
||||
}.evaluated
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ object Build {
|
|||
watchOnFileInputEvent := { (_, _) => Watch.CancelWatch },
|
||||
watchTasks := Def.inputTask {
|
||||
val prev = watchTasks.evaluated
|
||||
new StateTransform(prev.state.fail)
|
||||
StateTransform(_.fail)
|
||||
}.evaluated
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue