diff --git a/src/main/scala/bloop/integrations/maven/MojoImplementation.scala b/src/main/scala/bloop/integrations/maven/MojoImplementation.scala index a9a3baa..2bad020 100644 --- a/src/main/scala/bloop/integrations/maven/MojoImplementation.scala +++ b/src/main/scala/bloop/integrations/maven/MojoImplementation.scala @@ -214,6 +214,7 @@ object MojoImplementation { classesDir0: File, // needs to be lazy, since we resolve artifacts later on classpath0: () => java.util.List[_], + runtimeClasspath0: Option[() => java.util.List[_]], resources0: java.util.List[_], launcher: Option[AppLauncher], configuration: String @@ -289,7 +290,7 @@ object MojoImplementation { val resolution = Some(Config.Resolution(modules)) - val classpath = { + val (classpath, runtimeClasspath) = { val projectDependencies = dependencies.flatMap { d => val build = d.getBuild() if (configuration == "compile") build.getOutputDirectory() :: Nil @@ -302,7 +303,16 @@ object MojoImplementation { val fullClasspath = if (hasScalaLibrary) cp else cp ++ libraryAndDependencies.map(_.getFile().toPath()) - (projectDependencies.map(u => abs(new File(u))) ++ fullClasspath ++ extraClasspath).toList + val compileCp = + (projectDependencies.map(u => abs(new File(u))) ++ fullClasspath ++ extraClasspath).toList + + val runtimeCp = runtimeClasspath0.flatMap { getRuntimeCp => + val runtimeElements = + getRuntimeCp().asScala.toList.asInstanceOf[List[String]].map(u => abs(new File(u))) + Some((compileCp ++ runtimeElements).distinct) + } + + (compileCp, runtimeCp) } val tags = if (configuration == "test") List(Tag.Test) else List(Tag.Library) @@ -324,7 +334,7 @@ object MojoImplementation { val javaHome = Some(abs(mojo.getJavaHome().getParentFile.getParentFile)) val jvmArgs = launcher.map(_.getJvmArgs.toList).getOrElse(List.empty) val mainClass = launcher.map(_.getMainClass).filter(_.nonEmpty) - val platform = Some(Config.Platform.Jvm(Config.JvmConfig(javaHome, jvmArgs), mainClass, None, None, None)) + val platform = Some(Config.Platform.Jvm(Config.JvmConfig(javaHome, jvmArgs), mainClass, None, runtimeClasspath, None)) val resources = Some(resources0.asScala.toList.flatMap { case a: Resource => val dir = Paths.get(a.getDirectory()) @@ -366,6 +376,7 @@ object MojoImplementation { mojo.getCompileSourceDirectories.asScala.toSeq, mojo.getCompileOutputDir, project.getCompileClasspathElements, + Some(() => project.getRuntimeClasspathElements()), project.getResources, launcher, "compile" @@ -375,6 +386,7 @@ object MojoImplementation { mojo.getTestSourceDirectories.asScala.toSeq, mojo.getTestOutputDir, project.getTestClasspathElements, + None, project.getTestResources, launcher, "test" diff --git a/src/test/resources/runtime_dependency/pom.xml b/src/test/resources/runtime_dependency/pom.xml new file mode 100644 index 0000000..3253b42 --- /dev/null +++ b/src/test/resources/runtime_dependency/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + com.example + runtime_dependency + 1.0-SNAPSHOT + runtime_dependency + A Scala project with a runtime-scoped dependency to verify it appears in the bloop runtime classpath. + + + 1.8 + 1.8 + UTF-8 + 2.13.6 + + + + + org.scala-lang + scala-library + ${scala.version} + + + + + ch.qos.logback + logback-classic + 1.5.16 + runtime + + + + + src/main/scala + src/test/scala + + + net.alchim31.maven + scala-maven-plugin + 3.3.2 + + + + + compile + testCompile + + + + + + + + + + diff --git a/src/test/scala/bloop/integrations/maven/MavenConfigGenerationTest.scala b/src/test/scala/bloop/integrations/maven/MavenConfigGenerationTest.scala index b762499..a8093e7 100644 --- a/src/test/scala/bloop/integrations/maven/MavenConfigGenerationTest.scala +++ b/src/test/scala/bloop/integrations/maven/MavenConfigGenerationTest.scala @@ -543,4 +543,36 @@ class MavenConfigGenerationTest extends BaseConfigSuite { assertEquals("3.4.2", configFile.project.`scala`.get.version) } } + + @Test + def runtimeDependency() = { + check("runtime_dependency/pom.xml") { (configFile, projectName, subprojects) => + assert(subprojects.isEmpty) + assert(configFile.project.`scala`.isDefined) + + // logback-classic is runtime-scoped: it must NOT appear on the compile classpath + assert( + !hasCompileClasspathEntryName(configFile, "logback-classic"), + "logback-classic should NOT be on the compile classpath" + ) + + // but it MUST appear in the JVM platform runtime classpath + assert( + hasRuntimeClasspathEntryName(configFile, "logback-classic"), + "logback-classic should be on the JVM platform runtime classpath" + ) + + // transitive runtime dep (logback-core) should also be on runtime classpath + assert( + hasRuntimeClasspathEntryName(configFile, "logback-core"), + "logback-core (transitive of logback-classic) should be on the JVM platform runtime classpath" + ) + + // compile deps must still be present on the runtime classpath + assert( + hasRuntimeClasspathEntryName(configFile, "scala-library"), + "scala-library should still be on the JVM platform runtime classpath" + ) + } + } }