From 1d52064f45035a9875c14d5d0c233fbfaf7b971f Mon Sep 17 00:00:00 2001 From: G1ng3r Date: Thu, 29 Dec 2022 17:44:33 +0300 Subject: [PATCH] Sbt task bloopGenerate should throw occurred errors to indicate failures during build import --- .../compiler-plugin-allowlist/build.sbt | 5 ++- .../bloop/integrations/sbt/SbtBloop.scala | 45 ++++++++++++------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/frontend/src/test/resources/compiler-plugin-allowlist/build.sbt b/frontend/src/test/resources/compiler-plugin-allowlist/build.sbt index b2fcbd3658..e8fdb92e3f 100644 --- a/frontend/src/test/resources/compiler-plugin-allowlist/build.sbt +++ b/frontend/src/test/resources/compiler-plugin-allowlist/build.sbt @@ -1,6 +1,7 @@ bloopExportJarClassifiers in Global := Some(Set("sources")) bloopConfigDir in Global := baseDirectory.value / "bloop-config" import _root_.sbtcrossproject.CrossPlugin.autoImport.{crossProject => crossProjects} +import sbt.Value scalaVersion in ThisBuild := "2.12.8" @@ -8,8 +9,8 @@ lazy val `bloop-test-plugin` = project .settings( libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value, publishArtifact in Compile := false, - bloopGenerate in Compile := None, - bloopGenerate in Test := None + bloopGenerate in Compile := Value(None), + bloopGenerate in Test := Value(None) ) val silencerVersion = "1.3.1" diff --git a/integrations/sbt-bloop/src/main/scala/bloop/integrations/sbt/SbtBloop.scala b/integrations/sbt-bloop/src/main/scala/bloop/integrations/sbt/SbtBloop.scala index eb81d8f488..d5a1bd2d9b 100644 --- a/integrations/sbt-bloop/src/main/scala/bloop/integrations/sbt/SbtBloop.scala +++ b/integrations/sbt-bloop/src/main/scala/bloop/integrations/sbt/SbtBloop.scala @@ -25,6 +25,7 @@ import sbt.Def import sbt.File import sbt.Global import sbt.Inc +import sbt.Incomplete import sbt.IntegrationTest import sbt.KeyRanks import sbt.Keys @@ -40,6 +41,7 @@ import sbt.ThisBuild import sbt.ThisProject import sbt.Value import xsbti.compile.CompileOrder +import sbt.Result object BloopPlugin extends AutoPlugin { import sbt.plugins.JvmPlugin @@ -78,8 +80,8 @@ object BloopKeys { taskKey[Seq[(File, File)]]("Directory where to write the class files") val bloopInstall: TaskKey[Unit] = taskKey[Unit]("Generate all bloop configuration files") - val bloopGenerate: TaskKey[Option[File]] = - taskKey[Option[File]]("Generate bloop configuration file for this project") + val bloopGenerate: TaskKey[Result[Option[File]]] = + taskKey[Result[Option[File]]]("Generate bloop configuration file for this project") val bloopPostGenerate: TaskKey[Unit] = taskKey[Unit]("Force resource generators for Bloop.") @@ -866,7 +868,7 @@ object BloopDefaults { private[bloop] val targetNamesToConfigs = new ConcurrentHashMap[String, GeneratedProject]() - def bloopGenerate: Def.Initialize[Task[Option[File]]] = Def.taskDyn { + def bloopGenerate: Def.Initialize[Task[Result[Option[File]]]] = Def.taskDyn { val logger = Keys.streams.value.log val project = Keys.thisProject.value val scoped = Keys.resolvedScoped.value @@ -882,8 +884,8 @@ object BloopDefaults { } lazy val generated = Option(targetNamesToConfigs.get(projectName)) - if (isMetaBuild && configuration == Test) inlinedTask[Option[File]](None) - else if (!hasConfigSettings) inlinedTask[Option[File]](None) + if (isMetaBuild && configuration == Test) inlinedTask[Result[Option[File]]](Value(None)) + else if (!hasConfigSettings) inlinedTask[Result[Option[File]]](Value(None)) else if (generated.isDefined && generated.get.fromSbtUniverseId == currentSbtUniverse) { Def.task { // Force source generators on this task manually @@ -891,7 +893,7 @@ object BloopDefaults { // Force classpath to force side-effects downstream to fully simulate `bloopGenerate` val _ = emulateDependencyClasspath.value - generated.map(_.outPath.toFile) + Value(generated.map(_.outPath.toFile)) } } else { @@ -1066,15 +1068,9 @@ object BloopDefaults { logger.debug(s"Bloop wrote the configuration of project '$projectName' to '$outFile'") logger.success(s"Generated $userFriendlyConfigPath") - Some(outFile) + Option(outFile) } - }.result.map { - case Inc(cause) => - logger.error(s"Couldn't run bloopGenerate for $projectName. Cause:\n$cause") - None - case Value(maybeFile) => - maybeFile - } + }.result } /** @@ -1119,6 +1115,7 @@ object BloopDefaults { } def bloopInstall: Def.Initialize[Task[Unit]] = Def.taskDyn { + val logger = Keys.streams.value.log val filter = sbt.ScopeFilter( sbt.inAnyProject, sbt.inAnyConfiguration, @@ -1139,9 +1136,25 @@ object BloopDefaults { BloopKeys.bloopGenerate .all(filter) .map(_.toSet) + .map(_.foldLeft(Set.empty[Option[File]] -> Set.empty[Incomplete]) { + case ((succ, fail), res) => + res match { + case Inc(incomplete) => succ -> (fail + incomplete) + case Value(fileOpt) => (succ + fileOpt) -> fail + } + }) // Smart trick to modify state once a task has completed (who said tasks cannot alter state?) - .apply((t: Task[Set[Option[File]]]) => sbt.SessionVar.transform(t, removeProjects)) - .map(_ => ()) + .apply((t: Task[(Set[Option[File]], Set[Incomplete])]) => + sbt.SessionVar + .transform(t.map { case (files, _) => files }, removeProjects) + .flatMap(_ => t.map { case (_, fail) => fail }) + ) + .map(fail => + if (fail.nonEmpty) { + logger.error(s"Couldn't run bloopGenerate. Cause: ${fail.mkString("\n")}") + throw fail.head + } + ) } lazy val bloopConfigDir: Def.Initialize[Option[File]] = Def.setting { None }