diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index 55da21c94..8d45104cb 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -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) { diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 36059cdc3..992fb8548 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -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. diff --git a/main/src/main/scala/sbt/internal/TaskTimings.scala b/main/src/main/scala/sbt/internal/TaskTimings.scala index 6f421e829..fe814ccd5 100644 --- a/main/src/main/scala/sbt/internal/TaskTimings.scala +++ b/main/src/main/scala/sbt/internal/TaskTimings.scala @@ -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 = {