This commit is contained in:
Full Stack Developer 2026-04-13 09:06:06 -05:00 committed by GitHub
commit a38e5c33dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 381 additions and 0 deletions

View File

@ -479,6 +479,8 @@ object Keys {
val bspBuildTargetResourcesItem = taskKey[ResourcesItem]("").withRank(DTask)
val bspBuildTargetDependencySources = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetDependencySourcesItem = taskKey[DependencySourcesItem]("").withRank(DTask)
val bspBuildTargetDependencyModules = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetDependencyModulesItem = taskKey[DependencyModulesItem]("").withRank(DTask)
val bspBuildTargetOutputPaths = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetOutputPathsItem = taskKey[OutputPathsItem]("").withRank(DTask)
val bspBuildTargetCompile = inputKey[Unit]("").withRank(DTask)

View File

@ -166,6 +166,21 @@ object BuildServerProtocol {
state.value.respondEvent(result)
}.evaluated,
bspBuildTargetDependencySources / aggregate := false,
bspBuildTargetDependencyModules := bspInputTask { (workspace, filter) =>
val items = bspBuildTargetDependencyModulesItem.result.all(filter).value
val successfulItems = anyOrThrow(items)
val buildItems = workspace.builds
.map { case (targetId, loadedBuildUnit) =>
val projRef = ProjectRef(loadedBuildUnit.unit.uri, loadedBuildUnit.root)
(projRef / updateSbtClassifiers).map(getDependencyModulesItem(targetId, _))
}
.toSeq
.join
.value
val result = DependencyModulesResult((successfulItems ++ buildItems).toVector)
state.value.respondEvent(result)
}.evaluated,
bspBuildTargetDependencyModules / aggregate := false,
bspBuildTargetCompile := bspInputTask { (workspace, filter) =>
val s = state.value
workspace.warnIfBuildsNonEmpty(Method.Compile, s.log)
@ -306,6 +321,7 @@ object BuildServerProtocol {
ResourcesItem(id, uris)
},
bspBuildTargetDependencySourcesItem := dependencySourcesItemTask.value,
bspBuildTargetDependencyModulesItem := dependencyModulesItemTask.value,
bspBuildTargetOutputPathsItem := {
val id = bspTargetIdentifier.value
OutputPathsItem(id, Vector(OutputPathItem(target.value.toURI, OutputPathItemKind.Directory)))
@ -374,6 +390,7 @@ object BuildServerProtocol {
final val Resources = "buildTarget/resources"
final val OutputPaths = "buildTarget/outputPaths"
final val DependencySources = "buildTarget/dependencySources"
final val DependencyModules = "buildTarget/dependencyModules"
final val Compile = "buildTarget/compile"
final val Test = "buildTarget/test"
final val Run = "buildTarget/run"
@ -439,6 +456,12 @@ object BuildServerProtocol {
val command = Keys.bspBuildTargetDependencySources.key
val _ = callback.appendExec(s"$command $targets", Some(r.id))
case r if r.method == Method.DependencyModules =>
val param = Converter.fromJson[DependencyModulesParams](json(r)).get
val targets = param.targets.map(_.uri).mkString(" ")
val command = Keys.bspBuildTargetDependencyModules.key
val _ = callback.appendExec(s"$command $targets", Some(r.id))
case r if r.method == Method.Compile =>
val param = Converter.fromJson[CompileParams](json(r)).get
val targets = param.targets.map(_.uri).mkString(" ")
@ -856,6 +879,13 @@ object BuildServerProtocol {
)
}
private def dependencyModulesItemTask: Def.Initialize[Task[DependencyModulesItem]] = Def.task {
getDependencyModulesItem(
Keys.bspTargetIdentifier.value,
Keys.updateClassifiers.value
)
}
private def getDependencySourceItem(
targetId: BuildTargetIdentifier,
updateReport: UpdateReport
@ -869,6 +899,25 @@ object BuildServerProtocol {
DependencySourcesItem(targetId, sources.toVector.distinct)
}
private def getDependencyModulesItem(
targetId: BuildTargetIdentifier,
updateReport: UpdateReport
): DependencyModulesItem = {
val modules = for {
configuration <- updateReport.configurations.view
module <- configuration.modules.view
} yield {
val moduleId = module.module
DependencyModule(
name = s"${moduleId.organization}:${moduleId.name}",
version = moduleId.revision,
dataKind = None,
data = None,
)
}
DependencyModulesItem(targetId, modules.toVector.distinct)
}
private def bspCompileState: Initialize[BuildServerProtocol.BspCompileState] = Def.setting {
new BuildServerProtocol.BspCompileState()
}

View File

@ -0,0 +1,57 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* @param name Module name
* @param version Module version
* @param dataKind Kind of data to expect in the `data` field.
* @param data Language-specific metadata about this module.
*/
final class DependencyModule private (
val name: String,
val version: String,
val dataKind: Option[String],
val data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: DependencyModule => (this.name == x.name) && (this.version == x.version) && (this.dataKind == x.dataKind) && (this.data == x.data)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.DependencyModule".##) + name.##) + version.##) + dataKind.##) + data.##)
}
override def toString: String = {
"DependencyModule(" + name + ", " + version + ", " + dataKind + ", " + data + ")"
}
private def copy(name: String = name, version: String = version, dataKind: Option[String] = dataKind, data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = data): DependencyModule = {
new DependencyModule(name, version, dataKind, data)
}
def withName(name: String): DependencyModule = {
copy(name = name)
}
def withVersion(version: String): DependencyModule = {
copy(version = version)
}
def withDataKind(dataKind: Option[String]): DependencyModule = {
copy(dataKind = dataKind)
}
def withDataKind(dataKind: String): DependencyModule = {
copy(dataKind = Option(dataKind))
}
def withData(data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): DependencyModule = {
copy(data = data)
}
def withData(data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): DependencyModule = {
copy(data = Option(data))
}
}
object DependencyModule {
def apply(name: String, version: String, dataKind: Option[String], data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): DependencyModule = new DependencyModule(name, version, dataKind, data)
def apply(name: String, version: String, dataKind: String, data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): DependencyModule = new DependencyModule(name, version, Option(dataKind), Option(data))
}

View File

@ -0,0 +1,40 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
final class DependencyModulesItem private (
val target: Option[sbt.internal.bsp.BuildTargetIdentifier],
val modules: Vector[sbt.internal.bsp.DependencyModule]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: DependencyModulesItem => (this.target == x.target) && (this.modules == x.modules)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesItem".##) + target.##) + modules.##)
}
override def toString: String = {
"DependencyModulesItem(" + target + ", " + modules + ")"
}
private def copy(target: Option[sbt.internal.bsp.BuildTargetIdentifier] = target, modules: Vector[sbt.internal.bsp.DependencyModule] = modules): DependencyModulesItem = {
new DependencyModulesItem(target, modules)
}
def withTarget(target: Option[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesItem = {
copy(target = target)
}
def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): DependencyModulesItem = {
copy(target = Option(target))
}
def withModules(modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = {
copy(modules = modules)
}
}
object DependencyModulesItem {
def apply(target: Option[sbt.internal.bsp.BuildTargetIdentifier], modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = new DependencyModulesItem(target, modules)
def apply(target: sbt.internal.bsp.BuildTargetIdentifier, modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = new DependencyModulesItem(Option(target), modules)
}

View File

@ -0,0 +1,33 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/** Dependency Modules Request */
final class DependencyModulesParams 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: DependencyModulesParams => (this.targets == x.targets)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesParams".##) + targets.##)
}
override def toString: String = {
"DependencyModulesParams(" + targets + ")"
}
private def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = {
new DependencyModulesParams(targets)
}
def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = {
copy(targets = targets)
}
}
object DependencyModulesParams {
def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = new DependencyModulesParams(targets)
}

View File

@ -0,0 +1,33 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/** Dependency Modules Result */
final class DependencyModulesResult private (
val items: Vector[sbt.internal.bsp.DependencyModulesItem]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: DependencyModulesResult => (this.items == x.items)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesResult".##) + items.##)
}
override def toString: String = {
"DependencyModulesResult(" + items + ")"
}
private def copy(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = {
new DependencyModulesResult(items)
}
def withItems(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = {
copy(items = items)
}
}
object DependencyModulesResult {
def apply(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = new DependencyModulesResult(items)
}

View File

@ -0,0 +1,33 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DependencyModuleFormats { self: sbt.internal.util.codec.JValueFormats & sjsonnew.BasicJsonProtocol =>
given DependencyModuleFormat: JsonFormat[sbt.internal.bsp.DependencyModule] = new JsonFormat[sbt.internal.bsp.DependencyModule] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModule = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val name = unbuilder.readField[String]("name")
val version = unbuilder.readField[String]("version")
val dataKind = unbuilder.readField[Option[String]]("dataKind")
val data = unbuilder.readField[Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]]("data")
unbuilder.endObject()
sbt.internal.bsp.DependencyModule(name, version, dataKind, data)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DependencyModule, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("name", obj.name)
builder.addField("version", obj.version)
builder.addField("dataKind", obj.dataKind)
builder.addField("data", obj.data)
builder.endObject()
}
}
}

View File

@ -0,0 +1,29 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DependencyModulesItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol & sbt.internal.bsp.codec.DependencyModuleFormats & sbt.internal.util.codec.JValueFormats =>
given DependencyModulesItemFormat: JsonFormat[sbt.internal.bsp.DependencyModulesItem] = new JsonFormat[sbt.internal.bsp.DependencyModulesItem] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesItem = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val target = unbuilder.readField[Option[sbt.internal.bsp.BuildTargetIdentifier]]("target")
val modules = unbuilder.readField[Vector[sbt.internal.bsp.DependencyModule]]("modules")
unbuilder.endObject()
sbt.internal.bsp.DependencyModulesItem(target, modules)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DependencyModulesItem, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("target", obj.target)
builder.addField("modules", obj.modules)
builder.endObject()
}
}
}

View File

@ -0,0 +1,27 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DependencyModulesParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol =>
given DependencyModulesParamsFormat: JsonFormat[sbt.internal.bsp.DependencyModulesParams] = new JsonFormat[sbt.internal.bsp.DependencyModulesParams] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesParams = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets")
unbuilder.endObject()
sbt.internal.bsp.DependencyModulesParams(targets)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DependencyModulesParams, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("targets", obj.targets)
builder.endObject()
}
}
}

View File

@ -0,0 +1,27 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DependencyModulesResultFormats { self: sbt.internal.bsp.codec.DependencyModulesItemFormats & sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol & sbt.internal.bsp.codec.DependencyModuleFormats & sbt.internal.util.codec.JValueFormats =>
given DependencyModulesResultFormat: JsonFormat[sbt.internal.bsp.DependencyModulesResult] = new JsonFormat[sbt.internal.bsp.DependencyModulesResult] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesResult = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val items = unbuilder.readField[Vector[sbt.internal.bsp.DependencyModulesItem]]("items")
unbuilder.endObject()
sbt.internal.bsp.DependencyModulesResult(items)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.DependencyModulesResult, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("items", obj.items)
builder.endObject()
}
}
}

View File

@ -43,6 +43,10 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
with sbt.internal.bsp.codec.DependencySourcesParamsFormats
with sbt.internal.bsp.codec.DependencySourcesItemFormats
with sbt.internal.bsp.codec.DependencySourcesResultFormats
with sbt.internal.bsp.codec.DependencyModulesParamsFormats
with sbt.internal.bsp.codec.DependencyModuleFormats
with sbt.internal.bsp.codec.DependencyModulesItemFormats
with sbt.internal.bsp.codec.DependencyModulesResultFormats
with sbt.internal.bsp.codec.TaskStartParamsFormats
with sbt.internal.bsp.codec.TaskProgressParamsFormats
with sbt.internal.bsp.codec.TaskFinishParamsFormats

