mirror of https://github.com/sbt/sbt.git
Use and methods instead of mapR,mapFailure,flatFailure,flatMapR
This commit is contained in:
parent
5a45faf41b
commit
538f687208
|
|
@ -78,4 +78,22 @@ object Tags
|
|||
// If there is only one task, allow it to execute.
|
||||
tags.getOrElse(Tags.All, 0) == 1
|
||||
}
|
||||
|
||||
/** Ensure that a task with the given tag only executes with tasks also tagged with the given tag.*/
|
||||
def exclusiveGroup(exclusiveTag: Tag): Rule = customLimit { (tags: Map[Tag,Int]) =>
|
||||
val exclusiveCount = tags.getOrElse(exclusiveTag, 0)
|
||||
val allCount = tags.getOrElse(Tags.All, 0)
|
||||
// If there are no exclusive tasks in this group, this rule adds no restrictions.
|
||||
exclusiveCount == 0 ||
|
||||
// If all tasks have this tag, allow them to execute.
|
||||
exclusiveCount == allCount ||
|
||||
// Always allow a group containing only one task to execute (fallthrough case).
|
||||
allCount == 1
|
||||
}
|
||||
|
||||
/** A task tagged with one of `exclusiveTags` will not execute with another task with any of the other tags in `exclusiveTags`.*/
|
||||
def exclusiveGroups(exclusiveTags: Tag*): Rule = customLimit { (tags: Map[Tag,Int]) =>
|
||||
val groups = exclusiveTags.count(tag => tags.getOrElse(tag, 0) > 0)
|
||||
groups <= 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ sealed trait ScopedTaskable[T] extends Scoped {
|
|||
* The scope is represented by a value of type Scope.
|
||||
* The name and the type are represented by a value of type AttributeKey[T].
|
||||
* Instances are constructed using the companion object. */
|
||||
sealed trait SettingKey[T] extends ScopedTaskable[T] with KeyedInitialize[T] with Scoped.ScopingSetting[SettingKey[T]] with Scoped.DefinableSetting[T]
|
||||
sealed abstract class SettingKey[T] extends ScopedTaskable[T] with KeyedInitialize[T] with Scoped.ScopingSetting[SettingKey[T]] with Scoped.DefinableSetting[T]
|
||||
{
|
||||
val key: AttributeKey[T]
|
||||
final def toTask: Initialize[Task[T]] = this apply inlineTask
|
||||
|
|
@ -48,7 +48,7 @@ sealed trait SettingKey[T] extends ScopedTaskable[T] with KeyedInitialize[T] wit
|
|||
* The scope is represented by a value of type Scope.
|
||||
* The name and the type are represented by a value of type AttributeKey[Task[T]].
|
||||
* Instances are constructed using the companion object. */
|
||||
sealed trait TaskKey[T] extends ScopedTaskable[T] with KeyedInitialize[Task[T]] with Scoped.ScopingSetting[TaskKey[T]] with Scoped.DefinableTask[T]
|
||||
sealed abstract class TaskKey[T] extends ScopedTaskable[T] with KeyedInitialize[Task[T]] with Scoped.ScopingSetting[TaskKey[T]] with Scoped.DefinableTask[T]
|
||||
{
|
||||
val key: AttributeKey[Task[T]]
|
||||
def toTask: Initialize[Task[T]] = this
|
||||
|
|
@ -144,6 +144,9 @@ object Scoped
|
|||
|
||||
def dependsOn(tasks: AnyInitTask*): Initialize[Task[S]] = (i, Initialize.joinAny[Task](tasks)) { (thisTask, deps) => thisTask.dependsOn(deps : _*) }
|
||||
|
||||
def failure: Initialize[Task[Incomplete]] = i(_.failure)
|
||||
def result: Initialize[Task[Result[S]]] = i(_.result)
|
||||
|
||||
def triggeredBy(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Def.triggeredBy)
|
||||
def runBefore(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Def.runBefore)
|
||||
private[this] def nonLocal(tasks: Seq[AnyInitTask], key: AttributeKey[Seq[Task[_]]]): Initialize[Task[S]] =
|
||||
|
|
@ -159,12 +162,8 @@ object Scoped
|
|||
{
|
||||
protected def onTask[T](f: Task[S] => Task[T]): Initialize[R[T]]
|
||||
|
||||
def flatMapR[T](f: Result[S] => Task[T]): Initialize[R[T]] = onTask(_ flatMapR f)
|
||||
def flatMap[T](f: S => Task[T]): Initialize[R[T]] = flatMapR(f compose successM)
|
||||
def map[T](f: S => T): Initialize[R[T]] = mapR(f compose successM)
|
||||
def mapR[T](f: Result[S] => T): Initialize[R[T]] = onTask(_ mapR f)
|
||||
def flatFailure[T](f: Incomplete => Task[T]): Initialize[R[T]] = flatMapR(f compose failM)
|
||||
def mapFailure[T](f: Incomplete => T): Initialize[R[T]] = mapR(f compose failM)
|
||||
def andFinally(fin: => Unit): Initialize[R[S]] = onTask(_ andFinally fin)
|
||||
def doFinally(t: Task[Unit]): Initialize[R[S]] = onTask(_ doFinally t)
|
||||
|
||||
|
|
@ -173,6 +172,18 @@ object Scoped
|
|||
|
||||
def tag(tags: Tag*): Initialize[R[S]] = onTask(_.tag(tags: _*))
|
||||
def tagw(tags: (Tag, Int)*): Initialize[R[S]] = onTask(_.tagw(tags : _*))
|
||||
|
||||
@deprecated("Use the `result` method to create a task that returns the full Result of this task. Then, call `flatMap` on the new task.", "0.13.0")
|
||||
def flatMapR[T](f: Result[S] => Task[T]): Initialize[R[T]] = onTask(_ flatMapR f)
|
||||
|
||||
@deprecated("Use the `result` method to create a task that returns the full Result of this task. Then, call `map` on the new task.", "0.13.0")
|
||||
def mapR[T](f: Result[S] => T): Initialize[R[T]] = onTask(_ mapR f)
|
||||
|
||||
@deprecated("Use the `failure` method to create a task that returns Incomplete when this task fails and then call `flatMap` on the new task.", "0.13.0")
|
||||
def flatFailure[T](f: Incomplete => Task[T]): Initialize[R[T]] = flatMapR(f compose failM)
|
||||
|
||||
@deprecated("Use the `failure` method to create a task that returns Incomplete when this task fails and then call `map` on the new task.", "0.13.0")
|
||||
def mapFailure[T](f: Incomplete => T): Initialize[R[T]] = mapR(f compose failM)
|
||||
}
|
||||
|
||||
type AnyInitTask = Initialize[Task[T]] forSome { type T }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package sbt
|
||||
|
||||
import org.scalacheck._
|
||||
import Gen.{genInt,listOf,genString}
|
||||
import Prop.forAll
|
||||
import Tags._
|
||||
|
||||
object TagsTest extends Properties("Tags")
|
||||
{
|
||||
def tagMap: Gen[TagMap] = for(ts <- listOf(tagAndFrequency)) yield ts.toMap
|
||||
def tagAndFrequency: Gen[(Tag, Int)] = for(t <- tag; count <- genInt) yield (t, count)
|
||||
def tag: Gen[Tag] = for(s <- genString) yield Tag(s)
|
||||
|
||||
property("exclusive allows all groups without the exclusive tag") = forAll { (tm: TagMap, tag: Tag) =>
|
||||
excl(tag)(tm - tag)
|
||||
}
|
||||
property("exclusive only allows a group with an excusive tag when the size is one") = forAll { (tm: TagMap, size: Int, etag: Tag) =>
|
||||
val tm: TagMap = tm.updated(etag, math.abs(size))
|
||||
excl(etag)(tm) == (size <= 1)
|
||||
}
|
||||
property("exclusive always allows a group of size one") = forAll { (etag: Tag, mapTag: Tag) =>
|
||||
val tm: TagMap = Map(mapTag -> 1)
|
||||
excl(etag)(tm)
|
||||
}
|
||||
|
||||
private[this] def excl(tag: Tag): TagMap => Boolean = predicate(exclusive(tag) :: Nil)
|
||||
|
||||
}
|
||||
|
|
@ -383,9 +383,97 @@ do not affect already logged information.
|
|||
Handling Failure
|
||||
----------------
|
||||
|
||||
This section discusses the ``andFinally``, ``mapFailure``, and ``mapR``
|
||||
This section discusses the ``failure``, ``result``, and ``andFinally``
|
||||
methods, which are used to handle failure of other tasks.
|
||||
|
||||
``failure``
|
||||
~~~~~~~~~~~
|
||||
|
||||
The ``failure`` method creates a new task that returns the ``Incomplete`` value
|
||||
when the original task fails to complete normally. If the original task succeeds,
|
||||
the new task fails.
|
||||
`Incomplete <https://github.com/harrah/xsbt/latest/api/sbt/Incomplete.html>`_
|
||||
is an exception with information about any tasks that caused the failure
|
||||
and any underlying exceptions thrown during task execution.
|
||||
|
||||
For example:
|
||||
|
||||
::
|
||||
|
||||
intTask := error("Failed.")
|
||||
|
||||
val intTask := {
|
||||
println("Ignoring failure: " + intTask.failure.value)
|
||||
3
|
||||
}
|
||||
|
||||
This overrides the ``intTask`` so that the original exception is printed and the constant ``3`` is returned.
|
||||
|
||||
``failure`` does not prevent other tasks that depend on the target
|
||||
from failing. Consider the following example:
|
||||
|
||||
::
|
||||
|
||||
intTask := if(shouldSucceed) 5 else error("Failed.")
|
||||
|
||||
// Return 3 if intTask fails. If intTask succeeds, this task will fail.
|
||||
aTask := intTask.failure.value - 2
|
||||
|
||||
// A new task that increments the result of intTask.
|
||||
bTask := intTask.value + 1
|
||||
|
||||
cTask := aTask.value + bTask.value
|
||||
|
||||
The following table lists the results of each task depending on the initially invoked task:
|
||||
|
||||
============== =============== ============= ============== ============== ==============
|
||||
invoked task intTask result aTask result bTask result cTask result overall result
|
||||
============== =============== ============= ============== ============== ==============
|
||||
intTask failure not run not run not run failure
|
||||
aTask failure success not run not run success
|
||||
bTask failure not run failure not run failure
|
||||
cTask failure success failure failure failure
|
||||
intTask success not run not run not run success
|
||||
aTask success failure not run not run failure
|
||||
bTask success not run success not run success
|
||||
cTask success failure success failure failure
|
||||
============== =============== ============= ============== ============== ==============
|
||||
|
||||
The overall result is always the same as the root task (the directly
|
||||
invoked task). A ``failure`` turns a success into a failure, and a failure into an ``Incomplete``.
|
||||
A normal task definition fails when any of its inputs fail and computes its value otherwise.
|
||||
|
||||
``result``
|
||||
~~~~~~~~~~
|
||||
|
||||
The ``result`` method creates a new task that returns the full ``Result[T]`` value for the original task.
|
||||
`Result <https://github.com/harrah/xsbt/latest/api/sbt/Result.html>`_
|
||||
has the same structure as ``Either[Incomplete, T]`` for a task result of
|
||||
type ``T``. That is, it has two subtypes:
|
||||
|
||||
- ``Inc``, which wraps ``Incomplete`` in case of failure
|
||||
- ``Value``, which wraps a task's result in case of success.
|
||||
|
||||
Thus, the task created by ``result`` executes whether or not the original task succeeds or fails.
|
||||
|
||||
For example:
|
||||
|
||||
::
|
||||
|
||||
intTask := error("Failed.")
|
||||
|
||||
intTask := intTask.result.value match {
|
||||
case Inc(inc: Incomplete) =>
|
||||
println("Ignoring failure: " + inc)
|
||||
3
|
||||
case Value(v) =>
|
||||
println("Using successful result: " + v)
|
||||
v
|
||||
}
|
||||
|
||||
This overrides the original ``intTask`` definition so that if the original task fails, the exception is printed and the constant ``3`` is returned. If it succeeds, the value is printed and returned.
|
||||
|
||||
|
||||
andFinally
|
||||
~~~~~~~~~~
|
||||
|
||||
|
|
@ -434,129 +522,3 @@ execution. This case is similar to the following plain Scala code:
|
|||
|
||||
It is obvious here that calling intTask() will never result in "finally"
|
||||
being printed.
|
||||
|
||||
mapFailure
|
||||
~~~~~~~~~~
|
||||
|
||||
``mapFailure`` accepts a function of type ``Incomplete => T``, where
|
||||
``T`` is a type parameter. In the case of multiple inputs, the function
|
||||
has type ``Seq[Incomplete] => T``.
|
||||
`Incomplete <https://github.com/harrah/xsbt/latest/api/sbt/Incomplete.html>`_
|
||||
is an exception with information about any tasks that caused the failure
|
||||
and any underlying exceptions thrown during task execution. The
|
||||
resulting task defined by ``mapFailure`` fails if its input succeeds and
|
||||
evaluates the provided function if it fails.
|
||||
|
||||
For example:
|
||||
|
||||
::
|
||||
|
||||
intTask := error("Failed.")
|
||||
|
||||
val intTaskImpl = intTask mapFailure { (inc: Incomplete) =>
|
||||
println("Ignoring failure: " + inc)
|
||||
3
|
||||
}
|
||||
|
||||
intTask := intTaskImpl.value
|
||||
|
||||
This overrides the ``intTask`` so that the original exception is printed and the constant ``3`` is returned.
|
||||
|
||||
``mapFailure`` does not prevent other tasks that depend on the target
|
||||
from failing. Consider the following example:
|
||||
|
||||
::
|
||||
|
||||
intTask := if(shouldSucceed) 5 else error("Failed.")
|
||||
|
||||
|
||||
|
||||
// return 3 if intTask fails. if it succeeds, this task will fail
|
||||
val aTaskImpl = intTask mapFailure { (inc: Incomplete) => 3 }
|
||||
|
||||
aTask := aTaskImpl.value
|
||||
|
||||
// a new task that increments the result of intTask
|
||||
bTask := intTask.value + 1
|
||||
|
||||
cTask := aTask.value + bTask.value
|
||||
|
||||
The following table lists the results of each task depending on the initially invoked task:
|
||||
|
||||
============== =============== ============= ============== ============== ==============
|
||||
invoked task intTask result aTask result bTask result cTask result overall result
|
||||
============== =============== ============= ============== ============== ==============
|
||||
intTask failure not run not run not run failure
|
||||
aTask failure success not run not run success
|
||||
bTask failure not run failure not run failure
|
||||
cTask failure success failure failure failure
|
||||
intTask success not run not run not run success
|
||||
aTask success failure not run not run failure
|
||||
bTask success not run success not run success
|
||||
cTask success failure success failure failure
|
||||
============== =============== ============= ============== ============== ==============
|
||||
|
||||
The overall result is always the same as the root task (the directly
|
||||
invoked task). A ``mapFailure`` turns a success into a failure, and a
|
||||
failure into whatever the result of evaluating the supplied function is.
|
||||
A normal task definition fails when the input fails and applies the supplied function
|
||||
to a successfully completed input.
|
||||
|
||||
In the case of more than one input, ``mapFailure`` fails if all inputs
|
||||
succeed. If at least one input fails, the supplied function is provided
|
||||
with the list of ``Incomplete``\ s. For example:
|
||||
|
||||
::
|
||||
|
||||
val cTaskImpl = (aTask, bTask) mapFailure { (incs: Seq[Incomplete]) => 3 }
|
||||
|
||||
cTask := cTaskImpl.value
|
||||
|
||||
The following table lists the results of invoking ``cTask``, depending
|
||||
on the success of ``aTask`` and ``bTask``:
|
||||
|
||||
|
||||
============= ============= =============
|
||||
aTask result bTask result cTask result
|
||||
============= ============= =============
|
||||
failure failure success
|
||||
failure success success
|
||||
success failure success
|
||||
success success failure
|
||||
============= ============= =============
|
||||
|
||||
mapR
|
||||
~~~~
|
||||
|
||||
``mapR`` accepts a function of type ``Result[S] => T``, where ``S`` is
|
||||
the type of the task being mapped and ``T`` is a type parameter. In the
|
||||
case of multiple inputs, the function has type
|
||||
``(Result[A], Result[B], ...) => T``.
|
||||
`Result <https://github.com/harrah/xsbt/latest/api/sbt/Result.html>`_
|
||||
has the same structure as ``Either[Incomplete, S]`` for a task result of
|
||||
type ``S``. That is, it has two subtypes:
|
||||
|
||||
- ``Inc``, which wraps ``Incomplete`` in case of failure
|
||||
- ``Value``, which wraps a task's result in case of success.
|
||||
|
||||
Thus, ``mapR`` is always invoked whether or not the original task
|
||||
succeeds or fails.
|
||||
|
||||
For example:
|
||||
|
||||
::
|
||||
|
||||
intTask := error("Failed.")
|
||||
|
||||
val intTaskImpl = intTask mapR {
|
||||
case Inc(inc: Incomplete) =>
|
||||
println("Ignoring failure: " + inc)
|
||||
3
|
||||
case Value(v) =>
|
||||
println("Using successful result: " + v)
|
||||
v
|
||||
}
|
||||
|
||||
intTask := intTaskImpl.value
|
||||
|
||||
This overrides the original ``intTask`` definition so that if the original task fails, the exception is printed and the constant ``3`` is returned. If it succeeds, the value is printed and returned.
|
||||
|
|
|
|||
|
|
@ -20,18 +20,29 @@ sealed trait MultiInTask[K[L[x]]]
|
|||
|
||||
sealed trait SingleInTask[S]
|
||||
{
|
||||
def flatMapR[T](f: Result[S] => Task[T]): Task[T]
|
||||
def flatMap[T](f: S => Task[T]): Task[T]
|
||||
def map[T](f: S => T): Task[T]
|
||||
def mapR[T](f: Result[S] => T): Task[T]
|
||||
def flatFailure[T](f: Incomplete => Task[T]): Task[T]
|
||||
def mapFailure[T](f: Incomplete => T): Task[T]
|
||||
def dependsOn(tasks: Task[_]*): Task[S]
|
||||
def andFinally(fin: => Unit): Task[S]
|
||||
def doFinally(t: Task[Unit]): Task[S]
|
||||
|
||||
def || [T >: S](alt: Task[T]): Task[T]
|
||||
def && [T](alt: Task[T]): Task[T]
|
||||
|
||||
def failure: Task[Incomplete]
|
||||
def result: Task[Result[S]]
|
||||
|
||||
@deprecated("Use the `result` method to create a task that returns the full Result of this task. Then, call `map` on the new task.", "0.13.0")
|
||||
def mapR[T](f: Result[S] => T): Task[T]
|
||||
|
||||
@deprecated("Use the `failure` method to create a task that returns Incomplete when this task fails and then call `flatMap` on the new task.", "0.13.0")
|
||||
def flatFailure[T](f: Incomplete => Task[T]): Task[T]
|
||||
|
||||
@deprecated("Use the `failure` method to create a task that returns Incomplete when this task fails and then call `mapFailure` on the new task.", "0.13.0")
|
||||
def mapFailure[T](f: Incomplete => T): Task[T]
|
||||
|
||||
@deprecated("Use the `result` method to create a task that returns the full Result of this task. Then, call `flatMap` on the new task.", "0.13.0")
|
||||
def flatMapR[T](f: Result[S] => Task[T]): Task[T]
|
||||
}
|
||||
sealed trait TaskInfo[S]
|
||||
{
|
||||
|
|
@ -114,6 +125,9 @@ trait TaskExtra
|
|||
final implicit def singleInputTask[S](in: Task[S]): SingleInTask[S] = new SingleInTask[S] {
|
||||
type K[L[x]] = L[S]
|
||||
private def ml = AList.single[S]
|
||||
|
||||
def failure: Task[Incomplete] = mapFailure(idFun)
|
||||
def result: Task[Result[S]] = mapR(idFun)
|
||||
|
||||
def flatMapR[T](f: Result[S] => Task[T]): Task[T] = new FlatMapped[T, K](in, f, ml)
|
||||
def mapR[T](f: Result[S] => T): Task[T] = new Mapped[T, K](in, f, ml)
|
||||
|
|
|
|||
Loading…
Reference in New Issue