mirror of https://github.com/sbt/sbt.git
Introduce execId that gets sent back
Now the client can put an id on each exec. This can then be tracked and/or be used to block the user input.
This commit is contained in:
parent
1bf50e10c8
commit
892e25d23f
|
|
@ -6,26 +6,33 @@
|
||||||
package sbt
|
package sbt
|
||||||
final class Exec private (
|
final class Exec private (
|
||||||
val commandLine: String,
|
val commandLine: String,
|
||||||
|
val execId: Option[String],
|
||||||
val source: Option[sbt.CommandSource]) extends Serializable {
|
val source: Option[sbt.CommandSource]) extends Serializable {
|
||||||
|
|
||||||
|
private def this(commandLine: String, source: Option[sbt.CommandSource]) = this(commandLine, None, source)
|
||||||
|
|
||||||
override def equals(o: Any): Boolean = o match {
|
override def equals(o: Any): Boolean = o match {
|
||||||
case x: Exec => (this.commandLine == x.commandLine) && (this.source == x.source)
|
case x: Exec => (this.commandLine == x.commandLine) && (this.execId == x.execId) && (this.source == x.source)
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
override def hashCode: Int = {
|
override def hashCode: Int = {
|
||||||
37 * (37 * (17 + commandLine.##) + source.##)
|
37 * (37 * (37 * (17 + commandLine.##) + execId.##) + source.##)
|
||||||
}
|
}
|
||||||
override def toString: String = {
|
override def toString: String = {
|
||||||
"Exec(" + commandLine + ", " + source + ")"
|
"Exec(" + commandLine + ", " + execId + ", " + source + ")"
|
||||||
}
|
}
|
||||||
protected[this] def copy(commandLine: String = commandLine, source: Option[sbt.CommandSource] = source): Exec = {
|
protected[this] def copy(commandLine: String = commandLine, execId: Option[String] = execId, source: Option[sbt.CommandSource] = source): Exec = {
|
||||||
new Exec(commandLine, source)
|
new Exec(commandLine, execId, source)
|
||||||
}
|
}
|
||||||
def withCommandLine(commandLine: String): Exec = {
|
def withCommandLine(commandLine: String): Exec = {
|
||||||
copy(commandLine = commandLine)
|
copy(commandLine = commandLine)
|
||||||
}
|
}
|
||||||
|
def withExecId(execId: Option[String]): Exec = {
|
||||||
|
copy(execId = execId)
|
||||||
|
}
|
||||||
|
def withExecId(execId: String): Exec = {
|
||||||
|
copy(execId = Option(execId))
|
||||||
|
}
|
||||||
def withSource(source: Option[sbt.CommandSource]): Exec = {
|
def withSource(source: Option[sbt.CommandSource]): Exec = {
|
||||||
copy(source = source)
|
copy(source = source)
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +41,9 @@ final class Exec private (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
object Exec {
|
object Exec {
|
||||||
|
def newExecId: String = java.util.UUID.randomUUID.toString
|
||||||
def apply(commandLine: String, source: Option[sbt.CommandSource]): Exec = new Exec(commandLine, source)
|
def apply(commandLine: String, source: Option[sbt.CommandSource]): Exec = new Exec(commandLine, None, source)
|
||||||
def apply(commandLine: String, source: sbt.CommandSource): Exec = new Exec(commandLine, Option(source))
|
def apply(commandLine: String, source: sbt.CommandSource): Exec = new Exec(commandLine, None, Option(source))
|
||||||
|
def apply(commandLine: String, execId: Option[String], source: Option[sbt.CommandSource]): Exec = new Exec(commandLine, execId, source)
|
||||||
|
def apply(commandLine: String, execId: String, source: sbt.CommandSource): Exec = new Exec(commandLine, Option(execId), Option(source))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ package sbt
|
||||||
|
|
||||||
type Exec {
|
type Exec {
|
||||||
commandLine: String!
|
commandLine: String!
|
||||||
|
execId: String @since("0.0.1")
|
||||||
source: sbt.CommandSource
|
source: sbt.CommandSource
|
||||||
|
|
||||||
|
#xcompanion def newExecId: String = java.util.UUID.randomUUID.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandSource {
|
type CommandSource {
|
||||||
|
|
|
||||||
|
|
@ -198,12 +198,9 @@ object BasicCommands {
|
||||||
val s1 = exchange.run(s0)
|
val s1 = exchange.run(s0)
|
||||||
exchange.publishEvent(ConsolePromptEvent(s0))
|
exchange.publishEvent(ConsolePromptEvent(s0))
|
||||||
val exec: Exec = exchange.blockUntilNextExec
|
val exec: Exec = exchange.blockUntilNextExec
|
||||||
val line = exec.commandLine
|
val newState = s1.copy(onFailure = Some(Exec(Server, None)), remainingCommands = exec +: Exec(Server, None) +: s1.remainingCommands).setInteractive(true)
|
||||||
val source = exec.source
|
exchange.publishEvent(ConsoleUnpromptEvent(exec.source))
|
||||||
println(s"server (line, source): ($line, $source)")
|
if (exec.commandLine.trim.isEmpty) newState
|
||||||
val newState = s1.copy(onFailure = Some(Exec(Server, None)), remainingCommands = Exec(line, source) +: Exec(Server, None) +: s1.remainingCommands).setInteractive(true)
|
|
||||||
exchange.publishEvent(ConsoleUnpromptEvent(source))
|
|
||||||
if (line.trim.isEmpty) newState
|
|
||||||
else newState.clearGlobalLog
|
else newState.clearGlobalLog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,16 +89,18 @@ object Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This is the main function State transfer function of the sbt command processing, called by MainLoop.next, */
|
/** This is the main function State transfer function of the sbt command processing, called by MainLoop.next, */
|
||||||
def process(command: Exec, state: State): State =
|
def process(exec: Exec, state: State): State =
|
||||||
{
|
{
|
||||||
|
val channelName = exec.source map { _.channelName }
|
||||||
|
State.exchange.publishEvent(ExecStatusEvent("Processing", channelName, exec.execId, Vector()))
|
||||||
val parser = combine(state.definedCommands)
|
val parser = combine(state.definedCommands)
|
||||||
val newState = parse(command.commandLine, parser(state)) match {
|
val newState = parse(exec.commandLine, parser(state)) match {
|
||||||
case Right(s) => s() // apply command. command side effects happen here
|
case Right(s) => s() // apply command. command side effects happen here
|
||||||
case Left(errMsg) =>
|
case Left(errMsg) =>
|
||||||
state.log.error(errMsg)
|
state.log.error(errMsg)
|
||||||
state.fail
|
state.fail
|
||||||
}
|
}
|
||||||
State.exchange.publishEvent(ExecStatusEvent("Ready", newState.remainingCommands.toVector map { _.commandLine }))
|
State.exchange.publishEvent(ExecStatusEvent("Done", channelName, exec.execId, newState.remainingCommands.toVector map { _.commandLine }))
|
||||||
newState
|
newState
|
||||||
}
|
}
|
||||||
def invalidValue(label: String, allowed: Iterable[String])(value: String): String =
|
def invalidValue(label: String, allowed: Iterable[String])(value: String): String =
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ private[sbt] final class ConsoleChannel(val name: String) extends CommandChannel
|
||||||
// This internally handles thread interruption and returns Some("")
|
// This internally handles thread interruption and returns Some("")
|
||||||
val line = reader.readLine(prompt)
|
val line = reader.readLine(prompt)
|
||||||
line match {
|
line match {
|
||||||
case Some(cmd) => append(Exec(cmd, Some(CommandSource(name))))
|
case Some(cmd) => append(Exec(cmd, Some(Exec.newExecId), Some(CommandSource(name))))
|
||||||
case None => append(Exec("exit", Some(CommandSource(name))))
|
case None => append(Exec("exit", Some(Exec.newExecId), Some(CommandSource(name))))
|
||||||
}
|
}
|
||||||
askUserThread = None
|
askUserThread = None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,18 @@ package client
|
||||||
|
|
||||||
import java.net.{ URI, Socket, InetAddress, SocketException }
|
import java.net.{ URI, Socket, InetAddress, SocketException }
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||||
import sbt.protocol._
|
import sbt.protocol._
|
||||||
import sbt.internal.util.JLine
|
import sbt.internal.util.JLine
|
||||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
class NetworkClient(arguments: List[String]) { self =>
|
class NetworkClient(arguments: List[String]) { self =>
|
||||||
private val channelName = new AtomicReference("_")
|
private val channelName = new AtomicReference("_")
|
||||||
private val status = new AtomicReference("Ready")
|
private val status = new AtomicReference("Ready")
|
||||||
private val lock: AnyRef = new AnyRef {}
|
private val lock: AnyRef = new AnyRef {}
|
||||||
private val running = new AtomicBoolean(true)
|
private val running = new AtomicBoolean(true)
|
||||||
|
private val pendingExecIds = ListBuffer.empty[String]
|
||||||
|
|
||||||
def usageError = sys.error("Expecting: sbt client 127.0.0.1:port")
|
def usageError = sys.error("Expecting: sbt client 127.0.0.1:port")
|
||||||
val connection = init()
|
val connection = init()
|
||||||
start()
|
start()
|
||||||
|
|
@ -54,7 +57,14 @@ class NetworkClient(arguments: List[String]) { self =>
|
||||||
println(event)
|
println(event)
|
||||||
case e: ExecStatusEvent =>
|
case e: ExecStatusEvent =>
|
||||||
status.set(e.status)
|
status.set(e.status)
|
||||||
println(event)
|
// println(event)
|
||||||
|
e.execId foreach { execId =>
|
||||||
|
if (e.status == "Done" && (pendingExecIds contains execId)) {
|
||||||
|
lock.synchronized {
|
||||||
|
pendingExecIds -= execId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case e => println(e.toString)
|
case e => println(e.toString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,7 +78,10 @@ class NetworkClient(arguments: List[String]) { self =>
|
||||||
case Some(s) =>
|
case Some(s) =>
|
||||||
val execId = UUID.randomUUID.toString
|
val execId = UUID.randomUUID.toString
|
||||||
publishCommand(ExecCommand(s, execId))
|
publishCommand(ExecCommand(s, execId))
|
||||||
while (status.get != "Ready") {
|
lock.synchronized {
|
||||||
|
pendingExecIds += execId
|
||||||
|
}
|
||||||
|
while (pendingExecIds contains execId) {
|
||||||
Thread.sleep(100)
|
Thread.sleep(100)
|
||||||
}
|
}
|
||||||
case _ => //
|
case _ => //
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ final class NetworkChannel(val name: String, connection: Socket) extends Command
|
||||||
|
|
||||||
def onCommand(command: CommandMessage): Unit =
|
def onCommand(command: CommandMessage): Unit =
|
||||||
command match {
|
command match {
|
||||||
case x: ExecCommand => append(Exec(x.commandLine, Some(CommandSource(name))))
|
case x: ExecCommand => append(Exec(x.commandLine, x.execId orElse Some(Exec.newExecId), Some(CommandSource(name))))
|
||||||
}
|
}
|
||||||
|
|
||||||
def shutdown(): Unit = {
|
def shutdown(): Unit = {
|
||||||
|
|
|
||||||
|
|
@ -7,31 +7,46 @@ package sbt.protocol
|
||||||
/** Status event. */
|
/** Status event. */
|
||||||
final class ExecStatusEvent private (
|
final class ExecStatusEvent private (
|
||||||
val status: String,
|
val status: String,
|
||||||
|
val channelName: Option[String],
|
||||||
|
val execId: Option[String],
|
||||||
val commandQueue: Vector[String]) extends sbt.protocol.EventMessage() with Serializable {
|
val commandQueue: Vector[String]) extends sbt.protocol.EventMessage() with Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override def equals(o: Any): Boolean = o match {
|
override def equals(o: Any): Boolean = o match {
|
||||||
case x: ExecStatusEvent => (this.status == x.status) && (this.commandQueue == x.commandQueue)
|
case x: ExecStatusEvent => (this.status == x.status) && (this.channelName == x.channelName) && (this.execId == x.execId) && (this.commandQueue == x.commandQueue)
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
override def hashCode: Int = {
|
override def hashCode: Int = {
|
||||||
37 * (37 * (17 + status.##) + commandQueue.##)
|
37 * (37 * (37 * (37 * (17 + status.##) + channelName.##) + execId.##) + commandQueue.##)
|
||||||
}
|
}
|
||||||
override def toString: String = {
|
override def toString: String = {
|
||||||
"ExecStatusEvent(" + status + ", " + commandQueue + ")"
|
"ExecStatusEvent(" + status + ", " + channelName + ", " + execId + ", " + commandQueue + ")"
|
||||||
}
|
}
|
||||||
protected[this] def copy(status: String = status, commandQueue: Vector[String] = commandQueue): ExecStatusEvent = {
|
protected[this] def copy(status: String = status, channelName: Option[String] = channelName, execId: Option[String] = execId, commandQueue: Vector[String] = commandQueue): ExecStatusEvent = {
|
||||||
new ExecStatusEvent(status, commandQueue)
|
new ExecStatusEvent(status, channelName, execId, commandQueue)
|
||||||
}
|
}
|
||||||
def withStatus(status: String): ExecStatusEvent = {
|
def withStatus(status: String): ExecStatusEvent = {
|
||||||
copy(status = status)
|
copy(status = status)
|
||||||
}
|
}
|
||||||
|
def withChannelName(channelName: Option[String]): ExecStatusEvent = {
|
||||||
|
copy(channelName = channelName)
|
||||||
|
}
|
||||||
|
def withChannelName(channelName: String): ExecStatusEvent = {
|
||||||
|
copy(channelName = Option(channelName))
|
||||||
|
}
|
||||||
|
def withExecId(execId: Option[String]): ExecStatusEvent = {
|
||||||
|
copy(execId = execId)
|
||||||
|
}
|
||||||
|
def withExecId(execId: String): ExecStatusEvent = {
|
||||||
|
copy(execId = Option(execId))
|
||||||
|
}
|
||||||
def withCommandQueue(commandQueue: Vector[String]): ExecStatusEvent = {
|
def withCommandQueue(commandQueue: Vector[String]): ExecStatusEvent = {
|
||||||
copy(commandQueue = commandQueue)
|
copy(commandQueue = commandQueue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
object ExecStatusEvent {
|
object ExecStatusEvent {
|
||||||
|
|
||||||
def apply(status: String, commandQueue: Vector[String]): ExecStatusEvent = new ExecStatusEvent(status, commandQueue)
|
def apply(status: String, channelName: Option[String], execId: Option[String], commandQueue: Vector[String]): ExecStatusEvent = new ExecStatusEvent(status, channelName, execId, commandQueue)
|
||||||
|
def apply(status: String, channelName: String, execId: String, commandQueue: Vector[String]): ExecStatusEvent = new ExecStatusEvent(status, Option(channelName), Option(execId), commandQueue)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,11 @@ implicit lazy val ExecStatusEventFormat: JsonFormat[sbt.protocol.ExecStatusEvent
|
||||||
case Some(js) =>
|
case Some(js) =>
|
||||||
unbuilder.beginObject(js)
|
unbuilder.beginObject(js)
|
||||||
val status = unbuilder.readField[String]("status")
|
val status = unbuilder.readField[String]("status")
|
||||||
|
val channelName = unbuilder.readField[Option[String]]("channelName")
|
||||||
|
val execId = unbuilder.readField[Option[String]]("execId")
|
||||||
val commandQueue = unbuilder.readField[Vector[String]]("commandQueue")
|
val commandQueue = unbuilder.readField[Vector[String]]("commandQueue")
|
||||||
unbuilder.endObject()
|
unbuilder.endObject()
|
||||||
sbt.protocol.ExecStatusEvent(status, commandQueue)
|
sbt.protocol.ExecStatusEvent(status, channelName, execId, commandQueue)
|
||||||
case None =>
|
case None =>
|
||||||
deserializationError("Expected JsObject but found None")
|
deserializationError("Expected JsObject but found None")
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +24,8 @@ implicit lazy val ExecStatusEventFormat: JsonFormat[sbt.protocol.ExecStatusEvent
|
||||||
override def write[J](obj: sbt.protocol.ExecStatusEvent, builder: Builder[J]): Unit = {
|
override def write[J](obj: sbt.protocol.ExecStatusEvent, builder: Builder[J]): Unit = {
|
||||||
builder.beginObject()
|
builder.beginObject()
|
||||||
builder.addField("status", obj.status)
|
builder.addField("status", obj.status)
|
||||||
|
builder.addField("channelName", obj.channelName)
|
||||||
|
builder.addField("execId", obj.execId)
|
||||||
builder.addField("commandQueue", obj.commandQueue)
|
builder.addField("commandQueue", obj.commandQueue)
|
||||||
builder.endObject()
|
builder.endObject()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ type LogEvent implements EventMessage {
|
||||||
## Status event.
|
## Status event.
|
||||||
type ExecStatusEvent implements EventMessage {
|
type ExecStatusEvent implements EventMessage {
|
||||||
status: String!
|
status: String!
|
||||||
|
channelName: String
|
||||||
|
execId: String
|
||||||
commandQueue: [String]
|
commandQueue: [String]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue