From 8132093008d6366d7fb1c0e15b5545d71a81da98 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 16 Nov 2023 19:00:56 +0100 Subject: [PATCH] bugfix: Export runtime jars correctly from sbt Previously, we would not save runtime jars which could lead to users not being able to run their programs. Now, we export runtime classpath properly from sbt. Related to https://github.com/scalacenter/bloop/issues/1606 though I want to check out if it will also work via DAP --- .../bloop/integrations/sbt/SbtBloop.scala | 33 ++++------ .../sbt-bloop/runtime-dependency/build.sbt | 60 +++++++++++++++++++ .../runtime-dependency/project/plugins.sbt | 1 + .../sbt-bloop/runtime-dependency/test | 3 + 4 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/build.sbt create mode 100644 integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/project/plugins.sbt create mode 100644 integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/test 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 49aad31e8e..47deac9afe 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 @@ -35,6 +35,7 @@ import sbt.Optional import sbt.ProjectRef import sbt.Provided import sbt.ResolvedProject +import sbt.Runtime import sbt.TaskKey import sbt.Test import sbt.ThisBuild @@ -600,25 +601,6 @@ object BloopDefaults { } } - // Unused for now, but we leave it here because it may be useful in the future. - def nameFromDependency(dependency: ClasspathDependency, thisProject: ResolvedProject): String = { - import sbt.{LocalProject, LocalRootProject, RootProject} - - val projectName = dependency.project match { - case ThisProject => thisProject.id - case LocalProject(project) => project - // Not sure about these three: - case LocalRootProject => "root" - case ProjectRef(_, project) => project - case RootProject(_) => "root" - } - - dependency.configuration match { - case Some("compile") | None => projectName - case Some(configurationName) => s"$projectName-$configurationName" - } - } - /** * Replace any old path that is used as a scalac option by the new path. * @@ -806,8 +788,19 @@ object BloopDefaults { val isForkedExecution = (Keys.fork in configuration in forkScopedTask).value val workingDir = if (isForkedExecution) Keys.baseDirectory.value else rootBaseDirectory val extraJavaOptions = List(s"-Duser.dir=${workingDir.getAbsolutePath}") + lazy val runtimeClasspath = (Runtime / Keys.fullClasspath).value.map(_.data.toPath()).toList + lazy val javaRuntimeHome = (Runtime / Keys.javaHome).value.map(_.toPath()) + lazy val javaRuntimeOptions = (Runtime / Keys.javaOptions).value val config = Config.JvmConfig(Some(javaHome.toPath), (extraJavaOptions ++ javaOptions).toList) - Config.Platform.Jvm(config, mainClass, None, None, None) + lazy val configRuntime = + Config.JvmConfig(javaRuntimeHome.orElse(Some(javaHome.toPath)), (extraJavaOptions ++ javaRuntimeOptions).toList) + /* Runtime config is only used for run task, which is in Compile scope normally. + * Test classpath already contains runtime config, so it's not needed to set separate classpath for test scope. + */ + if (configuration == Compile) + Config.Platform.Jvm(config, mainClass, Some(configRuntime), Some(runtimeClasspath), None) + else + Config.Platform.Jvm(config, mainClass, None, None, None) } } // FORMAT: ON diff --git a/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/build.sbt b/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/build.sbt new file mode 100644 index 0000000000..617aa7335d --- /dev/null +++ b/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/build.sbt @@ -0,0 +1,60 @@ +import bloop.integrations.sbt.BloopDefaults + +name := "runtime-dependency" + +libraryDependencies += + "ch.qos.logback" % "logback-classic" % "1.2.7" % Runtime + +val bloopConfigFile = settingKey[File]("Config file to test") +ThisBuild / bloopConfigFile := { + val bloopDir = Keys.baseDirectory.value./(".bloop") + val config = bloopDir./("runtime-dependency.json") + config +} + +val bloopTestConfigFile = settingKey[File]("Test config file to test") +ThisBuild / bloopTestConfigFile := { + val bloopDir = Keys.baseDirectory.value./(".bloop") + val config = bloopDir./("runtime-dependency-test.json") + config +} + +val checkBloopFiles = taskKey[Unit]("Check bloop file contents") +ThisBuild / checkBloopFiles := { + val configContents = BloopDefaults.unsafeParseConfig(bloopConfigFile.value.toPath) + assert(configContents.project.platform.isDefined) + val platformJvm = + configContents.project.platform.get.asInstanceOf[bloop.config.Config.Platform.Jvm] + val obtainedRuntimeClasspath = platformJvm.classpath.map(_.map(_.getFileName.toString)) + val expectedRuntimeClasspath = Some( + List( + "classes", + "logback-core-1.2.7.jar", + "scala-library.jar", + "slf4j-api-1.7.32.jar", + "logback-classic-1.2.7.jar" + ) + ) + assert(obtainedRuntimeClasspath == expectedRuntimeClasspath) + + assert(configContents.project.classpath.map(_.getFileName.toString) == List("scala-library.jar")) + + val configTestContents = BloopDefaults.unsafeParseConfig(bloopTestConfigFile.value.toPath) + assert(configTestContents.project.platform.isDefined) + val testPlatformJvm = + configTestContents.project.platform.get.asInstanceOf[bloop.config.Config.Platform.Jvm] + assert(testPlatformJvm.classpath.isEmpty) + + val obtainedTestClasspath = configTestContents.project.classpath.map(_.getFileName.toString) + println(obtainedTestClasspath) + val expectedTestClasspath = + List( + "classes", + "logback-core-1.2.7.jar", + "scala-library.jar", + "slf4j-api-1.7.32.jar", + "logback-classic-1.2.7.jar" + ) + + assert(obtainedTestClasspath == expectedTestClasspath) +} diff --git a/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/project/plugins.sbt b/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/project/plugins.sbt new file mode 100644 index 0000000000..1a5c0709e6 --- /dev/null +++ b/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % sys.props.apply("plugin.version")) diff --git a/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/test b/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/test new file mode 100644 index 0000000000..e48940b924 --- /dev/null +++ b/integrations/sbt-bloop/src/sbt-test/sbt-bloop/runtime-dependency/test @@ -0,0 +1,3 @@ +> bloopGenerate +> test:bloopGenerate +> checkBloopFiles