mirror of https://github.com/sbt/sbt.git
Use Exec in State
This commit is contained in:
parent
d96ef58605
commit
1bf50e10c8
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* This code is generated using sbt-datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DO NOT EDIT MANUALLY
|
||||||
|
package sbt
|
||||||
|
final class CommandSource private (
|
||||||
|
val channelName: String) extends Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case x: CommandSource => (this.channelName == x.channelName)
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = {
|
||||||
|
37 * (17 + channelName.##)
|
||||||
|
}
|
||||||
|
override def toString: String = {
|
||||||
|
"CommandSource(" + channelName + ")"
|
||||||
|
}
|
||||||
|
protected[this] def copy(channelName: String = channelName): CommandSource = {
|
||||||
|
new CommandSource(channelName)
|
||||||
|
}
|
||||||
|
def withChannelName(channelName: String): CommandSource = {
|
||||||
|
copy(channelName = channelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object CommandSource {
|
||||||
|
|
||||||
|
def apply(channelName: String): CommandSource = new CommandSource(channelName)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* This code is generated using sbt-datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DO NOT EDIT MANUALLY
|
||||||
|
package sbt
|
||||||
|
final class Exec private (
|
||||||
|
val commandLine: String,
|
||||||
|
val source: Option[sbt.CommandSource]) extends Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case x: Exec => (this.commandLine == x.commandLine) && (this.source == x.source)
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = {
|
||||||
|
37 * (37 * (17 + commandLine.##) + source.##)
|
||||||
|
}
|
||||||
|
override def toString: String = {
|
||||||
|
"Exec(" + commandLine + ", " + source + ")"
|
||||||
|
}
|
||||||
|
protected[this] def copy(commandLine: String = commandLine, source: Option[sbt.CommandSource] = source): Exec = {
|
||||||
|
new Exec(commandLine, source)
|
||||||
|
}
|
||||||
|
def withCommandLine(commandLine: String): Exec = {
|
||||||
|
copy(commandLine = commandLine)
|
||||||
|
}
|
||||||
|
def withSource(source: Option[sbt.CommandSource]): Exec = {
|
||||||
|
copy(source = source)
|
||||||
|
}
|
||||||
|
def withSource(source: sbt.CommandSource): Exec = {
|
||||||
|
copy(source = Option(source))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object Exec {
|
||||||
|
|
||||||
|
def apply(commandLine: String, source: Option[sbt.CommandSource]): Exec = new Exec(commandLine, source)
|
||||||
|
def apply(commandLine: String, source: sbt.CommandSource): Exec = new Exec(commandLine, Option(source))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package sbt
|
||||||
|
@target(Scala)
|
||||||
|
|
||||||
|
type Exec {
|
||||||
|
commandLine: String!
|
||||||
|
source: sbt.CommandSource
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandSource {
|
||||||
|
channelName: String!
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ import sbt.internal.util.complete.{ Completion, Completions, DefaultParsers, His
|
||||||
import sbt.internal.util.Types.{ const, idFun }
|
import sbt.internal.util.Types.{ const, idFun }
|
||||||
import sbt.internal.inc.classpath.ClasspathUtilities.toLoader
|
import sbt.internal.inc.classpath.ClasspathUtilities.toLoader
|
||||||
import sbt.internal.inc.ModuleUtilities
|
import sbt.internal.inc.ModuleUtilities
|
||||||
import sbt.internal.{ Exec, ConsolePromptEvent, ConsoleUnpromptEvent }
|
import sbt.internal.{ ConsolePromptEvent, ConsoleUnpromptEvent }
|
||||||
import sbt.internal.client.NetworkClient
|
import sbt.internal.client.NetworkClient
|
||||||
import DefaultParsers._
|
import DefaultParsers._
|
||||||
import Function.tupled
|
import Function.tupled
|
||||||
|
|
@ -82,13 +82,13 @@ object BasicCommands {
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
def multiParser(s: State): Parser[Seq[String]] =
|
def multiParser(s: State): Parser[List[String]] =
|
||||||
{
|
{
|
||||||
val nonSemi = token(charClass(_ != ';').+, hide = const(true))
|
val nonSemi = token(charClass(_ != ';').+, hide = const(true))
|
||||||
(token(';' ~> OptSpace) flatMap { _ => matched((s.combinedParser & nonSemi) | nonSemi) <~ token(OptSpace) } map (_.trim)).+
|
(token(';' ~> OptSpace) flatMap { _ => matched((s.combinedParser & nonSemi) | nonSemi) <~ token(OptSpace) } map (_.trim)).+ map { _.toList }
|
||||||
}
|
}
|
||||||
|
|
||||||
def multiApplied(s: State) =
|
def multiApplied(s: State): Parser[() => State] =
|
||||||
Command.applyEffect(multiParser(s))(_ ::: s)
|
Command.applyEffect(multiParser(s))(_ ::: s)
|
||||||
|
|
||||||
def multi = Command.custom(multiApplied, Help(Multi, MultiBrief, MultiDetailed))
|
def multi = Command.custom(multiApplied, Help(Multi, MultiBrief, MultiDetailed))
|
||||||
|
|
@ -101,11 +101,11 @@ object BasicCommands {
|
||||||
if (s.remainingCommands.isEmpty) arg :: s else s
|
if (s.remainingCommands.isEmpty) arg :: s else s
|
||||||
}
|
}
|
||||||
def append = Command(AppendCommand, Help.more(AppendCommand, AppendLastDetailed))(otherCommandParser) { (s, arg) =>
|
def append = Command(AppendCommand, Help.more(AppendCommand, AppendLastDetailed))(otherCommandParser) { (s, arg) =>
|
||||||
s.copy(remainingCommands = s.remainingCommands :+ arg)
|
s.copy(remainingCommands = s.remainingCommands :+ Exec(arg, s.source))
|
||||||
}
|
}
|
||||||
|
|
||||||
def setOnFailure = Command(OnFailure, Help.more(OnFailure, OnFailureDetailed))(otherCommandParser) { (s, arg) =>
|
def setOnFailure = Command(OnFailure, Help.more(OnFailure, OnFailureDetailed))(otherCommandParser) { (s, arg) =>
|
||||||
s.copy(onFailure = Some(arg))
|
s.copy(onFailure = Some(Exec(arg, s.source)))
|
||||||
}
|
}
|
||||||
private[sbt] def compatCommands = Seq(
|
private[sbt] def compatCommands = Seq(
|
||||||
Command.command(Compat.ClearOnFailure) { s =>
|
Command.command(Compat.ClearOnFailure) { s =>
|
||||||
|
|
@ -114,7 +114,7 @@ object BasicCommands {
|
||||||
},
|
},
|
||||||
Command.arb(s => token(Compat.OnFailure, hide = const(true)).flatMap(x => otherCommandParser(s))) { (s, arg) =>
|
Command.arb(s => token(Compat.OnFailure, hide = const(true)).flatMap(x => otherCommandParser(s))) { (s, arg) =>
|
||||||
s.log.warn(Compat.OnFailureDeprecated)
|
s.log.warn(Compat.OnFailureDeprecated)
|
||||||
s.copy(onFailure = Some(arg))
|
s.copy(onFailure = Some(Exec(arg, s.source)))
|
||||||
},
|
},
|
||||||
Command.command(Compat.FailureWall) { s =>
|
Command.command(Compat.FailureWall) { s =>
|
||||||
s.log.warn(Compat.FailureWallDeprecated)
|
s.log.warn(Compat.FailureWallDeprecated)
|
||||||
|
|
@ -187,7 +187,7 @@ object BasicCommands {
|
||||||
val line = reader.readLine(prompt)
|
val line = reader.readLine(prompt)
|
||||||
line match {
|
line match {
|
||||||
case Some(line) =>
|
case Some(line) =>
|
||||||
val newState = s.copy(onFailure = Some(Shell), remainingCommands = line +: Shell +: s.remainingCommands).setInteractive(true)
|
val newState = s.copy(onFailure = Some(Exec(Shell, None)), remainingCommands = Exec(line, s.source) +: Exec(Shell, None) +: s.remainingCommands).setInteractive(true)
|
||||||
if (line.trim.isEmpty) newState else newState.clearGlobalLog
|
if (line.trim.isEmpty) newState else newState.clearGlobalLog
|
||||||
case None => s.setInteractive(false)
|
case None => s.setInteractive(false)
|
||||||
}
|
}
|
||||||
|
|
@ -197,9 +197,11 @@ object BasicCommands {
|
||||||
val exchange = State.exchange
|
val exchange = State.exchange
|
||||||
val s1 = exchange.run(s0)
|
val s1 = exchange.run(s0)
|
||||||
exchange.publishEvent(ConsolePromptEvent(s0))
|
exchange.publishEvent(ConsolePromptEvent(s0))
|
||||||
val Exec(line, source) = exchange.blockUntilNextExec
|
val exec: Exec = exchange.blockUntilNextExec
|
||||||
|
val line = exec.commandLine
|
||||||
|
val source = exec.source
|
||||||
println(s"server (line, source): ($line, $source)")
|
println(s"server (line, source): ($line, $source)")
|
||||||
val newState = s1.copy(onFailure = Some(Server), remainingCommands = line +: Server +: s1.remainingCommands).setInteractive(true)
|
val newState = s1.copy(onFailure = Some(Exec(Server, None)), remainingCommands = Exec(line, source) +: Exec(Server, None) +: s1.remainingCommands).setInteractive(true)
|
||||||
exchange.publishEvent(ConsoleUnpromptEvent(source))
|
exchange.publishEvent(ConsoleUnpromptEvent(source))
|
||||||
if (line.trim.isEmpty) newState
|
if (line.trim.isEmpty) newState
|
||||||
else newState.clearGlobalLog
|
else newState.clearGlobalLog
|
||||||
|
|
@ -212,8 +214,8 @@ object BasicCommands {
|
||||||
applyEffect(p)({ inputArg =>
|
applyEffect(p)({ inputArg =>
|
||||||
val arguments = inputArg.toList ++
|
val arguments = inputArg.toList ++
|
||||||
(s0.remainingCommands.toList match {
|
(s0.remainingCommands.toList match {
|
||||||
case "shell" :: Nil => Nil
|
case e :: Nil if e.commandLine == "shell" :: Nil => Nil
|
||||||
case xs => xs
|
case xs => xs map { _.commandLine }
|
||||||
})
|
})
|
||||||
NetworkClient.run(arguments)
|
NetworkClient.run(arguments)
|
||||||
"exit" :: s0.copy(remainingCommands = Nil)
|
"exit" :: s0.copy(remainingCommands = Nil)
|
||||||
|
|
@ -233,7 +235,7 @@ object BasicCommands {
|
||||||
val port = math.abs(portAndSuccess)
|
val port = math.abs(portAndSuccess)
|
||||||
val previousSuccess = portAndSuccess >= 0
|
val previousSuccess = portAndSuccess >= 0
|
||||||
readMessage(port, previousSuccess) match {
|
readMessage(port, previousSuccess) match {
|
||||||
case Some(message) => (message :: (ReadCommand + " " + port) :: s).copy(onFailure = Some(ReadCommand + " " + (-port)))
|
case Some(message) => (message :: (ReadCommand + " " + port) :: s).copy(onFailure = Some(Exec(ReadCommand + " " + (-port), s.source)))
|
||||||
case None =>
|
case None =>
|
||||||
System.err.println("Connection closed.")
|
System.err.println("Connection closed.")
|
||||||
s.fail
|
s.fail
|
||||||
|
|
@ -241,7 +243,7 @@ object BasicCommands {
|
||||||
case Right(from) =>
|
case Right(from) =>
|
||||||
val notFound = notReadable(from)
|
val notFound = notReadable(from)
|
||||||
if (notFound.isEmpty)
|
if (notFound.isEmpty)
|
||||||
readLines(from) ::: s // this means that all commands from all files are loaded, parsed, and inserted before any are executed
|
readLines(from).toList ::: s // this means that all commands from all files are loaded, parsed, and inserted before any are executed
|
||||||
else {
|
else {
|
||||||
s.log.error("Command file(s) not readable: \n\t" + notFound.mkString("\n\t"))
|
s.log.error("Command file(s) not readable: \n\t" + notFound.mkString("\n\t"))
|
||||||
s
|
s
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ object BasicKeys {
|
||||||
val serverPort = AttributeKey[Int]("server-port", "The port number used by server command.", 10000)
|
val serverPort = AttributeKey[Int]("server-port", "The port number used by server command.", 10000)
|
||||||
private[sbt] val interactive = AttributeKey[Boolean]("interactive", "True if commands are currently being entered from an interactive environment.", 10)
|
private[sbt] val interactive = AttributeKey[Boolean]("interactive", "True if commands are currently being entered from an interactive environment.", 10)
|
||||||
private[sbt] val classLoaderCache = AttributeKey[ClassLoaderCache]("class-loader-cache", "Caches class loaders based on the classpath entries and last modified times.", 10)
|
private[sbt] val classLoaderCache = AttributeKey[ClassLoaderCache]("class-loader-cache", "Caches class loaders based on the classpath entries and last modified times.", 10)
|
||||||
private[sbt] val OnFailureStack = AttributeKey[List[Option[String]]]("on-failure-stack", "Stack that remembers on-failure handlers.", 10)
|
private[sbt] val OnFailureStack = AttributeKey[List[Option[Exec]]]("on-failure-stack", "Stack that remembers on-failure handlers.", 10)
|
||||||
private[sbt] val explicitGlobalLogLevels = AttributeKey[Boolean]("explicit-global-log-levels", "True if the global logging levels were explicitly set by the user.", 10)
|
private[sbt] val explicitGlobalLogLevels = AttributeKey[Boolean]("explicit-global-log-levels", "True if the global logging levels were explicitly set by the user.", 10)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,16 +89,16 @@ 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: String, state: State): State =
|
def process(command: Exec, state: State): State =
|
||||||
{
|
{
|
||||||
val parser = combine(state.definedCommands)
|
val parser = combine(state.definedCommands)
|
||||||
val newState = parse(command, parser(state)) match {
|
val newState = parse(command.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))
|
State.exchange.publishEvent(ExecStatusEvent("Ready", 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 =
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,12 @@ final case class State(
|
||||||
configuration: xsbti.AppConfiguration,
|
configuration: xsbti.AppConfiguration,
|
||||||
definedCommands: Seq[Command],
|
definedCommands: Seq[Command],
|
||||||
exitHooks: Set[ExitHook],
|
exitHooks: Set[ExitHook],
|
||||||
onFailure: Option[String],
|
onFailure: Option[Exec],
|
||||||
remainingCommands: Seq[String],
|
remainingCommands: List[Exec],
|
||||||
history: State.History,
|
history: State.History,
|
||||||
attributes: AttributeMap,
|
attributes: AttributeMap,
|
||||||
globalLogging: GlobalLogging,
|
globalLogging: GlobalLogging,
|
||||||
|
source: Option[CommandSource],
|
||||||
next: State.Next
|
next: State.Next
|
||||||
) extends Identity {
|
) extends Identity {
|
||||||
lazy val combinedParser = Command.combine(definedCommands)(this)
|
lazy val combinedParser = Command.combine(definedCommands)(this)
|
||||||
|
|
@ -45,14 +46,20 @@ trait Identity {
|
||||||
|
|
||||||
/** Convenience methods for State transformations and operations. */
|
/** Convenience methods for State transformations and operations. */
|
||||||
trait StateOps {
|
trait StateOps {
|
||||||
def process(f: (String, State) => State): State
|
def process(f: (Exec, State) => State): State
|
||||||
|
|
||||||
/** Schedules `commands` to be run before any remaining commands.*/
|
/** Schedules `commands` to be run before any remaining commands.*/
|
||||||
def :::(commands: Seq[String]): State
|
def :::(newCommands: List[String]): State
|
||||||
|
|
||||||
|
/** Schedules `commands` to be run before any remaining commands.*/
|
||||||
|
def ++:(newCommands: List[Exec]): State
|
||||||
|
|
||||||
/** Schedules `command` to be run before any remaining commands.*/
|
/** Schedules `command` to be run before any remaining commands.*/
|
||||||
def ::(command: String): State
|
def ::(command: String): State
|
||||||
|
|
||||||
|
/** Schedules `command` to be run before any remaining commands.*/
|
||||||
|
def +:(command: Exec): State
|
||||||
|
|
||||||
/** Sets the next command processing action to be to continue processing the next command.*/
|
/** Sets the next command processing action to be to continue processing the next command.*/
|
||||||
def continue: State
|
def continue: State
|
||||||
|
|
||||||
|
|
@ -69,6 +76,9 @@ trait StateOps {
|
||||||
/** Sets the next command processing action to do.*/
|
/** Sets the next command processing action to do.*/
|
||||||
def setNext(n: State.Next): State
|
def setNext(n: State.Next): State
|
||||||
|
|
||||||
|
/** Sets the current command source channel.*/
|
||||||
|
def setSource(source: CommandSource): State
|
||||||
|
|
||||||
@deprecated("Use setNext", "0.11.0") def setResult(ro: Option[xsbti.MainResult]): State
|
@deprecated("Use setNext", "0.11.0") def setResult(ro: Option[xsbti.MainResult]): State
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -158,9 +168,9 @@ object State {
|
||||||
* @param executed the list of the most recently executed commands, with the most recent command first.
|
* @param executed the list of the most recently executed commands, with the most recent command first.
|
||||||
* @param maxSize the maximum number of commands to keep, or 0 to keep an unlimited number.
|
* @param maxSize the maximum number of commands to keep, or 0 to keep an unlimited number.
|
||||||
*/
|
*/
|
||||||
final class History private[State] (val executed: Seq[String], val maxSize: Int) {
|
final class History private[State] (val executed: Seq[Exec], val maxSize: Int) {
|
||||||
/** Adds `command` as the most recently executed command.*/
|
/** Adds `command` as the most recently executed command.*/
|
||||||
def ::(command: String): History =
|
def ::(command: Exec): History =
|
||||||
{
|
{
|
||||||
val prependTo = if (maxSize > 0 && executed.size >= maxSize) executed.take(maxSize - 1) else executed
|
val prependTo = if (maxSize > 0 && executed.size >= maxSize) executed.take(maxSize - 1) else executed
|
||||||
new History(command +: prependTo, maxSize)
|
new History(command +: prependTo, maxSize)
|
||||||
|
|
@ -168,8 +178,8 @@ object State {
|
||||||
/** Changes the maximum number of commands kept, adjusting the current history if necessary.*/
|
/** Changes the maximum number of commands kept, adjusting the current history if necessary.*/
|
||||||
def setMaxSize(size: Int): History =
|
def setMaxSize(size: Int): History =
|
||||||
new History(if (size <= 0) executed else executed.take(size), size)
|
new History(if (size <= 0) executed else executed.take(size), size)
|
||||||
def currentOption: Option[String] = executed.headOption
|
def currentOption: Option[Exec] = executed.headOption
|
||||||
def previous: Option[String] = executed.drop(1).headOption
|
def previous: Option[Exec] = executed.drop(1).headOption
|
||||||
}
|
}
|
||||||
/** Constructs an empty command History with a default, finite command limit.*/
|
/** Constructs an empty command History with a default, finite command limit.*/
|
||||||
def newHistory = new History(Vector.empty, HistoryCommands.MaxLines)
|
def newHistory = new History(Vector.empty, HistoryCommands.MaxLines)
|
||||||
|
|
@ -177,29 +187,37 @@ object State {
|
||||||
def defaultReload(state: State): Reboot =
|
def defaultReload(state: State): Reboot =
|
||||||
{
|
{
|
||||||
val app = state.configuration.provider
|
val app = state.configuration.provider
|
||||||
new Reboot(app.scalaProvider.version, state.remainingCommands, app.id, state.configuration.baseDirectory)
|
new Reboot(
|
||||||
|
app.scalaProvider.version,
|
||||||
|
state.remainingCommands map { case e: Exec => e.commandLine },
|
||||||
|
app.id, state.configuration.baseDirectory
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[sbt] lazy val exchange = new CommandExchange()
|
private[sbt] lazy val exchange = new CommandExchange()
|
||||||
|
|
||||||
/** Provides operations and transformations on State. */
|
/** Provides operations and transformations on State. */
|
||||||
implicit def stateOps(s: State): StateOps = new StateOps {
|
implicit def stateOps(s: State): StateOps = new StateOps {
|
||||||
def process(f: (String, State) => State): State =
|
def process(f: (Exec, State) => State): State =
|
||||||
s.remainingCommands match {
|
s.remainingCommands match {
|
||||||
case Seq() => exit(true)
|
case List() => exit(true)
|
||||||
case Seq(x, xs @ _*) =>
|
case x :: xs =>
|
||||||
log.debug(s"> $x")
|
log.debug(s"> $x")
|
||||||
f(x, s.copy(remainingCommands = xs, history = x :: s.history))
|
f(x, s.copy(remainingCommands = xs, history = x :: s.history))
|
||||||
}
|
}
|
||||||
def :::(newCommands: Seq[String]): State = s.copy(remainingCommands = newCommands ++ s.remainingCommands)
|
|
||||||
def ::(command: String): State = (command :: Nil) ::: this
|
def :::(newCommands: List[String]): State = ++:(newCommands map { Exec(_, s.source) })
|
||||||
|
def ++:(newCommands: List[Exec]): State = s.copy(remainingCommands = newCommands ::: s.remainingCommands)
|
||||||
|
def ::(command: String): State = +:(Exec(command, s.source))
|
||||||
|
def +:(command: Exec): State = (command :: Nil) ++: this
|
||||||
def ++(newCommands: Seq[Command]): State = s.copy(definedCommands = (s.definedCommands ++ newCommands).distinct)
|
def ++(newCommands: Seq[Command]): State = s.copy(definedCommands = (s.definedCommands ++ newCommands).distinct)
|
||||||
def +(newCommand: Command): State = this ++ (newCommand :: Nil)
|
def +(newCommand: Command): State = this ++ (newCommand :: Nil)
|
||||||
def baseDir: File = s.configuration.baseDirectory
|
def baseDir: File = s.configuration.baseDirectory
|
||||||
def setNext(n: Next) = s.copy(next = n)
|
def setNext(n: Next) = s.copy(next = n)
|
||||||
|
def setSource(x: CommandSource): State = s.copy(source = Some(x))
|
||||||
def setResult(ro: Option[xsbti.MainResult]) = ro match { case None => continue; case Some(r) => setNext(new Return(r)) }
|
def setResult(ro: Option[xsbti.MainResult]) = ro match { case None => continue; case Some(r) => setNext(new Return(r)) }
|
||||||
def continue = setNext(Continue)
|
def continue = setNext(Continue)
|
||||||
def reboot(full: Boolean) = { runExitHooks(); throw new xsbti.FullReload(s.remainingCommands.toArray, full) }
|
def reboot(full: Boolean) = { runExitHooks(); throw new xsbti.FullReload((s.remainingCommands map { case e: Exec => e.commandLine }).toArray, full) }
|
||||||
def reload = runExitHooks().setNext(new Return(defaultReload(s)))
|
def reload = runExitHooks().setNext(new Return(defaultReload(s)))
|
||||||
def clearGlobalLog = setNext(ClearGlobalLog)
|
def clearGlobalLog = setNext(ClearGlobalLog)
|
||||||
def keepLastLog = setNext(KeepLastLog)
|
def keepLastLog = setNext(KeepLastLog)
|
||||||
|
|
@ -220,7 +238,7 @@ object State {
|
||||||
else
|
else
|
||||||
applyOnFailure(s, remaining, s.copy(remainingCommands = remaining))
|
applyOnFailure(s, remaining, s.copy(remainingCommands = remaining))
|
||||||
}
|
}
|
||||||
private[this] def applyOnFailure(s: State, remaining: Seq[String], noHandler: => State): State =
|
private[this] def applyOnFailure(s: State, remaining: List[Exec], noHandler: => State): State =
|
||||||
s.onFailure match {
|
s.onFailure match {
|
||||||
case Some(c) => s.copy(remainingCommands = c +: remaining, onFailure = None)
|
case Some(c) => s.copy(remainingCommands = c +: remaining, onFailure = None)
|
||||||
case None => noHandler
|
case None => noHandler
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,12 @@ abstract class CommandChannel {
|
||||||
def publishEvent(event: EventMessage): Unit
|
def publishEvent(event: EventMessage): Unit
|
||||||
def publishBytes(bytes: Array[Byte]): Unit
|
def publishBytes(bytes: Array[Byte]): Unit
|
||||||
def shutdown(): Unit
|
def shutdown(): Unit
|
||||||
|
def name: String
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Exec(commandLine: String, source: Option[CommandSource])
|
// case class Exec(commandLine: String, source: Option[CommandSource])
|
||||||
|
|
||||||
case class CommandSource(channelName: String)
|
// case class CommandSource(channelName: String)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a data passed specifically for local prompting console.
|
* This is a data passed specifically for local prompting console.
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import java.net.SocketException
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import sbt.internal.server._
|
import sbt.internal.server._
|
||||||
import sbt.protocol.{ EventMessage, Serialization }
|
import sbt.protocol.{ EventMessage, Serialization, ChannelAcceptedEvent }
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import BasicKeys.serverPort
|
import BasicKeys.serverPort
|
||||||
|
|
@ -74,6 +74,7 @@ private[sbt] final class CommandExchange {
|
||||||
s.log.info(s"new client connected from: ${socket.getPort}")
|
s.log.info(s"new client connected from: ${socket.getPort}")
|
||||||
val channel = new NetworkChannel(newChannelName, socket)
|
val channel = new NetworkChannel(newChannelName, socket)
|
||||||
subscribe(channel)
|
subscribe(channel)
|
||||||
|
channel.publishEvent(ChannelAcceptedEvent(channel.name))
|
||||||
}
|
}
|
||||||
server match {
|
server match {
|
||||||
case Some(x) => // do nothing
|
case Some(x) => // do nothing
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import BasicKeys._
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import sbt.protocol.EventMessage
|
import sbt.protocol.EventMessage
|
||||||
|
|
||||||
private[sbt] final class ConsoleChannel(name: String) extends CommandChannel {
|
private[sbt] final class ConsoleChannel(val name: String) extends CommandChannel {
|
||||||
private var askUserThread: Option[Thread] = None
|
private var askUserThread: Option[Thread] = None
|
||||||
def makeAskUserThread(s: State): Thread = new Thread("ask-user-thread") {
|
def makeAskUserThread(s: State): Thread = new Thread("ask-user-thread") {
|
||||||
val history = (s get historyPath) getOrElse Some(new File(s.baseDir, ".history"))
|
val history = (s get historyPath) getOrElse Some(new File(s.baseDir, ".history"))
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import sbt.protocol._
|
||||||
import sbt.internal.util.JLine
|
import sbt.internal.util.JLine
|
||||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||||
|
|
||||||
class NetworkClient(arguments: List[String]) {
|
class NetworkClient(arguments: List[String]) { self =>
|
||||||
|
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)
|
||||||
|
|
@ -38,15 +39,7 @@ class NetworkClient(arguments: List[String]) {
|
||||||
println(s"client on port $port")
|
println(s"client on port $port")
|
||||||
val socket = new Socket(InetAddress.getByName(host), port)
|
val socket = new Socket(InetAddress.getByName(host), port)
|
||||||
new ServerConnection(socket) {
|
new ServerConnection(socket) {
|
||||||
override def onEvent(event: EventMessage): Unit =
|
override def onEvent(event: EventMessage): Unit = self.onEvent(event)
|
||||||
event match {
|
|
||||||
case e: ExecStatusEvent =>
|
|
||||||
lock.synchronized {
|
|
||||||
status.set(e.status)
|
|
||||||
}
|
|
||||||
println(event)
|
|
||||||
case e => println(e.toString)
|
|
||||||
}
|
|
||||||
override def onShutdown(): Unit =
|
override def onShutdown(): Unit =
|
||||||
{
|
{
|
||||||
running.set(false)
|
running.set(false)
|
||||||
|
|
@ -54,6 +47,17 @@ class NetworkClient(arguments: List[String]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def onEvent(event: EventMessage): Unit =
|
||||||
|
event match {
|
||||||
|
case e: ChannelAcceptedEvent =>
|
||||||
|
channelName.set(e.channelName)
|
||||||
|
println(event)
|
||||||
|
case e: ExecStatusEvent =>
|
||||||
|
status.set(e.status)
|
||||||
|
println(event)
|
||||||
|
case e => println(e.toString)
|
||||||
|
}
|
||||||
|
|
||||||
def start(): Unit =
|
def start(): Unit =
|
||||||
{
|
{
|
||||||
val reader = JLine.simple(None, JLine.HandleCONT, injectThreadSleep = true)
|
val reader = JLine.simple(None, JLine.HandleCONT, injectThreadSleep = true)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import java.net.{ Socket, SocketTimeoutException }
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import sbt.protocol.{ Serialization, CommandMessage, ExecCommand, EventMessage }
|
import sbt.protocol.{ Serialization, CommandMessage, ExecCommand, EventMessage }
|
||||||
|
|
||||||
final class NetworkChannel(name: String, connection: Socket) extends CommandChannel {
|
final class NetworkChannel(val name: String, connection: Socket) extends CommandChannel {
|
||||||
private val running = new AtomicBoolean(true)
|
private val running = new AtomicBoolean(true)
|
||||||
private val delimiter: Byte = '\n'.toByte
|
private val delimiter: Byte = '\n'.toByte
|
||||||
private val out = connection.getOutputStream
|
private val out = connection.getOutputStream
|
||||||
|
|
@ -50,7 +50,11 @@ final class NetworkChannel(name: String, connection: Socket) extends CommandChan
|
||||||
}
|
}
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
def publishEvent(event: EventMessage): Unit = ()
|
def publishEvent(event: EventMessage): Unit =
|
||||||
|
{
|
||||||
|
val bytes = Serialization.serializeEvent(event)
|
||||||
|
publishBytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
def publishBytes(event: Array[Byte]): Unit =
|
def publishBytes(event: Array[Byte]): Unit =
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ object Cross {
|
||||||
Seq(s"$SwitchCommand $verbose $version", projects.map(_ + "/" + aggCommand).mkString("all ", " ", ""))
|
Seq(s"$SwitchCommand $verbose $version", projects.map(_ + "/" + aggCommand).mkString("all ", " ", ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
allCommands ::: CrossRestoreSessionCommand :: captureCurrentSession(state, x)
|
allCommands.toList ::: CrossRestoreSessionCommand :: captureCurrentSession(state, x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,7 +169,7 @@ object Cross {
|
||||||
private def switchCommandImpl(state: State, args: Switch): State = {
|
private def switchCommandImpl(state: State, args: Switch): State = {
|
||||||
val switchedState = switchScalaVersion(args, state)
|
val switchedState = switchScalaVersion(args, state)
|
||||||
|
|
||||||
args.command.toSeq ::: switchedState
|
args.command.toList ::: switchedState
|
||||||
}
|
}
|
||||||
|
|
||||||
private def switchScalaVersion(switch: Switch, state: State): State = {
|
private def switchScalaVersion(switch: Switch, state: State): State = {
|
||||||
|
|
|
||||||
|
|
@ -94,9 +94,9 @@ object StandardMain {
|
||||||
import BasicCommandStrings.isEarlyCommand
|
import BasicCommandStrings.isEarlyCommand
|
||||||
val userCommands = configuration.arguments.map(_.trim)
|
val userCommands = configuration.arguments.map(_.trim)
|
||||||
val (earlyCommands, normalCommands) = (preCommands ++ userCommands).partition(isEarlyCommand)
|
val (earlyCommands, normalCommands) = (preCommands ++ userCommands).partition(isEarlyCommand)
|
||||||
val commands = earlyCommands ++ normalCommands
|
val commands = (earlyCommands ++ normalCommands).toList map { x => Exec(x, None) }
|
||||||
val initAttrs = BuiltinCommands.initialAttributes
|
val initAttrs = BuiltinCommands.initialAttributes
|
||||||
val s = State(configuration, initialDefinitions, Set.empty, None, commands, State.newHistory, initAttrs, initialGlobalLogging, State.Continue)
|
val s = State(configuration, initialDefinitions, Set.empty, None, commands, State.newHistory, initAttrs, initialGlobalLogging, None, State.Continue)
|
||||||
s.initializeClassLoaderCache
|
s.initializeClassLoaderCache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +129,7 @@ object BuiltinCommands {
|
||||||
// This parser schedules the default boot commands unless overridden by an alias
|
// This parser schedules the default boot commands unless overridden by an alias
|
||||||
def bootParser(s: State) =
|
def bootParser(s: State) =
|
||||||
{
|
{
|
||||||
val orElse = () => DefaultBootCommands ::: s
|
val orElse = () => DefaultBootCommands.toList ::: s
|
||||||
delegateToAlias(BootCommand, success(orElse))(s)
|
delegateToAlias(BootCommand, success(orElse))(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,7 +242,7 @@ object BuiltinCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
def initialize = Command.command(InitCommand) { s =>
|
def initialize = Command.command(InitCommand) { s =>
|
||||||
/*"load-commands -base ~/.sbt/commands" :: */ readLines(readable(sbtRCs(s))) ::: s
|
/*"load-commands -base ~/.sbt/commands" :: */ readLines(readable(sbtRCs(s))).toList ::: s
|
||||||
}
|
}
|
||||||
|
|
||||||
def eval = Command.single(EvalCommand, Help.more(EvalCommand, evalDetailed)) { (s, arg) =>
|
def eval = Command.single(EvalCommand, Help.more(EvalCommand, evalDetailed)) { (s, arg) =>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ object IvyConsole {
|
||||||
final val Name = "ivy-console"
|
final val Name = "ivy-console"
|
||||||
lazy val command =
|
lazy val command =
|
||||||
Command.command(Name) { state =>
|
Command.command(Name) { state =>
|
||||||
val Dependencies(managed, repos, unmanaged) = parseDependencies(state.remainingCommands, state.log)
|
val Dependencies(managed, repos, unmanaged) = parseDependencies(state.remainingCommands map { _.commandLine }, state.log)
|
||||||
val base = new File(CommandUtil.bootDirectory(state), Name)
|
val base = new File(CommandUtil.bootDirectory(state), Name)
|
||||||
IO.createDirectory(base)
|
IO.createDirectory(base)
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ object IvyConsole {
|
||||||
val append = Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, depSettings)
|
val append = Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, depSettings)
|
||||||
|
|
||||||
val newStructure = Load.reapply(session.original ++ append, structure)
|
val newStructure = Load.reapply(session.original ++ append, structure)
|
||||||
val newState = state.copy(remainingCommands = "console-quick" :: Nil)
|
val newState = state.copy(remainingCommands = Exec("console-quick", None) :: Nil)
|
||||||
Project.setProject(session, newStructure, newState)
|
Project.setProject(session, newStructure, newState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ object Script {
|
||||||
final val Name = "script"
|
final val Name = "script"
|
||||||
lazy val command =
|
lazy val command =
|
||||||
Command.command(Name) { state =>
|
Command.command(Name) { state =>
|
||||||
val scriptArg = state.remainingCommands.headOption getOrElse sys.error("No script file specified")
|
val scriptArg = state.remainingCommands.headOption map { _.commandLine } getOrElse sys.error("No script file specified")
|
||||||
val scriptFile = new File(scriptArg).getAbsoluteFile
|
val scriptFile = new File(scriptArg).getAbsoluteFile
|
||||||
val hash = Hash.halve(Hash.toHex(Hash(scriptFile.getAbsolutePath)))
|
val hash = Hash.halve(Hash.toHex(Hash(scriptFile.getAbsolutePath)))
|
||||||
val base = new File(CommandUtil.bootDirectory(state), hash)
|
val base = new File(CommandUtil.bootDirectory(state), hash)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* This code is generated using sbt-datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DO NOT EDIT MANUALLY
|
||||||
|
package sbt.protocol
|
||||||
|
final class ChannelAcceptedEvent private (
|
||||||
|
val channelName: String) extends sbt.protocol.EventMessage() with Serializable {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case x: ChannelAcceptedEvent => (this.channelName == x.channelName)
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = {
|
||||||
|
37 * (17 + channelName.##)
|
||||||
|
}
|
||||||
|
override def toString: String = {
|
||||||
|
"ChannelAcceptedEvent(" + channelName + ")"
|
||||||
|
}
|
||||||
|
protected[this] def copy(channelName: String = channelName): ChannelAcceptedEvent = {
|
||||||
|
new ChannelAcceptedEvent(channelName)
|
||||||
|
}
|
||||||
|
def withChannelName(channelName: String): ChannelAcceptedEvent = {
|
||||||
|
copy(channelName = channelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object ChannelAcceptedEvent {
|
||||||
|
|
||||||
|
def apply(channelName: String): ChannelAcceptedEvent = new ChannelAcceptedEvent(channelName)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* This code is generated using sbt-datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DO NOT EDIT MANUALLY
|
||||||
|
package sbt.protocol.codec
|
||||||
|
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||||
|
trait ChannelAcceptedEventFormats { self: sjsonnew.BasicJsonProtocol =>
|
||||||
|
implicit lazy val ChannelAcceptedEventFormat: JsonFormat[sbt.protocol.ChannelAcceptedEvent] = new JsonFormat[sbt.protocol.ChannelAcceptedEvent] {
|
||||||
|
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.protocol.ChannelAcceptedEvent = {
|
||||||
|
jsOpt match {
|
||||||
|
case Some(js) =>
|
||||||
|
unbuilder.beginObject(js)
|
||||||
|
val channelName = unbuilder.readField[String]("channelName")
|
||||||
|
unbuilder.endObject()
|
||||||
|
sbt.protocol.ChannelAcceptedEvent(channelName)
|
||||||
|
case None =>
|
||||||
|
deserializationError("Expected JsObject but found None")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override def write[J](obj: sbt.protocol.ChannelAcceptedEvent, builder: Builder[J]): Unit = {
|
||||||
|
builder.beginObject()
|
||||||
|
builder.addField("channelName", obj.channelName)
|
||||||
|
builder.endObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,6 @@
|
||||||
// DO NOT EDIT MANUALLY
|
// DO NOT EDIT MANUALLY
|
||||||
package sbt.protocol.codec
|
package sbt.protocol.codec
|
||||||
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
|
||||||
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats =>
|
trait EventMessageFormats { self: sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ChannelAcceptedEventFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats =>
|
||||||
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat2[sbt.protocol.EventMessage, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent]("type")
|
implicit lazy val EventMessageFormat: JsonFormat[sbt.protocol.EventMessage] = flatUnionFormat3[sbt.protocol.EventMessage, sbt.protocol.ChannelAcceptedEvent, sbt.protocol.LogEvent, sbt.protocol.ExecStatusEvent]("type")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@
|
||||||
|
|
||||||
// DO NOT EDIT MANUALLY
|
// DO NOT EDIT MANUALLY
|
||||||
package sbt.protocol.codec
|
package sbt.protocol.codec
|
||||||
trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ExecCommandFormats with sbt.protocol.codec.CommandMessageFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats with sbt.protocol.codec.EventMessageFormats
|
trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.protocol.codec.ExecCommandFormats with sbt.protocol.codec.CommandMessageFormats with sbt.protocol.codec.ChannelAcceptedEventFormats with sbt.protocol.codec.LogEventFormats with sbt.protocol.codec.ExecStatusEventFormats with sbt.protocol.codec.EventMessageFormats
|
||||||
object JsonProtocol extends JsonProtocol
|
object JsonProtocol extends JsonProtocol
|
||||||
|
|
@ -17,6 +17,10 @@ type ExecCommand implements CommandMessage {
|
||||||
interface EventMessage {
|
interface EventMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChannelAcceptedEvent implements EventMessage {
|
||||||
|
channelName: String!
|
||||||
|
}
|
||||||
|
|
||||||
## Log event.
|
## Log event.
|
||||||
type LogEvent implements EventMessage {
|
type LogEvent implements EventMessage {
|
||||||
level: String!
|
level: String!
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue