From 6dfebc689b074b0da81c51543914048ffda06e71 Mon Sep 17 00:00:00 2001 From: Iulian Dragos Date: Mon, 24 Apr 2023 12:33:09 +0200 Subject: [PATCH] Add a key for Zinc listeners. Expose what the incremental compiler is doing behind the scenes. The RunProfiler interface has been part of Zinc for a while, but this allows the build itself, or an Sbt plugin, to hook their own implementation. We expose a list of such listeners to avoid plugins stepping on each other and replacing an existing listener. --- main/src/main/scala/sbt/Defaults.scala | 7 ++- main/src/main/scala/sbt/Keys.scala | 3 +- .../sbt/internal/DefaultRunProfiler.scala | 53 +++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 main/src/main/scala/sbt/internal/DefaultRunProfiler.scala diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 92add3fb5..613bdf39e 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -946,11 +946,16 @@ object Defaults extends BuildCommon { compileAnalysisTargetRoot.value / compileAnalysisFilename.value }, externalHooks := IncOptions.defaultExternal, + zincCompilationListeners := Seq.empty, incOptions := { val old = incOptions.value + val extHooks = externalHooks.value + val newExtHooks = extHooks.withInvalidationProfiler( + () => new DefaultRunProfiler(zincCompilationListeners.value) + ) old .withAuxiliaryClassFiles(auxiliaryClassFiles.value.toArray) - .withExternalHooks(externalHooks.value) + .withExternalHooks(newExtHooks) .withClassfileManagerType( Option( TransactionalManagerType diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 42fbafceb..92e0c2b02 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -248,7 +248,8 @@ object Keys { val copyResources = taskKey[Seq[(File, File)]]("Copies resources to the output directory.").withRank(AMinusTask) val aggregate = settingKey[Boolean]("Configures task aggregation.").withRank(BMinusSetting) val sourcePositionMappers = taskKey[Seq[xsbti.Position => Option[xsbti.Position]]]("Maps positions in generated source files to the original source it was generated from").withRank(DTask) - val externalHooks = taskKey[ExternalHooks]("The external hooks used by zinc.") + private[sbt] val externalHooks = taskKey[ExternalHooks]("The external hooks used by zinc.") + val zincCompilationListeners = settingKey[Seq[RunProfiler]]("Listeners that receive information about incremental compiler decisions.").withRank(DSetting) val auxiliaryClassFiles = taskKey[Seq[AuxiliaryClassFiles]]("The auxiliary class files that must be managed by Zinc (for instance the TASTy files)") val fileConverter = settingKey[FileConverter]("The file converter used to convert between Path and VirtualFile") val allowMachinePath = settingKey[Boolean]("Allow machine-specific paths during conversion.") diff --git a/main/src/main/scala/sbt/internal/DefaultRunProfiler.scala b/main/src/main/scala/sbt/internal/DefaultRunProfiler.scala new file mode 100644 index 000000000..8878729af --- /dev/null +++ b/main/src/main/scala/sbt/internal/DefaultRunProfiler.scala @@ -0,0 +1,53 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt.internal + +import xsbti.VirtualFileRef +import xsbti.compile.{ APIChange, InitialChanges, RunProfiler } + +class DefaultRunProfiler(profilers: Seq[RunProfiler]) extends RunProfiler { + override def timeCompilation(startNanos: Long, durationNanos: Long): Unit = + profilers.foreach(_.timeCompilation(startNanos, durationNanos)) + + override def registerInitial(changes: InitialChanges): Unit = + profilers.foreach(_.registerInitial(changes)) + + override def registerEvent( + kind: String, + inputs: Array[String], + outputs: Array[String], + reason: String + ): Unit = + profilers.foreach(_.registerEvent(kind, inputs, outputs, reason)) + + override def registerCycle( + invalidatedClasses: Array[String], + invalidatedPackageObjects: Array[String], + initialSources: Array[VirtualFileRef], + invalidatedSources: Array[VirtualFileRef], + recompiledClasses: Array[String], + changesAfterRecompilation: Array[APIChange], + nextInvalidations: Array[String], + shouldCompileIncrementally: Boolean + ): Unit = + profilers.foreach( + _.registerCycle( + invalidatedClasses, + invalidatedPackageObjects, + initialSources, + invalidatedSources, + recompiledClasses, + changesAfterRecompilation, + nextInvalidations, + shouldCompileIncrementally + ) + ) + + override def registerRun(): Unit = + profilers.foreach(_.registerRun()) +}