From db4878c78600f4c80cf81d97ea915c3d5fee17fe Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sun, 28 Jun 2020 18:06:23 -0700 Subject: [PATCH] Make progress an object This commit reworks TaskProgress so that it is a singleton object. By using a singleton, we ensure that there is at most one progress thread running at a time. With multiple threads, there can be flickering in the progress reports. This fixes https://github.com/sbt/sbt/issues/5547. There also was a bug that the reference to the progress thread was not reset when the thread itself exited. As a result, it was possible for progress reporting to stop while tasks were still running. This seemed to primarily happen in multi-project builds. It should be fixed by this change. --- main/src/main/scala/sbt/EvaluateTask.scala | 2 +- .../main/scala/sbt/internal/TaskProgress.scala | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index ca78e4240..e4d94e431 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -255,7 +255,7 @@ object EvaluateTask { extracted, structure ) - val reporters = maker.map(_.progress) ++ Some(new TaskProgress) ++ + val reporters = maker.map(_.progress) ++ Some(TaskProgress) ++ (if (SysProp.taskTimings) new TaskTimings(reportOnShutdown = false, state.globalLogging.full) :: Nil else Nil) diff --git a/main/src/main/scala/sbt/internal/TaskProgress.scala b/main/src/main/scala/sbt/internal/TaskProgress.scala index 2a03206ee..ebdd06f19 100644 --- a/main/src/main/scala/sbt/internal/TaskProgress.scala +++ b/main/src/main/scala/sbt/internal/TaskProgress.scala @@ -16,14 +16,14 @@ import sbt.internal.util._ import scala.annotation.tailrec import scala.concurrent.duration._ +object TaskProgress extends TaskProgress + /** * implements task progress display on the shell. */ -private[sbt] final class TaskProgress +private[sbt] class TaskProgress private () extends AbstractTaskExecuteProgress with ExecuteProgress[Task] { - @deprecated("Use the no argument constructor.", "1.4.0") - def this(log: ManagedLogger) = this() private[this] val lastTaskCount = new AtomicInteger(0) private[this] val currentProgressThread = new AtomicReference[Option[ProgressThread]](None) private[this] val sleepDuration = SysProp.supershellSleep.millis @@ -38,6 +38,13 @@ private[sbt] final class TaskProgress private[this] def doReport(): Unit = { hasReported.set(true); report() } setDaemon(true) start() + private def resetThread(): Unit = + currentProgressThread.synchronized { + currentProgressThread.getAndSet(None) match { + case Some(t) if t != this => currentProgressThread.set(Some(t)) + case _ => + } + } @tailrec override def run(): Unit = { if (!isClosed.get() && (!hasReported.get || active.nonEmpty)) { try { @@ -61,6 +68,8 @@ private[sbt] final class TaskProgress } run() + } else { + resetThread() } } @@ -71,7 +80,7 @@ private[sbt] final class TaskProgress interrupt() report() appendProgress(ProgressEvent("Info", Vector(), None, None, None)) - () + resetThread() } }