diff --git a/main-command/src/main/scala/sbt/internal/server/Server.scala b/main-command/src/main/scala/sbt/internal/server/Server.scala index 47ad6b07b..0c8eab93e 100644 --- a/main-command/src/main/scala/sbt/internal/server/Server.scala +++ b/main-command/src/main/scala/sbt/internal/server/Server.scala @@ -8,9 +8,13 @@ package server import java.net.{ SocketTimeoutException, InetAddress, ServerSocket, Socket } import java.util.concurrent.atomic.AtomicBoolean import sbt.util.Logger +import sbt.internal.util.ErrorHandling +import scala.concurrent.{ Future, Promise } +import scala.util.{ Try, Success, Failure } private[sbt] sealed trait ServerInstance { def shutdown(): Unit + def ready: Future[Unit] } private[sbt] object Server { @@ -20,23 +24,31 @@ private[sbt] object Server { // val lock = new AnyRef {} // val clients: mutable.ListBuffer[ClientConnection] = mutable.ListBuffer.empty - val running = new AtomicBoolean(true) + val running = new AtomicBoolean(false) + val p: Promise[Unit] = Promise[Unit]() + val ready: Future[Unit] = p.future val serverThread = new Thread("sbt-socket-server") { - override def run(): Unit = { - val serverSocket = new ServerSocket(port, 50, InetAddress.getByName(host)) - serverSocket.setSoTimeout(5000) - - log.info(s"sbt server started at $host:$port") - while (running.get()) { - try { - val socket = serverSocket.accept() - onIncomingSocket(socket) - } catch { - case _: SocketTimeoutException => // its ok + Try { + ErrorHandling.translate(s"server failed to start on $host:$port. ") { + new ServerSocket(port, 50, InetAddress.getByName(host)) } - + } match { + case Failure(e) => p.failure(e) + case Success(serverSocket) => + serverSocket.setSoTimeout(5000) + log.info(s"sbt server started at $host:$port") + running.set(true) + p.success(()) + while (running.get()) { + try { + val socket = serverSocket.accept() + onIncomingSocket(socket) + } catch { + case _: SocketTimeoutException => // its ok + } + } } } } diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index d9ed0f40c..49b05ea7d 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -12,6 +12,9 @@ import scala.annotation.tailrec import BasicKeys.serverPort import java.net.Socket import sjsonnew.JsonFormat +import scala.concurrent.Await +import scala.concurrent.duration.Duration +import scala.util.{ Success, Failure } /** * The command exchange merges multiple command channels (e.g. network and console), @@ -81,7 +84,15 @@ private[sbt] final class CommandExchange { server match { case Some(x) => // do nothing case _ => - server = Some(Server.start("127.0.0.1", port, onIncomingSocket, s.log)) + val x = Server.start("127.0.0.1", port, onIncomingSocket, s.log) + Await.ready(x.ready, Duration("10s")) + x.ready.value match { + case Some(Success(_)) => + case Some(Failure(e)) => + s.log.error(e.toString) + case None => // this won't happen because we awaited + } + server = Some(x) } s }