mirror of https://github.com/sbt/sbt.git
Create BSP connection file at server startup
This commit is contained in:
parent
c80fe525c6
commit
a31747758c
|
|
@ -10,22 +10,24 @@ package internal
|
|||
package server
|
||||
|
||||
import java.io.{ File, IOException }
|
||||
import java.net.{ SocketTimeoutException, InetAddress, ServerSocket, Socket }
|
||||
import java.net.{ InetAddress, ServerSocket, Socket, SocketTimeoutException }
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.nio.file.attribute.{ UserPrincipal, AclEntry, AclEntryPermission, AclEntryType }
|
||||
import java.nio.file.attribute.{ AclEntry, AclEntryPermission, AclEntryType, UserPrincipal }
|
||||
import java.security.SecureRandom
|
||||
import java.math.BigInteger
|
||||
|
||||
import scala.concurrent.{ Future, Promise }
|
||||
import scala.util.{ Try, Success, Failure }
|
||||
import scala.util.{ Failure, Success, Try }
|
||||
import sbt.internal.protocol.{ PortFile, TokenFile }
|
||||
import sbt.util.Logger
|
||||
import sbt.io.IO
|
||||
import sbt.io.syntax._
|
||||
import sjsonnew.support.scalajson.unsafe.{ Converter, CompactPrinter }
|
||||
import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter }
|
||||
import sbt.internal.protocol.codec._
|
||||
import sbt.internal.util.ErrorHandling
|
||||
import sbt.internal.util.Util.isWindows
|
||||
import org.scalasbt.ipcsocket._
|
||||
import sbt.internal.bsp.BuildServerConnection
|
||||
|
||||
private[sbt] sealed trait ServerInstance {
|
||||
def shutdown(): Unit
|
||||
|
|
@ -85,6 +87,7 @@ private[sbt] object Server {
|
|||
serverSocketOpt = Option(serverSocket)
|
||||
log.info(s"sbt server started at ${connection.shortName}")
|
||||
writePortfile()
|
||||
writeBspConnectionDetails()
|
||||
running.set(true)
|
||||
p.success(())
|
||||
while (running.get()) {
|
||||
|
|
@ -194,6 +197,13 @@ private[sbt] object Server {
|
|||
IO.write(portfile, CompactPrinter(json))
|
||||
}
|
||||
|
||||
private[this] def writeBspConnectionDetails(): Unit = {
|
||||
import bsp.codec.JsonProtocol._
|
||||
val details = BuildServerConnection.details(sbtVersion)
|
||||
val json = Converter.toJson(details).get
|
||||
IO.write(bspConnectionFile, CompactPrinter(json), append = false)
|
||||
}
|
||||
|
||||
private[sbt] def prepareSocketfile(): Unit = {
|
||||
if (socketfile.exists) {
|
||||
IO.delete(socketfile)
|
||||
|
|
@ -211,7 +221,9 @@ private[sbt] case class ServerConnection(
|
|||
portfile: File,
|
||||
tokenfile: File,
|
||||
socketfile: File,
|
||||
pipeName: String
|
||||
pipeName: String,
|
||||
bspConnectionFile: File,
|
||||
sbtVersion: String
|
||||
) {
|
||||
def shortName: String = {
|
||||
connectionType match {
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ private[sbt] final class CommandExchange {
|
|||
private[sbt] def runServer(s: State): State = {
|
||||
lazy val port = s.get(serverPort).getOrElse(5001)
|
||||
lazy val host = s.get(serverHost).getOrElse("127.0.0.1")
|
||||
lazy val sbtVersion = s.configuration.provider.id.version
|
||||
lazy val auth: Set[ServerAuthentication] =
|
||||
s.get(serverAuthentication).getOrElse(Set(ServerAuthentication.Token))
|
||||
lazy val connectionType = s.get(serverConnectionType).getOrElse(ConnectionType.Tcp)
|
||||
|
|
@ -147,6 +148,7 @@ private[sbt] final class CommandExchange {
|
|||
val tokenfile = serverDir / h / "token.json"
|
||||
val socketfile = serverDir / h / "sock"
|
||||
val pipeName = "sbt-server-" + h
|
||||
val bspConnectionFile = s.baseDir / ".bsp" / "sbt.json"
|
||||
val connection = ServerConnection(
|
||||
connectionType,
|
||||
host,
|
||||
|
|
@ -156,6 +158,8 @@ private[sbt] final class CommandExchange {
|
|||
tokenfile,
|
||||
socketfile,
|
||||
pipeName,
|
||||
bspConnectionFile,
|
||||
sbtVersion
|
||||
)
|
||||
val serverInstance = Server.start(connection, onIncomingSocket, s.log)
|
||||
// don't throw exception when it times out
|
||||
|
|
|
|||
|
|
@ -25,11 +25,9 @@ import sjsonnew.support.scalajson.unsafe.Converter
|
|||
|
||||
object BuildServerProtocol {
|
||||
import sbt.internal.bsp.codec.JsonProtocol._
|
||||
private val bspVersion = "2.0.0-M5"
|
||||
private val languageIds = Vector("scala")
|
||||
private val bspTargetConfigs = Set("compile", "test")
|
||||
private val capabilities = BuildServerCapabilities(
|
||||
CompileProvider(languageIds),
|
||||
CompileProvider(BuildServerConnection.languages),
|
||||
dependencySourcesProvider = true
|
||||
)
|
||||
|
||||
|
|
@ -141,7 +139,13 @@ object BuildServerProtocol {
|
|||
{
|
||||
case r: JsonRpcRequestMessage if r.method == "build/initialize" =>
|
||||
val _ = Converter.fromJson[InitializeBuildParams](json(r)).get
|
||||
val response = InitializeBuildResult("sbt", sbtVersion, bspVersion, capabilities, None)
|
||||
val response = InitializeBuildResult(
|
||||
"sbt",
|
||||
sbtVersion,
|
||||
BuildServerConnection.bspVersion,
|
||||
capabilities,
|
||||
None
|
||||
)
|
||||
callback.jsonRpcRespond(response, Some(r.id)); ()
|
||||
|
||||
case r: JsonRpcRequestMessage if r.method == "workspace/buildTargets" =>
|
||||
|
|
@ -223,7 +227,7 @@ object BuildServerProtocol {
|
|||
Some(baseDirectory),
|
||||
tags,
|
||||
capabilities,
|
||||
languageIds,
|
||||
BuildServerConnection.languages,
|
||||
projectDependencies.join.value.toVector,
|
||||
dataKind = Some("scala"),
|
||||
data = Some(Converter.toJsonUnsafe(compileData)),
|
||||
|
|
|
|||
56
protocol/src/main/contraband-scala/sbt/internal/bsp/BspConnectionDetails.scala
generated
Normal file
56
protocol/src/main/contraband-scala/sbt/internal/bsp/BspConnectionDetails.scala
generated
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.internal.bsp
|
||||
/**
|
||||
* https://build-server-protocol.github.io/docs/server-discovery.html
|
||||
* @param name The name of the build tool
|
||||
* @param version The version of the build tool
|
||||
* @param bspVersion The bsp version of the build tool
|
||||
* @param languages A collection of languages supported by this BSP server
|
||||
* @param argv Command arguments runnable via system processes to start a BSP server
|
||||
*/
|
||||
final class BspConnectionDetails private (
|
||||
val name: String,
|
||||
val version: String,
|
||||
val bspVersion: String,
|
||||
val languages: Vector[String],
|
||||
val argv: Vector[String]) extends Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
case x: BspConnectionDetails => (this.name == x.name) && (this.version == x.version) && (this.bspVersion == x.bspVersion) && (this.languages == x.languages) && (this.argv == x.argv)
|
||||
case _ => false
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.BspConnectionDetails".##) + name.##) + version.##) + bspVersion.##) + languages.##) + argv.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"BspConnectionDetails(" + name + ", " + version + ", " + bspVersion + ", " + languages + ", " + argv + ")"
|
||||
}
|
||||
private[this] def copy(name: String = name, version: String = version, bspVersion: String = bspVersion, languages: Vector[String] = languages, argv: Vector[String] = argv): BspConnectionDetails = {
|
||||
new BspConnectionDetails(name, version, bspVersion, languages, argv)
|
||||
}
|
||||
def withName(name: String): BspConnectionDetails = {
|
||||
copy(name = name)
|
||||
}
|
||||
def withVersion(version: String): BspConnectionDetails = {
|
||||
copy(version = version)
|
||||
}
|
||||
def withBspVersion(bspVersion: String): BspConnectionDetails = {
|
||||
copy(bspVersion = bspVersion)
|
||||
}
|
||||
def withLanguages(languages: Vector[String]): BspConnectionDetails = {
|
||||
copy(languages = languages)
|
||||
}
|
||||
def withArgv(argv: Vector[String]): BspConnectionDetails = {
|
||||
copy(argv = argv)
|
||||
}
|
||||
}
|
||||
object BspConnectionDetails {
|
||||
|
||||
def apply(name: String, version: String, bspVersion: String, languages: Vector[String], argv: Vector[String]): BspConnectionDetails = new BspConnectionDetails(name, version, bspVersion, languages, argv)
|
||||
}
|
||||
35
protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BspConnectionDetailsFormats.scala
generated
Normal file
35
protocol/src/main/contraband-scala/sbt/internal/bsp/codec/BspConnectionDetailsFormats.scala
generated
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.internal.bsp.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait BspConnectionDetailsFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val BspConnectionDetailsFormat: JsonFormat[sbt.internal.bsp.BspConnectionDetails] = new JsonFormat[sbt.internal.bsp.BspConnectionDetails] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.BspConnectionDetails = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
val name = unbuilder.readField[String]("name")
|
||||
val version = unbuilder.readField[String]("version")
|
||||
val bspVersion = unbuilder.readField[String]("bspVersion")
|
||||
val languages = unbuilder.readField[Vector[String]]("languages")
|
||||
val argv = unbuilder.readField[Vector[String]]("argv")
|
||||
unbuilder.endObject()
|
||||
sbt.internal.bsp.BspConnectionDetails(name, version, bspVersion, languages, argv)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.internal.bsp.BspConnectionDetails, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("name", obj.name)
|
||||
builder.addField("version", obj.version)
|
||||
builder.addField("bspVersion", obj.bspVersion)
|
||||
builder.addField("languages", obj.languages)
|
||||
builder.addField("argv", obj.argv)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,4 +37,5 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
|||
with sbt.internal.bsp.codec.ScalacOptionsParamsFormats
|
||||
with sbt.internal.bsp.codec.ScalacOptionsItemFormats
|
||||
with sbt.internal.bsp.codec.ScalacOptionsResultFormats
|
||||
with sbt.internal.bsp.codec.BspConnectionDetailsFormats
|
||||
object JsonProtocol extends JsonProtocol
|
||||
|
|
@ -416,3 +416,21 @@ type ScalacOptionsItem {
|
|||
## The output directory for classfiles produced by this target
|
||||
classDirectory: java.net.URI
|
||||
}
|
||||
|
||||
## https://build-server-protocol.github.io/docs/server-discovery.html
|
||||
type BspConnectionDetails {
|
||||
## The name of the build tool
|
||||
name: String!
|
||||
|
||||
## The version of the build tool
|
||||
version: String!
|
||||
|
||||
## The bsp version of the build tool
|
||||
bspVersion: String!
|
||||
|
||||
## A collection of languages supported by this BSP server
|
||||
languages: [String]
|
||||
|
||||
## Command arguments runnable via system processes to start a BSP server
|
||||
argv: [String]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package sbt.internal.bsp
|
||||
|
||||
object BuildServerConnection {
|
||||
final val name = "sbt"
|
||||
final val bspVersion = "2.0.0-M5"
|
||||
final val languages = Vector("scala")
|
||||
final val argv = Vector("sbt", "-bsp")
|
||||
def details(sbtVersion: String): BspConnectionDetails = {
|
||||
BspConnectionDetails(name, sbtVersion, bspVersion, languages, argv)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue