diff --git a/main-command/src/main/scala/sbt/BasicCommands.scala b/main-command/src/main/scala/sbt/BasicCommands.scala index dab50cf5be..c0f8a708d9 100644 --- a/main-command/src/main/scala/sbt/BasicCommands.scala +++ b/main-command/src/main/scala/sbt/BasicCommands.scala @@ -21,7 +21,7 @@ import scala.util.control.NonFatal object BasicCommands { lazy val allBasicCommands = Seq(nop, ignore, help, completionsCommand, multi, ifLast, append, setOnFailure, clearOnFailure, - stashOnFailure, popOnFailure, reboot, call, early, exit, continuous, history, shell, server, client, read, alias) ++ compatCommands + stashOnFailure, popOnFailure, reboot, call, early, exit, continuous, history, shell, client, read, alias) ++ compatCommands def nop = Command.custom(s => success(() => s)) def ignore = Command.command(FailureWall)(idFun) @@ -193,17 +193,6 @@ object BasicCommands { } } - def server = Command.command(Server, Help.more(Server, ServerDetailed)) { s0 => - val exchange = State.exchange - val s1 = exchange.run(s0) - exchange.publishEventMessage(ConsolePromptEvent(s0)) - val exec: Exec = exchange.blockUntilNextExec - val newState = s1.copy(onFailure = Some(Exec(Server, None)), remainingCommands = exec +: Exec(Server, None) +: s1.remainingCommands).setInteractive(true) - exchange.publishEventMessage(ConsoleUnpromptEvent(exec.source)) - if (exec.commandLine.trim.isEmpty) newState - else newState.clearGlobalLog - } - def client = Command.make(Client, Help.more(Client, ClientDetailed))(clientParser) def clientParser(s0: State) = { diff --git a/main-command/src/main/scala/sbt/Command.scala b/main-command/src/main/scala/sbt/Command.scala index 1bed5a9be0..af6d082926 100644 --- a/main-command/src/main/scala/sbt/Command.scala +++ b/main-command/src/main/scala/sbt/Command.scala @@ -88,21 +88,6 @@ object Command { } } - /** This is the main function State transfer function of the sbt command processing, called by MainLoop.next, */ - def process(exec: Exec, state: State): State = - { - val channelName = exec.source map { _.channelName } - State.exchange.publishEventMessage(ExecStatusEvent("Processing", channelName, exec.execId, Vector())) - val parser = combine(state.definedCommands) - val newState = parse(exec.commandLine, parser(state)) match { - case Right(s) => s() // apply command. command side effects happen here - case Left(errMsg) => - state.log.error(errMsg) - state.fail - } - State.exchange.publishEventMessage(ExecStatusEvent("Done", channelName, exec.execId, newState.remainingCommands.toVector map { _.commandLine })) - newState - } def invalidValue(label: String, allowed: Iterable[String])(value: String): String = "Not a valid " + label + ": " + value + similar(value, allowed) def similar(value: String, allowed: Iterable[String]): String = diff --git a/main-command/src/main/scala/sbt/State.scala b/main-command/src/main/scala/sbt/State.scala index e08bbc5b62..9cee3f7258 100644 --- a/main-command/src/main/scala/sbt/State.scala +++ b/main-command/src/main/scala/sbt/State.scala @@ -8,7 +8,6 @@ import java.util.concurrent.Callable import sbt.util.Logger import sbt.internal.util.{ AttributeKey, AttributeMap, ErrorHandling, ExitHook, ExitHooks, GlobalLogging } import sbt.internal.util.complete.HistoryCommands -import sbt.internal.CommandExchange import sbt.internal.inc.classpath.ClassLoaderCache /** @@ -195,8 +194,6 @@ object State { ) } - private[sbt] lazy val exchange = new CommandExchange() - /** Provides operations and transformations on State. */ implicit def stateOps(s: State): StateOps = new StateOps { def process(f: (Exec, State) => State): State = diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 3e02a4b2fa..ecee9d5be1 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -8,6 +8,7 @@ import sbt.internal.{ Aggregation, BuildStructure, BuildUnit, + CommandExchange, CommandStrings, EvaluateConfigurations, Inspect, @@ -78,6 +79,8 @@ final class ConsoleMain extends xsbti.AppMain { } object StandardMain { + private[sbt] lazy val exchange = new CommandExchange() + def runManaged(s: State): xsbti.MainResult = { val previous = TrapExit.installManager() @@ -117,7 +120,7 @@ object BuiltinCommands { def DefaultCommands: Seq[Command] = Seq(ignore, help, completionsCommand, about, tasks, settingsCommand, loadProject, templateCommand, projects, project, reboot, read, history, set, sessionCommand, inspect, loadProjectImpl, loadFailed, Cross.crossBuild, Cross.switchVersion, Cross.crossRestoreSession, setOnFailure, clearOnFailure, stashOnFailure, popOnFailure, setLogLevel, plugin, plugins, - ifLast, multi, shell, BasicCommands.server, BasicCommands.client, continuous, eval, alias, append, last, lastGrep, export, boot, nop, call, exit, early, initialize, act) ++ + ifLast, multi, shell, server, BasicCommands.client, continuous, eval, alias, append, last, lastGrep, export, boot, nop, call, exit, early, initialize, act) ++ compatCommands def DefaultBootCommands: Seq[String] = LoadProject :: (IfLast + " " + Shell) :: Nil @@ -544,4 +547,16 @@ object BuiltinCommands { } s.put(Keys.stateCompilerCache, cache) } + + def server = Command.command(Server, Help.more(Server, ServerDetailed)) { s0 => + import sbt.internal.{ ConsolePromptEvent, ConsoleUnpromptEvent } + val exchange = StandardMain.exchange + val s1 = exchange run s0 + exchange publishEventMessage ConsolePromptEvent(s0) + val exec: Exec = exchange.blockUntilNextExec + val newState = s1.copy(onFailure = Some(Exec(Server, None)), remainingCommands = exec +: Exec(Server, None) +: s1.remainingCommands).setInteractive(true) + exchange publishEventMessage ConsoleUnpromptEvent(exec.source) + if (exec.commandLine.trim.isEmpty) newState + else newState.clearGlobalLog + } } diff --git a/main-command/src/main/scala/sbt/MainLoop.scala b/main/src/main/scala/sbt/MainLoop.scala similarity index 83% rename from main-command/src/main/scala/sbt/MainLoop.scala rename to main/src/main/scala/sbt/MainLoop.scala index db07d48c78..767dfd48de 100644 --- a/main-command/src/main/scala/sbt/MainLoop.scala +++ b/main/src/main/scala/sbt/MainLoop.scala @@ -9,7 +9,9 @@ import jline.TerminalFactory import sbt.io.Using import sbt.internal.util.{ ErrorHandling, GlobalLogBacking, GlobalLogging } +import sbt.internal.util.complete.DefaultParsers import sbt.util.{ AbstractLogger, Logger } +import sbt.protocol._ object MainLoop { /** Entry point to run the remaining commands in State with managed global logging.*/ @@ -98,12 +100,28 @@ object MainLoop { } def next(state: State): State = - ErrorHandling.wideConvert { state.process(Command.process) } match { + ErrorHandling.wideConvert { state.process(processCommand) } match { case Right(s) => s case Left(t: xsbti.FullReload) => throw t case Left(t) => state.handleError(t) } + /** This is the main function State transfer function of the sbt command processing. */ + def processCommand(exec: Exec, state: State): State = { + import DefaultParsers._ + val channelName = exec.source map (_.channelName) + StandardMain.exchange publishEventMessage ExecStatusEvent("Processing", channelName, exec.execId, Vector()) + val parser = Command combine state.definedCommands + val newState = parse(exec.commandLine, parser(state)) match { + case Right(s) => s() // apply command. command side effects happen here + case Left(errMsg) => + state.log error errMsg + state.fail + } + StandardMain.exchange publishEventMessage ExecStatusEvent("Done", channelName, exec.execId, newState.remainingCommands.toVector map (_.commandLine)) + newState + } + @deprecated("Use State.handleError", "0.13.0") def handleException(e: Throwable, s: State): State = s.handleError(e) diff --git a/main-command/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala similarity index 100% rename from main-command/src/main/scala/sbt/internal/CommandExchange.scala rename to main/src/main/scala/sbt/internal/CommandExchange.scala diff --git a/main-command/src/main/scala/sbt/internal/RelayAppender.scala b/main/src/main/scala/sbt/internal/RelayAppender.scala similarity index 87% rename from main-command/src/main/scala/sbt/internal/RelayAppender.scala rename to main/src/main/scala/sbt/internal/RelayAppender.scala index 201c1aad57..704b528f84 100644 --- a/main-command/src/main/scala/sbt/internal/RelayAppender.scala +++ b/main/src/main/scala/sbt/internal/RelayAppender.scala @@ -26,10 +26,10 @@ class RelayAppender(name: String) extends AbstractAppender(name, null, PatternLa } } def appendLog(level: Level.Value, message: => String): Unit = { - State.exchange.publishEventMessage(LogEvent(level.toString, message)) + StandardMain.exchange.publishEventMessage(LogEvent(level.toString, message)) } def appendEvent(level: Level.Value, event: AnyRef): Unit = event match { - case x: ChannelLogEntry => State.exchange.publishEvent(x: AbstractEntry) + case x: ChannelLogEntry => StandardMain.exchange.publishEvent(x: AbstractEntry) } } diff --git a/main-command/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala similarity index 100% rename from main-command/src/main/scala/sbt/internal/server/NetworkChannel.scala rename to main/src/main/scala/sbt/internal/server/NetworkChannel.scala diff --git a/main/src/test/scala/PluginCommandTest.scala b/main/src/test/scala/PluginCommandTest.scala index 2626194631..e21f36361e 100644 --- a/main/src/test/scala/PluginCommandTest.scala +++ b/main/src/test/scala/PluginCommandTest.scala @@ -52,7 +52,7 @@ object FakeState { try { System.setOut(new PrintStream(outBuffer, true)) val state = FakeState(enabledPlugins: _*) - Command.process(Exec(input, None), state) + MainLoop.processCommand(Exec(input, None), state) new String(outBuffer.toByteArray) } finally { System.setOut(previousOut)