diff --git a/bsp/src/mill/bsp/Constants.scala b/bsp/src/mill/bsp/Constants.scala index 9dd59b05f48f..735b27f3d61d 100644 --- a/bsp/src/mill/bsp/Constants.scala +++ b/bsp/src/mill/bsp/Constants.scala @@ -6,6 +6,6 @@ private[mill] object Constants { val bspProtocolVersion = BuildInfo.bsp4jVersion val bspWorkerImplClass = "mill.bsp.worker.BspWorkerImpl" val bspWorkerBuildInfoClass = "mill.bsp.worker.BuildInfo" - val languages: Seq[String] = Seq("java", "scala") + val languages: Seq[String] = Seq("java", "scala", "kotlin") val serverName = "mill-bsp" } diff --git a/build.mill b/build.mill index 25b4c03e51f9..db132da71696 100644 --- a/build.mill +++ b/build.mill @@ -428,7 +428,8 @@ trait MillBaseTestsModule extends TestModule { s"-DTEST_SCALATEST_VERSION=${Deps.TestDeps.scalaTest.dep.version}", s"-DTEST_TEST_INTERFACE_VERSION=${Deps.sbtTestInterface.dep.version}", s"-DTEST_ZIOTEST_VERSION=${Deps.TestDeps.zioTest.dep.version}", - s"-DTEST_ZINC_VERSION=${Deps.zinc.dep.version}" + s"-DTEST_ZINC_VERSION=${Deps.zinc.dep.version}", + s"-DMILL_TEST_KOTLIN_VERSION=${Deps.kotlinCompiler.dep.version}" ) } diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-compile-classpaths.json b/integration/ide/bsp-server/resources/fixtures/build-targets-compile-classpaths.json index f67288640f08..f39f59fa7eba 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-compile-classpaths.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-compile-classpaths.json @@ -8,6 +8,16 @@ "file:///workspace/hello-java/compile-resources" ] }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "classpath": [ + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib//kotlin-stdlib-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/annotations//annotations-.jar", + "file:///workspace/hello-kotlin/compile-resources" + ] + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-dependency-modules.json b/integration/ide/bsp-server/resources/fixtures/build-targets-dependency-modules.json index 2820a7f6c4ac..5dbf41724f10 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-dependency-modules.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-dependency-modules.json @@ -6,6 +6,17 @@ }, "modules": [] }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "modules": [ + { + "name": "org.jetbrains.kotlin:kotlin-stdlib", + "version": "" + } + ] + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-dependency-sources.json b/integration/ide/bsp-server/resources/fixtures/build-targets-dependency-sources.json index 1a0bee2bbee4..3be9d342e20a 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-dependency-sources.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-dependency-sources.json @@ -6,6 +6,15 @@ }, "sources": [] }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "sources": [ + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib//kotlin-stdlib--sources.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/annotations//annotations--sources.jar" + ] + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-javac-options.json b/integration/ide/bsp-server/resources/fixtures/build-targets-javac-options.json index 043b0582ab6f..65e5269db0d2 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-javac-options.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-javac-options.json @@ -10,6 +10,18 @@ ], "classDirectory": "file:///workspace/out/hello-java/compile.dest/classes" }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "options": [], + "classpath": [ + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib//kotlin-stdlib-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/annotations//annotations-.jar", + "file:///workspace/hello-kotlin/compile-resources" + ], + "classDirectory": "file:///workspace/out/hello-kotlin/compile.dest/classes" + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-jvm-run-environments.json b/integration/ide/bsp-server/resources/fixtures/build-targets-jvm-run-environments.json index 585df6807fc6..40d001f52ff5 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-jvm-run-environments.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-jvm-run-environments.json @@ -14,6 +14,22 @@ "environmentVariables": {}, "mainClasses": [] }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "classpath": [ + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib//kotlin-stdlib-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/annotations//annotations-.jar", + "file:///workspace/hello-kotlin/compile-resources", + "file:///workspace/hello-kotlin/resources", + "file:///workspace/out/hello-kotlin/compile.dest/classes" + ], + "jvmOptions": [], + "workingDirectory": "/workspace", + "environmentVariables": {}, + "mainClasses": [] + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-jvm-test-environments.json b/integration/ide/bsp-server/resources/fixtures/build-targets-jvm-test-environments.json index 585df6807fc6..40d001f52ff5 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-jvm-test-environments.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-jvm-test-environments.json @@ -14,6 +14,22 @@ "environmentVariables": {}, "mainClasses": [] }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "classpath": [ + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib//kotlin-stdlib-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/annotations//annotations-.jar", + "file:///workspace/hello-kotlin/compile-resources", + "file:///workspace/hello-kotlin/resources", + "file:///workspace/out/hello-kotlin/compile.dest/classes" + ], + "jvmOptions": [], + "workingDirectory": "/workspace", + "environmentVariables": {}, + "mainClasses": [] + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-output-paths.json b/integration/ide/bsp-server/resources/fixtures/build-targets-output-paths.json index 12bebf136cf4..167fc54a654e 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-output-paths.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-output-paths.json @@ -6,6 +6,12 @@ }, "outputPaths": [] }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "outputPaths": [] + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-resources.json b/integration/ide/bsp-server/resources/fixtures/build-targets-resources.json index fc0ab5736d10..7360d1c92ffb 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-resources.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-resources.json @@ -6,6 +6,12 @@ }, "resources": [] }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "resources": [] + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-scalac-options.json b/integration/ide/bsp-server/resources/fixtures/build-targets-scalac-options.json index 043b0582ab6f..65e5269db0d2 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-scalac-options.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-scalac-options.json @@ -10,6 +10,18 @@ ], "classDirectory": "file:///workspace/out/hello-java/compile.dest/classes" }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "options": [], + "classpath": [ + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib//kotlin-stdlib-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jetbrains/annotations//annotations-.jar", + "file:///workspace/hello-kotlin/compile-resources" + ], + "classDirectory": "file:///workspace/out/hello-kotlin/compile.dest/classes" + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/build-targets-sources.json b/integration/ide/bsp-server/resources/fixtures/build-targets-sources.json index bb3032f88af8..ef73b2656fc9 100644 --- a/integration/ide/bsp-server/resources/fixtures/build-targets-sources.json +++ b/integration/ide/bsp-server/resources/fixtures/build-targets-sources.json @@ -12,6 +12,18 @@ } ] }, + { + "target": { + "uri": "file:///workspace/hello-kotlin" + }, + "sources": [ + { + "uri": "file:///workspace/hello-kotlin/src", + "kind": 2, + "generated": false + } + ] + }, { "target": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/fixtures/initialize-build-result.json b/integration/ide/bsp-server/resources/fixtures/initialize-build-result.json index 207de64635de..3e7a009526d5 100644 --- a/integration/ide/bsp-server/resources/fixtures/initialize-build-result.json +++ b/integration/ide/bsp-server/resources/fixtures/initialize-build-result.json @@ -6,19 +6,22 @@ "compileProvider": { "languageIds": [ "java", - "scala" + "scala", + "kotlin" ] }, "testProvider": { "languageIds": [ "java", - "scala" + "scala", + "kotlin" ] }, "runProvider": { "languageIds": [ "java", - "scala" + "scala", + "kotlin" ] }, "debugProvider": { diff --git a/integration/ide/bsp-server/resources/fixtures/workspace-build-targets.json b/integration/ide/bsp-server/resources/fixtures/workspace-build-targets.json index 41f482a77d32..f38dccc829a7 100644 --- a/integration/ide/bsp-server/resources/fixtures/workspace-build-targets.json +++ b/integration/ide/bsp-server/resources/fixtures/workspace-build-targets.json @@ -26,6 +26,48 @@ "javaVersion": "" } }, + { + "id": { + "uri": "file:///workspace/hello-kotlin" + }, + "displayName": "hello-kotlin", + "baseDirectory": "file:///workspace/hello-kotlin", + "tags": [ + "library", + "application" + ], + "languageIds": [ + "java", + "scala", + "kotlin" + ], + "dependencies": [], + "capabilities": { + "canCompile": true, + "canTest": false, + "canRun": true, + "canDebug": false + }, + "dataKind": "scala", + "data": { + "scalaOrganization": "org.scala-lang", + "scalaVersion": "", + "scalaBinaryVersion": "2.13", + "platform": 1, + "jars": [ + "file:///coursier-cache/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler//scala-compiler-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/scala-lang/scala-reflect//scala-reflect-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/scala-lang/scala-library//scala-library-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/io/github/java-diff-utils/java-diff-utils//java-diff-utils-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/org/jline/jline//jline-.jar", + "file:///coursier-cache/https/repo1.maven.org/maven2/net/java/dev/jna/jna//jna-.jar" + ], + "jvmBuildTarget": { + "javaHome": "file:///java-home/", + "javaVersion": "" + } + } + }, { "id": { "uri": "file:///workspace/hello-scala" diff --git a/integration/ide/bsp-server/resources/project/build.mill b/integration/ide/bsp-server/resources/project/build.mill index 086b5caa7981..7e625ea7058d 100644 --- a/integration/ide/bsp-server/resources/project/build.mill +++ b/integration/ide/bsp-server/resources/project/build.mill @@ -1,10 +1,13 @@ package build import mill._ -import mill.scalalib._ -object `hello-java` extends JavaModule +object `hello-java` extends scalalib.JavaModule -object `hello-scala` extends ScalaModule { +object `hello-scala` extends scalalib.ScalaModule { def scalaVersion = Option(System.getenv("MILL_TEST_SCALA_2_13_VERSION")).getOrElse(???) } + +object `hello-kotlin` extends kotlinlib.KotlinModule { + def kotlinVersion = Option(System.getenv("MILL_TEST_KOTLIN_VERSION")).getOrElse(???) +} diff --git a/integration/ide/bsp-server/src/BspServerTests.scala b/integration/ide/bsp-server/src/BspServerTests.scala index 8f6e9afb66d2..120c43768998 100644 --- a/integration/ide/bsp-server/src/BspServerTests.scala +++ b/integration/ide/bsp-server/src/BspServerTests.scala @@ -42,9 +42,31 @@ object BspServerTests extends UtestIntegrationTestSuite { } } - val replaceAll = replaceAllValues(workspacePath) ++ scalaTransitiveSubstitutions ++ Seq( - scalaVersion -> "" - ) + val kotlinVersion = sys.props.getOrElse("MILL_TEST_KOTLIN_VERSION", ???) + val kotlinTransitiveSubstitutions = { + val scalaFetchRes = coursierapi.Fetch.create() + .addDependencies(coursierapi.Dependency.of( + "org.jetbrains.kotlin", + "kotlin-stdlib", + kotlinVersion + )) + .fetchResult() + scalaFetchRes.getDependencies.asScala + .filter(dep => dep.getModule.getOrganization != "org.jetbrains.kotlin") + .map { dep => + def basePath(version: String) = + s"${dep.getModule.getOrganization.split('.').mkString("/")}/${dep.getModule.getName}/$version/${dep.getModule.getName}-$version" + basePath(dep.getVersion) -> basePath(s"<${dep.getModule.getName}-version>") + } + } + + val replaceAll = replaceAllValues(workspacePath) ++ + scalaTransitiveSubstitutions ++ + kotlinTransitiveSubstitutions ++ + Seq( + scalaVersion -> "", + kotlinVersion -> "" + ) compareWithGsonFixture( initRes, diff --git a/kotlinlib/src/mill/kotlinlib/KotlinModule.scala b/kotlinlib/src/mill/kotlinlib/KotlinModule.scala index 937ea8363479..6a81e5557e42 100644 --- a/kotlinlib/src/mill/kotlinlib/KotlinModule.scala +++ b/kotlinlib/src/mill/kotlinlib/KotlinModule.scala @@ -5,11 +5,12 @@ package mill package kotlinlib -import mill.api.{Loose, PathRef, Result} +import mill.api.{Loose, PathRef, Result, internal} import mill.define.{Command, ModuleRef, Task} import mill.kotlinlib.worker.api.KotlinWorker import mill.scalalib.api.{CompilationResult, ZincWorkerApi} -import mill.scalalib.{JavaModule, Lib, ZincWorkerModule} +import mill.scalalib.bsp.{BspBuildTarget, BspModule} +import mill.scalalib.{JavaModule, Lib, ScalaModule, ZincWorkerModule} import mill.util.Jvm import mill.util.Util.millProjectModule import mill.{Agg, T} @@ -326,6 +327,54 @@ trait KotlinModule extends JavaModule { outer => private[kotlinlib] def internalReportOldProblems: Task[Boolean] = zincReportCachedProblems + @internal + override def bspBuildTarget: BspBuildTarget = super.bspBuildTarget.copy( + // Mark the module as a Scala one, so that intellij-scala handles it (and deals fine with Kotlin code) + languageIds = + Seq(BspModule.LanguageId.Java, BspModule.LanguageId.Scala, BspModule.LanguageId.Kotlin), + canCompile = true, + canRun = true + ) + + /** + * Classpath of the Scala Compiler, to be passed to IntelliJ + */ + def kotlinIntellijScalaCompilerClasspath: T[Agg[PathRef]] = + this match { + case scalaMod: ScalaModule => Task { scalaMod.scalaCompilerClasspath() } + case _ => + Task { + defaultResolver().resolveDeps( + mill.scalalib.Lib.scalaCompilerIvyDeps( + "org.scala-lang", + scala.util.Properties.versionNumberString + ) ++ + mill.scalalib.Lib.scalaRuntimeIvyDeps( + "org.scala-lang", + scala.util.Properties.versionNumberString + ) + ) + } + } + + @internal + override def bspBuildTargetData: Task[Option[(String, AnyRef)]] = + this match { + case scalaMod: ScalaModule => + ScalaModule.bspBuildTargetData(scalaMod) + case _ => + Task.Anon { + Some( + ScalaModule.bspBuildTargetData( + "org.scala-lang", + scala.util.Properties.versionNumberString, + kotlinIntellijScalaCompilerClasspath(), + jvmBuildTarget + ) + ) + } + } + /** * A test sub-module linked to its parent module best suited for unit-tests. */ diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala index 16ce9abf6c5a..082522a0692d 100644 --- a/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/scalalib/src/mill/scalalib/ScalaModule.scala @@ -2,6 +2,7 @@ package mill package scalalib import mill.api.{DummyInputStream, JarManifest, PathRef, Result, internal} +import mill.scalalib.bsp.JvmBuildTarget import mill.main.BuildInfo import mill.util.{Jvm, Util} import mill.util.Jvm.createJar @@ -580,19 +581,8 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase { outer => ) @internal - override def bspBuildTargetData: Task[Option[(String, AnyRef)]] = Task.Anon { - Some(( - "scala", - ScalaBuildTarget( - scalaOrganization = scalaOrganization(), - scalaVersion = scalaVersion(), - scalaBinaryVersion = ZincWorkerUtil.scalaBinaryVersion(scalaVersion()), - platform = ScalaPlatform.JVM, - jars = scalaCompilerClasspath().map(_.path.toNIO.toUri.toString).iterator.toSeq, - jvmBuildTarget = Some(jvmBuildTarget) - ) - )) - } + override def bspBuildTargetData: Task[Option[(String, AnyRef)]] = + ScalaModule.bspBuildTargetData(this) override def semanticDbScalaVersion: T[String] = scalaVersion() @@ -652,3 +642,34 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase { outer => ) } } + +object ScalaModule { + private[mill] def bspBuildTargetData(scalaMod: ScalaModule): Task[Option[(String, AnyRef)]] = + Task.Anon { + Some( + bspBuildTargetData( + scalaMod.scalaOrganization(), + scalaMod.scalaVersion(), + scalaMod.scalaCompilerClasspath(), + scalaMod.jvmBuildTarget + ) + ) + } + private[mill] def bspBuildTargetData( + scalaOrganization: String, + scalaVersion: String, + scalaCompilerClasspath: Agg[PathRef], + jvmBuildTarget: JvmBuildTarget + ): (String, AnyRef) = + ( + "scala", + ScalaBuildTarget( + scalaOrganization = scalaOrganization, + scalaVersion = scalaVersion, + scalaBinaryVersion = ZincWorkerUtil.scalaBinaryVersion(scalaVersion), + platform = ScalaPlatform.JVM, + jars = scalaCompilerClasspath.map(_.path.toNIO.toUri.toString).iterator.toSeq, + jvmBuildTarget = Some(jvmBuildTarget) + ) + ) +} diff --git a/scalalib/src/mill/scalalib/bsp/BspModule.scala b/scalalib/src/mill/scalalib/bsp/BspModule.scala index 42c386379874..edd208ca5795 100644 --- a/scalalib/src/mill/scalalib/bsp/BspModule.scala +++ b/scalalib/src/mill/scalalib/bsp/BspModule.scala @@ -46,6 +46,7 @@ object BspModule { object LanguageId { val Java = "java" val Scala = "scala" + val Kotlin = "kotlin" } /** Used to define the [[BspBuildTarget.tags]] field. */ diff --git a/testkit/src/mill/testkit/BspServerUtil.scala b/testkit/src/mill/testkit/BspServerUtil.scala index eb15e27690ab..567e89e54f32 100644 --- a/testkit/src/mill/testkit/BspServerUtil.scala +++ b/testkit/src/mill/testkit/BspServerUtil.scala @@ -147,7 +147,7 @@ object BspServerUtil { BuildInfo.millVersion, b.Bsp4j.PROTOCOL_VERSION, workspacePath.toNIO.toUri.toASCIIString, - new b.BuildClientCapabilities(List("java", "scala").asJava) + new b.BuildClientCapabilities(List("java", "scala", "kotlin").asJava) ) ).get() diff --git a/testkit/src/mill/testkit/IntegrationTester.scala b/testkit/src/mill/testkit/IntegrationTester.scala index d0ef5963e821..768cebe54cae 100644 --- a/testkit/src/mill/testkit/IntegrationTester.scala +++ b/testkit/src/mill/testkit/IntegrationTester.scala @@ -95,6 +95,9 @@ object IntegrationTester { Map("MILL_TEST_SUITE" -> this.getClass().toString()) ++ sys.props.get("MILL_TEST_SCALA_2_13_VERSION") .map("MILL_TEST_SCALA_2_13_VERSION" -> _) + .toSeq ++ + sys.props.get("MILL_TEST_KOTLIN_VERSION") + .map("MILL_TEST_KOTLIN_VERSION" -> _) .toSeq /**