mirror of https://github.com/sbt/sbt.git
Merge pull request #6114 from eatkins/bsp-consolidate
Use NetworkClient to implement `sbt -bsp`
This commit is contained in:
commit
37ffbf8ddd
|
|
@ -7,20 +7,12 @@
|
|||
|
||||
package sbt.internal.client
|
||||
|
||||
import java.io.{ File, InputStream, OutputStream }
|
||||
import java.io.{ InputStream, OutputStream }
|
||||
import java.net.Socket
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
import sbt.Exit
|
||||
import sbt.io.syntax._
|
||||
import sbt.protocol.ClientSocket
|
||||
|
||||
import scala.util.control.NonFatal
|
||||
import java.lang.ProcessBuilder.Redirect
|
||||
|
||||
class BspClient private (sbtServer: Socket) {
|
||||
private def run(): Exit = Exit(BspClient.bspRun(sbtServer))
|
||||
}
|
||||
|
||||
object BspClient {
|
||||
private[sbt] def bspRun(sbtServer: Socket): Int = {
|
||||
|
|
@ -72,52 +64,6 @@ object BspClient {
|
|||
thread
|
||||
}
|
||||
def run(configuration: xsbti.AppConfiguration): Exit = {
|
||||
val baseDirectory = configuration.baseDirectory
|
||||
val portFile = baseDirectory / "project" / "target" / "active.json"
|
||||
try {
|
||||
if (!portFile.exists) {
|
||||
forkServer(baseDirectory, portFile)
|
||||
}
|
||||
val (socket, _) = ClientSocket.socket(portFile)
|
||||
new BspClient(socket).run()
|
||||
} catch {
|
||||
case NonFatal(_) => Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forks another instance of sbt in the background.
|
||||
* This instance must be shutdown explicitly via `sbt -client shutdown`
|
||||
*/
|
||||
def forkServer(baseDirectory: File, portfile: File): Unit = {
|
||||
val args = List("--detach-stdio")
|
||||
val launchOpts = List(
|
||||
"-Dfile.encoding=UTF-8",
|
||||
"-Dsbt.io.virtual=true",
|
||||
"-Xms1024M",
|
||||
"-Xmx1024M",
|
||||
"-Xss4M",
|
||||
"-XX:ReservedCodeCacheSize=128m"
|
||||
)
|
||||
|
||||
val launcherJarString = sys.props.get("java.class.path") match {
|
||||
case Some(cp) =>
|
||||
cp.split(File.pathSeparator)
|
||||
.headOption
|
||||
.getOrElse(sys.error("launcher JAR classpath not found"))
|
||||
case _ => sys.error("property java.class.path expected")
|
||||
}
|
||||
|
||||
val cmd = "java" :: launchOpts ::: "-jar" :: launcherJarString :: args
|
||||
val processBuilder =
|
||||
new ProcessBuilder(cmd: _*)
|
||||
.directory(baseDirectory)
|
||||
.redirectInput(Redirect.PIPE)
|
||||
|
||||
val process = processBuilder.start()
|
||||
|
||||
while (process.isAlive && !portfile.exists) Thread.sleep(100)
|
||||
|
||||
if (!process.isAlive) sys.error("sbt server exited")
|
||||
Exit(NetworkClient.run(configuration, configuration.arguments.toList, redirectOutput = true))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1093,16 +1093,20 @@ object NetworkClient {
|
|||
terminal: Terminal,
|
||||
useJNI: Boolean
|
||||
): Int = {
|
||||
val printStream = if (args.bsp) errorStream else terminal.printStream
|
||||
val client =
|
||||
simpleClient(
|
||||
args.withBaseDirectory(baseDirectory),
|
||||
inputStream,
|
||||
printStream,
|
||||
errorStream,
|
||||
useJNI,
|
||||
terminal
|
||||
)
|
||||
clientImpl(client, args.bsp)
|
||||
}
|
||||
private def clientImpl(client: NetworkClient, isBsp: Boolean): Int = {
|
||||
try {
|
||||
if (args.bsp) {
|
||||
if (isBsp) {
|
||||
val (socket, _) =
|
||||
client.connectOrStartServerAndConnect(promptCompleteUsers = false, retry = true)
|
||||
BspClient.bspRun(socket)
|
||||
|
|
@ -1214,16 +1218,18 @@ object NetworkClient {
|
|||
}
|
||||
|
||||
def run(configuration: xsbti.AppConfiguration, arguments: List[String]): Int =
|
||||
try {
|
||||
val client = new NetworkClient(configuration, parseArgs(arguments.toArray))
|
||||
try {
|
||||
if (client.connect(log = true, promptCompleteUsers = false)) client.run()
|
||||
else 1
|
||||
} catch { case _: Throwable => 1 } finally client.close()
|
||||
} catch {
|
||||
case NonFatal(e) =>
|
||||
e.printStackTrace()
|
||||
1
|
||||
}
|
||||
run(configuration, arguments, false)
|
||||
def run(
|
||||
configuration: xsbti.AppConfiguration,
|
||||
arguments: List[String],
|
||||
redirectOutput: Boolean
|
||||
): Int = {
|
||||
val term = Terminal.console
|
||||
val err = new PrintStream(term.errorStream)
|
||||
val out = if (redirectOutput) err else new PrintStream(term.outputStream)
|
||||
val args = parseArgs(arguments.toArray).withBaseDirectory(configuration.baseDirectory)
|
||||
val client = simpleClient(args, term.inputStream, out, err, useJNI = false)
|
||||
clientImpl(client, args.bsp)
|
||||
}
|
||||
private class AccessDeniedException extends Throwable
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,10 +64,6 @@ private[sbt] object xMain {
|
|||
import sbt.internal.CommandStrings.{ BootCommand, DefaultsCommand, InitCommand }
|
||||
import sbt.internal.client.NetworkClient
|
||||
|
||||
val bootServerSocket = getSocketOrExit(configuration) match {
|
||||
case (_, Some(e)) => return e
|
||||
case (s, _) => s
|
||||
}
|
||||
// if we detect -Dsbt.client=true or -client, run thin client.
|
||||
val clientModByEnv = SysProp.client
|
||||
val userCommands = configuration.arguments
|
||||
|
|
@ -75,6 +71,12 @@ private[sbt] object xMain {
|
|||
.filterNot(_ == DashDashServer)
|
||||
val isClient: String => Boolean = cmd => (cmd == DashClient) || (cmd == DashDashClient)
|
||||
val isBsp: String => Boolean = cmd => (cmd == "-bsp") || (cmd == "--bsp")
|
||||
val isServer = !userCommands.exists(c => isBsp(c) || isClient(c))
|
||||
val bootServerSocket = if (isServer) getSocketOrExit(configuration) match {
|
||||
case (_, Some(e)) => return e
|
||||
case (s, _) => s
|
||||
}
|
||||
else None
|
||||
if (userCommands.exists(isBsp)) {
|
||||
BspClient.run(dealiasBaseDirectory(configuration))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ private[sbt] final class CommandExchange {
|
|||
private var server: Option[ServerInstance] = None
|
||||
private val firstInstance: AtomicBoolean = new AtomicBoolean(true)
|
||||
private val monitoringActiveJson: AtomicBoolean = new AtomicBoolean(false)
|
||||
private var consoleChannel: Option[ConsoleChannel] = None
|
||||
private val commandQueue: LinkedBlockingQueue[Exec] = new LinkedBlockingQueue[Exec]
|
||||
private val channelBuffer: ListBuffer[CommandChannel] = new ListBuffer()
|
||||
private val channelBufferLock = new AnyRef {}
|
||||
|
|
@ -60,6 +59,7 @@ private[sbt] final class CommandExchange {
|
|||
private[this] val lastState = new AtomicReference[State]
|
||||
private[this] val currentExecRef = new AtomicReference[Exec]
|
||||
private[sbt] def hasServer = server.isDefined
|
||||
addConsoleChannel()
|
||||
|
||||
def channels: List[CommandChannel] = channelBuffer.toList
|
||||
|
||||
|
|
@ -141,11 +141,9 @@ private[sbt] final class CommandExchange {
|
|||
}
|
||||
|
||||
private def addConsoleChannel(): Unit =
|
||||
if (consoleChannel.isEmpty) {
|
||||
if (!Terminal.startedByRemoteClient) {
|
||||
val name = ConsoleChannel.defaultName
|
||||
val console0 = new ConsoleChannel(name, mkAskUser(name))
|
||||
consoleChannel = Some(console0)
|
||||
subscribe(console0)
|
||||
subscribe(new ConsoleChannel(name, mkAskUser(name)))
|
||||
}
|
||||
def run(s: State): State = run(s, s.get(autoStartServer).getOrElse(true))
|
||||
def run(s: State, autoStart: Boolean): State = {
|
||||
|
|
@ -402,7 +400,6 @@ private[sbt] final class CommandExchange {
|
|||
.withChannelName(currentExec.flatMap(_.source.map(_.channelName)))
|
||||
case _ => pe
|
||||
}
|
||||
if (channels.isEmpty) addConsoleChannel()
|
||||
channels.foreach(c => ProgressState.updateProgressState(newPE, c.terminal))
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue