Implement buildTarget/javacOptions

This commit is contained in:
Adrien Piquerez 2023-08-10 16:11:28 +02:00
parent e3b7870b2d
commit 5515619ecc
14 changed files with 423 additions and 129 deletions

View File

@ -148,18 +148,20 @@ final case class PluginData(
resolvers: Option[Vector[Resolver]],
report: Option[UpdateReport],
scalacOptions: Seq[String],
javacOptions: Seq[String],
unmanagedSourceDirectories: Seq[File],
unmanagedSources: Seq[File],
managedSourceDirectories: Seq[File],
managedSources: Seq[File],
classDirectory: Option[File],
buildTarget: Option[BuildTargetIdentifier]
) {
val classpath: Seq[Attributed[File]] = definitionClasspath ++ dependencyClasspath
}
object PluginData {
private[sbt] def apply(dependencyClasspath: Def.Classpath): PluginData =
PluginData(dependencyClasspath, Nil, None, None, Nil, Nil, Nil, Nil, Nil, None)
private[sbt] def apply(depClasspath: Def.Classpath): PluginData =
PluginData(depClasspath, Nil, None, None, Nil, Nil, Nil, Nil, Nil, Nil, None, None)
}
object EvaluateTask {

View File

@ -419,19 +419,21 @@ object Keys {
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)
val bspBuildTargetRun = inputKey[Unit]("Corresponds to buildTarget/run request").withRank(DTask)
val bspBuildTargetCleanCache = inputKey[Unit]("Corresponds to buildTarget/cleanCache request").withRank(DTask)
val bspBuildTargetTest = inputKey[Unit]("Implementation of buildTarget/test").withRank(DTask)
val bspBuildTargetRun = inputKey[Unit]("Implementation of buildTarget/run").withRank(DTask)
val bspBuildTargetCleanCache = inputKey[Unit]("Implementation of buildTarget/cleanCache").withRank(DTask)
val bspBuildTargetScalacOptions = inputKey[Unit]("").withRank(DTask)
val bspBuildTargetScalacOptionsItem = taskKey[ScalacOptionsItem]("").withRank(DTask)
val bspBuildTargetJavacOptions = inputKey[Unit]("Implementation of buildTarget/javacOptions").withRank(DTask)
val bspBuildTargetJavacOptionsItem = taskKey[JavacOptionsItem]("Item of buildTarget/javacOptions").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 bspBuildTargetJVMRunEnvironment = inputKey[Unit]("Implementation of buildTarget/jvmRunEnvironment").withRank(DTask)
val bspBuildTargetJVMTestEnvironment = inputKey[Unit]("Implementation of buildTarget/jvmTestEnvironment").withRank(DTask)
val bspBuildTargetJvmEnvironmentItem = taskKey[JvmEnvironmentItem]("Computes JVM environment item").withRank(DTask)
val bspScalaTestClasses = inputKey[Unit]("Corresponds to buildTarget/scalaTestClasses request").withRank(DTask)
val bspScalaTestClasses = inputKey[Unit]("Implementation of buildTarget/scalaTestClasses").withRank(DTask)
val bspScalaTestClassesItem = taskKey[Seq[ScalaTestClassesItem]]("").withRank(DTask)
val bspScalaMainClasses = inputKey[Unit]("Corresponds to buildTarget/scalaMainClasses request").withRank(DTask)
val bspScalaMainClasses = inputKey[Unit]("Implementation of buildTarget/scalaMainClasses").withRank(DTask)
val bspScalaMainClassesItem = taskKey[ScalaMainClassesItem]("").withRank(DTask)
val bspReporter = taskKey[BuildServerReporter]("").withRank(DTask)

View File

@ -1176,21 +1176,25 @@ private[sbt] object Load {
val prod = (Configurations.Runtime / exportedProducts).value
val cp = (Configurations.Runtime / fullClasspath).value
val opts = (Configurations.Compile / scalacOptions).value
val javaOpts = (Configurations.Compile / javacOptions).value
val unmanagedSrcDirs = (Configurations.Compile / unmanagedSourceDirectories).value
val unmanagedSrcs = (Configurations.Compile / unmanagedSources).value
val managedSrcDirs = (Configurations.Compile / managedSourceDirectories).value
val managedSrcs = (Configurations.Compile / managedSources).value
val buildTarget = (Configurations.Compile / bspTargetIdentifier).value
val clsDir = (Configurations.Compile / classDirectory).value
PluginData(
removeEntries(cp, prod),
prod,
Some(fullResolvers.value.toVector),
Some(update.value),
opts,
javaOpts,
unmanagedSrcDirs,
unmanagedSrcs,
managedSrcDirs,
managedSrcs,
Some(clsDir),
Some(buildTarget)
)
},
@ -1244,11 +1248,7 @@ private[sbt] object Load {
}
def noPlugins(dir: File, config: LoadBuildConfiguration): LoadedPlugins =
loadPluginDefinition(
dir,
config,
PluginData(config.globalPluginClasspath, Nil, None, None, Nil, Nil, Nil, Nil, Nil, None)
)
loadPluginDefinition(dir, config, PluginData(config.globalPluginClasspath))
def buildPlugins(dir: File, s: State, config: LoadBuildConfiguration): LoadedPlugins =
loadPluginDefinition(dir, config, buildPluginDefinition(dir, s, config))
@ -1444,6 +1444,8 @@ final case class LoadBuildConfiguration(
Nil,
Nil,
Nil,
Nil,
None,
None
)
case None => PluginData(globalPluginClasspath)

View File

@ -201,24 +201,12 @@ object BuildServerProtocol {
}.evaluated,
bspBuildTargetCleanCache / aggregate := false,
bspBuildTargetScalacOptions := bspInputTask { (state, _, workspace, filter) =>
val builds = workspace.builds
Def.task {
val items = bspBuildTargetScalacOptionsItem.result.all(filter).value
val appProvider = appConfiguration.value.provider()
val sbtJars = appProvider.mainClasspath()
val buildItems = builds.map {
build =>
val plugins: LoadedPlugins = build._2.unit.plugins
val scalacOptions = plugins.pluginData.scalacOptions
val pluginClassPath = plugins.classpath
val classpath = (pluginClassPath ++ sbtJars).map(_.toURI).toVector
val item = ScalacOptionsItem(
build._1,
scalacOptions.toVector,
classpath,
new File(build._2.localBase, "project/target").toURI
)
Value(item)
val buildItems = workspace.builds.map {
case (targetId, build) => Value(scalacOptionsBuildItem(sbtJars, targetId, build))
}
val successfulItems = anyOrThrow(items ++ buildItems)
val result = ScalacOptionsResult(successfulItems.toVector)
@ -226,6 +214,20 @@ object BuildServerProtocol {
}
}.evaluated,
bspBuildTargetScalacOptions / aggregate := false,
bspBuildTargetJavacOptions := bspInputTask { (state, _, workspace, filter) =>
Def.task {
val items = bspBuildTargetJavacOptionsItem.result.all(filter).value
val appProvider = appConfiguration.value.provider()
val sbtJars = appProvider.mainClasspath()
val buildItems = workspace.builds.map {
case (targetId, build) => Value(javacOptionsBuildItem(sbtJars, targetId, build))
}
val successfulItems = anyOrThrow(items ++ buildItems)
val result = JavacOptionsResult(successfulItems.toVector)
state.respondEvent(result)
}
}.evaluated,
bspBuildTargetJavacOptions / aggregate := false,
bspScalaTestClasses := bspInputTask { (state, _, workspace, filter) =>
workspace.warnIfBuildsNonEmpty(Method.ScalaTestClasses, state.log)
Def.task {
@ -286,7 +288,20 @@ object BuildServerProtocol {
},
bspBuildTargetCompileItem := bspCompileTask.value,
bspBuildTargetRun := bspRunTask.evaluated,
bspBuildTargetScalacOptionsItem := scalacOptionsTask.value,
bspBuildTargetScalacOptionsItem := {
val target = Keys.bspTargetIdentifier.value
val scalacOptions = Keys.scalacOptions.value.toVector
val classDirectory = Keys.classDirectory.value
val classpath = classpathTask.value
ScalacOptionsItem(target, scalacOptions, classpath, classDirectory.toURI)
},
bspBuildTargetJavacOptionsItem := {
val target = Keys.bspTargetIdentifier.value
val javacOptions = Keys.javacOptions.value.toVector
val classDirectory = Keys.classDirectory.value
val classpath = classpathTask.value
JavacOptionsItem(target, javacOptions, classpath, classDirectory.toURI)
},
bspBuildTargetJVMRunEnvironment := bspInputTask { (state, _, _, filter) =>
Def.task {
val items = bspBuildTargetJvmEnvironmentItem.result.all(filter).value
@ -328,7 +343,7 @@ object BuildServerProtocol {
}
}
)
private object Method {
private[sbt] object Method {
final val Initialize = "build/initialize"
final val BuildTargets = "workspace/buildTargets"
final val Reload = "workspace/reload"
@ -665,6 +680,34 @@ object BuildServerProtocol {
)
}
private def scalacOptionsBuildItem(
sbtJars: Seq[File],
targetId: BuildTargetIdentifier,
build: LoadedBuildUnit
): ScalacOptionsItem = {
val plugins: LoadedPlugins = build.unit.plugins
val scalacOptions = plugins.pluginData.scalacOptions.toVector
val pluginClassPath = plugins.classpath
val classpath = (pluginClassPath ++ sbtJars).map(_.toURI).toVector
val classDirectory = plugins.pluginData.classDirectory.map(_.toURI)
val item = ScalacOptionsItem(targetId, scalacOptions, classpath, classDirectory)
item
}
private def javacOptionsBuildItem(
sbtJars: Seq[File],
targetId: BuildTargetIdentifier,
build: LoadedBuildUnit
): JavacOptionsItem = {
val plugins: LoadedPlugins = build.unit.plugins
val javacOptions = plugins.pluginData.javacOptions.toVector
val pluginClassPath = plugins.classpath
val classpath = (pluginClassPath ++ sbtJars).map(_.toURI).toVector
val classDirectory = plugins.pluginData.classDirectory.map(_.toURI)
val item = JavacOptionsItem(targetId, javacOptions, classpath, classDirectory)
item
}
private def bspInputTask[T](
taskImpl: (
State,
@ -697,26 +740,17 @@ object BuildServerProtocol {
)
}
private def scalacOptionsTask: Def.Initialize[Task[ScalacOptionsItem]] = Def.taskDyn {
val target = Keys.bspTargetIdentifier.value
val scalacOptions = Keys.scalacOptions.value
val classDirectory = Keys.classDirectory.value
private lazy val classpathTask: Def.Initialize[Task[Vector[URI]]] = Def.taskDyn {
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)
ScalacOptionsItem(
target,
scalacOptions.toVector,
classpath.map(_.toURI).toVector,
classDirectory.toURI
)
classpath.map(_.toURI).toVector
}
}

View File

@ -115,7 +115,7 @@ object FakeState {
Nil
)
val pluginData = PluginData(Nil, Nil, None, None, Nil, Nil, Nil, Nil, Nil, None)
val pluginData = PluginData(Nil, Nil, None, None, Nil, Nil, Nil, Nil, Nil, Nil, None, None)
val builds: DetectedModules[BuildDef] = new DetectedModules[BuildDef](Nil)
val detectedAutoPlugins: Seq[DetectedAutoPlugin] =

View File

@ -0,0 +1,57 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* @param options Additional arguments to the compiler.
For example, -deprecation.
* @param classpath The dependency classpath for this target, must be
identical to what is passed as arguments to
the -classpath flag in the command line interface
of scalac.
* @param classDirectory The output directory for classfiles produced by this target
*/
final class JavacOptionsItem private (
val target: sbt.internal.bsp.BuildTargetIdentifier,
val options: Vector[String],
val classpath: Vector[java.net.URI],
val classDirectory: Option[java.net.URI]) extends Serializable {
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
case x: JavacOptionsItem => (this.target == x.target) && (this.options == x.options) && (this.classpath == x.classpath) && (this.classDirectory == x.classDirectory)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.JavacOptionsItem".##) + target.##) + options.##) + classpath.##) + classDirectory.##)
}
override def toString: String = {
"JavacOptionsItem(" + target + ", " + options + ", " + classpath + ", " + classDirectory + ")"
}
private[this] def copy(target: sbt.internal.bsp.BuildTargetIdentifier = target, options: Vector[String] = options, classpath: Vector[java.net.URI] = classpath, classDirectory: Option[java.net.URI] = classDirectory): JavacOptionsItem = {
new JavacOptionsItem(target, options, classpath, classDirectory)
}
def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): JavacOptionsItem = {
copy(target = target)
}
def withOptions(options: Vector[String]): JavacOptionsItem = {
copy(options = options)
}
def withClasspath(classpath: Vector[java.net.URI]): JavacOptionsItem = {
copy(classpath = classpath)
}
def withClassDirectory(classDirectory: Option[java.net.URI]): JavacOptionsItem = {
copy(classDirectory = classDirectory)
}
def withClassDirectory(classDirectory: java.net.URI): JavacOptionsItem = {
copy(classDirectory = Option(classDirectory))
}
}
object JavacOptionsItem {
def apply(target: sbt.internal.bsp.BuildTargetIdentifier, options: Vector[String], classpath: Vector[java.net.URI], classDirectory: Option[java.net.URI]): JavacOptionsItem = new JavacOptionsItem(target, options, classpath, classDirectory)
def apply(target: sbt.internal.bsp.BuildTargetIdentifier, options: Vector[String], classpath: Vector[java.net.URI], classDirectory: java.net.URI): JavacOptionsItem = new JavacOptionsItem(target, options, classpath, Option(classDirectory))
}

View File

@ -0,0 +1,37 @@
/**
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp
/**
* Javac options
* The build target javac options request is sent from the client to the server
* to query for the list of compiler options necessary to compile in a given list of targets.
*/
final class JavacOptionsParams 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: JavacOptionsParams => (this.targets == x.targets)
case _ => false
})
override def hashCode: Int = {
37 * (37 * (17 + "sbt.internal.bsp.JavacOptionsParams".##) + targets.##)
}
override def toString: String = {
"JavacOptionsParams(" + targets + ")"
}
private[this] def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier] = targets): JavacOptionsParams = {
new JavacOptionsParams(targets)
}
def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): JavacOptionsParams = {
copy(targets = targets)
}
}
object JavacOptionsParams {
def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): JavacOptionsParams = new JavacOptionsParams(targets)
}

View File

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

View File

@ -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.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait JavacOptionsItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val JavacOptionsItemFormat: JsonFormat[sbt.internal.bsp.JavacOptionsItem] = new JsonFormat[sbt.internal.bsp.JavacOptionsItem] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JavacOptionsItem = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val target = unbuilder.readField[sbt.internal.bsp.BuildTargetIdentifier]("target")
val options = unbuilder.readField[Vector[String]]("options")
val classpath = unbuilder.readField[Vector[java.net.URI]]("classpath")
val classDirectory = unbuilder.readField[Option[java.net.URI]]("classDirectory")
unbuilder.endObject()
sbt.internal.bsp.JavacOptionsItem(target, options, classpath, classDirectory)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.JavacOptionsItem, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("target", obj.target)
builder.addField("options", obj.options)
builder.addField("classpath", obj.classpath)
builder.addField("classDirectory", obj.classDirectory)
builder.endObject()
}
}
}

View File

@ -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 JavacOptionsParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val JavacOptionsParamsFormat: JsonFormat[sbt.internal.bsp.JavacOptionsParams] = new JsonFormat[sbt.internal.bsp.JavacOptionsParams] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JavacOptionsParams = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets")
unbuilder.endObject()
sbt.internal.bsp.JavacOptionsParams(targets)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.JavacOptionsParams, 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/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt.internal.bsp.codec
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait JavacOptionsResultFormats { self: sbt.internal.bsp.codec.JavacOptionsItemFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val JavacOptionsResultFormat: JsonFormat[sbt.internal.bsp.JavacOptionsResult] = new JsonFormat[sbt.internal.bsp.JavacOptionsResult] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.JavacOptionsResult = {
__jsOpt match {
case Some(__js) =>
unbuilder.beginObject(__js)
val items = unbuilder.readField[Vector[sbt.internal.bsp.JavacOptionsItem]]("items")
unbuilder.endObject()
sbt.internal.bsp.JavacOptionsResult(items)
case None =>
deserializationError("Expected JsObject but found None")
}
}
override def write[J](obj: sbt.internal.bsp.JavacOptionsResult, builder: Builder[J]): Unit = {
builder.beginObject()
builder.addField("items", obj.items)
builder.endObject()
}
}
}

