Merge pull request #4678 from eatkins/supershell

Supershell
This commit is contained in:
eugene yokota 2019-05-14 21:27:39 -04:00 committed by GitHub
commit c61a1fa656
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 40 deletions

View File

@ -467,6 +467,7 @@ object EvaluateTask {
// Register with our cancel handler we're about to start. // Register with our cancel handler we're about to start.
val strat = config.cancelStrategy val strat = config.cancelStrategy
val cancelState = strat.onTaskEngineStart(runningEngine) val cancelState = strat.onTaskEngineStart(runningEngine)
config.progressReporter.initial()
try { try {
(state.get(stateBuildStructure), state.get(sessionSettings)) match { (state.get(stateBuildStructure), state.get(sessionSettings)) match {
case (Some(structure), Some(settings)) => case (Some(structure), Some(settings)) =>

View File

@ -8,18 +8,13 @@
package sbt package sbt
package internal package internal
import sbt.internal.util.{ import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger, AtomicReference }
RMap,
ConsoleAppender, import sbt.internal.util._
LogOption,
JLine,
ManagedLogger,
ProgressEvent,
ProgressItem
}
import sbt.util.Level import sbt.util.Level
import scala.concurrent.{ blocking, Future, ExecutionContext }
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger } import scala.annotation.tailrec
import scala.util.control.NonFatal
/** /**
* implements task progress display on the shell. * implements task progress display on the shell.
@ -27,46 +22,56 @@ import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
private[sbt] final class TaskProgress(log: ManagedLogger) private[sbt] final class TaskProgress(log: ManagedLogger)
extends AbstractTaskExecuteProgress extends AbstractTaskExecuteProgress
with ExecuteProgress[Task] { with ExecuteProgress[Task] {
private[this] val isReady = new AtomicBoolean(false)
private[this] val lastTaskCount = new AtomicInteger(0) private[this] val lastTaskCount = new AtomicInteger(0)
private[this] val isAllCompleted = new AtomicBoolean(false) private[this] val currentProgressThread = new AtomicReference[Option[ProgressThread]](None)
private[this] val isStopped = new AtomicBoolean(false) private[this] val sleepDuration =
try System.getProperty("sbt.supershell.sleep", "100").toLong
catch { case NonFatal(_) => 100L }
private[this] final class ProgressThread
extends Thread("task-progress-report-thread")
with AutoCloseable {
private[this] val isClosed = new AtomicBoolean(false)
setDaemon(true)
start()
@tailrec override def run(): Unit = {
if (!isClosed.get()) {
try {
report()
Thread.sleep(sleepDuration)
} catch {
case _: InterruptedException =>
}
run()
}
}
override def close(): Unit = {
isClosed.set(true)
interrupt()
}
}
override def initial(): Unit = { override def initial(): Unit = {
currentProgressThread.get() match {
case None =>
currentProgressThread.set(Some(new ProgressThread))
case _ =>
}
ConsoleAppender.setTerminalWidth(JLine.terminal.getWidth) ConsoleAppender.setTerminalWidth(JLine.terminal.getWidth)
} }
override def afterReady(task: Task[_]): Unit = { override def afterReady(task: Task[_]): Unit = ()
isReady.set(true)
}
override def afterCompleted[A](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 = currentProgressThread.getAndSet(None).foreach(_.close())
isStopped.set(true)
}
import ExecutionContext.Implicits._
Future {
while (!isReady.get && !isStopped.get) {
blocking {
Thread.sleep(500)
}
}
while (!isAllCompleted.get && !isStopped.get) {
blocking {
report()
Thread.sleep(500)
}
}
}
override def afterAllCompleted(results: RMap[Task, Result]): Unit = { override def afterAllCompleted(results: RMap[Task, Result]): Unit = {
// send an empty progress report to clear out the previous report // send an empty progress report to clear out the previous report
val event = ProgressEvent("Info", Vector(), Some(lastTaskCount.get), None, None) val event = ProgressEvent("Info", Vector(), Some(lastTaskCount.get), None, None)
import sbt.internal.util.codec.JsonProtocol._ import sbt.internal.util.codec.JsonProtocol._
log.logEvent(Level.Info, event) log.logEvent(Level.Info, event)
isAllCompleted.set(true) stop()
} }
private[this] val skipReportTasks = private[this] val skipReportTasks =
Set("run", "bgRun", "fgRun", "scala", "console", "consoleProject") Set("run", "bgRun", "fgRun", "scala", "console", "consoleProject")
@ -75,10 +80,18 @@ private[sbt] final class TaskProgress(log: ManagedLogger)
val ltc = lastTaskCount.get val ltc = lastTaskCount.get
val currentTasksCount = currentTasks.size val currentTasksCount = currentTasks.size
def report0(): Unit = { def report0(): Unit = {
val event = ProgressEvent("Info", currentTasks map { task => val event = ProgressEvent(
val elapsed = timings.get(task).currentElapsedMicros "Info",
ProgressItem(taskName(task), elapsed) currentTasks
}, Some(ltc), None, None) .map { task =>
val elapsed = timings.get(task).currentElapsedMicros
ProgressItem(taskName(task), elapsed)
}
.sortBy(_.name),
Some(ltc),
None,
None
)
import sbt.internal.util.codec.JsonProtocol._ import sbt.internal.util.codec.JsonProtocol._
log.logEvent(Level.Info, event) log.logEvent(Level.Info, event)
} }