mirror of https://github.com/sbt/sbt.git
open up ExecuteProgress, and adds a few keys
Fixes #4461 This opens up ExecuteProgress API that's been around under private[sbt]. Since the state passing mechanism hasn't been used, I got rid of it. The build user can configure the build using two keys Boolean `taskProgress` and `State => Seq[TaskProgress]` `progressReports`. `useSuperShell` is lightweight key on/off switch for the super shell that can be used as follows: ```scala Global / SettingKey[Boolean]("useSuperShell") := false ```
This commit is contained in:
parent
354f85cecb
commit
86abe3ed60
|
|
@ -291,7 +291,10 @@ lazy val taskProj = (project in file("tasks"))
|
||||||
name := "Tasks",
|
name := "Tasks",
|
||||||
mimaSettings,
|
mimaSettings,
|
||||||
mimaBinaryIssueFilters ++= Seq(
|
mimaBinaryIssueFilters ++= Seq(
|
||||||
exclude[ReversedMissingMethodProblem]("sbt.ExecuteProgress.stop")
|
// ok because sbt.ExecuteProgress has been under private[sbt]
|
||||||
|
exclude[IncompatibleResultTypeProblem]("sbt.ExecuteProgress.initial"),
|
||||||
|
exclude[DirectMissingMethodProblem]("sbt.ExecuteProgress.*"),
|
||||||
|
exclude[ReversedMissingMethodProblem]("sbt.ExecuteProgress.*"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.configure(addSbtUtilControl)
|
.configure(addSbtUtilControl)
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,15 @@ object Defaults extends BuildCommon {
|
||||||
() =>
|
() =>
|
||||||
{ IO.delete(dir); IO.createDirectory(dir) }
|
{ IO.delete(dir); IO.createDirectory(dir) }
|
||||||
},
|
},
|
||||||
|
useSuperShell :== sbt.internal.TaskProgress.isEnabled,
|
||||||
|
progressReports := { (s: State) =>
|
||||||
|
val progress = useSuperShell.value
|
||||||
|
val rs = EvaluateTask.taskTimingProgress.toVector ++ {
|
||||||
|
if (progress) Vector(EvaluateTask.taskProgress(s))
|
||||||
|
else Vector()
|
||||||
|
}
|
||||||
|
rs map { Keys.TaskProgress(_) }
|
||||||
|
},
|
||||||
Previous.cache := new Previous(
|
Previous.cache := new Previous(
|
||||||
Def.streamsManagerKey.value,
|
Def.streamsManagerKey.value,
|
||||||
Previous.references.value.getReferences
|
Previous.references.value.getReferences
|
||||||
|
|
|
||||||
|
|
@ -162,19 +162,21 @@ object EvaluateTask {
|
||||||
import Keys.state
|
import Keys.state
|
||||||
|
|
||||||
lazy private val sharedProgress = new TaskTimings(reportOnShutdown = true)
|
lazy private val sharedProgress = new TaskTimings(reportOnShutdown = true)
|
||||||
|
def taskTimingProgress: Option[ExecuteProgress[Task]] =
|
||||||
// sbt-pgp calls this
|
|
||||||
private[sbt] def defaultProgress(): ExecuteProgress[Task] = ExecuteProgress.empty[Task]
|
|
||||||
private[sbt] def defaultProgress(currentRef: ProjectRef): ExecuteProgress[Task] =
|
|
||||||
if (java.lang.Boolean.getBoolean("sbt.task.timings")) {
|
if (java.lang.Boolean.getBoolean("sbt.task.timings")) {
|
||||||
if (java.lang.Boolean.getBoolean("sbt.task.timings.on.shutdown"))
|
if (java.lang.Boolean.getBoolean("sbt.task.timings.on.shutdown"))
|
||||||
sharedProgress
|
Some(sharedProgress)
|
||||||
else
|
else
|
||||||
new TaskTimings(reportOnShutdown = false)
|
Some(new TaskTimings(reportOnShutdown = false))
|
||||||
} else {
|
} else None
|
||||||
if (ConsoleAppender.showProgress) new TaskProgress(currentRef)
|
|
||||||
else ExecuteProgress.empty[Task]
|
def taskProgress(state: State): ExecuteProgress[Task] = {
|
||||||
}
|
new TaskProgress(Project.extract(state).currentRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sbt-pgp calls this
|
||||||
|
@deprecated("No longer used", "1.3.0")
|
||||||
|
private[sbt] def defaultProgress(): ExecuteProgress[Task] = ExecuteProgress.empty[Task]
|
||||||
|
|
||||||
val SystemProcessors = Runtime.getRuntime.availableProcessors
|
val SystemProcessors = Runtime.getRuntime.availableProcessors
|
||||||
|
|
||||||
|
|
@ -232,13 +234,22 @@ object EvaluateTask {
|
||||||
state: State
|
state: State
|
||||||
): ExecuteProgress[Task] = {
|
): ExecuteProgress[Task] = {
|
||||||
import Types.const
|
import Types.const
|
||||||
val maker: State => Keys.TaskProgress = getSetting(
|
val maker: State => Seq[Keys.TaskProgress] = getSetting(
|
||||||
Keys.executeProgress,
|
Keys.progressReports,
|
||||||
const(new Keys.TaskProgress(defaultProgress(extracted.currentRef))),
|
const(Seq()),
|
||||||
extracted,
|
extracted,
|
||||||
structure
|
structure
|
||||||
)
|
)
|
||||||
maker(state).progress
|
val reporters = maker(state) map { _.progress }
|
||||||
|
// configure the logger for super shell
|
||||||
|
ConsoleAppender.setShowProgress((reporters collect {
|
||||||
|
case p: TaskProgress => ()
|
||||||
|
}).nonEmpty)
|
||||||
|
reporters match {
|
||||||
|
case xs if xs.isEmpty => ExecuteProgress.empty[Task]
|
||||||
|
case xs if xs.size == 1 => xs.head
|
||||||
|
case xs => ExecuteProgress.aggregate[Task](xs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO - Should this pull from Global or from the project itself?
|
// TODO - Should this pull from Global or from the project itself?
|
||||||
private[sbt] def forcegc(extracted: Extracted, structure: BuildStructure): Boolean =
|
private[sbt] def forcegc(extracted: Extracted, structure: BuildStructure): Boolean =
|
||||||
|
|
@ -258,7 +269,7 @@ object EvaluateTask {
|
||||||
extracted: Extracted,
|
extracted: Extracted,
|
||||||
structure: BuildStructure
|
structure: BuildStructure
|
||||||
): T =
|
): T =
|
||||||
key in extracted.currentRef get structure.data getOrElse default
|
(key in extracted.currentRef).get(structure.data).getOrElse(default)
|
||||||
|
|
||||||
def injectSettings: Seq[Setting[_]] = Seq(
|
def injectSettings: Seq[Setting[_]] = Seq(
|
||||||
(state in Global) ::= dummyState,
|
(state in Global) ::= dummyState,
|
||||||
|
|
|
||||||
|
|
@ -456,6 +456,18 @@ object Keys {
|
||||||
val (executionRoots, dummyRoots) = Def.dummy[Seq[ScopedKey[_]]]("executionRoots", "The list of root tasks for this task execution. Roots are the top-level tasks that were directly requested to be run.")
|
val (executionRoots, dummyRoots) = Def.dummy[Seq[ScopedKey[_]]]("executionRoots", "The list of root tasks for this task execution. Roots are the top-level tasks that were directly requested to be run.")
|
||||||
val state = Def.stateKey
|
val state = Def.stateKey
|
||||||
val streamsManager = Def.streamsManagerKey
|
val streamsManager = Def.streamsManagerKey
|
||||||
|
// wrapper to work around SI-2915
|
||||||
|
final class TaskProgress(val progress: ExecuteProgress[Task])
|
||||||
|
object TaskProgress {
|
||||||
|
def apply(progress: ExecuteProgress[Task]): TaskProgress = new TaskProgress(progress)
|
||||||
|
}
|
||||||
|
val useSuperShell = settingKey[Boolean]("Enables (true) or disables the super shell.")
|
||||||
|
// This key can be used to add custom ExecuteProgress instances
|
||||||
|
val progressReports = settingKey[State => Seq[TaskProgress]]("A function that returns a list of progress reporters.").withRank(DTask)
|
||||||
|
private[sbt] val postProgressReports = settingKey[Unit]("Internally used to modify logger.").withRank(DTask)
|
||||||
|
@deprecated("No longer used", "1.3.0")
|
||||||
|
private[sbt] val executeProgress = settingKey[State => TaskProgress]("Experimental task execution listener.").withRank(DTask)
|
||||||
|
|
||||||
private[sbt] val globalFileTreeView = AttributeKey[FileTreeDataView[FileCacheEntry]](
|
private[sbt] val globalFileTreeView = AttributeKey[FileTreeDataView[FileCacheEntry]](
|
||||||
"globalFileTreeView",
|
"globalFileTreeView",
|
||||||
"Provides a view into the file system that may or may not cache the tree in memory",
|
"Provides a view into the file system that may or may not cache the tree in memory",
|
||||||
|
|
@ -468,10 +480,6 @@ object Keys {
|
||||||
val globalPluginUpdate = taskKey[UpdateReport]("A hook to get the UpdateReport of the global plugin.").withRank(DTask)
|
val globalPluginUpdate = taskKey[UpdateReport]("A hook to get the UpdateReport of the global plugin.").withRank(DTask)
|
||||||
val classLoaderCache = taskKey[internal.ClassLoaderCache]("The cache of ClassLoaders to be used for layering in tasks that invoke other java code").withRank(DTask)
|
val classLoaderCache = taskKey[internal.ClassLoaderCache]("The cache of ClassLoaders to be used for layering in tasks that invoke other java code").withRank(DTask)
|
||||||
private[sbt] val taskRepository = AttributeKey[TaskRepository.Repr]("task-repository", "A repository that can be used to cache arbitrary values for a given task key that can be read or filled during task evaluation.", 10000)
|
private[sbt] val taskRepository = AttributeKey[TaskRepository.Repr]("task-repository", "A repository that can be used to cache arbitrary values for a given task key that can be read or filled during task evaluation.", 10000)
|
||||||
|
|
||||||
// wrapper to work around SI-2915
|
|
||||||
private[sbt] final class TaskProgress(val progress: ExecuteProgress[Task])
|
|
||||||
private[sbt] val executeProgress = settingKey[State => TaskProgress]("Experimental task execution listener.").withRank(DTask)
|
|
||||||
private[sbt] val taskCancelStrategy = settingKey[State => TaskCancellationStrategy]("Experimental task cancellation handler.").withRank(DTask)
|
private[sbt] val taskCancelStrategy = settingKey[State => TaskCancellationStrategy]("Experimental task cancellation handler.").withRank(DTask)
|
||||||
|
|
||||||
// Experimental in sbt 0.13.2 to enable grabbing semantic compile failures.
|
// Experimental in sbt 0.13.2 to enable grabbing semantic compile failures.
|
||||||
|
|
|
||||||
|
|
@ -138,20 +138,6 @@ object StandardMain {
|
||||||
// This is to workaround https://github.com/sbt/io/issues/110
|
// This is to workaround https://github.com/sbt/io/issues/110
|
||||||
sys.props.put("jna.nosys", "true")
|
sys.props.put("jna.nosys", "true")
|
||||||
|
|
||||||
ConsoleAppender.setTerminalWidth(JLine.usingTerminal(_.getWidth))
|
|
||||||
ConsoleAppender.setShowProgress(
|
|
||||||
ConsoleAppender.formatEnabledInEnv && sys.props
|
|
||||||
.get("sbt.progress")
|
|
||||||
.flatMap({ s =>
|
|
||||||
ConsoleAppender.parseLogOption(s) match {
|
|
||||||
case LogOption.Always => Some(true)
|
|
||||||
case LogOption.Never => Some(false)
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.getOrElse(true)
|
|
||||||
)
|
|
||||||
|
|
||||||
import BasicCommandStrings.isEarlyCommand
|
import BasicCommandStrings.isEarlyCommand
|
||||||
val userCommands = configuration.arguments.map(_.trim)
|
val userCommands = configuration.arguments.map(_.trim)
|
||||||
val (earlyCommands, normalCommands) = (preCommands ++ userCommands).partition(isEarlyCommand)
|
val (earlyCommands, normalCommands) = (preCommands ++ userCommands).partition(isEarlyCommand)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
package sbt
|
package sbt
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import sbt.internal.util.{ RMap, ConsoleOut }
|
import sbt.internal.util.{ RMap, ConsoleOut, ConsoleAppender, LogOption, JLine }
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import scala.concurrent.{ blocking, Future, ExecutionContext }
|
import scala.concurrent.{ blocking, Future, ExecutionContext }
|
||||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
|
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
|
||||||
|
|
@ -20,8 +20,6 @@ import TaskProgress._
|
||||||
* implements task progress display on the shell.
|
* implements task progress display on the shell.
|
||||||
*/
|
*/
|
||||||
private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecuteProgress[Task] {
|
private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecuteProgress[Task] {
|
||||||
type S = Unit
|
|
||||||
|
|
||||||
private[this] val showScopedKey = Def.showRelativeKey2(currentRef)
|
private[this] val showScopedKey = Def.showRelativeKey2(currentRef)
|
||||||
// private[this] var start = 0L
|
// private[this] var start = 0L
|
||||||
private[this] val activeTasks = new ConcurrentHashMap[Task[_], Long]
|
private[this] val activeTasks = new ConcurrentHashMap[Task[_], Long]
|
||||||
|
|
@ -33,9 +31,11 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
||||||
private[this] val isAllCompleted = new AtomicBoolean(false)
|
private[this] val isAllCompleted = new AtomicBoolean(false)
|
||||||
private[this] val isStopped = new AtomicBoolean(false)
|
private[this] val isStopped = new AtomicBoolean(false)
|
||||||
|
|
||||||
override def initial: Unit = ()
|
override def initial(): Unit = {
|
||||||
override def registered(
|
ConsoleAppender.setTerminalWidth(JLine.usingTerminal(_.getWidth))
|
||||||
state: Unit,
|
}
|
||||||
|
|
||||||
|
override def afterRegistered(
|
||||||
task: Task[_],
|
task: Task[_],
|
||||||
allDeps: Iterable[Task[_]],
|
allDeps: Iterable[Task[_]],
|
||||||
pendingDeps: Iterable[Task[_]]
|
pendingDeps: Iterable[Task[_]]
|
||||||
|
|
@ -47,16 +47,16 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override def ready(state: Unit, task: Task[_]): Unit = {
|
override def afterReady(task: Task[_]): Unit = {
|
||||||
isReady.set(true)
|
isReady.set(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def workStarting(task: Task[_]): Unit = {
|
override def beforeWork(task: Task[_]): Unit = {
|
||||||
activeTasks.put(task, System.nanoTime)
|
activeTasks.put(task, System.nanoTime)
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def workFinished[A](task: Task[A], result: Either[Task[A], Result[A]]): Unit = {
|
override def afterWork[A](task: Task[A], result: Either[Task[A], Result[A]]): Unit = {
|
||||||
val start = activeTasks.get(task)
|
val start = activeTasks.get(task)
|
||||||
timings.put(task, System.nanoTime - start)
|
timings.put(task, System.nanoTime - start)
|
||||||
activeTasks.remove(task)
|
activeTasks.remove(task)
|
||||||
|
|
@ -66,7 +66,7 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def completed[A](state: Unit, task: Task[A], result: Result[A]): Unit = ()
|
override def afterCompleted[A](task: Task[A], result: Result[A]): Unit = ()
|
||||||
|
|
||||||
override def stop(): Unit = {
|
override def stop(): Unit = {
|
||||||
isStopped.set(true)
|
isStopped.set(true)
|
||||||
|
|
@ -88,7 +88,7 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] val console = ConsoleOut.systemOut
|
private[this] val console = ConsoleOut.systemOut
|
||||||
override def allCompleted(state: Unit, results: RMap[Task, Result]): Unit = {
|
override def afterAllCompleted(results: RMap[Task, Result]): Unit = {
|
||||||
isAllCompleted.set(true)
|
isAllCompleted.set(true)
|
||||||
// completionReport()
|
// completionReport()
|
||||||
}
|
}
|
||||||
|
|
@ -167,4 +167,17 @@ private[sbt] object TaskProgress {
|
||||||
def cursorUp(n: Int): String = s"\u001B[${n}A"
|
def cursorUp(n: Int): String = s"\u001B[${n}A"
|
||||||
def cursorDown(n: Int): String = s"\u001B[${n}B"
|
def cursorDown(n: Int): String = s"\u001B[${n}B"
|
||||||
final val CursorDown1 = cursorDown(1)
|
final val CursorDown1 = cursorDown(1)
|
||||||
|
|
||||||
|
def isEnabled: Boolean =
|
||||||
|
ConsoleAppender.formatEnabledInEnv && sys.props
|
||||||
|
.get("sbt.supershell")
|
||||||
|
.flatMap(
|
||||||
|
str =>
|
||||||
|
ConsoleAppender.parseLogOption(str) match {
|
||||||
|
case LogOption.Always => Some(true)
|
||||||
|
case LogOption.Never => Some(false)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.getOrElse(true)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,6 @@ private[sbt] final class TaskTimings(reportOnShutdown: Boolean) extends ExecuteP
|
||||||
("ms", 6)
|
("ms", 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
type S = Unit
|
|
||||||
|
|
||||||
if (reportOnShutdown) {
|
if (reportOnShutdown) {
|
||||||
start = System.nanoTime
|
start = System.nanoTime
|
||||||
Runtime.getRuntime.addShutdownHook(new Thread {
|
Runtime.getRuntime.addShutdownHook(new Thread {
|
||||||
|
|
@ -48,35 +46,34 @@ private[sbt] final class TaskTimings(reportOnShutdown: Boolean) extends ExecuteP
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
def initial = {
|
override def initial(): Unit = {
|
||||||
if (!reportOnShutdown)
|
if (!reportOnShutdown)
|
||||||
start = System.nanoTime
|
start = System.nanoTime
|
||||||
}
|
}
|
||||||
def registered(
|
override def afterRegistered(
|
||||||
state: Unit,
|
|
||||||
task: Task[_],
|
task: Task[_],
|
||||||
allDeps: Iterable[Task[_]],
|
allDeps: Iterable[Task[_]],
|
||||||
pendingDeps: Iterable[Task[_]]
|
pendingDeps: Iterable[Task[_]]
|
||||||
) = {
|
): Unit = {
|
||||||
pendingDeps foreach { t =>
|
pendingDeps foreach { t =>
|
||||||
if (transformNode(t).isEmpty) anonOwners.put(t, task)
|
if (transformNode(t).isEmpty) anonOwners.put(t, task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def ready(state: Unit, task: Task[_]) = ()
|
override def afterReady(task: Task[_]): Unit = ()
|
||||||
def workStarting(task: Task[_]) = { timings.put(task, System.nanoTime); () }
|
override def beforeWork(task: Task[_]): Unit = { timings.put(task, System.nanoTime); () }
|
||||||
def workFinished[T](task: Task[T], result: Either[Task[T], Result[T]]) = {
|
override def afterWork[T](task: Task[T], result: Either[Task[T], Result[T]]) = {
|
||||||
timings.put(task, System.nanoTime - timings.get(task))
|
timings.put(task, System.nanoTime - timings.get(task))
|
||||||
result.left.foreach { t =>
|
result.left.foreach { t =>
|
||||||
calledBy.put(t, task)
|
calledBy.put(t, task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def completed[T](state: Unit, task: Task[T], result: Result[T]) = ()
|
override def afterCompleted[T](task: Task[T], result: Result[T]): Unit = ()
|
||||||
def allCompleted(state: Unit, results: RMap[Task, Result]) =
|
override def afterAllCompleted(results: RMap[Task, Result]): Unit =
|
||||||
if (!reportOnShutdown) {
|
if (!reportOnShutdown) {
|
||||||
report()
|
report()
|
||||||
}
|
}
|
||||||
|
|
||||||
def stop(): Unit = ()
|
override def stop(): Unit = ()
|
||||||
|
|
||||||
private val reFilePath = raw"\{[^}]+\}".r
|
private val reFilePath = raw"\{[^}]+\}".r
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,14 +69,14 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
||||||
case None => results(a)
|
case None => results(a)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
private[this] var progressState: progress.S = progress.initial
|
|
||||||
|
|
||||||
private[this] type State = State.Value
|
private[this] type State = State.Value
|
||||||
private[this] object State extends Enumeration {
|
private[this] object State extends Enumeration {
|
||||||
val Pending, Running, Calling, Done = Value
|
val Pending, Running, Calling, Done = Value
|
||||||
}
|
}
|
||||||
import State.{ Pending, Running, Calling, Done }
|
import State.{ Pending, Running, Calling, Done }
|
||||||
|
|
||||||
|
val init = progress.initial()
|
||||||
|
|
||||||
def dump: String =
|
def dump: String =
|
||||||
"State: " + state.toString + "\n\nResults: " + results + "\n\nCalls: " + callers + "\n\n"
|
"State: " + state.toString + "\n\nResults: " + results + "\n\nCalls: " + callers + "\n\n"
|
||||||
|
|
||||||
|
|
@ -90,7 +90,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
||||||
processAll()
|
processAll()
|
||||||
assert(results contains root, "No result for root node.")
|
assert(results contains root, "No result for root node.")
|
||||||
val finalResults = triggers.onComplete(results)
|
val finalResults = triggers.onComplete(results)
|
||||||
progressState = progress.allCompleted(progressState, finalResults)
|
progress.afterAllCompleted(finalResults)
|
||||||
finalResults
|
finalResults
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,7 +153,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
||||||
|
|
||||||
results(node) = result
|
results(node) = result
|
||||||
state(node) = Done
|
state(node) = Done
|
||||||
progressState = progress.completed(progressState, node, result)
|
progress.afterCompleted(node, result)
|
||||||
remove(reverse, node) foreach { dep =>
|
remove(reverse, node) foreach { dep =>
|
||||||
notifyDone(node, dep)
|
notifyDone(node, dep)
|
||||||
}
|
}
|
||||||
|
|
@ -210,8 +210,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
||||||
val v = register(node)
|
val v = register(node)
|
||||||
val deps = dependencies(v) ++ runBefore(node)
|
val deps = dependencies(v) ++ runBefore(node)
|
||||||
val active = IDSet[F[_]](deps filter notDone)
|
val active = IDSet[F[_]](deps filter notDone)
|
||||||
progressState = progress.registered(
|
progress.afterRegistered(
|
||||||
progressState,
|
|
||||||
node,
|
node,
|
||||||
deps,
|
deps,
|
||||||
active.toList
|
active.toList
|
||||||
|
|
@ -245,7 +244,7 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
||||||
}
|
}
|
||||||
|
|
||||||
state(node) = Running
|
state(node) = Running
|
||||||
progressState = progress.ready(progressState, node)
|
progress.afterReady(node)
|
||||||
submit(node)
|
submit(node)
|
||||||
|
|
||||||
post {
|
post {
|
||||||
|
|
@ -274,13 +273,13 @@ private[sbt] final class Execute[F[_] <: AnyRef](
|
||||||
* This returns a Completed instance, which contains the post-processing to perform after the result is retrieved from the Strategy.
|
* This returns a Completed instance, which contains the post-processing to perform after the result is retrieved from the Strategy.
|
||||||
*/
|
*/
|
||||||
def work[A](node: F[A], f: => Either[F[A], A])(implicit strategy: Strategy): Completed = {
|
def work[A](node: F[A], f: => Either[F[A], A])(implicit strategy: Strategy): Completed = {
|
||||||
progress.workStarting(node)
|
progress.beforeWork(node)
|
||||||
val rawResult = wideConvert(f).left.map {
|
val rawResult = wideConvert(f).left.map {
|
||||||
case i: Incomplete => if (config.overwriteNode(i)) i.copy(node = Some(node)) else i
|
case i: Incomplete => if (config.overwriteNode(i)) i.copy(node = Some(node)) else i
|
||||||
case e => Incomplete(Some(node), Incomplete.Error, directCause = Some(e))
|
case e => Incomplete(Some(node), Incomplete.Error, directCause = Some(e))
|
||||||
}
|
}
|
||||||
val result = rewrap(rawResult)
|
val result = rewrap(rawResult)
|
||||||
progress.workFinished(node, result)
|
progress.afterWork(node, result)
|
||||||
completed {
|
completed {
|
||||||
result match {
|
result match {
|
||||||
case Right(v) => retire(node, v)
|
case Right(v) => retire(node, v)
|
||||||
|
|
|
||||||
|
|
@ -14,32 +14,29 @@ import sbt.internal.util.RMap
|
||||||
* All methods are called from the same thread except `started` and `finished`,
|
* All methods are called from the same thread except `started` and `finished`,
|
||||||
* which is called from the executing task's thread.
|
* which is called from the executing task's thread.
|
||||||
* All methods should return quickly to avoid task execution overhead.
|
* All methods should return quickly to avoid task execution overhead.
|
||||||
*
|
|
||||||
* This class is experimental and subject to binary and source incompatible changes at any time.
|
|
||||||
*/
|
*/
|
||||||
private[sbt] trait ExecuteProgress[F[_]] {
|
trait ExecuteProgress[F[_]] {
|
||||||
type S
|
def initial(): Unit
|
||||||
def initial: S
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that a `task` has been registered in the system for execution.
|
* Notifies that a `task` has been registered in the system for execution.
|
||||||
* The dependencies of `task` are `allDeps` and the subset of those dependencies that
|
* The dependencies of `task` are `allDeps` and the subset of those dependencies that
|
||||||
* have not completed are `pendingDeps`.
|
* have not completed are `pendingDeps`.
|
||||||
*/
|
*/
|
||||||
def registered(state: S, task: F[_], allDeps: Iterable[F[_]], pendingDeps: Iterable[F[_]]): S
|
def afterRegistered(task: F[_], allDeps: Iterable[F[_]], pendingDeps: Iterable[F[_]]): Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that all of the dependencies of `task` have completed and `task` is therefore
|
* Notifies that all of the dependencies of `task` have completed and `task` is therefore
|
||||||
* ready to run. The task has not been scheduled on a thread yet.
|
* ready to run. The task has not been scheduled on a thread yet.
|
||||||
*/
|
*/
|
||||||
def ready(state: S, task: F[_]): S
|
def afterReady(task: F[_]): Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the work for `task` is starting after this call returns.
|
* Notifies that the work for `task` is starting after this call returns.
|
||||||
* This is called from the thread the task executes on, unlike most other methods in this callback.
|
* This is called from the thread the task executes on, unlike most other methods in this callback.
|
||||||
* It is called immediately before the task's work starts with minimal intervening executor overhead.
|
* It is called immediately before the task's work starts with minimal intervening executor overhead.
|
||||||
*/
|
*/
|
||||||
def workStarting(task: F[_]): Unit
|
def beforeWork(task: F[_]): Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the work for `task` work has finished. The task may have computed the next task to
|
* Notifies that the work for `task` work has finished. The task may have computed the next task to
|
||||||
|
|
@ -49,34 +46,68 @@ private[sbt] trait ExecuteProgress[F[_]] {
|
||||||
* This is called from the thread the task executes on, unlike most other methods in this callback.
|
* This is called from the thread the task executes on, unlike most other methods in this callback.
|
||||||
* It is immediately called after the task's work is complete with minimal intervening executor overhead.
|
* It is immediately called after the task's work is complete with minimal intervening executor overhead.
|
||||||
*/
|
*/
|
||||||
def workFinished[A](task: F[A], result: Either[F[A], Result[A]]): Unit
|
def afterWork[A](task: F[A], result: Either[F[A], Result[A]]): Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that `task` has completed.
|
* Notifies that `task` has completed.
|
||||||
* The task's work is done with a final `result`.
|
* The task's work is done with a final `result`.
|
||||||
* Any tasks called by `task` have completed.
|
* Any tasks called by `task` have completed.
|
||||||
*/
|
*/
|
||||||
def completed[A](state: S, task: F[A], result: Result[A]): S
|
def afterCompleted[A](task: F[A], result: Result[A]): Unit
|
||||||
|
|
||||||
/** All tasks have completed with the final `results` provided. */
|
/** All tasks have completed with the final `results` provided. */
|
||||||
def allCompleted(state: S, results: RMap[F, Result]): S
|
def afterAllCompleted(results: RMap[F, Result]): Unit
|
||||||
|
|
||||||
/** Notifies that either all tasks have finished or cancelled. */
|
/** Notifies that either all tasks have finished or cancelled. */
|
||||||
def stop(): Unit
|
def stop(): Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This module is experimental and subject to binary and source incompatible changes at any time. */
|
/** This module is experimental and subject to binary and source incompatible changes at any time. */
|
||||||
private[sbt] object ExecuteProgress {
|
object ExecuteProgress {
|
||||||
def empty[F[_]]: ExecuteProgress[F] = new ExecuteProgress[F] {
|
def empty[F[_]]: ExecuteProgress[F] = new ExecuteProgress[F] {
|
||||||
type S = Unit
|
override def initial(): Unit = ()
|
||||||
def initial = ()
|
override def afterRegistered(
|
||||||
def registered(state: Unit, task: F[_], allDeps: Iterable[F[_]], pendingDeps: Iterable[F[_]]) =
|
task: F[_],
|
||||||
|
allDeps: Iterable[F[_]],
|
||||||
|
pendingDeps: Iterable[F[_]]
|
||||||
|
): Unit =
|
||||||
()
|
()
|
||||||
def ready(state: Unit, task: F[_]) = ()
|
override def afterReady(task: F[_]): Unit = ()
|
||||||
def workStarting(task: F[_]) = ()
|
override def beforeWork(task: F[_]): Unit = ()
|
||||||
def workFinished[A](task: F[A], result: Either[F[A], Result[A]]) = ()
|
override def afterWork[A](task: F[A], result: Either[F[A], Result[A]]): Unit = ()
|
||||||
def completed[A](state: Unit, task: F[A], result: Result[A]) = ()
|
override def afterCompleted[A](task: F[A], result: Result[A]): Unit = ()
|
||||||
def allCompleted(state: Unit, results: RMap[F, Result]) = ()
|
override def afterAllCompleted(results: RMap[F, Result]): Unit = ()
|
||||||
def stop(): Unit = ()
|
override def stop(): Unit = ()
|
||||||
|
}
|
||||||
|
|
||||||
|
def aggregate[F[_]](reporters: Seq[ExecuteProgress[F]]) = new ExecuteProgress[F] {
|
||||||
|
override def initial(): Unit = {
|
||||||
|
reporters foreach { _.initial() }
|
||||||
|
}
|
||||||
|
override def afterRegistered(
|
||||||
|
task: F[_],
|
||||||
|
allDeps: Iterable[F[_]],
|
||||||
|
pendingDeps: Iterable[F[_]]
|
||||||
|
): Unit = {
|
||||||
|
reporters foreach { _.afterRegistered(task, allDeps, pendingDeps) }
|
||||||
|
}
|
||||||
|
override def afterReady(task: F[_]): Unit = {
|
||||||
|
reporters foreach { _.afterReady(task) }
|
||||||
|
}
|
||||||
|
override def beforeWork(task: F[_]): Unit = {
|
||||||
|
reporters foreach { _.beforeWork(task) }
|
||||||
|
}
|
||||||
|
override def afterWork[A](task: F[A], result: Either[F[A], Result[A]]): Unit = {
|
||||||
|
reporters foreach { _.afterWork(task, result) }
|
||||||
|
}
|
||||||
|
override def afterCompleted[A](task: F[A], result: Result[A]): Unit = {
|
||||||
|
reporters foreach { _.afterCompleted(task, result) }
|
||||||
|
}
|
||||||
|
override def afterAllCompleted(results: RMap[F, Result]): Unit = {
|
||||||
|
reporters foreach { _.afterAllCompleted(results) }
|
||||||
|
}
|
||||||
|
override def stop(): Unit = {
|
||||||
|
reporters foreach { _.stop() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue