From 19d7229ad6c1f50f227586f2a8e0d8122330928e Mon Sep 17 00:00:00 2001 From: Arthur McGibbon Date: Sun, 2 May 2021 22:27:41 +0100 Subject: [PATCH] gradle improvements --- .../integrations/gradle/BloopParameters.scala | 6 +- .../gradle/model/BloopConverter.scala | 9 +- .../bloop/integrations/gradle/syntax.scala | 20 ++ .../gradle/ConfigGenerationSuite.scala | 234 ++++++++++++++---- 4 files changed, 218 insertions(+), 51 deletions(-) diff --git a/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/BloopParameters.scala b/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/BloopParameters.scala index bb58cb9f2e..26f158a6aa 100644 --- a/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/BloopParameters.scala +++ b/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/BloopParameters.scala @@ -58,15 +58,17 @@ case class BloopParametersExtension(project: Project) { includeJavadoc_.set(false) @Input @Optional def getIncludeJavadoc: Property[java.lang.Boolean] = includeJavadoc_ - def createParameters: BloopParameters = + def createParameters: BloopParameters = { + val defaultTargetDir = project.getRootProject.workspacePath.resolve(".bloop").toFile BloopParameters( - targetDir_.getOrElse(project.getRootProject.getProjectDir / ".bloop"), + targetDir_.getOrElse(defaultTargetDir), compilerName_.getOrElse("scala-compiler"), stdLibName_.getOrElse("scala-library"), includeSources_.get, includeJavadoc_.get, getDottyVersionOption ) + } } case class BloopParameters( diff --git a/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/model/BloopConverter.scala b/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/model/BloopConverter.scala index 50d9bdafda..0320a95686 100644 --- a/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/model/BloopConverter.scala +++ b/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/model/BloopConverter.scala @@ -149,6 +149,7 @@ class BloopConverter(parameters: BloopParameters) { val DottyVersion = raw"""0\.(\d+)(.*)""".r val Scala3Version = raw"""3\.(\d+)\.(\d+)-(\w+)(.*)""".r + val Scala3VersionReleased = raw"""3\.(\d+)(.*)""".r val (dottyOrgName, dottyLibrary, artifactAndVersion) = version match { case DottyVersion(minor, patch) => val artifactID = s"dotty-compiler_0.$minor" @@ -159,6 +160,12 @@ class BloopConverter(parameters: BloopParameters) { val artifactVersion = if (remaining.isEmpty) "+" else s"3.$minor.$patch-$milestone$remaining" ("org.scala-lang", "SCALA3-LIBRARY", s"$artifactID:$artifactVersion") + case Scala3VersionReleased(minor, patch) => + val artifactID = s"scala3-compiler_3" + val artifactVersion = if (patch.isEmpty) "+" else s"3.$minor$patch" + ("org.scala-lang", "SCALA3-LIBRARY", s"$artifactID:$artifactVersion") + case "3" => + ("org.scala-lang", "SCALA3-LIBRARY", s"scala3-compiler_3:+") } val compilerDependencyName = s"$dottyOrgName:$artifactAndVersion" @@ -253,7 +260,7 @@ class BloopConverter(parameters: BloopParameters) { bloopProject = Config.Project( name = projectName, directory = project.getProjectDir.toPath, - workspaceDir = Option(project.getRootProject.getProjectDir.toPath), + workspaceDir = Option(project.getRootProject.workspacePath), sources = sources, sourcesGlobs = None, sourceRoots = None, diff --git a/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/syntax.scala b/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/syntax.scala index daa30db085..b75bce9911 100644 --- a/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/syntax.scala +++ b/integrations/gradle-bloop/src/main/scala/bloop/integrations/gradle/syntax.scala @@ -11,6 +11,7 @@ import org.gradle.api.{Project, Task, GradleException} import scala.collection.JavaConverters._ import scala.reflect.ClassTag import scala.util.control.NonFatal +import java.nio.file.Path object syntax { @@ -49,6 +50,25 @@ object syntax { def getExtension[T](implicit t: ClassTag[T]): T = { project.getExtensions.getByType(t.runtimeClass.asInstanceOf[Class[T]]) } + + private def getCommonRootPath(path1: Path, path2: Path): Path = { + var idx = 0 + var finished = false + while (!finished) { + if (idx < path1.getNameCount() && idx < path2.getNameCount() && path1.getName(idx) == path2 + .getName(idx)) + idx = idx + 1 + else + finished = true + } + path1.getRoot().resolve(path1.subpath(0, idx)) + } + + def workspacePath: Path = { + project.getAllprojects.asScala + .map(_.getProjectDir().toPath()) + .foldLeft(project.getRootDir().toPath())(getCommonRootPath) + } } /** diff --git a/integrations/gradle-bloop/src/test/scala/bloop/integrations/gradle/ConfigGenerationSuite.scala b/integrations/gradle-bloop/src/test/scala/bloop/integrations/gradle/ConfigGenerationSuite.scala index 445f14c772..a41433f02c 100644 --- a/integrations/gradle-bloop/src/test/scala/bloop/integrations/gradle/ConfigGenerationSuite.scala +++ b/integrations/gradle-bloop/src/test/scala/bloop/integrations/gradle/ConfigGenerationSuite.scala @@ -76,7 +76,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile group: 'org.scala-lang', name: 'scala-library', version: '2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} | | @@ -137,7 +137,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile group: 'org.scala-lang', name: 'scala-library', version: '2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} | | @@ -338,6 +338,9 @@ abstract class ConfigGenerationSuite { @Test def worksWithSpecificScala3B(): Unit = { worksWithScala3("3.0.0-M1", "3.0.0-M1") } + @Test def worksWithSpecificScala3C(): Unit = { + worksWithScala3("3.0.0", "3.0.0") + } @Test def worksWithScala3LatestNightly(): Unit = { // newer releases mean we can't test for version worksWithScala3("Latest", "") @@ -391,7 +394,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.13.1' + | implementation 'org.scala-lang:scala-library:2.13.1' |} """.stripMargin ) @@ -456,7 +459,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -504,7 +507,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -570,7 +573,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -645,7 +648,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -657,6 +660,7 @@ abstract class ConfigGenerationSuite { | id 'bloop' |} | + |apply plugin: 'java-library' |apply plugin: 'scala' |apply plugin: 'bloop' | @@ -665,9 +669,10 @@ abstract class ConfigGenerationSuite { |} | |dependencies { + | implementation 'org.scala-lang:scala-library:2.12.8' | implementation 'org.typelevel:cats-core_2.12:1.2.0' - | compile project(':a') - | compile project(':c') + | api project(':a') + | api project(':c') |} """.stripMargin ) @@ -687,7 +692,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -707,7 +712,8 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile project(':b') + | implementation 'org.scala-lang:scala-library:2.12.8' + | implementation project(':b') |} """.stripMargin ) @@ -761,6 +767,13 @@ abstract class ConfigGenerationSuite { val configCTest = readValidBloopConfig(bloopCTest) val configDTest = readValidBloopConfig(bloopDTest) + assert(configA.project.workspaceDir.nonEmpty) + // canonicalFile needed to pass tests on mac due to "/private/var" "/var" symlink + assertEquals( + testProjectDir.getRoot.getCanonicalFile, + configA.project.workspaceDir.get.toFile.getCanonicalFile + ) + assert(configA.project.`scala`.exists(_.version == "2.12.8")) assert(configB.project.`scala`.exists(_.version == "2.12.8")) assert(configC.project.`scala`.exists(_.version == "2.12.8")) @@ -885,7 +898,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -905,8 +918,8 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile project(':a') - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation project(':a') + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -967,6 +980,127 @@ abstract class ConfigGenerationSuite { assert(!hasRuntimeClasspathEntryName(configBTest, "/b-test/build/classes")) } + @Test def worksWithIncludeFlat(): Unit = { + val buildDirA = testProjectDir.newFolder("a") + testProjectDir.newFolder("a", "src", "main", "scala") + testProjectDir.newFolder("a", "src", "test", "scala") + val buildDirB = testProjectDir.newFolder("b") + testProjectDir.newFolder("b", "src", "main", "scala") + testProjectDir.newFolder("b", "src", "test", "scala") + val buildDirMaster = testProjectDir.newFolder("master") + val buildSettings = new File(buildDirMaster, "settings.gradle") + val buildFileA = new File(buildDirA, "build.gradle") + val buildFileB = new File(buildDirB, "build.gradle") + + writeBuildScript( + buildFileA, + s""" + |plugins { + | id 'bloop' + |} + | + |apply plugin: 'scala' + |apply plugin: 'bloop' + | + |repositories { + | mavenCentral() + |} + | + |dependencies { + | implementation 'org.scala-lang:scala-library:2.12.8' + |} + """.stripMargin + ) + + writeBuildScript( + buildFileB, + s""" + |plugins { + | id 'bloop' + |} + | + |apply plugin: 'scala' + |apply plugin: 'bloop' + | + |repositories { + | mavenCentral() + |} + | + |dependencies { + | implementation project(':a') + | implementation 'org.scala-lang:scala-library:2.12.8' + |} + """.stripMargin + ) + + writeBuildScript( + buildSettings, + """ + |rootProject.name = 'master' + |includeFlat 'a' + |includeFlat 'b' + """.stripMargin + ) + + createHelloWorldScalaSource(buildDirA, "package x { trait A }") + createHelloWorldScalaTestSource(buildDirA, "package y { trait B }") + createHelloWorldScalaTestSource(buildDirB, "package z { trait C extends x.A { } }") + + GradleRunner + .create() + .withGradleVersion(gradleVersion) + .withProjectDir(buildDirMaster) + .withPluginClasspath(getClasspath) + .withArguments("bloopInstall", "-Si") + .forwardOutput() + .build() + + val projectName = testProjectDir.getRoot.getName + val bloopDir = new File(testProjectDir.getRoot, ".bloop") + val bloopNone = new File(bloopDir, s"${projectName}.json") + val bloopA = new File(bloopDir, "a.json") + val bloopB = new File(bloopDir, "b.json") + val bloopMaster = new File(bloopDir, "master.json") + val bloopATest = new File(bloopDir, "a-test.json") + val bloopBTest = new File(bloopDir, "b-test.json") + + assert(!bloopNone.exists()) + assert(!bloopMaster.exists()) + val configA = readValidBloopConfig(bloopA) + val configB = readValidBloopConfig(bloopB) + val configATest = readValidBloopConfig(bloopATest) + val configBTest = readValidBloopConfig(bloopBTest) + + assert(configA.project.workspaceDir.nonEmpty) + // canonicalFile needed to pass tests on mac due to "/private/var" "/var" symlink + assertEquals( + testProjectDir.getRoot.getCanonicalFile, + configA.project.workspaceDir.get.toFile.getCanonicalFile + ) + assert(configA.project.dependencies.isEmpty) + assertEquals(List("a"), configATest.project.dependencies.sorted) + assertEquals(List("a"), configB.project.dependencies.sorted) + assertEquals(List("a", "b"), configBTest.project.dependencies.sorted) + + assert(!hasRuntimeClasspathEntryName(configA, "/build/resources/main")) + assert(!hasRuntimeClasspathEntryName(configB, "/build/resources/main")) + assert(!hasRuntimeClasspathEntryName(configATest, "/build/resources/main")) + assert(!hasRuntimeClasspathEntryName(configBTest, "/build/resources/main")) + + assert(!hasCompileClasspathEntryName(configA, "/build/resources/main")) + assert(!hasCompileClasspathEntryName(configB, "/build/resources/main")) + assert(!hasCompileClasspathEntryName(configATest, "/build/resources/main")) + assert(!hasCompileClasspathEntryName(configBTest, "/build/resources/main")) + + assert(!hasRuntimeClasspathEntryName(configA, "/a/build/classes")) + assert(!hasRuntimeClasspathEntryName(configB, "/b/build/classes")) + assert(!hasRuntimeClasspathEntryName(configATest, "/a-test/build/classes")) + assert(!hasRuntimeClasspathEntryName(configBTest, "/b-test/build/classes")) + + assert(hasBothClasspathsEntryName(configB, "/a/src/main/resources")) + assert(hasBothClasspathsEntryName(configB, "/a/build/classes")) + } + @Test def worksWithDuplicateNestedProjectNames(): Unit = { val buildSettings = testProjectDir.newFile("settings.gradle") val buildDirA = testProjectDir.newFolder("a", "foo") @@ -1001,7 +1135,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -1022,8 +1156,8 @@ abstract class ConfigGenerationSuite { | |dependencies { | implementation 'org.typelevel:cats-core_2.12:1.2.0' - | compile project(':a:foo') - | compile project(':c:foo') + | implementation project(':a:foo') + | implementation project(':c:foo') |} """.stripMargin ) @@ -1043,7 +1177,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -1063,7 +1197,8 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile project(':b:foo') + | implementation project(':b:foo') + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -1142,7 +1277,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -1163,7 +1298,7 @@ abstract class ConfigGenerationSuite { | |dependencies { | implementation 'org.typelevel:cats-core_2.12:1.2.0' - | compile project(':code:foo') + | implementation project(':code:foo') |} """.stripMargin ) @@ -1246,7 +1381,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -1266,7 +1401,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' | testImplementation project(':a').sourceSets.test.output |} """.stripMargin @@ -1374,7 +1509,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -1394,7 +1529,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' | testImplementation project( path: ':a', configuration: 'testArtifacts') |} """.stripMargin @@ -1487,7 +1622,8 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' + | testFixturesImplementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -1507,7 +1643,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' | testImplementation(testFixtures(project(":a"))) |} """.stripMargin @@ -1621,7 +1757,8 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' + | testImplementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -1641,7 +1778,8 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' + | testImplementation 'org.scala-lang:scala-library:2.12.8' | testImplementation project( path: ':a', configuration: "testArtifacts" ) |} """.stripMargin @@ -1725,7 +1863,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile group: 'org.scala-lang', name: 'scala-library', version: '2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} | |tasks.withType(ScalaCompile) { @@ -1774,7 +1912,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile group: 'org.scala-lang', name: 'scala-library', version: '2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} | |tasks.withType(JavaCompile) { @@ -1870,8 +2008,8 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' - | compile project(':a') + | implementation 'org.scala-lang:scala-library:2.12.8' + | implementation project(':a') |} | """.stripMargin @@ -1987,9 +2125,9 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.typelevel:cats-core_2.12:1.2.0' - | compile(project(path: ':a', configuration: 'foo')) - | testRuntime files("${System.properties['java.home']}/../lib/tools.jar") + | implementation 'org.typelevel:cats-core_2.12:1.2.0' + | implementation(project(path: ':a', configuration: 'foo')) + | testRuntimeOnly files("${System.properties['java.home']}/../lib/tools.jar") |} """.stripMargin ) @@ -2325,7 +2463,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -2357,7 +2495,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -2416,7 +2554,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -2436,10 +2574,10 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile project(':c') - | compile 'org.typelevel:cats-core_2.12:1.2.0' - | compile project(':a') - | compile project(':b') + | implementation project(':c') + | implementation 'org.typelevel:cats-core_2.12:1.2.0' + | implementation project(':a') + | implementation project(':b') |} """.stripMargin ) @@ -2574,7 +2712,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile project(':e') + | implementation project(':e') |} """.stripMargin ) @@ -2644,7 +2782,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile group: 'org.scala-lang', name: 'scala-library', version: '2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' | scalaCompilerPlugin "org.scalameta:semanticdb-scalac_2.12.8:4.1.9" |} | @@ -2708,7 +2846,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile group: 'org.scala-lang', name: 'scala-library', version: '2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' | scalaCompilerPlugins "org.scalameta:semanticdb-scalac_2.12.8:4.1.9" |} | @@ -2787,7 +2925,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile 'org.scala-lang:scala-library:2.12.8' + | implementation 'org.scala-lang:scala-library:2.12.8' |} """.stripMargin ) @@ -2870,7 +3008,7 @@ abstract class ConfigGenerationSuite { |} | |dependencies { - | compile group: 'org.scala-lang', name: 'scala-library', version: "$version" + | implementation group: 'org.scala-lang', name: 'scala-library', version: "$version" |} """.stripMargin )