diff --git a/build.sbt b/build.sbt index b8b9894ed..746e6b221 100644 --- a/build.sbt +++ b/build.sbt @@ -290,6 +290,9 @@ lazy val taskProj = (project in file("tasks")) testedBaseSettings, name := "Tasks", mimaSettings, + mimaBinaryIssueFilters ++= Seq( + exclude[ReversedMissingMethodProblem]("sbt.ExecuteProgress.stop") + ) ) .configure(addSbtUtilControl) diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index 1f861067a..767a00cac 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -161,7 +161,7 @@ object EvaluateTask { import std.Transform import Keys.state - lazy private val sharedProgress = new TaskTimings(shutdown = true) + lazy private val sharedProgress = new TaskTimings(reportOnShutdown = true) // sbt-pgp calls this private[sbt] def defaultProgress(): ExecuteProgress[Task] = ExecuteProgress.empty[Task] @@ -170,7 +170,7 @@ object EvaluateTask { if (java.lang.Boolean.getBoolean("sbt.task.timings.on.shutdown")) sharedProgress else - new TaskTimings(shutdown = false) + new TaskTimings(reportOnShutdown = false) } else { if (ConsoleAppender.showProgress) new TaskProgress(currentRef) else ExecuteProgress.empty[Task] @@ -412,6 +412,7 @@ object EvaluateTask { def shutdown(): Unit = { // First ensure that all threads are stopped for task execution. shutdownThreads() + config.progressReporter.stop() // Now we run the gc cleanup to force finalizers to clear out file handles (yay GC!) if (config.forceGarbageCollection) { diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 275ed4d3d..868986e5d 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -138,6 +138,20 @@ object StandardMain { // This is to workaround https://github.com/sbt/io/issues/110 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 val userCommands = configuration.arguments.map(_.trim) val (earlyCommands, normalCommands) = (preCommands ++ userCommands).partition(isEarlyCommand) diff --git a/main/src/main/scala/sbt/internal/TaskProgress.scala b/main/src/main/scala/sbt/internal/TaskProgress.scala index 6e4913750..cad026b83 100644 --- a/main/src/main/scala/sbt/internal/TaskProgress.scala +++ b/main/src/main/scala/sbt/internal/TaskProgress.scala @@ -31,6 +31,7 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro private[this] val isReady = new AtomicBoolean(false) private[this] val lastTaskCount = new AtomicInteger(0) private[this] val isAllCompleted = new AtomicBoolean(false) + private[this] val isStopped = new AtomicBoolean(false) override def initial: Unit = () override def registered( @@ -67,14 +68,18 @@ private[sbt] final class TaskProgress(currentRef: ProjectRef) extends ExecutePro override def completed[A](state: Unit, task: Task[A], result: Result[A]): Unit = () + override def stop(): Unit = { + isStopped.set(true) + } + import ExecutionContext.Implicits._ Future { - while (!isReady.get) { + while (!isReady.get && !isStopped.get) { blocking { Thread.sleep(500) } } - while (!isAllCompleted.get) { + while (!isAllCompleted.get && !isStopped.get) { blocking { report() Thread.sleep(500) diff --git a/main/src/main/scala/sbt/internal/TaskTimings.scala b/main/src/main/scala/sbt/internal/TaskTimings.scala index 43ab2bbdd..c5525a738 100644 --- a/main/src/main/scala/sbt/internal/TaskTimings.scala +++ b/main/src/main/scala/sbt/internal/TaskTimings.scala @@ -20,9 +20,9 @@ import TaskName._ * - -Dsbt.task.timings.on.shutdown=true|false * - -Dsbt.task.timings.unit=number * - -Dsbt.task.timings.threshold=number - * @param shutdown Should the report be given when exiting the JVM (true) or immediately (false)? + * @param reportOnShutdown Should the report be given when exiting the JVM (true) or immediately (false)? */ -private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[Task] { +private[sbt] final class TaskTimings(reportOnShutdown: Boolean) extends ExecuteProgress[Task] { private[this] val calledBy = new ConcurrentHashMap[Task[_], Task[_]] private[this] val anonOwners = new ConcurrentHashMap[Task[_], Task[_]] private[this] val timings = new ConcurrentHashMap[Task[_], Long] @@ -41,7 +41,7 @@ private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[ type S = Unit - if (shutdown) { + if (reportOnShutdown) { start = System.nanoTime Runtime.getRuntime.addShutdownHook(new Thread { override def run() = report() @@ -49,7 +49,7 @@ private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[ } def initial = { - if (!shutdown) + if (!reportOnShutdown) start = System.nanoTime } def registered( @@ -72,10 +72,12 @@ private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[ } def completed[T](state: Unit, task: Task[T], result: Result[T]) = () def allCompleted(state: Unit, results: RMap[Task, Result]) = - if (!shutdown) { + if (!reportOnShutdown) { report() } + def stop(): Unit = () + private val reFilePath = raw"\{[^}]+\}".r private[this] def report() = { diff --git a/project/Dependencies.scala b/project/Dependencies.scala index cc9d1e0dd..1fd0b948d 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -10,7 +10,7 @@ object Dependencies { // sbt modules private val ioVersion = "1.3.0-M5" - private val utilVersion = "1.3.0-M4" + private val utilVersion = "1.3.0-M5" private val lmVersion = sys.props.get("sbt.build.lm.version") match { case Some(version) => version diff --git a/tasks/src/main/scala/sbt/ExecuteProgress.scala b/tasks/src/main/scala/sbt/ExecuteProgress.scala index 8e553a590..faa152e87 100644 --- a/tasks/src/main/scala/sbt/ExecuteProgress.scala +++ b/tasks/src/main/scala/sbt/ExecuteProgress.scala @@ -60,6 +60,9 @@ private[sbt] trait ExecuteProgress[F[_]] { /** All tasks have completed with the final `results` provided. */ def allCompleted(state: S, results: RMap[F, Result]): S + + /** Notifies that either all tasks have finished or cancelled. */ + def stop(): Unit } /** This module is experimental and subject to binary and source incompatible changes at any time. */ @@ -74,5 +77,6 @@ private[sbt] object ExecuteProgress { def workFinished[A](task: F[A], result: Either[F[A], Result[A]]) = () def completed[A](state: Unit, task: F[A], result: Result[A]) = () def allCompleted(state: Unit, results: RMap[F, Result]) = () + def stop(): Unit = () } }