mirror of https://github.com/sbt/sbt.git
commit
dc676af358
|
|
@ -9,6 +9,7 @@ package sbt.internal.client
|
|||
|
||||
import java.io.{ File, InputStream, OutputStream }
|
||||
import java.net.Socket
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
import sbt.Exit
|
||||
import sbt.io.syntax._
|
||||
|
|
@ -18,18 +19,37 @@ import scala.sys.process.Process
|
|||
import scala.util.control.NonFatal
|
||||
|
||||
class BspClient private (sbtServer: Socket) {
|
||||
private val lock = new AnyRef
|
||||
private var terminated = false
|
||||
private def run(): Exit = Exit(BspClient.bspRun(sbtServer))
|
||||
}
|
||||
|
||||
private def transferTo(input: InputStream, output: OutputStream): Thread = {
|
||||
object BspClient {
|
||||
private[sbt] def bspRun(sbtServer: Socket): Int = {
|
||||
val lock = new AnyRef
|
||||
val terminated = new AtomicBoolean(false)
|
||||
transferTo(terminated, lock, sbtServer.getInputStream, System.out).start()
|
||||
transferTo(terminated, lock, System.in, sbtServer.getOutputStream).start()
|
||||
try {
|
||||
lock.synchronized {
|
||||
while (!terminated.get) lock.wait()
|
||||
}
|
||||
0
|
||||
} catch { case _: Throwable => 1 } finally sbtServer.close()
|
||||
}
|
||||
|
||||
private[sbt] def transferTo(
|
||||
terminated: AtomicBoolean,
|
||||
lock: AnyRef,
|
||||
input: InputStream,
|
||||
output: OutputStream
|
||||
): Thread = {
|
||||
val thread = new Thread {
|
||||
override def run(): Unit = {
|
||||
val buffer = Array.ofDim[Byte](1024)
|
||||
try {
|
||||
while (!terminated) {
|
||||
while (!terminated.get) {
|
||||
val size = input.read(buffer)
|
||||
if (size == -1) {
|
||||
terminated = true
|
||||
terminated.set(true)
|
||||
} else {
|
||||
output.write(buffer, 0, size)
|
||||
output.flush()
|
||||
|
|
@ -38,10 +58,11 @@ class BspClient private (sbtServer: Socket) {
|
|||
input.close()
|
||||
output.close()
|
||||
} catch {
|
||||
case _: InterruptedException => terminated.set(true)
|
||||
case NonFatal(_) => ()
|
||||
} finally {
|
||||
lock.synchronized {
|
||||
terminated = true
|
||||
terminated.set(true)
|
||||
lock.notify()
|
||||
}
|
||||
}
|
||||
|
|
@ -50,24 +71,6 @@ class BspClient private (sbtServer: Socket) {
|
|||
thread.setDaemon(true)
|
||||
thread
|
||||
}
|
||||
|
||||
private def run(): Exit = {
|
||||
try {
|
||||
transferTo(sbtServer.getInputStream, System.out).start()
|
||||
transferTo(System.in, sbtServer.getOutputStream).start()
|
||||
|
||||
lock.synchronized {
|
||||
while (!terminated) lock.wait()
|
||||
}
|
||||
|
||||
Exit(0)
|
||||
} catch {
|
||||
case NonFatal(_) => Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object BspClient {
|
||||
def run(configuration: xsbti.AppConfiguration): Exit = {
|
||||
val baseDirectory = configuration.baseDirectory
|
||||
val portFile = baseDirectory / "project" / "target" / "active.json"
|
||||
|
|
|
|||
|
|
@ -164,8 +164,10 @@ class NetworkClient(
|
|||
case _ =>
|
||||
}
|
||||
|
||||
// Open server connection based on the portfile
|
||||
def init(promptCompleteUsers: Boolean, retry: Boolean): ServerConnection =
|
||||
private[sbt] def connectOrStartServerAndConnect(
|
||||
promptCompleteUsers: Boolean,
|
||||
retry: Boolean
|
||||
): (Socket, Option[String]) =
|
||||
try {
|
||||
if (!portfile.exists) {
|
||||
if (promptCompleteUsers) {
|
||||
|
|
@ -208,7 +210,17 @@ class NetworkClient(
|
|||
connect(attempt + 1)
|
||||
}
|
||||
}
|
||||
val (sk, tkn) = connect(0)
|
||||
connect(0)
|
||||
} catch {
|
||||
case e: ConnectionRefusedException if retry =>
|
||||
if (Files.deleteIfExists(portfile.toPath))
|
||||
connectOrStartServerAndConnect(promptCompleteUsers, retry = false)
|
||||
else throw e
|
||||
}
|
||||
|
||||
// Open server connection based on the portfile
|
||||
def init(promptCompleteUsers: Boolean, retry: Boolean): ServerConnection = {
|
||||
val (sk, tkn) = connectOrStartServerAndConnect(promptCompleteUsers, retry)
|
||||
val conn = new ServerConnection(sk) {
|
||||
override def onNotification(msg: JsonRpcNotificationMessage): Unit = {
|
||||
msg.method match {
|
||||
|
|
@ -284,10 +296,6 @@ class NetworkClient(
|
|||
conn.sendString(Serialization.serializeCommandAsJsonMessage(initCommand))
|
||||
connectionHolder.set(conn)
|
||||
conn
|
||||
} catch {
|
||||
case e: ConnectionRefusedException if retry =>
|
||||
if (Files.deleteIfExists(portfile.toPath)) init(promptCompleteUsers, retry = false)
|
||||
else throw e
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1006,9 +1014,10 @@ object NetworkClient {
|
|||
val commandArguments: Seq[String],
|
||||
val completionArguments: Seq[String],
|
||||
val sbtScript: String,
|
||||
val bsp: Boolean,
|
||||
) {
|
||||
def withBaseDirectory(file: File): Arguments =
|
||||
new Arguments(file, sbtArguments, commandArguments, completionArguments, sbtScript)
|
||||
new Arguments(file, sbtArguments, commandArguments, completionArguments, sbtScript, bsp)
|
||||
}
|
||||
private[client] val completions = "--completions"
|
||||
private[client] val noTab = "--no-tab"
|
||||
|
|
@ -1016,6 +1025,7 @@ object NetworkClient {
|
|||
private[client] val sbtBase = "--sbt-base-directory"
|
||||
private[client] def parseArgs(args: Array[String]): Arguments = {
|
||||
var sbtScript = if (Properties.isWin) "sbt.bat" else "sbt"
|
||||
var bsp = false
|
||||
val commandArgs = new mutable.ArrayBuffer[String]
|
||||
val sbtArguments = new mutable.ArrayBuffer[String]
|
||||
val completionArguments = new mutable.ArrayBuffer[String]
|
||||
|
|
@ -1037,6 +1047,7 @@ object NetworkClient {
|
|||
.lastOption
|
||||
.map(_.replaceAllLiterally("%20", " "))
|
||||
.getOrElse(sbtScript)
|
||||
case "-bsp" | "--bsp" => bsp = true
|
||||
case "--sbt-script" if i + 1 < sanitized.length =>
|
||||
i += 1
|
||||
sbtScript = sanitized(i).replaceAllLiterally("%20", " ")
|
||||
|
|
@ -1050,7 +1061,7 @@ object NetworkClient {
|
|||
}
|
||||
val base = new File("").getCanonicalFile
|
||||
if (!sbtArguments.contains("-Dsbt.io.virtual=true")) sbtArguments += "-Dsbt.io.virtual=true"
|
||||
new Arguments(base, sbtArguments, commandArgs, completionArguments, sbtScript)
|
||||
new Arguments(base, sbtArguments, commandArgs, completionArguments, sbtScript, bsp)
|
||||
}
|
||||
|
||||
def client(
|
||||
|
|
@ -1091,8 +1102,14 @@ object NetworkClient {
|
|||
terminal
|
||||
)
|
||||
try {
|
||||
if (args.bsp) {
|
||||
val (socket, _) =
|
||||
client.connectOrStartServerAndConnect(promptCompleteUsers = false, retry = true)
|
||||
BspClient.bspRun(socket)
|
||||
} else {
|
||||
if (client.connect(log = true, promptCompleteUsers = false)) client.run()
|
||||
else 1
|
||||
}
|
||||
} catch { case _: Exception => 1 } finally client.close()
|
||||
}
|
||||
def client(
|
||||
|
|
|
|||
Loading…
Reference in New Issue