View File

@ -409,6 +409,35 @@ type DependencySourcesItem {
sources: [java.net.URI]
}
## Dependency Modules Request
type DependencyModulesParams {
targets: [sbt.internal.bsp.BuildTargetIdentifier]
}
## Dependency Modules Result
type DependencyModulesResult {
items: [sbt.internal.bsp.DependencyModulesItem]
}
type DependencyModulesItem {
target: sbt.internal.bsp.BuildTargetIdentifier
modules: [sbt.internal.bsp.DependencyModule]
}
type DependencyModule {
## Module name
name: String!
## Module version
version: String!
## Kind of data to expect in the `data` field.
dataKind: String
## Language-specific metadata about this module.
data: sjsonnew.shaded.scalajson.ast.unsafe.JValue
}
## Task Notifications
type TaskStartParams {

View File

@ -524,6 +524,19 @@ class BuildServerTest extends AbstractServerTest {
)
}
test("buildTarget/dependencyModules") {
val buildTarget = buildTargetUri("util", "Compile")
val badBuildTarget = buildTargetUri("badBuildTarget", "Compile")
val targets = Vector(buildTarget, badBuildTarget).map(BuildTargetIdentifier.apply)
val id = dependencyModules(targets.map(_.uri))
val res = svr.session.waitForResultInResponseMsg[DependencyModulesResult](10.seconds, id).get
val utilItem = res.items.find(_.target == BuildTargetIdentifier(buildTarget)).get
assert(
utilItem.modules.exists(_.name.contains("jsoniter-scala-core")),
s"dependencyModules should include jsoniter-scala-core, got: ${utilItem.modules.map(_.name)}"
)
}
test("buildTarget/outputPaths") {
val buildTarget = buildTargetUri("util", "Compile")
val badBuildTarget = buildTargetUri("badBuildTarget", "Compile")
@ -753,6 +766,11 @@ class BuildServerTest extends AbstractServerTest {
sendRequest("buildTarget/sources", SourcesParams(targets))
}
private def dependencyModules(buildTargets: Seq[URI]): String = {
val targets = buildTargets.map(BuildTargetIdentifier.apply).toVector
sendRequest("buildTarget/dependencyModules", DependencyModulesParams(targets))
}
private def sendRequest(method: String): String = {
val id = svr.session.nextId()
svr.session.sendJsonRpc(id, method, "{}").get