View File

@ -56,10 +56,13 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
with sbt.internal.bsp.codec.RunParamsFormats
with sbt.internal.bsp.codec.RunResultFormats
with sbt.internal.bsp.codec.ScalaBuildTargetFormats
with sbt.internal.bsp.codec.SbtBuildTargetFormats
with sbt.internal.bsp.codec.ScalacOptionsParamsFormats
with sbt.internal.bsp.codec.ScalacOptionsItemFormats
with sbt.internal.bsp.codec.ScalacOptionsResultFormats
with sbt.internal.bsp.codec.JavacOptionsParamsFormats
with sbt.internal.bsp.codec.JavacOptionsItemFormats
with sbt.internal.bsp.codec.JavacOptionsResultFormats
with sbt.internal.bsp.codec.SbtBuildTargetFormats
with sbt.internal.bsp.codec.BspConnectionDetailsFormats
with sbt.internal.bsp.codec.MetalsMetadataFormats
with sbt.internal.bsp.codec.ScalaTestClassesItemFormats

View File

@ -625,31 +625,6 @@ type ScalaBuildTarget {
jars: [String]!
}
# sbt Extension
## Contains sbt-specific metadata for providing editor support for sbt build files.
## This metadata is embedded in the data: Option[Json] field of the BuildTarget definition
## when the dataKind field contains "sbt".
type SbtBuildTarget {
## The sbt version. Useful to support version-dependent syntax.
sbtVersion: String!
## A sequence of Scala imports that are automatically imported in the sbt build files.
autoImports: [String]!
## The Scala build target describing the scala
## version and scala jars used by this sbt version.
scalaBuildTarget: sbt.internal.bsp.ScalaBuildTarget!
## An optional parent if the target has an sbt meta project.
parent: sbt.internal.bsp.BuildTargetIdentifier
## The inverse of parent, list of targets that have this build target
## defined as their parent. It can contain normal project targets or
## sbt build targets if this target represents an sbt meta-meta build.
children: [sbt.internal.bsp.BuildTargetIdentifier]!
}
## Scalac options
## The build target scalac options request is sent from the client to the server
## to query for the list of compiler options necessary to compile in a given list of targets.
@ -678,6 +653,61 @@ type ScalacOptionsItem {
classDirectory: java.net.URI
}
# Java Extension
## Javac options
## The build target javac options request is sent from the client to the server
## to query for the list of compiler options necessary to compile in a given list of targets.
type JavacOptionsParams {
targets: [sbt.internal.bsp.BuildTargetIdentifier]
}
type JavacOptionsResult {
items: [sbt.internal.bsp.JavacOptionsItem]
}
type JavacOptionsItem {
target: sbt.internal.bsp.BuildTargetIdentifier!
## Additional arguments to the compiler.
## For example, -deprecation.
options: [String]
## The dependency classpath for this target, must be
## identical to what is passed as arguments to
## the -classpath flag in the command line interface
## of scalac.
classpath: [java.net.URI]
## The output directory for classfiles produced by this target
classDirectory: java.net.URI
}
# sbt Extension
## Contains sbt-specific metadata for providing editor support for sbt build files.
## This metadata is embedded in the data: Option[Json] field of the BuildTarget definition
## when the dataKind field contains "sbt".
type SbtBuildTarget {
## The sbt version. Useful to support version-dependent syntax.
sbtVersion: String!
## A sequence of Scala imports that are automatically imported in the sbt build files.
autoImports: [String]!
## The Scala build target describing the scala
## version and scala jars used by this sbt version.
scalaBuildTarget: sbt.internal.bsp.ScalaBuildTarget!
## An optional parent if the target has an sbt meta project.
parent: sbt.internal.bsp.BuildTargetIdentifier
## The inverse of parent, list of targets that have this build target
## defined as their parent. It can contain normal project targets or
## sbt build targets if this target represents an sbt meta-meta build.
children: [sbt.internal.bsp.BuildTargetIdentifier]!
}
## https://build-server-protocol.github.io/docs/server-discovery.html
type BspConnectionDetails {
## The name of the build tool

View File

@ -32,8 +32,7 @@ object BuildServerTest extends AbstractServerTest {
private def nextId(): Int = idGen.getAndIncrement()
test("build/initialize") { _ =>
val id = nextId()
initializeRequest(id)
val id = initializeRequest()
assert(svr.waitForString(10.seconds) { s =>
(s contains s""""id":"${id}"""") &&
(s contains """"resourcesProvider":true""") &&
@ -42,10 +41,7 @@ object BuildServerTest extends AbstractServerTest {
}
test("workspace/buildTargets") { _ =>
svr.sendJsonRpc(
s"""{ "jsonrpc": "2.0", "id": "${nextId()}", "method": "workspace/buildTargets", "params": {} }"""
)
assert(processing("workspace/buildTargets"))
sendRequest("workspace/buildTargets")
val result = svr.waitFor[WorkspaceBuildTargetsResult](10.seconds)
val utilTarget = result.targets.find(_.displayName.contains("util")).get
assert(utilTarget.id.uri.toString.endsWith("#util/Compile"))
@ -58,16 +54,14 @@ object BuildServerTest extends AbstractServerTest {
test("buildTarget/sources") { _ =>
val buildTarget = buildTargetUri("util", "Compile")
val badBuildTarget = buildTargetUri("badBuildTarget", "Compile")
svr.sendJsonRpc(buildTargetSources(Seq(buildTarget, badBuildTarget)))
assert(processing("buildTarget/sources"))
buildTargetSources(Seq(buildTarget, badBuildTarget))
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: base sources") { _ =>
val buildTarget = buildTargetUri("buildserver", "Compile")
svr.sendJsonRpc(buildTargetSources(Seq(buildTarget)))
assert(processing("buildTarget/sources"))
buildTargetSources(Seq(buildTarget))
val s = svr.waitFor[SourcesResult](10.seconds)
val sources = s.items.head.sources
val expectedSource = SourceItem(
@ -80,8 +74,7 @@ object BuildServerTest extends AbstractServerTest {
test("buildTarget/sources: sbt") { _ =>
val x = new URI(s"${svr.baseDirectory.getAbsoluteFile.toURI}#buildserver-build")
svr.sendJsonRpc(buildTargetSources(Seq(x)))
assert(processing("buildTarget/sources"))
buildTargetSources(Seq(x))
val s = svr.waitFor[SourcesResult](10.seconds)
val sources = s.items.head.sources.map(_.uri).sorted
val expectedSources = Vector(
@ -99,17 +92,13 @@ object BuildServerTest extends AbstractServerTest {
test("buildTarget/compile") { _ =>
val buildTarget = buildTargetUri("util", "Compile")
compile(buildTarget, id = nextId())
assert(processing("buildTarget/compile"))
compile(buildTarget)
val res = svr.waitFor[BspCompileResult](10.seconds)
assert(res.statusCode == StatusCode.Success)
}
test("buildTarget/compile - reports compilation progress") { _ =>
val buildTarget = buildTargetUri("runAndTest", "Compile")
compile(buildTarget)
// This doesn't always come back in 10s on CI.
@ -271,18 +260,19 @@ object BuildServerTest extends AbstractServerTest {
)
}
test("buildTarget/scalacOptions") { _ =>
test("buildTarget/scalacOptions, buildTarget/javacOptions") { _ =>
val buildTarget = buildTargetUri("util", "Compile")
val badBuildTarget = buildTargetUri("badBuildTarget", "Compile")
val id = nextId()
svr.sendJsonRpc(
s"""{ "jsonrpc": "2.0", "id": "$id", "method": "buildTarget/scalacOptions", "params": {
| "targets": [{ "uri": "$buildTarget" }, { "uri": "$badBuildTarget" }]
|} }""".stripMargin
)
assert(processing("buildTarget/scalacOptions"))
val id1 = scalacOptions(Seq(buildTarget, badBuildTarget))
assert(svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id"""") &&
(s contains s""""id":"$id1"""") &&
(s contains "scala-library-2.13.11.jar")
})
val id2 = javacOptions(Seq(buildTarget, badBuildTarget))
assert(svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id2"""") &&
(s contains "scala-library-2.13.11.jar")
})
}
@ -306,7 +296,7 @@ object BuildServerTest extends AbstractServerTest {
| "targets": [{ "uri": "$buildTarget" }]
|} }""".stripMargin
)
assert(processing("buildTarget/cleanCache"))
assertProcessing("buildTarget/cleanCache")
val res = svr.waitFor[CleanCacheResult](10.seconds)
assert(res.cleaned)
assert(targetDir.list().isEmpty)
@ -316,7 +306,7 @@ object BuildServerTest extends AbstractServerTest {
svr.sendJsonRpc(
s"""{ "jsonrpc": "2.0", "id": "${nextId()}", "method": "workspace/buildTargets", "params": {} }"""
)
assert(processing("workspace/buildTargets"))
assertProcessing("workspace/buildTargets")
val result = svr.waitFor[WorkspaceBuildTargetsResult](10.seconds)
val allTargets = result.targets.map(_.id.uri)
@ -327,7 +317,7 @@ object BuildServerTest extends AbstractServerTest {
| ]
|} }""".stripMargin
)
assert(processing("buildTarget/cleanCache"))
assertProcessing("buildTarget/cleanCache")
val res = svr.waitFor[CleanCacheResult](10.seconds)
assert(res.cleaned)
}
@ -337,7 +327,7 @@ object BuildServerTest extends AbstractServerTest {
svr.sendJsonRpc(
s"""{ "jsonrpc": "2.0", "id": "$id", "method": "workspace/reload"}"""
)
assert(processing("workspace/reload"))
assertProcessing("workspace/reload")
assert(svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id"""") &&
(s contains """"result":null""")
@ -355,9 +345,8 @@ object BuildServerTest extends AbstractServerTest {
|)
|""".stripMargin
)
val id = nextId()
val id = reloadWorkspace()
// reload
reloadWorkspace(id)
assert(
svr.waitForString(10.seconds) { s =>
s.contains(s""""buildTarget":{"uri":"$metaBuildTarget"}""") &&
@ -405,7 +394,7 @@ object BuildServerTest extends AbstractServerTest {
| "targets": [{ "uri": "$buildTarget" }, { "uri": "$badBuildTarget" }]
|} }""".stripMargin
)
assert(processing("buildTarget/scalaMainClasses"))
assertProcessing("buildTarget/scalaMainClasses")
assert(svr.waitForString(30.seconds) { s =>
(s contains s""""id":"$id"""") &&
(s contains """"class":"main.Main"""")
@ -422,7 +411,7 @@ object BuildServerTest extends AbstractServerTest {
| "data": { "class": "main.Main" }
|} }""".stripMargin
)
assert(processing("buildTarget/run"))
assertProcessing("buildTarget/run")
assert(svr.waitForString(10.seconds) { s =>
(s contains "build/logMessage") &&
(s contains """"message":"Hello World!"""")
@ -443,7 +432,7 @@ object BuildServerTest extends AbstractServerTest {
| "params": { "targets": [{ "uri": "$buildTarget" }] }
|}""".stripMargin
)
assert(processing("buildTarget/jvmRunEnvironment"))
assertProcessing("buildTarget/jvmRunEnvironment")
assert {
svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id"""") &&
@ -465,7 +454,7 @@ object BuildServerTest extends AbstractServerTest {
| "params": { "targets": [{ "uri": "$buildTarget" }] }
|}""".stripMargin
)
assert(processing("buildTarget/jvmTestEnvironment"))
assertProcessing("buildTarget/jvmTestEnvironment")
assert {
svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id"""") &&
@ -487,7 +476,7 @@ object BuildServerTest extends AbstractServerTest {
| "targets": [{ "uri": "$buildTarget" }, { "uri": "$badBuildTarget" }]
|} }""".stripMargin
)
assert(processing("buildTarget/scalaTestClasses"))
assertProcessing("buildTarget/scalaTestClasses")
assert(svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id"""") &&
(s contains """"tests.FailingTest"""") &&
@ -504,7 +493,7 @@ object BuildServerTest extends AbstractServerTest {
| "targets": [{ "uri": "$buildTarget" }]
|} }""".stripMargin
)
assert(processing("buildTarget/test"))
assertProcessing("buildTarget/test")
assert(svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id"""") &&
(s contains """"statusCode":2""")
@ -528,7 +517,7 @@ object BuildServerTest extends AbstractServerTest {
| }
|} }""".stripMargin
)
assert(processing("buildTarget/test"))
assertProcessing("buildTarget/test")
assert(svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id"""") &&
(s contains """"statusCode":1""")
@ -557,8 +546,7 @@ object BuildServerTest extends AbstractServerTest {
test("buildTarget/compile: respond error") { _ =>
val buildTarget = buildTargetUri("respondError", "Compile")
val id = nextId()
compile(buildTarget, id)
val id = compile(buildTarget)
assert(svr.waitForString(10.seconds) { s =>
s.contains(s""""id":"$id"""") &&
s.contains(""""error"""") &&
@ -576,7 +564,7 @@ object BuildServerTest extends AbstractServerTest {
| "targets": [{ "uri": "$buildTarget" }, { "uri": "$badBuildTarget" }]
|} }""".stripMargin
)
assert(processing("buildTarget/resources"))
assertProcessing("buildTarget/resources")
assert(svr.waitForString(10.seconds) { s =>
(s contains s""""id":"$id"""") && (s contains "util/src/main/resources/")
})
@ -590,7 +578,7 @@ object BuildServerTest extends AbstractServerTest {
| "targets": [{ "uri": "$buildTarget" }, { "uri": "$badBuildTarget" }]
|} }""".stripMargin
)
assert(processing("buildTarget/outputPaths"))
assertProcessing("buildTarget/outputPaths")
val actualResult = svr.waitFor[OutputPathsResult](10.seconds)
val expectedResult = OutputPathsResult(
items = Vector(
@ -608,7 +596,7 @@ object BuildServerTest extends AbstractServerTest {
assert(actualResult == expectedResult)
}
private def initializeRequest(id: Int): Unit = {
private def initializeRequest(): Int = {
val params = InitializeBuildParams(
"test client",
"1.0.0",
@ -617,35 +605,55 @@ object BuildServerTest extends AbstractServerTest {
BuildClientCapabilities(Vector("scala")),
None
)
svr.sendJsonRpc(request(id, "build/initialize", params))
sendRequest("build/initialize", params)
}
private def processing(method: String, debug: Boolean = false): Boolean = {
svr.waitForString(10.seconds) { msg =>
private def assertProcessing(method: String, debug: Boolean = false): Unit = {
assert(svr.waitForString(10.seconds) { msg =>
if (debug) println(msg)
msg.contains("build/logMessage") &&
msg.contains(s""""message":"Processing $method"""")
}
msg.contains("build/logMessage") && msg.contains(s""""message":"Processing $method"""")
})
}
private def reloadWorkspace(id: Int = nextId()): Unit =
svr.sendJsonRpc(s"""{ "jsonrpc": "2.0", "id": "$id", "method": "workspace/reload"}""")
private def reloadWorkspace(): Int =
sendRequest("workspace/reload")
private def compile(buildTarget: URI, id: Int = nextId()): Unit = {
private def compile(buildTarget: URI): Int = {
val params =
CompileParams(targets = Vector(BuildTargetIdentifier(buildTarget)), None, Vector.empty)
svr.sendJsonRpc(request(id, "buildTarget/compile", params))
sendRequest("buildTarget/compile", params)
}
private def buildTargetSources(buildTargets: Seq[URI], id: Int = nextId()): String = {
private def scalacOptions(buildTargets: Seq[URI]): Int = {
val targets = buildTargets.map(BuildTargetIdentifier.apply).toVector
request(id, "buildTarget/sources", SourcesParams(targets))
sendRequest("buildTarget/scalacOptions", ScalacOptionsParams(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 javacOptions(buildTargets: Seq[URI]): Int = {
val targets = buildTargets.map(BuildTargetIdentifier.apply).toVector
sendRequest("buildTarget/scalacOptions", ScalacOptionsParams(targets))
}
private def buildTargetSources(buildTargets: Seq[URI]): Int = {
val targets = buildTargets.map(BuildTargetIdentifier.apply).toVector
sendRequest("buildTarget/sources", SourcesParams(targets))
}
private def sendRequest(method: String): Int = {
val id = nextId()
val msg = JsonRpcRequestMessage("2.0", id.toString, method, None)
val json = Converter.toJson(msg).get
svr.sendJsonRpc(CompactPrinter(json))
id
}
private def sendRequest[T: JsonWriter](method: String, params: T): Int = {
val id = nextId()
val msg = JsonRpcRequestMessage("2.0", id.toString, method, Converter.toJson(params).get)
val json = Converter.toJson(msg).get
svr.sendJsonRpc(CompactPrinter(json))
assertProcessing(method)
id
}
private def buildTargetUri(project: String, config: String): URI =