From ff7384fced17630f26e27f1f56e7b4fca43c2217 Mon Sep 17 00:00:00 2001 From: naf Date: Wed, 29 Dec 2021 21:17:05 -0500 Subject: [PATCH 01/42] Remove deprecated command --- main/src/main/scala/sbt/Main.scala | 8 -------- .../main/scala/sbt/internal/CommandStrings.scala | 13 ------------- 2 files changed, 21 deletions(-) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 6bb147f7d..e45987944 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -626,11 +626,6 @@ object BuiltinCommands { s } - @deprecated("Use `lastGrep` instead.", "1.2.0") - def oldLastGrep: Command = - lastGrepCommand(OldLastGrepCommand, oldLastGrepBrief, oldLastGrepDetailed, { s => - lastGrepParser(s) - }) def lastGrep: Command = lastGrepCommand(LastGrepCommand, lastGrepBrief, lastGrepDetailed, lastGrepParser) @@ -643,9 +638,6 @@ object BuiltinCommands { ): Command = Command(name, briefHelp, detail)(parser) { (s: State, sks: (String, Option[AnyKeys])) => { - if (name == OldLastGrepCommand) - s.log.warn(deprecationWarningText(OldLastGrepCommand, LastGrepCommand)) - (s, sks) match { case (s, (pattern, Some(sks))) => val (str, _, display) = extractLast(s) diff --git a/main/src/main/scala/sbt/internal/CommandStrings.scala b/main/src/main/scala/sbt/internal/CommandStrings.scala index 7c50f506e..439cdc295 100644 --- a/main/src/main/scala/sbt/internal/CommandStrings.scala +++ b/main/src/main/scala/sbt/internal/CommandStrings.scala @@ -70,23 +70,10 @@ $PrintCommand def pluginsDetailed = pluginsBrief // TODO: expand val LastCommand = "last" - val OldLastGrepCommand = "last-grep" val LastGrepCommand = "lastGrep" val ExportCommand = "export" val ExportStream = "export" - val oldLastGrepBrief = - (OldLastGrepCommand, "Shows lines from the last output for 'key' that match 'pattern'.") - val oldLastGrepDetailed = - s"""$OldLastGrepCommand - Displays lines from the logging of previous commands that match `pattern`. - -$OldLastGrepCommand [key] - Displays lines from logging associated with `key` that match `pattern`. The key typically refers to a task (for example, test:compile). The logging that is displayed is restricted to the logging for that particular task. - - is a regular expression interpreted by java.util.Pattern. Matching text is highlighted (when highlighting is supported and enabled). - See also '$LastCommand'.""" - val lastGrepBrief = (LastGrepCommand, "Shows lines from the last output for 'key' that match 'pattern'.") val lastGrepDetailed = From 1e89d713111fc48c11a1a102b4d70e4df0374078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pa=C5=82ka?= Date: Thu, 24 Mar 2022 15:35:57 +0100 Subject: [PATCH 02/42] Add support for scala-output-version flag in Scala 3 --- main/src/main/scala/sbt/Defaults.scala | 80 +++++++++++-- main/src/main/scala/sbt/Keys.scala | 6 +- .../scala/sbt/internal/ClassLoaders.scala | 4 +- .../build.sbt | 30 +++++ .../scala-output-version-redundant-flags/test | 3 + .../scala-output-version/Bar.scala | 5 + .../scala-output-version/build.sbt | 112 ++++++++++++++++++ .../foo/src/main/scala-2.13/Foo.scala | 11 ++ .../foo/src/main/scala-3/Foo.scala | 17 +++ .../foo/src/test/scala-2.13/FooTest.scala | 7 ++ .../foo/src/test/scala-3/FooTest.scala | 19 +++ .../scala-output-version/test | 35 ++++++ 12 files changed, 317 insertions(+), 12 deletions(-) create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/build.sbt create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/test create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/Bar.scala create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/build.sbt create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-2.13/Foo.scala create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-3/Foo.scala create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-2.13/FooTest.scala create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-3/FooTest.scala create mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/test diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index facf6637a..d7a1f6a4b 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -679,6 +679,15 @@ object Defaults extends BuildCommon { else topLoader }, scalaInstance := scalaInstanceTask.value, + runtimeScalaInstance := Def.taskDyn { + scalaOutputVersion.?.value + .map { version => + scalaInstanceTask0(version = version, isRuntimeInstance = true) + } + .getOrElse { + scalaInstance + } + }.value, crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled), pluginCrossBuild / sbtBinaryVersion := binarySbtVersion( (pluginCrossBuild / sbtVersion).value @@ -977,6 +986,49 @@ object Defaults extends BuildCommon { old ++ Seq("-Wconf:cat=unused-nowarn:s", "-Xsource:3") else old }, + scalacOptions := { + val old = scalacOptions.value + + // 3 possible sources of Scala output version + val fromCompiler = CrossVersion + .partialVersion(scalaVersion.value) + .map { case (major, minor) => s"${major}.${minor}" } + .getOrElse( + sys.error(s"Wrong value of `scalaVersion`: ${scalaVersion.value}") + ) + + val maybeFromSetting = scalaOutputVersion.?.value.map { version => + CrossVersion + .partialVersion(version) + .map { case (major, minor) => s"${major}.${minor}" } + .getOrElse( + sys.error(s"Wrong value of `scalaOutputVersion`: ${version}") + ) + } + + val maybeFromFlags = old.zipWithIndex.flatMap { + case (opt, idx) => + if (opt.startsWith("-scala-output-version:")) + Some(opt.stripPrefix("-scala-output-version:")) + else if (opt == "-scala-output-version" && idx + 1 < old.length) + Some(old(idx + 1)) + else None + }.lastOption + + // Add -scala-output-version flag when minor Scala versions are different + // unless the flag is already set properly + maybeFromSetting match { + case Some(fromSetting) if fromSetting != fromCompiler => + maybeFromFlags match { + case Some(fromFlags) if fromFlags == fromSetting => + old + case _ => + old ++ Seq("-scala-output-version", fromSetting) + } + case _ => + old + } + }, persistJarClasspath :== true, classpathEntryDefinesClassVF := { (if (persistJarClasspath.value) classpathDefinesClassCache.value @@ -1087,13 +1139,19 @@ object Defaults extends BuildCommon { } def scalaInstanceTask: Initialize[Task[ScalaInstance]] = Def.taskDyn { + scalaInstanceTask0(scalaVersion.value, false) + } + + private def scalaInstanceTask0( + version: String, + isRuntimeInstance: Boolean + ): Initialize[Task[ScalaInstance]] = Def.taskDyn { // if this logic changes, ensure that `unmanagedScalaInstanceOnly` and `update` are changed // appropriately to avoid cycles scalaHome.value match { case Some(h) => scalaInstanceFromHome(h) case None => val scalaProvider = appConfiguration.value.provider.scalaProvider - val version = scalaVersion.value if (version == scalaProvider.version) // use the same class loader as the Scala classes used by sbt Def.task { val allJars = scalaProvider.jars @@ -1111,7 +1169,7 @@ object Defaults extends BuildCommon { case _ => ScalaInstance(version, scalaProvider) } } else - scalaInstanceFromUpdate + scalaInstanceFromUpdate0(isRuntimeInstance) } } @@ -1132,22 +1190,29 @@ object Defaults extends BuildCommon { pre + post } - def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = Def.task { + def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = scalaInstanceFromUpdate0(false) + + private def scalaInstanceFromUpdate0( + isRuntimeInstance: Boolean + ): Initialize[Task[ScalaInstance]] = Def.task { val sv = scalaVersion.value val fullReport = update.value val toolReport = fullReport .configuration(Configurations.ScalaTool) .getOrElse(sys.error(noToolConfiguration(managedScalaInstance.value))) + lazy val runtimeReport = fullReport.configuration(Configurations.Runtime).get + val libraryReport = if (isRuntimeInstance) runtimeReport else toolReport - def file(id: String): File = { + def libraryFile(id: String): File = { val files = for { - m <- toolReport.modules if m.module.name.startsWith(id) + m <- libraryReport.modules if m.module.name.startsWith(id) (art, file) <- m.artifacts if art.`type` == Artifact.DefaultType } yield file files.headOption getOrElse sys.error(s"Missing $id jar file") } + val libraryJars = ScalaArtifacts.libraryIds(sv).map(libraryFile) val allCompilerJars = toolReport.modules.flatMap(_.artifacts.map(_._2)) val allDocJars = fullReport @@ -1155,7 +1220,6 @@ object Defaults extends BuildCommon { .toSeq .flatMap(_.modules) .flatMap(_.artifacts.map(_._2)) - val libraryJars = ScalaArtifacts.libraryIds(sv).map(file) makeScalaInstance( sv, @@ -2034,7 +2098,7 @@ object Defaults extends BuildCommon { def runnerInit: Initialize[Task[ScalaRun]] = Def.task { val tmp = taskTemporaryDirectory.value val resolvedScope = resolvedScoped.value.scope - val si = scalaInstance.value + val si = runtimeScalaInstance.value val s = streams.value val opts = forkOptions.value val options = javaOptions.value @@ -3255,7 +3319,7 @@ object Classpaths { autoScalaLibrary.value && scalaHome.value.isEmpty && managedScalaInstance.value, sbtPlugin.value, scalaOrganization.value, - scalaVersion.value + scalaOutputVersion.?.value.getOrElse(scalaVersion.value) ), // Override the default to handle mixing in the sbtPlugin + scala dependencies. allDependencies := { diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 2270ee573..a4fee0b85 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -186,9 +186,11 @@ object Keys { val compileOptions = taskKey[CompileOptions]("Collects basic options to configure compilers").withRank(DTask) val compileInputs = taskKey[Inputs]("Collects all inputs needed for compilation.").withRank(DTask) val scalaHome = settingKey[Option[File]]("If Some, defines the local Scala installation to use for compilation, running, and testing.").withRank(ASetting) - val scalaInstance = taskKey[ScalaInstance]("Defines the Scala instance to use for compilation, running, and testing.").withRank(DTask) + val scalaInstance = taskKey[ScalaInstance]("Defines the Scala instance to use for compilation").withRank(DTask) + val runtimeScalaInstance = taskKey[ScalaInstance]("Defines the Scala instance used at runtime (also for tests).").withRank(DTask) val scalaOrganization = settingKey[String]("Organization/group ID of the Scala used in the project. Default value is 'org.scala-lang'. This is an advanced setting used for clones of the Scala Language. It should be disregarded in standard use cases.").withRank(CSetting) - val scalaVersion = settingKey[String]("The version of Scala used for building.").withRank(APlusSetting) + val scalaVersion = settingKey[String]("The version of Scala compiler used for building this project.").withRank(APlusSetting) + val scalaOutputVersion = settingKey[String]("The version of Scala standard library used for running this project and declared as its transitive dependency.").withRank(APlusSetting) val scalaBinaryVersion = settingKey[String]("The Scala version substring describing binary compatibility.").withRank(BPlusSetting) val crossScalaVersions = settingKey[Seq[String]]("The versions of Scala used when cross-building.").withRank(BPlusSetting) val crossVersion = settingKey[CrossVersion]("Configures handling of the Scala version when cross-building.").withRank(CSetting) diff --git a/main/src/main/scala/sbt/internal/ClassLoaders.scala b/main/src/main/scala/sbt/internal/ClassLoaders.scala index 1c5df8aa0..0275ae9dd 100644 --- a/main/src/main/scala/sbt/internal/ClassLoaders.scala +++ b/main/src/main/scala/sbt/internal/ClassLoaders.scala @@ -35,7 +35,7 @@ private[sbt] object ClassLoaders { * Get the class loader for a test task. The configuration could be IntegrationTest or Test. */ private[sbt] def testTask: Def.Initialize[Task[ClassLoader]] = Def.task { - val si = scalaInstance.value + val si = runtimeScalaInstance.value val cp = fullClasspath.value.map(_.data) val dependencyStamps = modifiedTimes((dependencyClasspathFiles / outputFileStamps).value).toMap def getLm(f: File): Long = dependencyStamps.getOrElse(f, IO.getModifiedTimeOrZero(f)) @@ -64,7 +64,7 @@ private[sbt] object ClassLoaders { private[sbt] def runner: Def.Initialize[Task[ScalaRun]] = Def.taskDyn { val resolvedScope = resolvedScoped.value.scope - val instance = scalaInstance.value + val instance = runtimeScalaInstance.value val s = streams.value val opts = forkOptions.value val options = javaOptions.value diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/build.sbt b/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/build.sbt new file mode 100644 index 000000000..e1bc21ae3 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/build.sbt @@ -0,0 +1,30 @@ +val checkOptions = taskKey[Unit]("") + +lazy val p1 = project + .settings( + scalaVersion := "3.0.2", + checkOptions := { + assert((Compile / scalacOptions).value == Seq()) + assert((Test / scalacOptions).value == Seq()) + } + ) + +lazy val p2 = project + .settings( + scalaVersion := "3.0.2", + scalaOutputVersion := "3.0.2", + checkOptions := { + assert((Compile / scalacOptions).value == Seq()) + assert((Test / scalacOptions).value == Seq()) + } + ) + +lazy val p3 = project + .settings( + scalaVersion := "3.1.2-RC2", + scalaOutputVersion := "3.0.2", + checkOptions := { + assert((Compile / scalacOptions).value == Seq("-scala-output-version", "3.0")) + assert((Test / scalacOptions).value == Seq("-scala-output-version", "3.0")) + } + ) diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/test b/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/test new file mode 100644 index 000000000..500721a31 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/test @@ -0,0 +1,3 @@ +> p1 / checkOptions +> p2 / checkOptions +> p3 / checkOptions \ No newline at end of file diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/Bar.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/Bar.scala new file mode 100644 index 000000000..772478e95 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version/Bar.scala @@ -0,0 +1,5 @@ +object Bar { + def main(args: Array[String]) = { + assert(foo.main.Foo.numbers == Seq(1, 2, 3)) + } +} diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/build.sbt b/sbt-app/src/sbt-test/dependency-management/scala-output-version/build.sbt new file mode 100644 index 000000000..78ad544f4 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version/build.sbt @@ -0,0 +1,112 @@ +// cases 1, 2, 3: check for scala version in bar +// case a: check locally published Ivy dependency +// case b: check locally published Maven dependency +// case c: check unpublished sibling module dependency + +val org = "org.example" +val fooName = "sbt-test-scala-output-version-foo" +val revision = "0.0.1-SNAPSHOT" + +ThisBuild / organization := org +ThisBuild / version := revision + +lazy val foo = project.in(file("foo")) + .settings( + name := fooName, + scalaVersion := "3.1.2-RC2", + crossScalaVersions := List("2.13.8", "3.1.2-RC2"), + scalaOutputVersion := "3.0.2", + scalaOutputVersion := { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((3, _)) => "3.0.2" + case _ => scalaVersion.value + } + }, + libraryDependencies ++= Seq( + "org.scalameta" %% "munit" % "0.7.29" % Test + ), + TaskKey[Unit]("checkIvy") := { + val ivyFile = makeIvyXml.value + val ivyContent = IO.read(ivyFile) + val expectedContent = """""" + val hasCorrectStdlib = ivyContent.contains(expectedContent) + if (!hasCorrectStdlib) sys.error(s"The produced Ivy file is incorrect:\n\n${ivyContent}") + }, + TaskKey[Unit]("checkPom") := { + val pomFile = makePom.value + val pomContent = IO.read(pomFile) + val flatPom = pomContent.filterNot(_.isWhitespace) + val expectedContent = "org.scala-langscala3-library_33.0.2" + val hasCorrectStdlib = flatPom.contains(expectedContent) + if (!hasCorrectStdlib) sys.error(s"The produced POM file is incorrect:\n\n${pomContent}") + } + ) + +val scala3_1 = Seq(scalaVersion := "3.1.1") +val scala3_0 = Seq(scalaVersion := "3.0.2") +val scala2_13 = Seq(scalaVersion := "2.13.8") +val ivyFooDep = Seq( + libraryDependencies ++= Seq( + org %% fooName % revision + ), + resolvers := Seq(Resolver.defaultLocal) +) +val mavenFooDep = Seq( + libraryDependencies ++= Seq( + org %% fooName % revision + ), + resolvers := Seq(Resolver.mavenLocal) +) + +lazy val bar1a = project.in(file("bar1a")) + .settings( + scala3_1, + ivyFooDep + ) + +lazy val bar1b = project.in(file("bar1b")) + .settings( + scala3_1, + mavenFooDep + ) + +lazy val bar1c = project.in(file("bar1c")) + .settings( + scala3_1, + ).dependsOn(foo) + + +lazy val bar2a = project.in(file("bar2a")) + .settings( + scala3_0, + ivyFooDep + ) + +lazy val bar2b = project.in(file("bar2b")) + .settings( + scala3_0, + mavenFooDep + ) + +lazy val bar2c = project.in(file("bar2c")) + .settings( + scala3_0, + ).dependsOn(foo) + + +lazy val bar3a = project.in(file("bar3a")) + .settings( + scala2_13, + ivyFooDep + ) + +lazy val bar3b = project.in(file("bar3b")) + .settings( + scala2_13, + mavenFooDep + ) + +lazy val bar3c = project.in(file("bar3c")) + .settings( + scala2_13, + ).dependsOn(foo) diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-2.13/Foo.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-2.13/Foo.scala new file mode 100644 index 000000000..6347cd083 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-2.13/Foo.scala @@ -0,0 +1,11 @@ +package foo.main + +object Foo { + val numbers = Seq(1, 2, 3) +} + +object Run { + def main(args: Array[String]) = { + assert(Foo.numbers.length == 3) + } +} diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-3/Foo.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-3/Foo.scala new file mode 100644 index 000000000..11ec280a3 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-3/Foo.scala @@ -0,0 +1,17 @@ +package foo.main + +class MyException extends Exception("MyException") + +@annotation.experimental +object Exceptional: + import language.experimental.saferExceptions + def foo(): Unit throws MyException = // this requires at least 3.1.x to compile + throw new MyException + +object Foo: + val numbers = Seq(1, 2, 3) + +@main def run() = + val canEqualMethods = classOf[CanEqual.type].getMethods.toList + assert( canEqualMethods.exists(_.getName == "canEqualSeq")) // since 3.0.x + assert(!canEqualMethods.exists(_.getName == "canEqualSeqs")) // since 3.1.x diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-2.13/FooTest.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-2.13/FooTest.scala new file mode 100644 index 000000000..4102861ae --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-2.13/FooTest.scala @@ -0,0 +1,7 @@ +package foo.test + +class FooTest extends munit.FunSuite { + test("foo") { + assertEquals(foo.main.Foo.numbers, Seq(1, 2, 3)) + } +} diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-3/FooTest.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-3/FooTest.scala new file mode 100644 index 000000000..cc0ee76b6 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-3/FooTest.scala @@ -0,0 +1,19 @@ +package foo.test + +class MyException extends Exception("MyException") + +@annotation.experimental +object Exceptional: + import language.experimental.saferExceptions + def foo(): Unit throws MyException = // this requires at least 3.1.x to compile + throw new MyException + + +class FooTest extends munit.FunSuite: + test("foo") { + assertEquals(foo.main.Foo.numbers, Seq(1, 2, 3)) + + val canEqualMethods = classOf[CanEqual.type].getMethods.toList + assert( canEqualMethods.exists(_.getName == "canEqualSeq")) // since 3.0.x + assert(!canEqualMethods.exists(_.getName == "canEqualSeqs")) // since 3.1.x + } diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/test b/sbt-app/src/sbt-test/dependency-management/scala-output-version/test new file mode 100644 index 000000000..ee66638fb --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/scala-output-version/test @@ -0,0 +1,35 @@ +$ copy-file Bar.scala bar1a/src/main/scala/Bar.scala +$ copy-file Bar.scala bar1b/src/main/scala/Bar.scala +$ copy-file Bar.scala bar1c/src/main/scala/Bar.scala +$ copy-file Bar.scala bar2a/src/main/scala/Bar.scala +$ copy-file Bar.scala bar2b/src/main/scala/Bar.scala +$ copy-file Bar.scala bar2c/src/main/scala/Bar.scala +$ copy-file Bar.scala bar3a/src/main/scala/Bar.scala +$ copy-file Bar.scala bar3b/src/main/scala/Bar.scala +$ copy-file Bar.scala bar3c/src/main/scala/Bar.scala + +> ++3.1.2-RC2 +> foo / compile +> foo / run +> foo / test +> foo / publishLocal +> foo / checkIvy +> foo / publishM2 +> foo / checkPom + +> ++2.13.8 +> foo / compile +> foo / run +> foo / test +> foo / publishLocal +> foo / publishM2 + +> bar1a / run +> bar1b / run +> bar1c / run +> bar2a / run +> bar2b / run +> bar2c / run +> bar3a / run +> bar3b / run +> bar3c / run From 491f70cd30344b87bf52f972e903d52b3623d4ff Mon Sep 17 00:00:00 2001 From: Brice Jaglin Date: Wed, 23 Mar 2022 12:25:35 +0100 Subject: [PATCH 03/42] includePluginResolvers should work for coursier resolutions --- .../sbt/coursierint/CoursierRepositoriesTasks.scala | 11 +---------- .../dependency-management/resolvers-plugin/build.sbt | 7 +++++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala index 6545478a2..e05916408 100644 --- a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala +++ b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala @@ -57,16 +57,7 @@ object CoursierRepositoriesTasks { private final val keepPreloaded = false // coursierKeepPreloaded.value def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = Def.task { - val bootResOpt = bootResolvers.value - val overrideFlag = overrideBuildResolvers.value - val result0 = bootResOpt.filter(_ => overrideFlag) match { - case Some(r) => r - case None => - val extRes = externalResolvers.value - val isSbtPlugin = sbtPlugin.value - if (isSbtPlugin) sbtResolvers.value ++ extRes - else extRes - } + val result0 = fullResolvers.value.filterNot(_ == projectResolver.value) val reorderResolvers = true // coursierReorderResolvers.value val paths = ivyPaths.value diff --git a/sbt-app/src/sbt-test/dependency-management/resolvers-plugin/build.sbt b/sbt-app/src/sbt-test/dependency-management/resolvers-plugin/build.sbt index 5d76d6c17..cc96aa6cd 100644 --- a/sbt-app/src/sbt-test/dependency-management/resolvers-plugin/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/resolvers-plugin/build.sbt @@ -2,6 +2,9 @@ lazy val check = taskKey[Unit]("") ThisBuild / includePluginResolvers := true check := { - val rs = fullResolvers.value - assert(rs exists (_.name == "bintray-eed3si9n-sbt-plugins"), s"$rs does not include bintray") + val ivy = fullResolvers.value + assert(ivy exists (_.name == "bintray-eed3si9n-sbt-plugins"), s"$ivy does not include bintray") + + val cs = csrResolvers.value + assert(cs exists (_.name == "bintray-eed3si9n-sbt-plugins"), s"$cs does not include bintray") } From 862d373f02f178a844e7b48caa2f519386dc666b Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Fri, 18 Mar 2022 02:23:08 +0900 Subject: [PATCH 04/42] Don't fire publishDiagnostic if there's no problems both in current and previous compilation --- main/src/main/scala/sbt/Defaults.scala | 8 +++-- .../internal/server/BuildServerReporter.scala | 30 +++++++++++-------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index d7a1f6a4b..fad4a6a0c 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -2374,10 +2374,11 @@ object Defaults extends BuildCommon { val ci = (compile / compileInputs).value val ping = earlyOutputPing.value val reporter = (compile / bspReporter).value + val prevAnalysis = previousCompile.value.analysis.toOption.getOrElse(Analysis.empty) BspCompileTask.compute(bspTargetIdentifier.value, thisProjectRef.value, configuration.value) { task => // TODO - Should readAnalysis + saveAnalysis be scoped by the compile task too? - compileIncrementalTaskImpl(task, s, ci, ping, reporter) + compileIncrementalTaskImpl(task, s, ci, ping, reporter, prevAnalysis) } } private val incCompiler = ZincUtil.defaultIncrementalCompiler @@ -2406,7 +2407,8 @@ object Defaults extends BuildCommon { s: TaskStreams, ci: Inputs, promise: PromiseWrap[Boolean], - reporter: BuildServerReporter + reporter: BuildServerReporter, + prev: CompileAnalysis ): CompileResult = { lazy val x = s.text(ExportStream) def onArgs(cs: Compilers) = { @@ -2428,7 +2430,7 @@ object Defaults extends BuildCommon { .withSetup(onProgress(setup)) try { val result = incCompiler.compile(i, s.log) - reporter.sendSuccessReport(result.getAnalysis) + reporter.sendSuccessReport(result.getAnalysis, prev) result } catch { case e: Throwable => diff --git a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala index dba366578..8184b090c 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala @@ -38,7 +38,7 @@ sealed trait BuildServerReporter extends Reporter { protected def publishDiagnostic(problem: Problem): Unit - def sendSuccessReport(analysis: CompileAnalysis): Unit + def sendSuccessReport(analysis: CompileAnalysis, prev: CompileAnalysis): Unit def sendFailureReport(sources: Array[VirtualFile]): Unit @@ -86,20 +86,26 @@ final class BuildServerReporterImpl( if (ref.id().contains("<")) None else Some(converter.toPath(ref)) - override def sendSuccessReport(analysis: CompileAnalysis): Unit = { + override def sendSuccessReport(analysis: CompileAnalysis, prev: CompileAnalysis): Unit = { + val prevInfos = prev.readSourceInfos().getAllSourceInfos().asScala for { (source, infos) <- analysis.readSourceInfos.getAllSourceInfos.asScala filePath <- toSafePath(source) } { - val diagnostics = infos.getReportedProblems.toSeq.flatMap(toDiagnostic) - val params = PublishDiagnosticsParams( - textDocument = TextDocumentIdentifier(filePath.toUri), - buildTarget, - originId = None, - diagnostics.toVector, - reset = true - ) - exchange.notifyEvent("build/publishDiagnostics", params) + val prevProblems = prevInfos.get(source).map(_.getReportedProblems()).getOrElse(Array.empty) + val dontPublish = prevProblems.length == 0 && infos.getReportedProblems().length == 0 + + if (!dontPublish) { + val diagnostics = infos.getReportedProblems.toSeq.flatMap(toDiagnostic) + val params = PublishDiagnosticsParams( + textDocument = TextDocumentIdentifier(filePath.toUri), + buildTarget, + originId = None, + diagnostics.toVector, + reset = true + ) + exchange.notifyEvent("build/publishDiagnostics", params) + } } } @@ -179,7 +185,7 @@ final class BuildServerForwarder( protected override val underlying: Reporter ) extends BuildServerReporter { - override def sendSuccessReport(analysis: CompileAnalysis): Unit = () + override def sendSuccessReport(analysis: CompileAnalysis, prev: CompileAnalysis): Unit = () override def sendFailureReport(sources: Array[VirtualFile]): Unit = () From 620c55d6ac84bf10c992e2d7492c73703ec9362d Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Fri, 18 Mar 2022 23:04:07 +0900 Subject: [PATCH 05/42] Re-publish warnings on BSP server startup Imitate https://github.com/scalacenter/bloop/commit/8aaf828b033c081f420c2c54879b0e28eeeae9df --- main/src/main/scala/sbt/Defaults.scala | 8 +++++-- .../internal/server/BuildServerProtocol.scala | 16 ++++++++++++++ .../internal/server/BuildServerReporter.scala | 21 +++++++++++++++---- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index fad4a6a0c..82724a3b5 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -2393,7 +2393,7 @@ object Defaults extends BuildCommon { val result0 = incCompiler .asInstanceOf[sbt.internal.inc.IncrementalCompilerImpl] .compileAllJava(in, s.log) - reporter.sendSuccessReport(result0.analysis()) + reporter.sendSuccessReport(result0.analysis(), Analysis.empty, false) result0.withHasModified(result0.hasModified || r.hasModified) } else r } catch { @@ -2430,7 +2430,11 @@ object Defaults extends BuildCommon { .withSetup(onProgress(setup)) try { val result = incCompiler.compile(i, s.log) - reporter.sendSuccessReport(result.getAnalysis, prev) + reporter.sendSuccessReport( + result.getAnalysis, + prev, + BuildServerProtocol.shouldReportAllPreviousProblems(task.targetId) + ) result } catch { case e: Throwable => diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 0c6655e2d..1cfae2054 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -39,11 +39,26 @@ import scala.collection.mutable import scala.util.control.NonFatal import scala.util.{ Failure, Success, Try } import scala.annotation.nowarn +import scala.collection.concurrent.TrieMap import sbt.testing.Framework object BuildServerProtocol { import sbt.internal.bsp.codec.JsonProtocol._ + /** + * Keep track of those projects that were compiled at least once so that we can + * decide to enable fresh reporting for projects that are compiled for the first time. + * + * see: https://github.com/scalacenter/bloop/issues/726 + */ + private val compiledTargetsAtLeastOnce = new TrieMap[bsp.BuildTargetIdentifier, Boolean]() + def shouldReportAllPreviousProblems(id: bsp.BuildTargetIdentifier): Boolean = { + compiledTargetsAtLeastOnce.putIfAbsent(id, true) match { + case Some(_) => false + case None => true + } + } + private val capabilities = BuildServerCapabilities( CompileProvider(BuildServerConnection.languages), TestProvider(BuildServerConnection.languages), @@ -354,6 +369,7 @@ object BuildServerProtocol { case r if r.method == Method.Initialize => val params = Converter.fromJson[InitializeBuildParams](json(r)).get checkMetalsCompatibility(semanticdbEnabled, semanticdbVersion, params, callback.log) + compiledTargetsAtLeastOnce.clear() val response = InitializeBuildResult( "sbt", diff --git a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala index 8184b090c..98d59d645 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala @@ -38,7 +38,11 @@ sealed trait BuildServerReporter extends Reporter { protected def publishDiagnostic(problem: Problem): Unit - def sendSuccessReport(analysis: CompileAnalysis, prev: CompileAnalysis): Unit + def sendSuccessReport( + analysis: CompileAnalysis, + prev: CompileAnalysis, + reportAllPreviousProblems: Boolean + ): Unit def sendFailureReport(sources: Array[VirtualFile]): Unit @@ -86,7 +90,11 @@ final class BuildServerReporterImpl( if (ref.id().contains("<")) None else Some(converter.toPath(ref)) - override def sendSuccessReport(analysis: CompileAnalysis, prev: CompileAnalysis): Unit = { + override def sendSuccessReport( + analysis: CompileAnalysis, + prev: CompileAnalysis, + reportAllPreviousProblems: Boolean + ): Unit = { val prevInfos = prev.readSourceInfos().getAllSourceInfos().asScala for { (source, infos) <- analysis.readSourceInfos.getAllSourceInfos.asScala @@ -94,8 +102,9 @@ final class BuildServerReporterImpl( } { val prevProblems = prevInfos.get(source).map(_.getReportedProblems()).getOrElse(Array.empty) val dontPublish = prevProblems.length == 0 && infos.getReportedProblems().length == 0 + val shouldPublish = reportAllPreviousProblems || !dontPublish - if (!dontPublish) { + if (shouldPublish) { val diagnostics = infos.getReportedProblems.toSeq.flatMap(toDiagnostic) val params = PublishDiagnosticsParams( textDocument = TextDocumentIdentifier(filePath.toUri), @@ -185,7 +194,11 @@ final class BuildServerForwarder( protected override val underlying: Reporter ) extends BuildServerReporter { - override def sendSuccessReport(analysis: CompileAnalysis, prev: CompileAnalysis): Unit = () + override def sendSuccessReport( + analysis: CompileAnalysis, + prev: CompileAnalysis, + reportAllPreviousProblems: Boolean + ): Unit = () override def sendFailureReport(sources: Array[VirtualFile]): Unit = () From f5e9ab8424965683dac8e5d2ed6685a689a1fe3e Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Mon, 21 Mar 2022 21:35:11 +0900 Subject: [PATCH 06/42] Add test to verify server doesn't send notifications --- .../src/test/scala/testpkg/BuildServerTest.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index 9cbe43980..a6d900a16 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -125,10 +125,25 @@ object BuildServerTest extends AbstractServerTest { s.contains(""""message":"Compiling runAndTest (100%)"""") }) + assert(svr.waitForString(60.seconds) { s => + s.contains("build/publishDiagnostics") + s.contains(""""diagnostics":[]""") + }) + assert(svr.waitForString(60.seconds) { s => s.contains("build/taskFinish") && s.contains(""""message":"Compiled runAndTest"""") }) + + svr.sendJsonRpc( + s"""{ "jsonrpc": "2.0", "id": "34", "method": "buildTarget/compile", "params": { + | "targets": [{ "uri": "$buildTarget" }] + |} }""".stripMargin + ) + + assert(!svr.waitForString(30.seconds) { s => + s.contains("build/publishDiagnostics") + }, "shouldn't send publishDiagnostics if there's no change in diagnostics") } test("buildTarget/scalacOptions") { _ => From e0f309f4c6d68be824a92cfbfa4577a82056d23d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Mar 2022 04:02:03 +0000 Subject: [PATCH 07/42] Bump actions/cache from 2.1.7 to 3 Bumps [actions/cache](https://github.com/actions/cache) from 2.1.7 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.7...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c603b2f6d..49b534330 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: - name: Coursier cache uses: coursier/cache-action@v6 - name: Cache sbt - uses: actions/cache@v2.1.7 + uses: actions/cache@v3 with: path: ~/.sbt key: ${{ runner.os }}-sbt-cache-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} From 4f3ff52f6ed4b5ab4772b7dd04823a575651e548 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Thu, 31 Mar 2022 12:28:15 +0200 Subject: [PATCH 08/42] feat: generate JVM environment requests --- .../sbt/internal/bsp/JvmEnvironmentItem.scala | 48 +++++++++++++++++++ .../bsp/JvmRunEnvironmentParams.scala | 40 ++++++++++++++++ .../bsp/JvmRunEnvironmentResult.scala | 40 ++++++++++++++++ .../bsp/JvmTestEnvironmentParams.scala | 40 ++++++++++++++++ .../bsp/JvmTestEnvironmentResult.scala | 40 ++++++++++++++++ .../sbt/internal/bsp/codec/JsonProtocol.scala | 5 ++ .../bsp/codec/JvmEnvironmentItemFormats.scala | 35 ++++++++++++++ .../JvmRunEnvironmentParamsFormats.scala | 29 +++++++++++ .../JvmRunEnvironmentResultFormats.scala | 29 +++++++++++ .../JvmTestEnvironmentParamsFormats.scala | 29 +++++++++++ .../JvmTestEnvironmentResultFormats.scala | 29 +++++++++++ protocol/src/main/contraband/bsp.contra | 31 ++++++++++++ 12 files changed, 395 insertions(+) create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmEnvironmentItem.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentResult.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentResult.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmEnvironmentItemFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentResultFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentResultFormats.scala diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmEnvironmentItem.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmEnvironmentItem.scala new file mode 100644 index 000000000..6e3d6b895 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmEnvironmentItem.scala @@ -0,0 +1,48 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmEnvironmentItem private ( + val target: sbt.internal.bsp.BuildTargetIdentifier, + val classpath: Vector[java.net.URI], + val jvmOptions: Vector[String], + val workingDirectory: String, + val environmentVariables: scala.collection.immutable.Map[String, String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmEnvironmentItem => (this.target == x.target) && (this.classpath == x.classpath) && (this.jvmOptions == x.jvmOptions) && (this.workingDirectory == x.workingDirectory) && (this.environmentVariables == x.environmentVariables) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmEnvironmentItem".##) + target.##) + classpath.##) + jvmOptions.##) + workingDirectory.##) + environmentVariables.##) + } + override def toString: String = { + "JvmEnvironmentItem(" + target + ", " + classpath + ", " + jvmOptions + ", " + workingDirectory + ", " + environmentVariables + ")" + } + private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, classpath: Vector[java.net.URI] = classpath, jvmOptions: Vector[String] = jvmOptions, workingDirectory: String = workingDirectory, environmentVariables: scala.collection.immutable.Map[String, String] = environmentVariables): JvmEnvironmentItem = { + new JvmEnvironmentItem(target, classpath, jvmOptions, workingDirectory, environmentVariables) + } + def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): JvmEnvironmentItem = { + copy(target = target) + } + def withClasspath(classpath: Vector[java.net.URI]): JvmEnvironmentItem = { + copy(classpath = classpath) + } + def withJvmOptions(jvmOptions: Vector[String]): JvmEnvironmentItem = { + copy(jvmOptions = jvmOptions) + } + def withWorkingDirectory(workingDirectory: String): JvmEnvironmentItem = { + copy(workingDirectory = workingDirectory) + } + def withEnvironmentVariables(environmentVariables: scala.collection.immutable.Map[String, String]): JvmEnvironmentItem = { + copy(environmentVariables = environmentVariables) + } +} +object JvmEnvironmentItem { + + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, classpath: Vector[java.net.URI], jvmOptions: Vector[String], workingDirectory: String, environmentVariables: scala.collection.immutable.Map[String, String]): JvmEnvironmentItem = new JvmEnvironmentItem(target, classpath, jvmOptions, workingDirectory, environmentVariables) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentParams.scala new file mode 100644 index 000000000..f96b6a26e --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentParams.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmRunEnvironmentParams private ( + val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], + val originId: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmRunEnvironmentParams => (this.targets == x.targets) && (this.originId == x.originId) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmRunEnvironmentParams".##) + targets.##) + originId.##) + } + override def toString: String = { + "JvmRunEnvironmentParams(" + targets + ", " + originId + ")" + } + private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier] = targets, originId: Option[String] = originId): JvmRunEnvironmentParams = { + new JvmRunEnvironmentParams(targets, originId) + } + def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): JvmRunEnvironmentParams = { + copy(targets = targets) + } + def withOriginId(originId: Option[String]): JvmRunEnvironmentParams = { + copy(originId = originId) + } + def withOriginId(originId: String): JvmRunEnvironmentParams = { + copy(originId = Option(originId)) + } +} +object JvmRunEnvironmentParams { + + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: Option[String]): JvmRunEnvironmentParams = new JvmRunEnvironmentParams(targets, originId) + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: String): JvmRunEnvironmentParams = new JvmRunEnvironmentParams(targets, Option(originId)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentResult.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentResult.scala new file mode 100644 index 000000000..47ebb14ea --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentResult.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmRunEnvironmentResult private ( + val items: Vector[sbt.internal.bsp.JvmEnvironmentItem], + val originId: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmRunEnvironmentResult => (this.items == x.items) && (this.originId == x.originId) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmRunEnvironmentResult".##) + items.##) + originId.##) + } + override def toString: String = { + "JvmRunEnvironmentResult(" + items + ", " + originId + ")" + } + private[this] def copy(items: Vector[sbt.internal.bsp.JvmEnvironmentItem] = items, originId: Option[String] = originId): JvmRunEnvironmentResult = { + new JvmRunEnvironmentResult(items, originId) + } + def withItems(items: Vector[sbt.internal.bsp.JvmEnvironmentItem]): JvmRunEnvironmentResult = { + copy(items = items) + } + def withOriginId(originId: Option[String]): JvmRunEnvironmentResult = { + copy(originId = originId) + } + def withOriginId(originId: String): JvmRunEnvironmentResult = { + copy(originId = Option(originId)) + } +} +object JvmRunEnvironmentResult { + + def apply(items: Vector[sbt.internal.bsp.JvmEnvironmentItem], originId: Option[String]): JvmRunEnvironmentResult = new JvmRunEnvironmentResult(items, originId) + def apply(items: Vector[sbt.internal.bsp.JvmEnvironmentItem], originId: String): JvmRunEnvironmentResult = new JvmRunEnvironmentResult(items, Option(originId)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentParams.scala new file mode 100644 index 000000000..dd49a1474 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentParams.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmTestEnvironmentParams private ( + val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], + val originId: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmTestEnvironmentParams => (this.targets == x.targets) && (this.originId == x.originId) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmTestEnvironmentParams".##) + targets.##) + originId.##) + } + override def toString: String = { + "JvmTestEnvironmentParams(" + targets + ", " + originId + ")" + } + private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier] = targets, originId: Option[String] = originId): JvmTestEnvironmentParams = { + new JvmTestEnvironmentParams(targets, originId) + } + def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): JvmTestEnvironmentParams = { + copy(targets = targets) + } + def withOriginId(originId: Option[String]): JvmTestEnvironmentParams = { + copy(originId = originId) + } + def withOriginId(originId: String): JvmTestEnvironmentParams = { + copy(originId = Option(originId)) + } +} +object JvmTestEnvironmentParams { + + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: Option[String]): JvmTestEnvironmentParams = new JvmTestEnvironmentParams(targets, originId) + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: String): JvmTestEnvironmentParams = new JvmTestEnvironmentParams(targets, Option(originId)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentResult.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentResult.scala new file mode 100644 index 000000000..54fd64253 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentResult.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmTestEnvironmentResult private ( + val items: Vector[sbt.internal.bsp.JvmEnvironmentItem], + val originId: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmTestEnvironmentResult => (this.items == x.items) && (this.originId == x.originId) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmTestEnvironmentResult".##) + items.##) + originId.##) + } + override def toString: String = { + "JvmTestEnvironmentResult(" + items + ", " + originId + ")" + } + private[this] def copy(items: Vector[sbt.internal.bsp.JvmEnvironmentItem] = items, originId: Option[String] = originId): JvmTestEnvironmentResult = { + new JvmTestEnvironmentResult(items, originId) + } + def withItems(items: Vector[sbt.internal.bsp.JvmEnvironmentItem]): JvmTestEnvironmentResult = { + copy(items = items) + } + def withOriginId(originId: Option[String]): JvmTestEnvironmentResult = { + copy(originId = originId) + } + def withOriginId(originId: String): JvmTestEnvironmentResult = { + copy(originId = Option(originId)) + } +} +object JvmTestEnvironmentResult { + + def apply(items: Vector[sbt.internal.bsp.JvmEnvironmentItem], originId: Option[String]): JvmTestEnvironmentResult = new JvmTestEnvironmentResult(items, originId) + def apply(items: Vector[sbt.internal.bsp.JvmEnvironmentItem], originId: String): JvmTestEnvironmentResult = new JvmTestEnvironmentResult(items, Option(originId)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala index c55580da2..7d26ae037 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala @@ -63,4 +63,9 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.bsp.codec.ResourcesParamsFormats with sbt.internal.bsp.codec.ResourcesItemFormats with sbt.internal.bsp.codec.ResourcesResultFormats + with sbt.internal.bsp.codec.JvmEnvironmentItemFormats + with sbt.internal.bsp.codec.JvmTestEnvironmentParamsFormats + with sbt.internal.bsp.codec.JvmTestEnvironmentResultFormats + with sbt.internal.bsp.codec.JvmRunEnvironmentParamsFormats + with sbt.internal.bsp.codec.JvmRunEnvironmentResultFormats object JsonProtocol extends JsonProtocol \ No newline at end of file diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmEnvironmentItemFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmEnvironmentItemFormats.scala new file mode 100644 index 000000000..c1ecd6ee1 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmEnvironmentItemFormats.scala @@ -0,0 +1,35 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmEnvironmentItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmEnvironmentItemFormat: JsonFormat[sbt.internal.bsp.JvmEnvironmentItem] = new JsonFormat[sbt.internal.bsp.JvmEnvironmentItem] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmEnvironmentItem = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target") + val classpath = unbuilder.readField[Vector[java.net.URI]]("classpath") + val jvmOptions = unbuilder.readField[Vector[String]]("jvmOptions") + val workingDirectory = unbuilder.readField[String]("workingDirectory") + val environmentVariables = unbuilder.readField[scala.collection.immutable.Map[String, String]]("environmentVariables") + unbuilder.endObject() + sbt.internal.bsp.JvmEnvironmentItem(target, classpath, jvmOptions, workingDirectory, environmentVariables) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmEnvironmentItem, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("target", obj.target) + builder.addField("classpath", obj.classpath) + builder.addField("jvmOptions", obj.jvmOptions) + builder.addField("workingDirectory", obj.workingDirectory) + builder.addField("environmentVariables", obj.environmentVariables) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentParamsFormats.scala new file mode 100644 index 000000000..b1c5ce3e4 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentParamsFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmRunEnvironmentParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmRunEnvironmentParamsFormat: JsonFormat[sbt.internal.bsp.JvmRunEnvironmentParams] = new JsonFormat[sbt.internal.bsp.JvmRunEnvironmentParams] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmRunEnvironmentParams = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets") + val originId = unbuilder.readField[Option[String]]("originId") + unbuilder.endObject() + sbt.internal.bsp.JvmRunEnvironmentParams(targets, originId) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmRunEnvironmentParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("targets", obj.targets) + builder.addField("originId", obj.originId) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentResultFormats.scala new file mode 100644 index 000000000..6a9d40a5e --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentResultFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmRunEnvironmentResultFormats { self: sbt.internal.bsp.codec.JvmEnvironmentItemFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmRunEnvironmentResultFormat: JsonFormat[sbt.internal.bsp.JvmRunEnvironmentResult] = new JsonFormat[sbt.internal.bsp.JvmRunEnvironmentResult] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmRunEnvironmentResult = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val items = unbuilder.readField[Vector[sbt.internal.bsp.JvmEnvironmentItem]]("items") + val originId = unbuilder.readField[Option[String]]("originId") + unbuilder.endObject() + sbt.internal.bsp.JvmRunEnvironmentResult(items, originId) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmRunEnvironmentResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("items", obj.items) + builder.addField("originId", obj.originId) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentParamsFormats.scala new file mode 100644 index 000000000..b02e289f2 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentParamsFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmTestEnvironmentParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmTestEnvironmentParamsFormat: JsonFormat[sbt.internal.bsp.JvmTestEnvironmentParams] = new JsonFormat[sbt.internal.bsp.JvmTestEnvironmentParams] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmTestEnvironmentParams = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets") + val originId = unbuilder.readField[Option[String]]("originId") + unbuilder.endObject() + sbt.internal.bsp.JvmTestEnvironmentParams(targets, originId) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmTestEnvironmentParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("targets", obj.targets) + builder.addField("originId", obj.originId) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentResultFormats.scala new file mode 100644 index 000000000..cd9c9d297 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentResultFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmTestEnvironmentResultFormats { self: sbt.internal.bsp.codec.JvmEnvironmentItemFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmTestEnvironmentResultFormat: JsonFormat[sbt.internal.bsp.JvmTestEnvironmentResult] = new JsonFormat[sbt.internal.bsp.JvmTestEnvironmentResult] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmTestEnvironmentResult = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val items = unbuilder.readField[Vector[sbt.internal.bsp.JvmEnvironmentItem]]("items") + val originId = unbuilder.readField[Option[String]]("originId") + unbuilder.endObject() + sbt.internal.bsp.JvmTestEnvironmentResult(items, originId) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmTestEnvironmentResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("items", obj.items) + builder.addField("originId", obj.originId) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index 62438cff0..bc20a52e9 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -696,3 +696,34 @@ type ResourcesItem { ## List of resource files. resources: [java.net.URI] } + + +# JVM Environment requests + +type JvmEnvironmentItem { + target: sbt.internal.bsp.BuildTargetIdentifier! + classpath: [java.net.URI]! + jvmOptions: [String]! + workingDirectory: String! + environmentVariables: StringStringMap! +} + +type JvmTestEnvironmentParams { + targets: [sbt.internal.bsp.BuildTargetIdentifier]! + originId: String +} + +type JvmTestEnvironmentResult{ + items: [sbt.internal.bsp.JvmEnvironmentItem]! + originId: String +} + +type JvmRunEnvironmentParams { + targets: [sbt.internal.bsp.BuildTargetIdentifier]! + originId: String +} + +type JvmRunEnvironmentResult{ + items: [sbt.internal.bsp.JvmEnvironmentItem]! + originId: String +} \ No newline at end of file From 5ea12485c629a8db926342e109ba5d42d33f2df8 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Thu, 31 Mar 2022 23:26:41 +0200 Subject: [PATCH 09/42] feat: implement BSP's JVM environment requests --- main/src/main/scala/sbt/Keys.scala | 6 ++ .../internal/server/BuildServerProtocol.scala | 67 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 2270ee573..392812271 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -396,6 +396,7 @@ object Keys { val usePipelining = settingKey[Boolean]("Use subproject pipelining for compilation.").withRank(BSetting) val exportPipelining = settingKey[Boolean]("Product early output so downstream subprojects can do pipelining.").withRank(BSetting) + // BSP keys val bspConfig = taskKey[Unit]("Create or update the BSP connection files").withRank(DSetting) val bspEnabled = SettingKey[Boolean](BasicKeys.bspEnabled) val bspSbtEnabled = settingKey[Boolean]("Should BSP export meta-targets for the SBT build itself?") @@ -418,6 +419,11 @@ object Keys { val bspBuildTargetCleanCache = inputKey[Unit]("Corresponds to buildTarget/cleanCache request").withRank(DTask) val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask) val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask) + + val bspBuildTargetJVMRunEnvironment = inputKey[Unit]("Corresponds to the buildTarget/jvmRunEnvironment request").withRank(DTask) + val bspBuildTargetJVMTestEnvironment = inputKey[Unit]("Corresponds to the buildTarget/jvmTestEnvironment request").withRank(DTask) + val bspBuildTargetJvmEnvironmentItem = taskKey[JvmEnvironmentItem]("Computes JVM environment item").withRank(DTask) + val bspScalaTestClasses = inputKey[Unit]("Corresponds to buildTarget/scalaTestClasses request").withRank(DTask) val bspScalaTestClassesItem = taskKey[Seq[ScalaTestClassesItem]]("").withRank(DTask) val bspScalaMainClasses = inputKey[Unit]("Corresponds to buildTarget/scalaMainClasses request").withRank(DTask) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 1cfae2054..78ffa74f5 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -315,6 +315,31 @@ object BuildServerProtocol { bspBuildTargetCompileItem := bspCompileTask.value, bspBuildTargetRun := bspRunTask.evaluated, bspBuildTargetScalacOptionsItem := scalacOptionsTask.value, + bspBuildTargetJVMRunEnvironment := Def.inputTaskDyn { + val s = state.value + val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) + val workspace = bspFullWorkspace.value.filter(targets) + val filter = ScopeFilter.in(workspace.scopes.values.toList) + Def.task { + val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value + val successfulItems = anyOrThrow(items) + val result = JvmRunEnvironmentResult(successfulItems.toVector, None) + s.respondEvent(result) + } + }.evaluated, + bspBuildTargetJVMTestEnvironment := Def.inputTaskDyn { + val s = state.value + val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) + val workspace = bspFullWorkspace.value.filter(targets) + val filter = ScopeFilter.in(workspace.scopes.values.toList) + Def.task { + val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value + val successfulItems = anyOrThrow(items) + val result = JvmTestEnvironmentResult(successfulItems.toVector, None) + s.respondEvent(result) + } + }.evaluated, + bspBuildTargetJvmEnvironmentItem := jvmEnvironmentItem().value, bspInternalDependencyConfigurations := internalDependencyConfigurationsSetting.value, bspScalaTestClassesItem := scalaTestClassesTask.value, bspScalaMainClassesItem := scalaMainClassesTask.value, @@ -344,6 +369,8 @@ object BuildServerProtocol { final val Run = "buildTarget/run" final val CleanCache = "buildTarget/cleanCache" final val ScalacOptions = "buildTarget/scalacOptions" + final val JvmRunEnvironment = "buildTarget/jvmRunEnvironment" + final val JvmTestEnvironment = "buildTarget/jvmTestEnvironment" final val ScalaTestClasses = "buildTarget/scalaTestClasses" final val ScalaMainClasses = "buildTarget/scalaMainClasses" final val Exit = "build/exit" @@ -443,6 +470,18 @@ object BuildServerProtocol { val command = Keys.bspBuildTargetScalacOptions.key val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == Method.JvmRunEnvironment => + val param = Converter.fromJson[JvmRunEnvironmentParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetJVMRunEnvironment.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) + + case r if r.method == Method.JvmTestEnvironment => + val param = Converter.fromJson[JvmTestEnvironmentParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetJVMTestEnvironment.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == Method.ScalaTestClasses => val param = Converter.fromJson[ScalaTestClassesParams](json(r)).get val targets = param.targets.map(_.uri).mkString(" ") @@ -648,6 +687,33 @@ object BuildServerProtocol { ) } + private def jvmEnvironmentItem(): Initialize[Task[JvmEnvironmentItem]] = Def.taskDyn { + val target = Keys.bspTargetIdentifier.value + val baseDir = Keys.baseDirectory.value.toURI().toString() + val jvmOptions = Keys.javaOptions.value.toVector + val env = envVars.value + val externalDependencyClasspath = Keys.externalDependencyClasspath.value + + val internalDependencyClasspath = for { + (ref, configs) <- bspInternalDependencyConfigurations.value + config <- configs + } yield ref / config / Keys.classDirectory + + Def.task { + val classpath = + internalDependencyClasspath.join.value.distinct ++ + externalDependencyClasspath.map(_.data) + + JvmEnvironmentItem( + target, + classpath.map(_.toURI).toVector, + jvmOptions, + baseDir, + env + ) + } + } + private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = Def.taskDyn { val target = Keys.bspTargetIdentifier.value val scalacOptions = Keys.scalacOptions.value @@ -878,6 +944,7 @@ object BuildServerProtocol { } } + // here private def scalaMainClassesTask: Initialize[Task[ScalaMainClassesItem]] = Def.task { val jvmOptions = Keys.javaOptions.value.toVector val mainClasses = Keys.discoveredMainClasses.value.map( From 19b3ddb8e85988ec779362dd27e5839081ab8b64 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Tue, 5 Apr 2022 12:20:40 +0200 Subject: [PATCH 10/42] refactor: simplify JVm environment requests refactor: extract common logic to the `bspInputTask` --- .../internal/server/BuildServerProtocol.scala | 146 +++++++----------- 1 file changed, 54 insertions(+), 92 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 78ffa74f5..2c7989ce2 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -119,11 +119,7 @@ object BuildServerProtocol { } }.value, // https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request - bspBuildTargetSources := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetSources := bspInputTask { (state, _, workspace, filter) => // run the worker task concurrently Def.task { val items = bspBuildTargetSourcesItem.result.all(filter).value @@ -147,64 +143,48 @@ object BuildServerProtocol { } val successfulItems = anyOrThrow(items ++ buildItems) val result = SourcesResult(successfulItems.toVector) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetSources / aggregate := false, - bspBuildTargetResources := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.Resources, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetResources := bspInputTask { (state, _, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.Resources, state.log) // run the worker task concurrently Def.task { val items = bspBuildTargetResourcesItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = ResourcesResult(successfulItems.toVector) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetResources / aggregate := false, - bspBuildTargetDependencySources := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetDependencySources := bspInputTask { (state, _, workspace, filter) => // run the worker task concurrently Def.task { import sbt.internal.bsp.codec.JsonProtocol._ val items = bspBuildTargetDependencySourcesItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = DependencySourcesResult(successfulItems.toVector) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetDependencySources / aggregate := false, - bspBuildTargetCompile := Def.inputTaskDyn { - val s: State = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.Compile, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetCompile := bspInputTask { (state, _, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.Compile, state.log) Def.task { val statusCodes = Keys.bspBuildTargetCompileItem.result.all(filter).value val aggregatedStatusCode = allOrThrow(statusCodes) match { case Seq() => StatusCode.Success case codes => codes.max } - s.respondEvent(BspCompileResult(None, aggregatedStatusCode)) + state.respondEvent(BspCompileResult(None, aggregatedStatusCode)) } }.evaluated, bspBuildTargetCompile / aggregate := false, bspBuildTargetTest := bspTestTask.evaluated, bspBuildTargetTest / aggregate := false, - bspBuildTargetCleanCache := Def.inputTaskDyn { - val s: State = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.CleanCache, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetCleanCache := bspInputTask { (state, targets, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.CleanCache, state.log) Def.task { val results = Keys.clean.result.all(filter).value val successes = anyOrThrow(results).size @@ -214,18 +194,12 @@ object BuildServerProtocol { // checking that the executed results plus this entry is equal to the total number of targets. // When rebuilding a single module, the root build isn't sent, just the requested targets. val cleaned = successes + workspace.builds.size == targets.size - s.respondEvent(CleanCacheResult(None, cleaned)) + state.respondEvent(CleanCacheResult(None, cleaned)) } }.evaluated, bspBuildTargetCleanCache / aggregate := false, - bspBuildTargetScalacOptions := Def.inputTaskDyn { - val s = state.value - - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) + bspBuildTargetScalacOptions := bspInputTask { (state, _, workspace, filter) => val builds = workspace.builds - - val filter = ScopeFilter.in(workspace.scopes.values.toList) Def.task { val items = bspBuildTargetScalacOptionsItem.result.all(filter).value val appProvider = appConfiguration.value.provider() @@ -246,34 +220,26 @@ object BuildServerProtocol { } val successfulItems = anyOrThrow(items ++ buildItems) val result = ScalacOptionsResult(successfulItems.toVector) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetScalacOptions / aggregate := false, - bspScalaTestClasses := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspScalaTestClasses := bspInputTask { (state, _, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, state.log) Def.task { val items = bspScalaTestClassesItem.result.all(filter).value val successfulItems = anyOrThrow(items).flatten.toVector val result = ScalaTestClassesResult(successfulItems.toVector, None) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, - bspScalaMainClasses := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.ScalaMainClasses, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspScalaMainClasses := bspInputTask { (state, _, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.ScalaMainClasses, state.log) Def.task { val items = bspScalaMainClassesItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = ScalaMainClassesResult(successfulItems.toVector, None) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspScalaMainClasses / aggregate := false @@ -315,28 +281,20 @@ object BuildServerProtocol { bspBuildTargetCompileItem := bspCompileTask.value, bspBuildTargetRun := bspRunTask.evaluated, bspBuildTargetScalacOptionsItem := scalacOptionsTask.value, - bspBuildTargetJVMRunEnvironment := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetJVMRunEnvironment := bspInputTask { (state, _, _, filter) => Def.task { val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = JvmRunEnvironmentResult(successfulItems.toVector, None) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, - bspBuildTargetJVMTestEnvironment := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetJVMTestEnvironment := bspInputTask { (state, _, _, filter) => Def.task { val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = JvmTestEnvironmentResult(successfulItems.toVector, None) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetJvmEnvironmentItem := jvmEnvironmentItem().value, @@ -687,31 +645,36 @@ object BuildServerProtocol { ) } - private def jvmEnvironmentItem(): Initialize[Task[JvmEnvironmentItem]] = Def.taskDyn { - val target = Keys.bspTargetIdentifier.value - val baseDir = Keys.baseDirectory.value.toURI().toString() - val jvmOptions = Keys.javaOptions.value.toVector - val env = envVars.value - val externalDependencyClasspath = Keys.externalDependencyClasspath.value - - val internalDependencyClasspath = for { - (ref, configs) <- bspInternalDependencyConfigurations.value - config <- configs - } yield ref / config / Keys.classDirectory - - Def.task { - val classpath = - internalDependencyClasspath.join.value.distinct ++ - externalDependencyClasspath.map(_.data) - - JvmEnvironmentItem( - target, - classpath.map(_.toURI).toVector, - jvmOptions, - baseDir, - env - ) + private def bspInputTask[T]( + taskImpl: ( + State, + Seq[BuildTargetIdentifier], + BspFullWorkspace, + ScopeFilter + ) => Def.Initialize[Task[T]] + ): Def.Initialize[InputTask[T]] = + Def.inputTaskDyn { + val s = state.value + val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) + val workspace: BspFullWorkspace = bspFullWorkspace.value.filter(targets) + val filter = ScopeFilter.in(workspace.scopes.values.toList) + taskImpl(s, targets, workspace, filter) } + + private def jvmEnvironmentItem(): Initialize[Task[JvmEnvironmentItem]] = Def.task { + val target = Keys.bspTargetIdentifier.value + val classpath = Keys.fullClasspath.value.map(_.data.toURI).toVector + val jvmOptions = Keys.javaOptions.value.toVector + val baseDir = Keys.baseDirectory.value.toURI().toString() + val env = envVars.value + + JvmEnvironmentItem( + target, + classpath, + jvmOptions, + baseDir, + env + ) } private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = Def.taskDyn { @@ -944,7 +907,6 @@ object BuildServerProtocol { } } - // here private def scalaMainClassesTask: Initialize[Task[ScalaMainClassesItem]] = Def.task { val jvmOptions = Keys.javaOptions.value.toVector val mainClasses = Keys.discoveredMainClasses.value.map( From 77355134d0e63d4e756b4c09c8cd85a440c47b1a Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Tue, 5 Apr 2022 19:29:00 +0200 Subject: [PATCH 11/42] tests: run&test environment requests --- .../src/server-test/buildserver/build.sbt | 8 +++- .../test/scala/testpkg/BuildServerTest.scala | 45 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/server-test/src/server-test/buildserver/build.sbt b/server-test/src/server-test/buildserver/build.sbt index 52691a0a5..9d2de35fc 100644 --- a/server-test/src/server-test/buildserver/build.sbt +++ b/server-test/src/server-test/buildserver/build.sbt @@ -1,10 +1,16 @@ -ThisBuild / scalaVersion := "2.13.1" +ThisBuild / scalaVersion := "2.13.8" Global / serverLog / logLevel := Level.Debug lazy val runAndTest = project.in(file("run-and-test")) .settings( + libraryDependencies += "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "2.13.11", libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % "test", + Compile / javaOptions := Vector("Xmx256M"), + Compile / envVars := Map("KEY" -> "VALUE"), + + Test / javaOptions := Vector("Xmx512M"), + Test / envVars := Map("KEY_TEST" -> "VALUE_TEST"), ) .dependsOn(util) diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index a6d900a16..817b0e6ad 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -157,7 +157,7 @@ object BuildServerTest extends AbstractServerTest { assert(processing("buildTarget/scalacOptions")) assert(svr.waitForString(10.seconds) { s => (s contains """"id":"40"""") && - (s contains "scala-library-2.13.1.jar") + (s contains "scala-library-2.13.8.jar") }) } @@ -311,6 +311,49 @@ object BuildServerTest extends AbstractServerTest { }) } + test("buildTarget/jvmRunEnvironment") { _ => + val buildTarget = buildTargetUri("runAndTest", "Compile") + svr.sendJsonRpc( + s"""|{ "jsonrpc": "2.0", + | "id": "97", + | "method": "buildTarget/jvmRunEnvironment", + | "params": { "targets": [{ "uri": "$buildTarget" }] } + |}""".stripMargin + ) + assert(processing("buildTarget/jvmRunEnvironment")) + assert { + svr.waitForString(10.seconds) { s => + (s contains """"id":"97"""") && + (s contains "jsoniter-scala-core_2.13-2.13.11.jar") && // compile dependency + (s contains "\"jvmOptions\":[\"Xmx256M\"]") && + (s contains "\"environmentVariables\":{\"KEY\":\"VALUE\"}") && + (s contains "/buildserver/run-and-test/") // working directory + } + } + } + + test("buildTarget/jvmTestEnvironment") { _ => + val buildTarget = buildTargetUri("runAndTest", "Test") + svr.sendJsonRpc( + s"""|{ "jsonrpc": "2.0", + | "id": "98", + | "method": "buildTarget/jvmTestEnvironment", + | "params": { "targets": [{ "uri": "$buildTarget" }] } + |}""".stripMargin + ) + assert(processing("buildTarget/jvmTestEnvironment")) + assert { + svr.waitForString(10.seconds) { s => + (s contains """"id":"98"""") && + // test depends on compile so it has dependencies from both + (s contains "jsoniter-scala-core_2.13-2.13.11.jar") && // compile dependency + (s contains "scalatest_2.13-3.0.8.jar") && // test dependency + (s contains "\"jvmOptions\":[\"Xmx512M\"]") && + (s contains "\"environmentVariables\":{\"KEY_TEST\":\"VALUE_TEST\"}") + } + } + } + test("buildTarget/scalaTestClasses") { _ => val buildTarget = buildTargetUri("runAndTest", "Test") val badBuildTarget = buildTargetUri("badBuildTarget", "Test") From d3ee1d5942aaa37026da1856a129d44f6cc813bb Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 9 Apr 2022 15:12:20 -0700 Subject: [PATCH 12/42] Move on-termination test --- sbt-app/src/sbt-test/watch/{on-termination => on-error}/build.sbt | 0 .../watch/{on-termination => on-error}/project/Build.scala | 0 sbt-app/src/sbt-test/watch/{on-termination => on-error}/test | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename sbt-app/src/sbt-test/watch/{on-termination => on-error}/build.sbt (100%) rename sbt-app/src/sbt-test/watch/{on-termination => on-error}/project/Build.scala (100%) rename sbt-app/src/sbt-test/watch/{on-termination => on-error}/test (100%) diff --git a/sbt-app/src/sbt-test/watch/on-termination/build.sbt b/sbt-app/src/sbt-test/watch/on-error/build.sbt similarity index 100% rename from sbt-app/src/sbt-test/watch/on-termination/build.sbt rename to sbt-app/src/sbt-test/watch/on-error/build.sbt diff --git a/sbt-app/src/sbt-test/watch/on-termination/project/Build.scala b/sbt-app/src/sbt-test/watch/on-error/project/Build.scala similarity index 100% rename from sbt-app/src/sbt-test/watch/on-termination/project/Build.scala rename to sbt-app/src/sbt-test/watch/on-error/project/Build.scala diff --git a/sbt-app/src/sbt-test/watch/on-termination/test b/sbt-app/src/sbt-test/watch/on-error/test similarity index 100% rename from sbt-app/src/sbt-test/watch/on-termination/test rename to sbt-app/src/sbt-test/watch/on-error/test From 379503a894abc60e05d73c412417778b6228ec6e Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 9 Apr 2022 15:05:54 -0700 Subject: [PATCH 13/42] Restore watchOnTermination At some point the watchOnTermination callback stopped working. I'm not exactly sure how or why that happened but it is fairly straightforward to restore. The one tricky thing was that the callback has the signature (Watch.Action, _, _, _) => State, which requires propagating the action to the failWatch command. The easiest way to do this was to add a mutable field to the ContinuousState. This is rather ugly and reflects some poor design choices but a more comprehensive refactor is out of the scope of this fix. This commit adds a scripted test that ensures that the callback is invoked both in the successful and unsuccessful watch cases. In each case the callback deletes a file and we ensure that the file is indeed absent after the watch exits. --- .../main/scala/sbt/internal/Continuous.scala | 68 +++++++++++++------ .../src/sbt-test/watch/on-termination/bar.txt | 0 .../sbt-test/watch/on-termination/build.sbt | 15 ++++ .../src/sbt-test/watch/on-termination/foo.txt | 0 .../src/sbt-test/watch/on-termination/test | 8 +++ 5 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 sbt-app/src/sbt-test/watch/on-termination/bar.txt create mode 100644 sbt-app/src/sbt-test/watch/on-termination/build.sbt create mode 100644 sbt-app/src/sbt-test/watch/on-termination/foo.txt create mode 100644 sbt-app/src/sbt-test/watch/on-termination/test diff --git a/main/src/main/scala/sbt/internal/Continuous.scala b/main/src/main/scala/sbt/internal/Continuous.scala index a95e21ea1..ea1b5134f 100644 --- a/main/src/main/scala/sbt/internal/Continuous.scala +++ b/main/src/main/scala/sbt/internal/Continuous.scala @@ -1128,7 +1128,28 @@ private[sbt] object Continuous extends DeprecatedContinuous { val callbacks: Callbacks, val dynamicInputs: mutable.Set[DynamicInput], val pending: Boolean, + var failAction: Option[Watch.Action], ) { + def this( + count: Int, + commands: Seq[String], + beforeCommandImpl: (State, mutable.Set[DynamicInput]) => State, + afterCommand: State => State, + afterWatch: State => State, + callbacks: Callbacks, + dynamicInputs: mutable.Set[DynamicInput], + pending: Boolean, + ) = this( + count, + commands, + beforeCommandImpl, + afterCommand, + afterWatch, + callbacks, + dynamicInputs, + pending, + None + ) def beforeCommand(state: State): State = beforeCommandImpl(state, dynamicInputs) def incremented: ContinuousState = withCount(count + 1) def withPending(p: Boolean) = @@ -1323,7 +1344,8 @@ private[sbt] object ContinuousCommands { case Watch.Prompt => stop.map(_ :: s"$PromptChannel ${channel.name}" :: Nil mkString ";") case Watch.Run(commands) => stop.map(_ +: commands.map(_.commandLine).filter(_.nonEmpty) mkString "; ") - case Watch.HandleError(_) => + case a @ Watch.HandleError(_) => + cs.failAction = Some(a) stop.map(_ :: s"$failWatch ${channel.name}" :: Nil mkString "; ") case _ => stop } @@ -1353,27 +1375,31 @@ private[sbt] object ContinuousCommands { } cs.afterCommand(postState) } - private[sbt] val stopWatchCommand = watchCommand(stopWatch) { (channel, state) => - state.get(watchStates).flatMap(_.get(channel)) match { - case Some(cs) => - val afterWatchState = cs.afterWatch(state) - cs.callbacks.onExit() - StandardMain.exchange - .channelForName(channel) - .foreach { c => - c.terminal.setPrompt(Prompt.Pending) - c.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel)))) + private[this] val exitWatchShared = (error: Boolean) => + (channel: String, state: State) => + state.get(watchStates).flatMap(_.get(channel)) match { + case Some(cs) => + val afterWatchState = cs.afterWatch(state) + cs.callbacks.onExit() + StandardMain.exchange + .channelForName(channel) + .foreach { c => + c.terminal.setPrompt(Prompt.Pending) + c.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel)))) + } + val newState = afterWatchState.get(watchStates) match { + case None => afterWatchState + case Some(w) => afterWatchState.put(watchStates, w - channel) } - afterWatchState.get(watchStates) match { - case None => afterWatchState - case Some(w) => afterWatchState.put(watchStates, w - channel) - } - case _ => state - } - } - private[sbt] val failWatchCommand = watchCommand(failWatch) { (channel, state) => - state.fail - } + val commands = cs.commands.mkString("; ") + val count = cs.count + val action = cs.failAction.getOrElse(Watch.CancelWatch) + val st = cs.callbacks.onTermination(action, commands, count, newState) + if (error) st.fail else st + case _ => if (error) state.fail else state + } + private[sbt] val stopWatchCommand = watchCommand(stopWatch)(exitWatchShared(false)) + private[sbt] val failWatchCommand = watchCommand(failWatch)(exitWatchShared(true)) /* * Creates a FileTreeRepository where it is safe to call close without inadvertently cancelling * still active watches. diff --git a/sbt-app/src/sbt-test/watch/on-termination/bar.txt b/sbt-app/src/sbt-test/watch/on-termination/bar.txt new file mode 100644 index 000000000..e69de29bb diff --git a/sbt-app/src/sbt-test/watch/on-termination/build.sbt b/sbt-app/src/sbt-test/watch/on-termination/build.sbt new file mode 100644 index 000000000..798f18016 --- /dev/null +++ b/sbt-app/src/sbt-test/watch/on-termination/build.sbt @@ -0,0 +1,15 @@ +watchOnIteration := { (count, project, commands) => + Watch.CancelWatch +} +watchOnTermination := { (action, count, command, state) => + action match { + case Watch.CancelWatch => + java.nio.file.Files.delete(java.nio.file.Paths.get("foo.txt")) + case Watch.HandleError(e) => + if (e.getMessage == "fail") + java.nio.file.Files.delete(java.nio.file.Paths.get("bar.txt")) + else + throw new IllegalStateException("unexpected error") + } + state +} diff --git a/sbt-app/src/sbt-test/watch/on-termination/foo.txt b/sbt-app/src/sbt-test/watch/on-termination/foo.txt new file mode 100644 index 000000000..e69de29bb diff --git a/sbt-app/src/sbt-test/watch/on-termination/test b/sbt-app/src/sbt-test/watch/on-termination/test new file mode 100644 index 000000000..1634ee847 --- /dev/null +++ b/sbt-app/src/sbt-test/watch/on-termination/test @@ -0,0 +1,8 @@ +$ exists foo.txt +> ~compile +$ absent foo.txt +> set watchOnIteration := { (_, _, _) => new Watch.HandleError(new IllegalStateException("fail")) } +$ exists bar.txt +-> ~compile +$ absent bar.txt + From 97005df612b0b0f225600e3262731b3c8a7ae1d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 04:02:44 +0000 Subject: [PATCH 14/42] Bump actions/setup-java from 2 to 3 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 2 to 3. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49b534330..1215d9777 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,7 +80,7 @@ jobs: ref: develop path: zinc - name: Setup JDK - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: "${{ matrix.distribution }}" java-version: "${{ matrix.java }}" From f90b09f1ee3ffd46100773d302d7aff60369f741 Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Tue, 12 Apr 2022 10:50:28 +0200 Subject: [PATCH 15/42] feat: update Problem to account for related information and code This PR makes changes to the existing `xsbti.Problem` to account for an optional diagnostic code that the compiler can return for a given diagnostic and also related information. Given a piece of code like: ```scala try {} ``` You'll receive the following: ``` -- [E002] Syntax Warning: /Users/ckipp/Documents/scala-workspace/dotty-error-index/examples/002_EmptyCatchAndFinallyBlockID.scala:3:2 3 | try {} | ^^^^^^ | A try without catch or finally is equivalent to putting | its body in a block; no exceptions are handled. ``` The `E002` here is the actual code. Right now there would be no description. Some diagnostics have multiple positions that they need to represent. You can see an example of this [here](lampepfl/dotty#14002) in Dotty with the use of inlining. Instead of needing to rely on including all of that information in the diagnostic message it can now be extracted out into a `DiagnosticRelatedInformation`. These changes reference the conversation in #6868 --- .../src/main/java/xsbti/DiagnosticCode.java | 23 +++++++++++++++++++ .../xsbti/DiagnosticRelatedInformation.java | 20 ++++++++++++++++ .../src/main/java/xsbti/Problem.java | 22 ++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 internal/util-interface/src/main/java/xsbti/DiagnosticCode.java create mode 100644 internal/util-interface/src/main/java/xsbti/DiagnosticRelatedInformation.java diff --git a/internal/util-interface/src/main/java/xsbti/DiagnosticCode.java b/internal/util-interface/src/main/java/xsbti/DiagnosticCode.java new file mode 100644 index 000000000..6633e2b4e --- /dev/null +++ b/internal/util-interface/src/main/java/xsbti/DiagnosticCode.java @@ -0,0 +1,23 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package xsbti; + +import java.util.Optional; + +/** + * A DiagnosticCode is a unique identifier that the compiler can associate with a diagnostic. This + * is useful for tools to be able to quickly identify what diagnostic is being reported without + * having to rely on parsing the actual diagnostic message, which might not be stable. + */ +public interface DiagnosticCode { + /** The unique code. This is typically in the format of E000 */ + String code(); + + /** Possible explanation to explain the meaning of the code */ + Optional explanation(); +} diff --git a/internal/util-interface/src/main/java/xsbti/DiagnosticRelatedInformation.java b/internal/util-interface/src/main/java/xsbti/DiagnosticRelatedInformation.java new file mode 100644 index 000000000..786cecc52 --- /dev/null +++ b/internal/util-interface/src/main/java/xsbti/DiagnosticRelatedInformation.java @@ -0,0 +1,20 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package xsbti; + +/** + * Related information for a given diagnostic. At times this can be another place in your code + * contributing to the diagnostic or just relevant code relating to the diagnostic. + */ +public interface DiagnosticRelatedInformation { + /** Position of the related information */ + Position position(); + + /** Message indicating why this related information is attached to the diagnostic. */ + String message(); +} diff --git a/internal/util-interface/src/main/java/xsbti/Problem.java b/internal/util-interface/src/main/java/xsbti/Problem.java index 78c9145a3..e63a95b64 100644 --- a/internal/util-interface/src/main/java/xsbti/Problem.java +++ b/internal/util-interface/src/main/java/xsbti/Problem.java @@ -7,6 +7,8 @@ package xsbti; +import java.util.Collections; +import java.util.List; import java.util.Optional; public interface Problem { @@ -26,4 +28,24 @@ public interface Problem { default Optional rendered() { return Optional.empty(); } + + /** + * The unique code attached to the diagnostic being reported. + * + *

NOTE: To avoid breaking compatibility we provide a default to account for older Scala + * versions that do not have codes. + */ + default Optional diagnosticCode() { + return Optional.empty(); + } + + /** + * The possible releated information for the diagnostic being reported. + * + *

NOTE: To avoid breaking compatibility we provide a default to account for older Scala + * versions that do not have the concept of "related information". + */ + default List diagnosticRelatedInforamation() { + return Collections.emptyList(); + } } From 85efc87879d596cd519d56bc3e5b1bce3ca4f858 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Thu, 31 Mar 2022 12:28:15 +0200 Subject: [PATCH 16/42] feat: generate JVM environment requests --- .../sbt/internal/bsp/JvmEnvironmentItem.scala | 48 +++++++++++++++++++ .../bsp/JvmRunEnvironmentParams.scala | 40 ++++++++++++++++ .../bsp/JvmRunEnvironmentResult.scala | 40 ++++++++++++++++ .../bsp/JvmTestEnvironmentParams.scala | 40 ++++++++++++++++ .../bsp/JvmTestEnvironmentResult.scala | 40 ++++++++++++++++ .../sbt/internal/bsp/codec/JsonProtocol.scala | 5 ++ .../bsp/codec/JvmEnvironmentItemFormats.scala | 35 ++++++++++++++ .../JvmRunEnvironmentParamsFormats.scala | 29 +++++++++++ .../JvmRunEnvironmentResultFormats.scala | 29 +++++++++++ .../JvmTestEnvironmentParamsFormats.scala | 29 +++++++++++ .../JvmTestEnvironmentResultFormats.scala | 29 +++++++++++ protocol/src/main/contraband/bsp.contra | 31 ++++++++++++ 12 files changed, 395 insertions(+) create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmEnvironmentItem.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentResult.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentResult.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmEnvironmentItemFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentResultFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentResultFormats.scala diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmEnvironmentItem.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmEnvironmentItem.scala new file mode 100644 index 000000000..6e3d6b895 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmEnvironmentItem.scala @@ -0,0 +1,48 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmEnvironmentItem private ( + val target: sbt.internal.bsp.BuildTargetIdentifier, + val classpath: Vector[java.net.URI], + val jvmOptions: Vector[String], + val workingDirectory: String, + val environmentVariables: scala.collection.immutable.Map[String, String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmEnvironmentItem => (this.target == x.target) && (this.classpath == x.classpath) && (this.jvmOptions == x.jvmOptions) && (this.workingDirectory == x.workingDirectory) && (this.environmentVariables == x.environmentVariables) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmEnvironmentItem".##) + target.##) + classpath.##) + jvmOptions.##) + workingDirectory.##) + environmentVariables.##) + } + override def toString: String = { + "JvmEnvironmentItem(" + target + ", " + classpath + ", " + jvmOptions + ", " + workingDirectory + ", " + environmentVariables + ")" + } + private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, classpath: Vector[java.net.URI] = classpath, jvmOptions: Vector[String] = jvmOptions, workingDirectory: String = workingDirectory, environmentVariables: scala.collection.immutable.Map[String, String] = environmentVariables): JvmEnvironmentItem = { + new JvmEnvironmentItem(target, classpath, jvmOptions, workingDirectory, environmentVariables) + } + def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): JvmEnvironmentItem = { + copy(target = target) + } + def withClasspath(classpath: Vector[java.net.URI]): JvmEnvironmentItem = { + copy(classpath = classpath) + } + def withJvmOptions(jvmOptions: Vector[String]): JvmEnvironmentItem = { + copy(jvmOptions = jvmOptions) + } + def withWorkingDirectory(workingDirectory: String): JvmEnvironmentItem = { + copy(workingDirectory = workingDirectory) + } + def withEnvironmentVariables(environmentVariables: scala.collection.immutable.Map[String, String]): JvmEnvironmentItem = { + copy(environmentVariables = environmentVariables) + } +} +object JvmEnvironmentItem { + + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, classpath: Vector[java.net.URI], jvmOptions: Vector[String], workingDirectory: String, environmentVariables: scala.collection.immutable.Map[String, String]): JvmEnvironmentItem = new JvmEnvironmentItem(target, classpath, jvmOptions, workingDirectory, environmentVariables) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentParams.scala new file mode 100644 index 000000000..f96b6a26e --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentParams.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmRunEnvironmentParams private ( + val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], + val originId: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmRunEnvironmentParams => (this.targets == x.targets) && (this.originId == x.originId) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmRunEnvironmentParams".##) + targets.##) + originId.##) + } + override def toString: String = { + "JvmRunEnvironmentParams(" + targets + ", " + originId + ")" + } + private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier] = targets, originId: Option[String] = originId): JvmRunEnvironmentParams = { + new JvmRunEnvironmentParams(targets, originId) + } + def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): JvmRunEnvironmentParams = { + copy(targets = targets) + } + def withOriginId(originId: Option[String]): JvmRunEnvironmentParams = { + copy(originId = originId) + } + def withOriginId(originId: String): JvmRunEnvironmentParams = { + copy(originId = Option(originId)) + } +} +object JvmRunEnvironmentParams { + + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: Option[String]): JvmRunEnvironmentParams = new JvmRunEnvironmentParams(targets, originId) + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: String): JvmRunEnvironmentParams = new JvmRunEnvironmentParams(targets, Option(originId)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentResult.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentResult.scala new file mode 100644 index 000000000..47ebb14ea --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmRunEnvironmentResult.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmRunEnvironmentResult private ( + val items: Vector[sbt.internal.bsp.JvmEnvironmentItem], + val originId: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmRunEnvironmentResult => (this.items == x.items) && (this.originId == x.originId) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmRunEnvironmentResult".##) + items.##) + originId.##) + } + override def toString: String = { + "JvmRunEnvironmentResult(" + items + ", " + originId + ")" + } + private[this] def copy(items: Vector[sbt.internal.bsp.JvmEnvironmentItem] = items, originId: Option[String] = originId): JvmRunEnvironmentResult = { + new JvmRunEnvironmentResult(items, originId) + } + def withItems(items: Vector[sbt.internal.bsp.JvmEnvironmentItem]): JvmRunEnvironmentResult = { + copy(items = items) + } + def withOriginId(originId: Option[String]): JvmRunEnvironmentResult = { + copy(originId = originId) + } + def withOriginId(originId: String): JvmRunEnvironmentResult = { + copy(originId = Option(originId)) + } +} +object JvmRunEnvironmentResult { + + def apply(items: Vector[sbt.internal.bsp.JvmEnvironmentItem], originId: Option[String]): JvmRunEnvironmentResult = new JvmRunEnvironmentResult(items, originId) + def apply(items: Vector[sbt.internal.bsp.JvmEnvironmentItem], originId: String): JvmRunEnvironmentResult = new JvmRunEnvironmentResult(items, Option(originId)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentParams.scala new file mode 100644 index 000000000..dd49a1474 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentParams.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmTestEnvironmentParams private ( + val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], + val originId: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmTestEnvironmentParams => (this.targets == x.targets) && (this.originId == x.originId) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmTestEnvironmentParams".##) + targets.##) + originId.##) + } + override def toString: String = { + "JvmTestEnvironmentParams(" + targets + ", " + originId + ")" + } + private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier] = targets, originId: Option[String] = originId): JvmTestEnvironmentParams = { + new JvmTestEnvironmentParams(targets, originId) + } + def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): JvmTestEnvironmentParams = { + copy(targets = targets) + } + def withOriginId(originId: Option[String]): JvmTestEnvironmentParams = { + copy(originId = originId) + } + def withOriginId(originId: String): JvmTestEnvironmentParams = { + copy(originId = Option(originId)) + } +} +object JvmTestEnvironmentParams { + + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: Option[String]): JvmTestEnvironmentParams = new JvmTestEnvironmentParams(targets, originId) + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier], originId: String): JvmTestEnvironmentParams = new JvmTestEnvironmentParams(targets, Option(originId)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentResult.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentResult.scala new file mode 100644 index 000000000..54fd64253 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/JvmTestEnvironmentResult.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class JvmTestEnvironmentResult private ( + val items: Vector[sbt.internal.bsp.JvmEnvironmentItem], + val originId: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: JvmTestEnvironmentResult => (this.items == x.items) && (this.originId == x.originId) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.JvmTestEnvironmentResult".##) + items.##) + originId.##) + } + override def toString: String = { + "JvmTestEnvironmentResult(" + items + ", " + originId + ")" + } + private[this] def copy(items: Vector[sbt.internal.bsp.JvmEnvironmentItem] = items, originId: Option[String] = originId): JvmTestEnvironmentResult = { + new JvmTestEnvironmentResult(items, originId) + } + def withItems(items: Vector[sbt.internal.bsp.JvmEnvironmentItem]): JvmTestEnvironmentResult = { + copy(items = items) + } + def withOriginId(originId: Option[String]): JvmTestEnvironmentResult = { + copy(originId = originId) + } + def withOriginId(originId: String): JvmTestEnvironmentResult = { + copy(originId = Option(originId)) + } +} +object JvmTestEnvironmentResult { + + def apply(items: Vector[sbt.internal.bsp.JvmEnvironmentItem], originId: Option[String]): JvmTestEnvironmentResult = new JvmTestEnvironmentResult(items, originId) + def apply(items: Vector[sbt.internal.bsp.JvmEnvironmentItem], originId: String): JvmTestEnvironmentResult = new JvmTestEnvironmentResult(items, Option(originId)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala index c55580da2..7d26ae037 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala @@ -63,4 +63,9 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.bsp.codec.ResourcesParamsFormats with sbt.internal.bsp.codec.ResourcesItemFormats with sbt.internal.bsp.codec.ResourcesResultFormats + with sbt.internal.bsp.codec.JvmEnvironmentItemFormats + with sbt.internal.bsp.codec.JvmTestEnvironmentParamsFormats + with sbt.internal.bsp.codec.JvmTestEnvironmentResultFormats + with sbt.internal.bsp.codec.JvmRunEnvironmentParamsFormats + with sbt.internal.bsp.codec.JvmRunEnvironmentResultFormats object JsonProtocol extends JsonProtocol \ No newline at end of file diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmEnvironmentItemFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmEnvironmentItemFormats.scala new file mode 100644 index 000000000..c1ecd6ee1 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmEnvironmentItemFormats.scala @@ -0,0 +1,35 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmEnvironmentItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmEnvironmentItemFormat: JsonFormat[sbt.internal.bsp.JvmEnvironmentItem] = new JsonFormat[sbt.internal.bsp.JvmEnvironmentItem] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmEnvironmentItem = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target") + val classpath = unbuilder.readField[Vector[java.net.URI]]("classpath") + val jvmOptions = unbuilder.readField[Vector[String]]("jvmOptions") + val workingDirectory = unbuilder.readField[String]("workingDirectory") + val environmentVariables = unbuilder.readField[scala.collection.immutable.Map[String, String]]("environmentVariables") + unbuilder.endObject() + sbt.internal.bsp.JvmEnvironmentItem(target, classpath, jvmOptions, workingDirectory, environmentVariables) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmEnvironmentItem, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("target", obj.target) + builder.addField("classpath", obj.classpath) + builder.addField("jvmOptions", obj.jvmOptions) + builder.addField("workingDirectory", obj.workingDirectory) + builder.addField("environmentVariables", obj.environmentVariables) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentParamsFormats.scala new file mode 100644 index 000000000..b1c5ce3e4 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentParamsFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmRunEnvironmentParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmRunEnvironmentParamsFormat: JsonFormat[sbt.internal.bsp.JvmRunEnvironmentParams] = new JsonFormat[sbt.internal.bsp.JvmRunEnvironmentParams] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmRunEnvironmentParams = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets") + val originId = unbuilder.readField[Option[String]]("originId") + unbuilder.endObject() + sbt.internal.bsp.JvmRunEnvironmentParams(targets, originId) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmRunEnvironmentParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("targets", obj.targets) + builder.addField("originId", obj.originId) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentResultFormats.scala new file mode 100644 index 000000000..6a9d40a5e --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmRunEnvironmentResultFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmRunEnvironmentResultFormats { self: sbt.internal.bsp.codec.JvmEnvironmentItemFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmRunEnvironmentResultFormat: JsonFormat[sbt.internal.bsp.JvmRunEnvironmentResult] = new JsonFormat[sbt.internal.bsp.JvmRunEnvironmentResult] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmRunEnvironmentResult = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val items = unbuilder.readField[Vector[sbt.internal.bsp.JvmEnvironmentItem]]("items") + val originId = unbuilder.readField[Option[String]]("originId") + unbuilder.endObject() + sbt.internal.bsp.JvmRunEnvironmentResult(items, originId) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmRunEnvironmentResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("items", obj.items) + builder.addField("originId", obj.originId) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentParamsFormats.scala new file mode 100644 index 000000000..b02e289f2 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentParamsFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmTestEnvironmentParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmTestEnvironmentParamsFormat: JsonFormat[sbt.internal.bsp.JvmTestEnvironmentParams] = new JsonFormat[sbt.internal.bsp.JvmTestEnvironmentParams] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmTestEnvironmentParams = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets") + val originId = unbuilder.readField[Option[String]]("originId") + unbuilder.endObject() + sbt.internal.bsp.JvmTestEnvironmentParams(targets, originId) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmTestEnvironmentParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("targets", obj.targets) + builder.addField("originId", obj.originId) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentResultFormats.scala new file mode 100644 index 000000000..cd9c9d297 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JvmTestEnvironmentResultFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait JvmTestEnvironmentResultFormats { self: sbt.internal.bsp.codec.JvmEnvironmentItemFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val JvmTestEnvironmentResultFormat: JsonFormat[sbt.internal.bsp.JvmTestEnvironmentResult] = new JsonFormat[sbt.internal.bsp.JvmTestEnvironmentResult] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JvmTestEnvironmentResult = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val items = unbuilder.readField[Vector[sbt.internal.bsp.JvmEnvironmentItem]]("items") + val originId = unbuilder.readField[Option[String]]("originId") + unbuilder.endObject() + sbt.internal.bsp.JvmTestEnvironmentResult(items, originId) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.JvmTestEnvironmentResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("items", obj.items) + builder.addField("originId", obj.originId) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index 62438cff0..bc20a52e9 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -696,3 +696,34 @@ type ResourcesItem { ## List of resource files. resources: [java.net.URI] } + + +# JVM Environment requests + +type JvmEnvironmentItem { + target: sbt.internal.bsp.BuildTargetIdentifier! + classpath: [java.net.URI]! + jvmOptions: [String]! + workingDirectory: String! + environmentVariables: StringStringMap! +} + +type JvmTestEnvironmentParams { + targets: [sbt.internal.bsp.BuildTargetIdentifier]! + originId: String +} + +type JvmTestEnvironmentResult{ + items: [sbt.internal.bsp.JvmEnvironmentItem]! + originId: String +} + +type JvmRunEnvironmentParams { + targets: [sbt.internal.bsp.BuildTargetIdentifier]! + originId: String +} + +type JvmRunEnvironmentResult{ + items: [sbt.internal.bsp.JvmEnvironmentItem]! + originId: String +} \ No newline at end of file From ad4113caebc7e8486443d0e06ea10be2c80faba6 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Thu, 31 Mar 2022 23:26:41 +0200 Subject: [PATCH 17/42] feat: implement BSP's JVM environment requests --- main/src/main/scala/sbt/Keys.scala | 6 ++ .../internal/server/BuildServerProtocol.scala | 67 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index a4fee0b85..68332cd13 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -398,6 +398,7 @@ object Keys { val usePipelining = settingKey[Boolean]("Use subproject pipelining for compilation.").withRank(BSetting) val exportPipelining = settingKey[Boolean]("Product early output so downstream subprojects can do pipelining.").withRank(BSetting) + // BSP keys val bspConfig = taskKey[Unit]("Create or update the BSP connection files").withRank(DSetting) val bspEnabled = SettingKey[Boolean](BasicKeys.bspEnabled) val bspSbtEnabled = settingKey[Boolean]("Should BSP export meta-targets for the SBT build itself?") @@ -420,6 +421,11 @@ object Keys { val bspBuildTargetCleanCache = inputKey[Unit]("Corresponds to buildTarget/cleanCache request").withRank(DTask) val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask) val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask) + + val bspBuildTargetJVMRunEnvironment = inputKey[Unit]("Corresponds to the buildTarget/jvmRunEnvironment request").withRank(DTask) + val bspBuildTargetJVMTestEnvironment = inputKey[Unit]("Corresponds to the buildTarget/jvmTestEnvironment request").withRank(DTask) + val bspBuildTargetJvmEnvironmentItem = taskKey[JvmEnvironmentItem]("Computes JVM environment item").withRank(DTask) + val bspScalaTestClasses = inputKey[Unit]("Corresponds to buildTarget/scalaTestClasses request").withRank(DTask) val bspScalaTestClassesItem = taskKey[Seq[ScalaTestClassesItem]]("").withRank(DTask) val bspScalaMainClasses = inputKey[Unit]("Corresponds to buildTarget/scalaMainClasses request").withRank(DTask) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 1cfae2054..78ffa74f5 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -315,6 +315,31 @@ object BuildServerProtocol { bspBuildTargetCompileItem := bspCompileTask.value, bspBuildTargetRun := bspRunTask.evaluated, bspBuildTargetScalacOptionsItem := scalacOptionsTask.value, + bspBuildTargetJVMRunEnvironment := Def.inputTaskDyn { + val s = state.value + val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) + val workspace = bspFullWorkspace.value.filter(targets) + val filter = ScopeFilter.in(workspace.scopes.values.toList) + Def.task { + val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value + val successfulItems = anyOrThrow(items) + val result = JvmRunEnvironmentResult(successfulItems.toVector, None) + s.respondEvent(result) + } + }.evaluated, + bspBuildTargetJVMTestEnvironment := Def.inputTaskDyn { + val s = state.value + val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) + val workspace = bspFullWorkspace.value.filter(targets) + val filter = ScopeFilter.in(workspace.scopes.values.toList) + Def.task { + val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value + val successfulItems = anyOrThrow(items) + val result = JvmTestEnvironmentResult(successfulItems.toVector, None) + s.respondEvent(result) + } + }.evaluated, + bspBuildTargetJvmEnvironmentItem := jvmEnvironmentItem().value, bspInternalDependencyConfigurations := internalDependencyConfigurationsSetting.value, bspScalaTestClassesItem := scalaTestClassesTask.value, bspScalaMainClassesItem := scalaMainClassesTask.value, @@ -344,6 +369,8 @@ object BuildServerProtocol { final val Run = "buildTarget/run" final val CleanCache = "buildTarget/cleanCache" final val ScalacOptions = "buildTarget/scalacOptions" + final val JvmRunEnvironment = "buildTarget/jvmRunEnvironment" + final val JvmTestEnvironment = "buildTarget/jvmTestEnvironment" final val ScalaTestClasses = "buildTarget/scalaTestClasses" final val ScalaMainClasses = "buildTarget/scalaMainClasses" final val Exit = "build/exit" @@ -443,6 +470,18 @@ object BuildServerProtocol { val command = Keys.bspBuildTargetScalacOptions.key val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == Method.JvmRunEnvironment => + val param = Converter.fromJson[JvmRunEnvironmentParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetJVMRunEnvironment.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) + + case r if r.method == Method.JvmTestEnvironment => + val param = Converter.fromJson[JvmTestEnvironmentParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetJVMTestEnvironment.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == Method.ScalaTestClasses => val param = Converter.fromJson[ScalaTestClassesParams](json(r)).get val targets = param.targets.map(_.uri).mkString(" ") @@ -648,6 +687,33 @@ object BuildServerProtocol { ) } + private def jvmEnvironmentItem(): Initialize[Task[JvmEnvironmentItem]] = Def.taskDyn { + val target = Keys.bspTargetIdentifier.value + val baseDir = Keys.baseDirectory.value.toURI().toString() + val jvmOptions = Keys.javaOptions.value.toVector + val env = envVars.value + val externalDependencyClasspath = Keys.externalDependencyClasspath.value + + val internalDependencyClasspath = for { + (ref, configs) <- bspInternalDependencyConfigurations.value + config <- configs + } yield ref / config / Keys.classDirectory + + Def.task { + val classpath = + internalDependencyClasspath.join.value.distinct ++ + externalDependencyClasspath.map(_.data) + + JvmEnvironmentItem( + target, + classpath.map(_.toURI).toVector, + jvmOptions, + baseDir, + env + ) + } + } + private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = Def.taskDyn { val target = Keys.bspTargetIdentifier.value val scalacOptions = Keys.scalacOptions.value @@ -878,6 +944,7 @@ object BuildServerProtocol { } } + // here private def scalaMainClassesTask: Initialize[Task[ScalaMainClassesItem]] = Def.task { val jvmOptions = Keys.javaOptions.value.toVector val mainClasses = Keys.discoveredMainClasses.value.map( From 6eb911ad15aa3c21d633fd2be079baaf78e57069 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Tue, 5 Apr 2022 12:20:40 +0200 Subject: [PATCH 18/42] refactor: simplify JVm environment requests refactor: extract common logic to the `bspInputTask` --- .../internal/server/BuildServerProtocol.scala | 146 +++++++----------- 1 file changed, 54 insertions(+), 92 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 78ffa74f5..2c7989ce2 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -119,11 +119,7 @@ object BuildServerProtocol { } }.value, // https://github.com/build-server-protocol/build-server-protocol/blob/master/docs/specification.md#build-target-sources-request - bspBuildTargetSources := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetSources := bspInputTask { (state, _, workspace, filter) => // run the worker task concurrently Def.task { val items = bspBuildTargetSourcesItem.result.all(filter).value @@ -147,64 +143,48 @@ object BuildServerProtocol { } val successfulItems = anyOrThrow(items ++ buildItems) val result = SourcesResult(successfulItems.toVector) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetSources / aggregate := false, - bspBuildTargetResources := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.Resources, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetResources := bspInputTask { (state, _, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.Resources, state.log) // run the worker task concurrently Def.task { val items = bspBuildTargetResourcesItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = ResourcesResult(successfulItems.toVector) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetResources / aggregate := false, - bspBuildTargetDependencySources := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetDependencySources := bspInputTask { (state, _, workspace, filter) => // run the worker task concurrently Def.task { import sbt.internal.bsp.codec.JsonProtocol._ val items = bspBuildTargetDependencySourcesItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = DependencySourcesResult(successfulItems.toVector) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetDependencySources / aggregate := false, - bspBuildTargetCompile := Def.inputTaskDyn { - val s: State = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.Compile, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetCompile := bspInputTask { (state, _, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.Compile, state.log) Def.task { val statusCodes = Keys.bspBuildTargetCompileItem.result.all(filter).value val aggregatedStatusCode = allOrThrow(statusCodes) match { case Seq() => StatusCode.Success case codes => codes.max } - s.respondEvent(BspCompileResult(None, aggregatedStatusCode)) + state.respondEvent(BspCompileResult(None, aggregatedStatusCode)) } }.evaluated, bspBuildTargetCompile / aggregate := false, bspBuildTargetTest := bspTestTask.evaluated, bspBuildTargetTest / aggregate := false, - bspBuildTargetCleanCache := Def.inputTaskDyn { - val s: State = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.CleanCache, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetCleanCache := bspInputTask { (state, targets, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.CleanCache, state.log) Def.task { val results = Keys.clean.result.all(filter).value val successes = anyOrThrow(results).size @@ -214,18 +194,12 @@ object BuildServerProtocol { // checking that the executed results plus this entry is equal to the total number of targets. // When rebuilding a single module, the root build isn't sent, just the requested targets. val cleaned = successes + workspace.builds.size == targets.size - s.respondEvent(CleanCacheResult(None, cleaned)) + state.respondEvent(CleanCacheResult(None, cleaned)) } }.evaluated, bspBuildTargetCleanCache / aggregate := false, - bspBuildTargetScalacOptions := Def.inputTaskDyn { - val s = state.value - - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) + bspBuildTargetScalacOptions := bspInputTask { (state, _, workspace, filter) => val builds = workspace.builds - - val filter = ScopeFilter.in(workspace.scopes.values.toList) Def.task { val items = bspBuildTargetScalacOptionsItem.result.all(filter).value val appProvider = appConfiguration.value.provider() @@ -246,34 +220,26 @@ object BuildServerProtocol { } val successfulItems = anyOrThrow(items ++ buildItems) val result = ScalacOptionsResult(successfulItems.toVector) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetScalacOptions / aggregate := false, - bspScalaTestClasses := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspScalaTestClasses := bspInputTask { (state, _, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, state.log) Def.task { val items = bspScalaTestClassesItem.result.all(filter).value val successfulItems = anyOrThrow(items).flatten.toVector val result = ScalaTestClassesResult(successfulItems.toVector, None) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, - bspScalaMainClasses := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - workspace.warnIfBuildsNonEmpty(Method.ScalaMainClasses, s.log) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspScalaMainClasses := bspInputTask { (state, _, workspace, filter) => + workspace.warnIfBuildsNonEmpty(Method.ScalaMainClasses, state.log) Def.task { val items = bspScalaMainClassesItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = ScalaMainClassesResult(successfulItems.toVector, None) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspScalaMainClasses / aggregate := false @@ -315,28 +281,20 @@ object BuildServerProtocol { bspBuildTargetCompileItem := bspCompileTask.value, bspBuildTargetRun := bspRunTask.evaluated, bspBuildTargetScalacOptionsItem := scalacOptionsTask.value, - bspBuildTargetJVMRunEnvironment := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetJVMRunEnvironment := bspInputTask { (state, _, _, filter) => Def.task { val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = JvmRunEnvironmentResult(successfulItems.toVector, None) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, - bspBuildTargetJVMTestEnvironment := Def.inputTaskDyn { - val s = state.value - val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) - val workspace = bspFullWorkspace.value.filter(targets) - val filter = ScopeFilter.in(workspace.scopes.values.toList) + bspBuildTargetJVMTestEnvironment := bspInputTask { (state, _, _, filter) => Def.task { val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value val successfulItems = anyOrThrow(items) val result = JvmTestEnvironmentResult(successfulItems.toVector, None) - s.respondEvent(result) + state.respondEvent(result) } }.evaluated, bspBuildTargetJvmEnvironmentItem := jvmEnvironmentItem().value, @@ -687,31 +645,36 @@ object BuildServerProtocol { ) } - private def jvmEnvironmentItem(): Initialize[Task[JvmEnvironmentItem]] = Def.taskDyn { - val target = Keys.bspTargetIdentifier.value - val baseDir = Keys.baseDirectory.value.toURI().toString() - val jvmOptions = Keys.javaOptions.value.toVector - val env = envVars.value - val externalDependencyClasspath = Keys.externalDependencyClasspath.value - - val internalDependencyClasspath = for { - (ref, configs) <- bspInternalDependencyConfigurations.value - config <- configs - } yield ref / config / Keys.classDirectory - - Def.task { - val classpath = - internalDependencyClasspath.join.value.distinct ++ - externalDependencyClasspath.map(_.data) - - JvmEnvironmentItem( - target, - classpath.map(_.toURI).toVector, - jvmOptions, - baseDir, - env - ) + private def bspInputTask[T]( + taskImpl: ( + State, + Seq[BuildTargetIdentifier], + BspFullWorkspace, + ScopeFilter + ) => Def.Initialize[Task[T]] + ): Def.Initialize[InputTask[T]] = + Def.inputTaskDyn { + val s = state.value + val targets = spaceDelimited().parsed.map(uri => BuildTargetIdentifier(URI.create(uri))) + val workspace: BspFullWorkspace = bspFullWorkspace.value.filter(targets) + val filter = ScopeFilter.in(workspace.scopes.values.toList) + taskImpl(s, targets, workspace, filter) } + + private def jvmEnvironmentItem(): Initialize[Task[JvmEnvironmentItem]] = Def.task { + val target = Keys.bspTargetIdentifier.value + val classpath = Keys.fullClasspath.value.map(_.data.toURI).toVector + val jvmOptions = Keys.javaOptions.value.toVector + val baseDir = Keys.baseDirectory.value.toURI().toString() + val env = envVars.value + + JvmEnvironmentItem( + target, + classpath, + jvmOptions, + baseDir, + env + ) } private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = Def.taskDyn { @@ -944,7 +907,6 @@ object BuildServerProtocol { } } - // here private def scalaMainClassesTask: Initialize[Task[ScalaMainClassesItem]] = Def.task { val jvmOptions = Keys.javaOptions.value.toVector val mainClasses = Keys.discoveredMainClasses.value.map( From f16412c3dd5df52cb53a6e3642894ce04673ded6 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Tue, 5 Apr 2022 19:29:00 +0200 Subject: [PATCH 19/42] tests: run&test environment requests --- .../src/server-test/buildserver/build.sbt | 8 +++- .../test/scala/testpkg/BuildServerTest.scala | 45 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/server-test/src/server-test/buildserver/build.sbt b/server-test/src/server-test/buildserver/build.sbt index 52691a0a5..9d2de35fc 100644 --- a/server-test/src/server-test/buildserver/build.sbt +++ b/server-test/src/server-test/buildserver/build.sbt @@ -1,10 +1,16 @@ -ThisBuild / scalaVersion := "2.13.1" +ThisBuild / scalaVersion := "2.13.8" Global / serverLog / logLevel := Level.Debug lazy val runAndTest = project.in(file("run-and-test")) .settings( + libraryDependencies += "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "2.13.11", libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % "test", + Compile / javaOptions := Vector("Xmx256M"), + Compile / envVars := Map("KEY" -> "VALUE"), + + Test / javaOptions := Vector("Xmx512M"), + Test / envVars := Map("KEY_TEST" -> "VALUE_TEST"), ) .dependsOn(util) diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index a6d900a16..817b0e6ad 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -157,7 +157,7 @@ object BuildServerTest extends AbstractServerTest { assert(processing("buildTarget/scalacOptions")) assert(svr.waitForString(10.seconds) { s => (s contains """"id":"40"""") && - (s contains "scala-library-2.13.1.jar") + (s contains "scala-library-2.13.8.jar") }) } @@ -311,6 +311,49 @@ object BuildServerTest extends AbstractServerTest { }) } + test("buildTarget/jvmRunEnvironment") { _ => + val buildTarget = buildTargetUri("runAndTest", "Compile") + svr.sendJsonRpc( + s"""|{ "jsonrpc": "2.0", + | "id": "97", + | "method": "buildTarget/jvmRunEnvironment", + | "params": { "targets": [{ "uri": "$buildTarget" }] } + |}""".stripMargin + ) + assert(processing("buildTarget/jvmRunEnvironment")) + assert { + svr.waitForString(10.seconds) { s => + (s contains """"id":"97"""") && + (s contains "jsoniter-scala-core_2.13-2.13.11.jar") && // compile dependency + (s contains "\"jvmOptions\":[\"Xmx256M\"]") && + (s contains "\"environmentVariables\":{\"KEY\":\"VALUE\"}") && + (s contains "/buildserver/run-and-test/") // working directory + } + } + } + + test("buildTarget/jvmTestEnvironment") { _ => + val buildTarget = buildTargetUri("runAndTest", "Test") + svr.sendJsonRpc( + s"""|{ "jsonrpc": "2.0", + | "id": "98", + | "method": "buildTarget/jvmTestEnvironment", + | "params": { "targets": [{ "uri": "$buildTarget" }] } + |}""".stripMargin + ) + assert(processing("buildTarget/jvmTestEnvironment")) + assert { + svr.waitForString(10.seconds) { s => + (s contains """"id":"98"""") && + // test depends on compile so it has dependencies from both + (s contains "jsoniter-scala-core_2.13-2.13.11.jar") && // compile dependency + (s contains "scalatest_2.13-3.0.8.jar") && // test dependency + (s contains "\"jvmOptions\":[\"Xmx512M\"]") && + (s contains "\"environmentVariables\":{\"KEY_TEST\":\"VALUE_TEST\"}") + } + } + } + test("buildTarget/scalaTestClasses") { _ => val buildTarget = buildTargetUri("runAndTest", "Test") val badBuildTarget = buildTargetUri("badBuildTarget", "Test") From faf8dfde72910b78562bf6aede03163bc7ce1261 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Sat, 16 Apr 2022 13:46:12 +0200 Subject: [PATCH 20/42] bsp: add JVM test/run env capabilities to BSP --- .../internal/server/BuildServerProtocol.scala | 4 ++- .../bsp/BuildServerCapabilities.scala | 30 ++++++++++++++----- .../BuildServerCapabilitiesFormats.scala | 6 +++- protocol/src/main/contraband/bsp.contra | 9 ++++++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 2c7989ce2..f288d05a3 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -65,7 +65,9 @@ object BuildServerProtocol { RunProvider(BuildServerConnection.languages), dependencySourcesProvider = true, resourcesProvider = true, - canReload = true + canReload = true, + jvmRunEnvironmentProvider = true, + jvmTestEnvironmentProvider = true, ) private val bspReload = "bspReload" diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala index ccb10343c..82f88a090 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala @@ -17,22 +17,24 @@ final class BuildServerCapabilities private ( val runProvider: Option[sbt.internal.bsp.RunProvider], val dependencySourcesProvider: Option[Boolean], val resourcesProvider: Option[Boolean], - val canReload: Option[Boolean]) extends Serializable { + val canReload: Option[Boolean], + val jvmRunEnvironmentProvider: Option[Boolean], + val jvmTestEnvironmentProvider: Option[Boolean]) extends Serializable { override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { - case x: BuildServerCapabilities => (this.compileProvider == x.compileProvider) && (this.testProvider == x.testProvider) && (this.runProvider == x.runProvider) && (this.dependencySourcesProvider == x.dependencySourcesProvider) && (this.resourcesProvider == x.resourcesProvider) && (this.canReload == x.canReload) + case x: BuildServerCapabilities => (this.compileProvider == x.compileProvider) && (this.testProvider == x.testProvider) && (this.runProvider == x.runProvider) && (this.dependencySourcesProvider == x.dependencySourcesProvider) && (this.resourcesProvider == x.resourcesProvider) && (this.canReload == x.canReload) && (this.jvmRunEnvironmentProvider == x.jvmRunEnvironmentProvider) && (this.jvmTestEnvironmentProvider == x.jvmTestEnvironmentProvider) case _ => false }) override def hashCode: Int = { - 37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.BuildServerCapabilities".##) + compileProvider.##) + testProvider.##) + runProvider.##) + dependencySourcesProvider.##) + resourcesProvider.##) + canReload.##) + 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.BuildServerCapabilities".##) + compileProvider.##) + testProvider.##) + runProvider.##) + dependencySourcesProvider.##) + resourcesProvider.##) + canReload.##) + jvmRunEnvironmentProvider.##) + jvmTestEnvironmentProvider.##) } override def toString: String = { - "BuildServerCapabilities(" + compileProvider + ", " + testProvider + ", " + runProvider + ", " + dependencySourcesProvider + ", " + resourcesProvider + ", " + canReload + ")" + "BuildServerCapabilities(" + compileProvider + ", " + testProvider + ", " + runProvider + ", " + dependencySourcesProvider + ", " + resourcesProvider + ", " + canReload + ", " + jvmRunEnvironmentProvider + ", " + jvmTestEnvironmentProvider + ")" } - private[this] def copy(compileProvider: Option[sbt.internal.bsp.CompileProvider] = compileProvider, testProvider: Option[sbt.internal.bsp.TestProvider] = testProvider, runProvider: Option[sbt.internal.bsp.RunProvider] = runProvider, dependencySourcesProvider: Option[Boolean] = dependencySourcesProvider, resourcesProvider: Option[Boolean] = resourcesProvider, canReload: Option[Boolean] = canReload): BuildServerCapabilities = { - new BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, canReload) + private[this] def copy(compileProvider: Option[sbt.internal.bsp.CompileProvider] = compileProvider, testProvider: Option[sbt.internal.bsp.TestProvider] = testProvider, runProvider: Option[sbt.internal.bsp.RunProvider] = runProvider, dependencySourcesProvider: Option[Boolean] = dependencySourcesProvider, resourcesProvider: Option[Boolean] = resourcesProvider, canReload: Option[Boolean] = canReload, jvmRunEnvironmentProvider: Option[Boolean] = jvmRunEnvironmentProvider, jvmTestEnvironmentProvider: Option[Boolean] = jvmTestEnvironmentProvider): BuildServerCapabilities = { + new BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, canReload, jvmRunEnvironmentProvider, jvmTestEnvironmentProvider) } def withCompileProvider(compileProvider: Option[sbt.internal.bsp.CompileProvider]): BuildServerCapabilities = { copy(compileProvider = compileProvider) @@ -70,9 +72,21 @@ final class BuildServerCapabilities private ( def withCanReload(canReload: Boolean): BuildServerCapabilities = { copy(canReload = Option(canReload)) } + def withJvmRunEnvironmentProvider(jvmRunEnvironmentProvider: Option[Boolean]): BuildServerCapabilities = { + copy(jvmRunEnvironmentProvider = jvmRunEnvironmentProvider) + } + def withJvmRunEnvironmentProvider(jvmRunEnvironmentProvider: Boolean): BuildServerCapabilities = { + copy(jvmRunEnvironmentProvider = Option(jvmRunEnvironmentProvider)) + } + def withJvmTestEnvironmentProvider(jvmTestEnvironmentProvider: Option[Boolean]): BuildServerCapabilities = { + copy(jvmTestEnvironmentProvider = jvmTestEnvironmentProvider) + } + def withJvmTestEnvironmentProvider(jvmTestEnvironmentProvider: Boolean): BuildServerCapabilities = { + copy(jvmTestEnvironmentProvider = Option(jvmTestEnvironmentProvider)) + } } object BuildServerCapabilities { - def apply(compileProvider: Option[sbt.internal.bsp.CompileProvider], testProvider: Option[sbt.internal.bsp.TestProvider], runProvider: Option[sbt.internal.bsp.RunProvider], dependencySourcesProvider: Option[Boolean], resourcesProvider: Option[Boolean], canReload: Option[Boolean]): BuildServerCapabilities = new BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, canReload) - def apply(compileProvider: sbt.internal.bsp.CompileProvider, testProvider: sbt.internal.bsp.TestProvider, runProvider: sbt.internal.bsp.RunProvider, dependencySourcesProvider: Boolean, resourcesProvider: Boolean, canReload: Boolean): BuildServerCapabilities = new BuildServerCapabilities(Option(compileProvider), Option(testProvider), Option(runProvider), Option(dependencySourcesProvider), Option(resourcesProvider), Option(canReload)) + def apply(compileProvider: Option[sbt.internal.bsp.CompileProvider], testProvider: Option[sbt.internal.bsp.TestProvider], runProvider: Option[sbt.internal.bsp.RunProvider], dependencySourcesProvider: Option[Boolean], resourcesProvider: Option[Boolean], canReload: Option[Boolean], jvmRunEnvironmentProvider: Option[Boolean], jvmTestEnvironmentProvider: Option[Boolean]): BuildServerCapabilities = new BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, canReload, jvmRunEnvironmentProvider, jvmTestEnvironmentProvider) + def apply(compileProvider: sbt.internal.bsp.CompileProvider, testProvider: sbt.internal.bsp.TestProvider, runProvider: sbt.internal.bsp.RunProvider, dependencySourcesProvider: Boolean, resourcesProvider: Boolean, canReload: Boolean, jvmRunEnvironmentProvider: Boolean, jvmTestEnvironmentProvider: Boolean): BuildServerCapabilities = new BuildServerCapabilities(Option(compileProvider), Option(testProvider), Option(runProvider), Option(dependencySourcesProvider), Option(resourcesProvider), Option(canReload), Option(jvmRunEnvironmentProvider), Option(jvmTestEnvironmentProvider)) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BuildServerCapabilitiesFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BuildServerCapabilitiesFormats.scala index 0947bd565..c23b3db80 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BuildServerCapabilitiesFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BuildServerCapabilitiesFormats.scala @@ -17,8 +17,10 @@ implicit lazy val BuildServerCapabilitiesFormat: JsonFormat[sbt.internal.bsp.Bui val dependencySourcesProvider = unbuilder.readField[Option[Boolean]]("dependencySourcesProvider") val resourcesProvider = unbuilder.readField[Option[Boolean]]("resourcesProvider") val canReload = unbuilder.readField[Option[Boolean]]("canReload") + val jvmRunEnvironmentProvider = unbuilder.readField[Option[Boolean]]("jvmRunEnvironmentProvider") + val jvmTestEnvironmentProvider = unbuilder.readField[Option[Boolean]]("jvmTestEnvironmentProvider") unbuilder.endObject() - sbt.internal.bsp.BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, canReload) + sbt.internal.bsp.BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, canReload, jvmRunEnvironmentProvider, jvmTestEnvironmentProvider) case None => deserializationError("Expected JsObject but found None") } @@ -31,6 +33,8 @@ implicit lazy val BuildServerCapabilitiesFormat: JsonFormat[sbt.internal.bsp.Bui builder.addField("dependencySourcesProvider", obj.dependencySourcesProvider) builder.addField("resourcesProvider", obj.resourcesProvider) builder.addField("canReload", obj.canReload) + builder.addField("jvmRunEnvironmentProvider", obj.jvmRunEnvironmentProvider) + builder.addField("jvmTestEnvironmentProvider", obj.jvmTestEnvironmentProvider) builder.endObject() } } diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index bc20a52e9..79734b10f 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -208,6 +208,15 @@ type BuildServerCapabilities { # The server sends notifications to the client on build # target change events via buildTarget/didChange # buildTargetChangedProvider: Boolean + + + # The JVM run/test environment request is sent from the client to the server + # in order to gather information required to launch a Java process. + # This is useful when the client wants to control the Java process execution, + # for example to enable custom Java agents or launch a custom main class during + # unit testing or debugging + jvmRunEnvironmentProvider: Boolean + jvmTestEnvironmentProvider: Boolean } type CompileProvider { From ec9c3f26c6394724c4089c322cd440025fb7c76c Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Sat, 16 Apr 2022 21:53:32 +0900 Subject: [PATCH 21/42] Update semanticdbVersion --- build.sbt | 2 +- main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index a33ac73ae..c2e3feb81 100644 --- a/build.sbt +++ b/build.sbt @@ -46,7 +46,7 @@ ThisBuild / resolvers += Resolver.mavenLocal Global / semanticdbEnabled := !(Global / insideCI).value // Change main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala too, if you change this. -Global / semanticdbVersion := "4.4.28" +Global / semanticdbVersion := "4.5.4" val excludeLint = SettingKey[Set[Def.KeyedInitialize[_]]]("excludeLintKeys") Global / excludeLint := (Global / excludeLint).?.value.getOrElse(Set.empty) Global / excludeLint += componentID diff --git a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala index 76b9c8f1b..f8f2eebde 100644 --- a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala +++ b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala @@ -26,7 +26,7 @@ object SemanticdbPlugin extends AutoPlugin { semanticdbEnabled := SysProp.semanticdb, semanticdbIncludeInJar := false, semanticdbOptions := List(), - semanticdbVersion := "4.4.28" + semanticdbVersion := "4.5.4" ) override lazy val projectSettings: Seq[Def.Setting[_]] = Seq( From cf976885f7afe186a30410c8829dd45cd9e0f1a0 Mon Sep 17 00:00:00 2001 From: Philippus Date: Sun, 17 Apr 2022 12:59:12 +0200 Subject: [PATCH 22/42] Add SBTN_AUTO_COMPLETE environment variable --- .../src/main/scala/sbt/internal/client/NetworkClient.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala index 71a11e6fd..eb7fc322e 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -139,7 +139,7 @@ class NetworkClient( private val rebooting = new AtomicBoolean(false) private lazy val noTab = arguments.completionArguments.contains("--no-tab") private lazy val noStdErr = arguments.completionArguments.contains("--no-stderr") && - !sys.env.contains("SBTC_AUTO_COMPLETE") + !sys.env.contains("SBTN_AUTO_COMPLETE") && !sys.env.contains("SBTC_AUTO_COMPLETE") private def mkSocket(file: File): (Socket, Option[String]) = ClientSocket.socket(file, useJNI) From 1d3b9143a43ccbac692145044b128193da76f48c Mon Sep 17 00:00:00 2001 From: Philippus Date: Sun, 17 Apr 2022 12:56:06 +0200 Subject: [PATCH 23/42] Fix typos --- .../main/scala/sbt/internal/client/NetworkClient.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala index eb7fc322e..8909d6d42 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -67,7 +67,7 @@ trait ConsoleInterface { } /** - * A NetworkClient connects to a running an sbt instance or starts a + * A NetworkClient connects to a running sbt instance or starts a * new instance if there isn't already one running. Once connected, * it can send commands for sbt to run, it can send completions to sbt * and print the completions to stdout so that a shell can consume @@ -78,15 +78,15 @@ trait ConsoleInterface { * needs to start it. It also contains the sbt command * arguments to send to the server if any are present. * @param console a logging instance. This can use a ConsoleAppender or - * just simply print to a PrintSream. + * just simply print to a PrintStream. * @param inputStream the InputStream from which the client reads bytes. It * is not hardcoded to System.in so that a NetworkClient * can be remotely controlled by a java process, which - * is useful in test. + * is useful in testing. * @param errorStream the sink for messages that we always want to be printed. * It is usually System.err but could be overridden in tests * or set to a null OutputStream if the NetworkClient needs - * to be silent + * to be silent. * @param printStream the sink for standard out messages. It is typically * System.out but in the case of completions, the bytes written * to System.out are usually treated as completion results From 64c7071ff291aef8259628b9cce151885aed7858 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 9 Apr 2022 15:12:20 -0700 Subject: [PATCH 24/42] Move on-termination test --- sbt-app/src/sbt-test/watch/{on-termination => on-error}/build.sbt | 0 .../watch/{on-termination => on-error}/project/Build.scala | 0 sbt-app/src/sbt-test/watch/{on-termination => on-error}/test | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename sbt-app/src/sbt-test/watch/{on-termination => on-error}/build.sbt (100%) rename sbt-app/src/sbt-test/watch/{on-termination => on-error}/project/Build.scala (100%) rename sbt-app/src/sbt-test/watch/{on-termination => on-error}/test (100%) diff --git a/sbt-app/src/sbt-test/watch/on-termination/build.sbt b/sbt-app/src/sbt-test/watch/on-error/build.sbt similarity index 100% rename from sbt-app/src/sbt-test/watch/on-termination/build.sbt rename to sbt-app/src/sbt-test/watch/on-error/build.sbt diff --git a/sbt-app/src/sbt-test/watch/on-termination/project/Build.scala b/sbt-app/src/sbt-test/watch/on-error/project/Build.scala similarity index 100% rename from sbt-app/src/sbt-test/watch/on-termination/project/Build.scala rename to sbt-app/src/sbt-test/watch/on-error/project/Build.scala diff --git a/sbt-app/src/sbt-test/watch/on-termination/test b/sbt-app/src/sbt-test/watch/on-error/test similarity index 100% rename from sbt-app/src/sbt-test/watch/on-termination/test rename to sbt-app/src/sbt-test/watch/on-error/test From ca7c872e27609bb54c0c6478b02fae2fab31f57d Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 9 Apr 2022 15:05:54 -0700 Subject: [PATCH 25/42] Restore watchOnTermination At some point the watchOnTermination callback stopped working. I'm not exactly sure how or why that happened but it is fairly straightforward to restore. The one tricky thing was that the callback has the signature (Watch.Action, _, _, _) => State, which requires propagating the action to the failWatch command. The easiest way to do this was to add a mutable field to the ContinuousState. This is rather ugly and reflects some poor design choices but a more comprehensive refactor is out of the scope of this fix. This commit adds a scripted test that ensures that the callback is invoked both in the successful and unsuccessful watch cases. In each case the callback deletes a file and we ensure that the file is indeed absent after the watch exits. --- .../main/scala/sbt/internal/Continuous.scala | 68 +++++++++++++------ .../src/sbt-test/watch/on-termination/bar.txt | 0 .../sbt-test/watch/on-termination/build.sbt | 15 ++++ .../src/sbt-test/watch/on-termination/foo.txt | 0 .../src/sbt-test/watch/on-termination/test | 8 +++ 5 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 sbt-app/src/sbt-test/watch/on-termination/bar.txt create mode 100644 sbt-app/src/sbt-test/watch/on-termination/build.sbt create mode 100644 sbt-app/src/sbt-test/watch/on-termination/foo.txt create mode 100644 sbt-app/src/sbt-test/watch/on-termination/test diff --git a/main/src/main/scala/sbt/internal/Continuous.scala b/main/src/main/scala/sbt/internal/Continuous.scala index c206cb71e..68c2d4a87 100644 --- a/main/src/main/scala/sbt/internal/Continuous.scala +++ b/main/src/main/scala/sbt/internal/Continuous.scala @@ -1128,7 +1128,28 @@ private[sbt] object Continuous extends DeprecatedContinuous { val callbacks: Callbacks, val dynamicInputs: mutable.Set[DynamicInput], val pending: Boolean, + var failAction: Option[Watch.Action], ) { + def this( + count: Int, + commands: Seq[String], + beforeCommandImpl: (State, mutable.Set[DynamicInput]) => State, + afterCommand: State => State, + afterWatch: State => State, + callbacks: Callbacks, + dynamicInputs: mutable.Set[DynamicInput], + pending: Boolean, + ) = this( + count, + commands, + beforeCommandImpl, + afterCommand, + afterWatch, + callbacks, + dynamicInputs, + pending, + None + ) def beforeCommand(state: State): State = beforeCommandImpl(state, dynamicInputs) def incremented: ContinuousState = withCount(count + 1) def withPending(p: Boolean) = @@ -1323,7 +1344,8 @@ private[sbt] object ContinuousCommands { case Watch.Prompt => stop.map(_ :: s"$PromptChannel ${channel.name}" :: Nil mkString ";") case Watch.Run(commands) => stop.map(_ +: commands.map(_.commandLine).filter(_.nonEmpty) mkString "; ") - case Watch.HandleError(_) => + case a @ Watch.HandleError(_) => + cs.failAction = Some(a) stop.map(_ :: s"$failWatch ${channel.name}" :: Nil mkString "; ") case _ => stop } @@ -1353,27 +1375,31 @@ private[sbt] object ContinuousCommands { } cs.afterCommand(postState) } - private[sbt] val stopWatchCommand = watchCommand(stopWatch) { (channel, state) => - state.get(watchStates).flatMap(_.get(channel)) match { - case Some(cs) => - val afterWatchState = cs.afterWatch(state) - cs.callbacks.onExit() - StandardMain.exchange - .channelForName(channel) - .foreach { c => - c.terminal.setPrompt(Prompt.Pending) - c.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel)))) + private[this] val exitWatchShared = (error: Boolean) => + (channel: String, state: State) => + state.get(watchStates).flatMap(_.get(channel)) match { + case Some(cs) => + val afterWatchState = cs.afterWatch(state) + cs.callbacks.onExit() + StandardMain.exchange + .channelForName(channel) + .foreach { c => + c.terminal.setPrompt(Prompt.Pending) + c.unprompt(ConsoleUnpromptEvent(Some(CommandSource(channel)))) + } + val newState = afterWatchState.get(watchStates) match { + case None => afterWatchState + case Some(w) => afterWatchState.put(watchStates, w - channel) } - afterWatchState.get(watchStates) match { - case None => afterWatchState - case Some(w) => afterWatchState.put(watchStates, w - channel) - } - case _ => state - } - } - private[sbt] val failWatchCommand = watchCommand(failWatch) { (channel, state) => - state.fail - } + val commands = cs.commands.mkString("; ") + val count = cs.count + val action = cs.failAction.getOrElse(Watch.CancelWatch) + val st = cs.callbacks.onTermination(action, commands, count, newState) + if (error) st.fail else st + case _ => if (error) state.fail else state + } + private[sbt] val stopWatchCommand = watchCommand(stopWatch)(exitWatchShared(false)) + private[sbt] val failWatchCommand = watchCommand(failWatch)(exitWatchShared(true)) /* * Creates a FileTreeRepository where it is safe to call close without inadvertently cancelling * still active watches. diff --git a/sbt-app/src/sbt-test/watch/on-termination/bar.txt b/sbt-app/src/sbt-test/watch/on-termination/bar.txt new file mode 100644 index 000000000..e69de29bb diff --git a/sbt-app/src/sbt-test/watch/on-termination/build.sbt b/sbt-app/src/sbt-test/watch/on-termination/build.sbt new file mode 100644 index 000000000..798f18016 --- /dev/null +++ b/sbt-app/src/sbt-test/watch/on-termination/build.sbt @@ -0,0 +1,15 @@ +watchOnIteration := { (count, project, commands) => + Watch.CancelWatch +} +watchOnTermination := { (action, count, command, state) => + action match { + case Watch.CancelWatch => + java.nio.file.Files.delete(java.nio.file.Paths.get("foo.txt")) + case Watch.HandleError(e) => + if (e.getMessage == "fail") + java.nio.file.Files.delete(java.nio.file.Paths.get("bar.txt")) + else + throw new IllegalStateException("unexpected error") + } + state +} diff --git a/sbt-app/src/sbt-test/watch/on-termination/foo.txt b/sbt-app/src/sbt-test/watch/on-termination/foo.txt new file mode 100644 index 000000000..e69de29bb diff --git a/sbt-app/src/sbt-test/watch/on-termination/test b/sbt-app/src/sbt-test/watch/on-termination/test new file mode 100644 index 000000000..1634ee847 --- /dev/null +++ b/sbt-app/src/sbt-test/watch/on-termination/test @@ -0,0 +1,8 @@ +$ exists foo.txt +> ~compile +$ absent foo.txt +> set watchOnIteration := { (_, _, _) => new Watch.HandleError(new IllegalStateException("fail")) } +$ exists bar.txt +-> ~compile +$ absent bar.txt + From 45518c7f24a216afeb742bec2df135db0a2e0994 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Sat, 16 Apr 2022 21:53:32 +0900 Subject: [PATCH 26/42] Update semanticdbVersion --- build.sbt | 2 +- main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index a33ac73ae..c2e3feb81 100644 --- a/build.sbt +++ b/build.sbt @@ -46,7 +46,7 @@ ThisBuild / resolvers += Resolver.mavenLocal Global / semanticdbEnabled := !(Global / insideCI).value // Change main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala too, if you change this. -Global / semanticdbVersion := "4.4.28" +Global / semanticdbVersion := "4.5.4" val excludeLint = SettingKey[Set[Def.KeyedInitialize[_]]]("excludeLintKeys") Global / excludeLint := (Global / excludeLint).?.value.getOrElse(Set.empty) Global / excludeLint += componentID diff --git a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala index 76b9c8f1b..f8f2eebde 100644 --- a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala +++ b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala @@ -26,7 +26,7 @@ object SemanticdbPlugin extends AutoPlugin { semanticdbEnabled := SysProp.semanticdb, semanticdbIncludeInJar := false, semanticdbOptions := List(), - semanticdbVersion := "4.4.28" + semanticdbVersion := "4.5.4" ) override lazy val projectSettings: Seq[Def.Setting[_]] = Seq( From 20a9269e791747d01721e65b4829d0a22aef9e96 Mon Sep 17 00:00:00 2001 From: Philippus Date: Sun, 17 Apr 2022 12:59:12 +0200 Subject: [PATCH 27/42] Add SBTN_AUTO_COMPLETE environment variable --- .../src/main/scala/sbt/internal/client/NetworkClient.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala index 71a11e6fd..eb7fc322e 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -139,7 +139,7 @@ class NetworkClient( private val rebooting = new AtomicBoolean(false) private lazy val noTab = arguments.completionArguments.contains("--no-tab") private lazy val noStdErr = arguments.completionArguments.contains("--no-stderr") && - !sys.env.contains("SBTC_AUTO_COMPLETE") + !sys.env.contains("SBTN_AUTO_COMPLETE") && !sys.env.contains("SBTC_AUTO_COMPLETE") private def mkSocket(file: File): (Socket, Option[String]) = ClientSocket.socket(file, useJNI) From 11275f604cdfd435d7042badfd136b3ff1586e0a Mon Sep 17 00:00:00 2001 From: Philippus Date: Sun, 17 Apr 2022 12:56:06 +0200 Subject: [PATCH 28/42] Fix typos --- .../main/scala/sbt/internal/client/NetworkClient.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala index eb7fc322e..8909d6d42 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -67,7 +67,7 @@ trait ConsoleInterface { } /** - * A NetworkClient connects to a running an sbt instance or starts a + * A NetworkClient connects to a running sbt instance or starts a * new instance if there isn't already one running. Once connected, * it can send commands for sbt to run, it can send completions to sbt * and print the completions to stdout so that a shell can consume @@ -78,15 +78,15 @@ trait ConsoleInterface { * needs to start it. It also contains the sbt command * arguments to send to the server if any are present. * @param console a logging instance. This can use a ConsoleAppender or - * just simply print to a PrintSream. + * just simply print to a PrintStream. * @param inputStream the InputStream from which the client reads bytes. It * is not hardcoded to System.in so that a NetworkClient * can be remotely controlled by a java process, which - * is useful in test. + * is useful in testing. * @param errorStream the sink for messages that we always want to be printed. * It is usually System.err but could be overridden in tests * or set to a null OutputStream if the NetworkClient needs - * to be silent + * to be silent. * @param printStream the sink for standard out messages. It is typically * System.out but in the case of completions, the bytes written * to System.out are usually treated as completion results From 053834aea07a0bc89f88e0fdcce84a133b17340a Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 17 Apr 2022 23:26:40 -0400 Subject: [PATCH 29/42] Zinc 1.7.0-M2 --- build.sbt | 2 +- project/Dependencies.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index c2e3feb81..f59529599 100644 --- a/build.sbt +++ b/build.sbt @@ -10,7 +10,7 @@ import scala.util.Try // ThisBuild settings take lower precedence, // but can be shared across the multi projects. ThisBuild / version := { - val v = "1.6.3-SNAPSHOT" + val v = "1.7.0-SNAPSHOT" nightlyVersion.getOrElse(v) } ThisBuild / version2_13 := "2.0.0-SNAPSHOT" diff --git a/project/Dependencies.scala b/project/Dependencies.scala index ae0d47987..535f2e3bb 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -15,7 +15,7 @@ object Dependencies { private val ioVersion = nightlyVersion.getOrElse("1.6.0") private val lmVersion = sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.6.1") - val zincVersion = nightlyVersion.getOrElse("1.6.0") + val zincVersion = nightlyVersion.getOrElse("1.7.0-M2") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion From c4840ec4738587e81fb57b0bd3a550151dfb3a85 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 1 May 2022 03:07:17 -0400 Subject: [PATCH 30/42] Fix Main.scala referencing oldLastGrep --- main/src/main/scala/sbt/Main.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index e45987944..4d30a9920 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -329,7 +329,6 @@ object BuiltinCommands { startServer, eval, last, - oldLastGrep, lastGrep, export, boot, @@ -626,7 +625,6 @@ object BuiltinCommands { s } - def lastGrep: Command = lastGrepCommand(LastGrepCommand, lastGrepBrief, lastGrepDetailed, lastGrepParser) From f6ff6996a5d3712e408077ae04902d9ce2a85754 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Sun, 22 May 2022 10:48:48 +0900 Subject: [PATCH 31/42] fix typo --- main-command/src/main/scala/sbt/internal/ui/UITask.scala | 2 +- main/src/main/scala/sbt/BackgroundJobService.scala | 2 +- main/src/main/scala/sbt/Defaults.scala | 2 +- main/src/main/scala/sbt/UpperStateOps.scala | 4 ++-- main/src/main/scala/sbt/nio/Settings.scala | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/main-command/src/main/scala/sbt/internal/ui/UITask.scala b/main-command/src/main/scala/sbt/internal/ui/UITask.scala index 1ed500047..5c27fc873 100644 --- a/main-command/src/main/scala/sbt/internal/ui/UITask.scala +++ b/main-command/src/main/scala/sbt/internal/ui/UITask.scala @@ -75,7 +75,7 @@ private[sbt] object UITask { this.synchronized(this.wait()) Right("") // should be unreachable // JLine returns null on ctrl+d when there is no other input. This interprets - // ctrl+d with no imput as an exit + // ctrl+d with no input as an exit case None => Left(TerminateAction) case Some(s: String) => s.trim() match { diff --git a/main/src/main/scala/sbt/BackgroundJobService.scala b/main/src/main/scala/sbt/BackgroundJobService.scala index 1cbff3f2d..8faad7728 100644 --- a/main/src/main/scala/sbt/BackgroundJobService.scala +++ b/main/src/main/scala/sbt/BackgroundJobService.scala @@ -44,7 +44,7 @@ abstract class BackgroundJobService extends Closeable { start(logger, file)._2.apply() } - /** Same as shutown. */ + /** Same as shutdown. */ def close(): Unit /** Shuts down all background jobs. */ diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 4b0fc2ad9..f2e355bc2 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -4387,7 +4387,7 @@ trait BuildExtra extends BuildCommon with DefExtra { } @deprecated( - "externalIvyFile is not supported by Couriser, and will be removed in the future", + "externalIvyFile is not supported by Coursier, and will be removed in the future", since = "1.5.0" ) def externalIvyFile( diff --git a/main/src/main/scala/sbt/UpperStateOps.scala b/main/src/main/scala/sbt/UpperStateOps.scala index 02c9ef0c3..e53f600b4 100644 --- a/main/src/main/scala/sbt/UpperStateOps.scala +++ b/main/src/main/scala/sbt/UpperStateOps.scala @@ -18,12 +18,12 @@ trait UpperStateOps extends Any { /** * ProjectRef to the current project of the state session that can be change using - * `project` commmand. + * `project` command. */ def currentRef: ProjectRef /** - * Current project of the state session that can be change using `project` commmand. + * Current project of the state session that can be change using `project` command. */ def currentProject: ResolvedProject diff --git a/main/src/main/scala/sbt/nio/Settings.scala b/main/src/main/scala/sbt/nio/Settings.scala index 3f78649af..cef86648f 100644 --- a/main/src/main/scala/sbt/nio/Settings.scala +++ b/main/src/main/scala/sbt/nio/Settings.scala @@ -259,7 +259,7 @@ private[sbt] object Settings { * Provides an automatically generated clean method for a task that provides fileOutputs. * * @param taskKey the task for which we add a custom clean implementation - * @return a task specificic clean implementation + * @return a task specific clean implementation */ @nowarn private[sbt] def cleanImpl[T: JsonFormat: ToSeqPath](taskKey: TaskKey[T]): Def.Setting[_] = { From 9565e33ea8efa1f81ff34cb85a3a46624ac797a2 Mon Sep 17 00:00:00 2001 From: "dmitrii.naumenko" Date: Mon, 23 May 2022 18:05:33 +0300 Subject: [PATCH 32/42] "oldshell" command should use `OldShell` on failure instead of `Shell` following up https://github.com/sbt/sbt/pull/3098 --- main-command/src/main/scala/sbt/BasicCommands.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main-command/src/main/scala/sbt/BasicCommands.scala b/main-command/src/main/scala/sbt/BasicCommands.scala index bb58bd301..06b7599f1 100644 --- a/main-command/src/main/scala/sbt/BasicCommands.scala +++ b/main-command/src/main/scala/sbt/BasicCommands.scala @@ -406,7 +406,7 @@ object BasicCommands { case Some(line) => val newState = s .copy( - onFailure = Some(Exec(Shell, None)), + onFailure = Some(Exec(OldShell, None)), remainingCommands = Exec(line, s.source) +: Exec(OldShell, None) +: s.remainingCommands ) .setInteractive(true) From e42c6ccaed4be9cedde6629c4e36940aed3af942 Mon Sep 17 00:00:00 2001 From: gontard Date: Mon, 23 May 2022 20:54:11 +0200 Subject: [PATCH 33/42] Fix scripted tests doc --- DEVELOPING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEVELOPING.md b/DEVELOPING.md index 8b1db7b09..40cbfda3a 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -151,14 +151,14 @@ suite with `sbt testOnly` #### Integration tests -Scripted integration tests reside in `sbt/src/sbt-test` and are +Scripted integration tests reside in `sbt-app/src/sbt-test` and are written using the same testing infrastructure sbt plugin authors can use to test their own plugins with sbt. You can read more about this style of tests [here](https://www.scala-sbt.org/1.0/docs/Testing-sbt-plugins). You can run the integration tests with the `sbt scripted` sbt command. To run a single test, such as the test in -`sbt/src/sbt-test/project/global-plugin`, simply run: +`sbt-app/src/sbt-test/project/global-plugin`, simply run: sbt "scripted project/global-plugin" From 65cdcf434d7030feb76a9187ee81739591536957 Mon Sep 17 00:00:00 2001 From: gontard Date: Mon, 23 May 2022 21:31:26 +0200 Subject: [PATCH 34/42] Activate test-quick scripted test --- sbt-app/src/sbt-test/tests/test-quick/build.sbt | 3 +-- .../sbt-test/tests/test-quick/src/test/scala/Create.scala | 7 +++---- .../sbt-test/tests/test-quick/src/test/scala/Delete.scala | 5 ++--- sbt-app/src/sbt-test/tests/test-quick/{disabled => test} | 0 4 files changed, 6 insertions(+), 9 deletions(-) rename sbt-app/src/sbt-test/tests/test-quick/{disabled => test} (100%) diff --git a/sbt-app/src/sbt-test/tests/test-quick/build.sbt b/sbt-app/src/sbt-test/tests/test-quick/build.sbt index 0fb62b441..9fd396d27 100644 --- a/sbt-app/src/sbt-test/tests/test-quick/build.sbt +++ b/sbt-app/src/sbt-test/tests/test-quick/build.sbt @@ -1,9 +1,8 @@ val scalatest = "org.scalatest" %% "scalatest" % "3.0.5" -val scalaxml = "org.scala-lang.modules" %% "scala-xml" % "1.1.1" ThisBuild / scalaVersion := "2.12.12" lazy val root = (project in file(".")) .settings( - libraryDependencies ++= List(scalaxml, scalatest), + libraryDependencies += scalatest % Test, Test / parallelExecution := false ) diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Create.scala b/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Create.scala index 121de95b0..651807d8d 100644 --- a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Create.scala +++ b/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Create.scala @@ -1,11 +1,10 @@ import org.scalatest.FlatSpec -import org.scalatest.matchers.ShouldMatchers -class Create extends FlatSpec with ShouldMatchers with Base { +class Create extends FlatSpec with Base { "a file" should "not exist" in { A(new B).foo - marker.exists should equal(false) - marker.createNewFile() should equal (true) + assert(marker.exists == false) + assert(marker.createNewFile() == true) } } diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Delete.scala b/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Delete.scala index cd2eb6617..ff1caacb1 100644 --- a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Delete.scala +++ b/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/Delete.scala @@ -1,9 +1,8 @@ import org.scalatest.FlatSpec -import org.scalatest.matchers.ShouldMatchers -class Delete extends FlatSpec with ShouldMatchers with Base { +class Delete extends FlatSpec with Base { "a file" should "exist" in { - marker.exists should equal(true) + assert(marker.exists == true) marker.delete() } diff --git a/sbt-app/src/sbt-test/tests/test-quick/disabled b/sbt-app/src/sbt-test/tests/test-quick/test similarity index 100% rename from sbt-app/src/sbt-test/tests/test-quick/disabled rename to sbt-app/src/sbt-test/tests/test-quick/test From 903fd6ae7aa21e66f92ec7933ecf7b99b5263274 Mon Sep 17 00:00:00 2001 From: gontard Date: Tue, 24 May 2022 06:44:26 +0200 Subject: [PATCH 35/42] Reproduce issue #5504 in scripted test --- .../sbt-test/tests/test-quick/changed/MathFunction.scala | 3 +++ .../tests/test-quick/src/main/scala/MathFunction.scala | 3 +++ .../tests/test-quick/src/test/scala/MathFunctionSpec.scala | 7 +++++++ sbt-app/src/sbt-test/tests/test-quick/test | 6 ++++++ 4 files changed, 19 insertions(+) create mode 100644 sbt-app/src/sbt-test/tests/test-quick/changed/MathFunction.scala create mode 100644 sbt-app/src/sbt-test/tests/test-quick/src/main/scala/MathFunction.scala create mode 100644 sbt-app/src/sbt-test/tests/test-quick/src/test/scala/MathFunctionSpec.scala diff --git a/sbt-app/src/sbt-test/tests/test-quick/changed/MathFunction.scala b/sbt-app/src/sbt-test/tests/test-quick/changed/MathFunction.scala new file mode 100644 index 000000000..1be75e613 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/test-quick/changed/MathFunction.scala @@ -0,0 +1,3 @@ +object MathFunction { + def times2(i: Int): Int = 2 * 2 +} diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/main/scala/MathFunction.scala b/sbt-app/src/sbt-test/tests/test-quick/src/main/scala/MathFunction.scala new file mode 100644 index 000000000..08d0ec501 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/test-quick/src/main/scala/MathFunction.scala @@ -0,0 +1,3 @@ +object MathFunction { + def times2(i: Int): Int = i * 2 +} diff --git a/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/MathFunctionSpec.scala b/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/MathFunctionSpec.scala new file mode 100644 index 000000000..7ee6336da --- /dev/null +++ b/sbt-app/src/sbt-test/tests/test-quick/src/test/scala/MathFunctionSpec.scala @@ -0,0 +1,7 @@ +import org.scalatest.FlatSpec + +class MathFunctionTest extends FlatSpec { + "times2" should "double the input" in { + assert(MathFunction.times2(4) == 8) + } +} diff --git a/sbt-app/src/sbt-test/tests/test-quick/test b/sbt-app/src/sbt-test/tests/test-quick/test index d88f8a185..c86f0276f 100644 --- a/sbt-app/src/sbt-test/tests/test-quick/test +++ b/sbt-app/src/sbt-test/tests/test-quick/test @@ -32,3 +32,9 @@ $ sleep 2000 -> testQuick Create > testQuick Delete > testQuick Create + +# https://github.com/sbt/sbt/issues/5504 +$ copy-file changed/MathFunction.scala src/test/scala/MathFunction.scala +> compile +$ sleep 2000 +-> testQuick MathFunctionTest From 3c497addd193b3ed6d338b9798b1c486547781d1 Mon Sep 17 00:00:00 2001 From: gontard Date: Tue, 24 May 2022 10:54:11 +0200 Subject: [PATCH 36/42] Fix testQuick on changed function in object Fix https://github.com/sbt/sbt/issues/5504 --- main/src/main/scala/sbt/Defaults.scala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index f2e355bc2..7eb5016b8 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1395,11 +1395,10 @@ object Defaults extends BuildCommon { val x = { import analysis.{ apis, relations => rel } rel.internalClassDeps(c).map(intlStamp(_, analysis, s + c)) ++ - rel.externalDeps(c).map(stamp) + - (apis.internal.get(c) match { - case Some(x) => x.compilationTimestamp - case _ => Long.MinValue - }) + rel.externalDeps(c).map(stamp) ++ + rel.productClassName.reverse(c).flatMap { pc => + apis.internal.get(pc).map(_.compilationTimestamp) + } + Long.MinValue }.max if (x != Long.MinValue) { stamps(c) = x From 86fd6dc058a47fe83210b3dc9650b55cc080cc0b Mon Sep 17 00:00:00 2001 From: Alonso Montero <31372753+AlonsoM45@users.noreply.github.com> Date: Thu, 26 May 2022 21:10:41 -0600 Subject: [PATCH 37/42] Use XDG_RUNTIME_DIR environment variable to choose the path used for the creation of sockets (#6887) The `XDG_RUNTIME_DIR` environment variable will be used to choose the base directory in which the sockets will be created by **sbt**. This can help when issues such as #6777 appear. There are other related issues, such as #6101, [Metals issue #2235](https://github.com/scalameta/metals/issues/2235), [Che issue #18394](https://github.com/eclipse/che/issues/18394). Those are closed issues, but there are some cases in which the solution does not work (such as the case in #6777). Furthermore, the solution given seems more like a workaround than an actual fix. **What causes this issue?** At least in my case, the **ServerAlreadyBootingException** is thrown after **sbt** tries to create a Unix domain socket and fails. In my specific environment, I was not able to create the sockets in some directories because they were mounted on an NFS. This prevented me from using any automated sbt command on any of those directories (Metals uses sbt under the hood, and it was not able to start because of the ServerAlreadyBootingException), which in turn resulted in me not being able to use Metals on a project that was created on any of those directories. **How is the issue solved in this PR?** If the `XDG_RUNTIME_DIR` environment variable is set, then sockets will be created in a folder with a hashed name, inside the directory `XDG_RUNTIME_DIR/.sbt/`. If this variable is not set, everything works exactly the same as always. Let's see an example: 1. My environment variable `XDG_RUNTIME_DIR` is set to /home/alonso/.runtime-dir` 2. I create my project in `/home/alonso/workspace/hello-world` 3. I run `sbt compile` 4. The socket is created in `/home/alonso/.runtime-dir/.sbt/sbt-socket102030405060/sbt-load.sock`. The number **102030405060** is a hash that is computed from the base directory of the project (it is actually the same hash that is produced in order to create sockets in Windows) and it will be different depending on the location of the project 5. The sbt command executed correctly, which would not have happened if the socket had been created in the `home/alonso/workspace` directory or any of its subdirectories (in this example, `/home/BlackDiamond/workspace` corresponds to a network file share) Co-authored-by: Alonso Montero --- .../java/sbt/internal/BootServerSocket.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/main-command/src/main/java/sbt/internal/BootServerSocket.java b/main-command/src/main/java/sbt/internal/BootServerSocket.java index beff97566..5cf91dc50 100644 --- a/main-command/src/main/java/sbt/internal/BootServerSocket.java +++ b/main-command/src/main/java/sbt/internal/BootServerSocket.java @@ -284,10 +284,11 @@ public class BootServerSocket implements AutoCloseable { public BootServerSocket(final AppConfiguration configuration) throws ServerAlreadyBootingException, IOException { final Path base = configuration.baseDirectory().toPath().toRealPath(); - final Path target = base.resolve("project").resolve("target"); if (!isWindows) { + final String actualSocketLocation = socketLocation(base); + final Path target = Paths.get(actualSocketLocation).getParent(); if (!Files.isDirectory(target)) Files.createDirectories(target); - socketFile = Paths.get(socketLocation(base)); + socketFile = Paths.get(actualSocketLocation); } else { socketFile = null; } @@ -301,13 +302,20 @@ public class BootServerSocket implements AutoCloseable { } } - public static String socketLocation(final Path base) throws UnsupportedEncodingException { + public static String socketLocation(final Path base) + throws UnsupportedEncodingException, IOException { final Path target = base.resolve("project").resolve("target"); + long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8")); if (isWindows) { - long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8")); return "sbt-load" + hash; } else { - return base.relativize(target.resolve("sbt-load.sock")).toString(); + final String alternativeSocketLocation = + System.getenv().getOrDefault("XDG_RUNTIME_DIR", "/tmp"); + final Path alternativeSocketLocationRoot = + Paths.get(alternativeSocketLocation).resolve(".sbt"); + final Path locationForSocket = alternativeSocketLocationRoot.resolve("sbt-socket" + hash); + final Path pathForSocket = locationForSocket.resolve("sbt-load.sock"); + return pathForSocket.toString(); } } From 120014bd65b7b9476a50768987004d42e1a7eeaf Mon Sep 17 00:00:00 2001 From: Alonso Montero <31372753+AlonsoM45@users.noreply.github.com> Date: Thu, 26 May 2022 21:10:41 -0600 Subject: [PATCH 38/42] Use XDG_RUNTIME_DIR environment variable to choose the path used for the creation of sockets (#6887) The `XDG_RUNTIME_DIR` environment variable will be used to choose the base directory in which the sockets will be created by **sbt**. This can help when issues such as #6777 appear. There are other related issues, such as #6101, [Metals issue #2235](https://github.com/scalameta/metals/issues/2235), [Che issue #18394](https://github.com/eclipse/che/issues/18394). Those are closed issues, but there are some cases in which the solution does not work (such as the case in #6777). Furthermore, the solution given seems more like a workaround than an actual fix. **What causes this issue?** At least in my case, the **ServerAlreadyBootingException** is thrown after **sbt** tries to create a Unix domain socket and fails. In my specific environment, I was not able to create the sockets in some directories because they were mounted on an NFS. This prevented me from using any automated sbt command on any of those directories (Metals uses sbt under the hood, and it was not able to start because of the ServerAlreadyBootingException), which in turn resulted in me not being able to use Metals on a project that was created on any of those directories. **How is the issue solved in this PR?** If the `XDG_RUNTIME_DIR` environment variable is set, then sockets will be created in a folder with a hashed name, inside the directory `XDG_RUNTIME_DIR/.sbt/`. If this variable is not set, everything works exactly the same as always. Let's see an example: 1. My environment variable `XDG_RUNTIME_DIR` is set to /home/alonso/.runtime-dir` 2. I create my project in `/home/alonso/workspace/hello-world` 3. I run `sbt compile` 4. The socket is created in `/home/alonso/.runtime-dir/.sbt/sbt-socket102030405060/sbt-load.sock`. The number **102030405060** is a hash that is computed from the base directory of the project (it is actually the same hash that is produced in order to create sockets in Windows) and it will be different depending on the location of the project 5. The sbt command executed correctly, which would not have happened if the socket had been created in the `home/alonso/workspace` directory or any of its subdirectories (in this example, `/home/BlackDiamond/workspace` corresponds to a network file share) Co-authored-by: Alonso Montero --- .../java/sbt/internal/BootServerSocket.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/main-command/src/main/java/sbt/internal/BootServerSocket.java b/main-command/src/main/java/sbt/internal/BootServerSocket.java index beff97566..5cf91dc50 100644 --- a/main-command/src/main/java/sbt/internal/BootServerSocket.java +++ b/main-command/src/main/java/sbt/internal/BootServerSocket.java @@ -284,10 +284,11 @@ public class BootServerSocket implements AutoCloseable { public BootServerSocket(final AppConfiguration configuration) throws ServerAlreadyBootingException, IOException { final Path base = configuration.baseDirectory().toPath().toRealPath(); - final Path target = base.resolve("project").resolve("target"); if (!isWindows) { + final String actualSocketLocation = socketLocation(base); + final Path target = Paths.get(actualSocketLocation).getParent(); if (!Files.isDirectory(target)) Files.createDirectories(target); - socketFile = Paths.get(socketLocation(base)); + socketFile = Paths.get(actualSocketLocation); } else { socketFile = null; } @@ -301,13 +302,20 @@ public class BootServerSocket implements AutoCloseable { } } - public static String socketLocation(final Path base) throws UnsupportedEncodingException { + public static String socketLocation(final Path base) + throws UnsupportedEncodingException, IOException { final Path target = base.resolve("project").resolve("target"); + long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8")); if (isWindows) { - long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8")); return "sbt-load" + hash; } else { - return base.relativize(target.resolve("sbt-load.sock")).toString(); + final String alternativeSocketLocation = + System.getenv().getOrDefault("XDG_RUNTIME_DIR", "/tmp"); + final Path alternativeSocketLocationRoot = + Paths.get(alternativeSocketLocation).resolve(".sbt"); + final Path locationForSocket = alternativeSocketLocationRoot.resolve("sbt-socket" + hash); + final Path pathForSocket = locationForSocket.resolve("sbt-load.sock"); + return pathForSocket.toString(); } } From 4bc880bfae5bc67b0866eeb978ad9ec92a74e3dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 04:02:43 +0000 Subject: [PATCH 39/42] Bump actions/setup-python from 3 to 4 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1215d9777..b2c6fc547 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: distribution: "${{ matrix.distribution }}" java-version: "${{ matrix.java }}" - name: Set up Python 3.7 - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: 3.7 - name: Coursier cache From c04b2a4f732de848fec564b8c4ec694a156d11c8 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 13 Jun 2022 00:52:32 -0400 Subject: [PATCH 40/42] lm 1.7.0-M1 This removes OkHttp dependency. This also removes an experimental feature to customize HTTP for Ivy called CustomHttp we added in sbt 1.3.0. Since LM got switched to Coursier in 1.3.0, I don't think we advertized CustomHttp. --- build.sbt | 1 + main/src/main/scala/sbt/Defaults.scala | 10 +++----- main/src/main/scala/sbt/Opts.scala | 6 +++++ .../main/scala/sbt/internal/CustomHttp.scala | 25 ------------------- .../main/scala/sbt/internal/RemoteCache.scala | 2 +- project/Dependencies.scala | 2 +- 6 files changed, 13 insertions(+), 33 deletions(-) delete mode 100644 main/src/main/scala/sbt/internal/CustomHttp.scala diff --git a/build.sbt b/build.sbt index f59529599..c1fbace0a 100644 --- a/build.sbt +++ b/build.sbt @@ -1057,6 +1057,7 @@ lazy val mainProj = (project in file("main")) exclude[DirectMissingMethodProblem]("sbt.Defaults.earlyArtifactPathSetting"), exclude[MissingClassProblem]("sbt.internal.server.BuildServerReporter$"), exclude[IncompatibleTemplateDefProblem]("sbt.internal.server.BuildServerReporter"), + exclude[MissingClassProblem]("sbt.internal.CustomHttp*"), ) ) .configure( diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 82724a3b5..8f10c9dba 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -43,7 +43,7 @@ import sbt.internal.librarymanagement.mavenint.{ PomExtraDependencyAttributes, SbtPomExtraProperties } -import sbt.internal.librarymanagement.{ CustomHttp => _, _ } +import sbt.internal.librarymanagement._ import sbt.internal.nio.{ CheckBuildSources, Globs } import sbt.internal.server.{ BspCompileProgress, @@ -258,8 +258,6 @@ object Defaults extends BuildCommon { artifactClassifier :== None, checksums := Classpaths.bootChecksums(appConfiguration.value), conflictManager := ConflictManager.default, - CustomHttp.okhttpClientBuilder :== CustomHttp.defaultHttpClientBuilder, - CustomHttp.okhttpClient := CustomHttp.okhttpClientBuilder.value.build, pomExtra :== NodeSeq.Empty, pomPostProcess :== idFun, pomAllRepositories :== false, @@ -2705,7 +2703,7 @@ object Defaults extends BuildCommon { def dependencyResolutionTask: Def.Initialize[Task[DependencyResolution]] = Def.taskIf { if (useCoursier.value) CoursierDependencyResolution(csrConfiguration.value) - else IvyDependencyResolution(ivyConfiguration.value, CustomHttp.okhttpClient.value) + else IvyDependencyResolution(ivyConfiguration.value) } } @@ -3129,7 +3127,7 @@ object Classpaths { else None }, dependencyResolution := dependencyResolutionTask.value, - publisher := IvyPublisher(ivyConfiguration.value, CustomHttp.okhttpClient.value), + publisher := IvyPublisher(ivyConfiguration.value), ivyConfiguration := mkIvyConfiguration.value, ivyConfigurations := { val confs = thisProject.value.configurations @@ -3432,7 +3430,7 @@ object Classpaths { private[sbt] def ivySbt0: Initialize[Task[IvySbt]] = Def.task { Credentials.register(credentials.value, streams.value.log) - new IvySbt(ivyConfiguration.value, CustomHttp.okhttpClient.value) + new IvySbt(ivyConfiguration.value) } def moduleSettings0: Initialize[Task[ModuleSettings]] = Def.task { val deps = allDependencies.value.toVector diff --git a/main/src/main/scala/sbt/Opts.scala b/main/src/main/scala/sbt/Opts.scala index 720fd0f93..25afca7fd 100644 --- a/main/src/main/scala/sbt/Opts.scala +++ b/main/src/main/scala/sbt/Opts.scala @@ -41,8 +41,14 @@ object Opts { } object resolver { import sbt.io.syntax._ + @deprecated("Use sonatypeOssReleases instead", "1.7.0") val sonatypeReleases = Resolver.sonatypeRepo("releases") + val sonatypeOssReleases = Resolver.sonatypeOssRepos("releases") + + @deprecated("Use sonatypeOssSnapshots instead", "1.7.0") val sonatypeSnapshots = Resolver.sonatypeRepo("snapshots") + val sonatypeOssSnapshots = Resolver.sonatypeOssRepos("snapshots") + val sonatypeStaging = MavenRepository( "sonatype-staging", "https://oss.sonatype.org/service/local/staging/deploy/maven2" diff --git a/main/src/main/scala/sbt/internal/CustomHttp.scala b/main/src/main/scala/sbt/internal/CustomHttp.scala deleted file mode 100644 index bc9a12ae2..000000000 --- a/main/src/main/scala/sbt/internal/CustomHttp.scala +++ /dev/null @@ -1,25 +0,0 @@ -/* - * sbt - * Copyright 2011 - 2018, Lightbend, Inc. - * Copyright 2008 - 2010, Mark Harrah - * Licensed under Apache License 2.0 (see LICENSE) - */ - -package sbt.internal - -import sbt.internal.librarymanagement.{ CustomHttp => LMCustomHttp } -import okhttp3._ - -import sbt.BuildSyntax._ -import sbt.KeyRanks._ - -object CustomHttp { - val okhttpClientBuilder = - settingKey[OkHttpClient.Builder]("Builder for the HTTP client.").withRank(CSetting) - val okhttpClient = - settingKey[OkHttpClient]("HTTP client used for library management.").withRank(CSetting) - - def defaultHttpClientBuilder: OkHttpClient.Builder = { - LMCustomHttp.defaultHttpClientBuilder - } -} diff --git a/main/src/main/scala/sbt/internal/RemoteCache.scala b/main/src/main/scala/sbt/internal/RemoteCache.scala index 200117de7..58e7b4b9c 100644 --- a/main/src/main/scala/sbt/internal/RemoteCache.scala +++ b/main/src/main/scala/sbt/internal/RemoteCache.scala @@ -139,7 +139,7 @@ object RemoteCache { ivySbt := { Credentials.register(credentials.value, streams.value.log) val config0 = ivyConfiguration.value - new IvySbt(config0, sbt.internal.CustomHttp.okhttpClient.value) + new IvySbt(config0) }, ) ) ++ inTask(pullRemoteCache)( diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 535f2e3bb..b84554c9f 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -14,7 +14,7 @@ object Dependencies { // sbt modules private val ioVersion = nightlyVersion.getOrElse("1.6.0") private val lmVersion = - sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.6.1") + sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.7.0-M1") val zincVersion = nightlyVersion.getOrElse("1.7.0-M2") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion From d5889d3ce36f21843f121ae817d2f5f3a710f4c7 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 12 Jun 2022 23:25:36 -0400 Subject: [PATCH 41/42] Bump to Scala 2.12.16 --- .github/workflows/ci.yml | 4 ++-- build.sbt | 2 +- main/src/main/scala/sbt/PluginCross.scala | 2 +- main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala | 2 +- project/Dependencies.scala | 4 ++-- project/build.properties | 2 +- sbt-app/src/sbt-test/actions/cross-advanced/build.sbt | 2 +- sbt-app/src/sbt-test/actions/cross-advanced/test | 2 +- sbt-app/src/sbt-test/compiler-project/run-test/build.sbt | 2 +- .../sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt | 2 +- sbt-app/src/sbt-test/dependency-graph/toFileSubTask/build.sbt | 2 +- sbt-app/src/sbt-test/project/sbt-plugin/build.sbt | 2 +- .../src/sbt-test/project/sbt-plugin/changes/oldSbtPlugin.sbt | 2 +- sbt-app/src/sbt-test/project/semanticdb/build.sbt | 2 +- sbt-app/src/sbt-test/project/unified/build.sbt | 2 +- sbt-app/src/sbt-test/source-dependencies/constants/test | 2 +- .../src/sbt-test/tests/scala-instance-classloader/build.sbt | 2 +- server-test/src/server-test/response/build.sbt | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad88219d2..06c63b5af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,8 +49,8 @@ jobs: env: JAVA_OPTS: -Xms800M -Xmx2G -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8 JVM_OPTS: -Xms800M -Xmx2G -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8 - SCALA_212: 2.12.15 - SCALA_213: 2.13.6 + SCALA_212: 2.12.16 + SCALA_213: 2.13.8 SCALA_3: 3.1.0 UTIL_TESTS: "utilCache/test utilControl/test utilInterface/test utilLogging/test utilPosition/test utilRelation/test utilScripted/test utilTracking/test" SBT_LOCAL: false diff --git a/build.sbt b/build.sbt index c1fbace0a..3168ba1dd 100644 --- a/build.sbt +++ b/build.sbt @@ -46,7 +46,7 @@ ThisBuild / resolvers += Resolver.mavenLocal Global / semanticdbEnabled := !(Global / insideCI).value // Change main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala too, if you change this. -Global / semanticdbVersion := "4.5.4" +Global / semanticdbVersion := "4.5.9" val excludeLint = SettingKey[Set[Def.KeyedInitialize[_]]]("excludeLintKeys") Global / excludeLint := (Global / excludeLint).?.value.getOrElse(Set.empty) Global / excludeLint += componentID diff --git a/main/src/main/scala/sbt/PluginCross.scala b/main/src/main/scala/sbt/PluginCross.scala index 98d5d57e1..740709b98 100644 --- a/main/src/main/scala/sbt/PluginCross.scala +++ b/main/src/main/scala/sbt/PluginCross.scala @@ -99,7 +99,7 @@ private[sbt] object PluginCross { VersionNumber(sv) match { case VersionNumber(Seq(0, 12, _*), _, _) => "2.9.2" case VersionNumber(Seq(0, 13, _*), _, _) => "2.10.7" - case VersionNumber(Seq(1, 0, _*), _, _) => "2.12.15" + case VersionNumber(Seq(1, 0, _*), _, _) => "2.12.16" case _ => sys.error(s"Unsupported sbt binary version: $sv") } } diff --git a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala index f8f2eebde..c1563c60d 100644 --- a/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala +++ b/main/src/main/scala/sbt/plugins/SemanticdbPlugin.scala @@ -26,7 +26,7 @@ object SemanticdbPlugin extends AutoPlugin { semanticdbEnabled := SysProp.semanticdb, semanticdbIncludeInJar := false, semanticdbOptions := List(), - semanticdbVersion := "4.5.4" + semanticdbVersion := "4.5.9" ) override lazy val projectSettings: Seq[Def.Setting[_]] = Seq( diff --git a/project/Dependencies.scala b/project/Dependencies.scala index b84554c9f..368646ed4 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -4,8 +4,8 @@ import sbt.contraband.ContrabandPlugin.autoImport._ object Dependencies { // WARNING: Please Scala update versions in PluginCross.scala too - val scala212 = "2.12.15" - val scala213 = "2.13.6" + val scala212 = "2.12.16" + val scala213 = "2.13.8" val checkPluginCross = settingKey[Unit]("Make sure scalaVersion match up") val baseScalaVersion = scala212 def nightlyVersion: Option[String] = diff --git a/project/build.properties b/project/build.properties index 77df8ac33..c8fcab543 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.4 \ No newline at end of file +sbt.version=1.6.2 diff --git a/sbt-app/src/sbt-test/actions/cross-advanced/build.sbt b/sbt-app/src/sbt-test/actions/cross-advanced/build.sbt index a77d7c0dd..91460f0e3 100644 --- a/sbt-app/src/sbt-test/actions/cross-advanced/build.sbt +++ b/sbt-app/src/sbt-test/actions/cross-advanced/build.sbt @@ -1,6 +1,6 @@ lazy val check = taskKey[Unit]("") lazy val compile2 = taskKey[Unit]("") -lazy val scala212 = "2.12.15" +lazy val scala212 = "2.12.16" lazy val root = (project in file(".")) .aggregate(foo, bar, client) diff --git a/sbt-app/src/sbt-test/actions/cross-advanced/test b/sbt-app/src/sbt-test/actions/cross-advanced/test index 5b3ab9f3b..5ee486310 100644 --- a/sbt-app/src/sbt-test/actions/cross-advanced/test +++ b/sbt-app/src/sbt-test/actions/cross-advanced/test @@ -17,7 +17,7 @@ ## test + with command or alias > clean ## for command cross building you do need crossScalaVerions on root -> set root/crossScalaVersions := Seq("2.12.15", "2.13.1") +> set root/crossScalaVersions := Seq("2.12.16", "2.13.1") > + build $ exists foo/target/scala-2.12 $ exists foo/target/scala-2.13 diff --git a/sbt-app/src/sbt-test/compiler-project/run-test/build.sbt b/sbt-app/src/sbt-test/compiler-project/run-test/build.sbt index 09ac3d406..f424c2d91 100644 --- a/sbt-app/src/sbt-test/compiler-project/run-test/build.sbt +++ b/sbt-app/src/sbt-test/compiler-project/run-test/build.sbt @@ -1,4 +1,4 @@ -ThisBuild / scalaVersion := "2.12.15" +ThisBuild / scalaVersion := "2.12.16" libraryDependencies ++= Seq( "com.novocode" % "junit-interface" % "0.5" % Test, diff --git a/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt b/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt index 3e9fa7240..f67a2c7ee 100644 --- a/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt +++ b/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt @@ -1,4 +1,4 @@ -ThisBuild / scalaVersion := "2.12.15" +ThisBuild / scalaVersion := "2.12.16" libraryDependencies ++= Seq( "org.slf4j" % "slf4j-api" % "1.7.2", diff --git a/sbt-app/src/sbt-test/dependency-graph/toFileSubTask/build.sbt b/sbt-app/src/sbt-test/dependency-graph/toFileSubTask/build.sbt index f830ec558..b8c0e1620 100644 --- a/sbt-app/src/sbt-test/dependency-graph/toFileSubTask/build.sbt +++ b/sbt-app/src/sbt-test/dependency-graph/toFileSubTask/build.sbt @@ -1,5 +1,5 @@ // ThisBuild / useCoursier := false -ThisBuild / scalaVersion := "2.12.15" +ThisBuild / scalaVersion := "2.12.16" ThisBuild / organization := "org.example" ThisBuild / version := "0.1" diff --git a/sbt-app/src/sbt-test/project/sbt-plugin/build.sbt b/sbt-app/src/sbt-test/project/sbt-plugin/build.sbt index bb26b40e0..1831f255c 100644 --- a/sbt-app/src/sbt-test/project/sbt-plugin/build.sbt +++ b/sbt-app/src/sbt-test/project/sbt-plugin/build.sbt @@ -1,6 +1,6 @@ lazy val root = project.in(file(".")) .enablePlugins(SbtPlugin) .settings( - scalaVersion := "2.12.15", + scalaVersion := "2.12.16", scalacOptions ++= Seq("-Xfatal-warnings", "-Xlint") ) diff --git a/sbt-app/src/sbt-test/project/sbt-plugin/changes/oldSbtPlugin.sbt b/sbt-app/src/sbt-test/project/sbt-plugin/changes/oldSbtPlugin.sbt index ce0acfbe0..03437f9da 100644 --- a/sbt-app/src/sbt-test/project/sbt-plugin/changes/oldSbtPlugin.sbt +++ b/sbt-app/src/sbt-test/project/sbt-plugin/changes/oldSbtPlugin.sbt @@ -1,6 +1,6 @@ lazy val root = project.in(file(".")) .settings( - scalaVersion := "2.12.15", + scalaVersion := "2.12.16", sbtPlugin := true, scalacOptions ++= Seq("-Xfatal-warnings", "-Xlint") ) diff --git a/sbt-app/src/sbt-test/project/semanticdb/build.sbt b/sbt-app/src/sbt-test/project/semanticdb/build.sbt index 3a76b7064..8c8a5b3d2 100644 --- a/sbt-app/src/sbt-test/project/semanticdb/build.sbt +++ b/sbt-app/src/sbt-test/project/semanticdb/build.sbt @@ -1,4 +1,4 @@ -ThisBuild / scalaVersion := "2.12.15" +ThisBuild / scalaVersion := "2.12.16" ThisBuild / semanticdbEnabled := true ThisBuild / semanticdbIncludeInJar := true diff --git a/sbt-app/src/sbt-test/project/unified/build.sbt b/sbt-app/src/sbt-test/project/unified/build.sbt index 11d0eb84e..8210ad038 100644 --- a/sbt-app/src/sbt-test/project/unified/build.sbt +++ b/sbt-app/src/sbt-test/project/unified/build.sbt @@ -1,4 +1,4 @@ -ThisBuild / scalaVersion := "2.12.15" +ThisBuild / scalaVersion := "2.12.16" import sbt.internal.CommandStrings.{ inspectBrief, inspectDetailed } import sbt.internal.Inspect diff --git a/sbt-app/src/sbt-test/source-dependencies/constants/test b/sbt-app/src/sbt-test/source-dependencies/constants/test index bc2cb09c9..b1e725f26 100644 --- a/sbt-app/src/sbt-test/source-dependencies/constants/test +++ b/sbt-app/src/sbt-test/source-dependencies/constants/test @@ -1,4 +1,4 @@ -> ++2.12.15! +> ++2.12.16! $ copy-file changes/B.scala B.scala diff --git a/sbt-app/src/sbt-test/tests/scala-instance-classloader/build.sbt b/sbt-app/src/sbt-test/tests/scala-instance-classloader/build.sbt index b099f2338..1f8431d46 100644 --- a/sbt-app/src/sbt-test/tests/scala-instance-classloader/build.sbt +++ b/sbt-app/src/sbt-test/tests/scala-instance-classloader/build.sbt @@ -3,7 +3,7 @@ import sbt.internal.inc.ScalaInstance lazy val OtherScala = config("other-scala").hide lazy val junitinterface = "com.novocode" % "junit-interface" % "0.11" lazy val akkaActor = "com.typesafe.akka" %% "akka-actor" % "2.5.17" -ThisBuild / scalaVersion := "2.12.15" +ThisBuild / scalaVersion := "2.12.16" lazy val root = (project in file(".")) .configs(OtherScala) diff --git a/server-test/src/server-test/response/build.sbt b/server-test/src/server-test/response/build.sbt index 1f18c7ab3..90f7f9f8d 100644 --- a/server-test/src/server-test/response/build.sbt +++ b/server-test/src/server-test/response/build.sbt @@ -1,6 +1,6 @@ import sbt.internal.server.{ ServerHandler, ServerIntent } -ThisBuild / scalaVersion := "2.12.15" +ThisBuild / scalaVersion := "2.12.16" Global / serverLog / logLevel := Level.Debug // custom handler From d9e43ecfdfac9ab2523803d77c7e07bd80a1d392 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 12 Jun 2022 23:11:28 -0400 Subject: [PATCH 42/42] Revert "Add support for scala-output-version flag in Scala 3" This reverts commit 1e89d713111fc48c11a1a102b4d70e4df0374078. --- main/src/main/scala/sbt/Defaults.scala | 80 ++----------- main/src/main/scala/sbt/Keys.scala | 6 +- .../scala/sbt/internal/ClassLoaders.scala | 4 +- .../build.sbt | 30 ----- .../scala-output-version-redundant-flags/test | 3 - .../scala-output-version/Bar.scala | 5 - .../scala-output-version/build.sbt | 112 ------------------ .../foo/src/main/scala-2.13/Foo.scala | 11 -- .../foo/src/main/scala-3/Foo.scala | 17 --- .../foo/src/test/scala-2.13/FooTest.scala | 7 -- .../foo/src/test/scala-3/FooTest.scala | 19 --- .../scala-output-version/test | 35 ------ 12 files changed, 12 insertions(+), 317 deletions(-) delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/build.sbt delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/test delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/Bar.scala delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/build.sbt delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-2.13/Foo.scala delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-3/Foo.scala delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-2.13/FooTest.scala delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-3/FooTest.scala delete mode 100644 sbt-app/src/sbt-test/dependency-management/scala-output-version/test diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 8f10c9dba..6e4746a53 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -677,15 +677,6 @@ object Defaults extends BuildCommon { else topLoader }, scalaInstance := scalaInstanceTask.value, - runtimeScalaInstance := Def.taskDyn { - scalaOutputVersion.?.value - .map { version => - scalaInstanceTask0(version = version, isRuntimeInstance = true) - } - .getOrElse { - scalaInstance - } - }.value, crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled), pluginCrossBuild / sbtBinaryVersion := binarySbtVersion( (pluginCrossBuild / sbtVersion).value @@ -984,49 +975,6 @@ object Defaults extends BuildCommon { old ++ Seq("-Wconf:cat=unused-nowarn:s", "-Xsource:3") else old }, - scalacOptions := { - val old = scalacOptions.value - - // 3 possible sources of Scala output version - val fromCompiler = CrossVersion - .partialVersion(scalaVersion.value) - .map { case (major, minor) => s"${major}.${minor}" } - .getOrElse( - sys.error(s"Wrong value of `scalaVersion`: ${scalaVersion.value}") - ) - - val maybeFromSetting = scalaOutputVersion.?.value.map { version => - CrossVersion - .partialVersion(version) - .map { case (major, minor) => s"${major}.${minor}" } - .getOrElse( - sys.error(s"Wrong value of `scalaOutputVersion`: ${version}") - ) - } - - val maybeFromFlags = old.zipWithIndex.flatMap { - case (opt, idx) => - if (opt.startsWith("-scala-output-version:")) - Some(opt.stripPrefix("-scala-output-version:")) - else if (opt == "-scala-output-version" && idx + 1 < old.length) - Some(old(idx + 1)) - else None - }.lastOption - - // Add -scala-output-version flag when minor Scala versions are different - // unless the flag is already set properly - maybeFromSetting match { - case Some(fromSetting) if fromSetting != fromCompiler => - maybeFromFlags match { - case Some(fromFlags) if fromFlags == fromSetting => - old - case _ => - old ++ Seq("-scala-output-version", fromSetting) - } - case _ => - old - } - }, persistJarClasspath :== true, classpathEntryDefinesClassVF := { (if (persistJarClasspath.value) classpathDefinesClassCache.value @@ -1137,19 +1085,13 @@ object Defaults extends BuildCommon { } def scalaInstanceTask: Initialize[Task[ScalaInstance]] = Def.taskDyn { - scalaInstanceTask0(scalaVersion.value, false) - } - - private def scalaInstanceTask0( - version: String, - isRuntimeInstance: Boolean - ): Initialize[Task[ScalaInstance]] = Def.taskDyn { // if this logic changes, ensure that `unmanagedScalaInstanceOnly` and `update` are changed // appropriately to avoid cycles scalaHome.value match { case Some(h) => scalaInstanceFromHome(h) case None => val scalaProvider = appConfiguration.value.provider.scalaProvider + val version = scalaVersion.value if (version == scalaProvider.version) // use the same class loader as the Scala classes used by sbt Def.task { val allJars = scalaProvider.jars @@ -1167,7 +1109,7 @@ object Defaults extends BuildCommon { case _ => ScalaInstance(version, scalaProvider) } } else - scalaInstanceFromUpdate0(isRuntimeInstance) + scalaInstanceFromUpdate } } @@ -1188,29 +1130,22 @@ object Defaults extends BuildCommon { pre + post } - def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = scalaInstanceFromUpdate0(false) - - private def scalaInstanceFromUpdate0( - isRuntimeInstance: Boolean - ): Initialize[Task[ScalaInstance]] = Def.task { + def scalaInstanceFromUpdate: Initialize[Task[ScalaInstance]] = Def.task { val sv = scalaVersion.value val fullReport = update.value val toolReport = fullReport .configuration(Configurations.ScalaTool) .getOrElse(sys.error(noToolConfiguration(managedScalaInstance.value))) - lazy val runtimeReport = fullReport.configuration(Configurations.Runtime).get - val libraryReport = if (isRuntimeInstance) runtimeReport else toolReport - def libraryFile(id: String): File = { + def file(id: String): File = { val files = for { - m <- libraryReport.modules if m.module.name.startsWith(id) + m <- toolReport.modules if m.module.name.startsWith(id) (art, file) <- m.artifacts if art.`type` == Artifact.DefaultType } yield file files.headOption getOrElse sys.error(s"Missing $id jar file") } - val libraryJars = ScalaArtifacts.libraryIds(sv).map(libraryFile) val allCompilerJars = toolReport.modules.flatMap(_.artifacts.map(_._2)) val allDocJars = fullReport @@ -1218,6 +1153,7 @@ object Defaults extends BuildCommon { .toSeq .flatMap(_.modules) .flatMap(_.artifacts.map(_._2)) + val libraryJars = ScalaArtifacts.libraryIds(sv).map(file) makeScalaInstance( sv, @@ -2096,7 +2032,7 @@ object Defaults extends BuildCommon { def runnerInit: Initialize[Task[ScalaRun]] = Def.task { val tmp = taskTemporaryDirectory.value val resolvedScope = resolvedScoped.value.scope - val si = runtimeScalaInstance.value + val si = scalaInstance.value val s = streams.value val opts = forkOptions.value val options = javaOptions.value @@ -3323,7 +3259,7 @@ object Classpaths { autoScalaLibrary.value && scalaHome.value.isEmpty && managedScalaInstance.value, sbtPlugin.value, scalaOrganization.value, - scalaOutputVersion.?.value.getOrElse(scalaVersion.value) + scalaVersion.value ), // Override the default to handle mixing in the sbtPlugin + scala dependencies. allDependencies := { diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 68332cd13..392812271 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -186,11 +186,9 @@ object Keys { val compileOptions = taskKey[CompileOptions]("Collects basic options to configure compilers").withRank(DTask) val compileInputs = taskKey[Inputs]("Collects all inputs needed for compilation.").withRank(DTask) val scalaHome = settingKey[Option[File]]("If Some, defines the local Scala installation to use for compilation, running, and testing.").withRank(ASetting) - val scalaInstance = taskKey[ScalaInstance]("Defines the Scala instance to use for compilation").withRank(DTask) - val runtimeScalaInstance = taskKey[ScalaInstance]("Defines the Scala instance used at runtime (also for tests).").withRank(DTask) + val scalaInstance = taskKey[ScalaInstance]("Defines the Scala instance to use for compilation, running, and testing.").withRank(DTask) val scalaOrganization = settingKey[String]("Organization/group ID of the Scala used in the project. Default value is 'org.scala-lang'. This is an advanced setting used for clones of the Scala Language. It should be disregarded in standard use cases.").withRank(CSetting) - val scalaVersion = settingKey[String]("The version of Scala compiler used for building this project.").withRank(APlusSetting) - val scalaOutputVersion = settingKey[String]("The version of Scala standard library used for running this project and declared as its transitive dependency.").withRank(APlusSetting) + val scalaVersion = settingKey[String]("The version of Scala used for building.").withRank(APlusSetting) val scalaBinaryVersion = settingKey[String]("The Scala version substring describing binary compatibility.").withRank(BPlusSetting) val crossScalaVersions = settingKey[Seq[String]]("The versions of Scala used when cross-building.").withRank(BPlusSetting) val crossVersion = settingKey[CrossVersion]("Configures handling of the Scala version when cross-building.").withRank(CSetting) diff --git a/main/src/main/scala/sbt/internal/ClassLoaders.scala b/main/src/main/scala/sbt/internal/ClassLoaders.scala index 0275ae9dd..1c5df8aa0 100644 --- a/main/src/main/scala/sbt/internal/ClassLoaders.scala +++ b/main/src/main/scala/sbt/internal/ClassLoaders.scala @@ -35,7 +35,7 @@ private[sbt] object ClassLoaders { * Get the class loader for a test task. The configuration could be IntegrationTest or Test. */ private[sbt] def testTask: Def.Initialize[Task[ClassLoader]] = Def.task { - val si = runtimeScalaInstance.value + val si = scalaInstance.value val cp = fullClasspath.value.map(_.data) val dependencyStamps = modifiedTimes((dependencyClasspathFiles / outputFileStamps).value).toMap def getLm(f: File): Long = dependencyStamps.getOrElse(f, IO.getModifiedTimeOrZero(f)) @@ -64,7 +64,7 @@ private[sbt] object ClassLoaders { private[sbt] def runner: Def.Initialize[Task[ScalaRun]] = Def.taskDyn { val resolvedScope = resolvedScoped.value.scope - val instance = runtimeScalaInstance.value + val instance = scalaInstance.value val s = streams.value val opts = forkOptions.value val options = javaOptions.value diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/build.sbt b/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/build.sbt deleted file mode 100644 index e1bc21ae3..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/build.sbt +++ /dev/null @@ -1,30 +0,0 @@ -val checkOptions = taskKey[Unit]("") - -lazy val p1 = project - .settings( - scalaVersion := "3.0.2", - checkOptions := { - assert((Compile / scalacOptions).value == Seq()) - assert((Test / scalacOptions).value == Seq()) - } - ) - -lazy val p2 = project - .settings( - scalaVersion := "3.0.2", - scalaOutputVersion := "3.0.2", - checkOptions := { - assert((Compile / scalacOptions).value == Seq()) - assert((Test / scalacOptions).value == Seq()) - } - ) - -lazy val p3 = project - .settings( - scalaVersion := "3.1.2-RC2", - scalaOutputVersion := "3.0.2", - checkOptions := { - assert((Compile / scalacOptions).value == Seq("-scala-output-version", "3.0")) - assert((Test / scalacOptions).value == Seq("-scala-output-version", "3.0")) - } - ) diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/test b/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/test deleted file mode 100644 index 500721a31..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version-redundant-flags/test +++ /dev/null @@ -1,3 +0,0 @@ -> p1 / checkOptions -> p2 / checkOptions -> p3 / checkOptions \ No newline at end of file diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/Bar.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/Bar.scala deleted file mode 100644 index 772478e95..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version/Bar.scala +++ /dev/null @@ -1,5 +0,0 @@ -object Bar { - def main(args: Array[String]) = { - assert(foo.main.Foo.numbers == Seq(1, 2, 3)) - } -} diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/build.sbt b/sbt-app/src/sbt-test/dependency-management/scala-output-version/build.sbt deleted file mode 100644 index 78ad544f4..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version/build.sbt +++ /dev/null @@ -1,112 +0,0 @@ -// cases 1, 2, 3: check for scala version in bar -// case a: check locally published Ivy dependency -// case b: check locally published Maven dependency -// case c: check unpublished sibling module dependency - -val org = "org.example" -val fooName = "sbt-test-scala-output-version-foo" -val revision = "0.0.1-SNAPSHOT" - -ThisBuild / organization := org -ThisBuild / version := revision - -lazy val foo = project.in(file("foo")) - .settings( - name := fooName, - scalaVersion := "3.1.2-RC2", - crossScalaVersions := List("2.13.8", "3.1.2-RC2"), - scalaOutputVersion := "3.0.2", - scalaOutputVersion := { - CrossVersion.partialVersion(scalaVersion.value) match { - case Some((3, _)) => "3.0.2" - case _ => scalaVersion.value - } - }, - libraryDependencies ++= Seq( - "org.scalameta" %% "munit" % "0.7.29" % Test - ), - TaskKey[Unit]("checkIvy") := { - val ivyFile = makeIvyXml.value - val ivyContent = IO.read(ivyFile) - val expectedContent = """""" - val hasCorrectStdlib = ivyContent.contains(expectedContent) - if (!hasCorrectStdlib) sys.error(s"The produced Ivy file is incorrect:\n\n${ivyContent}") - }, - TaskKey[Unit]("checkPom") := { - val pomFile = makePom.value - val pomContent = IO.read(pomFile) - val flatPom = pomContent.filterNot(_.isWhitespace) - val expectedContent = "org.scala-langscala3-library_33.0.2" - val hasCorrectStdlib = flatPom.contains(expectedContent) - if (!hasCorrectStdlib) sys.error(s"The produced POM file is incorrect:\n\n${pomContent}") - } - ) - -val scala3_1 = Seq(scalaVersion := "3.1.1") -val scala3_0 = Seq(scalaVersion := "3.0.2") -val scala2_13 = Seq(scalaVersion := "2.13.8") -val ivyFooDep = Seq( - libraryDependencies ++= Seq( - org %% fooName % revision - ), - resolvers := Seq(Resolver.defaultLocal) -) -val mavenFooDep = Seq( - libraryDependencies ++= Seq( - org %% fooName % revision - ), - resolvers := Seq(Resolver.mavenLocal) -) - -lazy val bar1a = project.in(file("bar1a")) - .settings( - scala3_1, - ivyFooDep - ) - -lazy val bar1b = project.in(file("bar1b")) - .settings( - scala3_1, - mavenFooDep - ) - -lazy val bar1c = project.in(file("bar1c")) - .settings( - scala3_1, - ).dependsOn(foo) - - -lazy val bar2a = project.in(file("bar2a")) - .settings( - scala3_0, - ivyFooDep - ) - -lazy val bar2b = project.in(file("bar2b")) - .settings( - scala3_0, - mavenFooDep - ) - -lazy val bar2c = project.in(file("bar2c")) - .settings( - scala3_0, - ).dependsOn(foo) - - -lazy val bar3a = project.in(file("bar3a")) - .settings( - scala2_13, - ivyFooDep - ) - -lazy val bar3b = project.in(file("bar3b")) - .settings( - scala2_13, - mavenFooDep - ) - -lazy val bar3c = project.in(file("bar3c")) - .settings( - scala2_13, - ).dependsOn(foo) diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-2.13/Foo.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-2.13/Foo.scala deleted file mode 100644 index 6347cd083..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-2.13/Foo.scala +++ /dev/null @@ -1,11 +0,0 @@ -package foo.main - -object Foo { - val numbers = Seq(1, 2, 3) -} - -object Run { - def main(args: Array[String]) = { - assert(Foo.numbers.length == 3) - } -} diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-3/Foo.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-3/Foo.scala deleted file mode 100644 index 11ec280a3..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/main/scala-3/Foo.scala +++ /dev/null @@ -1,17 +0,0 @@ -package foo.main - -class MyException extends Exception("MyException") - -@annotation.experimental -object Exceptional: - import language.experimental.saferExceptions - def foo(): Unit throws MyException = // this requires at least 3.1.x to compile - throw new MyException - -object Foo: - val numbers = Seq(1, 2, 3) - -@main def run() = - val canEqualMethods = classOf[CanEqual.type].getMethods.toList - assert( canEqualMethods.exists(_.getName == "canEqualSeq")) // since 3.0.x - assert(!canEqualMethods.exists(_.getName == "canEqualSeqs")) // since 3.1.x diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-2.13/FooTest.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-2.13/FooTest.scala deleted file mode 100644 index 4102861ae..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-2.13/FooTest.scala +++ /dev/null @@ -1,7 +0,0 @@ -package foo.test - -class FooTest extends munit.FunSuite { - test("foo") { - assertEquals(foo.main.Foo.numbers, Seq(1, 2, 3)) - } -} diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-3/FooTest.scala b/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-3/FooTest.scala deleted file mode 100644 index cc0ee76b6..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version/foo/src/test/scala-3/FooTest.scala +++ /dev/null @@ -1,19 +0,0 @@ -package foo.test - -class MyException extends Exception("MyException") - -@annotation.experimental -object Exceptional: - import language.experimental.saferExceptions - def foo(): Unit throws MyException = // this requires at least 3.1.x to compile - throw new MyException - - -class FooTest extends munit.FunSuite: - test("foo") { - assertEquals(foo.main.Foo.numbers, Seq(1, 2, 3)) - - val canEqualMethods = classOf[CanEqual.type].getMethods.toList - assert( canEqualMethods.exists(_.getName == "canEqualSeq")) // since 3.0.x - assert(!canEqualMethods.exists(_.getName == "canEqualSeqs")) // since 3.1.x - } diff --git a/sbt-app/src/sbt-test/dependency-management/scala-output-version/test b/sbt-app/src/sbt-test/dependency-management/scala-output-version/test deleted file mode 100644 index ee66638fb..000000000 --- a/sbt-app/src/sbt-test/dependency-management/scala-output-version/test +++ /dev/null @@ -1,35 +0,0 @@ -$ copy-file Bar.scala bar1a/src/main/scala/Bar.scala -$ copy-file Bar.scala bar1b/src/main/scala/Bar.scala -$ copy-file Bar.scala bar1c/src/main/scala/Bar.scala -$ copy-file Bar.scala bar2a/src/main/scala/Bar.scala -$ copy-file Bar.scala bar2b/src/main/scala/Bar.scala -$ copy-file Bar.scala bar2c/src/main/scala/Bar.scala -$ copy-file Bar.scala bar3a/src/main/scala/Bar.scala -$ copy-file Bar.scala bar3b/src/main/scala/Bar.scala -$ copy-file Bar.scala bar3c/src/main/scala/Bar.scala - -> ++3.1.2-RC2 -> foo / compile -> foo / run -> foo / test -> foo / publishLocal -> foo / checkIvy -> foo / publishM2 -> foo / checkPom - -> ++2.13.8 -> foo / compile -> foo / run -> foo / test -> foo / publishLocal -> foo / publishM2 - -> bar1a / run -> bar1b / run -> bar1c / run -> bar2a / run -> bar2b / run -> bar2c / run -> bar3a / run -> bar3b / run -> bar3c / run