Fixes shutdown hook error in timing report

This fixes the closed channel exception generated when running
sbt -timings help. This bug was introduced in sbt 1.4 where a wrapper
was created (Terminal.scala) around the terminal. This meant that the
shutdown hook which had been used previously was no longer working.

This has been fixed by avoiding the use of the JVM shutdown hook and
instead manually running the thunk at a place in the code where
the programme is still able to respond.
This commit is contained in:
Amina Adewusi 2021-08-20 17:45:14 +01:00
parent 2a26e81868
commit 3c9826f4f4
3 changed files with 27 additions and 1 deletions

View File

@ -9,6 +9,7 @@ package sbt
import java.io.File
import java.util.concurrent.atomic.AtomicReference
import sbt.Def.{ ScopedKey, Setting, dummyState }
import sbt.Keys.{ TaskProgress => _, name => _, _ }
import sbt.Project.richInitializeTask
@ -28,6 +29,7 @@ import sbt.internal.bsp.BuildTargetIdentifier
import scala.annotation.nowarn
import scala.Console.RED
import scala.concurrent.duration.Duration
import scala.util.control.NonFatal
/**
* An API that allows you to cancel executing tasks upon some signal.
@ -169,6 +171,28 @@ object EvaluateTask {
if (SysProp.taskTimingsOnShutdown) Some(sharedProgress)
else None
private val capturedThunk = new AtomicReference[() => Unit]()
def onShutdown(): Unit = {
val thunk = capturedThunk.getAndSet(null)
if (thunk != null) thunk()
}
// our own implementation of shutdown hook, because the "sbt -timings help" command was not working with the JVM shutdown hook,
// which is a little hard to control.
def addShutdownHandler[A](thunk: () => A): Unit = {
capturedThunk
.set(
() =>
try {
thunk()
()
} catch {
case NonFatal(e) =>
System.err.println(s"Caught exception running shutdown hook: $e")
e.printStackTrace(System.err)
}
)
}
lazy private val sharedTraceEvent = new TaskTraceEvent()
def taskTraceEvent: Option[ExecuteProgress[Task]] =
if (SysProp.traces) {

View File

@ -290,6 +290,7 @@ private[sbt] final class CommandExchange {
// interrupt and kill the thread
server.foreach(_.shutdown())
server = None
EvaluateTask.onShutdown
}
// This is an interface to directly respond events.

View File

@ -8,6 +8,7 @@
package sbt
package internal
import sbt.EvaluateTask.addShutdownHandler
import sbt.internal.util.{ ConsoleOut, RMap }
import sbt.util.{ Level, Logger }
@ -38,7 +39,7 @@ private[sbt] final class TaskTimings(reportOnShutdown: Boolean, logger: Logger)
if (reportOnShutdown) {
start = System.nanoTime
ShutdownHooks.add(() => report())
addShutdownHandler(() => report())
}
override def initial(): Unit = {