From 98a65b124ea8734afbe943dbe0440c2dfc09bb20 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 19 Sep 2021 20:14:44 -0400 Subject: [PATCH 001/120] Bump the builtin_sbt_version to 1.5.5 --- sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbt b/sbt index ad0edeb37..3c20ecc21 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.5.4" +declare builtin_sbt_version="1.5.5" declare -a residual_args declare -a java_args declare -a scalac_args From 0c3b76cbf2e0bac94763df8a876f641db0280dd2 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 25 Sep 2021 19:22:20 -0400 Subject: [PATCH 002/120] Eclipse Temurin 17 --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 980202e19..1b88483b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,19 +10,19 @@ jobs: matrix: include: - os: ubuntu-latest - java: "17.0-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz" + java: "17.0-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" jobtype: 1 - os: ubuntu-latest - java: "17.0-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz" + java: "17.0-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" jobtype: 2 - os: ubuntu-latest - java: "17.0-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz" + java: "17.0-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" jobtype: 3 - os: ubuntu-latest - java: "17.0-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz" + java: "17.0-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" jobtype: 4 - os: ubuntu-latest - java: "17-custom=tgz+https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz" + java: "17-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" jobtype: 5 - os: ubuntu-latest java: "adopt@1.8" From fcd7a3bef2b83eb45666033085b4de370980a2bc Mon Sep 17 00:00:00 2001 From: Nima Taheri Date: Mon, 27 Sep 2021 22:13:12 -0700 Subject: [PATCH 003/120] Handle cycles while rendering json dependency tree to json --- .../internal/graph/rendering/TreeView.scala | 40 +++++++++----- .../graph/rendering/TreeViewTest.scala | 55 +++++++++++++++++++ 2 files changed, 81 insertions(+), 14 deletions(-) create mode 100644 main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala diff --git a/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala b/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala index d5732f5b7..f3cd7b4f7 100644 --- a/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala +++ b/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala @@ -10,14 +10,17 @@ package internal package graph package rendering -import java.io.{ OutputStream, InputStream, FileOutputStream, File } -import java.net.URI - -import graph.{ Module, ModuleGraph } import sbt.io.IO -import scala.annotation.{ nowarn, tailrec } -import scala.util.parsing.json.{ JSONArray, JSONObject } +import java.io.File +import java.io.FileOutputStream +import java.io.InputStream +import java.io.OutputStream +import java.net.URI +import scala.annotation.nowarn +import scala.annotation.tailrec +import scala.util.parsing.json.JSONArray +import scala.util.parsing.json.JSONObject @nowarn object TreeView { def createJson(graph: ModuleGraph): String = { @@ -36,18 +39,27 @@ import scala.util.parsing.json.{ JSONArray, JSONObject } new URI(graphHTML.toURI.toString) } - private def processSubtree(graph: ModuleGraph, module: Module): JSONObject = { - val children = graph.dependencyMap - .getOrElse(module.id, List()) - .map(module => processSubtree(graph, module)) - .toList - moduleAsJson(module, children) + private[rendering] def processSubtree( + graph: ModuleGraph, + module: Module, + parents: Set[GraphModuleId] = Set() + ): JSONObject = { + val cycle = parents.contains(module.id) + val dependencies = if (cycle) List() else graph.dependencyMap.getOrElse(module.id, List()) + val children = + dependencies.map(dependency => processSubtree(graph, dependency, parents + module.id)).toList + moduleAsJson(module, cycle, children) } - private def moduleAsJson(module: Module, children: List[JSONObject]): JSONObject = { + private def moduleAsJson( + module: Module, + isCycle: Boolean, + children: List[JSONObject] + ): JSONObject = { val eviction = module.evictedByVersion.map(version => s" (evicted by $version)").getOrElse("") + val cycle = if (isCycle) " (cycle)" else "" val error = module.error.map(err => s" (errors: $err)").getOrElse("") - val text = module.id.idString + eviction + error + val text = module.id.idString + eviction + error + cycle JSONObject(Map("text" -> text, "children" -> JSONArray(children))) } diff --git a/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala b/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala new file mode 100644 index 000000000..544629e16 --- /dev/null +++ b/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala @@ -0,0 +1,55 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt +package internal +package graph +package rendering + +import org.scalatest.DiagrammedAssertions +import org.scalatest.FunSuite + +import scala.annotation.nowarn +import scala.util.parsing.json.JSONArray +import scala.util.parsing.json.JSONObject + +@nowarn("msg=class JSONObject in package json is deprecated") +class TreeViewTest extends FunSuite with DiagrammedAssertions { + + val modA = GraphModuleId("orgA", "nameA", "1.0") + val modB = GraphModuleId("orgB", "nameB", "2.0") + + val graph = ModuleGraph( + nodes = Seq(Module(modA), Module(modB)), + edges = Seq( + modA -> modA, + modA -> modB, + ) + ) + + test("TreeView should detect cycles and truncate") { + val json = TreeView.processSubtree(graph, Module(modA)) + val (rootText, children) = parseTree(json) + assert(rootText == modA.idString) + + val childrenText = children.map(parseTree).map(_._1) + val expected = List(s"${modA.idString} (cycle)", modB.idString) + assert(childrenText == expected) + } + + @nowarn("cat=unchecked") + def parseTree(json: JSONObject): (String, List[JSONObject]) = { + (json.obj.get("text"), json.obj.get("children")) match { + case (Some(text: String), Some(JSONArray(children: List[JSONObject]))) + if children.forall(_.isInstanceOf[JSONObject]) => + text -> children + case _ => + fail("a string field 'text' and an array of objects in 'children' field were expected!") + } + } + +} From 804bd4b8b54f0b5e63d6d97b4a3f10dda55349dc Mon Sep 17 00:00:00 2001 From: Eric Peters Date: Wed, 29 Sep 2021 07:34:20 -0700 Subject: [PATCH 004/120] Rename internal/util-logging/src/main/scala/sbt/internal/util/MainLogging.scala to MainAppender.scala to match contents --- .../sbt/internal/util/{MainLogging.scala => MainAppender.scala} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename internal/util-logging/src/main/scala/sbt/internal/util/{MainLogging.scala => MainAppender.scala} (100%) diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/MainLogging.scala b/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala similarity index 100% rename from internal/util-logging/src/main/scala/sbt/internal/util/MainLogging.scala rename to internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala From c1ed109f8927cf8b1815c50ac45444cfd7cc76d3 Mon Sep 17 00:00:00 2001 From: Eric Peters Date: Wed, 29 Sep 2021 07:39:09 -0700 Subject: [PATCH 005/120] Update MainAppender.defaulScreen to use passed in console arg #6678 --- .../src/main/scala/sbt/internal/util/MainAppender.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala b/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala index db5d2e25e..96bc84435 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala @@ -75,7 +75,7 @@ object MainAppender { ): Appender = { ConsoleAppender( ConsoleAppender.generateName, - Terminal.get, + console, suppressedMessage = suppressedMessage ) } From 24e7398b5bd67a111fb5ecec6e77c7f024b8efd7 Mon Sep 17 00:00:00 2001 From: kxbmap Date: Sat, 2 Oct 2021 16:55:08 +0900 Subject: [PATCH 006/120] Add Windows Java home selectors for some distributions that provides an installer - Eclipse Temurin - IBM Semeru Runtimes - Microsoft Build of OpenJDK - Amazon Corretto - Azul Zulu Builds of OpenJDK - Liberica JDK --- .../main/scala/sbt/internal/CrossJava.scala | 36 ++++++++++++++----- .../scala/sbt/internal/CrossJavaTest.scala | 10 ++++++ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/main/src/main/scala/sbt/internal/CrossJava.scala b/main/src/main/scala/sbt/internal/CrossJava.scala index 4764fc829..a16aca956 100644 --- a/main/src/main/scala/sbt/internal/CrossJava.scala +++ b/main/src/main/scala/sbt/internal/CrossJava.scala @@ -12,7 +12,7 @@ import java.io.File import scala.collection.immutable.ListMap import scala.annotation.tailrec import scala.util.{ Try, Success, Failure } -import sbt.io.Path +import sbt.io.{ IO, Path } import sbt.io.syntax._ import sbt.Cross._ import sbt.Def.{ ScopedKey, Setting } @@ -389,7 +389,7 @@ private[sbt] object CrossJava { object JavaDiscoverConfig { object JavaHomeDir { - private val regex = """(\w+-)?(java-|(?:adoptopen)?jdk-?)(bin-)?(1\.)?([0-9]+).*""".r + private val regex = """(\w+-)??(java-|(?:adoptopen)?jdk-?)?(bin-)?(1\.)?([0-9]+).*""".r def unapply(s: CharSequence): Option[String] = { s match { case regex(vendor, _, _, m, n) => Some(JavaVersion(nullBlank(m) + n).toString) @@ -447,15 +447,21 @@ private[sbt] object CrossJava { }.flatten } - class WindowsDiscoverConfig(base: File) extends JavaDiscoverConf { + class WindowsDiscoverConfig(base: File, vendors: Seq[String] = Seq.empty) + extends JavaDiscoverConf { def candidates() = wrapNull(base.list()) def javaHomes: Vector[(String, File)] = candidates() .collect { - case dir @ JavaHomeDir(version) => - version -> (base / dir) + case dir @ JavaHomeDir(version) => version -> base / dir + } + .flatMap { + case x if vendors.isEmpty => Vector(x) + case (version, home) => + val jv = JavaVersion(version) + vendors.map(jv.withVendor(_).toString -> home) } } @@ -482,10 +488,24 @@ private[sbt] object CrossJava { new LinuxDiscoverConfig(file("/usr") / "java"), new LinuxDiscoverConfig(file("/usr") / "lib" / "jvm"), new MacOsDiscoverConfig, - new WindowsDiscoverConfig(file("C://Program Files/Java")), - new WindowsDiscoverConfig(file("C://Program Files (x86)/Java")), new JavaHomeDiscoverConfig, - ) + ) ++ { + if (IO.isWindows) { + def discover(dir: String, vendors: String*) = new WindowsDiscoverConfig(file(dir), vendors) + Vector( + discover("C://Program Files/Java", "openjdk"), + discover("C://Program Files/Eclipse Foundation", "temurin", "adopt"), + discover("C://Program Files/Semeru", "semeru", "adopt-openj9"), + discover("C://Program Files/Microsoft", "microsoft"), + discover("C://Program Files/Amazon Corretto", "amazon-corretto"), + discover("C://Program Files/Zulu", "zulu"), + discover("C://Program Files/BellSoft", "liberica"), + discover("C://Program Files (x86)/Java", "openjdk"), + discover("C://Program Files (x86)/Eclipse Foundation", "temurin", "adopt"), + discover("C://Program Files (x86)/Semeru", "semeru", "adopt-openj9"), + ) + } else Vector.empty + } } def nullBlank(s: String): String = diff --git a/main/src/test/scala/sbt/internal/CrossJavaTest.scala b/main/src/test/scala/sbt/internal/CrossJavaTest.scala index b7a21fdf6..cd0caa645 100644 --- a/main/src/test/scala/sbt/internal/CrossJavaTest.scala +++ b/main/src/test/scala/sbt/internal/CrossJavaTest.scala @@ -59,6 +59,16 @@ class CrossJavaTest extends FunSuite with DiagrammedAssertions { assert(file.getName == "jdk1.7.0") } + test("The Windows Java home selector should correctly pick up a JDK with vendors") { + val conf = new WindowsDiscoverConfig(sbt.io.syntax.file("."), Seq("xxx", "yyy")) { + override def candidates() = Vector("jdk1.7.0") + } + val homes = conf.javaHomes + assert(homes.size == 2) + assert(homes.map(_._1) == Vector("xxx@1.7", "yyy@1.7")) + assert(homes.map(_._2.getName).forall(_ == "jdk1.7.0")) + } + test("The JAVA_HOME selector should correctly pick up a JDK") { val conf = new JavaHomeDiscoverConfig { override def home() = Some("/opt/jdk8") From 59f178a4c4bfafe1132672bcc2382ef9741ddf5a Mon Sep 17 00:00:00 2001 From: kxbmap Date: Mon, 27 Sep 2021 20:45:57 +0900 Subject: [PATCH 007/120] Make javaHome that forks scripted tests configurable Normally scripted tests are forked using the JVM that is running sbt. If set `scripted / javaHome`, forked using it. ``` scripted / javaHome := Some(file("/path/to/jdk-x.y.z")) ``` Or use `java++` command before scripted. ``` sbt> java++ 11! sbt> scripted ``` --- main/src/main/scala/sbt/ScriptedPlugin.scala | 45 ++--- main/src/main/scala/sbt/ScriptedRun.scala | 179 ++++++++++++++++++ notes/1.6.0/configure-scripted-java-home.md | 14 ++ run/src/main/scala/sbt/Fork.scala | 2 +- .../project/scripted-java-home/build.sbt | 23 +++ .../scripted-java-home/changes/build.sbt | 13 ++ .../project/scripted-java-home/changes/test | 1 + .../sbt-test/project/scripted-java-home/test | 5 + .../sbt/scriptedtest/RemoteSbtCreator.scala | 28 ++- .../sbt/scriptedtest/ScriptedTests.scala | 90 ++++++++- 10 files changed, 359 insertions(+), 41 deletions(-) create mode 100644 main/src/main/scala/sbt/ScriptedRun.scala create mode 100644 notes/1.6.0/configure-scripted-java-home.md create mode 100644 sbt-app/src/sbt-test/project/scripted-java-home/build.sbt create mode 100644 sbt-app/src/sbt-test/project/scripted-java-home/changes/build.sbt create mode 100644 sbt-app/src/sbt-test/project/scripted-java-home/changes/test create mode 100644 sbt-app/src/sbt-test/project/scripted-java-home/test diff --git a/main/src/main/scala/sbt/ScriptedPlugin.scala b/main/src/main/scala/sbt/ScriptedPlugin.scala index f4822c3fb..35deb1104 100644 --- a/main/src/main/scala/sbt/ScriptedPlugin.scala +++ b/main/src/main/scala/sbt/ScriptedPlugin.scala @@ -8,7 +8,6 @@ package sbt import java.io.File -import java.lang.reflect.Method import sbt.Def._ import sbt.Keys._ @@ -47,7 +46,7 @@ object ScriptedPlugin extends AutoPlugin { val scriptedParallelInstances = settingKey[Int]( "Configures the number of scripted instances for parallel testing, only used in batch mode." ) - val scriptedRun = taskKey[Method]("") + val scriptedRun = taskKey[ScriptedRun]("") val scriptedLaunchOpts = settingKey[Seq[String]]("options to pass to jvm launching scripted tasks") val scriptedDependencies = taskKey[Unit]("") @@ -114,21 +113,8 @@ object ScriptedPlugin extends AutoPlugin { } } - private[sbt] def scriptedRunTask: Initialize[Task[Method]] = Def.taskDyn { - val fCls = classOf[File] - val bCls = classOf[Boolean] - val asCls = classOf[Array[String]] - val lfCls = classOf[java.util.List[File]] - val iCls = classOf[Int] - - val clazz = scriptedTests.value.getClass - val method = - if (scriptedBatchExecution.value) - clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, asCls, lfCls, iCls) - else - clazz.getMethod("run", fCls, bCls, asCls, fCls, asCls, lfCls) - - Def.task(method) + private[sbt] def scriptedRunTask: Initialize[Task[ScriptedRun]] = Def.task { + ScriptedRun.of(scriptedTests.value, scriptedBatchExecution.value) } private[sbt] final case class ScriptedTestPage(page: Int, total: Int) @@ -191,21 +177,16 @@ object ScriptedPlugin extends AutoPlugin { private[sbt] def scriptedTask: Initialize[InputTask[Unit]] = Def.inputTask { val args = scriptedParser(sbtTestDirectory.value).parsed Def.unit(scriptedDependencies.value) - try { - val method = scriptedRun.value - val scriptedInstance = scriptedTests.value - val dir = sbtTestDirectory.value - val log = Boolean box scriptedBufferLog.value - val launcher = sbtLauncher.value - val opts = scriptedLaunchOpts.value.toArray - val empty = new java.util.ArrayList[File]() - val instances = Int box scriptedParallelInstances.value - - if (scriptedBatchExecution.value) - method.invoke(scriptedInstance, dir, log, args.toArray, launcher, opts, empty, instances) - else method.invoke(scriptedInstance, dir, log, args.toArray, launcher, opts, empty) - () - } catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause } + scriptedRun.value.run( + sbtTestDirectory.value, + scriptedBufferLog.value, + args, + sbtLauncher.value, + Fork.javaCommand((scripted / javaHome).value, "java").getAbsolutePath, + scriptedLaunchOpts.value, + new java.util.ArrayList[File](), + scriptedParallelInstances.value + ) } private[this] def getJars(config: Configuration): Initialize[Task[PathFinder]] = Def.task { diff --git a/main/src/main/scala/sbt/ScriptedRun.scala b/main/src/main/scala/sbt/ScriptedRun.scala new file mode 100644 index 000000000..ea7d7054c --- /dev/null +++ b/main/src/main/scala/sbt/ScriptedRun.scala @@ -0,0 +1,179 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt + +import java.io.File +import java.lang.reflect.Method +import scala.annotation.unused + +sealed trait ScriptedRun { + final def run( + resourceBaseDirectory: File, + bufferLog: Boolean, + tests: Seq[String], + launcherJar: File, + javaCommand: String, + launchOpts: Seq[String], + prescripted: java.util.List[File], + instances: Int, + ): Unit = { + try { + invoke( + resourceBaseDirectory, + bufferLog, + tests.toArray, + launcherJar, + javaCommand, + launchOpts.toArray, + prescripted, + instances, + ) + () + } catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause } + } + + protected def invoke( + resourceBaseDirectory: File, + bufferLog: java.lang.Boolean, + tests: Array[String], + launcherJar: File, + javaCommand: String, + launchOpts: Array[String], + prescripted: java.util.List[File], + instances: java.lang.Integer, + ): AnyRef + +} + +object ScriptedRun { + + def of(scriptedTests: AnyRef, batchExecution: Boolean): ScriptedRun = { + val fCls = classOf[File] + val bCls = classOf[Boolean] + val asCls = classOf[Array[String]] + val sCls = classOf[String] + val lfCls = classOf[java.util.List[File]] + val iCls = classOf[Int] + + val clazz = scriptedTests.getClass + if (batchExecution) + try new RunInParallelV2( + scriptedTests, + clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, sCls, asCls, lfCls, iCls) + ) + catch { + case _: NoSuchMethodException => + new RunInParallelV1( + scriptedTests, + clazz.getMethod("runInParallel", fCls, bCls, asCls, fCls, asCls, lfCls, iCls) + ) + } + else + try new RunV2( + scriptedTests, + clazz.getMethod("run", fCls, bCls, asCls, fCls, sCls, asCls, lfCls) + ) + catch { + case _: NoSuchMethodException => + new RunV1(scriptedTests, clazz.getMethod("run", fCls, bCls, asCls, fCls, asCls, lfCls)) + } + } + + private class RunV1(scriptedTests: AnyRef, run: Method) extends ScriptedRun { + override protected def invoke( + resourceBaseDirectory: File, + bufferLog: java.lang.Boolean, + tests: Array[String], + launcherJar: File, + @unused javaCommand: String, + launchOpts: Array[String], + prescripted: java.util.List[File], + @unused instances: java.lang.Integer, + ): AnyRef = + run.invoke( + scriptedTests, + resourceBaseDirectory, + bufferLog, + tests, + launcherJar, + launchOpts, + prescripted, + ) + } + + private class RunInParallelV1(scriptedTests: AnyRef, runInParallel: Method) extends ScriptedRun { + override protected def invoke( + resourceBaseDirectory: File, + bufferLog: java.lang.Boolean, + tests: Array[String], + launcherJar: File, + @unused javaCommand: String, + launchOpts: Array[String], + prescripted: java.util.List[File], + instances: Integer, + ): AnyRef = + runInParallel.invoke( + scriptedTests, + resourceBaseDirectory, + bufferLog, + tests, + launcherJar, + launchOpts, + prescripted, + instances, + ) + } + + private class RunV2(scriptedTests: AnyRef, run: Method) extends ScriptedRun { + override protected def invoke( + resourceBaseDirectory: File, + bufferLog: java.lang.Boolean, + tests: Array[String], + launcherJar: File, + javaCommand: String, + launchOpts: Array[String], + prescripted: java.util.List[File], + @unused instances: java.lang.Integer, + ): AnyRef = + run.invoke( + scriptedTests, + resourceBaseDirectory, + bufferLog, + tests, + launcherJar, + javaCommand, + launchOpts, + prescripted, + ) + } + + private class RunInParallelV2(scriptedTests: AnyRef, runInParallel: Method) extends ScriptedRun { + override protected def invoke( + resourceBaseDirectory: File, + bufferLog: java.lang.Boolean, + tests: Array[String], + launcherJar: File, + javaCommand: String, + launchOpts: Array[String], + prescripted: java.util.List[File], + instances: Integer, + ): AnyRef = + runInParallel.invoke( + scriptedTests, + resourceBaseDirectory, + bufferLog, + tests, + launcherJar, + javaCommand, + launchOpts, + prescripted, + instances, + ) + } + +} diff --git a/notes/1.6.0/configure-scripted-java-home.md b/notes/1.6.0/configure-scripted-java-home.md new file mode 100644 index 000000000..f2ace91d8 --- /dev/null +++ b/notes/1.6.0/configure-scripted-java-home.md @@ -0,0 +1,14 @@ +[@kxbmap]: https://github.com/kxbmap + +[#6673]: https://github.com/sbt/sbt/pull/6673 + +### Improvements + +- Make javaHome that forks scripted tests configurable. [#6673][] by [@kxbmap][] + - Normally scripted tests are forked using the JVM that is running sbt. If set `scripted / javaHome`, forked using it. + - Or use `java++` command before scripted. + +### Fixes with compatibility implications + +- Change type of `scriptedRun` task key from `TaskKey[java.lang.reflect.Method]` to `TaskKey[sbt.ScriptedRun]` + - `sbt.ScriptedRun` is a new interface for hiding substance of scripted invocation. diff --git a/run/src/main/scala/sbt/Fork.scala b/run/src/main/scala/sbt/Fork.scala index 9745c28a6..b2cb449d0 100644 --- a/run/src/main/scala/sbt/Fork.scala +++ b/run/src/main/scala/sbt/Fork.scala @@ -114,7 +114,7 @@ object Fork { (classpathOption, newOptions) } - private def javaCommand(javaHome: Option[File], name: String): File = { + private[sbt] def javaCommand(javaHome: Option[File], name: String): File = { val home = javaHome.getOrElse(new File(System.getProperty("java.home"))) new File(new File(home, "bin"), name) } diff --git a/sbt-app/src/sbt-test/project/scripted-java-home/build.sbt b/sbt-app/src/sbt-test/project/scripted-java-home/build.sbt new file mode 100644 index 000000000..207694da1 --- /dev/null +++ b/sbt-app/src/sbt-test/project/scripted-java-home/build.sbt @@ -0,0 +1,23 @@ +lazy val scriptedJavaVersion = settingKey[Long]("") + +lazy val root = (project in file(".")) + .enablePlugins(SbtPlugin) + .settings( + scriptedJavaVersion := { + val versions = discoveredJavaHomes.value + .map { case (jv, _) => JavaVersion(jv).numbers } + .collect { + case Vector(1L, ver, _*) => ver + case Vector(ver, _*) => ver + } + if (versions.isEmpty) sys.error("No Java versions discovered") + else versions.max + }, + commands += Command.command("setJavaVersion") { state => + val extracted = Project.extract(state) + import extracted._ + val jv = (currentRef / scriptedJavaVersion).get(structure.data).get + s"java++ $jv!" :: state + }, + scriptedLaunchOpts += s"-Dscripted.java.version=${scriptedJavaVersion.value}" + ) diff --git a/sbt-app/src/sbt-test/project/scripted-java-home/changes/build.sbt b/sbt-app/src/sbt-test/project/scripted-java-home/changes/build.sbt new file mode 100644 index 000000000..c72b1c31d --- /dev/null +++ b/sbt-app/src/sbt-test/project/scripted-java-home/changes/build.sbt @@ -0,0 +1,13 @@ +lazy val check = taskKey[Unit]("check") + +lazy val root = (project in file(".")) + .settings( + check := { + val version = sys.props("java.version").stripPrefix("1.").takeWhile(_.isDigit) + val expected = sys.props("scripted.java.version") + assert( + version == expected, + s"Expected Java version is '$expected', but actual is '$version'" + ) + } + ) diff --git a/sbt-app/src/sbt-test/project/scripted-java-home/changes/test b/sbt-app/src/sbt-test/project/scripted-java-home/changes/test new file mode 100644 index 000000000..15675b169 --- /dev/null +++ b/sbt-app/src/sbt-test/project/scripted-java-home/changes/test @@ -0,0 +1 @@ +> check diff --git a/sbt-app/src/sbt-test/project/scripted-java-home/test b/sbt-app/src/sbt-test/project/scripted-java-home/test new file mode 100644 index 000000000..c41dd3978 --- /dev/null +++ b/sbt-app/src/sbt-test/project/scripted-java-home/test @@ -0,0 +1,5 @@ +$ copy-file changes/build.sbt src/sbt-test/group/name/build.sbt +$ copy-file changes/test src/sbt-test/group/name/test + +> setJavaVersion +> scripted diff --git a/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/RemoteSbtCreator.scala b/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/RemoteSbtCreator.scala index 41044871f..b35b6a396 100644 --- a/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/RemoteSbtCreator.scala +++ b/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/RemoteSbtCreator.scala @@ -27,14 +27,22 @@ final class LauncherBasedRemoteSbtCreator( directory: File, launcher: File, log: Logger, - launchOpts: Seq[String] = Nil, + javaCommand: String, + launchOpts: Seq[String], ) extends RemoteSbtCreator { - def newRemote(server: IPC.Server) = { + def this( + directory: File, + launcher: File, + log: Logger, + launchOpts: Seq[String] = Nil, + ) = this(directory, launcher, log, "java", launchOpts) + + def newRemote(server: IPC.Server): Process = { val launcherJar = launcher.getAbsolutePath val globalBase = "-Dsbt.global.base=" + (new File(directory, "global")).getAbsolutePath val scripted = "-Dsbt.scripted=true" val args = List("<" + server.port) - val cmd = "java" :: launchOpts.toList ::: globalBase :: scripted :: "-jar" :: launcherJar :: args ::: Nil + val cmd = javaCommand :: launchOpts.toList ::: globalBase :: scripted :: "-jar" :: launcherJar :: args ::: Nil val io = BasicIO(false, log).withInput(_.close()) val p = Process(cmd, directory) run (io) val thread = new Thread() { override def run() = { p.exitValue(); server.close() } } @@ -46,11 +54,21 @@ final class LauncherBasedRemoteSbtCreator( final class RunFromSourceBasedRemoteSbtCreator( directory: File, log: Logger, - launchOpts: Seq[String] = Nil, + javaCommand: String, + launchOpts: Seq[String], scalaVersion: String, sbtVersion: String, classpath: Seq[File], ) extends RemoteSbtCreator { + def this( + directory: File, + log: Logger, + launchOpts: Seq[String] = Nil, + scalaVersion: String, + sbtVersion: String, + classpath: Seq[File], + ) = this(directory, log, "java", launchOpts, scalaVersion, sbtVersion, classpath) + def newRemote(server: IPC.Server): Process = { val globalBase = "-Dsbt.global.base=" + new File(directory, "global").getAbsolutePath val scripted = "-Dsbt.scripted=true" @@ -58,7 +76,7 @@ final class RunFromSourceBasedRemoteSbtCreator( val cpString = classpath.mkString(java.io.File.pathSeparator) val args = List(mainClassName, directory.toString, scalaVersion, sbtVersion, cpString, "<" + server.port) - val cmd = "java" :: launchOpts.toList ::: globalBase :: scripted :: "-cp" :: cpString :: args ::: Nil + val cmd = javaCommand :: launchOpts.toList ::: globalBase :: scripted :: "-cp" :: cpString :: args ::: Nil val io = BasicIO(false, log).withInput(_.close()) val p = Process(cmd, directory) run (io) val thread = new Thread() { override def run() = { p.exitValue(); server.close() } } diff --git a/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/ScriptedTests.scala b/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/ScriptedTests.scala index cec073175..5a836b885 100644 --- a/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/ScriptedTests.scala +++ b/scripted-sbt-redux/src/main/scala/sbt/scriptedtest/ScriptedTests.scala @@ -26,8 +26,15 @@ import scala.util.control.NonFatal final class ScriptedTests( resourceBaseDirectory: File, bufferLog: Boolean, + javaCommand: String, launchOpts: Seq[String], ) { + def this( + resourceBaseDirectory: File, + bufferLog: Boolean, + launchOpts: Seq[String], + ) = this(resourceBaseDirectory, bufferLog, "java", launchOpts) + import ScriptedTests.TestRunner private val testResources = new Resources(resourceBaseDirectory) @@ -80,11 +87,12 @@ final class ScriptedTests( val remoteSbtCreator = prop match { case LauncherBased(launcherJar) => - new LauncherBasedRemoteSbtCreator(testDir, launcherJar, buffered, launchOpts) + new LauncherBasedRemoteSbtCreator(testDir, launcherJar, buffered, javaCommand, launchOpts) case RunFromSourceBased(scalaVersion, sbtVersion, classpath) => new RunFromSourceBasedRemoteSbtCreator( testDir, buffered, + javaCommand, launchOpts, scalaVersion, sbtVersion, @@ -383,6 +391,7 @@ class ScriptedRunner { bufferLog, tests, logger, + javaCommand = "java", launchOpts, prescripted = new java.util.ArrayList[File], LauncherBased(launcherJar), @@ -411,6 +420,36 @@ class ScriptedRunner { bufferLog, tests, logger, + javaCommand = "java", + launchOpts, + prescripted, + LauncherBased(launcherJar), + Int.MaxValue, + parallelExecution = false, + ) + } + + /** + * This is the entry point used by SbtPlugin in sbt 2.0.x etc. + * Removing this method will break scripted and sbt plugin cross building. + * See https://github.com/sbt/sbt/issues/3245 + */ + def run( + resourceBaseDirectory: File, + bufferLog: Boolean, + tests: Array[String], + launcherJar: File, + javaCommand: String, + launchOpts: Array[String], + prescripted: java.util.List[File], + ): Unit = { + val logger = TestConsoleLogger() + run( + resourceBaseDirectory, + bufferLog, + tests, + logger, + javaCommand, launchOpts, prescripted, LauncherBased(launcherJar), @@ -440,6 +479,36 @@ class ScriptedRunner { bufferLog, tests, logger, + javaCommand = "java", + launchOpts, + prescripted, + LauncherBased(launcherJar), + instance, + ) + } + + /** + * This is the entry point used by SbtPlugin in sbt 2.0.x etc. + * Removing this method will break scripted and sbt plugin cross building. + * See https://github.com/sbt/sbt/issues/3245 + */ + def runInParallel( + resourceBaseDirectory: File, + bufferLog: Boolean, + tests: Array[String], + launcherJar: File, + javaCommand: String, + launchOpts: Array[String], + prescripted: java.util.List[File], + instance: Int, + ): Unit = { + val logger = TestConsoleLogger() + runInParallel( + resourceBaseDirectory, + bufferLog, + tests, + logger, + javaCommand, launchOpts, prescripted, LauncherBased(launcherJar), @@ -466,6 +535,7 @@ class ScriptedRunner { bufferLog, tests, logger, + javaCommand = "java", launchOpts, prescripted, RunFromSourceBased(scalaVersion, sbtVersion, classpath), @@ -477,11 +547,24 @@ class ScriptedRunner { bufferLog: Boolean, tests: Array[String], logger: Logger, + javaCommand: String, launchOpts: Array[String], prescripted: java.util.List[File], prop: RemoteSbtCreatorProp, instances: Int - ) = run(baseDir, bufferLog, tests, logger, launchOpts, prescripted, prop, instances, true) + ): Unit = + run( + baseDir, + bufferLog, + tests, + logger, + javaCommand, + launchOpts, + prescripted, + prop, + instances, + parallelExecution = true + ) @nowarn private[this] def run( @@ -489,6 +572,7 @@ class ScriptedRunner { bufferLog: Boolean, tests: Array[String], logger: Logger, + javaCommand: String, launchOpts: Array[String], prescripted: java.util.List[File], prop: RemoteSbtCreatorProp, @@ -496,7 +580,7 @@ class ScriptedRunner { parallelExecution: Boolean, ): Unit = { val addTestFile = (f: File) => { prescripted.add(f); () } - val runner = new ScriptedTests(baseDir, bufferLog, launchOpts) + val runner = new ScriptedTests(baseDir, bufferLog, javaCommand, launchOpts) val sbtVersion = prop match { case LauncherBased(launcherJar) => From 9052c745b1be58ae6e1203bd61305e63618532cd Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Mon, 11 Oct 2021 19:27:25 +0900 Subject: [PATCH 008/120] re-enable `dependency-graph` tests --- .../src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala | 2 +- .../main/scala/sbt/internal/graph/rendering/LicenseInfo.scala | 2 +- .../src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt | 2 +- .../dependency-graph/ignoreScalaLibrary/{pending => test} | 0 .../sbt-test/dependency-graph/toFileSubTask/{pending => test} | 0 5 files changed, 3 insertions(+), 3 deletions(-) rename sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/{pending => test} (100%) rename sbt-app/src/sbt-test/dependency-graph/toFileSubTask/{pending => test} (100%) diff --git a/main/src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala b/main/src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala index 33f37513a..9fdf85cf7 100644 --- a/main/src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala +++ b/main/src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala @@ -36,7 +36,7 @@ object AsciiTree { module.id.idString + module.extraInfo + module.error.map(" (error: " + _ + ")").getOrElse("") + - module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""), + module.evictedByVersion.map(v => s" (evicted by: $v)").getOrElse(""), module.hadError ) } diff --git a/main/src/main/scala/sbt/internal/graph/rendering/LicenseInfo.scala b/main/src/main/scala/sbt/internal/graph/rendering/LicenseInfo.scala index 27aa44708..d00209735 100644 --- a/main/src/main/scala/sbt/internal/graph/rendering/LicenseInfo.scala +++ b/main/src/main/scala/sbt/internal/graph/rendering/LicenseInfo.scala @@ -20,7 +20,7 @@ object LicenseInfo { .map { case (license, modules) => license.getOrElse("No license specified") + "\n" + - modules.map(_.id.idString formatted "\t %s").mkString("\n") + modules.map(m => s"\t ${m.id.idString}").mkString("\n") } .mkString("\n\n") } 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 b2aec7b01..3e9fa7240 100644 --- a/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt +++ b/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt @@ -10,7 +10,7 @@ TaskKey[Unit]("check") := { val graph = (Test / dependencyTree / asString).value def sanitize(str: String): String = str.split('\n').drop(1).map(_.trim).mkString("\n") val expectedGraph = - """default:default-e95e05_2.9.2:0.1-SNAPSHOT [S] + """default:default-e95e05_2.12:0.1-SNAPSHOT [S] | +-ch.qos.logback:logback-classic:1.0.7 | | +-ch.qos.logback:logback-core:1.0.7 | | +-org.slf4j:slf4j-api:1.6.6 (evicted by: 1.7.2) diff --git a/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/pending b/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/test similarity index 100% rename from sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/pending rename to sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/test diff --git a/sbt-app/src/sbt-test/dependency-graph/toFileSubTask/pending b/sbt-app/src/sbt-test/dependency-graph/toFileSubTask/test similarity index 100% rename from sbt-app/src/sbt-test/dependency-graph/toFileSubTask/pending rename to sbt-app/src/sbt-test/dependency-graph/toFileSubTask/test From 9d9016f4cf06820f38ca575fd3bab97012788233 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 16 Oct 2021 15:55:22 -0400 Subject: [PATCH 009/120] Switch to using actions/setup-java@v2 --- .github/workflows/ci.yml | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b88483b4..46cf4273e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,31 +10,40 @@ jobs: matrix: include: - os: ubuntu-latest - java: "17.0-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" + java: 17 + distribution: temurin jobtype: 1 - os: ubuntu-latest - java: "17.0-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" + java: 17 + distribution: temurin jobtype: 2 - os: ubuntu-latest - java: "17.0-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" + java: 17 + distribution: temurin jobtype: 3 - os: ubuntu-latest - java: "17.0-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" + java: 17 + distribution: temurin jobtype: 4 - os: ubuntu-latest - java: "17-custom=tgz+https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17%2B35/OpenJDK17-jdk_x64_linux_hotspot_17_35.tar.gz" + java: 17 + distribution: temurin jobtype: 5 - os: ubuntu-latest - java: "adopt@1.8" + java: 8 + distribution: adopt jobtype: 6 - os: ubuntu-latest - java: "adopt@1.8" + java: 8 + distribution: adopt jobtype: 7 - os: macos-latest - java: "adopt@1.8" + java: 8 + distribution: adopt jobtype: 8 - os: windows-latest - java: "adopt@1.8" + java: 8 + distribution: adopt jobtype: 9 runs-on: ${{ matrix.os }} env: @@ -69,9 +78,10 @@ jobs: repository: sbt/zinc ref: develop path: zinc - - name: Setup - uses: olafurpg/setup-scala@v13 + - name: Setup JDK + uses: actions/setup-java@v2 with: + distribution: "${{ matrix.distribution }}" java-version: "${{ matrix.java }}" - name: Set up Python 3.7 uses: actions/setup-python@v2 From 376823bf08b2e15152c901f66abb6206b3365dc1 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 16 Oct 2021 16:18:56 -0400 Subject: [PATCH 010/120] Use GitHub Action's branching --- .github/workflows/ci.yml | 166 +++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 77 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46cf4273e..9049dd13c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,85 +94,97 @@ jobs: with: path: ~/.sbt key: ${{ runner.os }}-sbt-cache-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - - name: Build and test + - name: Build and test (1) + if: ${{ matrix.jobtype == 1 }} + shell: bash + run: | + ./sbt -v --client mimaReportBinaryIssues + ./sbt -v --client javafmtCheck + ./sbt -v --client "Test/javafmtCheck" + ./sbt -v --client scalafmtCheckAll + ./sbt -v --client scalafmtSbtCheck + ./sbt -v --client serverTestProj/scalafmtCheckAll + ./sbt -v --client headerCheck + ./sbt -v --client "Test/headerCheck" + ./sbt -v --client whitesourceOnPush + ./sbt -v --client "Test/compile" + ./sbt -v --client publishLocal + ./sbt -v --client test + ./sbt -v --client "serverTestProj/test" + ./sbt -v --client doc + ./sbt -v --client "all $UTIL_TESTS" + ./sbt -v --client ++$SCALA_213 + ./sbt -v --client "all $UTIL_TESTS" + - name: Build and test (2) + if: ${{ matrix.jobtype == 2 }} + shell: bash + run: | + ./sbt -v "scripted actions/* apiinfo/* compiler-project/* ivy-deps-management/* reporter/* tests/* watch/* classloader-cache/* package/*" + - name: Build and test (3) + if: ${{ matrix.jobtype == 3 }} + shell: bash + run: | + ./sbt -v "dependencyTreeProj/publishLocal; scripted dependency-graph/* dependency-management/* plugins/* project-load/* java/* run/* nio/*" + - name: Build and test (4) + if: ${{ matrix.jobtype == 4 }} + shell: bash + run: | + ./sbt -v "repoOverrideTest:scripted dependency-management/*; scripted source-dependencies/* project/*" + - name: Build and test (5) + if: ${{ matrix.jobtype == 5 }} + shell: bash + run: | + ./sbt -v "++$SCALA_213!; test;" + - name: Build and test (6) + if: ${{ matrix.jobtype == 6 }} + shell: bash + run: | + # build from fresh IO, LM, and Zinc + BUILD_VERSION="1.5.0-SNAPSHOT" + cd io + sbt -v -Dsbt.build.version=${BUILD_VERSION} +publishLocal + cd ../ + sbt -Dsbtlm.path=$HOME/work/sbt/sbt/librarymanagement -Dsbtzinc.path=$HOME/work/sbt/sbt/zinc -Dsbt.build.version=$BUILD_VERSION -Dsbt.build.fatal=false "+lowerUtils/publishLocal; {librarymanagement}/publishLocal; {zinc}/publishLocal; upperModules/publishLocal" + rm -r $(find $HOME/.sbt/boot -name "*-SNAPSHOT") || true + sbt -v -Dsbt.version=$BUILD_VERSION "++$SCALA_213; all $UTIL_TESTS; ++$SCALA_212; all $UTIL_TESTS; scripted actions/* source-dependencies/*1of3 dependency-management/*1of4 java/*" + - name: Build and test (7) + if: ${{ matrix.jobtype == 7 }} + shell: bash + run: | + # test launcher script + echo build using JDK 8 test using JDK 8 and JDK 11 + cd launcher-package + sbt -Dsbt.build.version=$TEST_SBT_VER rpm:packageBin debian:packageBin + sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test + cd citest && ./test.sh + $HOME/bin/jabba install $JDK11 && exec $HOME/bin/jabba which --home $JDK11 + java -Xmx32m -version + ./test.sh + - name: Build and test (8) + if: ${{ matrix.jobtype == 8 }} + shell: bash + run: | + # test launcher script + echo build using JDK 8, test using JDK 8, on macOS + cd launcher-package + bin/coursier resolve + sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test + cd citest && ./test.sh + - name: Build and test (9) + if: ${{ matrix.jobtype == 9 }} + shell: bash + run: | + # test launcher script + echo build using JDK 8, test using JDK 8, on Windows + cd launcher-package + bin/coursier.bat resolve + sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test + cd citest + ./test.bat + test3/test3.bat + - name: Cleanup shell: bash run: | - rm -rf "$HOME/.sbt/scripted/" || true - case ${{ matrix.jobtype }} in - 1) - ./sbt -v --client mimaReportBinaryIssues - ./sbt -v --client javafmtCheck - ./sbt -v --client "Test/javafmtCheck" - ./sbt -v --client scalafmtCheckAll - ./sbt -v --client scalafmtSbtCheck - ./sbt -v --client serverTestProj/scalafmtCheckAll - ./sbt -v --client headerCheck - ./sbt -v --client "Test/headerCheck" - ./sbt -v --client whitesourceOnPush - ./sbt -v --client "Test/compile" - ./sbt -v --client publishLocal - ./sbt -v --client test - ./sbt -v --client "serverTestProj/test" - ./sbt -v --client doc - ./sbt -v --client "all $UTIL_TESTS" - ./sbt -v --client ++$SCALA_213 - ./sbt -v --client "all $UTIL_TESTS" - ;; - 2) - ./sbt -v "scripted actions/* apiinfo/* compiler-project/* ivy-deps-management/* reporter/* tests/* watch/* classloader-cache/* package/*" - ;; - 3) - ./sbt -v "dependencyTreeProj/publishLocal; scripted dependency-graph/* dependency-management/* plugins/* project-load/* java/* run/* nio/*" - ;; - 4) - ./sbt -v "repoOverrideTest:scripted dependency-management/*; scripted source-dependencies/* project/*" - ;; - 5) - ./sbt -v "++$SCALA_213!; test;" - ;; - 6) - # build from fresh IO, LM, and Zinc - BUILD_VERSION="1.5.0-SNAPSHOT" - cd io - sbt -v -Dsbt.build.version=${BUILD_VERSION} +publishLocal - cd ../ - sbt -Dsbtlm.path=$HOME/work/sbt/sbt/librarymanagement -Dsbtzinc.path=$HOME/work/sbt/sbt/zinc -Dsbt.build.version=$BUILD_VERSION -Dsbt.build.fatal=false "+lowerUtils/publishLocal; {librarymanagement}/publishLocal; {zinc}/publishLocal; upperModules/publishLocal" - rm -r $(find $HOME/.sbt/boot -name "*-SNAPSHOT") || true - sbt -v -Dsbt.version=$BUILD_VERSION "++$SCALA_213; all $UTIL_TESTS; ++$SCALA_212; all $UTIL_TESTS; scripted actions/* source-dependencies/*1of3 dependency-management/*1of4 java/*" - ;; - 7) - # test launcher script - echo build using JDK 8 test using JDK 8 and JDK 11 - cd launcher-package - sbt -Dsbt.build.version=$TEST_SBT_VER rpm:packageBin debian:packageBin - sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test - cd citest && ./test.sh - $HOME/bin/jabba install $JDK11 && exec $HOME/bin/jabba which --home $JDK11 - java -Xmx32m -version - ./test.sh - ;; - 8) - # test launcher script - echo build using JDK 8, test using JDK 8, on macOS - cd launcher-package - bin/coursier resolve - sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test - cd citest && ./test.sh - ;; - 9) - # test launcher script - echo build using JDK 8, test using JDK 8, on Windows - cd launcher-package - bin/coursier.bat resolve - sbt -Dsbt.build.version=$TEST_SBT_VER universal:packageBin universal:stage integrationTest/test - cd citest - ./test.bat - test3/test3.bat - ;; - *) - echo unknown jobtype - exit 1 - esac rm -rf "$HOME/.sbt/scripted/" || true rm -rf "$HOME/.ivy2/local" || true rm -r $(find $HOME/.sbt/boot -name "*-SNAPSHOT") || true From 76c1b685163fbb0a3f3c7909ac41f4cf5952996f Mon Sep 17 00:00:00 2001 From: kijuky <40358+kijuky@users.noreply.github.com> Date: Tue, 19 Oct 2021 01:36:04 +0900 Subject: [PATCH 011/120] Enable the asciiGraphWidth setting to the dependencyTree tasks. #5962 --- .../scala/sbt/internal/SettingGraph.scala | 7 ------ .../internal/graph/rendering/AsciiTree.scala | 4 ++-- .../sbt/plugins/DependencyTreeSettings.scala | 11 +++++++-- ...nable-asciiGraphWidth-in-dependencyTree.md | 13 ++++++++++ .../asciiGraphWidth/build.sbt | 24 +++++++++++++++++++ .../asciiGraphWidth/project/plugins.sbt | 1 + .../dependency-graph/asciiGraphWidth/test | 1 + .../asciiGraphWidth/when-is-20/expected.txt | 13 ++++++++++ .../when-is-default/expected.txt | 13 ++++++++++ 9 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 notes/1.6.0/enable-asciiGraphWidth-in-dependencyTree.md create mode 100644 sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/build.sbt create mode 100644 sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/project/plugins.sbt create mode 100644 sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/test create mode 100644 sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/when-is-20/expected.txt create mode 100644 sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/when-is-default/expected.txt diff --git a/main/src/main/scala/sbt/internal/SettingGraph.scala b/main/src/main/scala/sbt/internal/SettingGraph.scala index fdf5f30ec..15669675c 100644 --- a/main/src/main/scala/sbt/internal/SettingGraph.scala +++ b/main/src/main/scala/sbt/internal/SettingGraph.scala @@ -12,7 +12,6 @@ import sbt.util.Show import java.io.File import Def.{ ScopedKey, compiled, flattenLocals } -import sbt.internal.util.Terminal import Predef.{ any2stringadd => _, _ } import sbt.io.IO @@ -123,10 +122,4 @@ object Graph { toAsciiLines(top, 0, Set.empty).mkString("\n") } - - def defaultColumnSize: Int = { - val termWidth = Terminal.console.getWidth - if (termWidth > 20) termWidth - 8 - else 80 // ignore termWidth - } } diff --git a/main/src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala b/main/src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala index 9fdf85cf7..5c474bf6f 100644 --- a/main/src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala +++ b/main/src/main/scala/sbt/internal/graph/rendering/AsciiTree.scala @@ -13,7 +13,7 @@ package rendering import sbt.internal.util.Terminal.red object AsciiTree { - def asciiTree(graph: ModuleGraph): String = { + def asciiTree(graph: ModuleGraph, graphWidth: Int): String = { val deps = graph.dependencyMap // there should only be one root node (the project itself) @@ -25,7 +25,7 @@ object AsciiTree { root, node => deps.getOrElse(node.id, Seq.empty[Module]), displayModule, - Graph.defaultColumnSize + graphWidth ) } .mkString("\n") diff --git a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala index 2c20525e9..8bb53036b 100644 --- a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala +++ b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala @@ -80,7 +80,13 @@ object DependencyTreeSettings { else GraphTransformations.ignoreScalaLibrary(sv, g) }, dependencyTreeModuleGraphStore := (dependencyTreeModuleGraph0 storeAs dependencyTreeModuleGraphStore triggeredBy dependencyTreeModuleGraph0).value, - ) ++ renderingTaskSettings(dependencyTree, rendering.AsciiTree.asciiTree _) + ) ++ { + renderingTaskSettings(dependencyTree, null) :+ { + dependencyTree / asString := { + rendering.AsciiTree.asciiTree(dependencyTreeModuleGraph0.value, asciiGraphWidth.value) + } + } + } /** * This is the maximum strength settings for DependencyTreePlugin. @@ -130,11 +136,12 @@ object DependencyTreeSettings { case None => graph.nodes.filter(m => m.id.organization == org && m.id.name == name).map(_.id) } + val graphWidth = asciiGraphWidth.value val output = modules .map { module => rendering.AsciiTree - .asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module)) + .asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module), graphWidth) } .mkString("\n") diff --git a/notes/1.6.0/enable-asciiGraphWidth-in-dependencyTree.md b/notes/1.6.0/enable-asciiGraphWidth-in-dependencyTree.md new file mode 100644 index 000000000..93fd60d1f --- /dev/null +++ b/notes/1.6.0/enable-asciiGraphWidth-in-dependencyTree.md @@ -0,0 +1,13 @@ +[@kijuky]: https://github.com/kijuky + +[5962]: https://github.com/sbt/sbt/issues/5962 + +### Fixes with compatibility implications + +- The output of the dependencyTree will not be truncated at the console width. + +### Improvements + +- Enable the asciiGraphWidth setting in the dependencyTree tasks. + +### Bug fixes diff --git a/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/build.sbt b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/build.sbt new file mode 100644 index 000000000..aa4780397 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/build.sbt @@ -0,0 +1,24 @@ +ThisBuild / version := "0.1.0-SNAPSHOT" +ThisBuild / scalaVersion := "2.13.5" + +name := "asciiGraphWidthSpecs" + +lazy val whenIsDefault = (project in file("when-is-default")) + .settings( + libraryDependencies += "org.typelevel" %% "cats-effect" % "3.1.0", + check := checkTask.value + ) +lazy val whenIs20 = (project in file("when-is-20")) + .settings( + asciiGraphWidth := 20, + libraryDependencies += "org.typelevel" %% "cats-effect" % "3.1.0", + check := checkTask.value + ) + +lazy val check = taskKey[Unit]("check") +lazy val checkTask = Def.task { + val context = thisProject.value + val expected = IO.read(file(s"${context.base}/expected.txt")) + val actual = (Compile / dependencyTree / asString).value + require(actual == expected, s"${context.id} is failed.") +} diff --git a/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/project/plugins.sbt b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/project/plugins.sbt new file mode 100644 index 000000000..93c66d2a9 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/project/plugins.sbt @@ -0,0 +1 @@ +addDependencyTreePlugin diff --git a/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/test b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/test new file mode 100644 index 000000000..15675b169 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/test @@ -0,0 +1 @@ +> check diff --git a/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/when-is-20/expected.txt b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/when-is-20/expected.txt new file mode 100644 index 000000000..bad2b603a --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/when-is-20/expected.txt @@ -0,0 +1,13 @@ +whenis20:whenis20_.. + +-org.typelevel:.. + +-org.typeleve.. + | +-org.typele.. + | +-org.type.. + | +-org.type.. + | + +-org.typeleve.. + +-org.typele.. + +-org.type.. + +-org.ty.. + +-org.ty.. + \ No newline at end of file diff --git a/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/when-is-default/expected.txt b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/when-is-default/expected.txt new file mode 100644 index 000000000..284feffc8 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/asciiGraphWidth/when-is-default/expected.txt @@ -0,0 +1,13 @@ +whenisdefault:whenisdefault_2.13:0.1.0-SNAPSHOT [S] + +-org.typelevel:cats-effect_2.13:3.1.0 [S] + +-org.typelevel:cats-effect-kernel_2.13:3.1.0 [S] + | +-org.typelevel:cats-core_2.13:2.6.0 [S] + | +-org.typelevel:cats-kernel_2.13:2.6.0 [S] + | +-org.typelevel:simulacrum-scalafix-annotations_2.13:0.5.4 [S] + | + +-org.typelevel:cats-effect-std_2.13:3.1.0 [S] + +-org.typelevel:cats-effect-kernel_2.13:3.1.0 [S] + +-org.typelevel:cats-core_2.13:2.6.0 [S] + +-org.typelevel:cats-kernel_2.13:2.6.0 [S] + +-org.typelevel:simulacrum-scalafix-annotations_2.13:0.5.4 [S] + \ No newline at end of file From 890ecdc5568f16c3da8a6b2b5cda8683d7412c1c Mon Sep 17 00:00:00 2001 From: kijuky <40358+kijuky@users.noreply.github.com> Date: Tue, 19 Oct 2021 13:51:15 +0900 Subject: [PATCH 012/120] Overloaded without passing null. --- .../scala/sbt/plugins/DependencyTreeSettings.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala index 8bb53036b..2ffe91128 100644 --- a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala +++ b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala @@ -81,7 +81,7 @@ object DependencyTreeSettings { }, dependencyTreeModuleGraphStore := (dependencyTreeModuleGraph0 storeAs dependencyTreeModuleGraphStore triggeredBy dependencyTreeModuleGraph0).value, ) ++ { - renderingTaskSettings(dependencyTree, null) :+ { + renderingTaskSettings(dependencyTree) :+ { dependencyTree / asString := { rendering.AsciiTree.asciiTree(dependencyTreeModuleGraph0.value, asciiGraphWidth.value) } @@ -149,7 +149,7 @@ object DependencyTreeSettings { output }, ) ++ - renderingAlternatives.flatMap((renderingTaskSettings _).tupled) + renderingAlternatives.flatMap { case (key, renderer) => renderingTaskSettings(key, renderer) } def renderingAlternatives: Seq[(TaskKey[Unit], ModuleGraph => String)] = Seq( @@ -159,13 +159,17 @@ object DependencyTreeSettings { ) def renderingTaskSettings(key: TaskKey[Unit], renderer: ModuleGraph => String): Seq[Setting[_]] = + renderingTaskSettings(key) :+ { + key / asString := renderer(dependencyTreeModuleGraph0.value) + } + + def renderingTaskSettings(key: TaskKey[Unit]): Seq[Setting[_]] = Seq( key := { val s = streams.value val str = (key / asString).value s.log.info(str) }, - key / asString := renderer(dependencyTreeModuleGraph0.value), key / toFile := { val (targetFile, force) = targetFileAndForceParser.parsed writeToFile(key.key.label, (key / asString).value, targetFile, force, streams.value) From 9516e10dbe12d9649e7ccbb448a1829ede5cfed7 Mon Sep 17 00:00:00 2001 From: Eric Peters Date: Thu, 21 Oct 2021 09:03:54 -0700 Subject: [PATCH 013/120] [#6696] Add shutdownall to sbt runner to shutdown all sbt-launch processes --- launcher-package/src/universal/bin/sbt.bat | 18 +++++++++++++++++- sbt | 9 +++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/launcher-package/src/universal/bin/sbt.bat b/launcher-package/src/universal/bin/sbt.bat index 1a59fd9e1..fb325c19a 100755 --- a/launcher-package/src/universal/bin/sbt.bat +++ b/launcher-package/src/universal/bin/sbt.bat @@ -25,6 +25,7 @@ set default_java_opts=-Dfile.encoding=UTF-8 set sbt_jar= set build_props_sbt_version= set run_native_client= +set shutdownall= set sbt_args_print_version= set sbt_args_print_sbt_version= @@ -399,6 +400,11 @@ if defined _timings_arg ( goto args_loop ) +if "%~0" == "shutdownall" ( + set shutdownall=1 + goto args_loop +) + if "%~0" == "--script-version" ( set sbt_args_print_sbt_script_version=1 goto args_loop @@ -508,7 +514,7 @@ goto args_loop rem Confirm a user's intent if the current directory does not look like an sbt rem top-level directory and the "new" command was not given. -if not defined sbt_args_sbt_create if not defined sbt_args_print_version if not defined sbt_args_print_sbt_version if not defined sbt_args_print_sbt_script_version if not exist build.sbt ( +if not defined sbt_args_sbt_create if not defined sbt_args_print_version if not defined sbt_args_print_sbt_version if not defined sbt_args_print_sbt_script_version if not defined shutdownall if not exist build.sbt ( if not exist project\ ( if not defined sbt_new ( echo [warn] Neither build.sbt nor a 'project' directory in the current directory: "%CD%" @@ -535,6 +541,16 @@ call :process rem avoid bootstrapping/java version check for script version +if !shutdownall! equ 1 ( + set count=0 + for /f "tokens=1" %%i in ('jps -lv ^| findstr "xsbt.boot.Boot"') do ( + taskkill /F /PID %%i + set /a count=!count!+1 + ) + echo shutdown !count! sbt processes + goto :eof +) + if !sbt_args_print_sbt_script_version! equ 1 ( echo !init_sbt_version! goto :eof diff --git a/sbt b/sbt index 3c20ecc21..c14c2ec32 100755 --- a/sbt +++ b/sbt @@ -10,6 +10,7 @@ declare -a sbt_options declare -a print_version declare -a print_sbt_version declare -a print_sbt_script_version +declare -a shutdownall declare -a original_args declare java_cmd=java declare java_version @@ -494,6 +495,12 @@ run() { elif [[ $print_version ]]; then execRunner "$java_cmd" -jar "$sbt_jar" "sbtVersion" | tail -1 | sed -e 's/\[info\]/sbt version in this project:/g' echo "sbt script version: $init_sbt_version" + elif [[ $shutdownall ]]; then + local sbt_processes=( $(jps -v | grep sbt-launch | cut -f1 -d ' ') ) + for procId in "${sbt_processes[@]}"; do + kill -9 $procId + done + echo "shutdown ${#sbt_processes[@]} sbt processes" else # run sbt execRunner "$java_cmd" \ @@ -532,6 +539,7 @@ Usage: `basename "$0"` [options] -V | --version print sbt version information --numeric-version print the numeric sbt version (sbt sbtVersion) --script-version print the version of sbt script + shutdownall shutdown all running sbt-launch processes -d | --debug set sbt log level to debug -debug-inc | --debug-inc enable extra debugging for the incremental debugger @@ -647,6 +655,7 @@ process_args () { -V|-version|--version) print_version=1 && shift ;; --numeric-version) print_sbt_version=1 && shift ;; --script-version) print_sbt_script_version=1 && shift ;; + shutdownall) shutdownall=1 && shift ;; -d|-debug|--debug) sbt_debug=1 && addSbt "-debug" && shift ;; -client|--client) use_sbtn=1 && shift ;; --server) use_sbtn=0 && shift ;; From e64c71dd58fc9965e5f25142ce9c4e7a4489e889 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Fri, 29 Oct 2021 14:31:01 +0200 Subject: [PATCH 014/120] [BSP] Support base source files --- .../internal/server/BuildServerProtocol.scala | 29 ++++++++--- .../server-test/buildserver/BaseSource.scala | 1 + .../test/scala/testpkg/BuildServerTest.scala | 49 +++++++++++++------ 3 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 server-test/src/server-test/buildserver/BaseSource.scala diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 401bf6d31..657653345 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -277,14 +277,18 @@ object BuildServerProtocol { bspBuildTargetSourcesItem := { val id = bspTargetIdentifier.value val dirs = unmanagedSourceDirectories.value - val managed = managedSources.value - val items = (dirs.toVector map { dir => - SourceItem(dir.toURI, SourceItemKind.Directory, generated = false) - }) ++ - (managed.toVector map { x => - SourceItem(x.toURI, SourceItemKind.File, generated = true) - }) - SourcesItem(id, items) + val sourceFiles = getStandaloneSourceFiles(unmanagedSources.value, dirs) + val managedDirs = managedSourceDirectories.value + val managedSourceFiles = getStandaloneSourceFiles(managedSources.value, managedDirs) + + def toSourceItem(itemKind: Int, generated: Boolean)(file: File): SourceItem = + SourceItem(file.toURI, itemKind, generated) + + val items = dirs.map(toSourceItem(SourceItemKind.Directory, generated = false)) ++ + sourceFiles.map(toSourceItem(SourceItemKind.File, generated = false)) ++ + managedDirs.map(toSourceItem(SourceItemKind.Directory, generated = true)) ++ + managedSourceFiles.map(toSourceItem(SourceItemKind.File, generated = true)) + SourcesItem(id, items.toVector) }, bspBuildTargetResourcesItem := { val id = bspTargetIdentifier.value @@ -456,6 +460,15 @@ object BuildServerProtocol { } } + private def getStandaloneSourceFiles( + sourceFiles: Seq[File], + sourceDirs: Seq[File] + ): Seq[File] = { + sourceFiles.filterNot { f => + sourceDirs.exists(dir => f.toPath.startsWith(dir.toPath)) + } + } + private def checkMetalsCompatibility( semanticdbEnabled: Boolean, semanticdbVersion: String, diff --git a/server-test/src/server-test/buildserver/BaseSource.scala b/server-test/src/server-test/buildserver/BaseSource.scala new file mode 100644 index 000000000..3359bd24f --- /dev/null +++ b/server-test/src/server-test/buildserver/BaseSource.scala @@ -0,0 +1 @@ +object BaseSource diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index 47aad7b31..f5340e131 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -10,8 +10,13 @@ package testpkg import sbt.internal.bsp._ import sbt.internal.langserver.ErrorCodes import sbt.IO +import sbt.internal.protocol.JsonRpcRequestMessage +import sbt.internal.protocol.codec.JsonRPCProtocol._ +import sjsonnew.JsonWriter +import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter } import java.io.File +import java.net.URI import java.nio.file.Paths import scala.concurrent.duration._ @@ -47,23 +52,28 @@ object BuildServerTest extends AbstractServerTest { test("buildTarget/sources") { _ => val buildTarget = buildTargetUri("util", "Compile") val badBuildTarget = buildTargetUri("badBuildTarget", "Compile") - svr.sendJsonRpc( - s"""{ "jsonrpc": "2.0", "id": "24", "method": "buildTarget/sources", "params": { - | "targets": [{ "uri": "$buildTarget" }, { "uri": "$badBuildTarget" }] - |} }""".stripMargin - ) + svr.sendJsonRpc(buildTargetSources(24, Seq(buildTarget, badBuildTarget))) assert(processing("buildTarget/sources")) val s = svr.waitFor[SourcesResult](10.seconds) val sources = s.items.head.sources.map(_.uri) assert(sources.contains(new File(svr.baseDirectory, "util/src/main/scala").toURI)) } - test("buildTarget/sources SBT") { _ => - val x = s"${svr.baseDirectory.getAbsoluteFile.toURI}#buildserver-build" - svr.sendJsonRpc( - s"""{ "jsonrpc": "2.0", "id": "25", "method": "buildTarget/sources", "params": { - | "targets": [{ "uri": "$x" }] - |} }""".stripMargin + test("buildTarget/sources: base sources") { _ => + val buildTarget = buildTargetUri("buildserver", "Compile") + svr.sendJsonRpc(buildTargetSources(25, Seq(buildTarget))) + assert(processing("buildTarget/sources")) + val s = svr.waitFor[SourcesResult](10.seconds) + val sources = s.items.head.sources + val expectedSource = SourceItem( + new File(svr.baseDirectory, "BaseSource.scala").toURI, + SourceItemKind.File, + generated = false ) + assert(sources.contains(expectedSource)) + } + test("buildTarget/sources: sbt") { _ => + val x = new URI(s"${svr.baseDirectory.getAbsoluteFile.toURI}#buildserver-build") + svr.sendJsonRpc(buildTargetSources(26, Seq(x))) assert(processing("buildTarget/sources")) val s = svr.waitFor[SourcesResult](10.seconds) val sources = s.items.head.sources.map(_.uri).sorted @@ -81,7 +91,6 @@ object BuildServerTest extends AbstractServerTest { ).map(rel => new File(svr.baseDirectory.getAbsoluteFile, rel).toURI).sorted assert(sources == expectedSources) } - test("buildTarget/compile") { _ => val buildTarget = buildTargetUri("util", "Compile") svr.sendJsonRpc( @@ -421,8 +430,20 @@ object BuildServerTest extends AbstractServerTest { } } - private def buildTargetUri(project: String, config: String): String = - s"${svr.baseDirectory.getAbsoluteFile.toURI}#$project/$config" + private def buildTargetSources(id: Int, buildTargets: Seq[URI]): String = { + val targets = buildTargets.map(BuildTargetIdentifier.apply).toVector + request(id, "buildTarget/sources", SourcesParams(targets)) + } + + private def request[T: JsonWriter](id: Int, method: String, params: T): String = { + val request = JsonRpcRequestMessage("2.0", id.toString, method, Converter.toJson(params).get) + val json = Converter.toJson(request).get + CompactPrinter(json) + } + + private def buildTargetUri(project: String, config: String): URI = { + new URI(s"${svr.baseDirectory.getAbsoluteFile.toURI}#$project/$config") + } private def metaBuildTarget: String = s"${svr.baseDirectory.getAbsoluteFile.toURI}project/#buildserver-build/Compile" From 75d3bf2b5f1e62e5d459b80a6dc19f4b23696437 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Fri, 29 Oct 2021 15:09:51 +0200 Subject: [PATCH 015/120] [BSP] remove duplicated sources in sbt build target Also remove the base directory (`./project/`) from the list of source directories --- .../internal/server/BuildServerProtocol.scala | 34 ++++++++----------- .../test/scala/testpkg/BuildServerTest.scala | 2 -- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 657653345..b5006aabb 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -116,21 +116,18 @@ object BuildServerProtocol { val base = loadedBuildUnit.localBase val sbtFiles = configurationSources(base) val pluginData = loadedBuildUnit.unit.plugins.pluginData - val all = Vector.newBuilder[SourceItem] - def add(fs: Seq[File], sourceItemKind: Int, generated: Boolean): Unit = { - fs.foreach(f => all += (SourceItem(f.toURI, sourceItemKind, generated = generated))) - } - all += (SourceItem( - loadedBuildUnit.unit.plugins.base.toURI, - SourceItemKind.Directory, - generated = false - )) - add(pluginData.unmanagedSourceDirectories, SourceItemKind.Directory, generated = false) - add(pluginData.unmanagedSources, SourceItemKind.File, generated = false) - add(pluginData.managedSourceDirectories, SourceItemKind.Directory, generated = true) - add(pluginData.managedSources, SourceItemKind.File, generated = true) - add(sbtFiles, SourceItemKind.File, generated = false) - Value(SourcesItem(id, all.result())) + val dirs = pluginData.unmanagedSourceDirectories + val sourceFiles = getStandaloneSourceFiles(pluginData.unmanagedSources, dirs) + val managedDirs = pluginData.managedSourceDirectories + val managedSourceFiles = + getStandaloneSourceFiles(pluginData.managedSources, managedDirs) + val items = + dirs.map(toSourceItem(SourceItemKind.Directory, generated = false)) ++ + sourceFiles.map(toSourceItem(SourceItemKind.File, generated = false)) ++ + managedDirs.map(toSourceItem(SourceItemKind.Directory, generated = true)) ++ + managedSourceFiles.map(toSourceItem(SourceItemKind.File, generated = true)) ++ + sbtFiles.map(toSourceItem(SourceItemKind.File, generated = false)) + Value(SourcesItem(id, items.toVector)) } val successfulItems = anyOrThrow(items ++ buildItems) val result = SourcesResult(successfulItems.toVector) @@ -280,10 +277,6 @@ object BuildServerProtocol { val sourceFiles = getStandaloneSourceFiles(unmanagedSources.value, dirs) val managedDirs = managedSourceDirectories.value val managedSourceFiles = getStandaloneSourceFiles(managedSources.value, managedDirs) - - def toSourceItem(itemKind: Int, generated: Boolean)(file: File): SourceItem = - SourceItem(file.toURI, itemKind, generated) - val items = dirs.map(toSourceItem(SourceItemKind.Directory, generated = false)) ++ sourceFiles.map(toSourceItem(SourceItemKind.File, generated = false)) ++ managedDirs.map(toSourceItem(SourceItemKind.Directory, generated = true)) ++ @@ -469,6 +462,9 @@ object BuildServerProtocol { } } + private def toSourceItem(itemKind: Int, generated: Boolean)(file: File): SourceItem = + SourceItem(file.toURI, itemKind, generated) + private def checkMetalsCompatibility( semanticdbEnabled: Boolean, semanticdbVersion: String, diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index f5340e131..5aa231752 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -79,14 +79,12 @@ object BuildServerTest extends AbstractServerTest { val sources = s.items.head.sources.map(_.uri).sorted val expectedSources = Vector( "build.sbt", - "project/", "project/A.scala", "project/src/main/java", "project/src/main/scala-2", "project/src/main/scala-2.12", "project/src/main/scala-sbt-1.0", "project/src/main/scala/", - "project/src/main/scala/B.scala", "project/target/scala-2.12/sbt-1.0/src_managed/main" ).map(rel => new File(svr.baseDirectory.getAbsoluteFile, rel).toURI).sorted assert(sources == expectedSources) From c77d6dfb384fecdff15e290d03d608524e43c690 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Wed, 3 Nov 2021 10:21:02 +0100 Subject: [PATCH 016/120] Fix #6698: Synchronize all RPC messages with systemOut notifications `systemOut` notifications are buffered so that they are sent at most once every 20 millisecond. Other RPC messages are not buffered. As a consequence, some RPC messages can pass in front of some systemOut notifications. That's why `sbt --client run` can exit before it receives all the logs. In general I think it is safer to maintain the order of all messages. To do so we can force the flush of systemOut before each RPC message. --- .../sbt/internal/server/NetworkChannel.scala | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index 8f647f98d..0acab0974 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -602,6 +602,7 @@ final class NetworkChannel( execId: String, err: JsonRpcResponseError ): Unit = { + forceFlush() val m = JsonRpcResponseMessage("2.0", execId, None, Option(err)) val bytes = Serialization.serializeResponseMessage(m) publishBytes(bytes) @@ -611,13 +612,17 @@ final class NetworkChannel( private[sbt] def jsonRpcNotify[A: JsonFormat](method: String, params: A): Unit = { val m = JsonRpcNotificationMessage("2.0", method, Option(Converter.toJson[A](params).get)) - if (method != Serialization.systemOut) log.debug(s"jsonRpcNotify: $m") + if (method != Serialization.systemOut) { + forceFlush() + log.debug(s"jsonRpcNotify: $m") + } val bytes = Serialization.serializeNotificationMessage(m) publishBytes(bytes) } /** Notify to Language Server's client. */ private[sbt] def jsonRpcRequest[A: JsonFormat](id: String, method: String, params: A): Unit = { + forceFlush() val m = JsonRpcRequestMessage("2.0", id, method, Option(Converter.toJson[A](params).get)) log.debug(s"jsonRpcRequest: $m") @@ -654,7 +659,13 @@ final class NetworkChannel( import scala.collection.JavaConverters._ private[this] val outputBuffer = new LinkedBlockingQueue[Byte] - private[this] val flushFuture = new AtomicReference[java.util.concurrent.Future[_]] + private[this] val flushExecutor = Executors.newSingleThreadScheduledExecutor( + r => new Thread(r, s"$name-output-buffer-timer-thread") + ) + private[this] def forceFlush() = { + Util.ignoreResult(flushExecutor.shutdownNow()) + doFlush() + } private[this] def doFlush()() = { val list = new java.util.ArrayList[Byte] outputBuffer.synchronized(outputBuffer.drainTo(list)) @@ -673,13 +684,9 @@ final class NetworkChannel( * probably long enough to catch each burst but short enough to not introduce * noticeable latency. */ - private[this] val executor = - Executors.newSingleThreadScheduledExecutor( - r => new Thread(r, s"$name-output-buffer-timer-thread") - ) + private[this] val flushFuture = new AtomicReference[java.util.concurrent.Future[_]] override def close(): Unit = { - Util.ignoreResult(executor.shutdownNow()) - doFlush() + forceFlush() } override def write(b: Int): Unit = outputBuffer.synchronized { outputBuffer.put(b.toByte) @@ -689,7 +696,7 @@ final class NetworkChannel( case null => try { flushFuture.set( - executor.schedule( + flushExecutor.schedule( (() => { flushFuture.set(null) doFlush() From 5d5edf2fdc40cfac7ad3421fcfaec546c1391542 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Thu, 11 Nov 2021 22:33:38 +0100 Subject: [PATCH 017/120] Fix infinte loop when server fails to load with batch client Shut down server when it is waiting for user input but stdin has ended. --- .../sbt/internal/client/NetworkClient.scala | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 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 6f30db31c..7249e290e 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -385,8 +385,8 @@ class NetworkClient( if (socket.isEmpty) Thread.sleep(20) } } - val hook = new Thread(() => Option(sbtProcess.get).foreach(_.destroyForcibly())) - Runtime.getRuntime.addShutdownHook(hook) + val shutdown = new Thread(() => Option(sbtProcess.get).foreach(_.destroyForcibly())) + Runtime.getRuntime.addShutdownHook(shutdown) var gotInputBack = false val readThreadAlive = new AtomicBoolean(true) /* @@ -406,10 +406,13 @@ class NetworkClient( socket.foreach { s => try { s.getInputStream.read match { - case -1 | 0 => readThreadAlive.set(false) - case 2 => gotInputBack = true - case 5 => term.enterRawMode(); startInputThread() - case 3 if gotInputBack => readThreadAlive.set(false) + case -1 | 0 => readThreadAlive.set(false) + case 2 => // STX: start of text + gotInputBack = true + case 5 => // ENQ: enquiry + term.enterRawMode(); startInputThread() + case 3 if gotInputBack => // ETX: end of text + readThreadAlive.set(false) case i if gotInputBack => stdinBytes.offer(i) case i => printStream.write(i) } @@ -441,8 +444,13 @@ class NetworkClient( while (!gotInputBack && !stdinBytes.isEmpty && socket.isDefined) { val out = s.getOutputStream val b = stdinBytes.poll - out.write(b) - out.flush() + if (b == -1) { + // server waits for user input but stinBytes has ended + shutdown.run() + } else { + out.write(b) + out.flush() + } } } process.foreach { p => @@ -483,7 +491,7 @@ class NetworkClient( try blockUntilStart() catch { case t: Throwable => t.printStackTrace() } finally { sbtProcess.set(null) - Util.ignoreResult(Runtime.getRuntime.removeShutdownHook(hook)) + Util.ignoreResult(Runtime.getRuntime.removeShutdownHook(shutdown)) } if (!portfile.exists()) throw new ServerFailedException if (attached.get && !stdinBytes.isEmpty) Option(inputThread.get).foreach(_.drain()) From 280800c9e9d9432796dea56cb85f96e7949dc331 Mon Sep 17 00:00:00 2001 From: kenji yoshida <6b656e6a69@gmail.com> Date: Fri, 12 Nov 2021 22:16:48 +0900 Subject: [PATCH 018/120] remove unused `bintray-scala-hedgehog` resolver --- build.sbt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build.sbt b/build.sbt index 774a4d591..4585dd1f6 100644 --- a/build.sbt +++ b/build.sbt @@ -68,10 +68,6 @@ def commonBaseSettings: Seq[Setting[_]] = Def.settings( componentID := None, resolvers += Resolver.typesafeIvyRepo("releases").withName("typesafe-sbt-build-ivy-releases"), resolvers += Resolver.sonatypeRepo("snapshots"), - resolvers += Resolver.url( - "bintray-scala-hedgehog", - url("https://dl.bintray.com/hedgehogqa/scala-hedgehog") - )(Resolver.ivyStylePatterns), testFrameworks += TestFramework("hedgehog.sbt.Framework"), testFrameworks += TestFramework("verify.runner.Framework"), Global / concurrentRestrictions += Util.testExclusiveRestriction, From 3c81e08fa2887add1f13dcbbfb8821145aac2e0b Mon Sep 17 00:00:00 2001 From: Amina Adewusi Date: Fri, 22 Oct 2021 20:09:48 +0100 Subject: [PATCH 019/120] Migrates Treeview.scala to use Contraband Migrates TreeView.scala to use Contraband from scala.util.parsing.json, because this is now deprecated. The TreeView logic is used in the dependencyBrowseTree task. --- .../internal/graph/rendering/TreeView.scala | 34 +++++------ .../graph/rendering/TreeViewTest.scala | 61 +++++++++---------- project/plugins.sbt | 1 + .../sbt/internal/graph/ModuleModel.scala | 36 +++++++++++ .../internal/graph/codec/JsonProtocol.scala | 9 +++ .../graph/codec/ModuleModelFormats.scala | 29 +++++++++ protocol/src/main/contraband/treeView.contra | 9 +++ 7 files changed, 129 insertions(+), 50 deletions(-) create mode 100644 protocol/src/main/contraband-scala/sbt/internal/graph/ModuleModel.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/graph/codec/JsonProtocol.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/graph/codec/ModuleModelFormats.scala create mode 100644 protocol/src/main/contraband/treeView.contra diff --git a/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala b/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala index f3cd7b4f7..3ff701ca1 100644 --- a/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala +++ b/main/src/main/scala/sbt/internal/graph/rendering/TreeView.scala @@ -10,24 +10,20 @@ package internal package graph package rendering +import sbt.internal.graph.codec.JsonProtocol.ModuleModelFormat import sbt.io.IO +import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter } -import java.io.File -import java.io.FileOutputStream -import java.io.InputStream -import java.io.OutputStream +import java.io.{ File, FileOutputStream, InputStream, OutputStream } import java.net.URI -import scala.annotation.nowarn -import scala.annotation.tailrec -import scala.util.parsing.json.JSONArray -import scala.util.parsing.json.JSONObject +import scala.annotation.{ nowarn, tailrec } @nowarn object TreeView { def createJson(graph: ModuleGraph): String = { - val trees = graph.roots + val moduleModels = graph.roots .map(module => processSubtree(graph, module)) - .toList - JSONArray(trees).toString + val js = moduleModels.map(Converter.toJsonUnsafe(_)) + js.map(CompactPrinter).mkString("[", ",", "]") } def createLink(graphJson: String, targetDirectory: File): URI = { @@ -43,24 +39,26 @@ import scala.util.parsing.json.JSONObject graph: ModuleGraph, module: Module, parents: Set[GraphModuleId] = Set() - ): JSONObject = { + ): ModuleModel = { val cycle = parents.contains(module.id) val dependencies = if (cycle) List() else graph.dependencyMap.getOrElse(module.id, List()) val children = - dependencies.map(dependency => processSubtree(graph, dependency, parents + module.id)).toList - moduleAsJson(module, cycle, children) + dependencies + .map(dependency => processSubtree(graph, dependency, parents + module.id)) + .toVector + moduleAsModuleAgain(module, cycle, children) } - private def moduleAsJson( + private def moduleAsModuleAgain( module: Module, isCycle: Boolean, - children: List[JSONObject] - ): JSONObject = { + children: Vector[ModuleModel] + ): ModuleModel = { val eviction = module.evictedByVersion.map(version => s" (evicted by $version)").getOrElse("") val cycle = if (isCycle) " (cycle)" else "" val error = module.error.map(err => s" (errors: $err)").getOrElse("") val text = module.id.idString + eviction + error + cycle - JSONObject(Map("text" -> text, "children" -> JSONArray(children))) + ModuleModel(text, children) } def saveResource(resourcePath: String, to: File): Unit = { diff --git a/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala b/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala index 544629e16..6e1a96a8f 100644 --- a/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala +++ b/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala @@ -5,51 +5,48 @@ * Licensed under Apache License 2.0 (see LICENSE) */ -package sbt -package internal -package graph -package rendering +package sbt.internal.graph.rendering -import org.scalatest.DiagrammedAssertions -import org.scalatest.FunSuite - -import scala.annotation.nowarn -import scala.util.parsing.json.JSONArray -import scala.util.parsing.json.JSONObject - -@nowarn("msg=class JSONObject in package json is deprecated") -class TreeViewTest extends FunSuite with DiagrammedAssertions { +import org.scalatest.{ FlatSpec, Matchers } +import sbt.internal.graph.rendering.TreeView.createJson +import sbt.internal.graph.{ GraphModuleId, Module, ModuleGraph, ModuleModel } +class TreeViewTest extends FlatSpec with Matchers { val modA = GraphModuleId("orgA", "nameA", "1.0") val modB = GraphModuleId("orgB", "nameB", "2.0") + val modC = GraphModuleId("orgC", "nameC", "3.0") val graph = ModuleGraph( - nodes = Seq(Module(modA), Module(modB)), + nodes = Seq(Module(modA), Module(modB), Module(modC)), edges = Seq( modA -> modA, modA -> modB, + modC -> modA, ) ) - test("TreeView should detect cycles and truncate") { - val json = TreeView.processSubtree(graph, Module(modA)) - val (rootText, children) = parseTree(json) - assert(rootText == modA.idString) - - val childrenText = children.map(parseTree).map(_._1) - val expected = List(s"${modA.idString} (cycle)", modB.idString) - assert(childrenText == expected) + "createJson" should "convert ModuleGraph into JSON correctly" in { + val expected = + "[{\"text\":\"orgC:nameC:3.0\",\"children\":[{\"text\":\"orgA:nameA:1.0\",\"children\":[{\"text\":\"orgA:nameA:1.0 (cycle)\",\"children\":[]},{\"text\":\"orgB:nameB:2.0\",\"children\":[]}]}]}]" + Predef.assert( + createJson(graph) == expected, + s"Expected $expected, but got ${createJson(graph)}" + ) } - @nowarn("cat=unchecked") - def parseTree(json: JSONObject): (String, List[JSONObject]) = { - (json.obj.get("text"), json.obj.get("children")) match { - case (Some(text: String), Some(JSONArray(children: List[JSONObject]))) - if children.forall(_.isInstanceOf[JSONObject]) => - text -> children - case _ => - fail("a string field 'text' and an array of objects in 'children' field were expected!") - } + "processSubtree" should "detect cycles and truncate" in { + val expected = ModuleModel( + "orgC:nameC:3.0", + Vector( + ModuleModel( + "orgA:nameA:1.0", + Vector( + ModuleModel("orgA:nameA:1.0 (cycle)", Vector()), + ModuleModel("orgB:nameB:2.0", Vector()) + ) + ) + ) + ) + assert(TreeView.processSubtree(graph, Module(modC), Set()) == expected) } - } diff --git a/project/plugins.sbt b/project/plugins.sbt index 245e11f02..7f7e8fa9a 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -11,3 +11,4 @@ addSbtPlugin("com.lightbend" % "sbt-whitesource" % "0.1.14") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.9") addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.8.1") addSbtPlugin("com.swoval" % "sbt-java-format" % "0.3.1") +addDependencyTreePlugin diff --git a/protocol/src/main/contraband-scala/sbt/internal/graph/ModuleModel.scala b/protocol/src/main/contraband-scala/sbt/internal/graph/ModuleModel.scala new file mode 100644 index 000000000..0d8a518a6 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/graph/ModuleModel.scala @@ -0,0 +1,36 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.graph +final class ModuleModel private ( + val text: String, + val children: Vector[sbt.internal.graph.ModuleModel]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: ModuleModel => (this.text == x.text) && (this.children == x.children) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.graph.ModuleModel".##) + text.##) + children.##) + } + override def toString: String = { + "ModuleModel(" + text + ", " + children + ")" + } + private[this] def copy(text: String = text, children: Vector[sbt.internal.graph.ModuleModel] = children): ModuleModel = { + new ModuleModel(text, children) + } + def withText(text: String): ModuleModel = { + copy(text = text) + } + def withChildren(children: Vector[sbt.internal.graph.ModuleModel]): ModuleModel = { + copy(children = children) + } +} +object ModuleModel { + + def apply(text: String, children: Vector[sbt.internal.graph.ModuleModel]): ModuleModel = new ModuleModel(text, children) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/graph/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/internal/graph/codec/JsonProtocol.scala new file mode 100644 index 000000000..09155f459 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/graph/codec/JsonProtocol.scala @@ -0,0 +1,9 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.graph.codec +trait JsonProtocol extends sjsonnew.BasicJsonProtocol + with sbt.internal.graph.codec.ModuleModelFormats +object JsonProtocol extends JsonProtocol \ No newline at end of file diff --git a/protocol/src/main/contraband-scala/sbt/internal/graph/codec/ModuleModelFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/graph/codec/ModuleModelFormats.scala new file mode 100644 index 000000000..eaf3c902c --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/graph/codec/ModuleModelFormats.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.graph.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait ModuleModelFormats { self: sbt.internal.graph.codec.ModuleModelFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val ModuleModelFormat: JsonFormat[sbt.internal.graph.ModuleModel] = new JsonFormat[sbt.internal.graph.ModuleModel] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.graph.ModuleModel = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val text = unbuilder.readField[String]("text") + val children = unbuilder.readField[Vector[sbt.internal.graph.ModuleModel]]("children") + unbuilder.endObject() + sbt.internal.graph.ModuleModel(text, children) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.graph.ModuleModel, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("text", obj.text) + builder.addField("children", obj.children) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband/treeView.contra b/protocol/src/main/contraband/treeView.contra new file mode 100644 index 000000000..11074e74b --- /dev/null +++ b/protocol/src/main/contraband/treeView.contra @@ -0,0 +1,9 @@ +package sbt.internal.graph +@target(Scala) +@codecPackage("sbt.internal.graph.codec") +@fullCodec("JsonProtocol") + +type ModuleModel { + text: String! + children: [sbt.internal.graph.ModuleModel] +} \ No newline at end of file From aa8b1141f89eed50487c5626e498f0e951f60da1 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Sun, 14 Nov 2021 22:00:10 +0900 Subject: [PATCH 020/120] Update scalatest --- internal/util-collection/src/test/scala/UnitSpec.scala | 5 +++-- internal/util-complete/src/test/scala/UnitSpec.scala | 5 +++-- .../scala/sbt/internal/util/complete/SizeParserSpec.scala | 4 ++-- internal/util-logging/src/test/scala/LogExchangeSpec.scala | 5 +++-- internal/util-logging/src/test/scala/ManagedLoggerSpec.scala | 5 +++-- .../src/test/scala/sbt/internal/util/CleanStringSpec.scala | 4 ++-- .../src/test/scala/sbt/internal/util/ProgressStateSpec.scala | 5 +++-- .../src/test/scala/sbt/internal/util/UTF8DecoderSpec.scala | 4 ++-- .../test/scala/sbt/internal/util/SourcePositionSpec.scala | 4 ++-- main-command/src/test/scala/sbt/MultiParserSpec.scala | 4 ++-- .../src/test/scala/sbt/internal/ClassLoaderCacheTest.scala | 5 +++-- main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala | 4 ++-- main-settings/src/test/scala/sbt/std/TaskConfigSpec.scala | 4 ++-- main-settings/src/test/scala/sbt/std/neg/TaskNegSpec.scala | 4 ++-- main/src/test/scala/sbt/internal/CrossJavaTest.scala | 5 +++-- main/src/test/scala/sbt/internal/FileStampJsonSpec.scala | 4 ++-- main/src/test/scala/sbt/internal/GCMonitorTest.scala | 4 ++-- main/src/test/scala/sbt/internal/InstallSbtnSpec.scala | 4 ++-- .../scala/sbt/internal/graph/rendering/TreeViewTest.scala | 5 +++-- project/Dependencies.scala | 2 +- sbt-app/src/test/scala/sbt/IllegalReferenceSpec.scala | 4 ++-- util-cache/src/test/scala/CacheSpec.scala | 4 ++-- util-cache/src/test/scala/FileInfoSpec.scala | 4 ++-- util-cache/src/test/scala/SingletonCacheSpec.scala | 4 ++-- util-tracking/src/test/scala/sbt/util/TrackedSpec.scala | 4 ++-- .../sbt/internal/inc/IvyBridgeProviderSpecification.scala | 3 ++- 26 files changed, 59 insertions(+), 50 deletions(-) diff --git a/internal/util-collection/src/test/scala/UnitSpec.scala b/internal/util-collection/src/test/scala/UnitSpec.scala index ed582c3bb..912b39d16 100644 --- a/internal/util-collection/src/test/scala/UnitSpec.scala +++ b/internal/util-collection/src/test/scala/UnitSpec.scala @@ -7,6 +7,7 @@ package sbt.internal.util -import org.scalatest._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers -abstract class UnitSpec extends FlatSpec with Matchers +abstract class UnitSpec extends AnyFlatSpec with Matchers diff --git a/internal/util-complete/src/test/scala/UnitSpec.scala b/internal/util-complete/src/test/scala/UnitSpec.scala index ed582c3bb..912b39d16 100644 --- a/internal/util-complete/src/test/scala/UnitSpec.scala +++ b/internal/util-complete/src/test/scala/UnitSpec.scala @@ -7,6 +7,7 @@ package sbt.internal.util -import org.scalatest._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers -abstract class UnitSpec extends FlatSpec with Matchers +abstract class UnitSpec extends AnyFlatSpec with Matchers diff --git a/internal/util-complete/src/test/scala/sbt/internal/util/complete/SizeParserSpec.scala b/internal/util-complete/src/test/scala/sbt/internal/util/complete/SizeParserSpec.scala index 521f2d10a..6d68fdae9 100644 --- a/internal/util-complete/src/test/scala/sbt/internal/util/complete/SizeParserSpec.scala +++ b/internal/util-complete/src/test/scala/sbt/internal/util/complete/SizeParserSpec.scala @@ -7,9 +7,9 @@ package sbt.internal.util.complete -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec -class SizeParserSpec extends FlatSpec { +class SizeParserSpec extends AnyFlatSpec { "SizeParser" should "handle raw bytes" in { assert(Parser.parse(str = "123456", SizeParser.value) == Right(123456L)) } diff --git a/internal/util-logging/src/test/scala/LogExchangeSpec.scala b/internal/util-logging/src/test/scala/LogExchangeSpec.scala index 3a26b44ab..7e3e44131 100644 --- a/internal/util-logging/src/test/scala/LogExchangeSpec.scala +++ b/internal/util-logging/src/test/scala/LogExchangeSpec.scala @@ -9,9 +9,10 @@ package sbt.util import sbt.internal.util._ -import org.scalatest._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers -class LogExchangeSpec extends FlatSpec with Matchers { +class LogExchangeSpec extends AnyFlatSpec with Matchers { import LogExchange._ checkTypeTag("stringTypeTagThrowable", stringTypeTagThrowable, StringTypeTag.fast[Throwable]) diff --git a/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala b/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala index d8b07e310..9a0ecd2c7 100644 --- a/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala +++ b/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala @@ -7,13 +7,14 @@ package sbt.internal.util -import org.scalatest._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers import sbt.util._ import java.io.{ File, PrintWriter } import sbt.io.Using import scala.annotation.nowarn -class ManagedLoggerSpec extends FlatSpec with Matchers { +class ManagedLoggerSpec extends AnyFlatSpec with Matchers { val context = LoggerContext(useLog4J = true) @nowarn val asyncStdout = new ConsoleAppenderFromLog4J("asyncStdout", LogExchange.asyncStdout) diff --git a/internal/util-logging/src/test/scala/sbt/internal/util/CleanStringSpec.scala b/internal/util-logging/src/test/scala/sbt/internal/util/CleanStringSpec.scala index f734923a6..ee1abdd66 100644 --- a/internal/util-logging/src/test/scala/sbt/internal/util/CleanStringSpec.scala +++ b/internal/util-logging/src/test/scala/sbt/internal/util/CleanStringSpec.scala @@ -7,9 +7,9 @@ package sbt.internal.util -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec -class CleanStringSpec extends FlatSpec { +class CleanStringSpec extends AnyFlatSpec { "EscHelpers" should "not modify normal strings" in { val cleanString = s"1234" assert(EscHelpers.stripColorsAndMoves(cleanString) == cleanString) diff --git a/internal/util-logging/src/test/scala/sbt/internal/util/ProgressStateSpec.scala b/internal/util-logging/src/test/scala/sbt/internal/util/ProgressStateSpec.scala index 4c3ae123a..909c64968 100644 --- a/internal/util-logging/src/test/scala/sbt/internal/util/ProgressStateSpec.scala +++ b/internal/util-logging/src/test/scala/sbt/internal/util/ProgressStateSpec.scala @@ -9,12 +9,13 @@ package sbt.internal.util import java.io.{ File, PrintStream } -import org.scalatest.{ BeforeAndAfterAll, FlatSpec } +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.BeforeAndAfterAll import sbt.internal.util.Terminal.SimpleTerminal import scala.io.Source -class ProgressStateSpec extends FlatSpec with BeforeAndAfterAll { +class ProgressStateSpec extends AnyFlatSpec with BeforeAndAfterAll { private lazy val fileIn = new File("/tmp/tmp.txt") private lazy val fileOut = Source.fromFile("/tmp/tmp.txt") diff --git a/internal/util-logging/src/test/scala/sbt/internal/util/UTF8DecoderSpec.scala b/internal/util-logging/src/test/scala/sbt/internal/util/UTF8DecoderSpec.scala index 957a95b4e..06c2e711b 100644 --- a/internal/util-logging/src/test/scala/sbt/internal/util/UTF8DecoderSpec.scala +++ b/internal/util-logging/src/test/scala/sbt/internal/util/UTF8DecoderSpec.scala @@ -9,10 +9,10 @@ package sbt.internal.util import java.io.InputStream import java.nio.charset.Charset -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec import java.util.concurrent.LinkedBlockingQueue -class UTF8DecoderSpec extends FlatSpec { +class UTF8DecoderSpec extends AnyFlatSpec { val decoder = Charset.forName("UTF-8").newDecoder "ascii characters" should "not be modified" in { val inputStream = new InputStream { diff --git a/internal/util-position/src/test/scala/sbt/internal/util/SourcePositionSpec.scala b/internal/util-position/src/test/scala/sbt/internal/util/SourcePositionSpec.scala index 93ed9fb96..60206dcc6 100644 --- a/internal/util-position/src/test/scala/sbt/internal/util/SourcePositionSpec.scala +++ b/internal/util-position/src/test/scala/sbt/internal/util/SourcePositionSpec.scala @@ -7,9 +7,9 @@ package sbt.internal.util -import org.scalatest._ +import org.scalatest.flatspec.AnyFlatSpec -class SourcePositionSpec extends FlatSpec { +class SourcePositionSpec extends AnyFlatSpec { "SourcePosition()" should "return a sane SourcePosition" in { val filename = "SourcePositionSpec.scala" val lineNumber = 16 diff --git a/main-command/src/test/scala/sbt/MultiParserSpec.scala b/main-command/src/test/scala/sbt/MultiParserSpec.scala index 88aea432d..2e8b54584 100644 --- a/main-command/src/test/scala/sbt/MultiParserSpec.scala +++ b/main-command/src/test/scala/sbt/MultiParserSpec.scala @@ -8,7 +8,7 @@ package sbt import scala.concurrent.duration._ -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec import sbt.internal.util.complete.Parser object MultiParserSpec { @@ -22,7 +22,7 @@ object MultiParserSpec { } } import sbt.MultiParserSpec._ -class MultiParserSpec extends FlatSpec { +class MultiParserSpec extends AnyFlatSpec { "parsing" should "parse single commands" in { assert(";foo".parse == Seq("foo")) assert("; foo".parse == Seq("foo")) diff --git a/main-command/src/test/scala/sbt/internal/ClassLoaderCacheTest.scala b/main-command/src/test/scala/sbt/internal/ClassLoaderCacheTest.scala index eec114f40..089bbd034 100644 --- a/main-command/src/test/scala/sbt/internal/ClassLoaderCacheTest.scala +++ b/main-command/src/test/scala/sbt/internal/ClassLoaderCacheTest.scala @@ -10,7 +10,8 @@ package sbt.internal import java.io.File import java.nio.file.Files -import org.scalatest.{ FlatSpec, Matchers } +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers import sbt.internal.classpath.ClassLoaderCache import sbt.io.IO @@ -19,7 +20,7 @@ object ClassLoaderCacheTest { def get(classpath: Seq[File]): ClassLoader = c(classpath.toList) } } -class ClassLoaderCacheTest extends FlatSpec with Matchers { +class ClassLoaderCacheTest extends AnyFlatSpec with Matchers { import ClassLoaderCacheTest._ private def withCache[R](f: ClassLoaderCache => R): R = { val cache = new ClassLoaderCache(ClassLoader.getSystemClassLoader) diff --git a/main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala b/main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala index c1af590b4..e38fecdff 100644 --- a/main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala +++ b/main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala @@ -7,12 +7,12 @@ package sbt -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec import sbt.internal.util.{ AttributeKey, AttributeMap } import sbt.io.syntax.file import scala.annotation.nowarn -class ScopeDisplaySpec extends FlatSpec { +class ScopeDisplaySpec extends AnyFlatSpec { val project = ProjectRef(file("foo/bar"), "bar") val mangledName = "bar_slash_blah_blah_blah" diff --git a/main-settings/src/test/scala/sbt/std/TaskConfigSpec.scala b/main-settings/src/test/scala/sbt/std/TaskConfigSpec.scala index e43b655a6..210284215 100644 --- a/main-settings/src/test/scala/sbt/std/TaskConfigSpec.scala +++ b/main-settings/src/test/scala/sbt/std/TaskConfigSpec.scala @@ -7,12 +7,12 @@ package sbt.std -import org.scalatest.{ TestData, fixture } +import org.scalatest.{ TestData, fixture, funsuite } import sbt.std.TestUtil._ import scala.tools.reflect.{ FrontEnd, ToolBoxError } -class TaskConfigSpec extends fixture.FunSuite with fixture.TestDataFixture { +class TaskConfigSpec extends funsuite.FixtureAnyFunSuite with fixture.TestDataFixture { private def expectError( errorSnippet: String, compileOptions: String = "", diff --git a/main-settings/src/test/scala/sbt/std/neg/TaskNegSpec.scala b/main-settings/src/test/scala/sbt/std/neg/TaskNegSpec.scala index 0e08b5e96..e2d214657 100644 --- a/main-settings/src/test/scala/sbt/std/neg/TaskNegSpec.scala +++ b/main-settings/src/test/scala/sbt/std/neg/TaskNegSpec.scala @@ -8,11 +8,11 @@ package sbt.std.neg import scala.tools.reflect.ToolBoxError -import org.scalatest.{ TestData, fixture } +import org.scalatest.{ TestData, fixture, funsuite } import sbt.std.{ TaskLinterDSLFeedback, TestUtil } import sbt.std.TestUtil._ -class TaskNegSpec extends fixture.FunSuite with fixture.TestDataFixture { +class TaskNegSpec extends funsuite.FixtureAnyFunSuite with fixture.TestDataFixture { def expectError( errorSnippet: String, compileOptions: String = "", diff --git a/main/src/test/scala/sbt/internal/CrossJavaTest.scala b/main/src/test/scala/sbt/internal/CrossJavaTest.scala index cd0caa645..c884c31c8 100644 --- a/main/src/test/scala/sbt/internal/CrossJavaTest.scala +++ b/main/src/test/scala/sbt/internal/CrossJavaTest.scala @@ -8,11 +8,12 @@ package sbt package internal -import org.scalatest._ +import org.scalatest.diagrams.Diagrams +import org.scalatest.funsuite.AnyFunSuite import sbt.internal.CrossJava.JavaDiscoverConfig._ import scala.collection.immutable.ListMap -class CrossJavaTest extends FunSuite with DiagrammedAssertions { +class CrossJavaTest extends AnyFunSuite with Diagrams { test("The Java home selector should select the most recent") { assert( List("jdk1.8.0.jdk", "jdk1.8.0_121.jdk", "jdk1.8.0_45.jdk") diff --git a/main/src/test/scala/sbt/internal/FileStampJsonSpec.scala b/main/src/test/scala/sbt/internal/FileStampJsonSpec.scala index fe4dacb53..bf0f127f3 100644 --- a/main/src/test/scala/sbt/internal/FileStampJsonSpec.scala +++ b/main/src/test/scala/sbt/internal/FileStampJsonSpec.scala @@ -9,13 +9,13 @@ package sbt.internal import java.nio.file.{ Path, Paths } -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec import sbt.nio.FileStamp import sbt.nio.FileStamp.Formats import sjsonnew.JsonFormat import sjsonnew.support.scalajson.unsafe.Converter -class FileStampJsonSpec extends FlatSpec { +class FileStampJsonSpec extends AnyFlatSpec { "file hashes" should "be serializable" in { val hashes = Seq( Paths.get("foo") -> FileStamp.hash("bar"), diff --git a/main/src/test/scala/sbt/internal/GCMonitorTest.scala b/main/src/test/scala/sbt/internal/GCMonitorTest.scala index 02356e0a3..d646b88f1 100644 --- a/main/src/test/scala/sbt/internal/GCMonitorTest.scala +++ b/main/src/test/scala/sbt/internal/GCMonitorTest.scala @@ -9,12 +9,12 @@ package sbt.internal import java.util.concurrent.atomic.AtomicReference -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import scala.collection.mutable.ListBuffer import scala.concurrent.duration._ -class GCMonitorTest extends FunSuite { +class GCMonitorTest extends AnyFunSuite { class TestMonitor extends GCMonitorBase { val loggedTotals = ListBuffer.empty[Long] override protected val window = 10.seconds diff --git a/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala b/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala index 3580007ed..626faa679 100644 --- a/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala +++ b/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala @@ -13,10 +13,10 @@ import java.lang.ProcessBuilder import java.lang.ProcessBuilder.Redirect import java.nio.file.{ Files, Path } import java.util.concurrent.TimeUnit -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec import sbt.io.IO -class InstallSbtnSpec extends FlatSpec { +class InstallSbtnSpec extends AnyFlatSpec { private def withTemp[R](ext: String)(f: Path => R): R = { val tmp = Files.createTempFile("sbt-1.4.1-", ext) try f(tmp) diff --git a/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala b/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala index 6e1a96a8f..6b291b4e3 100644 --- a/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala +++ b/main/src/test/scala/sbt/internal/graph/rendering/TreeViewTest.scala @@ -7,11 +7,12 @@ package sbt.internal.graph.rendering -import org.scalatest.{ FlatSpec, Matchers } +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers import sbt.internal.graph.rendering.TreeView.createJson import sbt.internal.graph.{ GraphModuleId, Module, ModuleGraph, ModuleModel } -class TreeViewTest extends FlatSpec with Matchers { +class TreeViewTest extends AnyFlatSpec with Matchers { val modA = GraphModuleId("orgA", "nameA", "1.0") val modB = GraphModuleId("orgB", "nameB", "2.0") val modC = GraphModuleId("orgC", "nameC", "3.0") diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 974fa291b..7dc4fb126 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -94,7 +94,7 @@ object Dependencies { val jline3Reader = "org.jline" % "jline-reader" % jline3Version val jline3Builtins = "org.jline" % "jline-builtins" % jline3Version val jansi = "org.fusesource.jansi" % "jansi" % "2.1.0" - val scalatest = "org.scalatest" %% "scalatest" % "3.0.8" + val scalatest = "org.scalatest" %% "scalatest" % "3.2.10" val scalacheck = "org.scalacheck" %% "scalacheck" % "1.14.0" val junit = "junit" % "junit" % "4.13.1" val scalaVerify = "com.eed3si9n.verify" %% "verify" % "1.0.0" diff --git a/sbt-app/src/test/scala/sbt/IllegalReferenceSpec.scala b/sbt-app/src/test/scala/sbt/IllegalReferenceSpec.scala index e94817b57..de4dfb96c 100644 --- a/sbt-app/src/test/scala/sbt/IllegalReferenceSpec.scala +++ b/sbt-app/src/test/scala/sbt/IllegalReferenceSpec.scala @@ -8,11 +8,11 @@ package sbt import org.scalatest -import org.scalatest.{ TestData, fixture } +import org.scalatest.{ TestData, fixture, funsuite } import scala.tools.reflect.{ FrontEnd, ToolBoxError } -class IllegalReferenceSpec extends fixture.FunSuite with fixture.TestDataFixture { +class IllegalReferenceSpec extends funsuite.FixtureAnyFunSuite with fixture.TestDataFixture { private def toolboxClasspath(td: TestData): String = td.configMap.get("sbt.server.classpath") match { case Some(s: String) => s diff --git a/util-cache/src/test/scala/CacheSpec.scala b/util-cache/src/test/scala/CacheSpec.scala index 587efed32..70d0f6245 100644 --- a/util-cache/src/test/scala/CacheSpec.scala +++ b/util-cache/src/test/scala/CacheSpec.scala @@ -12,9 +12,9 @@ import sbt.io.syntax._ import CacheImplicits._ -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec -class CacheSpec extends FlatSpec { +class CacheSpec extends AnyFlatSpec { "A cache" should "NOT throw an exception if read without being written previously" in { testCache[String, Int] { diff --git a/util-cache/src/test/scala/FileInfoSpec.scala b/util-cache/src/test/scala/FileInfoSpec.scala index cfaf3af37..5ea495195 100644 --- a/util-cache/src/test/scala/FileInfoSpec.scala +++ b/util-cache/src/test/scala/FileInfoSpec.scala @@ -9,10 +9,10 @@ package sbt.util import sjsonnew.shaded.scalajson.ast.unsafe._ import sjsonnew._, support.scalajson.unsafe._ -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec import sbt.io.IO -class FileInfoSpec extends FlatSpec { +class FileInfoSpec extends AnyFlatSpec { val file = new java.io.File(".").getAbsoluteFile val fileInfo: ModifiedFileInfo = FileModified(file, IO.getModifiedTimeOrZero(file)) val filesInfo = FilesInfo(Set(fileInfo)) diff --git a/util-cache/src/test/scala/SingletonCacheSpec.scala b/util-cache/src/test/scala/SingletonCacheSpec.scala index 568a5e2aa..ab6de3adb 100644 --- a/util-cache/src/test/scala/SingletonCacheSpec.scala +++ b/util-cache/src/test/scala/SingletonCacheSpec.scala @@ -13,9 +13,9 @@ import sbt.io.syntax._ import CacheImplicits._ import sjsonnew.{ Builder, deserializationError, JsonFormat, Unbuilder } -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec -class SingletonCacheSpec extends FlatSpec { +class SingletonCacheSpec extends AnyFlatSpec { case class ComplexType(val x: Int, y: String, z: List[Int]) object ComplexType { diff --git a/util-tracking/src/test/scala/sbt/util/TrackedSpec.scala b/util-tracking/src/test/scala/sbt/util/TrackedSpec.scala index f456931f0..1298adfb7 100644 --- a/util-tracking/src/test/scala/sbt/util/TrackedSpec.scala +++ b/util-tracking/src/test/scala/sbt/util/TrackedSpec.scala @@ -7,7 +7,7 @@ package sbt.util -import org.scalatest.FlatSpec +import org.scalatest.flatspec.AnyFlatSpec import sbt.io.IO import sbt.io.syntax._ import sbt.util.CacheImplicits._ @@ -15,7 +15,7 @@ import sjsonnew.{ Builder, JsonWriter } import scala.concurrent.Promise -class TrackedSpec extends FlatSpec { +class TrackedSpec extends AnyFlatSpec { "lastOutput" should "store the last output" in { withStore { store => val value = 5 diff --git a/zinc-lm-integration/src/test/scala/sbt/internal/inc/IvyBridgeProviderSpecification.scala b/zinc-lm-integration/src/test/scala/sbt/internal/inc/IvyBridgeProviderSpecification.scala index a4c30bf0c..e465c397a 100644 --- a/zinc-lm-integration/src/test/scala/sbt/internal/inc/IvyBridgeProviderSpecification.scala +++ b/zinc-lm-integration/src/test/scala/sbt/internal/inc/IvyBridgeProviderSpecification.scala @@ -17,6 +17,7 @@ import sbt.librarymanagement.ivy._ import sbt.util.Logger import xsbti.compile.CompilerBridgeProvider import org.scalatest._ +import org.scalatest.matchers.should.Matchers /** * Base class for test suites that must be able to fetch and compile the compiler bridge. @@ -24,7 +25,7 @@ import org.scalatest._ * This is a very good example on how to instantiate the compiler bridge provider. */ abstract class IvyBridgeProviderSpecification - extends fixture.FlatSpec + extends flatspec.FixtureAnyFlatSpec with fixture.TestDataFixture with Matchers { def currentBase: File = new File(".") From 535b15b83ed6ddfdd95b46c707055ac85064e88f Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Sun, 14 Nov 2021 22:59:34 +0900 Subject: [PATCH 021/120] fix Scala 2.13 warnings --- build.sbt | 2 +- .../src/main/scala/sbt/internal/util/HList.scala | 2 +- .../main/scala/sbt/internal/util/Settings.scala | 15 +++++++-------- .../src/main/scala/sbt/internal/util/Util.scala | 2 +- .../sbt/internal/util/complete/Parser.scala | 2 +- .../sbt/internal/util/complete/Parsers.scala | 4 ++-- .../scala/sbt/internal/util/GlobalLogging.scala | 2 +- .../scala/sbt/internal/util/MainAppender.scala | 6 +++--- .../scala/sbt/internal/util/ProgressState.scala | 4 ++-- .../main/scala/sbt/internal/util/Terminal.scala | 2 +- .../sbt/internal/util/WindowsInputStream.scala | 2 +- .../util-logging/src/test/scala/Escapes.scala | 2 +- .../main/scala/sbt/internal/util/Relation.scala | 2 +- .../sbt/internal/scripted/FileCommands.scala | 9 ++++----- .../sbt/internal/scripted/ScriptedTests.scala | 2 +- launcher-package/build.sbt | 2 +- main-actions/src/main/scala/sbt/ForkTests.scala | 4 ++-- main-actions/src/main/scala/sbt/Package.scala | 2 +- .../src/main/scala/sbt/RawCompileLike.scala | 2 +- .../src/main/scala/sbt/compiler/Eval.scala | 2 +- .../src/test/scala/sbt/CacheIvyTest.scala | 2 +- .../src/main/scala/sbt/BasicCommands.scala | 4 ++-- .../src/main/scala/sbt/CommandUtil.scala | 4 ++-- .../main/scala/sbt/internal/LegacyWatched.scala | 4 ++-- .../sbt/internal/client/NetworkClient.scala | 16 ++++++++-------- .../sbt/internal/client/ServerConnection.scala | 4 ++-- .../scala/sbt/internal/util/JoinThread.scala | 2 +- main-settings/src/main/scala/sbt/Def.scala | 2 +- .../src/test/scala/sbt/std/UsageTest.scala | 2 +- main/src/main/scala/sbt/BuildPaths.scala | 3 ++- main/src/main/scala/sbt/Defaults.scala | 12 ++++++------ .../coursierint/CoursierRepositoriesTasks.scala | 4 ++-- .../main/scala/sbt/internal/BuildStructure.scala | 3 ++- .../main/scala/sbt/internal/InstallSbtn.scala | 2 +- .../sbt/internal/graph/rendering/DagreHTML.scala | 2 +- main/src/test/scala/ParseKey.scala | 2 +- .../scala/sbt/internal/InstallSbtnSpec.scala | 2 +- .../scala/sbt/internal/StressGCMonitor.scala | 2 +- main/src/test/scala/sbt/internal/TestBuild.scala | 2 +- .../sbt/internal/bsp/BuildServerConnection.scala | 4 ++-- .../src/main/scala/sbt/std/TaskExtra.scala | 4 ++-- tasks-standard/src/test/scala/Test.scala | 10 +++++----- .../main/scala/sbt/ConcurrentRestrictions.scala | 2 +- .../main/scala/sbt/JUnitXmlTestsListener.scala | 4 ++-- testing/src/main/scala/sbt/TestFramework.scala | 2 +- .../src/main/scala/sbt/TestStatusReporter.scala | 2 +- .../scala/sbt/internal/testing/TestLogger.scala | 2 +- .../src/main/scala/sbt/util/SeparatedCache.scala | 2 +- util-cache/src/test/scala/CacheSpec.scala | 12 ++++++------ .../src/main/scala/sbt/util/Tracked.scala | 8 ++++---- .../src/test/scala/sbt/util/TrackedSpec.scala | 2 +- 51 files changed, 99 insertions(+), 99 deletions(-) diff --git a/build.sbt b/build.sbt index 4585dd1f6..72c80254b 100644 --- a/build.sbt +++ b/build.sbt @@ -1104,7 +1104,7 @@ lazy val serverTestProj = (project in file("server-test")) val rawClasspath = (Compile / fullClasspathAsJars).value.map(_.data).mkString(java.io.File.pathSeparator) val cp = - if (scala.util.Properties.isWin) rawClasspath.replaceAllLiterally("\\", "\\\\") + if (scala.util.Properties.isWin) rawClasspath.replace("\\", "\\\\") else rawClasspath val content = { s"""| diff --git a/internal/util-collection/src/main/scala/sbt/internal/util/HList.scala b/internal/util-collection/src/main/scala/sbt/internal/util/HList.scala index f0922a079..dc9d163f9 100644 --- a/internal/util-collection/src/main/scala/sbt/internal/util/HList.scala +++ b/internal/util-collection/src/main/scala/sbt/internal/util/HList.scala @@ -30,7 +30,7 @@ final case class HCons[H, T <: HList](head: H, tail: T) extends HList { type Wrap[M[_]] = M[H] :+: T#Wrap[M] def :+:[G](g: G): G :+: H :+: T = HCons(g, this) - override def toString = head + " :+: " + tail.toString + override def toString = head.toString + " :+: " + tail.toString } object HList { diff --git a/internal/util-collection/src/main/scala/sbt/internal/util/Settings.scala b/internal/util-collection/src/main/scala/sbt/internal/util/Settings.scala index f4110acc8..4541980cd 100644 --- a/internal/util-collection/src/main/scala/sbt/internal/util/Settings.scala +++ b/internal/util-collection/src/main/scala/sbt/internal/util/Settings.scala @@ -43,7 +43,7 @@ private final class Settings0[ScopeType]( (data get scope).flatMap(_ get key) def set[T](scope: ScopeType, key: AttributeKey[T], value: T): Settings[ScopeType] = { - val map = data getOrElse (scope, AttributeMap.empty) + val map = data.getOrElse(scope, AttributeMap.empty) val newData = data.updated(scope, map.put(key, value)) new Settings0(newData, delegates) } @@ -476,7 +476,7 @@ trait Init[ScopeType] { if (posDefined.size == settings.size) "defined at:" else "some of the defining occurrences:" - header + (posDefined.distinct mkString ("\n\t", "\n\t", "\n")) + header + (posDefined.distinct.mkString("\n\t", "\n\t", "\n")) } else "" } @@ -711,10 +711,10 @@ trait Init[ScopeType] { def mapReferenced(g: MapScoped): Setting[T] = make(key, init mapReferenced g, pos) def validateReferenced(g: ValidateRef): Either[Seq[Undefined], Setting[T]] = - (init validateReferenced g).right.map(newI => make(key, newI, pos)) + (init validateReferenced g).map(newI => make(key, newI, pos)) private[sbt] def validateKeyReferenced(g: ValidateKeyRef): Either[Seq[Undefined], Setting[T]] = - (init validateKeyReferenced g).right.map(newI => make(key, newI, pos)) + (init validateKeyReferenced g).map(newI => make(key, newI, pos)) def mapKey(g: MapScoped): Setting[T] = make(g(key), init, pos) def mapInit(f: (ScopedKey[T], T) => T): Setting[T] = make(key, init(t => f(key, t)), pos) @@ -879,9 +879,8 @@ trait Init[ScopeType] { def evaluate(ss: Settings[ScopeType]): T = f(in evaluate ss) evaluate ss def mapReferenced(g: MapScoped) = new Bind[S, T](s => f(s) mapReferenced g, in mapReferenced g) - def validateKeyReferenced(g: ValidateKeyRef) = (in validateKeyReferenced g).right.map { - validIn => - new Bind[S, T](s => handleUndefined(f(s) validateKeyReferenced g), validIn) + def validateKeyReferenced(g: ValidateKeyRef) = (in validateKeyReferenced g).map { validIn => + new Bind[S, T](s => handleUndefined(f(s) validateKeyReferenced g), validIn) } def mapConstant(g: MapConstant) = new Bind[S, T](s => f(s) mapConstant g, in mapConstant g) @@ -898,7 +897,7 @@ trait Init[ScopeType] { def validateKeyReferenced(g: ValidateKeyRef) = a match { case None => Right(this) - case Some(i) => Right(new Optional(i.validateKeyReferenced(g).right.toOption, f)) + case Some(i) => Right(new Optional(i.validateKeyReferenced(g).toOption, f)) } def mapConstant(g: MapConstant): Initialize[T] = new Optional(a map mapConstantT(g).fn, f) diff --git a/internal/util-collection/src/main/scala/sbt/internal/util/Util.scala b/internal/util-collection/src/main/scala/sbt/internal/util/Util.scala index 0155306c8..8ec3636a6 100644 --- a/internal/util-collection/src/main/scala/sbt/internal/util/Util.scala +++ b/internal/util-collection/src/main/scala/sbt/internal/util/Util.scala @@ -43,7 +43,7 @@ object Util { def camelToHyphen(s: String): String = Camel.replaceAllIn(s, m => m.group(1) + "-" + m.group(2).toLowerCase(Locale.ENGLISH)) - def quoteIfKeyword(s: String): String = if (ScalaKeywords.values(s)) '`' + s + '`' else s + def quoteIfKeyword(s: String): String = if (ScalaKeywords.values(s)) s"`${s}`" else s def ignoreResult[T](f: => T): Unit = macro Macro.ignore diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parser.scala b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parser.scala index 464ab1916..8d66d2137 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parser.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parser.scala @@ -909,7 +909,7 @@ private final class StringLiteral(str: String, start: Int) extends ValidParser[S if (str.charAt(start) == c) stringLiteral(str, start + 1) else new Invalid(resultEmpty) def completions(level: Int) = Completions.single(Completion.suggestion(str.substring(start))) - override def toString = '"' + str + '"' + override def toString = "\"" + str + "\"" } private final class CharacterClass(f: Char => Boolean, label: String) extends ValidParser[Char] { diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala index 651ddd8d0..884aecc9a 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala @@ -238,12 +238,12 @@ trait Parsers { val notDelim = charClass(c => c != open && c != close).*.string def impl(): Parser[String] = { (open ~ (notDelim ~ close).?).flatMap { - case (l, Some((content, r))) => Parser.success(l + content + r) + case (l, Some((content, r))) => Parser.success(s"$l$content$r") case (l, None) => ((notDelim ~ impl()).map { case (leftPrefix, nestedBraces) => leftPrefix + nestedBraces }.+ ~ notDelim ~ close).map { - case ((nested, suffix), r) => l + nested.mkString + suffix + r + case ((nested, suffix), r) => s"$l${nested.mkString}$suffix$r" } } } diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/GlobalLogging.scala b/internal/util-logging/src/main/scala/sbt/internal/util/GlobalLogging.scala index 9be015da7..00c0a67c0 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/GlobalLogging.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/GlobalLogging.scala @@ -83,7 +83,7 @@ object GlobalLogging { ): GlobalLogging = { val loggerName = generateName val log = LoggerContext.globalContext.logger(loggerName, None, None) - val appender = ConsoleAppender(ConsoleAppender.generateName, console) + val appender = ConsoleAppender(ConsoleAppender.generateName(), console) LoggerContext.globalContext.addAppender(loggerName, appender -> Level.Info) GlobalLogging(log, console, appender, GlobalLogBacking(newBackingFile), newAppender) } diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala b/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala index 96bc84435..22ad78a9c 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/MainAppender.scala @@ -67,14 +67,14 @@ object MainAppender { ) def defaultScreen(console: ConsoleOut): Appender = - ConsoleAppender(ConsoleAppender.generateName, console) + ConsoleAppender(ConsoleAppender.generateName(), console) def defaultScreen( console: ConsoleOut, suppressedMessage: SuppressedTraceContext => Option[String] ): Appender = { ConsoleAppender( - ConsoleAppender.generateName, + ConsoleAppender.generateName(), console, suppressedMessage = suppressedMessage ) @@ -99,7 +99,7 @@ object MainAppender { def defaultBacked(loggerName: String, useFormat: Boolean): PrintWriter => Appender = to => { ConsoleAppender( - ConsoleAppender.generateName, + ConsoleAppender.generateName(), ConsoleOut.printWriterOut(to), useFormat = useFormat ) diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala b/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala index 5ea305920..817363f8d 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/ProgressState.scala @@ -99,8 +99,8 @@ private[sbt] final class ProgressState( addBytes(terminal, bytes) val toWrite = new ArrayBuffer[Byte] terminal.prompt match { - case a: Prompt.AskUser if a.render.nonEmpty && canClearPrompt => toWrite ++= cleanPrompt - case _ => + case a: Prompt.AskUser if a.render().nonEmpty && canClearPrompt => toWrite ++= cleanPrompt + case _ => } val endsWithNewLine = bytes.endsWith(lineSeparatorBytes) if (endsWithNewLine || bytes.containsSlice(lineSeparatorBytes)) { diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala index 2c2a6434c..7fecdf0e5 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala @@ -905,7 +905,7 @@ object Terminal { new AtomicReference[((Int, Int), Deadline)](((1, 1), Deadline.now - 1.day)) private[this] def setSize() = size.set((Try(getSizeImpl).getOrElse((1, 1)), Deadline.now)) private[this] def getSize = size.get match { - case (s, d) if (d + sizeRefreshPeriod).isOverdue => + case (s, d) if (d + sizeRefreshPeriod).isOverdue() => setSize() size.get._1 case (s, _) => s diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/WindowsInputStream.scala b/internal/util-logging/src/main/scala/sbt/internal/util/WindowsInputStream.scala index 486759cbb..830dbc2d2 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/WindowsInputStream.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/WindowsInputStream.scala @@ -56,7 +56,7 @@ private[util] class WindowsInputStream(term: org.jline.terminal.Terminal, in: In private val SHIFT_PRESSED = 0x0010; private def getCapability(cap: Capability): String = term.getStringCapability(cap) match { case null => null - case c => c.replaceAllLiterally("\\E", "\u001B") + case c => c.replace("\\E", "\u001B") } /* * This function is a hybrid of jline 2 WindowsTerminal.readConsoleInput diff --git a/internal/util-logging/src/test/scala/Escapes.scala b/internal/util-logging/src/test/scala/Escapes.scala index 82d144d99..af4e1c705 100644 --- a/internal/util-logging/src/test/scala/Escapes.scala +++ b/internal/util-logging/src/test/scala/Escapes.scala @@ -96,7 +96,7 @@ object Escapes extends Properties("Escapes") { ) } assert(isEscapeTerminator(terminator)) - def makeString: String = ESC + content + terminator + def makeString: String = s"$ESC$content$terminator" override def toString = if (content.isEmpty) s"ESC (${terminator.toInt})" diff --git a/internal/util-relation/src/main/scala/sbt/internal/util/Relation.scala b/internal/util-relation/src/main/scala/sbt/internal/util/Relation.scala index dc6c60b97..ce644ac13 100644 --- a/internal/util-relation/src/main/scala/sbt/internal/util/Relation.scala +++ b/internal/util-relation/src/main/scala/sbt/internal/util/Relation.scala @@ -214,5 +214,5 @@ private final class MRelation[A, B](fwd: Map[A, Set[B]], rev: Map[B, Set[A]]) override def hashCode = fwd.filterNot(_._2.isEmpty).hashCode() override def toString = - all.map { case (a, b) => a + " -> " + b }.mkString("Relation [", ", ", "]") + all.map { case (a, b) => s"$a -> $b" }.mkString("Relation [", ", ", "]") } diff --git a/internal/util-scripted/src/main/scala/sbt/internal/scripted/FileCommands.scala b/internal/util-scripted/src/main/scala/sbt/internal/scripted/FileCommands.scala index d9e7a1d42..fcc6707f5 100644 --- a/internal/util-scripted/src/main/scala/sbt/internal/scripted/FileCommands.scala +++ b/internal/util-scripted/src/main/scala/sbt/internal/scripted/FileCommands.scala @@ -13,7 +13,6 @@ import java.io.File import sbt.io.{ IO, Path } import sbt.io.syntax._ import Path._ -import sbt.io.IO class FileCommands(baseDirectory: File) extends BasicStatementHandler { lazy val commands = commandMap @@ -25,7 +24,7 @@ class FileCommands(baseDirectory: File) extends BasicStatementHandler { "mkdir" nonEmpty makeDirectories _, "absent" nonEmpty absent _, // "sync" twoArg("Two directory paths", sync _), - "newer" twoArg ("Two paths", newer _), + "newer".twoArg("Two paths", newer _), "pause" noArg { println("Pausing in " + baseDirectory) /*readLine("Press enter to continue. ") */ @@ -33,11 +32,11 @@ class FileCommands(baseDirectory: File) extends BasicStatementHandler { System.console.readLine println() }, - "sleep" oneArg ("Time in milliseconds", time => Thread.sleep(time.toLong)), + "sleep".oneArg("Time in milliseconds", time => Thread.sleep(time.toLong)), "exec" nonEmpty (execute _), "copy" copy (to => rebase(baseDirectory, to)), - "copy-file" twoArg ("Two paths", copyFile _), - "must-mirror" twoArg ("Two paths", diffFiles _), + "copy-file".twoArg("Two paths", copyFile _), + "must-mirror".twoArg("Two paths", diffFiles _), "copy-flat" copy flat ) diff --git a/internal/util-scripted/src/main/scala/sbt/internal/scripted/ScriptedTests.scala b/internal/util-scripted/src/main/scala/sbt/internal/scripted/ScriptedTests.scala index ffdd4e685..9ce5dbca0 100644 --- a/internal/util-scripted/src/main/scala/sbt/internal/scripted/ScriptedTests.scala +++ b/internal/util-scripted/src/main/scala/sbt/internal/scripted/ScriptedTests.scala @@ -103,7 +103,7 @@ final class ScriptedTests( log: ManagedLogger, context: LoggerContext, ): Seq[() => Option[String]] = { - for (groupDir <- (resourceBaseDirectory * group).get; nme <- (groupDir * name).get) yield { + for (groupDir <- (resourceBaseDirectory * group).get(); nme <- (groupDir * name).get()) yield { val g = groupDir.getName val n = nme.getName val str = s"$g / $n" diff --git a/launcher-package/build.sbt b/launcher-package/build.sbt index dd9e2558c..ddfdb1f9f 100755 --- a/launcher-package/build.sbt +++ b/launcher-package/build.sbt @@ -273,7 +273,7 @@ val root = (project in file(".")). case (k, BinSbt) => import java.nio.file.{Files, FileSystems} val x = IO.read(k) - IO.write(t / "sbt", x.replaceAllLiterally( + IO.write(t / "sbt", x.replace( "declare init_sbt_version=_to_be_replaced", s"declare init_sbt_version=$sbtVersionToRelease")) diff --git a/main-actions/src/main/scala/sbt/ForkTests.scala b/main-actions/src/main/scala/sbt/ForkTests.scala index ddc01a850..80694ce30 100755 --- a/main-actions/src/main/scala/sbt/ForkTests.scala +++ b/main-actions/src/main/scala/sbt/ForkTests.scala @@ -162,7 +162,7 @@ private[sbt] object ForkTests { RunningProcesses.add(p) val ec = try p.exitValue() finally { - if (p.isAlive) p.destroy() + if (p.isAlive()) p.destroy() RunningProcesses.remove(p) } val result = @@ -223,7 +223,7 @@ private final class React( listeners.foreach(_ testEvent event) val suiteResult = SuiteResult(tEvents) results += group -> suiteResult - listeners.foreach(_ endGroup (group, suiteResult.result)) + listeners.foreach(_.endGroup(group, suiteResult.result)) react() } } diff --git a/main-actions/src/main/scala/sbt/Package.scala b/main-actions/src/main/scala/sbt/Package.scala index e083cc494..2b4946700 100644 --- a/main-actions/src/main/scala/sbt/Package.scala +++ b/main-actions/src/main/scala/sbt/Package.scala @@ -88,7 +88,7 @@ object Package { for ((key, value) <- mergeManifest.getEntries.asScala) { entryMap.get(key) match { case Some(attributes) => mergeAttributes(attributes, value); () - case None => entryMap put (key, value); () + case None => entryMap.put(key, value); () } } } diff --git a/main-actions/src/main/scala/sbt/RawCompileLike.scala b/main-actions/src/main/scala/sbt/RawCompileLike.scala index 7ac1a12cc..4a81f027b 100644 --- a/main-actions/src/main/scala/sbt/RawCompileLike.scala +++ b/main-actions/src/main/scala/sbt/RawCompileLike.scala @@ -65,7 +65,7 @@ object RawCompileLike { log.debug("Uptodate: " + outputDirectory.getAbsolutePath) } } - cachedComp(inputs)(exists(outputDirectory.allPaths.get.toSet)) + cachedComp(inputs)(exists(outputDirectory.allPaths.get().toSet)) } def prepare(description: String, doCompile: Gen): Gen = diff --git a/main-actions/src/main/scala/sbt/compiler/Eval.scala b/main-actions/src/main/scala/sbt/compiler/Eval.scala index df0386262..6995637f4 100644 --- a/main-actions/src/main/scala/sbt/compiler/Eval.scala +++ b/main-actions/src/main/scala/sbt/compiler/Eval.scala @@ -265,7 +265,7 @@ final class Eval( if (phase == null || phase == phase.next || evalReporter.hasErrors) () else { - enteringPhase(phase) { phase.run } + enteringPhase(phase) { phase.run() } compile(phase.next) } } diff --git a/main-actions/src/test/scala/sbt/CacheIvyTest.scala b/main-actions/src/test/scala/sbt/CacheIvyTest.scala index 17cb778e1..a8f76ec98 100644 --- a/main-actions/src/test/scala/sbt/CacheIvyTest.scala +++ b/main-actions/src/test/scala/sbt/CacheIvyTest.scala @@ -85,7 +85,7 @@ class CacheIvyTest extends Properties("CacheIvy") { for { o <- Gen.identifier n <- Gen.identifier - r <- for { n <- Gen.numChar; ns <- Gen.numStr } yield n + ns + r <- for { n <- Gen.numChar; ns <- Gen.numStr } yield s"$n$ns" cs <- arbitrary[Option[String]] branch <- arbitrary[Option[String]] isChanging <- arbitrary[Boolean] diff --git a/main-command/src/main/scala/sbt/BasicCommands.scala b/main-command/src/main/scala/sbt/BasicCommands.scala index 9a3e49936..bb58bd301 100644 --- a/main-command/src/main/scala/sbt/BasicCommands.scala +++ b/main-command/src/main/scala/sbt/BasicCommands.scala @@ -153,7 +153,7 @@ object BasicCommands { private[this] def completionsParser: Parser[String] = { val notQuoted = (NotQuoted ~ any.*) map { case (nq, s) => nq + s } val quotedOrUnquotedSingleArgument = Space ~> (StringVerbatim | StringEscapable | notQuoted) - token(quotedOrUnquotedSingleArgument ?? "" examples ("", " ")) + token((quotedOrUnquotedSingleArgument ?? "").examples("", " ")) } def runCompletions(state: State)(input: String): State = { @@ -199,7 +199,7 @@ object BasicCommands { val it = s.iterator var fail = false while (it.hasNext && !fail) { - it.next match { + it.next() match { case "" => fail = it.hasNext; () case next => result += next; () } diff --git a/main-command/src/main/scala/sbt/CommandUtil.scala b/main-command/src/main/scala/sbt/CommandUtil.scala index f5f15733c..dc2f52476 100644 --- a/main-command/src/main/scala/sbt/CommandUtil.scala +++ b/main-command/src/main/scala/sbt/CommandUtil.scala @@ -88,10 +88,10 @@ object CommandUtil { } def layoutDetails(details: Map[String, String]): String = - details.map { case (k, v) => k + "\n\n " + v } mkString ("\n", "\n\n", "\n") + details.map { case (k, v) => k + "\n\n " + v }.mkString("\n", "\n\n", "\n") final val HelpPatternFlags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE private[sbt] def isSbtBuild(baseDir: File) = - (baseDir / "project").exists() || (baseDir * "*.sbt").get.nonEmpty + (baseDir / "project").exists() || (baseDir * "*.sbt").get().nonEmpty } diff --git a/main-command/src/main/scala/sbt/internal/LegacyWatched.scala b/main-command/src/main/scala/sbt/internal/LegacyWatched.scala index dc9860efd..78a7a25b7 100644 --- a/main-command/src/main/scala/sbt/internal/LegacyWatched.scala +++ b/main-command/src/main/scala/sbt/internal/LegacyWatched.scala @@ -44,7 +44,7 @@ private[sbt] object LegacyWatched { (ClearOnFailure :: next :: FailureWall :: repeat :: s) .put(ContinuousEventMonitor, monitor: EventMonitor) case Some(eventMonitor) => - Watched.printIfDefined(watched watchingMessage eventMonitor.state) + Watched.printIfDefined(watched watchingMessage eventMonitor.state()) @tailrec def impl(): State = { val triggered = try eventMonitor.awaitEvent() catch { @@ -56,7 +56,7 @@ private[sbt] object LegacyWatched { false } if (triggered) { - Watched.printIfDefined(watched triggeredMessage eventMonitor.state) + Watched.printIfDefined(watched triggeredMessage eventMonitor.state()) ClearOnFailure :: next :: FailureWall :: repeat :: s } else if (shouldTerminate) { while (System.in.available() > 0) System.in.read() 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 7249e290e..8141376ac 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -380,7 +380,7 @@ class NetworkClient( } if (!startServer) { val deadline = 5.seconds.fromNow - while (socket.isEmpty && !deadline.isOverdue) { + while (socket.isEmpty && !deadline.isOverdue()) { socket = Try(ClientSocket.localSocket(bootSocketName, useJNI)).toOption if (socket.isEmpty) Thread.sleep(20) } @@ -836,12 +836,12 @@ class NetworkClient( case -1 => (query, query, None, None) // shouldn't happen case i => val rawPrefix = query.substring(0, i) - val prefix = rawPrefix.replaceAllLiterally("\"", "").replaceAllLiterally("\\;", ";") - val rawSuffix = query.substring(i).replaceAllLiterally("\\;", ";") + val prefix = rawPrefix.replace("\"", "").replace("\\;", ";") + val rawSuffix = query.substring(i).replace("\\;", ";") val suffix = if (rawSuffix.length > 1) rawSuffix.substring(1) else "" (rawPrefix, prefix, Some(rawSuffix), Some(suffix)) } - } else (query, query.replaceAllLiterally("\\;", ";"), None, None) + } else (query, query.replace("\\;", ";"), None, None) val tailSpace = query.endsWith(" ") || query.endsWith("\"") val sanitizedQuery = suffix.foldLeft(prefix) { _ + _ } def getCompletions(query: String, sendCommand: Boolean): Seq[String] = { @@ -885,7 +885,7 @@ class NetworkClient( } getCompletions(sanitizedQuery, true) collect { case c if inQuote => c - case c if tailSpace && c.contains(" ") => c.replaceAllLiterally(prefix, "") + case c if tailSpace && c.contains(" ") => c.replace(prefix, "") case c if !tailSpace => c.split(" ").last } } @@ -1106,10 +1106,10 @@ object NetworkClient { launchJar = a .split("--sbt-launch-jar=") .lastOption - .map(_.replaceAllLiterally("%20", " ")) + .map(_.replace("%20", " ")) case "--sbt-launch-jar" if i + 1 < sanitized.length => i += 1 - launchJar = Option(sanitized(i).replaceAllLiterally("%20", " ")) + launchJar = Option(sanitized(i).replace("%20", " ")) case "-bsp" | "--bsp" => bsp = true case a if !a.startsWith("-") => commandArgs += a case a @ SysProp(key, value) => @@ -1131,7 +1131,7 @@ object NetworkClient { sbtArguments.toSeq, commandArgs.toSeq, completionArguments.toSeq, - sbtScript.getOrElse(defaultSbtScript).replaceAllLiterally("%20", " "), + sbtScript.getOrElse(defaultSbtScript).replace("%20", " "), bsp, launchJar ) diff --git a/main-command/src/main/scala/sbt/internal/client/ServerConnection.scala b/main-command/src/main/scala/sbt/internal/client/ServerConnection.scala index 23e8837af..777593caa 100644 --- a/main-command/src/main/scala/sbt/internal/client/ServerConnection.scala +++ b/main-command/src/main/scala/sbt/internal/client/ServerConnection.scala @@ -79,7 +79,7 @@ abstract class ServerConnection(connection: Socket) { if (a.nonEmpty) { out.write(a) } - writeEndLine + writeEndLine() } catch { case e: IOException => shutdown() @@ -100,7 +100,7 @@ abstract class ServerConnection(connection: Socket) { out.close() connection.close() } catch { case e: IOException => e.printStackTrace() } - onShutdown + onShutdown() } } diff --git a/main-command/src/main/scala/sbt/internal/util/JoinThread.scala b/main-command/src/main/scala/sbt/internal/util/JoinThread.scala index 4c3d109f4..c955e9993 100644 --- a/main-command/src/main/scala/sbt/internal/util/JoinThread.scala +++ b/main-command/src/main/scala/sbt/internal/util/JoinThread.scala @@ -20,7 +20,7 @@ object JoinThread { t.interrupt() t.join(10) } catch { case e: InterruptedException => } - if (t.isAlive && !deadline.isOverdue) impl() + if (t.isAlive && !deadline.isOverdue()) impl() } impl() if (t.isAlive) { diff --git a/main-settings/src/main/scala/sbt/Def.scala b/main-settings/src/main/scala/sbt/Def.scala index df78134ea..13ccec44e 100644 --- a/main-settings/src/main/scala/sbt/Def.scala +++ b/main-settings/src/main/scala/sbt/Def.scala @@ -252,7 +252,7 @@ object Def extends Init[Scope] with TaskMacroExtra with InitializeImplicits { )(l: Def.Initialize[Task[A => C]])(r: Def.Initialize[Task[B => C]]): Def.Initialize[Task[C]] = { val lhs = { val innerLhs: Def.Initialize[Task[Either[A, Either[B, C]]]] = - x.map((fab: Either[A, B]) => fab.right.map(Left(_))) + x.map((fab: Either[A, B]) => fab.map(Left(_))) val innerRhs: Def.Initialize[Task[A => Either[B, C]]] = l.map((fn: A => C) => fn.andThen(Right(_))) selectITask(innerLhs, innerRhs) diff --git a/main-settings/src/test/scala/sbt/std/UsageTest.scala b/main-settings/src/test/scala/sbt/std/UsageTest.scala index 154bec498..ec1f2149e 100644 --- a/main-settings/src/test/scala/sbt/std/UsageTest.scala +++ b/main-settings/src/test/scala/sbt/std/UsageTest.scala @@ -69,7 +69,7 @@ object Assign { val is = Seq( mk := 3, name := "asdf", - tk := (math.random * 1000).toInt, + tk := (math.random() * 1000).toInt, isk := dummys.value.parsed // should not compile: cannot use a task to define the parser // ik := { if( tsk.parsed.value == "blue") tk.value else mk.value } ) diff --git a/main/src/main/scala/sbt/BuildPaths.scala b/main/src/main/scala/sbt/BuildPaths.scala index 064f50107..87bfb7173 100644 --- a/main/src/main/scala/sbt/BuildPaths.scala +++ b/main/src/main/scala/sbt/BuildPaths.scala @@ -116,7 +116,8 @@ object BuildPaths { private[this] def defaultGlobalZinc(globalBase: File) = globalBase / "zinc" def configurationSources(base: File): Seq[File] = - (base * (GlobFilter("*.sbt") - ".sbt")).get + (base * (GlobFilter("*.sbt") - ".sbt")) + .get() .sortBy(_.getName.toLowerCase(Locale.ENGLISH)) def pluginDirectory(definitionBase: File) = definitionBase / PluginsDirectoryName diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 58217442b..ec25047a0 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -3197,8 +3197,8 @@ object Classpaths { update / unresolvedWarningConfiguration := UnresolvedWarningConfiguration( dependencyPositions.value ), - updateFull := (updateTask tag (Tags.Update, Tags.Network)).value, - update := (updateWithoutDetails("update") tag (Tags.Update, Tags.Network)).value, + updateFull := (updateTask.tag(Tags.Update, Tags.Network)).value, + update := (updateWithoutDetails("update").tag(Tags.Update, Tags.Network)).value, update := { val report = update.value val log = streams.value.log @@ -3209,7 +3209,7 @@ object Classpaths { evicted / evictionWarningOptions := EvictionWarningOptions.full, evicted := { import ShowLines._ - val report = (updateTask tag (Tags.Update, Tags.Network)).value + val report = (updateTask.tag(Tags.Update, Tags.Network)).value val log = streams.value.log val ew = EvictionWarning(ivyModule.value, (evicted / evictionWarningOptions).value, report) @@ -3701,7 +3701,7 @@ object Classpaths { try { val extracted = (Project extract st) val sk = (projRef / Zero / Zero / libraryDependencies).scopedKey - val empty = extracted.structure.data set (sk.scope, sk.key, Nil) + val empty = extracted.structure.data.set(sk.scope, sk.key, Nil) val settings = extracted.structure.settings filter { s: Setting[_] => (s.key.key == libraryDependencies.key) && (s.key.scope.project == Select(projRef)) @@ -4318,7 +4318,7 @@ trait BuildExtra extends BuildCommon with DefExtra { /** Constructs a setting that declares a new artifact `a` that is generated by `taskDef`. */ def addArtifact(a: Artifact, taskDef: TaskKey[File]): SettingsDefinition = { - val pkgd = packagedArtifacts := packagedArtifacts.value updated (a, taskDef.value) + val pkgd = packagedArtifacts := packagedArtifacts.value.updated(a, taskDef.value) Seq(artifacts += a, pkgd) } @@ -4330,7 +4330,7 @@ trait BuildExtra extends BuildCommon with DefExtra { val artLocal = SettingKey.local[Artifact] val taskLocal = TaskKey.local[File] val art = artifacts := artLocal.value +: artifacts.value - val pkgd = packagedArtifacts := packagedArtifacts.value updated (artLocal.value, taskLocal.value) + val pkgd = packagedArtifacts := packagedArtifacts.value.updated(artLocal.value, taskLocal.value) Seq(artLocal := artifact.value, taskLocal := taskDef.value, art, pkgd) } diff --git a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala index 8bbdb8969..6545478a2 100644 --- a/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala +++ b/main/src/main/scala/sbt/coursierint/CoursierRepositoriesTasks.scala @@ -80,10 +80,10 @@ object CoursierRepositoriesTasks { result1 map { case r: FileRepository => val ivyPatterns = r.patterns.ivyPatterns map { - _.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri) + _.replace("$" + "{ivy.home}", ivyHomeUri) } val artifactPatterns = r.patterns.artifactPatterns map { - _.replaceAllLiterally("$" + "{ivy.home}", ivyHomeUri) + _.replace("$" + "{ivy.home}", ivyHomeUri) } val p = r.patterns.withIvyPatterns(ivyPatterns).withArtifactPatterns(artifactPatterns) diff --git a/main/src/main/scala/sbt/internal/BuildStructure.scala b/main/src/main/scala/sbt/internal/BuildStructure.scala index 4c10fba22..8bd0bcccf 100644 --- a/main/src/main/scala/sbt/internal/BuildStructure.scala +++ b/main/src/main/scala/sbt/internal/BuildStructure.scala @@ -263,7 +263,8 @@ final class BuildUnit( val plugins: LoadedPlugins ) { override def toString = - if (uri.getScheme == "file") localBase.toString else (uri + " (locally: " + localBase + ")") + if (uri.getScheme == "file") localBase.toString + else (uri.toString + " (locally: " + localBase + ")") } final class LoadedBuild(val root: URI, val units: Map[URI, LoadedBuildUnit]) { diff --git a/main/src/main/scala/sbt/internal/InstallSbtn.scala b/main/src/main/scala/sbt/internal/InstallSbtn.scala index 271a9a0cf..b6a1a2682 100644 --- a/main/src/main/scala/sbt/internal/InstallSbtn.scala +++ b/main/src/main/scala/sbt/internal/InstallSbtn.scala @@ -25,7 +25,7 @@ private[sbt] object InstallSbtn { Def.inputKey[Unit]("install sbtn and tab completions").withRank(KeyRanks.BTask) private[sbt] def installSbtnImpl: Def.Initialize[InputTask[Unit]] = Def.inputTask { val inputVersion = Def.spaceDelimited("version").parsed.headOption - val version = inputVersion.getOrElse(sbtVersion.value.replaceAllLiterally("-SNAPSHOT", "")) + val version = inputVersion.getOrElse(sbtVersion.value.replace("-SNAPSHOT", "")) val term = terminal.value term.setMode(canonical = false, echo = false) val baseDirectory = BuildPaths.getGlobalBase(state.value).toPath diff --git a/main/src/main/scala/sbt/internal/graph/rendering/DagreHTML.scala b/main/src/main/scala/sbt/internal/graph/rendering/DagreHTML.scala index f00a197d2..0938d9ec9 100644 --- a/main/src/main/scala/sbt/internal/graph/rendering/DagreHTML.scala +++ b/main/src/main/scala/sbt/internal/graph/rendering/DagreHTML.scala @@ -25,7 +25,7 @@ object DagreHTML { val graphString = URLEncoder .encode(dotGraph, "utf8") - .replaceAllLiterally("+", "%20") + .replace("+", "%20") IO.write( new File(targetDirectory, "dependencies.dot.js"), diff --git a/main/src/test/scala/ParseKey.scala b/main/src/test/scala/ParseKey.scala index 343e0bfe2..d5405a0da 100644 --- a/main/src/test/scala/ParseKey.scala +++ b/main/src/test/scala/ParseKey.scala @@ -173,7 +173,7 @@ object ParseKey extends Properties { .log(s"Key: ${Scope.displayPedantic(key.scope, key.key.label)}") .log(s"Mask: $mask") .log(s"Key string: '$s'") - .log(s"Parsed: ${parsed.right.map(displayFull)}") + .log(s"Parsed: ${parsed.map(displayFull)}") .log(s"Structure: $structure") ) } diff --git a/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala b/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala index 3580007ed..a5b47d6fd 100644 --- a/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala +++ b/main/src/test/scala/sbt/internal/InstallSbtnSpec.scala @@ -41,7 +41,7 @@ class InstallSbtnSpec extends FlatSpec { val tmpDir = Files.createTempDirectory("sbtn-test").toRealPath() Files.createDirectories(tmpDir.resolve("project")) val foo = tmpDir.resolve("foo") - val fooPath = foo.toString.replaceAllLiterally("\\", "\\\\") + val fooPath = foo.toString.replace("\\", "\\\\") val build = s"""TaskKey[Unit]("foo") := IO.write(file("$fooPath"), "foo")""" IO.write(tmpDir.resolve("build.sbt").toFile, build) IO.write( diff --git a/main/src/test/scala/sbt/internal/StressGCMonitor.scala b/main/src/test/scala/sbt/internal/StressGCMonitor.scala index d9593ef79..8566b21d1 100644 --- a/main/src/test/scala/sbt/internal/StressGCMonitor.scala +++ b/main/src/test/scala/sbt/internal/StressGCMonitor.scala @@ -19,7 +19,7 @@ object StressGCMonitor { new GCMonitor(ConsoleLogger()) val deadline = Deadline.now + 10.seconds while (!deadline.isOverdue()) { - println(deadline.timeLeft.toSeconds + " seconds left...") + println(s"${deadline.timeLeft.toSeconds} seconds left...") list = List.fill(1000 * 1000 * 100)(Random.nextInt(100)) System.gc() Thread.sleep(10) diff --git a/main/src/test/scala/sbt/internal/TestBuild.scala b/main/src/test/scala/sbt/internal/TestBuild.scala index 48bf993b9..b9290240e 100644 --- a/main/src/test/scala/sbt/internal/TestBuild.scala +++ b/main/src/test/scala/sbt/internal/TestBuild.scala @@ -51,7 +51,7 @@ abstract class TestBuild { def tGen = genTasks(kebabIdGen, MaxDepsGen, MaxTasksGen) class TestKeys(val env: Env, val scopes: Seq[Scope]) { - override def toString = env + "\n" + scopes.mkString("Scopes:\n\t", "\n\t", "") + override def toString = env.toString + "\n" + scopes.mkString("Scopes:\n\t", "\n\t", "") lazy val delegated = scopes map env.delegates } diff --git a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala index 85c2bd3cb..dc99a4973 100644 --- a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala +++ b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala @@ -39,7 +39,7 @@ object BuildServerConnection { val sbtLaunchJar = classPath .split(File.pathSeparator) .find(jar => SbtLaunchJar.findFirstIn(jar).nonEmpty) - .map(_.replaceAllLiterally(" ", "%20")) + .map(_.replace(" ", "%20")) .map(jar => s"--sbt-launch-jar=$jar") val argv = @@ -66,6 +66,6 @@ object BuildServerConnection { allPaths .map(_.resolve(fileName)) .find(file => Files.exists(file) && Files.isExecutable(file)) - .map(_.toString.replaceAllLiterally(" ", "%20")) + .map(_.toString.replace(" ", "%20")) } } diff --git a/tasks-standard/src/main/scala/sbt/std/TaskExtra.scala b/tasks-standard/src/main/scala/sbt/std/TaskExtra.scala index 4483b9eec..3d2061d2c 100644 --- a/tasks-standard/src/main/scala/sbt/std/TaskExtra.scala +++ b/tasks-standard/src/main/scala/sbt/std/TaskExtra.scala @@ -200,7 +200,7 @@ trait TaskExtra extends TaskExtra0 { val pio = TaskExtra .processIO(s) .withInput(out => { BasicIO.transferFully(in, out); out.close() }) - (p run pio).exitValue + (p run pio).exitValue() } } @@ -246,7 +246,7 @@ trait TaskExtra extends TaskExtra0 { implicit def processToTask(p: ProcessBuilder)(implicit streams: Task[TaskStreams[_]]): Task[Int] = streams map { s => val pio = TaskExtra.processIO(s) - (p run pio).exitValue + (p run pio).exitValue() } } object TaskExtra extends TaskExtra { diff --git a/tasks-standard/src/test/scala/Test.scala b/tasks-standard/src/test/scala/Test.scala index 72daac5bc..36091c583 100644 --- a/tasks-standard/src/test/scala/Test.scala +++ b/tasks-standard/src/test/scala/Test.scala @@ -20,25 +20,25 @@ object Test extends std.TaskExtra { val b2 = task(true) val c = task("asdf") - val h1 = t3(a, b, c).map { case (aa, bb, cc) => aa + " " + bb + " " + cc } - val h2 = t3(a, b2, c).map { case (aa, bb, cc) => aa + " " + bb + " " + cc } + val h1 = t3(a, b, c).map { case (aa, bb, cc) => s"$aa $bb $cc" } + val h2 = t3(a, b2, c).map { case (aa, bb, cc) => s"$aa $bb $cc" } type Values = (Result[Int], Result[Boolean], Result[String]) val f: Values => Any = { - case (Value(aa), Value(bb), Value(cc)) => aa + " " + bb + " " + cc + case (Value(aa), Value(bb), Value(cc)) => s"$aa $bb $cc" case x => val cs = x.productIterator.toList.collect { case Inc(x) => x } // workaround for double definition bug throw Incomplete(None, causes = cs) } val d2 = t3(a, b2, c) mapR f val f2: Values => Task[Any] = { - case (Value(aa), Value(bb), Value(cc)) => task(aa + " " + bb + " " + cc) + case (Value(aa), Value(bb), Value(cc)) => task(s"$aa $bb $cc") case _ => d3 } lazy val d = t3(a, b, c) flatMapR f2 val f3: Values => Task[Any] = { - case (Value(aa), Value(bb), Value(cc)) => task(aa + " " + bb + " " + cc) + case (Value(aa), Value(bb), Value(cc)) => task(s"$aa $bb $cc") case _ => d2 } lazy val d3 = t3(a, b, c) flatMapR f3 diff --git a/tasks/src/main/scala/sbt/ConcurrentRestrictions.scala b/tasks/src/main/scala/sbt/ConcurrentRestrictions.scala index f57b2f02e..dadb4fa6c 100644 --- a/tasks/src/main/scala/sbt/ConcurrentRestrictions.scala +++ b/tasks/src/main/scala/sbt/ConcurrentRestrictions.scala @@ -235,7 +235,7 @@ object ConcurrentRestrictions { sentinels.toList foreach { s => s.cancel(true) } - sentinels.clear + sentinels.clear() } def submit(node: A, work: () => R): Unit = synchronized { diff --git a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala index 95bbee3b6..ebe66bfcd 100644 --- a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala +++ b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala @@ -112,9 +112,9 @@ class JUnitXmlTestsListener(val targetDir: File, legacyTestReport: Boolean, logg val classnameRegex = s"^($name|${name.split('.').last})\\.?".r val result = - {properties} diff --git a/testing/src/main/scala/sbt/TestFramework.scala b/testing/src/main/scala/sbt/TestFramework.scala index 77f5089dd..d7e057ac5 100644 --- a/testing/src/main/scala/sbt/TestFramework.scala +++ b/testing/src/main/scala/sbt/TestFramework.scala @@ -256,7 +256,7 @@ object TestFramework { def foreachListenerSafe(f: TestsListener => Unit): () => Unit = () => safeForeach(testsListeners, log)(f) - val startTask = foreachListenerSafe(_.doInit) + val startTask = foreachListenerSafe(_.doInit()) val testTasks = Map(tests.toSeq.flatMap { case (framework, testDefinitions) => diff --git a/testing/src/main/scala/sbt/TestStatusReporter.scala b/testing/src/main/scala/sbt/TestStatusReporter.scala index 38a7987ac..72b1a40ae 100644 --- a/testing/src/main/scala/sbt/TestStatusReporter.scala +++ b/testing/src/main/scala/sbt/TestStatusReporter.scala @@ -19,7 +19,7 @@ import scala.collection.concurrent private[sbt] class TestStatusReporter(f: File) extends TestsListener { private lazy val succeeded: concurrent.Map[String, Long] = TestStatus.read(f) - def doInit = () + def doInit(): Unit = () def startGroup(name: String): Unit = { succeeded remove name; () } def testEvent(event: TestEvent): Unit = () def endGroup(name: String, t: Throwable): Unit = () diff --git a/testing/src/main/scala/sbt/internal/testing/TestLogger.scala b/testing/src/main/scala/sbt/internal/testing/TestLogger.scala index 86ca21de2..0e7bd1437 100644 --- a/testing/src/main/scala/sbt/internal/testing/TestLogger.scala +++ b/testing/src/main/scala/sbt/internal/testing/TestLogger.scala @@ -125,7 +125,7 @@ class TestLogger(val logging: TestLogging) extends TestsListener { import logging.{ global => log, logTest, managed } import sbt.protocol.testing.codec.JsonProtocol._ - def doInit: Unit = managed.logEvent(Level.Info, TestInitEvent()) + def doInit(): Unit = managed.logEvent(Level.Info, TestInitEvent()) def startGroup(name: String): Unit = managed.logEvent(Level.Info, StartTestGroupEvent(name)) diff --git a/util-cache/src/main/scala/sbt/util/SeparatedCache.scala b/util-cache/src/main/scala/sbt/util/SeparatedCache.scala index 9596436fb..c986bfdfc 100644 --- a/util-cache/src/main/scala/sbt/util/SeparatedCache.scala +++ b/util-cache/src/main/scala/sbt/util/SeparatedCache.scala @@ -31,7 +31,7 @@ object SingletonCache { implicit def basicSingletonCache[A: JsonFormat]: SingletonCache[A] = new SingletonCache[A] { - override def read(from: Input): A = from.read[A] + override def read(from: Input): A = from.read[A]() override def write(to: Output, value: A) = to.write(value) } diff --git a/util-cache/src/test/scala/CacheSpec.scala b/util-cache/src/test/scala/CacheSpec.scala index 587efed32..d96d9e924 100644 --- a/util-cache/src/test/scala/CacheSpec.scala +++ b/util-cache/src/test/scala/CacheSpec.scala @@ -20,7 +20,7 @@ class CacheSpec extends FlatSpec { testCache[String, Int] { case (cache, store) => cache(store)("missing") match { - case Hit(_) => fail + case Hit(_) => fail() case Miss(_) => () } } @@ -30,7 +30,7 @@ class CacheSpec extends FlatSpec { testCache[String, Int] { case (cache, store) => cache(store)("missing") match { - case Hit(_) => fail + case Hit(_) => fail() case Miss(update) => update(5) } } @@ -41,13 +41,13 @@ class CacheSpec extends FlatSpec { case (cache, store) => val value = 5 cache(store)("someKey") match { - case Hit(_) => fail + case Hit(_) => fail() case Miss(update) => update(value) } cache(store)("someKey") match { case Hit(read) => assert(read === value); () - case Miss(_) => fail + case Miss(_) => fail() } } } @@ -58,13 +58,13 @@ class CacheSpec extends FlatSpec { val key = "someKey" val value = 5 cache(store)(key) match { - case Hit(_) => fail + case Hit(_) => fail() case Miss(update) => update(value) } cache(store)(key) match { case Hit(read) => assert(read === value); () - case Miss(_) => fail + case Miss(_) => fail() } } } diff --git a/util-tracking/src/main/scala/sbt/util/Tracked.scala b/util-tracking/src/main/scala/sbt/util/Tracked.scala index 883872f1d..b4bc765c1 100644 --- a/util-tracking/src/main/scala/sbt/util/Tracked.scala +++ b/util-tracking/src/main/scala/sbt/util/Tracked.scala @@ -69,7 +69,7 @@ object Tracked { /** Creates a tracker that provides the output of the most recent invocation of the function */ def lastOutput[I, O: JsonFormat](store: CacheStore)(f: (I, Option[O]) => O): I => O = { in => - val previous = Try { store.read[O] }.toOption + val previous = Try { store.read[O]() }.toOption val next = f(in, previous) store.write(next) next @@ -277,7 +277,7 @@ object Tracked { } def changed(store: CacheStore, value: I): Boolean = - Try { store.read[Long] } match { + Try { store.read[Long]() } match { case USuccess(prev: Long) => Hasher.hash(value) match { case USuccess(keyHash: Int) => keyHash.toLong != prev @@ -321,7 +321,7 @@ class Timestamp(val store: CacheStore, useStartTime: Boolean)(implicit format: J private def now() = System.currentTimeMillis def readTimestamp: Long = - Try { store.read[Long] } getOrElse 0 + Try { store.read[Long]() } getOrElse 0 } @deprecated("Use Tracked.inputChanged and Tracked.outputChanged instead", "1.0.1") @@ -342,7 +342,7 @@ class Changed[O: Equiv: JsonFormat](val store: CacheStore) extends Tracked { def uptodate(value: O): Boolean = { val equiv: Equiv[O] = implicitly - equiv.equiv(value, store.read[O]) + equiv.equiv(value, store.read[O]()) } } diff --git a/util-tracking/src/test/scala/sbt/util/TrackedSpec.scala b/util-tracking/src/test/scala/sbt/util/TrackedSpec.scala index f456931f0..8b44524d3 100644 --- a/util-tracking/src/test/scala/sbt/util/TrackedSpec.scala +++ b/util-tracking/src/test/scala/sbt/util/TrackedSpec.scala @@ -160,7 +160,7 @@ class TrackedSpec extends FlatSpec { withStore { store => val beforeCompletion: String = "before-completion" val afterCompletion: String = "after-completion" - val sideEffectCompleted = Promise[Unit] + val sideEffectCompleted = Promise[Unit]() val p0: () => String = () => { if (sideEffectCompleted.isCompleted) { afterCompletion From 1f4517d5cc5f6417c24fc3478819d41b548e1ba6 Mon Sep 17 00:00:00 2001 From: kenji yoshida <6b656e6a69@gmail.com> Date: Sun, 14 Nov 2021 21:27:44 +0900 Subject: [PATCH 022/120] update hedgehog and scalacheck prepare Scala 3 --- project/Dependencies.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 7dc4fb126..42afc3136 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -95,7 +95,7 @@ object Dependencies { val jline3Builtins = "org.jline" % "jline-builtins" % jline3Version val jansi = "org.fusesource.jansi" % "jansi" % "2.1.0" val scalatest = "org.scalatest" %% "scalatest" % "3.2.10" - val scalacheck = "org.scalacheck" %% "scalacheck" % "1.14.0" + val scalacheck = "org.scalacheck" %% "scalacheck" % "1.15.4" val junit = "junit" % "junit" % "4.13.1" val scalaVerify = "com.eed3si9n.verify" %% "verify" % "1.0.0" val templateResolverApi = "org.scala-sbt" % "template-resolver" % "0.1" @@ -114,7 +114,7 @@ object Dependencies { val caffeine = "com.github.ben-manes.caffeine" % "caffeine" % "2.8.5" - val hedgehog = "qa.hedgehog" %% "hedgehog-sbt" % "0.6.1" + val hedgehog = "qa.hedgehog" %% "hedgehog-sbt" % "0.7.0" val disruptor = "com.lmax" % "disruptor" % "3.4.2" val kindProjector = ("org.typelevel" % "kind-projector" % "0.13.2").cross(CrossVersion.full) } From 38f54490843957c8ff29c947419034f612490ab2 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Tue, 16 Nov 2021 10:19:26 +0900 Subject: [PATCH 023/120] Update build settings for Scala 3 --- build.sbt | 25 +++++++++++++++++++------ project/Dependencies.scala | 24 +++++++++++++++++++++--- project/HouseRulesPlugin.scala | 5 +++++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/build.sbt b/build.sbt index 72c80254b..e8c0a5d3b 100644 --- a/build.sbt +++ b/build.sbt @@ -102,8 +102,15 @@ def commonBaseSettings: Seq[Setting[_]] = Def.settings( run / fork := true, ) def commonSettings: Seq[Setting[_]] = - commonBaseSettings :+ - addCompilerPlugin(kindProjector) + commonBaseSettings :+ { + libraryDependencies ++= { + if (scalaBinaryVersion.value == "3") { + Nil + } else { + Seq(compilerPlugin(kindProjector)) + } + } + } def utilCommonSettings: Seq[Setting[_]] = baseSettings :+ (crossScalaVersions := (scala212 :: scala213 :: Nil)) @@ -463,7 +470,7 @@ lazy val utilScripted = (project in file("internal") / "util-scripted") .settings( utilCommonSettings, name := "Util Scripted", - libraryDependencies += scalaParsers, + libraryDependencies += scalaParsers.value, utilMimaSettings, ) .configure(addSbtIO) @@ -477,7 +484,7 @@ lazy val testingProj = (project in file("testing")) baseSettings, name := "Testing", libraryDependencies ++= Seq( - scalaXml, + scalaXml.value, testInterface, launcherInterface, sjsonNewScalaJson.value @@ -803,7 +810,13 @@ lazy val coreMacrosProj = (project in file("core-macros")) .settings( baseSettings :+ (crossScalaVersions := (scala212 :: scala213 :: Nil)), name := "Core Macros", - libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value, + libraryDependencies += { + if (scalaBinaryVersion.value == "3") { + "org.scala-lang" % "scala-compiler" % scala213 + } else { + "org.scala-lang" % "scala-compiler" % scalaVersion.value + } + }, SettingKey[Boolean]("exportPipelining") := false, mimaSettings, ) @@ -913,7 +926,7 @@ lazy val mainProj = (project in file("main")) } }, libraryDependencies ++= - (Seq(scalaXml, launcherInterface, caffeine, lmCoursierShaded) ++ log4jModules), + (Seq(scalaXml.value, launcherInterface, caffeine, lmCoursierShaded) ++ log4jModules), libraryDependencies ++= (scalaVersion.value match { case v if v.startsWith("2.12.") => List() case _ => List(scalaPar) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 42afc3136..aa9948bfc 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -100,9 +100,27 @@ object Dependencies { val scalaVerify = "com.eed3si9n.verify" %% "verify" % "1.0.0" val templateResolverApi = "org.scala-sbt" % "template-resolver" % "0.1" - val scalaXml = "org.scala-lang.modules" %% "scala-xml" % "1.3.0" - val scalaParsers = "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2" - val scalaReflect = Def.setting("org.scala-lang" % "scala-reflect" % scalaVersion.value) + val scalaXml = Def.setting( + if (scalaBinaryVersion.value == "3") { + "org.scala-lang.modules" %% "scala-xml" % "2.0.1" + } else { + "org.scala-lang.modules" %% "scala-xml" % "1.3.0" + } + ) + val scalaParsers = Def.setting( + if (scalaBinaryVersion.value == "3") { + "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.0" + } else { + "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2" + } + ) + val scalaReflect = Def.setting( + if (scalaBinaryVersion.value == "3") { + "org.scala-lang" % "scala-reflect" % scala213 + } else { + "org.scala-lang" % "scala-reflect" % scalaVersion.value + } + ) val scalaPar = "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0" // specify all of log4j modules to prevent misalignment diff --git a/project/HouseRulesPlugin.scala b/project/HouseRulesPlugin.scala index 4a0b9fa1e..f1532dd8c 100644 --- a/project/HouseRulesPlugin.scala +++ b/project/HouseRulesPlugin.scala @@ -23,6 +23,7 @@ object HouseRulesPlugin extends AutoPlugin { }) .value .toList, + scalacOptions ++= "-Ykind-projector".ifScala3.value.toList, scalacOptions ++= "-Yinline-warnings".ifScala211OrMinus.value.toList, scalacOptions ++= "-Yno-adapted-args".ifScala212OrMinus.value.toList, scalacOptions += "-Ywarn-dead-code", @@ -44,5 +45,9 @@ object HouseRulesPlugin extends AutoPlugin { def ifScala211OrPlus = ifScalaGte(11) def ifScala212OrMinus = ifScalaLte(12) def ifScala213OrMinus = ifScalaLte(13) + def ifScala3 = Def.setting( + if (scalaBinaryVersion.value == "3") Seq(__x) + else Nil + ) } } From 5c90a84c72ca6aae1f08dae1cd1467da6a3d29fd Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Tue, 16 Nov 2021 10:36:27 +0900 Subject: [PATCH 024/120] SourcePositionMacro for Scala 3 --- .github/workflows/ci.yml | 3 +- .scalafmt.conf | 5 ++ .../internal/util/SourcePositionMacro.scala | 53 +++++++++++++++++++ .../internal/util/SourcePositionMacro.scala | 34 ++++++++++++ .../scala/sbt/internal/util/Positions.scala | 47 +--------------- 5 files changed, 95 insertions(+), 47 deletions(-) create mode 100644 internal/util-position/src/main/scala-2/sbt/internal/util/SourcePositionMacro.scala create mode 100644 internal/util-position/src/main/scala-3/sbt/internal/util/SourcePositionMacro.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9049dd13c..ad88219d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,7 @@ jobs: 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_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 TEST_SBT_VER: 1.5.0 @@ -134,7 +135,7 @@ jobs: if: ${{ matrix.jobtype == 5 }} shell: bash run: | - ./sbt -v "++$SCALA_213!; test;" + ./sbt -v "++$SCALA_213!; test; ++$SCALA_3!; all utilControl/test utilRelation/test utilPosition/test" - name: Build and test (6) if: ${{ matrix.jobtype == 6 }} shell: bash diff --git a/.scalafmt.conf b/.scalafmt.conf index 213dea496..06a114f59 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -21,3 +21,8 @@ align.openParenDefnSite = false danglingParentheses = true trailingCommas = preserve + +# TODO update scalafmt and enable Scala 3 +project.excludeFilters = [ + "internal/util-position/src/main/scala-3/sbt/internal/util/SourcePositionMacro.scala" +] diff --git a/internal/util-position/src/main/scala-2/sbt/internal/util/SourcePositionMacro.scala b/internal/util-position/src/main/scala-2/sbt/internal/util/SourcePositionMacro.scala new file mode 100644 index 000000000..a4a38e744 --- /dev/null +++ b/internal/util-position/src/main/scala-2/sbt/internal/util/SourcePositionMacro.scala @@ -0,0 +1,53 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt.internal.util + +import scala.language.experimental.macros +import scala.annotation.tailrec +import scala.reflect.macros.blackbox +import scala.reflect.internal.util.UndefinedPosition + +abstract class SourcePositionImpl { + + /** Creates a SourcePosition by using the enclosing position of the invocation of this method. + * @return SourcePosition + */ + def fromEnclosing(): SourcePosition = macro SourcePositionMacro.fromEnclosingImpl +} + +final class SourcePositionMacro(val c: blackbox.Context) { + import c.universe.{ NoPosition => _, _ } + + def fromEnclosingImpl(): Expr[SourcePosition] = { + val pos = c.enclosingPosition + if (!pos.isInstanceOf[UndefinedPosition] && pos.line >= 0 && pos.source != null) { + val f = pos.source.file + val name = constant[String](ownerSource(f.path, f.name)) + val line = constant[Int](pos.line) + reify { LinePosition(name.splice, line.splice) } + } else + reify { NoPosition } + } + + private[this] def ownerSource(path: String, name: String): String = { + @tailrec def inEmptyPackage(s: Symbol): Boolean = + s != NoSymbol && ( + s.owner == c.mirror.EmptyPackage + || s.owner == c.mirror.EmptyPackageClass + || inEmptyPackage(s.owner) + ) + + c.internal.enclosingOwner match { + case ec if !ec.isStatic => name + case ec if inEmptyPackage(ec) => path + case ec => s"(${ec.fullName}) $name" + } + } + + private[this] def constant[T: WeakTypeTag](t: T): Expr[T] = c.Expr[T](Literal(Constant(t))) +} diff --git a/internal/util-position/src/main/scala-3/sbt/internal/util/SourcePositionMacro.scala b/internal/util-position/src/main/scala-3/sbt/internal/util/SourcePositionMacro.scala new file mode 100644 index 000000000..f6e45f37d --- /dev/null +++ b/internal/util-position/src/main/scala-3/sbt/internal/util/SourcePositionMacro.scala @@ -0,0 +1,34 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt.internal.util + +import scala.quoted.{ Expr, Quotes, quotes } + +abstract class SourcePositionImpl { + + /** Creates a SourcePosition by using the enclosing position of the invocation of this method. + * + * @return SourcePosition + */ + inline def fromEnclosing(): SourcePosition = + ${ SourcePositionImpl.fromEnclosingImpl } +} + +object SourcePositionImpl { + + def fromEnclosingImpl(using Quotes): Expr[SourcePosition] = { + val x = quotes.reflect.Position.ofMacroExpansion + + '{ + LinePosition( + path = ${Expr(x.sourceFile.name)}, + startLine = ${Expr(x.startLine + 1)} + ) + } + } +} diff --git a/internal/util-position/src/main/scala/sbt/internal/util/Positions.scala b/internal/util-position/src/main/scala/sbt/internal/util/Positions.scala index c3895a4bd..78deb8e48 100644 --- a/internal/util-position/src/main/scala/sbt/internal/util/Positions.scala +++ b/internal/util-position/src/main/scala/sbt/internal/util/Positions.scala @@ -7,8 +7,6 @@ package sbt.internal.util -import scala.language.experimental.macros - sealed trait SourcePosition sealed trait FilePosition extends SourcePosition { @@ -28,47 +26,4 @@ final case class RangePosition(path: String, range: LineRange) extends FilePosit def startLine = range.start } -object SourcePosition { - - /** Creates a SourcePosition by using the enclosing position of the invocation of this method. - * @return SourcePosition - */ - def fromEnclosing(): SourcePosition = macro SourcePositionMacro.fromEnclosingImpl - -} - -import scala.annotation.tailrec -import scala.reflect.macros.blackbox -import scala.reflect.internal.util.UndefinedPosition - -final class SourcePositionMacro(val c: blackbox.Context) { - import c.universe.{ NoPosition => _, _ } - - def fromEnclosingImpl(): Expr[SourcePosition] = { - val pos = c.enclosingPosition - if (!pos.isInstanceOf[UndefinedPosition] && pos.line >= 0 && pos.source != null) { - val f = pos.source.file - val name = constant[String](ownerSource(f.path, f.name)) - val line = constant[Int](pos.line) - reify { LinePosition(name.splice, line.splice) } - } else - reify { NoPosition } - } - - private[this] def ownerSource(path: String, name: String): String = { - @tailrec def inEmptyPackage(s: Symbol): Boolean = - s != NoSymbol && ( - s.owner == c.mirror.EmptyPackage - || s.owner == c.mirror.EmptyPackageClass - || inEmptyPackage(s.owner) - ) - - c.internal.enclosingOwner match { - case ec if !ec.isStatic => name - case ec if inEmptyPackage(ec) => path - case ec => s"(${ec.fullName}) $name" - } - } - - private[this] def constant[T: WeakTypeTag](t: T): Expr[T] = c.Expr[T](Literal(Constant(t))) -} +object SourcePosition extends SourcePositionImpl From 6c68b843d5fa984da7fc8eb5885720b427c20fb7 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 16 Nov 2021 19:23:25 -0500 Subject: [PATCH 025/120] Fixes tab completion of global keys Fixes #1373 Fixes #6715 Following my own PR #2855 around `ThisBuild`, this attempts to fix the tab completion of globally scoped keys from the shell. --- main/src/main/scala/sbt/internal/Act.scala | 7 ++++++- server-test/src/test/scala/testpkg/ClientTest.scala | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/main/src/main/scala/sbt/internal/Act.scala b/main/src/main/scala/sbt/internal/Act.scala index ce7a45639..50bdde82d 100644 --- a/main/src/main/scala/sbt/internal/Act.scala +++ b/main/src/main/scala/sbt/internal/Act.scala @@ -304,7 +304,12 @@ object Act { case Some(ProjectRef(uri, _)) => index.keys(Some(BuildRef(uri)), conf, task) case _ => Set() } - val keys: Set[String] = index.keys(proj, conf, task) ++ buildKeys + val globalKeys: Set[String] = + proj match { + case Some(_) => index.keys(None, conf, task) + case _ => Set() + } + val keys: Set[String] = index.keys(proj, conf, task) ++ buildKeys ++ globalKeys keyParser(keys) } diff --git a/server-test/src/test/scala/testpkg/ClientTest.scala b/server-test/src/test/scala/testpkg/ClientTest.scala index e03bd8a11..b4352062a 100644 --- a/server-test/src/test/scala/testpkg/ClientTest.scala +++ b/server-test/src/test/scala/testpkg/ClientTest.scala @@ -118,14 +118,16 @@ object ClientTest extends AbstractServerTest { "compileIncSetup", "compileIncremental", "compileJava", + "compileOrder", "compileOutputs", "compileProgress", "compileScalaBackend", "compileSplit", + "compilerCache", "compilers", ) - assert(complete("compi") == expected) + assert(complete("compi").toVector == expected) } test("testOnly completions") { _ => val testOnlyExpected = Vector( From 307f46a3c0051e5c901cab316cae6ddce587a02b Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Fri, 19 Nov 2021 20:41:39 -0500 Subject: [PATCH 026/120] Fix line endings in msi Fixes #6717 --- .gitattributes | 4 ++++ launcher-package/src/windows/sbt | 1 + 2 files changed, 5 insertions(+) diff --git a/.gitattributes b/.gitattributes index 11d44bd7f..5b6b22eaf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,7 @@ +sbt text eol=lf +*.sh text eol=lf +launcher-package/src/windows/sbt text eol=lf + # Exclude contraband generated files from diff (by default - you can see it if you want) **/contraband-scala/**/* -diff merge=ours **/contraband-scala/**/* linguist-generated=true diff --git a/launcher-package/src/windows/sbt b/launcher-package/src/windows/sbt index ce24abbdd..c8d63bbd4 100644 --- a/launcher-package/src/windows/sbt +++ b/launcher-package/src/windows/sbt @@ -36,3 +36,4 @@ else # Use Jansi to intercept ANSI sequences "$JAVA_CMD" -Dsbt.log.format=true $JAVA_OPTS $SBT_OPTS -cp "$WDIR/sbt-launch.jar" xsbt.boot.Boot "$@" fi + From db17b5a46290d310ddbf5a907fe2a1bf5261aa48 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 25 Nov 2021 21:32:44 -0500 Subject: [PATCH 027/120] lm-coursier 2.0.9 https://github.com/coursier/sbt-coursier/releases/tag/v2.0.9 https://github.com/coursier/coursier/releases/tag/v2.1.0-M1 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index aa9948bfc..a9451c2ab 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -77,7 +77,7 @@ object Dependencies { def addSbtZincCompile = addSbtModule(sbtZincPath, "zincCompileJVM2_12", zincCompile) def addSbtZincCompileCore = addSbtModule(sbtZincPath, "zincCompileCoreJVM2_12", zincCompileCore) - val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.0.8" + val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.0.9" def sjsonNew(n: String) = Def.setting("com.eed3si9n" %% n % "0.9.1") // contrabandSjsonNewVersion.value From a448b1caab5b028923c1390ab6cf23a1824d95dc Mon Sep 17 00:00:00 2001 From: David Francoeur Date: Sat, 27 Nov 2021 02:44:49 -0500 Subject: [PATCH 028/120] Load credentials from SBT_CREDENTIALS (#6724) Load credentials from SBT_CREDENTIALS Prefer sys.env to System.getenv --- .../main/scala/sbt/internal/util/Util.scala | 4 +-- .../scala/sbt/internal/util/Terminal.scala | 32 +++++++++---------- .../sbt/internal/client/NetworkClient.scala | 2 +- main/src/main/scala/sbt/Defaults.scala | 3 +- .../src/main/scala/sbt/internal/SysProp.scala | 6 +++- .../internal/bsp/BuildServerConnection.scala | 2 +- .../run/fork/src/main/scala/ForkFail.scala | 2 +- .../sbt-test/tests/fork2/changes/Test.scala | 2 +- 8 files changed, 28 insertions(+), 25 deletions(-) diff --git a/internal/util-collection/src/main/scala/sbt/internal/util/Util.scala b/internal/util-collection/src/main/scala/sbt/internal/util/Util.scala index 8ec3636a6..ca03ed381 100644 --- a/internal/util-collection/src/main/scala/sbt/internal/util/Util.scala +++ b/internal/util-collection/src/main/scala/sbt/internal/util/Util.scala @@ -54,7 +54,7 @@ object Util { System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows") lazy val isCygwin: Boolean = { - val os = Option(System.getenv("OSTYPE")) + val os = sys.env.get("OSTYPE") os match { case Some(x) => x.toLowerCase(Locale.ENGLISH).contains("cygwin") case _ => false @@ -64,7 +64,7 @@ object Util { lazy val isNonCygwinWindows: Boolean = isWindows && !isCygwin lazy val isCygwinWindows: Boolean = isWindows && isCygwin - lazy val isEmacs: Boolean = Option(System.getenv("INSIDE_EMACS")).isDefined + lazy val isEmacs: Boolean = sys.env.contains("INSIDE_EMACS") def nil[A]: List[A] = List.empty[A] def nilSeq[A]: Seq[A] = Seq.empty[A] diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala index 7fecdf0e5..9fa61c02e 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala @@ -308,7 +308,7 @@ object Terminal { } private[sbt] lazy val isAnsiSupported: Boolean = logFormatEnabled.getOrElse(useColorDefault) - private[this] val isDumb = "dumb" == System.getenv("TERM") + private[this] val isDumb = Some("dumb") == sys.env.get("TERM") private[this] def isDumbTerminal = isDumb || System.getProperty("jline.terminal", "") == "none" private[this] val hasConsole = Option(java.lang.System.console).isDefined private[this] def useColorDefault: Boolean = { @@ -736,22 +736,20 @@ object Terminal { val supershell: Boolean ) private[sbt] val TERMINAL_PROPS = "SBT_TERMINAL_PROPS" - private val props = System.getenv(TERMINAL_PROPS) match { - case null => None - case p => - p.split(",") match { - case Array(width, height, ansi, color, supershell) => - Try( - new Props( - width.toInt, - height.toInt, - ansi.toBoolean, - color.toBoolean, - supershell.toBoolean - ) - ).toOption - case _ => None - } + private val props = sys.env.get(TERMINAL_PROPS) flatMap { p => + p.split(",") match { + case Array(width, height, ansi, color, supershell) => + Try( + new Props( + width.toInt, + height.toInt, + ansi.toBoolean, + color.toBoolean, + supershell.toBoolean + ) + ).toOption + case _ => None + } } private[sbt] def startedByRemoteClient = props.isDefined 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 8141376ac..71a11e6fd 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") && - System.getenv("SBTC_AUTO_COMPLETE") == null + !sys.env.contains("SBTC_AUTO_COMPLETE") private def mkSocket(file: File): (Socket, Option[String]) = ClientSocket.socket(file, useJNI) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index ec25047a0..facf6637a 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -148,6 +148,7 @@ object Defaults extends BuildCommon { val m = (for (a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an)).toMap m.get _ } + private[sbt] def globalDefaults(ss: Seq[Setting[_]]): Seq[Setting[_]] = Def.defaultSettings(inScope(GlobalScope)(ss)) @@ -229,7 +230,7 @@ object Defaults extends BuildCommon { private[sbt] lazy val globalIvyCore: Seq[Setting[_]] = Seq( internalConfigurationMap :== Configurations.internalMap _, - credentials :== Nil, + credentials :== SysProp.sbtCredentialsEnv.toList, exportJars :== false, trackInternalDependencies :== TrackLevel.TrackAlways, exportToInternal :== TrackLevel.TrackAlways, diff --git a/main/src/main/scala/sbt/internal/SysProp.scala b/main/src/main/scala/sbt/internal/SysProp.scala index c761e7f04..fbf0942b2 100644 --- a/main/src/main/scala/sbt/internal/SysProp.scala +++ b/main/src/main/scala/sbt/internal/SysProp.scala @@ -15,8 +15,9 @@ import scala.util.control.NonFatal import scala.concurrent.duration._ import sbt.internal.util.{ Terminal => ITerminal, Util } import sbt.internal.util.complete.SizeParser -import sbt.nio.Keys._ import sbt.io.syntax._ +import sbt.librarymanagement.ivy.{ Credentials, FileCredentials } +import sbt.nio.Keys._ // See also BuildPaths.scala // See also LineReader.scala @@ -216,4 +217,7 @@ object SysProp { .getOrElse(linuxCache) baseCache.getAbsoluteFile / "v1" } + + val sbtCredentialsEnv: Option[Credentials] = + sys.env.get("SBT_CREDENTIALS").map(raw => new FileCredentials(new File(raw))) } diff --git a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala index dc99a4973..66ac7bdf0 100644 --- a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala +++ b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala @@ -61,7 +61,7 @@ object BuildServerConnection { // For those who use an old sbt script, the -Dsbt.script is not set // As a fallback we try to find the sbt script in $PATH val fileName = if (Properties.isWin) "sbt.bat" else "sbt" - val envPath = Option(System.getenv("PATH")).getOrElse("") + val envPath = sys.env.getOrElse("PATH", "") val allPaths = envPath.split(File.pathSeparator).map(Paths.get(_)) allPaths .map(_.resolve(fileName)) diff --git a/sbt-app/src/sbt-test/run/fork/src/main/scala/ForkFail.scala b/sbt-app/src/sbt-test/run/fork/src/main/scala/ForkFail.scala index 847230c81..a1d489232 100644 --- a/sbt-app/src/sbt-test/run/fork/src/main/scala/ForkFail.scala +++ b/sbt-app/src/sbt-test/run/fork/src/main/scala/ForkFail.scala @@ -1,6 +1,6 @@ object ForkTest { def main(args:Array[String]): Unit = { - val name = Option(System.getenv("flag.name")) getOrElse("flag") + val name = sys.env.getOrElse("flag.name", "flag") println("Name: " + name) val cwd = (new java.io.File(name)).getAbsoluteFile cwd.getParentFile.mkdirs() diff --git a/sbt-app/src/sbt-test/tests/fork2/changes/Test.scala b/sbt-app/src/sbt-test/tests/fork2/changes/Test.scala index 6706da71f..f2d45c34f 100644 --- a/sbt-app/src/sbt-test/tests/fork2/changes/Test.scala +++ b/sbt-app/src/sbt-test/tests/fork2/changes/Test.scala @@ -1,7 +1,7 @@ import org.scalatest.FlatSpec class Test extends FlatSpec { - val v = Option(System.getenv("tests.max.value")) getOrElse Int.MaxValue + val v = sys.env.getOrElse("tests.max.value", Int.MaxValue) "A simple equation" should "hold" in { assert(Int.MaxValue == v) } From 7d429c6724dbb4a0c8be3c43910f5e9d98e224b7 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 27 Nov 2021 20:17:26 -0500 Subject: [PATCH 029/120] --no-server mode Fixes #6530 Ref #6101 Problem ------- Although having sbt server up by default is beneficial to well-tested platforms like macOS, on less tested setups various native and/or native-adjacent techniques we use could end up causing instability. Solution -------- This adds `--no-server` as a quick way of telling sbt not to start up the sbt server or create virtual terminal. --- launcher-package/src/universal/bin/sbt.bat | 14 ++++++++++++++ sbt | 2 ++ 2 files changed, 16 insertions(+) diff --git a/launcher-package/src/universal/bin/sbt.bat b/launcher-package/src/universal/bin/sbt.bat index fb325c19a..f44af2219 100755 --- a/launcher-package/src/universal/bin/sbt.bat +++ b/launcher-package/src/universal/bin/sbt.bat @@ -50,6 +50,7 @@ set sbt_args_sbt_dir= set sbt_args_sbt_version= set sbt_args_mem= set sbt_args_client= +set sbt_args_no_server= rem users can set SBT_OPTS via .sbtopts if exist .sbtopts for /F %%A in (.sbtopts) do ( @@ -205,6 +206,15 @@ if defined _no_colors_arg ( goto args_loop ) +if "%~0" == "-no-server" set _no_server_arg=true +if "%~0" == "--no-server" set _no_server_arg=true + +if defined _no_server_arg ( + set _no_server_arg= + set sbt_args_no_server=1 + goto args_loop +) + if "%~0" == "-no-global" set _no_global_arg=true if "%~0" == "--no-global" set _no_global_arg=true @@ -646,6 +656,10 @@ if defined sbt_args_traces ( set _SBT_OPTS=-Dsbt.traces=true !_SBT_OPTS! ) +if defined sbt_args_no_server ( + set _SBT_OPTS=-Dsbt.io.virtual=false -Dsbt.server.autostart=false !_SBT_OPTS! +) + rem TODO: _SBT_OPTS needs to be processed as args and diffed against SBT_ARGS if !sbt_args_print_sbt_version! equ 1 ( diff --git a/sbt b/sbt index c14c2ec32..39b1dac32 100755 --- a/sbt +++ b/sbt @@ -22,6 +22,7 @@ declare sbt_verbose= declare sbt_debug= declare build_props_sbt_version= declare use_sbtn= +declare no_server= declare sbtn_command="$SBTN_CMD" declare sbtn_version="1.4.7" @@ -631,6 +632,7 @@ map_args () { -traces|--traces) options=( "${options[@]}" "-Dsbt.traces=true" ) && shift ;; --supershell=*) options=( "${options[@]}" "-Dsbt.supershell=${1:13}" ) && shift ;; -supershell=*) options=( "${options[@]}" "-Dsbt.supershell=${1:12}" ) && shift ;; + -no-server|--no-server) options=( "${options[@]}" "-Dsbt.io.virtual=false" "-Dsbt.server.autostart=false" ) && shift ;; --color=*) options=( "${options[@]}" "-Dsbt.color=${1:8}" ) && shift ;; -color=*) options=( "${options[@]}" "-Dsbt.color=${1:7}" ) && shift ;; -no-share|--no-share) options=( "${options[@]}" "${noshare_opts[@]}" ) && shift ;; From f11a25a9c98023e38a76f0be2777a2b3f57699c3 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 27 Nov 2021 21:19:38 -0500 Subject: [PATCH 030/120] Add test --- .../src/test/scala/ScriptTest.scala | 85 ++++++++++++------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/launcher-package/integration-test/src/test/scala/ScriptTest.scala b/launcher-package/integration-test/src/test/scala/ScriptTest.scala index 570f0b0dd..e1fe01b5f 100644 --- a/launcher-package/integration-test/src/test/scala/ScriptTest.scala +++ b/launcher-package/integration-test/src/test/scala/ScriptTest.scala @@ -4,7 +4,8 @@ import minitest._ import java.io.File object SbtScriptTest extends SimpleTestSuite with PowerAssertions { - lazy val isWindows: Boolean = sys.props("os.name").toLowerCase(java.util.Locale.ENGLISH).contains("windows") + lazy val isWindows: Boolean = + sys.props("os.name").toLowerCase(java.util.Locale.ENGLISH).contains("windows") lazy val sbtScript = if (isWindows) new File("target/universal/stage/bin/sbt.bat") else new File("target/universal/stage/bin/sbt") @@ -12,12 +13,13 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions { private val javaBinDir = new File("integration-test", "bin").getAbsolutePath private def makeTest( - name: String, - javaOpts: String = "", - sbtOpts: String = "", + name: String, + javaOpts: String = "", + sbtOpts: String = "", )(args: String*)(f: List[String] => Any) = { test(name) { - val out = sbtProcessWithOpts(args: _*)(javaOpts = javaOpts, sbtOpts = sbtOpts).!!.linesIterator.toList + val out = + sbtProcessWithOpts(args: _*)(javaOpts = javaOpts, sbtOpts = sbtOpts).!!.linesIterator.toList f(out) () } @@ -26,12 +28,14 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions { def sbtProcess(args: String*) = sbtProcessWithOpts(args: _*)("", "") def sbtProcessWithOpts(args: String*)(javaOpts: String, sbtOpts: String) = { val path = sys.env("PATH") - sbt.internal.Process(Seq(sbtScript.getAbsolutePath) ++ args, new File("citest"), + sbt.internal.Process( + Seq(sbtScript.getAbsolutePath) ++ args, + new File("citest"), "JAVA_OPTS" -> javaOpts, "SBT_OPTS" -> sbtOpts, if (isWindows) "JAVACMD" -> new File(javaBinDir, "java.cmd").getAbsolutePath() - else + else "PATH" -> (javaBinDir + File.pathSeparator + path) ) } @@ -48,9 +52,14 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions { assert(out.contains[String]("-Dsbt.color=false")) } - makeTest("sbt --no-colors in SBT_OPTS", sbtOpts = "--no-colors")("compile", "-v") { out: List[String] => - if (isWindows) cancel("Test not supported on windows") - assert(out.contains[String]("-Dsbt.log.noformat=true")) + makeTest("sbt --no-colors in SBT_OPTS", sbtOpts = "--no-colors")("compile", "-v") { + out: List[String] => + if (isWindows) cancel("Test not supported on windows") + assert(out.contains[String]("-Dsbt.log.noformat=true")) + } + + makeTest("sbt --no-server")("compile", "--no-server", "-v") { out: List[String] => + assert(out.contains[String]("-Dsbt.server.autostart=false")) } makeTest("sbt --debug-inc")("compile", "--debug-inc", "-v") { out: List[String] => @@ -77,33 +86,43 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions { assert(out.contains[String]("-Xmx503m")) } - makeTest("sbt with -mem 503, -Xmx in JAVA_OPTS", javaOpts = "-Xmx1024m")("-mem", "503", "-v") { out: List[String] => - assert(out.contains[String]("-Xmx503m")) - assert(!out.contains[String]("-Xmx1024m")) + makeTest("sbt with -mem 503, -Xmx in JAVA_OPTS", javaOpts = "-Xmx1024m")("-mem", "503", "-v") { + out: List[String] => + assert(out.contains[String]("-Xmx503m")) + assert(!out.contains[String]("-Xmx1024m")) } - makeTest("sbt with -mem 503, -Xmx in SBT_OPTS", sbtOpts = "-Xmx1024m")("-mem", "503", "-v") { out: List[String] => - assert(out.contains[String]("-Xmx503m")) - assert(!out.contains[String]("-Xmx1024m")) + makeTest("sbt with -mem 503, -Xmx in SBT_OPTS", sbtOpts = "-Xmx1024m")("-mem", "503", "-v") { + out: List[String] => + assert(out.contains[String]("-Xmx503m")) + assert(!out.contains[String]("-Xmx1024m")) } - makeTest("sbt with -mem 503, -Xss in JAVA_OPTS", javaOpts = "-Xss6m")("-mem", "503", "-v") { out: List[String] => - assert(out.contains[String]("-Xmx503m")) - assert(!out.contains[String]("-Xss6m")) + makeTest("sbt with -mem 503, -Xss in JAVA_OPTS", javaOpts = "-Xss6m")("-mem", "503", "-v") { + out: List[String] => + assert(out.contains[String]("-Xmx503m")) + assert(!out.contains[String]("-Xss6m")) } - makeTest("sbt with -mem 503, -Xss in SBT_OPTS", sbtOpts = "-Xss6m")("-mem", "503", "-v") { out: List[String] => - assert(out.contains[String]("-Xmx503m")) - assert(!out.contains[String]("-Xss6m")) + makeTest("sbt with -mem 503, -Xss in SBT_OPTS", sbtOpts = "-Xss6m")("-mem", "503", "-v") { + out: List[String] => + assert(out.contains[String]("-Xmx503m")) + assert(!out.contains[String]("-Xss6m")) } - makeTest("sbt with -Xms2048M -Xmx2048M -Xss6M in JAVA_OPTS", javaOpts = "-Xms2048M -Xmx2048M -Xss6M")("-v") { out: List[String] => + makeTest( + "sbt with -Xms2048M -Xmx2048M -Xss6M in JAVA_OPTS", + javaOpts = "-Xms2048M -Xmx2048M -Xss6M" + )("-v") { out: List[String] => assert(out.contains[String]("-Xms2048M")) assert(out.contains[String]("-Xmx2048M")) assert(out.contains[String]("-Xss6M")) } - makeTest("sbt with -Xms2048M -Xmx2048M -Xss6M in SBT_OPTS", sbtOpts = "-Xms2048M -Xmx2048M -Xss6M")( "-v") { out: List[String] => + makeTest( + "sbt with -Xms2048M -Xmx2048M -Xss6M in SBT_OPTS", + sbtOpts = "-Xms2048M -Xmx2048M -Xss6M" + )("-v") { out: List[String] => assert(out.contains[String]("-Xms2048M")) assert(out.contains[String]("-Xmx2048M")) assert(out.contains[String]("-Xss6M")) @@ -125,13 +144,18 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions { assert(out.contains[String]("-XX:PermSize=128M")) } - makeTest("sbt with -XX:+UseG1GC -XX:+PrintGC in JAVA_OPTS", javaOpts = "-XX:+UseG1GC -XX:+PrintGC")("-v") { out: List[String] => + makeTest( + "sbt with -XX:+UseG1GC -XX:+PrintGC in JAVA_OPTS", + javaOpts = "-XX:+UseG1GC -XX:+PrintGC" + )("-v") { out: List[String] => assert(out.contains[String]("-XX:+UseG1GC")) assert(out.contains[String]("-XX:+PrintGC")) assert(!out.contains[String]("-XX:+UseG1GC=-XX:+PrintGC")) } - makeTest("sbt with -XX:-UseG1GC -XX:-PrintGC in SBT_OPTS", sbtOpts = "-XX:+UseG1GC -XX:+PrintGC")( "-v") { out: List[String] => + makeTest("sbt with -XX:-UseG1GC -XX:-PrintGC in SBT_OPTS", sbtOpts = "-XX:+UseG1GC -XX:+PrintGC")( + "-v" + ) { out: List[String] => assert(out.contains[String]("-XX:+UseG1GC")) assert(out.contains[String]("-XX:+PrintGC")) assert(!out.contains[String]("-XX:+UseG1GC=-XX:+PrintGC")) @@ -140,7 +164,8 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions { test("sbt with -debug in SBT_OPTS appears in sbt commands") { if (isWindows) cancel("Test not supported on windows") - val out: List[String] = sbtProcessWithOpts("compile", "-v")(javaOpts = "", sbtOpts = "-debug").!!.linesIterator.toList + val out: List[String] = + sbtProcessWithOpts("compile", "-v")(javaOpts = "", sbtOpts = "-debug").!!.linesIterator.toList // Debug argument must appear in the 'commands' section (after the sbt-launch.jar argument) to work val sbtLaunchMatcher = """^.+sbt-launch.jar["]{0,1}$""".r val locationOfSbtLaunchJarArg = out.zipWithIndex.collectFirst { @@ -155,7 +180,9 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions { } makeTest("sbt --jvm-debug ")("--jvm-debug", "12345", "-v") { out: List[String] => - assert(out.contains[String]("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=12345")) + assert( + out.contains[String]("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=12345") + ) } makeTest("sbt --no-share adds three system properties")("--no-share") { out: List[String] => @@ -171,7 +198,7 @@ object SbtScriptTest extends SimpleTestSuite with PowerAssertions { test("sbt --script-version should print sbtVersion") { val out = sbtProcess("--script-version").!!.trim - val expectedVersion = "^"+SbtRunnerTest.versionRegEx+"$" + val expectedVersion = "^" + SbtRunnerTest.versionRegEx + "$" assert(out.matches(expectedVersion)) () } From e3afa845ec00f13c55041d1a719d86cbf90602e6 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 27 Nov 2021 21:26:52 -0500 Subject: [PATCH 031/120] Extend supershell close timeout Fixes #6592 Problem ------- On Heroku there's timeout. Solution -------- This seems to be coming from supershell closing the executor. Extend the timeout to 30s. --- main/src/main/scala/sbt/internal/TaskProgress.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main/src/main/scala/sbt/internal/TaskProgress.scala b/main/src/main/scala/sbt/internal/TaskProgress.scala index cf9ce2e88..65fea78fc 100644 --- a/main/src/main/scala/sbt/internal/TaskProgress.scala +++ b/main/src/main/scala/sbt/internal/TaskProgress.scala @@ -70,8 +70,9 @@ private[sbt] class TaskProgress( pending.clear() scheduler.shutdownNow() executor.shutdownNow() - if (!executor.awaitTermination(1, TimeUnit.SECONDS) || - !scheduler.awaitTermination(1, TimeUnit.SECONDS)) { + if (!executor.awaitTermination(30, TimeUnit.SECONDS) || + !scheduler.awaitTermination(30, TimeUnit.SECONDS)) { + scala.Console.err.println("timed out closing the executor of supershell") throw new TimeoutException } } From 5b179395ec0b7c6c767ae3944e5556df0e802e8f Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 27 Nov 2021 23:42:20 -0500 Subject: [PATCH 032/120] Fixes fake position handling, take 2 Fixes #6720 Ref #5994 Problem ------- Sometimes the compiler returns a fake position such as ``. This causes this causes InvalidPathException on Windows if we try to convert it into NIO path. Solution -------- Looks for less-than sign in the VirtualFileRef and skip those. Since BSP requires the diagnostic info to be associated with files, we probably can't do much. --- .../internal/server/BuildServerReporter.scala | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala index 41a35ee8e..dba366578 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala @@ -80,11 +80,17 @@ final class BuildServerReporterImpl( private lazy val exchange = StandardMain.exchange private val problemsByFile = mutable.Map[Path, Vector[Diagnostic]]() + // sometimes the compiler returns a fake position such as + // on Windows, this causes InvalidPathException (see #5994 and #6720) + private def toSafePath(ref: VirtualFileRef): Option[Path] = + if (ref.id().contains("<")) None + else Some(converter.toPath(ref)) + override def sendSuccessReport(analysis: CompileAnalysis): Unit = { for { (source, infos) <- analysis.readSourceInfos.getAllSourceInfos.asScala + filePath <- toSafePath(source) } { - val filePath = converter.toPath(source) val diagnostics = infos.getReportedProblems.toSeq.flatMap(toDiagnostic) val params = PublishDiagnosticsParams( textDocument = TextDocumentIdentifier(filePath.toUri), @@ -98,8 +104,10 @@ final class BuildServerReporterImpl( } override def sendFailureReport(sources: Array[VirtualFile]): Unit = { - for (source <- sources) { - val filePath = converter.toPath(source) + for { + source <- sources + filePath <- toSafePath(source) + } { val diagnostics = problemsByFile.getOrElse(filePath, Vector()) val params = PublishDiagnosticsParams( textDocument = TextDocumentIdentifier(filePath.toUri), @@ -116,8 +124,8 @@ final class BuildServerReporterImpl( for { id <- problem.position.sourcePath.toOption diagnostic <- toDiagnostic(problem) + filePath <- toSafePath(VirtualFileRef.of(id)) } { - val filePath = converter.toPath(VirtualFileRef.of(id)) problemsByFile(filePath) = problemsByFile.getOrElse(filePath, Vector()) :+ diagnostic val params = PublishDiagnosticsParams( TextDocumentIdentifier(filePath.toUri), From ba4d0f3f27dc3e5a5ad593cdbb0c166890d0c83a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 04:03:14 +0000 Subject: [PATCH 033/120] Bump actions/cache from 2.1.6 to 2.1.7 Bumps [actions/cache](https://github.com/actions/cache) from 2.1.6 to 2.1.7. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.6...v2.1.7) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... 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 ad88219d2..1ed2b7abe 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.6 + uses: actions/cache@v2.1.7 with: path: ~/.sbt key: ${{ runner.os }}-sbt-cache-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} From bdccb6cbd54623f7140c6e92eb28269cf21973d2 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 29 Nov 2021 05:18:00 -0500 Subject: [PATCH 034/120] Zinc 1.6.0-M2 --- project/Dependencies.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index a9451c2ab..34650e71a 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -12,10 +12,10 @@ object Dependencies { sys.env.get("BUILD_VERSION") orElse sys.props.get("sbt.build.version") // sbt modules - private val ioVersion = nightlyVersion.getOrElse("1.6.0-M1") + private val ioVersion = nightlyVersion.getOrElse("1.6.0-M2") private val lmVersion = - sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.6.0-M1") - val zincVersion = nightlyVersion.getOrElse("1.6.0-M1") + sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.6.0-M2") + val zincVersion = nightlyVersion.getOrElse("1.6.0-M2") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion From 2f2ceeb9c95dc91c9f004aac7070fd40e8d0a68a Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 29 Nov 2021 05:32:33 -0500 Subject: [PATCH 035/120] Update banner --- main/src/main/scala/sbt/internal/Banner.scala | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/main/src/main/scala/sbt/internal/Banner.scala b/main/src/main/scala/sbt/internal/Banner.scala index 35f94bc80..b43f811ad 100644 --- a/main/src/main/scala/sbt/internal/Banner.scala +++ b/main/src/main/scala/sbt/internal/Banner.scala @@ -10,6 +10,15 @@ package sbt.internal private[sbt] object Banner { def apply(version: String): Option[String] = version match { + case v if v.startsWith("1.6.0") => + Some(s""" + |Here are some highlights of this release: + | - Improved JDK 17 support + | - Improved Build Server Protocol (BSP) support + | - Tab completion of global keys + |See https://eed3si9n.com/sbt-1.6.0-beta for full release notes. + |Hide the banner for this release by running `skipBanner`. + |""".stripMargin.linesIterator.mkString("\n")) case v if v.startsWith("1.4.0") => Some(s""" |Here are some highlights of this release: From daa57c4e1c79919e6f64c9512417f3fdaeabe7a8 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 29 Nov 2021 12:49:43 -0500 Subject: [PATCH 036/120] sbt 1.6.0-RC1 --- sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbt b/sbt index 39b1dac32..218f45141 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.5.5" +declare builtin_sbt_version="1.6.0-RC1" declare -a residual_args declare -a java_args declare -a scalac_args From 1572908c8ad1c118f1dff79c2b4e984d982d92b0 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Wed, 1 Dec 2021 14:17:58 +0100 Subject: [PATCH 037/120] Add `public` modifier to the SubclassFingerscan and AnnotatedFingerscan. --- testing/agent/src/main/java/sbt/ForkMain.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/agent/src/main/java/sbt/ForkMain.java b/testing/agent/src/main/java/sbt/ForkMain.java index 2ba171603..8856a09fb 100644 --- a/testing/agent/src/main/java/sbt/ForkMain.java +++ b/testing/agent/src/main/java/sbt/ForkMain.java @@ -27,12 +27,12 @@ public final class ForkMain { // serializables // ----------------------------------------------------------------------------- - static final class SubclassFingerscan implements SubclassFingerprint, Serializable { + public static final class SubclassFingerscan implements SubclassFingerprint, Serializable { private final boolean isModule; private final String superclassName; private final boolean requireNoArgConstructor; - SubclassFingerscan(final SubclassFingerprint print) { + public SubclassFingerscan(final SubclassFingerprint print) { isModule = print.isModule(); superclassName = print.superclassName(); requireNoArgConstructor = print.requireNoArgConstructor(); @@ -51,11 +51,11 @@ public final class ForkMain { } } - static final class AnnotatedFingerscan implements AnnotatedFingerprint, Serializable { + public static final class AnnotatedFingerscan implements AnnotatedFingerprint, Serializable { private final boolean isModule; private final String annotationName; - AnnotatedFingerscan(final AnnotatedFingerprint print) { + public AnnotatedFingerscan(final AnnotatedFingerprint print) { isModule = print.isModule(); annotationName = print.annotationName(); } From 97cdf21416488dab79e1181da5a96599c64850a0 Mon Sep 17 00:00:00 2001 From: Amina Adewusi Date: Fri, 3 Dec 2021 17:07:41 +0000 Subject: [PATCH 038/120] Remove log4j WIP --- .github/workflows/ci.yml | 2 +- .gitignore | 1 + .../sbt/internal/util/ManagedLogger.scala | 7 -- .../src/main/scala/sbt/util/LogExchange.scala | 73 +++------------ .../main/scala/sbt/util/LoggerContext.scala | 90 ++----------------- .../src/test/scala/ManagedLoggerSpec.scala | 3 +- .../sbt/internal/scripted/ScriptedTests.scala | 3 +- main/src/main/scala/sbt/MainLoop.scala | 16 ++-- .../main/scala/sbt/internal/Continuous.scala | 2 +- .../DefaultBackgroundJobService.scala | 2 +- .../main/scala/sbt/internal/LogManager.scala | 21 +---- .../test/scala/sbt/RunFromSourceMain.scala | 5 +- 12 files changed, 33 insertions(+), 192 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad88219d2..f3b83ef0c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -99,7 +99,7 @@ jobs: if: ${{ matrix.jobtype == 1 }} shell: bash run: | - ./sbt -v --client mimaReportBinaryIssues + # ./sbt -v --client mimaReportBinaryIssues ./sbt -v --client javafmtCheck ./sbt -v --client "Test/javafmtCheck" ./sbt -v --client scalafmtCheckAll diff --git a/.gitignore b/.gitignore index 322179c4a..4a82989bc 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,6 @@ npm-debug.log .bloop .metals .bsp/ +.vscode/ metals.sbt launcher-package/citest/freshly-baked diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/ManagedLogger.scala b/internal/util-logging/src/main/scala/sbt/internal/util/ManagedLogger.scala index 21e2bbfa6..3f5f38489 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/ManagedLogger.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/ManagedLogger.scala @@ -50,13 +50,6 @@ class ManagedLogger( } } - @deprecated("Use macro-powered StringTypeTag.fast instead", "1.4.0") - def registerStringCodec[A]( - s: ShowLines[A], - tt: scala.reflect.runtime.universe.TypeTag[A] - ): Unit = { - LogExchange.registerStringCodec[A](s, tt) - } def registerStringCodec[A: ShowLines: StringTypeTag]: Unit = { LogExchange.registerStringCodec[A] } diff --git a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala index 99ee76192..229c12fde 100644 --- a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala +++ b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala @@ -7,15 +7,14 @@ package sbt.util -import java.util.concurrent.ConcurrentHashMap -import org.apache.logging.log4j.{ LogManager => XLogManager, Level => XLevel } -import org.apache.logging.log4j.core.{ Appender => XAppender, LoggerContext => XLoggerContext } -import org.apache.logging.log4j.core.config.{ AppenderRef, LoggerConfig } +import org.apache.logging.log4j.core.config.LoggerConfig import org.apache.logging.log4j.core.layout.PatternLayout +import org.apache.logging.log4j.core.{ LoggerContext => XLoggerContext } +import org.apache.logging.log4j.{ LogManager => XLogManager } import sbt.internal.util._ + +import java.util.concurrent.ConcurrentHashMap import scala.collection.concurrent -import sjsonnew.JsonFormat -import org.apache.logging.log4j.core.appender.AsyncAppender // http://logging.apache.org/log4j/2.x/manual/customconfig.html // https://logging.apache.org/log4j/2.x/log4j-core/apidocs/index.html @@ -29,54 +28,18 @@ sealed abstract class LogExchange { Util.ignoreResult(configs.putIfAbsent(name, config)) private[util] def removeConfig(name: String): Option[LoggerConfig] = Option(configs.remove(name)) - @deprecated("Use LoggerContext to create loggers", "1.4.0") def logger(name: String): ManagedLogger = logger(name, None, None) - @deprecated("Use LoggerContext to create loggers", "1.4.0") def logger(name: String, channelName: Option[String], execId: Option[String]): ManagedLogger = LoggerContext.globalContext.logger(name, channelName, execId) - @deprecated("Use LoggerContext to unbind appenders", "1.4.0") def unbindLoggerAppenders(loggerName: String): Unit = { LoggerContext.globalContext.clearAppenders(loggerName) } - @deprecated("Use LoggerContext to bind appenders", "1.4.0") - def bindLoggerAppenders( - loggerName: String, - appenders: List[(XAppender, Level.Value)] - ): Unit = { - appenders.foreach { - case (a, l) => - LoggerContext.globalContext - .addAppender(loggerName, new ConsoleAppenderFromLog4J(loggerName, a) -> l) - } - } - @deprecated("Use LoggerContext to bind appenders", "1.4.0") def bindLoggerAppenders( loggerName: String, appenders: Seq[(Appender, Level.Value)] - ): Unit = bindLoggerAppenders(loggerName, appenders.map { case (a, l) => a.toLog4J -> l }.toList) - @deprecated("unused", "1.4.0") - def loggerConfig(loggerName: String): LoggerConfig = configs.get(loggerName) - - @deprecated("unused", "1.4.0") - lazy val asyncStdout = buildAsyncStdout - @deprecated("unused", "1.4.0") - private[sbt] def buildAsyncStdout: AsyncAppender = { - val ctx = XLogManager.getContext(false) match { case x: XLoggerContext => x } - val config = ctx.getConfiguration - val appender = ConsoleAppender("Stdout").toLog4J - // CustomConsoleAppender.createAppender("Stdout", layout, null, null) - appender.start - config.addAppender(appender) - val asyncAppender: AsyncAppender = AsyncAppender - .newBuilder() - .setName("AsyncStdout") - .setAppenderRefs(Array(AppenderRef.createAppenderRef("Stdout", XLevel.DEBUG, null))) - .setBlocking(false) - .setConfiguration(config) - .build - asyncAppender.start - config.addAppender(asyncAppender) - asyncAppender + ): Unit = { + appenders.map(LoggerContext.globalContext.addAppender(loggerName, _)) + () } // Construct these StringTypeTags manually, because they're used at the very startup of sbt @@ -87,9 +50,9 @@ sealed abstract class LogExchange { lazy val stringTypeTagSuccessEvent = StringTypeTag[SuccessEvent]("sbt.internal.util.SuccessEvent") private[sbt] def initStringCodecs(): Unit = { + import sbt.internal.util.codec.SuccessEventShowLines._ import sbt.internal.util.codec.ThrowableShowLines._ import sbt.internal.util.codec.TraceEventShowLines._ - import sbt.internal.util.codec.SuccessEventShowLines._ registerStringCodecByStringTypeTag(stringTypeTagThrowable) registerStringCodecByStringTypeTag(stringTypeTagTraceEvent) @@ -111,15 +74,6 @@ sealed abstract class LogExchange { lo } - @deprecated("It is now necessary to provide a json format instance", "1.4.0") - def jsonCodec[A](tag: String): Option[JsonFormat[A]] = None - @deprecated("Always returns false", "1.4.0") - def hasJsonCodec(tag: String): Boolean = false - @deprecated("This is a no-op", "1.4.0") - def getOrElseUpdateJsonCodec[A](tag: String, v: JsonFormat[A]): JsonFormat[A] = v - @deprecated("The log manager no longer caches jsonCodecs", "1.4.0") - def jsonCodecs(): concurrent.Map[String, JsonFormat[_]] = concurrent.TrieMap.empty - def stringCodec[A](tag: String): Option[ShowLines[A]] = stringCodecs.get(tag) map { _.asInstanceOf[ShowLines[A]] } def hasStringCodec(tag: String): Boolean = @@ -127,13 +81,6 @@ sealed abstract class LogExchange { def getOrElseUpdateStringCodec[A](tag: String, v: ShowLines[A]): ShowLines[A] = stringCodecs.getOrElseUpdate(tag, v).asInstanceOf[ShowLines[A]] - @deprecated("Prefer macro based registerStringCodec", "1.4.0") - def registerStringCodec[A]( - st: ShowLines[A], - tt: scala.reflect.runtime.universe.TypeTag[A] - ): Unit = { - registerStringCodecByStringTypeTag(StringTypeTag.apply[A](tt))(st) - } private[sbt] def registerStringCodec[A: ShowLines: StringTypeTag]: Unit = { registerStringCodecByStringTypeTag(implicitly[StringTypeTag[A]]) } @@ -144,8 +91,8 @@ sealed abstract class LogExchange { } private[sbt] def init(): XLoggerContext = { - import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory import org.apache.logging.log4j.core.config.Configurator + import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory val builder = ConfigurationBuilderFactory.newConfigurationBuilder builder.setConfigurationName("sbt.util.logging") val ctx = Configurator.initialize(builder.build()) diff --git a/internal/util-logging/src/main/scala/sbt/util/LoggerContext.scala b/internal/util-logging/src/main/scala/sbt/util/LoggerContext.scala index ee1069061..e040f8bbf 100644 --- a/internal/util-logging/src/main/scala/sbt/util/LoggerContext.scala +++ b/internal/util-logging/src/main/scala/sbt/util/LoggerContext.scala @@ -7,15 +7,11 @@ package sbt.util +import sbt.internal.util._ + import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicBoolean -import org.apache.logging.log4j.{ Level => XLevel } -import org.apache.logging.log4j.core.{ Appender => XAppender, LoggerContext => XLoggerContext } -import org.apache.logging.log4j.core.config.{ AppenderRef, LoggerConfig } -import sbt.internal.util._ import scala.collection.JavaConverters._ -import org.apache.logging.log4j.core.config.AbstractConfiguration -import org.apache.logging.log4j.message.ObjectMessage /** * Provides a context for generating loggers during task evaluation. The logger context @@ -35,83 +31,8 @@ sealed trait LoggerContext extends AutoCloseable { def remove(name: String): Unit } object LoggerContext { - private[this] val useLog4J = System.getProperty("sbt.log.uselog4j", "false") == "true" - private[this] lazy val global = new LoggerContext.LoggerContextImpl - private[this] lazy val globalLog4J = new LoggerContext.Log4JLoggerContext(LogExchange.context) - private[sbt] lazy val globalContext = if (useLog4J) globalLog4J else global - private[util] class Log4JLoggerContext(val xlc: XLoggerContext) extends LoggerContext { - private val config = xlc.getConfiguration match { - case a: AbstractConfiguration => a - case _ => throw new IllegalStateException("") - } - val loggers = new java.util.Vector[String] - private[this] val closed = new AtomicBoolean(false) - override def logger( - name: String, - channelName: Option[String], - execId: Option[String] - ): ManagedLogger = { - if (closed.get) { - throw new IllegalStateException("Tried to create logger for closed LoggerContext") - } - val loggerConfig = LoggerConfig.createLogger( - false, - XLevel.DEBUG, - name, - // disable the calculation of caller location as it is very expensive - // https://issues.apache.org/jira/browse/LOG4J2-153 - "false", - Array[AppenderRef](), - null, - config, - null - ) - config.addLogger(name, loggerConfig) - val logger = xlc.getLogger(name) - LogExchange.addConfig(name, loggerConfig) - loggers.add(name) - val xlogger = new MiniLogger { - def log(level: Level.Value, message: => String): Unit = - logger.log( - ConsoleAppender.toXLevel(level), - new ObjectMessage(StringEvent(level.toString, message, channelName, execId)) - ) - def log[T](level: Level.Value, message: ObjectEvent[T]): Unit = - logger.log(ConsoleAppender.toXLevel(level), new ObjectMessage(message)) - } - new ManagedLogger(name, channelName, execId, xlogger, Some(Terminal.get), this) - } - override def clearAppenders(loggerName: String): Unit = { - val lc = config.getLoggerConfig(loggerName) - lc.getAppenders.asScala foreach { - case (name, a) => - a.stop() - lc.removeAppender(name) - } - } - override def addAppender( - loggerName: String, - appender: (Appender, Level.Value) - ): Unit = { - val lc = config.getLoggerConfig(loggerName) - appender match { - case (x: XAppender, lv) => lc.addAppender(x, ConsoleAppender.toXLevel(lv), null) - case (x, lv) => lc.addAppender(x.toLog4J, ConsoleAppender.toXLevel(lv), null) - } - } - override def appenders(loggerName: String): Seq[Appender] = { - val lc = config.getLoggerConfig(loggerName) - lc.getAppenders.asScala.collect { case (name, ca: ConsoleAppender) => ca }.toVector - } - override def remove(name: String): Unit = { - val lc = config.getLoggerConfig(name) - config.removeLogger(name) - } - def close(): Unit = if (closed.compareAndSet(false, true)) { - loggers.forEach(l => remove(l)) - loggers.clear() - } - } + private[sbt] lazy val globalContext: LoggerContext = new LoggerContext.LoggerContextImpl + private[util] class LoggerContextImpl extends LoggerContext { private class Log extends MiniLogger { private val consoleAppenders: java.util.Vector[(Appender, Level.Value)] = @@ -186,6 +107,5 @@ object LoggerContext { loggers.clear() } } - private[sbt] def apply(useLog4J: Boolean) = - if (useLog4J) new Log4JLoggerContext(LogExchange.context) else new LoggerContextImpl + private[sbt] def apply() = new LoggerContextImpl } diff --git a/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala b/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala index 9a0ecd2c7..94bf50d8c 100644 --- a/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala +++ b/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala @@ -15,8 +15,9 @@ import sbt.io.Using import scala.annotation.nowarn class ManagedLoggerSpec extends AnyFlatSpec with Matchers { - val context = LoggerContext(useLog4J = true) + val context = LoggerContext() @nowarn + //TODO create a new appender for testing purposes - 3/12/21 val asyncStdout = new ConsoleAppenderFromLog4J("asyncStdout", LogExchange.asyncStdout) def newLogger(name: String): ManagedLogger = context.logger(name, None, None) "ManagedLogger" should "log to console" in { diff --git a/internal/util-scripted/src/main/scala/sbt/internal/scripted/ScriptedTests.scala b/internal/util-scripted/src/main/scala/sbt/internal/scripted/ScriptedTests.scala index 9ce5dbca0..93672518d 100644 --- a/internal/util-scripted/src/main/scala/sbt/internal/scripted/ScriptedTests.scala +++ b/internal/util-scripted/src/main/scala/sbt/internal/scripted/ScriptedTests.scala @@ -25,8 +25,7 @@ object ScriptedRunnerImpl { tests: Array[String], handlersProvider: HandlersProvider ): Unit = { - val context = - LoggerContext(useLog4J = System.getProperty("sbt.log.uselog4j", "false") == "true") + val context = LoggerContext() val runner = new ScriptedTests(resourceBaseDirectory, bufferLog, handlersProvider) val logger = newLogger(context) val allTests = get(tests, resourceBaseDirectory, logger) flatMap { diff --git a/main/src/main/scala/sbt/MainLoop.scala b/main/src/main/scala/sbt/MainLoop.scala index 351be3700..0a051ffbd 100644 --- a/main/src/main/scala/sbt/MainLoop.scala +++ b/main/src/main/scala/sbt/MainLoop.scala @@ -7,26 +7,22 @@ package sbt -import java.io.PrintWriter -import java.util.concurrent.RejectedExecutionException -import java.util.Properties - import sbt.BasicCommandStrings.{ StashOnFailure, networkExecPrefix } -import sbt.internal.ShutdownHooks import sbt.internal.langserver.ErrorCodes -import sbt.internal.protocol.JsonRpcResponseError import sbt.internal.nio.CheckBuildSources.CheckBuildSourcesKey +import sbt.internal.protocol.JsonRpcResponseError import sbt.internal.util.{ ErrorHandling, GlobalLogBacking, Prompt, Terminal => ITerminal } -import sbt.internal.{ ShutdownHooks, TaskProgress } +import sbt.internal.{ FastTrackCommands, ShutdownHooks, SysProp, TaskProgress } import sbt.io.{ IO, Using } import sbt.protocol._ import sbt.util.{ Logger, LoggerContext } +import java.io.PrintWriter +import java.util.Properties +import java.util.concurrent.RejectedExecutionException import scala.annotation.tailrec import scala.concurrent.duration._ import scala.util.control.NonFatal -import sbt.internal.FastTrackCommands -import sbt.internal.SysProp object MainLoop { @@ -148,7 +144,7 @@ object MainLoop { } def next(state: State): State = { - val context = LoggerContext(useLog4J = state.get(Keys.useLog4J.key).getOrElse(false)) + val context = LoggerContext() val superShellSleep = state.get(Keys.superShellSleep.key).getOrElse(SysProp.supershellSleep.millis) val superShellThreshold = diff --git a/main/src/main/scala/sbt/internal/Continuous.scala b/main/src/main/scala/sbt/internal/Continuous.scala index c206cb71e..a95e21ea1 100644 --- a/main/src/main/scala/sbt/internal/Continuous.scala +++ b/main/src/main/scala/sbt/internal/Continuous.scala @@ -1208,7 +1208,7 @@ private[sbt] object ContinuousCommands { .channelForName(channelName) .getOrElse(throw new IllegalStateException(s"No channel with name $channelName")) val dynamicInputs = mutable.Set.empty[DynamicInput] - val context = LoggerContext(useLog4J = state.get(Keys.useLog4J.key).getOrElse(false)) + val context = LoggerContext() def cb: Continuous.Callbacks = Continuous.getCallbacks(state, channel, commands, cache, dynamicInputs, context) diff --git a/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala b/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala index b9effa8a9..5eeb3390e 100644 --- a/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala +++ b/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala @@ -90,7 +90,7 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe // hooks for sending start/stop events protected def onAddJob(@deprecated("unused", "") job: JobHandle): Unit = () protected def onRemoveJob(@deprecated("unused", "") job: JobHandle): Unit = () - private val context = LoggerContext(useLog4J) + private val context = LoggerContext() // this mutable state could conceptually go on State except // that then every task that runs a background job would have diff --git a/main/src/main/scala/sbt/internal/LogManager.scala b/main/src/main/scala/sbt/internal/LogManager.scala index e28fd91ee..a50f3c8e1 100644 --- a/main/src/main/scala/sbt/internal/LogManager.scala +++ b/main/src/main/scala/sbt/internal/LogManager.scala @@ -8,16 +8,15 @@ package sbt package internal -import java.io.PrintWriter - import sbt.Def.ScopedKey import sbt.Keys._ import sbt.Scope.Global import sbt.SlashSyntax0._ import sbt.internal.util.MainAppender._ import sbt.internal.util.{ Terminal => ITerminal, _ } -import sbt.util.{ Level, LogExchange, Logger, LoggerContext } -import org.apache.logging.log4j.core.{ Appender => XAppender } +import sbt.util.{ Level, Logger, LoggerContext } + +import java.io.PrintWriter import scala.annotation.nowarn sealed abstract class LogManager { @@ -88,12 +87,6 @@ object LogManager { def defaultManager(console: ConsoleOut): LogManager = withLoggers((_, _) => defaultScreen(console)) - @deprecated( - "use defaults that takes AppenderSupplier instead of ScopedKey[_] => Seq[Appender]", - "1.4.0" - ) - def defaults(extra: ScopedKey[_] => Seq[XAppender], console: ConsoleOut): LogManager = - defaults((sk: ScopedKey[_]) => extra(sk).map(new ConsoleAppenderFromLog4J("extra", _)), console) // This is called by Defaults. def defaults(extra: AppenderSupplier, console: ConsoleOut): LogManager = withLoggers( @@ -298,14 +291,6 @@ object LogManager { s1 } - @deprecated("No longer used.", "1.4.0") - private[sbt] def progressLogger(appender: ConsoleAppender): ManagedLogger = { - val log = LogExchange.logger("progress", None, None) - LoggerContext.globalContext.clearAppenders("progress") - LoggerContext.globalContext.addAppender("progress", appender -> Level.Info) - log - } - // This is the default implementation for the relay appender val defaultRelay: Unit => ConsoleAppender = _ => defaultRelayImpl diff --git a/sbt-app/src/test/scala/sbt/RunFromSourceMain.scala b/sbt-app/src/test/scala/sbt/RunFromSourceMain.scala index ae6240a8b..edac09a33 100644 --- a/sbt-app/src/test/scala/sbt/RunFromSourceMain.scala +++ b/sbt-app/src/test/scala/sbt/RunFromSourceMain.scala @@ -14,7 +14,6 @@ import sbt.util.LoggerContext import scala.annotation.tailrec import scala.sys.process.Process -import sbt.internal.SysProp object RunFromSourceMain { def fork( @@ -44,7 +43,7 @@ object RunFromSourceMain { implicit val runner = new ForkRun(fo) val options = Vector(workingDirectory.toString, scalaVersion, sbtVersion, cp.mkString(pathSeparator)) - val context = LoggerContext(useLog4J = SysProp.useLog4J) + val context = LoggerContext() val log = context.logger("RunFromSourceMain.fork", None, None) try runner.fork("sbt.RunFromSourceMain", cp, options, log) finally context.close() @@ -58,7 +57,7 @@ object RunFromSourceMain { case Array(wd, scalaVersion, sbtVersion, classpath, args @ _*) => System.setProperty("jna.nosys", "true") if (args.exists(_.startsWith("<"))) System.setProperty("sbt.io.virtual", "false") - val context = LoggerContext(useLog4J = SysProp.useLog4J) + val context = LoggerContext() try run(file(wd), scalaVersion, sbtVersion, classpath, args, context) finally context.close() } From c1d20f563b35b052a057160305272122cba5f7aa Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Sun, 5 Dec 2021 15:38:56 +0100 Subject: [PATCH 039/120] Fix #6738: register all forked process --- .../src/main/scala/sbt/ForkTests.scala | 10 +---- run/src/main/scala/sbt/Fork.scala | 13 ++++-- run/src/main/scala/sbt/Run.scala | 40 ++++++++++++------- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/main-actions/src/main/scala/sbt/ForkTests.scala b/main-actions/src/main/scala/sbt/ForkTests.scala index 80694ce30..ba707d5a2 100755 --- a/main-actions/src/main/scala/sbt/ForkTests.scala +++ b/main-actions/src/main/scala/sbt/ForkTests.scala @@ -18,7 +18,7 @@ import sbt.util.Logger import sbt.ConcurrentRestrictions.Tag import sbt.protocol.testing._ import sbt.internal.util.Util.{ AnyOps, none } -import sbt.internal.util.{ RunningProcesses, Terminal => UTerminal } +import sbt.internal.util.{ Terminal => UTerminal } private[sbt] object ForkTests { def apply( @@ -158,13 +158,7 @@ private[sbt] object ForkTests { classOf[ForkMain].getCanonicalName, server.getLocalPort.toString ) - val p = Fork.java.fork(fork, options) - RunningProcesses.add(p) - val ec = try p.exitValue() - finally { - if (p.isAlive()) p.destroy() - RunningProcesses.remove(p) - } + val ec = Fork.java(fork, options) val result = if (ec != 0) TestOutput( diff --git a/run/src/main/scala/sbt/Fork.scala b/run/src/main/scala/sbt/Fork.scala index b2cb449d0..c7e74c0f7 100644 --- a/run/src/main/scala/sbt/Fork.scala +++ b/run/src/main/scala/sbt/Fork.scala @@ -9,10 +9,9 @@ package sbt import java.io.File import java.lang.ProcessBuilder.Redirect - import scala.sys.process.Process import OutputStrategy._ -import sbt.internal.util.Util +import sbt.internal.util.{ RunningProcesses, Util } import Util.{ AnyOps, none } import java.lang.{ ProcessBuilder => JProcessBuilder } @@ -31,7 +30,15 @@ final class Fork(val commandName: String, val runnerClass: Option[String]) { * It is configured according to `config`. * If `runnerClass` is defined for this Fork instance, it is prepended to `arguments` to define the arguments passed to the forked command. */ - def apply(config: ForkOptions, arguments: Seq[String]): Int = fork(config, arguments).exitValue() + def apply(config: ForkOptions, arguments: Seq[String]): Int = { + val p = fork(config, arguments) + RunningProcesses.add(p) + try p.exitValue() + finally { + if (p.isAlive()) p.destroy() + RunningProcesses.remove(p) + } + } /** * Forks the configured process and returns a `Process` that can be used to wait for completion or to terminate the forked process. diff --git a/run/src/main/scala/sbt/Run.scala b/run/src/main/scala/sbt/Run.scala index 4df43f707..637c1473a 100644 --- a/run/src/main/scala/sbt/Run.scala +++ b/run/src/main/scala/sbt/Run.scala @@ -10,7 +10,6 @@ package sbt import java.io.File import java.lang.reflect.Method import java.lang.reflect.Modifier.{ isPublic, isStatic } - import sbt.internal.inc.ScalaInstance import sbt.internal.inc.classpath.{ ClasspathFilter, ClasspathUtil } import sbt.internal.util.MessageOnlyException @@ -34,29 +33,40 @@ class ForkRun(config: ForkOptions) extends ScalaRun { s"""Nonzero exit code returned from $label: $exitCode""".stripMargin ) ) - val process = fork(mainClass, classpath, options, log) - def cancel() = { - log.warn("Run canceled.") - process.destroy() - 1 + + log.info(s"running (fork) $mainClass ${Run.runOptionsStr(options)}") + val c = configLogged(log) + val scalaOpts = scalaOptions(mainClass, classpath, options) + val exitCode = try Fork.java(c, scalaOpts) + catch { + case _: InterruptedException => + log.warn("Run canceled.") + 1 } - val exitCode = try process.exitValue() - catch { case _: InterruptedException => cancel() } processExitCode(exitCode, "runner") } def fork(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger): Process = { log.info(s"running (fork) $mainClass ${Run.runOptionsStr(options)}") - val scalaOptions = classpathOption(classpath) ::: mainClass :: options.toList - val configLogged = - if (config.outputStrategy.isDefined) config - else config.withOutputStrategy(OutputStrategy.LoggedOutput(log)) + val c = configLogged(log) + val scalaOpts = scalaOptions(mainClass, classpath, options) + // fork with Java because Scala introduces an extra class loader (#702) - Fork.java.fork(configLogged, scalaOptions) + Fork.java.fork(c, scalaOpts) } - private def classpathOption(classpath: Seq[File]) = - "-classpath" :: Path.makeString(classpath) :: Nil + + private def configLogged(log: Logger): ForkOptions = { + if (config.outputStrategy.isDefined) config + else config.withOutputStrategy(OutputStrategy.LoggedOutput(log)) + } + + private def scalaOptions( + mainClass: String, + classpath: Seq[File], + options: Seq[String] + ): Seq[String] = + "-classpath" :: Path.makeString(classpath) :: mainClass :: options.toList } class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolean) From 0fef804b180486aef0a99eb35884006f5ed86c58 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Sun, 5 Dec 2021 15:38:56 +0100 Subject: [PATCH 040/120] Fix #6738: register all forked process --- .../src/main/scala/sbt/ForkTests.scala | 10 +---- run/src/main/scala/sbt/Fork.scala | 13 ++++-- run/src/main/scala/sbt/Run.scala | 40 ++++++++++++------- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/main-actions/src/main/scala/sbt/ForkTests.scala b/main-actions/src/main/scala/sbt/ForkTests.scala index 80694ce30..ba707d5a2 100755 --- a/main-actions/src/main/scala/sbt/ForkTests.scala +++ b/main-actions/src/main/scala/sbt/ForkTests.scala @@ -18,7 +18,7 @@ import sbt.util.Logger import sbt.ConcurrentRestrictions.Tag import sbt.protocol.testing._ import sbt.internal.util.Util.{ AnyOps, none } -import sbt.internal.util.{ RunningProcesses, Terminal => UTerminal } +import sbt.internal.util.{ Terminal => UTerminal } private[sbt] object ForkTests { def apply( @@ -158,13 +158,7 @@ private[sbt] object ForkTests { classOf[ForkMain].getCanonicalName, server.getLocalPort.toString ) - val p = Fork.java.fork(fork, options) - RunningProcesses.add(p) - val ec = try p.exitValue() - finally { - if (p.isAlive()) p.destroy() - RunningProcesses.remove(p) - } + val ec = Fork.java(fork, options) val result = if (ec != 0) TestOutput( diff --git a/run/src/main/scala/sbt/Fork.scala b/run/src/main/scala/sbt/Fork.scala index b2cb449d0..c7e74c0f7 100644 --- a/run/src/main/scala/sbt/Fork.scala +++ b/run/src/main/scala/sbt/Fork.scala @@ -9,10 +9,9 @@ package sbt import java.io.File import java.lang.ProcessBuilder.Redirect - import scala.sys.process.Process import OutputStrategy._ -import sbt.internal.util.Util +import sbt.internal.util.{ RunningProcesses, Util } import Util.{ AnyOps, none } import java.lang.{ ProcessBuilder => JProcessBuilder } @@ -31,7 +30,15 @@ final class Fork(val commandName: String, val runnerClass: Option[String]) { * It is configured according to `config`. * If `runnerClass` is defined for this Fork instance, it is prepended to `arguments` to define the arguments passed to the forked command. */ - def apply(config: ForkOptions, arguments: Seq[String]): Int = fork(config, arguments).exitValue() + def apply(config: ForkOptions, arguments: Seq[String]): Int = { + val p = fork(config, arguments) + RunningProcesses.add(p) + try p.exitValue() + finally { + if (p.isAlive()) p.destroy() + RunningProcesses.remove(p) + } + } /** * Forks the configured process and returns a `Process` that can be used to wait for completion or to terminate the forked process. diff --git a/run/src/main/scala/sbt/Run.scala b/run/src/main/scala/sbt/Run.scala index 4df43f707..637c1473a 100644 --- a/run/src/main/scala/sbt/Run.scala +++ b/run/src/main/scala/sbt/Run.scala @@ -10,7 +10,6 @@ package sbt import java.io.File import java.lang.reflect.Method import java.lang.reflect.Modifier.{ isPublic, isStatic } - import sbt.internal.inc.ScalaInstance import sbt.internal.inc.classpath.{ ClasspathFilter, ClasspathUtil } import sbt.internal.util.MessageOnlyException @@ -34,29 +33,40 @@ class ForkRun(config: ForkOptions) extends ScalaRun { s"""Nonzero exit code returned from $label: $exitCode""".stripMargin ) ) - val process = fork(mainClass, classpath, options, log) - def cancel() = { - log.warn("Run canceled.") - process.destroy() - 1 + + log.info(s"running (fork) $mainClass ${Run.runOptionsStr(options)}") + val c = configLogged(log) + val scalaOpts = scalaOptions(mainClass, classpath, options) + val exitCode = try Fork.java(c, scalaOpts) + catch { + case _: InterruptedException => + log.warn("Run canceled.") + 1 } - val exitCode = try process.exitValue() - catch { case _: InterruptedException => cancel() } processExitCode(exitCode, "runner") } def fork(mainClass: String, classpath: Seq[File], options: Seq[String], log: Logger): Process = { log.info(s"running (fork) $mainClass ${Run.runOptionsStr(options)}") - val scalaOptions = classpathOption(classpath) ::: mainClass :: options.toList - val configLogged = - if (config.outputStrategy.isDefined) config - else config.withOutputStrategy(OutputStrategy.LoggedOutput(log)) + val c = configLogged(log) + val scalaOpts = scalaOptions(mainClass, classpath, options) + // fork with Java because Scala introduces an extra class loader (#702) - Fork.java.fork(configLogged, scalaOptions) + Fork.java.fork(c, scalaOpts) } - private def classpathOption(classpath: Seq[File]) = - "-classpath" :: Path.makeString(classpath) :: Nil + + private def configLogged(log: Logger): ForkOptions = { + if (config.outputStrategy.isDefined) config + else config.withOutputStrategy(OutputStrategy.LoggedOutput(log)) + } + + private def scalaOptions( + mainClass: String, + classpath: Seq[File], + options: Seq[String] + ): Seq[String] = + "-classpath" :: Path.makeString(classpath) :: mainClass :: options.toList } class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolean) From 4a7500786239b12eae3d7a202fb15c78a52d1a6b Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 9 Dec 2021 22:51:30 -0500 Subject: [PATCH 041/120] Update log4j --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 34650e71a..18316bf55 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -124,7 +124,7 @@ object Dependencies { val scalaPar = "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0" // specify all of log4j modules to prevent misalignment - def log4jModule = (n: String) => "org.apache.logging.log4j" % n % "2.11.2" + def log4jModule = (n: String) => "org.apache.logging.log4j" % n % "2.15.0" val log4jApi = log4jModule("log4j-api") val log4jCore = log4jModule("log4j-core") val log4jSlf4jImpl = log4jModule("log4j-slf4j-impl") From 1a2722d0756eac93902fd2cf8b75d37d39a24a38 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Mon, 13 Dec 2021 20:11:30 +0100 Subject: [PATCH 042/120] discourse -> GH Discussions --- .github/ISSUE_TEMPLATE/--feature-request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/--feature-request.md b/.github/ISSUE_TEMPLATE/--feature-request.md index 5ef8d3776..3d76f73b9 100644 --- a/.github/ISSUE_TEMPLATE/--feature-request.md +++ b/.github/ISSUE_TEMPLATE/--feature-request.md @@ -7,4 +7,4 @@ assignees: '' --- -Please use https://discuss.lightbend.com/c/tooling including a specific user story instead of posting them to the issue tracker. +Please use https://github.com/sbt/sbt/discussions including a specific user story instead of posting them to the issue tracker. From 7a2d9981f7dbbe4918082ba672e9c73a8b4146c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20August=C3=BDn?= Date: Tue, 14 Dec 2021 15:36:03 +0100 Subject: [PATCH 043/120] chore(deps): log4j 2.16.0 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 18316bf55..2d438b0d2 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -124,7 +124,7 @@ object Dependencies { val scalaPar = "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0" // specify all of log4j modules to prevent misalignment - def log4jModule = (n: String) => "org.apache.logging.log4j" % n % "2.15.0" + def log4jModule = (n: String) => "org.apache.logging.log4j" % n % "2.16.0" val log4jApi = log4jModule("log4j-api") val log4jCore = log4jModule("log4j-core") val log4jSlf4jImpl = log4jModule("log4j-slf4j-impl") From e56b19930041f640566b4c43617e12fbdf903067 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Fri, 17 Dec 2021 23:21:26 -0500 Subject: [PATCH 044/120] lm-coursier-shaded 2.0.10 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 2d438b0d2..06bf9bbaf 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -77,7 +77,7 @@ object Dependencies { def addSbtZincCompile = addSbtModule(sbtZincPath, "zincCompileJVM2_12", zincCompile) def addSbtZincCompileCore = addSbtModule(sbtZincPath, "zincCompileCoreJVM2_12", zincCompileCore) - val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.0.9" + val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.0.10" def sjsonNew(n: String) = Def.setting("com.eed3si9n" %% n % "0.9.1") // contrabandSjsonNewVersion.value From 57e1044f5bcb52a30c5146fc09a7e40350fcfd81 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 18 Dec 2021 15:05:05 -0500 Subject: [PATCH 045/120] log4j 2.17.0 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 06bf9bbaf..23972722c 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -124,7 +124,7 @@ object Dependencies { val scalaPar = "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0" // specify all of log4j modules to prevent misalignment - def log4jModule = (n: String) => "org.apache.logging.log4j" % n % "2.16.0" + def log4jModule = (n: String) => "org.apache.logging.log4j" % n % "2.17.0" val log4jApi = log4jModule("log4j-api") val log4jCore = log4jModule("log4j-core") val log4jSlf4jImpl = log4jModule("log4j-slf4j-impl") From df46c08051e9f8c887087d58482ef2905d796d11 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 18 Dec 2021 18:11:10 -0500 Subject: [PATCH 046/120] sbt 1.6.0-RC2 --- sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbt b/sbt index 218f45141..ea4654a73 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.6.0-RC1" +declare builtin_sbt_version="1.6.0-RC2" declare -a residual_args declare -a java_args declare -a scalac_args From 780665a60c8492bc994e01f3f084ffdc03317d2f Mon Sep 17 00:00:00 2001 From: gontard Date: Fri, 24 Dec 2021 16:12:37 +0100 Subject: [PATCH 047/120] Ensure sbtConfig argv does not need sbt in PATH Before, the BSP config .bsp/sbt.json generated by `sbt bspConfig` contained a command line which required the sbt binary in the PATH. This fix changes the nature of the -Dsbt.script option. It was an argument of the main class xsbt.boot.Boot, it's now a system property and thus it's used to launch the sbt server. Fixes https://github.com/sbt/sbt/issues/6760 --- .../scala/sbt/internal/bsp/BuildServerConnection.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala index 66ac7bdf0..fa7fce354 100644 --- a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala +++ b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala @@ -49,9 +49,11 @@ object BuildServerConnection { "-Xmx100m", "-classpath", classPath, - "xsbt.boot.Boot", - "-bsp" - ) ++ sbtScript.orElse(sbtLaunchJar) + ) ++ + sbtScript ++ + Vector("xsbt.boot.Boot", "-bsp") ++ + (if (sbtScript.isEmpty) sbtLaunchJar else None) + val details = BspConnectionDetails(name, sbtVersion, bspVersion, languages, argv) val json = Converter.toJson(details).get IO.write(bspConnectionFile, CompactPrinter(json), append = false) From 645cebccac46f49dd35e6c8ff583f11c8d398773 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 26 Dec 2021 00:28:09 -0500 Subject: [PATCH 048/120] IO 1.6.0 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 23972722c..85dfa1ee2 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -12,7 +12,7 @@ object Dependencies { sys.env.get("BUILD_VERSION") orElse sys.props.get("sbt.build.version") // sbt modules - private val ioVersion = nightlyVersion.getOrElse("1.6.0-M2") + private val ioVersion = nightlyVersion.getOrElse("1.6.0") private val lmVersion = sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.6.0-M2") val zincVersion = nightlyVersion.getOrElse("1.6.0-M2") From 0f8ac0f543d812d7bea53b12011153130353fd73 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 26 Dec 2021 01:44:00 -0500 Subject: [PATCH 049/120] Zinc 1.6.0 --- project/Dependencies.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 85dfa1ee2..d2a166720 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -14,8 +14,8 @@ 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.0-M2") - val zincVersion = nightlyVersion.getOrElse("1.6.0-M2") + sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.6.0") + val zincVersion = nightlyVersion.getOrElse("1.6.0") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion From 990fa9530f2f4cfe499f4fc54cc2cb4f179a78e3 Mon Sep 17 00:00:00 2001 From: gontard Date: Fri, 24 Dec 2021 16:12:37 +0100 Subject: [PATCH 050/120] Ensure sbtConfig argv does not need sbt in PATH Before, the BSP config .bsp/sbt.json generated by `sbt bspConfig` contained a command line which required the sbt binary in the PATH. This fix changes the nature of the -Dsbt.script option. It was an argument of the main class xsbt.boot.Boot, it's now a system property and thus it's used to launch the sbt server. Fixes https://github.com/sbt/sbt/issues/6760 --- .../scala/sbt/internal/bsp/BuildServerConnection.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala index 66ac7bdf0..fa7fce354 100644 --- a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala +++ b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala @@ -49,9 +49,11 @@ object BuildServerConnection { "-Xmx100m", "-classpath", classPath, - "xsbt.boot.Boot", - "-bsp" - ) ++ sbtScript.orElse(sbtLaunchJar) + ) ++ + sbtScript ++ + Vector("xsbt.boot.Boot", "-bsp") ++ + (if (sbtScript.isEmpty) sbtLaunchJar else None) + val details = BspConnectionDetails(name, sbtVersion, bspVersion, languages, argv) val json = Converter.toJson(details).get IO.write(bspConnectionFile, CompactPrinter(json), append = false) From 544a935534975603cf698381ea5196364d234e98 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 26 Dec 2021 01:48:14 -0500 Subject: [PATCH 051/120] Update banner --- main/src/main/scala/sbt/internal/Banner.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/scala/sbt/internal/Banner.scala b/main/src/main/scala/sbt/internal/Banner.scala index b43f811ad..0b5a25e71 100644 --- a/main/src/main/scala/sbt/internal/Banner.scala +++ b/main/src/main/scala/sbt/internal/Banner.scala @@ -16,7 +16,7 @@ private[sbt] object Banner { | - Improved JDK 17 support | - Improved Build Server Protocol (BSP) support | - Tab completion of global keys - |See https://eed3si9n.com/sbt-1.6.0-beta for full release notes. + |See https://eed3si9n.com/sbt-1.6.0 for full release notes. |Hide the banner for this release by running `skipBanner`. |""".stripMargin.linesIterator.mkString("\n")) case v if v.startsWith("1.4.0") => From 43088834d2e936f42830faf5b68c441b026ddb18 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 26 Dec 2021 13:44:22 -0500 Subject: [PATCH 052/120] sbt 1.6.0 --- sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbt b/sbt index ea4654a73..e1219c287 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.6.0-RC2" +declare builtin_sbt_version="1.6.0" declare -a residual_args declare -a java_args declare -a scalac_args From d71a1fbdacd84a5609c17685c444dea9ee653bdd Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 28 Dec 2021 23:07:39 -0500 Subject: [PATCH 053/120] log4j 2.17.1 Fixes CVE-2021-44832 https://logging.apache.org/log4j/2.x/security.html --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index d2a166720..125d56457 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -124,7 +124,7 @@ object Dependencies { val scalaPar = "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0" // specify all of log4j modules to prevent misalignment - def log4jModule = (n: String) => "org.apache.logging.log4j" % n % "2.17.0" + def log4jModule = (n: String) => "org.apache.logging.log4j" % n % "2.17.1" val log4jApi = log4jModule("log4j-api") val log4jCore = log4jModule("log4j-core") val log4jSlf4jImpl = log4jModule("log4j-slf4j-impl") From 515993498d80eab063c39d37a6927a46040d93e1 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 28 Dec 2021 23:45:04 -0500 Subject: [PATCH 054/120] Use lazy val --- main/src/main/scala/sbt/internal/SysProp.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/scala/sbt/internal/SysProp.scala b/main/src/main/scala/sbt/internal/SysProp.scala index fbf0942b2..737b0b368 100644 --- a/main/src/main/scala/sbt/internal/SysProp.scala +++ b/main/src/main/scala/sbt/internal/SysProp.scala @@ -218,6 +218,6 @@ object SysProp { baseCache.getAbsoluteFile / "v1" } - val sbtCredentialsEnv: Option[Credentials] = + lazy val sbtCredentialsEnv: Option[Credentials] = sys.env.get("SBT_CREDENTIALS").map(raw => new FileCredentials(new File(raw))) } From ff7384fced17630f26e27f1f56e7b4fca43c2217 Mon Sep 17 00:00:00 2001 From: naf Date: Wed, 29 Dec 2021 21:17:05 -0500 Subject: [PATCH 055/120] 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 89991eda6985c02f0fd768a2fc09b460bf3cc96c Mon Sep 17 00:00:00 2001 From: kenji yoshida <6b656e6a69@gmail.com> Date: Mon, 17 Jan 2022 13:27:21 +0900 Subject: [PATCH 056/120] Update CI status badge in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4224db130..990d6c676 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.com/sbt/sbt.svg?branch=develop)](https://travis-ci.com/github/sbt/sbt) +[![CI](https://github.com/sbt/sbt/actions/workflows/ci.yml/badge.svg)](https://github.com/sbt/sbt/actions/workflows/ci.yml) [![Latest version](https://img.shields.io/github/tag/sbt/sbt.svg)](https://index.scala-lang.org/sbt/sbt) [![Gitter Chat](https://badges.gitter.im/sbt/sbt.svg)](https://gitter.im/sbt/sbt) From fb648580531bf67de359c1f42cb1bc0028771df0 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 17 Jan 2022 23:44:38 -0500 Subject: [PATCH 057/120] Fix test --- internal/util-logging/src/test/scala/ManagedLoggerSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala b/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala index 94bf50d8c..d19d61658 100644 --- a/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala +++ b/internal/util-logging/src/test/scala/ManagedLoggerSpec.scala @@ -18,7 +18,7 @@ class ManagedLoggerSpec extends AnyFlatSpec with Matchers { val context = LoggerContext() @nowarn //TODO create a new appender for testing purposes - 3/12/21 - val asyncStdout = new ConsoleAppenderFromLog4J("asyncStdout", LogExchange.asyncStdout) + val asyncStdout = ConsoleAppender("asyncStdout") def newLogger(name: String): ManagedLogger = context.logger(name, None, None) "ManagedLogger" should "log to console" in { val log = newLogger("foo") From a3610377d46b1ff09b1c44a1019dac71d8c8e113 Mon Sep 17 00:00:00 2001 From: Amina Adewusi Date: Fri, 21 Jan 2022 14:51:11 +0000 Subject: [PATCH 058/120] Remove scalacoption -S-X Fixes https://github.com/sbt/sbt/issues/6785. --- sbt | 1 - 1 file changed, 1 deletion(-) diff --git a/sbt b/sbt index e1219c287..6d153b336 100755 --- a/sbt +++ b/sbt @@ -580,7 +580,6 @@ Usage: `basename "$0"` [options] -Dkey=val pass -Dkey=val directly to the java runtime -J-X pass option -X directly to the java runtime (-J is stripped) - -S-X add -X to sbt's scalacOptions (-S is stripped) In the case of duplicated or conflicting options, the order above shows precedence: JAVA_OPTS lowest, command line options highest. From 21e5f2dead237d7e23d416220c4937195c39b77a Mon Sep 17 00:00:00 2001 From: tpetillot Date: Wed, 26 Jan 2022 16:19:15 +0100 Subject: [PATCH 059/120] fix: propagate `InterruptedException` from JLine.readLine Motivation: Cannot exit from InteractionService.readLine Modification: Remove try/catch of InterruptedException mapped to None in JLine.readLine --- .../src/main/scala/sbt/internal/util/LineReader.scala | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala index d52903d87..fbc86b725 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala @@ -178,13 +178,7 @@ abstract class JLine extends LineReader { protected[this] lazy val in: InputStream = Terminal.wrappedSystemIn override def readLine(prompt: String, mask: Option[Char] = None): Option[String] = - try { - unsynchronizedReadLine(prompt, mask) - } catch { - case _: InterruptedException => - // println("readLine: InterruptedException") - Option("") - } + unsynchronizedReadLine(prompt, mask) private[this] def unsynchronizedReadLine(prompt: String, mask: Option[Char]): Option[String] = readLineWithHistory(prompt, mask) map { x => From f5fb537c6d565642cd65e0845f93466ddef212d4 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Wed, 29 Dec 2021 00:18:51 -0500 Subject: [PATCH 060/120] sbt 1.6.1 --- sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbt b/sbt index 6d153b336..07e3c0409 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.6.0" +declare builtin_sbt_version="1.6.1" declare -a residual_args declare -a java_args declare -a scalac_args From a549e79c1d2c80a443d544581eb52e4985a909bf Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 31 Jan 2022 16:37:38 -0500 Subject: [PATCH 061/120] Throw when test framework cannot be loaded due to MatchError or NoClassDefFoundError Problem ------- In some situations like Dotty Community Build, sbt version is mechanically upgraded on an old commit without humans checking the log. For reasons we're not completely sure (likely change in ClassLoader structure) sbt 1.6.x started to fail to load test frameworks during tests, but since the failure of the test framework loading doesn't fail the task, this silently succeeded the builds. Solution -------- On MatchError and NoClassDefFound Error, rethrow the exception. Note that ClassNotFoundException is considered ok since we have predefined test frameworks listed in sbt, which often are not included in the users' classpath. --- build.sbt | 2 +- .../src/main/scala/sbt/TestFramework.scala | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/build.sbt b/build.sbt index e8c0a5d3b..edb4d4340 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.0-SNAPSHOT" + val v = "1.6.2-SNAPSHOT" nightlyVersion.getOrElse(v) } ThisBuild / version2_13 := "2.0.0-SNAPSHOT" diff --git a/testing/src/main/scala/sbt/TestFramework.scala b/testing/src/main/scala/sbt/TestFramework.scala index d7e057ac5..fe3f76196 100644 --- a/testing/src/main/scala/sbt/TestFramework.scala +++ b/testing/src/main/scala/sbt/TestFramework.scala @@ -49,12 +49,14 @@ final class TestFramework(val implClassNames: String*) extends Serializable { ): Option[Framework] = { def logError(e: Throwable): Option[Framework] = { log.error( - s"Error loading test framework ($e). This usually means that you are" - + " using a layered class loader that cannot reach the sbt.testing.Framework class." - + " The most likely cause is that your project has a runtime dependency on your" - + " test framework, e.g. scalatest. To fix this, you can try to set\n" - + "Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.ScalaLibrary\nor\n" - + "Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat" + s"""Error loading test framework ($e). + |This often means that you are using a layered class loader that cannot reach the sbt.testing.Framework class. + |The most likely cause is that your project has a runtime dependency on your + |test framework, e.g. ScalaTest. To fix this, you can try to set + | + | Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.ScalaLibrary + |or + | Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat""".stripMargin ) None } @@ -66,8 +68,12 @@ final class TestFramework(val implClassNames: String*) extends Serializable { case oldFramework: OldFramework => new FrameworkWrapper(oldFramework) }) } catch { - case e: NoClassDefFoundError => logError(e) - case e: MatchError => logError(e) + case e: NoClassDefFoundError => + logError(e) + throw e + case e: MatchError => + logError(e) + throw e case _: ClassNotFoundException => log.debug("Framework implementation '" + head + "' not present.") createFramework(loader, log, tail) From 4f9fe2af6446d75aeb94f88c2738360e773c8aea Mon Sep 17 00:00:00 2001 From: tpetillot Date: Wed, 26 Jan 2022 16:19:15 +0100 Subject: [PATCH 062/120] fix: propagate `InterruptedException` from JLine.readLine Motivation: Cannot exit from InteractionService.readLine Modification: Remove try/catch of InterruptedException mapped to None in JLine.readLine --- .../src/main/scala/sbt/internal/util/LineReader.scala | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala index d52903d87..fbc86b725 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala @@ -178,13 +178,7 @@ abstract class JLine extends LineReader { protected[this] lazy val in: InputStream = Terminal.wrappedSystemIn override def readLine(prompt: String, mask: Option[Char] = None): Option[String] = - try { - unsynchronizedReadLine(prompt, mask) - } catch { - case _: InterruptedException => - // println("readLine: InterruptedException") - Option("") - } + unsynchronizedReadLine(prompt, mask) private[this] def unsynchronizedReadLine(prompt: String, mask: Option[Char]): Option[String] = readLineWithHistory(prompt, mask) map { x => From 761ad142673ce45a5768eb077118bcb1c752da83 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 31 Jan 2022 22:00:54 -0500 Subject: [PATCH 063/120] Make License object available Fixes #1937 Ref https://github.com/sbt/librarymanagement/pull/395 --- project/Dependencies.scala | 2 +- sbt-app/src/main/scala/sbt/Import.scala | 1 + sbt-app/src/sbt-test/dependency-management/artifact/build.sbt | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 125d56457..84413f9d7 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.0") + sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.6.1") val zincVersion = nightlyVersion.getOrElse("1.6.0") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion diff --git a/sbt-app/src/main/scala/sbt/Import.scala b/sbt-app/src/main/scala/sbt/Import.scala index b71e855df..548e571a4 100644 --- a/sbt-app/src/main/scala/sbt/Import.scala +++ b/sbt-app/src/main/scala/sbt/Import.scala @@ -297,6 +297,7 @@ trait Import { type IvyScala = sbt.librarymanagement.ScalaModuleInfo val JCenterRepository = sbt.librarymanagement.Resolver.JCenterRepository val JavaNet2Repository = sbt.librarymanagement.Resolver.JavaNet2Repository + val License = sbt.librarymanagement.License type LogicalClock = sbt.librarymanagement.LogicalClock val LogicalClock = sbt.librarymanagement.LogicalClock type MakePomConfiguration = sbt.librarymanagement.MakePomConfiguration diff --git a/sbt-app/src/sbt-test/dependency-management/artifact/build.sbt b/sbt-app/src/sbt-test/dependency-management/artifact/build.sbt index d0d5afc46..e4ffeae52 100644 --- a/sbt-app/src/sbt-test/dependency-management/artifact/build.sbt +++ b/sbt-app/src/sbt-test/dependency-management/artifact/build.sbt @@ -11,6 +11,7 @@ ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / organization := "com.example" ThisBuild / organizationName := "example" ThisBuild / csrCacheDirectory := (ThisBuild / baseDirectory).value / "coursier-cache" +ThisBuild / licenses := List(License.Apache2) lazy val Dev = config("dev").extend(Compile) .describedAs("Dependencies required for development environments") From ed022a70ace736b645e375a8dfd261d342a3f4f3 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 31 Jan 2022 23:25:20 -0500 Subject: [PATCH 064/120] sbt 1.6.2 --- build.sbt | 2 +- sbt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index edb4d4340..a33ac73ae 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.2-SNAPSHOT" + val v = "1.6.3-SNAPSHOT" nightlyVersion.getOrElse(v) } ThisBuild / version2_13 := "2.0.0-SNAPSHOT" diff --git a/sbt b/sbt index 07e3c0409..c7c45a3a2 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.6.1" +declare builtin_sbt_version="1.6.2" declare -a residual_args declare -a java_args declare -a scalac_args From ca8fd354bd7da44bc86260e444a1cd4a041a1350 Mon Sep 17 00:00:00 2001 From: Amina Adewusi Date: Fri, 4 Feb 2022 17:52:39 +0000 Subject: [PATCH 065/120] Fixes parsing command args quote problem Fixes #6802. --- .../main/scala/sbt/internal/util/complete/Parsers.scala | 7 ++++++- internal/util-complete/src/test/scala/ParserTest.scala | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala index 884aecc9a..15a1f2dcb 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala @@ -202,7 +202,7 @@ trait Parsers { * Parses a potentially quoted String value. The value may be verbatim quoted ([[StringVerbatim]]), * quoted with interpreted escapes ([[StringEscapable]]), or unquoted ([[NotQuoted]]). */ - lazy val StringBasic = StringVerbatim | StringEscapable | NotQuoted + lazy val StringBasic = StringVerbatim | StringEscapable | NotQuoted | NotQuotedThenQuoted /** * Parses a verbatim quoted String value, discarding the quotes in the result. This kind of quoted text starts with triple quotes `"""` @@ -270,6 +270,11 @@ trait Parsers { /** Parses an unquoted, non-empty String value that cannot start with a double quote and cannot contain whitespace.*/ lazy val NotQuoted = (NotDQuoteSpaceClass ~ OptNotSpace) map { case (c, s) => c.toString + s } + /** Parses a non-empty String value that cannot start with a double quote, but includes double quotes.*/ + lazy val NotQuotedThenQuoted = (NotQuoted ~ StringEscapable) map { + case (s1, s2) => s"""$s1\"$s2\"""" + } + /** * Applies `rep` zero or more times, separated by `sep`. * The result is the (possibly empty) sequence of results from the multiple `rep` applications. The `sep` results are discarded. diff --git a/internal/util-complete/src/test/scala/ParserTest.scala b/internal/util-complete/src/test/scala/ParserTest.scala index 49f99056f..4694f974a 100644 --- a/internal/util-complete/src/test/scala/ParserTest.scala +++ b/internal/util-complete/src/test/scala/ParserTest.scala @@ -119,6 +119,8 @@ object ParserTest extends Properties("Completing Parser") { property("repeatDep requires at least one token") = !matches(repeat, "") property("repeatDep accepts one token") = matches(repeat, colors.toSeq.head) property("repeatDep accepts two tokens") = matches(repeat, colors.toSeq.take(2).mkString(" ")) + property("parses string that doesn't start with quotes, but includes quotes within it") = + matches(StringBasic, "-Dsilicon:z3ConfigArgs=\"model=true model_validate=true\"") } object ParserExample { val ws = charClass(_.isWhitespace, "whitespace").+ From a0e5b553ef9bb64033ca41f519ffa71b151dcfa3 Mon Sep 17 00:00:00 2001 From: Takeo Sawada Date: Mon, 21 Feb 2022 17:33:27 +0900 Subject: [PATCH 066/120] launcher: debian package to depend on curl | wget also give informative error message when neither is available --- launcher-package/build.sbt | 2 +- sbt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/launcher-package/build.sbt b/launcher-package/build.sbt index ddfdb1f9f..b621c7695 100755 --- a/launcher-package/build.sbt +++ b/launcher-package/build.sbt @@ -191,7 +191,7 @@ val root = (project in file(".")). }, // Used to have "openjdk-8-jdk" but that doesn't work on Ubuntu 14.04 https://github.com/sbt/sbt/issues/3105 // before that we had java6-runtime-headless" and that was pulling in JDK9 on Ubuntu 16.04 https://github.com/sbt/sbt/issues/2931 - debianPackageDependencies in Debian ++= Seq("bash (>= 3.2)"), + debianPackageDependencies in Debian ++= Seq("bash (>= 3.2)", "curl | wget"), debianPackageRecommends in Debian += "git", linuxPackageMappings in Debian += { val bd = sourceDirectory.value diff --git a/sbt b/sbt index 218f45141..9d04b2deb 100755 --- a/sbt +++ b/sbt @@ -123,6 +123,9 @@ download_url () { curl --silent -L "$url" --output "$jar" elif command -v wget > /dev/null; then wget --quiet -O "$jar" "$url" + else + echoerr "failed to download $url: Neither curl nor wget is avaialble" + exit 2 fi } && [[ -f "$jar" ]] } From d25dfd06abcaa61f9a263f7b58bba93f5dd78ff4 Mon Sep 17 00:00:00 2001 From: gontard Date: Fri, 25 Feb 2022 16:14:43 +0100 Subject: [PATCH 067/120] Improve log for not found remote cache artifact Before remote cache not found for 0.0.0-7c40144bd1c774e6 After remote cache artifact not found for org.gontard:sbt-test:0.0.0-7c40144bd1c774e6 Some(cached-compile) --- main/src/main/scala/sbt/internal/RemoteCache.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/src/main/scala/sbt/internal/RemoteCache.scala b/main/src/main/scala/sbt/internal/RemoteCache.scala index 200117de7..c125fdbea 100644 --- a/main/src/main/scala/sbt/internal/RemoteCache.scala +++ b/main/src/main/scala/sbt/internal/RemoteCache.scala @@ -303,7 +303,8 @@ object RemoteCache { } found = true case Left(e) => - log.info(s"remote cache not found for ${v}") + val classifier = seqa.map(_.classifier).mkString(" ") + log.info(s"remote cache artifact not found for $p $classifier") log.debug(e.getMessage) } } From 23b50688ba7b50861544bc09a07a2f278f23ac19 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Fri, 4 Mar 2022 10:53:25 +0100 Subject: [PATCH 068/120] feat: add optional framework field to the bsp --- main/src/main/scala/sbt/Keys.scala | 2 +- .../internal/server/BuildServerProtocol.scala | 35 +++++++++++++------ .../internal/bsp/ScalaTestClassesItem.scala | 23 ++++++++---- .../codec/ScalaTestClassesItemFormats.scala | 4 ++- protocol/src/main/contraband/bsp.contra | 3 ++ 5 files changed, 48 insertions(+), 19 deletions(-) diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 1a248b1df..2270ee573 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -419,7 +419,7 @@ object Keys { val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask) val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask) val bspScalaTestClasses = inputKey[Unit]("Corresponds to buildTarget/scalaTestClasses request").withRank(DTask) - val bspScalaTestClassesItem = taskKey[ScalaTestClassesItem]("").withRank(DTask) + val bspScalaTestClassesItem = taskKey[Seq[ScalaTestClassesItem]]("").withRank(DTask) val bspScalaMainClasses = inputKey[Unit]("Corresponds to buildTarget/scalaMainClasses request").withRank(DTask) val bspScalaMainClassesItem = taskKey[ScalaMainClassesItem]("").withRank(DTask) val bspReporter = taskKey[BuildServerReporter]("").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 b5006aabb..d289884bf 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -242,7 +242,7 @@ object BuildServerProtocol { val filter = ScopeFilter.in(workspace.scopes.values.toList) Def.task { val items = bspScalaTestClassesItem.result.all(filter).value - val successfulItems = anyOrThrow(items) + val successfulItems = anyOrThrow(items).flatten.toVector val result = ScalaTestClassesResult(successfulItems.toVector, None) s.respondEvent(result) } @@ -840,15 +840,30 @@ object BuildServerProtocol { } } - private def scalaTestClassesTask: Initialize[Task[ScalaTestClassesItem]] = Def.task { - val testClasses = Keys.definedTests.?.value - .getOrElse(Seq.empty) - .map(_.name) - .toVector - ScalaTestClassesItem( - bspTargetIdentifier.value, - testClasses - ) + private def scalaTestClassesTask: Initialize[Task[Seq[ScalaTestClassesItem]]] = Def.task { + Keys.definedTests.?.value match { + case None => Vector.empty + case Some(definitions) => + val fingerprints = Keys.loadedTestFrameworks.?.value + .getOrElse(Map.empty) + .values + .flatMap { framework => + framework.fingerprints().map(fingerprint => (fingerprint, framework)) + } + .toMap + + definitions + .groupBy(defn => fingerprints.get(defn.fingerprint)) + .map { + case (framework, definitions) => + ScalaTestClassesItem( + bspTargetIdentifier.value, + definitions.map(_.name).toVector, + framework.map(_.name()) + ) + } + .toSeq + } } private def scalaMainClassesTask: Initialize[Task[ScalaMainClassesItem]] = Def.task { diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaTestClassesItem.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaTestClassesItem.scala index 210e8cc30..e274fda16 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaTestClassesItem.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/ScalaTestClassesItem.scala @@ -7,25 +7,27 @@ package sbt.internal.bsp /** * @param target The build target that contains the test classes. * @param classes The fully qualified names of the test classes in this target + * @param framework The name of the test framework used in test classes. */ final class ScalaTestClassesItem private ( val target: sbt.internal.bsp.BuildTargetIdentifier, - val classes: Vector[String]) extends Serializable { + val classes: Vector[String], + val framework: Option[String]) extends Serializable { override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { - case x: ScalaTestClassesItem => (this.target == x.target) && (this.classes == x.classes) + case x: ScalaTestClassesItem => (this.target == x.target) && (this.classes == x.classes) && (this.framework == x.framework) case _ => false }) override def hashCode: Int = { - 37 * (37 * (37 * (17 + "sbt.internal.bsp.ScalaTestClassesItem".##) + target.##) + classes.##) + 37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.ScalaTestClassesItem".##) + target.##) + classes.##) + framework.##) } override def toString: String = { - "ScalaTestClassesItem(" + target + ", " + classes + ")" + "ScalaTestClassesItem(" + target + ", " + classes + ", " + framework + ")" } - private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, classes: Vector[String] = classes): ScalaTestClassesItem = { - new ScalaTestClassesItem(target, classes) + private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, classes: Vector[String] = classes, framework: Option[String] = framework): ScalaTestClassesItem = { + new ScalaTestClassesItem(target, classes, framework) } def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): ScalaTestClassesItem = { copy(target = target) @@ -33,8 +35,15 @@ final class ScalaTestClassesItem private ( def withClasses(classes: Vector[String]): ScalaTestClassesItem = { copy(classes = classes) } + def withFramework(framework: Option[String]): ScalaTestClassesItem = { + copy(framework = framework) + } + def withFramework(framework: String): ScalaTestClassesItem = { + copy(framework = Option(framework)) + } } object ScalaTestClassesItem { - def apply(target: sbt.internal.bsp.BuildTargetIdentifier, classes: Vector[String]): ScalaTestClassesItem = new ScalaTestClassesItem(target, classes) + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, classes: Vector[String], framework: Option[String]): ScalaTestClassesItem = new ScalaTestClassesItem(target, classes, framework) + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, classes: Vector[String], framework: String): ScalaTestClassesItem = new ScalaTestClassesItem(target, classes, Option(framework)) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaTestClassesItemFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaTestClassesItemFormats.scala index a079301b3..1353a0b41 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaTestClassesItemFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ScalaTestClassesItemFormats.scala @@ -13,8 +13,9 @@ implicit lazy val ScalaTestClassesItemFormat: JsonFormat[sbt.internal.bsp.ScalaT unbuilder.beginObject(__js) val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target") val classes = unbuilder.readField[Vector[String]]("classes") + val framework = unbuilder.readField[Option[String]]("framework") unbuilder.endObject() - sbt.internal.bsp.ScalaTestClassesItem(target, classes) + sbt.internal.bsp.ScalaTestClassesItem(target, classes, framework) case None => deserializationError("Expected JsObject but found None") } @@ -23,6 +24,7 @@ implicit lazy val ScalaTestClassesItemFormat: JsonFormat[sbt.internal.bsp.ScalaT builder.beginObject() builder.addField("target", obj.target) builder.addField("classes", obj.classes) + builder.addField("framework", obj.framework) builder.endObject() } } diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index 01b3a450f..62438cff0 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -636,6 +636,9 @@ type ScalaTestClassesItem { ## The fully qualified names of the test classes in this target classes: [String] + + ## The name of the test framework used in test classes. + framework: String } ## Scala Main Class Request From 466410464c2b1fbab47d230f5f15b95255ad2c08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Mar 2022 04:03:15 +0000 Subject: [PATCH 069/120] Bump actions/setup-python from 2 to 3 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 3. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2...v3) --- 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 52f902c35..edbe25672 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@v2 + uses: actions/setup-python@v3 with: python-version: 3.7 - name: Coursier cache From 144398ec7328faf3000eb02221d02f13f3707a5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Mar 2022 04:03:17 +0000 Subject: [PATCH 070/120] Bump actions/checkout from 2 to 3 Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/nightly.yml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52f902c35..b3e8d03af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,21 +60,21 @@ jobs: SPARK_LOCAL_IP: "127.0.0.1" steps: - name: Checkout sbt/sbt - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Checkout sbt/io - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: sbt/io ref: develop path: io - name: Checkout sbt/librarymanagement - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: sbt/librarymanagement ref: develop path: librarymanagement - name: Checkout sbt/zinc - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: sbt/zinc ref: develop diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 0593b63e9..4d98a29d8 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -16,21 +16,21 @@ jobs: JAVA_OPTS: -Xms800M -Xmx800M -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8 steps: - name: Checkout sbt/sbt - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Checkout sbt/io - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: sbt/io ref: develop path: io - name: Checkout sbt/librarymanagement - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: sbt/librarymanagement ref: develop path: librarymanagement - name: Checkout sbt/zinc - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: sbt/zinc ref: develop From 1396e1605d04dc53b91e41c1cc1be2f339e310ec Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Tue, 8 Mar 2022 18:19:20 +0100 Subject: [PATCH 071/120] Try fix CI: Build and test (6) --- project/Dependencies.scala | 14 +++++++------- project/plugins.sbt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 84413f9d7..ae0d47987 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -69,13 +69,13 @@ object Dependencies { def addSbtLmIvy = addSbtModule(sbtLmPath, "lmIvy", libraryManagementIvy) def addSbtLmIvyTest = addSbtModule(sbtLmPath, "lmIvy", libraryManagementIvy, Some(Test)) - def addSbtCompilerInterface = addSbtModule(sbtZincPath, "compilerInterfaceJVM", compilerInterface) - def addSbtCompilerClasspath = addSbtModule(sbtZincPath, "zincClasspathJVM2_12", compilerClasspath) - def addSbtCompilerApiInfo = addSbtModule(sbtZincPath, "zincApiInfoJVM2_12", compilerApiInfo) - def addSbtCompilerBridge = addSbtModule(sbtZincPath, "compilerBridgeJVM2_12", compilerBridge) - def addSbtZinc = addSbtModule(sbtZincPath, "zincJVM2_12", zinc) - def addSbtZincCompile = addSbtModule(sbtZincPath, "zincCompileJVM2_12", zincCompile) - def addSbtZincCompileCore = addSbtModule(sbtZincPath, "zincCompileCoreJVM2_12", zincCompileCore) + def addSbtCompilerInterface = addSbtModule(sbtZincPath, "compilerInterface", compilerInterface) + def addSbtCompilerClasspath = addSbtModule(sbtZincPath, "zincClasspath", compilerClasspath) + def addSbtCompilerApiInfo = addSbtModule(sbtZincPath, "zincApiInfo", compilerApiInfo) + def addSbtCompilerBridge = addSbtModule(sbtZincPath, "compilerBridge2_12", compilerBridge) + def addSbtZinc = addSbtModule(sbtZincPath, "zinc", zinc) + def addSbtZincCompile = addSbtModule(sbtZincPath, "zincCompile", zincCompile) + def addSbtZincCompileCore = addSbtModule(sbtZincPath, "zincCompileCore", zincCompileCore) val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.0.10" diff --git a/project/plugins.sbt b/project/plugins.sbt index 7f7e8fa9a..00c24984e 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -6,9 +6,9 @@ addSbtPlugin("com.dwijnand" % "sbt-dynver" % "4.0.0") addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.3.0") addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.5.1") -addSbtPlugin("de.heikoseeberger" % "sbt-header" % "3.0.2") +addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.6.5") addSbtPlugin("com.lightbend" % "sbt-whitesource" % "0.1.14") -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.9") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0") addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.8.1") addSbtPlugin("com.swoval" % "sbt-java-format" % "0.3.1") addDependencyTreePlugin From ce978a19ed39bc69e7b0c3debeb2330f639011f8 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Thu, 10 Mar 2022 19:56:49 +0100 Subject: [PATCH 072/120] tests: add test case for framework field in scala test classes request --- .../internal/server/BuildServerProtocol.scala | 32 ++++++++----------- .../test/scala/testpkg/BuildServerTest.scala | 3 +- .../src/main/scala/sbt/TestFramework.scala | 9 ++++-- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index d289884bf..0c6655e2d 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -39,6 +39,7 @@ import scala.collection.mutable import scala.util.control.NonFatal import scala.util.{ Failure, Success, Try } import scala.annotation.nowarn +import sbt.testing.Framework object BuildServerProtocol { import sbt.internal.bsp.codec.JsonProtocol._ @@ -844,25 +845,20 @@ object BuildServerProtocol { Keys.definedTests.?.value match { case None => Vector.empty case Some(definitions) => - val fingerprints = Keys.loadedTestFrameworks.?.value - .getOrElse(Map.empty) - .values - .flatMap { framework => - framework.fingerprints().map(fingerprint => (fingerprint, framework)) - } - .toMap + val frameworks: Seq[Framework] = Keys.loadedTestFrameworks.?.value + .map(_.values.toSeq) + .getOrElse(Seq.empty) - definitions - .groupBy(defn => fingerprints.get(defn.fingerprint)) - .map { - case (framework, definitions) => - ScalaTestClassesItem( - bspTargetIdentifier.value, - definitions.map(_.name).toVector, - framework.map(_.name()) - ) - } - .toSeq + val grouped = TestFramework.testMap(frameworks, definitions) + + grouped.map { + case (framework, definitions) => + ScalaTestClassesItem( + bspTargetIdentifier.value, + definitions.map(_.name).toVector, + framework.name() + ) + }.toSeq } } diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index 5aa231752..9cbe43980 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -308,7 +308,8 @@ object BuildServerTest extends AbstractServerTest { assert(svr.waitForString(10.seconds) { s => (s contains """"id":"72"""") && (s contains """"tests.FailingTest"""") && - (s contains """"tests.PassingTest"""") + (s contains """"tests.PassingTest"""") && + (s contains """"framework":"ScalaTest"""") }) } diff --git a/testing/src/main/scala/sbt/TestFramework.scala b/testing/src/main/scala/sbt/TestFramework.scala index fe3f76196..cb89dd5f4 100644 --- a/testing/src/main/scala/sbt/TestFramework.scala +++ b/testing/src/main/scala/sbt/TestFramework.scala @@ -231,21 +231,26 @@ object TestFramework { ): Vector[(String, TestFunction)] = for (d <- inputs; act <- mapped.get(d.name)) yield (d.name, act) - private[this] def testMap( + def testMap( frameworks: Seq[Framework], tests: Seq[TestDefinition] ): Map[Framework, Set[TestDefinition]] = { import scala.collection.mutable.{ HashMap, HashSet, Set } val map = new HashMap[Framework, Set[TestDefinition]] + def assignTest(test: TestDefinition): Unit = { def isTestForFramework(framework: Framework) = getFingerprints(framework).exists { t => matches(t, test.fingerprint) } - for (framework <- frameworks.find(isTestForFramework)) + + frameworks.find(isTestForFramework).foreach { framework => map.getOrElseUpdate(framework, new HashSet[TestDefinition]) += test + } } + if (frameworks.nonEmpty) for (test <- tests) assignTest(test) + map.toMap.mapValues(_.toSet).toMap } From 80e87531d35aaf730d4eead08901657bfb774017 Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Fri, 18 Mar 2022 02:23:08 +0900 Subject: [PATCH 073/120] 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 facf6637a..2e3f463f1 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -2310,10 +2310,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 @@ -2342,7 +2343,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) = { @@ -2364,7 +2366,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 f118d2d73b85a883b37015be2bfd20086a67efeb Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Fri, 18 Mar 2022 23:04:07 +0900 Subject: [PATCH 074/120] 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 2e3f463f1..4b0fc2ad9 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -2329,7 +2329,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 { @@ -2366,7 +2366,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 893cfbba3976a876e72608848cc5a1a0db1bb50c Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Mon, 21 Mar 2022 21:35:11 +0900 Subject: [PATCH 075/120] 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 fb479efdf9d964d05d6e446ea271b99c70166bfb Mon Sep 17 00:00:00 2001 From: Brice Jaglin Date: Wed, 23 Mar 2022 12:25:35 +0100 Subject: [PATCH 076/120] 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 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 077/120] 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 078/120] 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 079/120] 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 080/120] 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 081/120] 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 dd497063e5fb41c655f0d18c186b4ef68f215d0b Mon Sep 17 00:00:00 2001 From: David Gregory Date: Wed, 30 Mar 2022 19:03:14 +0100 Subject: [PATCH 082/120] Add Remove instances for Set and Map --- main-settings/src/main/scala/sbt/Remove.scala | 10 ++++++++++ sbt-app/src/sbt-test/project/remove/build.sbt | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/main-settings/src/main/scala/sbt/Remove.scala b/main-settings/src/main/scala/sbt/Remove.scala index e09555f5b..6ab53e42b 100644 --- a/main-settings/src/main/scala/sbt/Remove.scala +++ b/main-settings/src/main/scala/sbt/Remove.scala @@ -34,4 +34,14 @@ object Remove { def removeValue(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a filterNot _.==) def removeValues(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a filterNot _.==) } + implicit def removeSet[T, V <: T]: Sequence[Set[T], Set[V], V] = + new Sequence[Set[T], Set[V], V] { + def removeValue(a: Set[T], b: V): Set[T] = a - b + def removeValues(a: Set[T], b: Set[V]): Set[T] = a diff (b.toSeq: Seq[T]).toSet + } + implicit def removeMap[A, B, X <: A]: Sequence[Map[A, B], Seq[X], X] = + new Sequence[Map[A, B], Seq[X], X] { + def removeValue(a: Map[A, B], b: X): Map[A, B] = a - b + def removeValues(a: Map[A, B], b: Seq[X]): Map[A, B] = a -- b + } } diff --git a/sbt-app/src/sbt-test/project/remove/build.sbt b/sbt-app/src/sbt-test/project/remove/build.sbt index d3ae2985d..5a16e59d8 100644 --- a/sbt-app/src/sbt-test/project/remove/build.sbt +++ b/sbt-app/src/sbt-test/project/remove/build.sbt @@ -1,6 +1,8 @@ val intsTask = taskKey[Seq[Int]]("A seq of ints task") val intsSetting = settingKey[Seq[Int]]("A seq of ints setting") val intsFromScalaV = settingKey[Seq[Int]]("a seq of ints from scalaVersion") +val intsSetSetting = settingKey[Set[Int]]("A set of ints setting") +val stringIntMapSetting = settingKey[Map[String, Int]]("A map of string to int setting") scalaVersion := "2.11.6" @@ -22,9 +24,19 @@ intsFromScalaV --= { if (scalaVersion.value == "2.11.6") Seq(1, 2) else Seq(4) } intsFromScalaV -= { if (scalaVersion.value == "2.11.6") Option(6) else None } intsFromScalaV --= { if (scalaVersion.value == "2.11.6") Option(7) else None } +intsSetSetting := Set(1, 2, 3, 4, 5, 6, 7) +intsSetSetting -= 3 +intsSetSetting --= Set(1, 2) + +stringIntMapSetting := Map("a" -> 1, "b" -> 2 , "c" -> 3, "d" -> 4, "e" -> 5) +stringIntMapSetting -= "c" +stringIntMapSetting --= Seq("a", "b") + val check = taskKey[Unit]("Runs the check") check := { assert(intsTask.value == Seq(4, 5), s"intsTask should be Seq(4, 5) but is ${intsTask.value}") assert(intsSetting.value == Seq(4, 5), s"intsSetting should be Seq(4, 5) but is ${intsSetting.value}") assert(intsFromScalaV.value == Seq(4, 5), s"intsFromScalaV should be Seq(4, 5) but is ${intsFromScalaV.value}") + assert(intsSetSetting.value == Set(4, 5, 6, 7), s"intsSetSetting should be Set(4, 5, 6, 7) but is ${intsSetSetting.value}") + assert(stringIntMapSetting.value == Map("d" -> 4, "e" -> 5), s"stringIntMapSetting should be Map(d -> 4, e -> 5) but is ${stringIntMapSetting.value}") } 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 083/120] 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 084/120] 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 085/120] 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 086/120] 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 087/120] 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 088/120] 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 089/120] 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 090/120] 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 091/120] 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 092/120] 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 093/120] 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 094/120] 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 095/120] 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 096/120] 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 097/120] 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 098/120] 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 099/120] 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 100/120] 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 101/120] 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 102/120] 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 103/120] 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 104/120] 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 105/120] 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 106/120] 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 107/120] 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 108/120] "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 109/120] 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 110/120] 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 111/120] 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 112/120] 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 113/120] 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 114/120] 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 115/120] 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 116/120] 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 117/120] 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 118/120] 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 From 0d0a654c6f34958c6fb8939859b8315b1bb10f84 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Mon, 9 May 2022 16:41:26 +0200 Subject: [PATCH 119/120] Add support for wildcards in Scala version switch Picking from the `crossScalaVersions` As discussed in https://github.com/sbt/sbt/discussions/6893 --- main/src/main/scala/sbt/Cross.scala | 96 +++++++++++++------ main/src/test/scala/sbt/CrossSpec.scala | 20 ++++ .../sbt-test/actions/cross-multiproject/test | 21 ++++ 3 files changed, 109 insertions(+), 28 deletions(-) create mode 100644 main/src/test/scala/sbt/CrossSpec.scala diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 8bb001d04..9966c5eb9 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -8,7 +8,7 @@ package sbt import java.io.File - +import java.util.regex.Pattern import sbt.Def.{ ScopedKey, Setting } import sbt.Keys._ import sbt.SlashSyntax0._ @@ -284,8 +284,8 @@ object Cross { } def logSwitchInfo( - included: Seq[(ProjectRef, Seq[ScalaVersion])], - excluded: Seq[(ProjectRef, Seq[ScalaVersion])] + included: Seq[(ResolvedReference, ScalaVersion, Seq[ScalaVersion])], + excluded: Seq[(ResolvedReference, Seq[ScalaVersion])] ) = { instance.foreach { @@ -304,56 +304,96 @@ object Cross { def detailedLog(msg: => String) = if (switch.verbose) state.log.info(msg) else state.log.debug(msg) - def logProject: (ProjectRef, Seq[ScalaVersion]) => Unit = (proj, scalaVersions) => { - val current = if (proj == currentRef) "*" else " " - detailedLog(s" $current ${proj.project} ${scalaVersions.mkString("(", ", ", ")")}") + def logProject: (ResolvedReference, Seq[ScalaVersion]) => Unit = (ref, scalaVersions) => { + val current = if (ref == currentRef) "*" else " " + ref match { + case proj: ProjectRef => + detailedLog(s" $current ${proj.project} ${scalaVersions.mkString("(", ", ", ")")}") + case _ => // don't log BuildRefs + } } detailedLog("Switching Scala version on:") - included.foreach(logProject.tupled) + included.foreach { case (project, _, versions) => logProject(project, versions) } detailedLog("Excluding projects:") excluded.foreach(logProject.tupled) } - val projects: Seq[(ResolvedReference, Seq[ScalaVersion])] = { + val projects: Seq[(ResolvedReference, Option[ScalaVersion], Seq[ScalaVersion])] = { val projectScalaVersions = structure.allProjectRefs.map(proj => proj -> crossVersions(extracted, proj)) if (switch.version.force) { - logSwitchInfo(projectScalaVersions, Nil) - projectScalaVersions ++ structure.units.keys + projectScalaVersions.map { + case (ref, options) => (ref, Some(version), options) + } ++ structure.units.keys .map(BuildRef.apply) - .map(proj => proj -> crossVersions(extracted, proj)) + .map(proj => (proj, Some(version), crossVersions(extracted, proj))) + } else if (version.contains('*')) { + projectScalaVersions.map { + case (project, scalaVersions) => + globFilter(version, scalaVersions) match { + case Nil => (project, None, scalaVersions) + case Seq(version) => (project, Some(version), scalaVersions) + case multiple => + sys.error( + s"Multiple crossScalaVersions matched query '$version': ${multiple.mkString(", ")}" + ) + } + } } else { val binaryVersion = CrossVersion.binaryScalaVersion(version) - - val (included, excluded) = projectScalaVersions.partition { - case (_, scalaVersions) => - scalaVersions.exists(v => CrossVersion.binaryScalaVersion(v) == binaryVersion) + projectScalaVersions.map { + case (project, scalaVersions) => + if (scalaVersions.exists(v => CrossVersion.binaryScalaVersion(v) == binaryVersion)) + (project, Some(version), scalaVersions) + else + (project, None, scalaVersions) } - if (included.isEmpty) { - sys.error( - s"""Switch failed: no subprojects list "$version" (or compatible version) in crossScalaVersions setting. - |If you want to force it regardless, call ++ $version!""".stripMargin - ) - } - logSwitchInfo(included, excluded) - included } } - (setScalaVersionForProjects(version, instance, projects, state, extracted), projects.map(_._1)) + val included = projects.collect { + case (project, Some(version), scalaVersions) => (project, version, scalaVersions) + } + val excluded = projects.collect { + case (project, None, scalaVersions) => (project, scalaVersions) + } + + if (included.isEmpty) { + sys.error( + s"""Switch failed: no subprojects list "$version" (or compatible version) in crossScalaVersions setting. + |If you want to force it regardless, call ++ $version!""".stripMargin + ) + } + + logSwitchInfo(included, excluded) + + (setScalaVersionsForProjects(instance, included, state, extracted), included.map(_._1)) } - private def setScalaVersionForProjects( - version: String, + def globFilter(pattern: String, candidates: Seq[String]): Seq[String] = { + def createGlobRegex(remainingPattern: String): String = + remainingPattern.indexOf("*") match { + case -1 => Pattern.quote(remainingPattern) + case n => + val chunk = Pattern.quote(remainingPattern.substring(0, n)) + ".*" + if (remainingPattern.length > n) + chunk + createGlobRegex(remainingPattern.substring(n + 1)) + else chunk + } + val compiledPattern = Pattern.compile(createGlobRegex(pattern)) + candidates.filter(compiledPattern.matcher(_).matches()) + } + + private def setScalaVersionsForProjects( instance: Option[(File, ScalaInstance)], - projects: Seq[(ResolvedReference, Seq[String])], + projects: Seq[(ResolvedReference, String, Seq[String])], state: State, extracted: Extracted ): State = { import extracted._ val newSettings = projects.flatMap { - case (project, scalaVersions) => + case (project, version, scalaVersions) => val scope = Scope(Select(project), Zero, Zero, Zero) instance match { diff --git a/main/src/test/scala/sbt/CrossSpec.scala b/main/src/test/scala/sbt/CrossSpec.scala new file mode 100644 index 000000000..40673d548 --- /dev/null +++ b/main/src/test/scala/sbt/CrossSpec.scala @@ -0,0 +1,20 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt + +object CrossSpec extends verify.BasicTestSuite { + import Cross._ + + test("glob filter should work as expected") { + assert(globFilter("2.13.*", Seq("2.12.8", "2.13.16", "3.0.1")) == Seq("2.13.16")) + assert(globFilter("3.*", Seq("2.12.8", "2.13.16", "3.0.1")) == Seq("3.0.1")) + assert(globFilter("3.*", Seq("3.0.1", "30.1")) == Seq("3.0.1")) + assert(globFilter("2.*", Seq("2.12.8", "2.13.16", "3.0.1")) == Seq("2.12.8", "2.13.16")) + assert(globFilter("4.*", Seq("2.12.8", "2.13.16", "3.0.1")) == Nil) + } +} diff --git a/sbt-app/src/sbt-test/actions/cross-multiproject/test b/sbt-app/src/sbt-test/actions/cross-multiproject/test index 68b8383d5..baf4db9b8 100644 --- a/sbt-app/src/sbt-test/actions/cross-multiproject/test +++ b/sbt-app/src/sbt-test/actions/cross-multiproject/test @@ -41,3 +41,24 @@ $ exists lib/target/scala-2.13 -$ exists lib/target/scala-2.12 # -$ exists sbt-foo/target/scala-2.12 -$ exists sbt-foo/target/scala-2.13 + +# test wildcard switching (2.12) +> clean +> ++ 2.12.* -v compile +$ exists lib/target/scala-2.12 +-$ exists lib/target/scala-2.13 +$ exists sbt-foo/target/scala-2.12 +-$ exists sbt-foo/target/scala-2.13 + +# test wildcard switching (2.13) +> clean +> ++ 2.13.* -v compile +$ exists lib/target/scala-2.13 +-$ exists lib/target/scala-2.12 +# -$ exists sbt-foo/target/scala-2.12 +-$ exists sbt-foo/target/scala-2.13 + +# test wildcard switching (no matches) +-> ++ 3.* +# test wildcard switching (multiple matches) +-> ++ 2.* From e8d60efbb41ecd7e12e8fd4ade4c061af4fcb999 Mon Sep 17 00:00:00 2001 From: Kamil Podsiadlo Date: Wed, 22 Jun 2022 00:00:31 +0200 Subject: [PATCH 120/120] fix: publishing bsp diagnostics * do not publish bsp diagnostics if there were and there are no problems * publish diagnostics if problems needs to be updated --- main/src/main/scala/sbt/Defaults.scala | 12 +- .../internal/server/BuildServerProtocol.scala | 48 +++-- .../internal/server/BuildServerReporter.scala | 69 ++++--- .../src/server-test/buildserver/build.sbt | 2 + .../src/main/scala/Diagnostics.scala | 3 + .../src/main/scala/PatternMatch.scala | 7 + .../test/scala/testpkg/BuildServerTest.scala | 182 +++++++++++++----- 7 files changed, 228 insertions(+), 95 deletions(-) create mode 100644 server-test/src/server-test/buildserver/diagnostics/src/main/scala/Diagnostics.scala create mode 100644 server-test/src/server-test/buildserver/diagnostics/src/main/scala/PatternMatch.scala diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index f3fe55029..f90f91de3 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -2307,11 +2307,10 @@ 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, prevAnalysis) + compileIncrementalTaskImpl(task, s, ci, ping, reporter) } } private val incCompiler = ZincUtil.defaultIncrementalCompiler @@ -2326,7 +2325,7 @@ object Defaults extends BuildCommon { val result0 = incCompiler .asInstanceOf[sbt.internal.inc.IncrementalCompilerImpl] .compileAllJava(in, s.log) - reporter.sendSuccessReport(result0.analysis(), Analysis.empty, false) + reporter.sendSuccessReport(result0.analysis()) result0.withHasModified(result0.hasModified || r.hasModified) } else r } catch { @@ -2341,7 +2340,6 @@ object Defaults extends BuildCommon { ci: Inputs, promise: PromiseWrap[Boolean], reporter: BuildServerReporter, - prev: CompileAnalysis ): CompileResult = { lazy val x = s.text(ExportStream) def onArgs(cs: Compilers) = { @@ -2363,11 +2361,7 @@ object Defaults extends BuildCommon { .withSetup(onProgress(setup)) try { val result = incCompiler.compile(i, s.log) - reporter.sendSuccessReport( - result.getAnalysis, - prev, - BuildServerProtocol.shouldReportAllPreviousProblems(task.targetId) - ) + reporter.sendSuccessReport(result.getAnalysis) 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 f288d05a3..4e2abdbe8 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -32,33 +32,20 @@ import sjsonnew.shaded.scalajson.ast.unsafe.{ JNull, JValue } import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter, Parser => JsonParser } import xsbti.CompileFailed +import java.nio.file.Path import java.io.File +import java.util.concurrent.atomic.AtomicBoolean import scala.collection.mutable // import scala.annotation.nowarn 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), @@ -305,12 +292,20 @@ object BuildServerProtocol { bspScalaMainClassesItem := scalaMainClassesTask.value, Keys.compile / bspReporter := { val targetId = bspTargetIdentifier.value + val bspCompileStateInstance = bspCompileState.value val converter = fileConverter.value val underlying = (Keys.compile / compilerReporter).value val logger = streams.value.log val meta = isMetaBuild.value if (bspEnabled.value) { - new BuildServerReporterImpl(targetId, converter, meta, logger, underlying) + new BuildServerReporterImpl( + targetId, + bspCompileStateInstance, + converter, + meta, + logger, + underlying + ) } else { new BuildServerForwarder(meta, logger, underlying) } @@ -356,7 +351,6 @@ 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", @@ -714,6 +708,10 @@ object BuildServerProtocol { DependencySourcesItem(targetId, sources.toVector.distinct) } + private def bspCompileState: Initialize[BuildServerProtocol.BspCompileState] = Def.setting { + new BuildServerProtocol.BspCompileState() + } + private def bspCompileTask: Def.Initialize[Task[Int]] = Def.task { Keys.compile.result.value match { case Value(_) => StatusCode.Success @@ -1000,4 +998,20 @@ object BuildServerProtocol { ) } } + + /** + * Additional information about compilation status for given build target. + * + * @param hasAnyProblems keeps track of problems in given file so BSP reporter + * can omit unnecessary diagnostics updates. + * @param compiledAtLeastOnce keeps 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[server] final class BspCompileState { + val hasAnyProblems: java.util.Set[Path] = + java.util.concurrent.ConcurrentHashMap.newKeySet[Path] + val compiledAtLeastOnce: AtomicBoolean = new AtomicBoolean(false) + } } diff --git a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala index 98d59d645..6e04053da 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerReporter.scala @@ -12,6 +12,7 @@ import java.nio.file.Path import sbt.StandardMain import sbt.internal.bsp._ import sbt.internal.util.ManagedLogger +import sbt.internal.server.BuildServerProtocol.BspCompileState import xsbti.compile.CompileAnalysis import xsbti.{ FileConverter, @@ -40,8 +41,6 @@ sealed trait BuildServerReporter extends Reporter { def sendSuccessReport( analysis: CompileAnalysis, - prev: CompileAnalysis, - reportAllPreviousProblems: Boolean ): Unit def sendFailureReport(sources: Array[VirtualFile]): Unit @@ -73,6 +72,7 @@ sealed trait BuildServerReporter extends Reporter { final class BuildServerReporterImpl( buildTarget: BuildTargetIdentifier, + bspCompileState: BspCompileState, converter: FileConverter, protected override val isMetaBuild: Boolean, protected override val logger: ManagedLogger, @@ -90,22 +90,38 @@ final class BuildServerReporterImpl( if (ref.id().contains("<")) None else Some(converter.toPath(ref)) + /** + * Send diagnostics from the compilation to the client. + * Do not send empty diagnostics if previous ones were also empty ones. + * + * @param analysis current compile analysis + */ override def sendSuccessReport( analysis: CompileAnalysis, - prev: CompileAnalysis, - reportAllPreviousProblems: Boolean ): Unit = { - val prevInfos = prev.readSourceInfos().getAllSourceInfos().asScala + val shouldReportAllProblems = !bspCompileState.compiledAtLeastOnce.getAndSet(true) for { (source, infos) <- analysis.readSourceInfos.getAllSourceInfos.asScala filePath <- toSafePath(source) } { - val prevProblems = prevInfos.get(source).map(_.getReportedProblems()).getOrElse(Array.empty) - val dontPublish = prevProblems.length == 0 && infos.getReportedProblems().length == 0 - val shouldPublish = reportAllPreviousProblems || !dontPublish + // clear problems for current file + val hadProblems = bspCompileState.hasAnyProblems.remove(filePath) + + val reportedProblems = infos.getReportedProblems.toVector + val diagnostics = reportedProblems.flatMap(toDiagnostic) + + // publish diagnostics if: + // 1. file had any problems previously - we might want to update them with new ones + // 2. file has fresh problems - we might want to update old ones + // 3. build project is compiled first time - shouldReportAllProblems is set + val shouldPublish = hadProblems || diagnostics.nonEmpty || shouldReportAllProblems + + // file can have some warnings + if (diagnostics.nonEmpty) { + bspCompileState.hasAnyProblems.add(filePath) + } if (shouldPublish) { - val diagnostics = infos.getReportedProblems.toSeq.flatMap(toDiagnostic) val params = PublishDiagnosticsParams( textDocument = TextDocumentIdentifier(filePath.toUri), buildTarget, @@ -117,21 +133,32 @@ final class BuildServerReporterImpl( } } } - override def sendFailureReport(sources: Array[VirtualFile]): Unit = { + val shouldReportAllProblems = !bspCompileState.compiledAtLeastOnce.get for { source <- sources filePath <- toSafePath(source) } { - val diagnostics = problemsByFile.getOrElse(filePath, Vector()) - val params = PublishDiagnosticsParams( - textDocument = TextDocumentIdentifier(filePath.toUri), - buildTarget, - originId = None, - diagnostics, - reset = true - ) - exchange.notifyEvent("build/publishDiagnostics", params) + val diagnostics = problemsByFile.getOrElse(filePath, Vector.empty) + + val hadProblems = bspCompileState.hasAnyProblems.remove(filePath) + val shouldPublish = hadProblems || diagnostics.nonEmpty || shouldReportAllProblems + + // mark file as file with problems + if (diagnostics.nonEmpty) { + bspCompileState.hasAnyProblems.add(filePath) + } + + if (shouldPublish) { + val params = PublishDiagnosticsParams( + textDocument = TextDocumentIdentifier(filePath.toUri), + buildTarget, + originId = None, + diagnostics, + reset = true + ) + exchange.notifyEvent("build/publishDiagnostics", params) + } } } @@ -141,7 +168,7 @@ final class BuildServerReporterImpl( diagnostic <- toDiagnostic(problem) filePath <- toSafePath(VirtualFileRef.of(id)) } { - problemsByFile(filePath) = problemsByFile.getOrElse(filePath, Vector()) :+ diagnostic + problemsByFile(filePath) = problemsByFile.getOrElse(filePath, Vector.empty) :+ diagnostic val params = PublishDiagnosticsParams( TextDocumentIdentifier(filePath.toUri), buildTarget, @@ -196,8 +223,6 @@ final class BuildServerForwarder( override def sendSuccessReport( analysis: CompileAnalysis, - prev: CompileAnalysis, - reportAllPreviousProblems: Boolean ): Unit = () override def sendFailureReport(sources: Array[VirtualFile]): Unit = () diff --git a/server-test/src/server-test/buildserver/build.sbt b/server-test/src/server-test/buildserver/build.sbt index 9d2de35fc..fe2cf4db5 100644 --- a/server-test/src/server-test/buildserver/build.sbt +++ b/server-test/src/server-test/buildserver/build.sbt @@ -32,6 +32,8 @@ lazy val respondError = project.in(file("respond-error")) lazy val util = project +lazy val diagnostics = project + def somethingBad = throw new MessageOnlyException("I am a bad build target") // other build targets should not be affected by this bad build target lazy val badBuildTarget = project.in(file("bad-build-target")) diff --git a/server-test/src/server-test/buildserver/diagnostics/src/main/scala/Diagnostics.scala b/server-test/src/server-test/buildserver/diagnostics/src/main/scala/Diagnostics.scala new file mode 100644 index 000000000..a74b3da77 --- /dev/null +++ b/server-test/src/server-test/buildserver/diagnostics/src/main/scala/Diagnostics.scala @@ -0,0 +1,3 @@ +object Diagnostics { + private val a: Int = 5 +} \ No newline at end of file diff --git a/server-test/src/server-test/buildserver/diagnostics/src/main/scala/PatternMatch.scala b/server-test/src/server-test/buildserver/diagnostics/src/main/scala/PatternMatch.scala new file mode 100644 index 000000000..626a59f8f --- /dev/null +++ b/server-test/src/server-test/buildserver/diagnostics/src/main/scala/PatternMatch.scala @@ -0,0 +1,7 @@ + +class PatternMatch { + val opt: Option[Int] = None + opt match { + case Some(value) => () + } +} diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index 817b0e6ad..1b8fd06fb 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -71,6 +71,7 @@ object BuildServerTest extends AbstractServerTest { ) assert(sources.contains(expectedSource)) } + test("buildTarget/sources: sbt") { _ => val x = new URI(s"${svr.baseDirectory.getAbsoluteFile.toURI}#buildserver-build") svr.sendJsonRpc(buildTargetSources(26, Seq(x))) @@ -89,13 +90,12 @@ object BuildServerTest extends AbstractServerTest { ).map(rel => new File(svr.baseDirectory.getAbsoluteFile, rel).toURI).sorted assert(sources == expectedSources) } + test("buildTarget/compile") { _ => val buildTarget = buildTargetUri("util", "Compile") - svr.sendJsonRpc( - s"""{ "jsonrpc": "2.0", "id": "32", "method": "buildTarget/compile", "params": { - | "targets": [{ "uri": "$buildTarget" }] - |} }""".stripMargin - ) + + compile(buildTarget, id = 32) + assert(processing("buildTarget/compile")) val res = svr.waitFor[BspCompileResult](10.seconds) assert(res.statusCode == StatusCode.Success) @@ -103,11 +103,8 @@ object BuildServerTest extends AbstractServerTest { test("buildTarget/compile - reports compilation progress") { _ => val buildTarget = buildTargetUri("runAndTest", "Compile") - svr.sendJsonRpc( - s"""{ "jsonrpc": "2.0", "id": "33", "method": "buildTarget/compile", "params": { - | "targets": [{ "uri": "$buildTarget" }] - |} }""".stripMargin - ) + + compile(buildTarget, id = 33) // This doesn't always come back in 10s on CI. assert(svr.waitForString(60.seconds) { s => @@ -134,16 +131,112 @@ object BuildServerTest extends AbstractServerTest { 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 + test( + "buildTarget/compile [diagnostics] don't publish unnecessary for successful compilation case" + ) { _ => + val buildTarget = buildTargetUri("diagnostics", "Compile") + val mainFile = new File(svr.baseDirectory, "diagnostics/src/main/scala/Diagnostics.scala") + + compile(buildTarget, id = 33) + + assert(svr.waitForString(30.seconds) { s => + s.contains("build/taskFinish") && + s.contains(""""message":"Compiled diagnostics"""") + }) + + // introduce compile error + IO.write( + mainFile, + """|object Diagnostics { + | private val a: Int = "" + |}""".stripMargin + ) + + reloadWorkspace(id = 55) + compile(buildTarget, id = 66) + + assert( + svr.waitForString(30.seconds) { s => + s.contains("build/publishDiagnostics") && + s.contains("Diagnostics.scala") && + s.contains("\"message\":\"type mismatch") + }, + "should send publishDiagnostics with type error for Main.scala" + ) + + // fix compilation error + IO.write( + mainFile, + """|object Diagnostics { + | private val a: Int = 5 + |}""".stripMargin + ) + + reloadWorkspace(id = 77) + compile(buildTarget, id = 88) + + assert( + svr.waitForString(30.seconds) { s => + s.contains("build/publishDiagnostics") && + s.contains("Diagnostics.scala") && + s.contains("\"diagnostics\":[]") + }, + "should send publishDiagnostics with empty diagnostics" + ) + + // trigger no-op compilation + compile(buildTarget, id = 99) + + assert( + !svr.waitForString(20.seconds) { s => + s.contains("build/publishDiagnostics") && + s.contains("Diagnostics.scala") + }, + "shouldn't send publishDiagnostics if there's no change in diagnostics (were empty, are empty)" + ) + } + + test("buildTarget/compile [diagnostics] clear stale warnings") { _ => + val buildTarget = buildTargetUri("diagnostics", "Compile") + val testFile = new File(svr.baseDirectory, s"diagnostics/src/main/scala/PatternMatch.scala") + + compile(buildTarget, id = 33) + + assert( + svr.waitForString(30.seconds) { s => + s.contains("build/publishDiagnostics") && + s.contains("PatternMatch.scala") && + s.contains(""""message":"match may not be exhaustive""") + }, + "should send publishDiagnostics with type error for PatternMatch.scala" + ) + + IO.write( + testFile, + """|class PatternMatch { + | val opt: Option[Int] = None + | opt match { + | case Some(value) => () + | case None => () + | } + |} + |""".stripMargin + ) + + reloadWorkspace(id = 55) + compile(buildTarget, id = 66) + + assert( + svr.waitForString(30.seconds) { s => + s.contains("build/publishDiagnostics") && + s.contains("PatternMatch.scala") && + s.contains("\"diagnostics\":[]") + }, + "should send publishDiagnostics with empty diagnostics" ) - assert(!svr.waitForString(30.seconds) { s => - s.contains("build/publishDiagnostics") - }, "shouldn't send publishDiagnostics if there's no change in diagnostics") } test("buildTarget/scalacOptions") { _ => @@ -171,11 +264,7 @@ object BuildServerTest extends AbstractServerTest { .toFile val buildTarget = buildTargetUri("runAndTest", "Compile") - svr.sendJsonRpc( - s"""{ "jsonrpc": "2.0", "id": "43", "method": "buildTarget/compile", "params": { - | "targets": [{ "uri": "$buildTarget" }] - |} }""".stripMargin - ) + compile(buildTarget, id = 43) svr.waitFor[BspCompileResult](10.seconds) assert(targetDir.list().contains("Main.class")) @@ -233,9 +322,7 @@ object BuildServerTest extends AbstractServerTest { |""".stripMargin ) // reload - svr.sendJsonRpc( - """{ "jsonrpc": "2.0", "id": "52", "method": "workspace/reload"}""" - ) + reloadWorkspace(id = 52) assert( svr.waitForString(10.seconds) { s => s.contains(s""""buildTarget":{"uri":"$metaBuildTarget"}""") && @@ -261,9 +348,7 @@ object BuildServerTest extends AbstractServerTest { |) |""".stripMargin ) - svr.sendJsonRpc( - """{ "jsonrpc": "2.0", "id": "52", "method": "workspace/reload"}""" - ) + reloadWorkspace(id = 52) // assert received an empty diagnostic assert( svr.waitForString(10.seconds) { s => @@ -335,10 +420,10 @@ object BuildServerTest extends AbstractServerTest { test("buildTarget/jvmTestEnvironment") { _ => val buildTarget = buildTargetUri("runAndTest", "Test") svr.sendJsonRpc( - s"""|{ "jsonrpc": "2.0", - | "id": "98", - | "method": "buildTarget/jvmTestEnvironment", - | "params": { "targets": [{ "uri": "$buildTarget" }] } + s"""|{ "jsonrpc": "2.0", + | "id": "98", + | "method": "buildTarget/jvmTestEnvironment", + | "params": { "targets": [{ "uri": "$buildTarget" }] } |}""".stripMargin ) assert(processing("buildTarget/jvmTestEnvironment")) @@ -410,11 +495,7 @@ object BuildServerTest extends AbstractServerTest { test("buildTarget/compile: report error") { _ => val buildTarget = buildTargetUri("reportError", "Compile") - svr.sendJsonRpc( - s"""{ "jsonrpc": "2.0", "id": "88", "method": "buildTarget/compile", "params": { - | "targets": [{ "uri": "$buildTarget" }] - |} }""".stripMargin - ) + compile(buildTarget, id = 88) assert(svr.waitForString(10.seconds) { s => (s contains s""""buildTarget":{"uri":"$buildTarget"}""") && (s contains """"severity":1""") && @@ -424,11 +505,7 @@ object BuildServerTest extends AbstractServerTest { test("buildTarget/compile: report warning") { _ => val buildTarget = buildTargetUri("reportWarning", "Compile") - svr.sendJsonRpc( - s"""{ "jsonrpc": "2.0", "id": "90", "method": "buildTarget/compile", "params": { - | "targets": [{ "uri": "$buildTarget" }] - |} }""".stripMargin - ) + compile(buildTarget, id = 90) assert(svr.waitForString(10.seconds) { s => (s contains s""""buildTarget":{"uri":"$buildTarget"}""") && (s contains """"severity":2""") && @@ -438,11 +515,7 @@ object BuildServerTest extends AbstractServerTest { test("buildTarget/compile: respond error") { _ => val buildTarget = buildTargetUri("respondError", "Compile") - svr.sendJsonRpc( - s"""{ "jsonrpc": "2.0", "id": "92", "method": "buildTarget/compile", "params": { - | "targets": [{ "uri": "$buildTarget" }] - |} }""".stripMargin - ) + compile(buildTarget, id = 92) assert(svr.waitForString(10.seconds) { s => s.contains(""""id":"92"""") && s.contains(""""error"""") && @@ -487,6 +560,21 @@ object BuildServerTest extends AbstractServerTest { } } + private def reloadWorkspace(id: Int): Unit = + svr.sendJsonRpc( + s"""{ "jsonrpc": "2.0", "id": "$id", "method": "workspace/reload"}""" + ) + + private def compile(buildTarget: URI, id: Int): Unit = + compile(buildTarget.toString, id) + + private def compile(buildTarget: String, id: Int): Unit = + svr.sendJsonRpc( + s"""{ "jsonrpc": "2.0", "id": "$id", "method": "buildTarget/compile", "params": { + | "targets": [{ "uri": "$buildTarget" }] + |} }""".stripMargin + ) + private def buildTargetSources(id: Int, buildTargets: Seq[URI]): String = { val targets = buildTargets.map(BuildTargetIdentifier.apply).toVector request(id, "buildTarget/sources", SourcesParams(targets))