Update Continuous to directly use multi parser

It didn't really make sense for Continuous to use the other command
parser and then reparse the results. I was able to slightly simplify
things by using the multi parser directly.
This commit is contained in:
Ethan Atkins 2019-06-14 12:46:44 -07:00
parent ff16d76ad3
commit 30a16d1e10
1 changed files with 19 additions and 22 deletions

View File

@ -17,7 +17,6 @@ import sbt.BasicCommandStrings.{
continuousBriefHelp, continuousBriefHelp,
continuousDetail continuousDetail
} }
import sbt.BasicCommands.otherCommandParser
import sbt.Def._ import sbt.Def._
import sbt.Keys._ import sbt.Keys._
import sbt.Scope.Global import sbt.Scope.Global
@ -105,8 +104,8 @@ private[sbt] object Continuous extends DeprecatedContinuous {
*/ */
private[sbt] def continuous: Command = private[sbt] def continuous: Command =
Command(ContinuousExecutePrefix, continuousBriefHelp, continuousDetail)(continuousParser) { Command(ContinuousExecutePrefix, continuousBriefHelp, continuousDetail)(continuousParser) {
case (s, (initialCount, command)) => case (s, (initialCount, commands)) =>
runToTermination(s, command, initialCount, isCommand = true) runToTermination(s, commands, initialCount, isCommand = true)
} }
/** /**
@ -117,9 +116,9 @@ private[sbt] object Continuous extends DeprecatedContinuous {
*/ */
private[sbt] def continuousTask: Def.Initialize[InputTask[StateTransform]] = private[sbt] def continuousTask: Def.Initialize[InputTask[StateTransform]] =
Def.inputTask { Def.inputTask {
val (initialCount, command) = continuousParser.parsed val (initialCount, commands) = continuousParser.parsed
new StateTransform( new StateTransform(
runToTermination(state.value, command, initialCount, isCommand = false) runToTermination(state.value, commands, initialCount, isCommand = false)
) )
} }
@ -137,15 +136,20 @@ private[sbt] object Continuous extends DeprecatedContinuous {
10000 10000
) )
private[this] val continuousParser: State => Parser[(Int, String)] = { private[this] val continuousParser: State => Parser[(Int, Seq[String])] = {
def toInt(s: String): Int = Try(s.toInt).getOrElse(0) def toInt(s: String): Int = Try(s.toInt).getOrElse(0)
// This allows us to re-enter the watch with the previous count. // This allows us to re-enter the watch with the previous count.
val digitParser: Parser[Int] = val digitParser: Parser[Int] =
(Parsers.Space.* ~> matched(Parsers.Digit.+) <~ Parsers.Space.*).map(toInt) (Parsers.Space.* ~> matched(Parsers.Digit.+) <~ Parsers.Space.*).map(toInt)
state => state =>
val ocp = otherCommandParser(state) val ocp = BasicCommands.multiParserImpl(Some(state)) |
(digitParser.? ~ ocp).map { case (i, s) => (i.getOrElse(0), s) } BasicCommands.otherCommandParser(state).map(_ :: Nil)
(digitParser.? ~ ocp).flatMap {
case (i, cmds) if cmds.exists(_.nonEmpty) =>
Parser.success((i.getOrElse(0), cmds.filter(_.nonEmpty)))
case (_, cmds) => Parser.failure("Couldn't parse any commands")
}
} }
/** /**
@ -202,8 +206,8 @@ private[sbt] object Continuous extends DeprecatedContinuous {
.getOrElse(throw exception) .getOrElse(throw exception)
} }
private[sbt] def setup[R](state: State, command: String)( private[sbt] def setup[R](state: State, commands: Seq[String])(
f: (Seq[String], State, Seq[(String, State, () => Boolean)], Seq[String]) => R f: (State, Seq[(String, State, () => Boolean)], Seq[String]) => R
): R = { ): R = {
// First set up the state so that we can capture whether or not a task completed successfully // First set up the state so that we can capture whether or not a task completed successfully
// or if it threw an Exception (we lose the actual exception, but that should still be printed // or if it threw an Exception (we lose the actual exception, but that should still be printed
@ -253,14 +257,6 @@ private[sbt] object Continuous extends DeprecatedContinuous {
) )
} }
// We support multiple commands in watch, so it's necessary to run the command string through
// the multi parser.
val trimmed = command.trim
val commands = Parser.parse(trimmed, BasicCommands.multiParserImpl(Some(s))) match {
case Left(_) => trimmed :: Nil
case Right(c) => c
}
// Convert the command strings to runnable tasks, which are represented by // Convert the command strings to runnable tasks, which are represented by
// () => Try[Boolean]. // () => Try[Boolean].
val taskParser = s.combinedParser val taskParser = s.combinedParser
@ -274,7 +270,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
case Left(c) => (i :+ c, v) case Left(c) => (i :+ c, v)
} }
} }
f(commands, s, valid, invalid) f(s, valid, invalid)
} }
private[this] def withCharBufferedStdIn[R](f: InputStream => R): R = { private[this] def withCharBufferedStdIn[R](f: InputStream => R): R = {
@ -319,7 +315,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
private[sbt] def runToTermination( private[sbt] def runToTermination(
state: State, state: State,
command: String, commands: Seq[String],
count: Int, count: Int,
isCommand: Boolean isCommand: Boolean
): State = withCharBufferedStdIn { in => ): State = withCharBufferedStdIn { in =>
@ -341,7 +337,7 @@ private[sbt] object Continuous extends DeprecatedContinuous {
stateWithRepo.put(persistentFileStampCache, fileStampCache) stateWithRepo.put(persistentFileStampCache, fileStampCache)
else stateWithRepo else stateWithRepo
) )
setup(fullState, command) { (commands, s, valid, invalid) => setup(fullState, commands) { (s, valid, invalid) =>
EvaluateTask.withStreams(extracted.structure, s)(_.use(streams in Global) { streams => EvaluateTask.withStreams(extracted.structure, s)(_.use(streams in Global) { streams =>
implicit val logger: Logger = streams.log implicit val logger: Logger = streams.log
if (invalid.isEmpty) { if (invalid.isEmpty) {
@ -369,7 +365,8 @@ private[sbt] object Continuous extends DeprecatedContinuous {
e.throwable.getStackTrace.foreach(e => logger.error(e.toString)) e.throwable.getStackTrace.foreach(e => logger.error(e.toString))
case _ => case _ =>
} }
callbacks.onTermination(terminationAction, command, currentCount.get(), state) val fullCommand = commands.mkString("; ")
callbacks.onTermination(terminationAction, fullCommand, currentCount.get(), state)
} finally { } finally {
callbacks.onExit() callbacks.onExit()
} }