From 2bffb2731e85f0bd8a0040d26e42958295ff564d Mon Sep 17 00:00:00 2001 From: Krzysztof Pado Date: Wed, 27 Jul 2022 19:40:18 -0700 Subject: [PATCH] Add support for BSP's buildTarget/outputPaths method --- main/src/main/scala/sbt/Keys.scala | 2 ++ .../internal/server/BuildServerProtocol.scala | 22 ++++++++++++ notes/1.8.0/bsp-output-paths.md | 4 +++ .../bsp/BuildServerCapabilities.scala | 21 +++++++---- .../sbt/internal/bsp/OutputPathItem.scala | 36 +++++++++++++++++++ .../sbt/internal/bsp/OutputPathsItem.scala | 36 +++++++++++++++++++ .../sbt/internal/bsp/OutputPathsParams.scala | 33 +++++++++++++++++ .../sbt/internal/bsp/OutputPathsResult.scala | 33 +++++++++++++++++ .../BuildServerCapabilitiesFormats.scala | 4 ++- .../bsp/codec/ExcludeItemFormats.scala | 29 +++++++++++++++ .../bsp/codec/ExcludesItemFormats.scala | 29 +++++++++++++++ .../bsp/codec/ExcludesParamsFormats.scala | 27 ++++++++++++++ .../bsp/codec/ExcludesResultFormats.scala | 27 ++++++++++++++ .../sbt/internal/bsp/codec/JsonProtocol.scala | 4 +++ .../bsp/codec/OutputPathItemFormats.scala | 29 +++++++++++++++ .../bsp/codec/OutputPathsItemFormats.scala | 29 +++++++++++++++ .../bsp/codec/OutputPathsParamsFormats.scala | 27 ++++++++++++++ .../bsp/codec/OutputPathsResultFormats.scala | 27 ++++++++++++++ protocol/src/main/contraband/bsp.contra | 24 +++++++++++++ .../internal/bsp/BuildServerConnection.scala | 2 +- .../sbt/internal/bsp/OutputPathItemKind.scala | 17 +++++++++ .../src/server-test/buildserver/build.sbt | 5 ++- .../test/scala/testpkg/BuildServerTest.scala | 31 ++++++++++++++-- 23 files changed, 486 insertions(+), 12 deletions(-) create mode 100644 notes/1.8.0/bsp-output-paths.md create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathItem.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsItem.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsResult.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludeItemFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesItemFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesResultFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathItemFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsItemFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsResultFormats.scala create mode 100644 protocol/src/main/scala/sbt/internal/bsp/OutputPathItemKind.scala diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 392812271..10ae7f1b1 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -412,6 +412,8 @@ object Keys { val bspBuildTargetResourcesItem = taskKey[ResourcesItem]("").withRank(DTask) val bspBuildTargetDependencySources = inputKey[Unit]("").withRank(DTask) val bspBuildTargetDependencySourcesItem = taskKey[DependencySourcesItem]("").withRank(DTask) + val bspBuildTargetOutputPaths = inputKey[Unit]("").withRank(DTask) + val bspBuildTargetOutputPathsItem = taskKey[OutputPathsItem]("").withRank(DTask) val bspBuildTargetCompile = inputKey[Unit]("").withRank(DTask) val bspBuildTargetCompileItem = taskKey[Int]("").withRank(DTask) val bspBuildTargetTest = inputKey[Unit]("Corresponds to buildTarget/test 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 4e2abdbe8..adc0004a5 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -52,6 +52,7 @@ object BuildServerProtocol { RunProvider(BuildServerConnection.languages), dependencySourcesProvider = true, resourcesProvider = true, + outputPathsProvider = true, canReload = true, jvmRunEnvironmentProvider = true, jvmTestEnvironmentProvider = true, @@ -158,6 +159,16 @@ object BuildServerProtocol { } }.evaluated, bspBuildTargetDependencySources / aggregate := false, + bspBuildTargetOutputPaths := bspInputTask { (state, _, workspace, filter) => + Def.task { + import sbt.internal.bsp.codec.JsonProtocol._ + val items = bspBuildTargetOutputPathsItem.result.all(filter).value + val successfulItems = anyOrThrow(items) + val result = OutputPathsResult(successfulItems.toVector) + state.respondEvent(result) + } + }.evaluated, + bspBuildTargetOutputPaths / aggregate := false, bspBuildTargetCompile := bspInputTask { (state, _, workspace, filter) => workspace.warnIfBuildsNonEmpty(Method.Compile, state.log) Def.task { @@ -267,6 +278,10 @@ object BuildServerProtocol { ResourcesItem(id, uris) }, bspBuildTargetDependencySourcesItem := dependencySourcesItemTask.value, + bspBuildTargetOutputPathsItem := { + val id = bspTargetIdentifier.value + OutputPathsItem(id, Vector(OutputPathItem(target.value.toURI, OutputPathItemKind.Directory))) + }, bspBuildTargetCompileItem := bspCompileTask.value, bspBuildTargetRun := bspRunTask.evaluated, bspBuildTargetScalacOptionsItem := scalacOptionsTask.value, @@ -318,6 +333,7 @@ object BuildServerProtocol { final val Shutdown = "build/shutdown" final val Sources = "buildTarget/sources" final val Resources = "buildTarget/resources" + final val OutputPaths = "buildTarget/outputPaths" final val DependencySources = "buildTarget/dependencySources" final val Compile = "buildTarget/compile" final val Test = "buildTarget/test" @@ -453,6 +469,12 @@ object BuildServerProtocol { val targets = param.targets.map(_.uri).mkString(" ") val command = Keys.bspBuildTargetResources.key val _ = callback.appendExec(s"$command $targets", Some(r.id)) + + case r if r.method == Method.OutputPaths => + val param = Converter.fromJson[OutputPathsParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetOutputPaths.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) }, onResponse = PartialFunction.empty, onNotification = { diff --git a/notes/1.8.0/bsp-output-paths.md b/notes/1.8.0/bsp-output-paths.md new file mode 100644 index 000000000..a59adde1c --- /dev/null +++ b/notes/1.8.0/bsp-output-paths.md @@ -0,0 +1,4 @@ +[@povder]: https://github.com/povder + +### Improvements +- Add support for newly introduced `buildTarget/outputPaths` method of BSP protocol. See [bsp#269](https://github.com/build-server-protocol/build-server-protocol/pull/269) pull request and [bsp#205](https://github.com/build-server-protocol/build-server-protocol/issues/205) issue. 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 82f88a090..4d625cce9 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/BuildServerCapabilities.scala @@ -17,6 +17,7 @@ final class BuildServerCapabilities private ( val runProvider: Option[sbt.internal.bsp.RunProvider], val dependencySourcesProvider: Option[Boolean], val resourcesProvider: Option[Boolean], + val outputPathsProvider: Option[Boolean], val canReload: Option[Boolean], val jvmRunEnvironmentProvider: Option[Boolean], val jvmTestEnvironmentProvider: Option[Boolean]) extends Serializable { @@ -24,17 +25,17 @@ final class BuildServerCapabilities private ( 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) && (this.jvmRunEnvironmentProvider == x.jvmRunEnvironmentProvider) && (this.jvmTestEnvironmentProvider == x.jvmTestEnvironmentProvider) + case x: BuildServerCapabilities => (this.compileProvider == x.compileProvider) && (this.testProvider == x.testProvider) && (this.runProvider == x.runProvider) && (this.dependencySourcesProvider == x.dependencySourcesProvider) && (this.resourcesProvider == x.resourcesProvider) && (this.outputPathsProvider == x.outputPathsProvider) && (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 * (37 * (37 * (17 + "sbt.internal.bsp.BuildServerCapabilities".##) + compileProvider.##) + testProvider.##) + runProvider.##) + dependencySourcesProvider.##) + resourcesProvider.##) + canReload.##) + jvmRunEnvironmentProvider.##) + jvmTestEnvironmentProvider.##) + 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.BuildServerCapabilities".##) + compileProvider.##) + testProvider.##) + runProvider.##) + dependencySourcesProvider.##) + resourcesProvider.##) + outputPathsProvider.##) + canReload.##) + jvmRunEnvironmentProvider.##) + jvmTestEnvironmentProvider.##) } override def toString: String = { - "BuildServerCapabilities(" + compileProvider + ", " + testProvider + ", " + runProvider + ", " + dependencySourcesProvider + ", " + resourcesProvider + ", " + canReload + ", " + jvmRunEnvironmentProvider + ", " + jvmTestEnvironmentProvider + ")" + "BuildServerCapabilities(" + compileProvider + ", " + testProvider + ", " + runProvider + ", " + dependencySourcesProvider + ", " + resourcesProvider + ", " + outputPathsProvider + ", " + 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, jvmRunEnvironmentProvider: Option[Boolean] = jvmRunEnvironmentProvider, jvmTestEnvironmentProvider: Option[Boolean] = jvmTestEnvironmentProvider): BuildServerCapabilities = { - new 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, outputPathsProvider: Option[Boolean] = outputPathsProvider, canReload: Option[Boolean] = canReload, jvmRunEnvironmentProvider: Option[Boolean] = jvmRunEnvironmentProvider, jvmTestEnvironmentProvider: Option[Boolean] = jvmTestEnvironmentProvider): BuildServerCapabilities = { + new BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, outputPathsProvider, canReload, jvmRunEnvironmentProvider, jvmTestEnvironmentProvider) } def withCompileProvider(compileProvider: Option[sbt.internal.bsp.CompileProvider]): BuildServerCapabilities = { copy(compileProvider = compileProvider) @@ -66,6 +67,12 @@ final class BuildServerCapabilities private ( def withResourcesProvider(resourcesProvider: Boolean): BuildServerCapabilities = { copy(resourcesProvider = Option(resourcesProvider)) } + def withOutputPathsProvider(outputPathsProvider: Option[Boolean]): BuildServerCapabilities = { + copy(outputPathsProvider = outputPathsProvider) + } + def withOutputPathsProvider(outputPathsProvider: Boolean): BuildServerCapabilities = { + copy(outputPathsProvider = Option(outputPathsProvider)) + } def withCanReload(canReload: Option[Boolean]): BuildServerCapabilities = { copy(canReload = canReload) } @@ -87,6 +94,6 @@ final class BuildServerCapabilities private ( } 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], 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)) + 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], outputPathsProvider: Option[Boolean], canReload: Option[Boolean], jvmRunEnvironmentProvider: Option[Boolean], jvmTestEnvironmentProvider: Option[Boolean]): BuildServerCapabilities = new BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, outputPathsProvider, canReload, jvmRunEnvironmentProvider, jvmTestEnvironmentProvider) + def apply(compileProvider: sbt.internal.bsp.CompileProvider, testProvider: sbt.internal.bsp.TestProvider, runProvider: sbt.internal.bsp.RunProvider, dependencySourcesProvider: Boolean, resourcesProvider: Boolean, outputPathsProvider: Boolean, canReload: Boolean, jvmRunEnvironmentProvider: Boolean, jvmTestEnvironmentProvider: Boolean): BuildServerCapabilities = new BuildServerCapabilities(Option(compileProvider), Option(testProvider), Option(runProvider), Option(dependencySourcesProvider), Option(resourcesProvider), Option(outputPathsProvider), Option(canReload), Option(jvmRunEnvironmentProvider), Option(jvmTestEnvironmentProvider)) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathItem.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathItem.scala new file mode 100644 index 000000000..da00ff79c --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathItem.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.bsp +final class OutputPathItem private ( + val uri: java.net.URI, + val kind: Int) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: OutputPathItem => (this.uri == x.uri) && (this.kind == x.kind) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.OutputPathItem".##) + uri.##) + kind.##) + } + override def toString: String = { + "OutputPathItem(" + uri + ", " + kind + ")" + } + private[this] def copy(uri: java.net.URI = uri, kind: Int = kind): OutputPathItem = { + new OutputPathItem(uri, kind) + } + def withUri(uri: java.net.URI): OutputPathItem = { + copy(uri = uri) + } + def withKind(kind: Int): OutputPathItem = { + copy(kind = kind) + } +} +object OutputPathItem { + + def apply(uri: java.net.URI, kind: Int): OutputPathItem = new OutputPathItem(uri, kind) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsItem.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsItem.scala new file mode 100644 index 000000000..f101d7555 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsItem.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.bsp +final class OutputPathsItem private ( + val target: sbt.internal.bsp.BuildTargetIdentifier, + val outputPaths: Vector[sbt.internal.bsp.OutputPathItem]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: OutputPathsItem => (this.target == x.target) && (this.outputPaths == x.outputPaths) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.OutputPathsItem".##) + target.##) + outputPaths.##) + } + override def toString: String = { + "OutputPathsItem(" + target + ", " + outputPaths + ")" + } + private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, outputPaths: Vector[sbt.internal.bsp.OutputPathItem] = outputPaths): OutputPathsItem = { + new OutputPathsItem(target, outputPaths) + } + def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): OutputPathsItem = { + copy(target = target) + } + def withOutputPaths(outputPaths: Vector[sbt.internal.bsp.OutputPathItem]): OutputPathsItem = { + copy(outputPaths = outputPaths) + } +} +object OutputPathsItem { + + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, outputPaths: Vector[sbt.internal.bsp.OutputPathItem]): OutputPathsItem = new OutputPathsItem(target, outputPaths) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsParams.scala new file mode 100644 index 000000000..4a1d97c43 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsParams.scala @@ -0,0 +1,33 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +/** Build Target OutputPaths Request */ +final class OutputPathsParams private ( + val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: OutputPathsParams => (this.targets == x.targets) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.bsp.OutputPathsParams".##) + targets.##) + } + override def toString: String = { + "OutputPathsParams(" + targets + ")" + } + private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier] = targets): OutputPathsParams = { + new OutputPathsParams(targets) + } + def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): OutputPathsParams = { + copy(targets = targets) + } +} +object OutputPathsParams { + + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): OutputPathsParams = new OutputPathsParams(targets) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsResult.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsResult.scala new file mode 100644 index 000000000..50e2062bd --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/OutputPathsResult.scala @@ -0,0 +1,33 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +/** Build Target OutputPaths response */ +final class OutputPathsResult private ( + val items: Vector[sbt.internal.bsp.OutputPathsItem]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: OutputPathsResult => (this.items == x.items) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.bsp.OutputPathsResult".##) + items.##) + } + override def toString: String = { + "OutputPathsResult(" + items + ")" + } + private[this] def copy(items: Vector[sbt.internal.bsp.OutputPathsItem] = items): OutputPathsResult = { + new OutputPathsResult(items) + } + def withItems(items: Vector[sbt.internal.bsp.OutputPathsItem]): OutputPathsResult = { + copy(items = items) + } +} +object OutputPathsResult { + + def apply(items: Vector[sbt.internal.bsp.OutputPathsItem]): OutputPathsResult = new OutputPathsResult(items) +} 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 c23b3db80..9c8684ba3 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 @@ -16,11 +16,12 @@ implicit lazy val BuildServerCapabilitiesFormat: JsonFormat[sbt.internal.bsp.Bui val runProvider = unbuilder.readField[Option[sbt.internal.bsp.RunProvider]]("runProvider") val dependencySourcesProvider = unbuilder.readField[Option[Boolean]]("dependencySourcesProvider") val resourcesProvider = unbuilder.readField[Option[Boolean]]("resourcesProvider") + val outputPathsProvider = unbuilder.readField[Option[Boolean]]("outputPathsProvider") 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, jvmRunEnvironmentProvider, jvmTestEnvironmentProvider) + sbt.internal.bsp.BuildServerCapabilities(compileProvider, testProvider, runProvider, dependencySourcesProvider, resourcesProvider, outputPathsProvider, canReload, jvmRunEnvironmentProvider, jvmTestEnvironmentProvider) case None => deserializationError("Expected JsObject but found None") } @@ -32,6 +33,7 @@ implicit lazy val BuildServerCapabilitiesFormat: JsonFormat[sbt.internal.bsp.Bui builder.addField("runProvider", obj.runProvider) builder.addField("dependencySourcesProvider", obj.dependencySourcesProvider) builder.addField("resourcesProvider", obj.resourcesProvider) + builder.addField("outputPathsProvider", obj.outputPathsProvider) builder.addField("canReload", obj.canReload) builder.addField("jvmRunEnvironmentProvider", obj.jvmRunEnvironmentProvider) builder.addField("jvmTestEnvironmentProvider", obj.jvmTestEnvironmentProvider) diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludeItemFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludeItemFormats.scala new file mode 100644 index 000000000..6e65b8630 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludeItemFormats.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 ExcludeItemFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val ExcludeItemFormat: JsonFormat[sbt.internal.bsp.ExcludeItem] = new JsonFormat[sbt.internal.bsp.ExcludeItem] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.ExcludeItem = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val uri = unbuilder.readField[java.net.URI]("uri") + val kind = unbuilder.readField[Int]("kind") + unbuilder.endObject() + sbt.internal.bsp.ExcludeItem(uri, kind) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.ExcludeItem, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("uri", obj.uri) + builder.addField("kind", obj.kind) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesItemFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesItemFormats.scala new file mode 100644 index 000000000..cc324552f --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesItemFormats.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 ExcludesItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sbt.internal.bsp.codec.ExcludeItemFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val ExcludesItemFormat: JsonFormat[sbt.internal.bsp.ExcludesItem] = new JsonFormat[sbt.internal.bsp.ExcludesItem] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.ExcludesItem = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target") + val excludes = unbuilder.readField[Vector[sbt.internal.bsp.ExcludeItem]]("excludes") + unbuilder.endObject() + sbt.internal.bsp.ExcludesItem(target, excludes) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.ExcludesItem, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("target", obj.target) + builder.addField("excludes", obj.excludes) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesParamsFormats.scala new file mode 100644 index 000000000..f43a536c3 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesParamsFormats.scala @@ -0,0 +1,27 @@ +/** + * 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 ExcludesParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val ExcludesParamsFormat: JsonFormat[sbt.internal.bsp.ExcludesParams] = new JsonFormat[sbt.internal.bsp.ExcludesParams] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.ExcludesParams = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets") + unbuilder.endObject() + sbt.internal.bsp.ExcludesParams(targets) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.ExcludesParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("targets", obj.targets) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesResultFormats.scala new file mode 100644 index 000000000..a167af41e --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/ExcludesResultFormats.scala @@ -0,0 +1,27 @@ +/** + * 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 ExcludesResultFormats { self: sbt.internal.bsp.codec.ExcludesItemFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val ExcludesResultFormat: JsonFormat[sbt.internal.bsp.ExcludesResult] = new JsonFormat[sbt.internal.bsp.ExcludesResult] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.ExcludesResult = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val items = unbuilder.readField[Vector[sbt.internal.bsp.ExcludesItem]]("items") + unbuilder.endObject() + sbt.internal.bsp.ExcludesResult(items) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.ExcludesResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("items", obj.items) + builder.endObject() + } +} +} 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 7d26ae037..5c087e4b4 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 @@ -29,6 +29,10 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.bsp.codec.SourceItemFormats with sbt.internal.bsp.codec.SourcesItemFormats with sbt.internal.bsp.codec.SourcesResultFormats + with sbt.internal.bsp.codec.OutputPathsParamsFormats + with sbt.internal.bsp.codec.OutputPathItemFormats + with sbt.internal.bsp.codec.OutputPathsItemFormats + with sbt.internal.bsp.codec.OutputPathsResultFormats with sbt.internal.bsp.codec.DependencySourcesParamsFormats with sbt.internal.bsp.codec.DependencySourcesItemFormats with sbt.internal.bsp.codec.DependencySourcesResultFormats diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathItemFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathItemFormats.scala new file mode 100644 index 000000000..e9eba8f0e --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathItemFormats.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 OutputPathItemFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val OutputPathItemFormat: JsonFormat[sbt.internal.bsp.OutputPathItem] = new JsonFormat[sbt.internal.bsp.OutputPathItem] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.OutputPathItem = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val uri = unbuilder.readField[java.net.URI]("uri") + val kind = unbuilder.readField[Int]("kind") + unbuilder.endObject() + sbt.internal.bsp.OutputPathItem(uri, kind) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.OutputPathItem, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("uri", obj.uri) + builder.addField("kind", obj.kind) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsItemFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsItemFormats.scala new file mode 100644 index 000000000..f3c0795ee --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsItemFormats.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 OutputPathsItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sbt.internal.bsp.codec.OutputPathItemFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val OutputPathsItemFormat: JsonFormat[sbt.internal.bsp.OutputPathsItem] = new JsonFormat[sbt.internal.bsp.OutputPathsItem] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.OutputPathsItem = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target") + val outputPaths = unbuilder.readField[Vector[sbt.internal.bsp.OutputPathItem]]("outputPaths") + unbuilder.endObject() + sbt.internal.bsp.OutputPathsItem(target, outputPaths) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.OutputPathsItem, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("target", obj.target) + builder.addField("outputPaths", obj.outputPaths) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsParamsFormats.scala new file mode 100644 index 000000000..b984eeeb2 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsParamsFormats.scala @@ -0,0 +1,27 @@ +/** + * 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 OutputPathsParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val OutputPathsParamsFormat: JsonFormat[sbt.internal.bsp.OutputPathsParams] = new JsonFormat[sbt.internal.bsp.OutputPathsParams] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.OutputPathsParams = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets") + unbuilder.endObject() + sbt.internal.bsp.OutputPathsParams(targets) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.OutputPathsParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("targets", obj.targets) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsResultFormats.scala new file mode 100644 index 000000000..0aa475097 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/OutputPathsResultFormats.scala @@ -0,0 +1,27 @@ +/** + * 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 OutputPathsResultFormats { self: sbt.internal.bsp.codec.OutputPathsItemFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val OutputPathsResultFormat: JsonFormat[sbt.internal.bsp.OutputPathsResult] = new JsonFormat[sbt.internal.bsp.OutputPathsResult] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.OutputPathsResult = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val items = unbuilder.readField[Vector[sbt.internal.bsp.OutputPathsItem]]("items") + unbuilder.endObject() + sbt.internal.bsp.OutputPathsResult(items) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.OutputPathsResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("items", obj.items) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index 79734b10f..d5f0beec5 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -202,6 +202,10 @@ type BuildServerCapabilities { # via method buildTarget/resources resourcesProvider: Boolean + # The server provides output paths + # via method buildTarget/outputPaths + outputPathsProvider: Boolean + ## Reloading the workspace state through workspace/reload is supported canReload: Boolean @@ -290,6 +294,26 @@ type SourceItem { generated: Boolean! } +## Build Target OutputPaths Request +type OutputPathsParams { + targets: [sbt.internal.bsp.BuildTargetIdentifier] +} + +## Build Target OutputPaths response +type OutputPathsResult { + items: [sbt.internal.bsp.OutputPathsItem] +} + +type OutputPathsItem { + target: sbt.internal.bsp.BuildTargetIdentifier! + outputPaths: [sbt.internal.bsp.OutputPathItem] +} + +type OutputPathItem { + uri: java.net.URI! + kind: Int! +} + ## Dependency Sources Request type DependencySourcesParams { targets: [sbt.internal.bsp.BuildTargetIdentifier] diff --git a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala index fa7fce354..bdc850cd2 100644 --- a/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala +++ b/protocol/src/main/scala/sbt/internal/bsp/BuildServerConnection.scala @@ -17,7 +17,7 @@ import scala.util.Properties object BuildServerConnection { final val name = "sbt" - final val bspVersion = "2.0.0-M5" + final val bspVersion = "2.1.0-M1" final val languages = Vector("scala") private final val SbtLaunchJar = "sbt-launch(-.*)?\\.jar".r diff --git a/protocol/src/main/scala/sbt/internal/bsp/OutputPathItemKind.scala b/protocol/src/main/scala/sbt/internal/bsp/OutputPathItemKind.scala new file mode 100644 index 000000000..aaee48e65 --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/bsp/OutputPathItemKind.scala @@ -0,0 +1,17 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt.internal.bsp + +object OutputPathItemKind { + + /** The output path item references a normal file. */ + val File: Int = 1 + + /** The output path item references a directory. */ + val Directory: Int = 2 +} diff --git a/server-test/src/server-test/buildserver/build.sbt b/server-test/src/server-test/buildserver/build.sbt index fe2cf4db5..e41e0192b 100644 --- a/server-test/src/server-test/buildserver/build.sbt +++ b/server-test/src/server-test/buildserver/build.sbt @@ -30,7 +30,9 @@ lazy val respondError = project.in(file("respond-error")) } ) -lazy val util = project +lazy val util = project.settings( + Compile / target := baseDirectory.value / "custom-target", +) lazy val diagnostics = project @@ -44,6 +46,7 @@ lazy val badBuildTarget = project.in(file("bad-build-target")) Compile / bspBuildTargetDependencySourcesItem := somethingBad, Compile / bspBuildTargetScalacOptionsItem := somethingBad, Compile / bspBuildTargetCompileItem := somethingBad, + Compile / bspBuildTargetOutputPathsItem := somethingBad, Compile / bspScalaMainClasses := somethingBad, Test / bspBuildTarget := somethingBad, Test / bspScalaTestClasses := somethingBad, diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index 1b8fd06fb..aa08914f1 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -31,7 +31,8 @@ object BuildServerTest extends AbstractServerTest { initializeRequest() assert(svr.waitForString(10.seconds) { s => (s contains """"id":"8"""") && - (s contains """"resourcesProvider":true""") + (s contains """"resourcesProvider":true""") && + (s contains """"outputPathsProvider":true""") }) } @@ -538,13 +539,39 @@ object BuildServerTest extends AbstractServerTest { }) } + test("buildTarget/outputPaths") { _ => + val buildTarget = buildTargetUri("util", "Compile") + val badBuildTarget = buildTargetUri("badBuildTarget", "Compile") + svr.sendJsonRpc( + s"""{ "jsonrpc": "2.0", "id": "97", "method": "buildTarget/outputPaths", "params": { + | "targets": [{ "uri": "$buildTarget" }, { "uri": "$badBuildTarget" }] + |} }""".stripMargin + ) + assert(processing("buildTarget/outputPaths")) + val actualResult = svr.waitFor[OutputPathsResult](10.seconds) + val expectedResult = OutputPathsResult( + items = Vector( + OutputPathsItem( + target = BuildTargetIdentifier(buildTarget), + outputPaths = Vector( + OutputPathItem( + uri = new File(svr.baseDirectory, "util/custom-target").toURI, + kind = OutputPathItemKind.Directory + ) + ) + ) + ) + ) + assert(actualResult == expectedResult) + } + private def initializeRequest(): Unit = { svr.sendJsonRpc( """{ "jsonrpc": "2.0", "id": "8", "method": "build/initialize", | "params": { | "displayName": "test client", | "version": "1.0.0", - | "bspVersion": "2.0.0-M5", + | "bspVersion": "2.1.0-M1", | "rootUri": "file://root/", | "capabilities": { "languageIds": ["scala"] } | }