mirror of https://github.com/sbt/sbt.git
Refactor to abstract listening for command line
This commit is contained in:
parent
649dc0ce3c
commit
f9dd8b73b7
13
build.sbt
13
build.sbt
|
|
@ -176,12 +176,11 @@ lazy val actionsProj = (project in file("main-actions")).
|
|||
|
||||
// General command support and core commands not specific to a build system
|
||||
lazy val commandProj = (project in file("main-command")).
|
||||
dependsOn(serverProj).
|
||||
settings(
|
||||
testedBaseSettings,
|
||||
name := "Command",
|
||||
libraryDependencies ++= Seq(launcherInterface, compilerInterface,
|
||||
sbtIO, utilLogging, utilCompletion, compilerClasspath)
|
||||
sbtIO, utilLogging, utilCompletion, compilerClasspath, json4s, json4sNative) // to transitively get json4s)
|
||||
)
|
||||
|
||||
// Fixes scope=Scope for Setting (core defined in collectionProj) to define the settings system used in build definitions
|
||||
|
|
@ -194,15 +193,9 @@ lazy val mainSettingsProj = (project in file("main-settings")).
|
|||
utilLogging, sbtIO, utilCompletion, compilerClasspath, libraryManagement)
|
||||
)
|
||||
|
||||
lazy val serverProj = (project in mainPath / "server").
|
||||
settings(
|
||||
baseSettings,
|
||||
libraryDependencies ++= Seq(json4s, json4sNative) // to transitively get json4s
|
||||
)
|
||||
|
||||
// The main integration project for sbt. It brings all of the Projsystems together, configures them, and provides for overriding conventions.
|
||||
lazy val mainProj = (project in file("main")).
|
||||
dependsOn(actionsProj, mainSettingsProj, runProj, commandProj, serverProj).
|
||||
dependsOn(actionsProj, mainSettingsProj, runProj, commandProj).
|
||||
settings(
|
||||
testedBaseSettings,
|
||||
name := "Main",
|
||||
|
|
@ -251,7 +244,7 @@ lazy val myProvided = config("provided") intransitive
|
|||
def allProjects = Seq(
|
||||
testingProj, testAgentProj, taskProj, stdTaskProj, runProj,
|
||||
scriptedSbtProj, scriptedPluginProj,
|
||||
actionsProj, commandProj, mainSettingsProj, serverProj, mainProj, sbtProj, bundledLauncherProj)
|
||||
actionsProj, commandProj, mainSettingsProj, mainProj, sbtProj, bundledLauncherProj)
|
||||
|
||||
def projectsWithMyProvided = allProjects.map(p => p.copy(configurations = (p.configurations.filter(_ != Provided)) :+ myProvided))
|
||||
lazy val nonRoots = projectsWithMyProvided.map(p => LocalProject(p.id))
|
||||
|
|
|
|||
|
|
@ -149,6 +149,9 @@ object BasicCommandStrings {
|
|||
def Shell = "shell"
|
||||
def ShellDetailed = "Provides an interactive prompt from which commands can be run."
|
||||
|
||||
def Server = "server"
|
||||
def ServerDetailed = "Provides a network server and an interactive prompt from which commands can be run."
|
||||
|
||||
def StashOnFailure = "sbtStashOnFailure"
|
||||
def PopOnFailure = "sbtPopOnFailure"
|
||||
|
||||
|
|
|
|||
|
|
@ -13,14 +13,16 @@ import BasicCommandStrings._
|
|||
import CommandUtil._
|
||||
import BasicKeys._
|
||||
|
||||
import sbt.server.Server
|
||||
import java.io.File
|
||||
import sbt.io.IO
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
import scala.util.control.NonFatal
|
||||
import scala.annotation.tailrec
|
||||
|
||||
object BasicCommands {
|
||||
lazy val allBasicCommands = Seq(nop, ignore, help, completionsCommand, multi, ifLast, append, setOnFailure, clearOnFailure, stashOnFailure, popOnFailure, reboot, call, early, exit, continuous, history, shell, read, alias) ++ compatCommands
|
||||
lazy val allBasicCommands = Seq(nop, ignore, help, completionsCommand, multi, ifLast, append, setOnFailure, clearOnFailure, stashOnFailure, popOnFailure, reboot, call, early, exit, continuous, history, shell, server, read, alias) ++ compatCommands
|
||||
|
||||
def nop = Command.custom(s => success(() => s))
|
||||
def ignore = Command.command(FailureWall)(idFun)
|
||||
|
|
@ -180,9 +182,6 @@ object BasicCommands {
|
|||
}
|
||||
|
||||
def shell = Command.command(Shell, Help.more(Shell, ShellDetailed)) { s =>
|
||||
// TODO hook it in, start in the right place, shutdown on termination
|
||||
val server = Server.start("127.0.0.1", 12700)
|
||||
|
||||
val history = (s get historyPath) getOrElse Some(new File(s.baseDir, ".history"))
|
||||
val prompt = (s get shellPrompt) match { case Some(pf) => pf(s); case None => "> " }
|
||||
val reader = new FullReader(history, s.combinedParser)
|
||||
|
|
@ -195,6 +194,32 @@ object BasicCommands {
|
|||
}
|
||||
}
|
||||
|
||||
var askingAlready = false
|
||||
val commandListers = Seq(new ConsoleListener(), new NetworkListener())
|
||||
val commandQueue: ConcurrentLinkedQueue[Option[String]] = new ConcurrentLinkedQueue()
|
||||
|
||||
@tailrec def blockUntilNextCommand: Option[String] =
|
||||
Option(commandQueue.poll) match {
|
||||
case Some(x) => x
|
||||
case None =>
|
||||
Thread.sleep(50)
|
||||
blockUntilNextCommand
|
||||
}
|
||||
def server = Command.command(Server, Help.more(Server, ServerDetailed)) { s =>
|
||||
if (!askingAlready) {
|
||||
commandListers foreach { x =>
|
||||
x.run(commandQueue, CommandStatus(s, true))
|
||||
}
|
||||
}
|
||||
blockUntilNextCommand match {
|
||||
case Some(line) =>
|
||||
// tell listern to be inactive .
|
||||
val newState = s.copy(onFailure = Some(Server), remainingCommands = line +: Server +: s.remainingCommands).setInteractive(true)
|
||||
if (line.trim.isEmpty) newState else newState.clearGlobalLog
|
||||
case None => s.setInteractive(false)
|
||||
}
|
||||
}
|
||||
|
||||
def read = Command.make(ReadCommand, Help.more(ReadCommand, ReadDetailed))(s => applyEffect(readParser(s))(doRead(s)))
|
||||
def readParser(s: State) =
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package sbt
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
trait CommandListener {
|
||||
// represents a loop that keeps asking an IO device for String input
|
||||
def run(queue: ConcurrentLinkedQueue[Option[String]],
|
||||
status: CommandStatus): Unit
|
||||
def shutdown(): Unit
|
||||
def setStatus(status: CommandStatus): Unit
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package sbt
|
||||
|
||||
case class CommandStatus(state: State, canEnter: Boolean)
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package sbt
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicReference }
|
||||
|
||||
class ConsoleListener extends CommandListener {
|
||||
|
||||
// val history = (s get historyPath) getOrElse Some(new File(s.baseDir, ".history"))
|
||||
// val prompt = (s get shellPrompt) match { case Some(pf) => pf(s); case None => "> " }
|
||||
// val reader = new FullReader(history, s.combinedParser)
|
||||
// val line = reader.readLine(prompt)
|
||||
// line match {
|
||||
// case Some(line) =>
|
||||
// val newState = s.copy(onFailure = Some(Shell), remainingCommands = line +: Shell +: s.remainingCommands).setInteractive(true)
|
||||
// if (line.trim.isEmpty) newState else newState.clearGlobalLog
|
||||
// case None => s.setInteractive(false)
|
||||
// }
|
||||
|
||||
def run(queue: ConcurrentLinkedQueue[Option[String]],
|
||||
status: CommandStatus): Unit =
|
||||
{
|
||||
// spawn thread and loop
|
||||
}
|
||||
|
||||
def shutdown(): Unit =
|
||||
{
|
||||
// interrupt and kill the thread
|
||||
}
|
||||
|
||||
def setStatus(status: CommandStatus): Unit = ???
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package sbt
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
import server.Server
|
||||
|
||||
class NetworkListener extends CommandListener {
|
||||
def run(queue: ConcurrentLinkedQueue[Option[String]],
|
||||
status: CommandStatus): Unit =
|
||||
{
|
||||
val server = Server.start("127.0.0.1", 12700)
|
||||
// spawn thread and loop
|
||||
}
|
||||
|
||||
def shutdown(): Unit =
|
||||
{
|
||||
// interrupt and kill the thread
|
||||
}
|
||||
|
||||
def setStatus(status: CommandStatus): Unit = ???
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Lightbend Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package sbt.server
|
||||
package sbt
|
||||
package server
|
||||
|
||||
import java.net.{ SocketTimeoutException, Socket }
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Lightbend Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package sbt.server
|
||||
package sbt
|
||||
package server
|
||||
|
||||
import org.json4s.JsonAST.{ JArray, JString }
|
||||
import org.json4s._
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Lightbend Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package sbt.server
|
||||
package sbt
|
||||
package server
|
||||
|
||||
import java.net.{ SocketTimeoutException, InetAddress, ServerSocket }
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Lightbend Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package sbt.server
|
||||
package sbt
|
||||
package server
|
||||
|
||||
trait Event
|
||||
|
||||
Loading…
Reference in New Issue