mirror of https://github.com/sbt/sbt.git
Split Processor into Processor/BasicProcessor:
* Processor provides a high level of integration with command processing. * BasicProcessor operates on a Project but does not affect command processing.
This commit is contained in:
parent
df6d83911a
commit
de8af817ac
|
|
@ -141,8 +141,11 @@ class xMain extends xsbti.AppMain
|
|||
def rememberFail(newArgs: List[String]) = failAction.map(f => (FailureHandlerPrefix + f)).toList ::: newArgs
|
||||
|
||||
def tryOrFail(action: => Trampoline) = try { action } catch { case e: Exception => logCommandError(project.log, e); failed(BuildErrorExitCode) }
|
||||
def reload(newID: ApplicationID, args: List[String]) =
|
||||
def reload(args: List[String]) =
|
||||
{
|
||||
val newID = new ApplicationID(configuration.provider.id, baseProject.sbtVersion.value)
|
||||
result( new Reboot(project.defScalaVersion.value, rememberCurrent(args), newID, configuration.baseDirectory) )
|
||||
}
|
||||
def failed(code: Int) =
|
||||
failAction match
|
||||
{
|
||||
|
|
@ -154,7 +157,7 @@ class xMain extends xsbti.AppMain
|
|||
{
|
||||
case "" :: tail => continue(project, tail, failAction)
|
||||
case (ExitCommand | QuitCommand) :: _ => result( Exit(NormalExitCode) )
|
||||
case RebootCommand :: tail => reload( new ApplicationID(configuration.provider.id, baseProject.sbtVersion.value), tail )
|
||||
case RebootCommand :: tail => reload( tail )
|
||||
case InteractiveCommand :: _ => continue(project, prompt(baseProject, project) :: arguments, interactiveContinue)
|
||||
case SpecificBuild(version, action) :: tail =>
|
||||
if(Some(version) != baseProject.info.buildScalaVersion)
|
||||
|
|
@ -220,10 +223,14 @@ class xMain extends xsbti.AppMain
|
|||
continue(project, tail, failAction)
|
||||
}
|
||||
|
||||
case PHandler(processor, arguments) :: tail =>
|
||||
case PHandler(parsed) :: tail =>
|
||||
tryOrFail {
|
||||
val result =processor(project, arguments)
|
||||
continue(project, result.insertArguments ::: tail, failAction)
|
||||
parsed.processor(parsed.label, project, failAction, parsed.arguments) match
|
||||
{
|
||||
case s: processor.Success => continue(s.project, s.insertArguments ::: tail, s.onFailure)
|
||||
case e: processor.Exit => result( Exit(e.code) )
|
||||
case r: processor.Reload => reload( r.insertArguments ::: tail )
|
||||
}
|
||||
}
|
||||
|
||||
case action :: tail =>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ package sbt.processor
|
|||
|
||||
class Handler(baseProject: Project) extends NotNull
|
||||
{
|
||||
def unapply(line: String): Option[(Processor, String)] =
|
||||
def unapply(line: String): Option[ParsedProcessor] =
|
||||
line.split("""\s+""", 2) match
|
||||
{
|
||||
case Array(GetProcessor(processor), args @ _*) => Some( (processor, args.mkString) )
|
||||
case Array(label @ GetProcessor(processor), args @ _*) => Some( new ParsedProcessor(label, processor, args.mkString) )
|
||||
case _ => None
|
||||
}
|
||||
private object GetProcessor
|
||||
|
|
@ -31,4 +31,5 @@ class Handler(baseProject: Project) extends NotNull
|
|||
|
||||
lazy val defParser = new DefinitionParser
|
||||
lazy val manager = new ManagerImpl(files, scalaVersion, new Persist(lock, persistLockFile.asFile, defParser), baseProject.log)
|
||||
}
|
||||
}
|
||||
class ParsedProcessor(val label: String, val processor: Processor, val arguments: String) extends NotNull
|
||||
|
|
@ -11,10 +11,28 @@ trait Processor extends NotNull
|
|||
/** Apply this processor's action to the given `project`.
|
||||
* The arguments are passed unparsed as a single String `args`.
|
||||
* The return value optionally provides additional commands to run, such as 'reload'.
|
||||
* Note: `project` is not necessarily the root project. To get the root project, use `project.rootProject`.*/
|
||||
def apply(project: Project, args: String): ProcessorResult
|
||||
* Note: `project` is not necessarily the root project. To get the root project, use `project.rootProject`.
|
||||
* The `label` used to call the processor is provided to allow recursing.*/
|
||||
def apply(label: String, project: Project, onFailure: Option[String], args: String): ProcessorResult
|
||||
}
|
||||
/** The result of a Processor run.
|
||||
/** An interface for code that operates on an sbt `Project` but doesn't need to modify command processing.*/
|
||||
abstract class BasicProcessor extends Processor
|
||||
{
|
||||
/** Apply this processor's action to the given `project`.
|
||||
* The arguments are passed unparsed as a single String `args`.
|
||||
* Note: `project` is not necessarily the root project. To get the root project, use `project.rootProject`.*/
|
||||
def apply(project: Project, args: String): Unit
|
||||
|
||||
override final def apply(label: String, project: Project, onFailure: Option[String], args: String): ProcessorResult =
|
||||
{
|
||||
apply(project, args)
|
||||
new Success(project, onFailure)
|
||||
}
|
||||
}
|
||||
|
||||
/** The result of a Processor run.*/
|
||||
sealed trait ProcessorResult extends NotNull
|
||||
/* Processor success.
|
||||
* `insertArgs` allows the Processor to insert additional commands to run.
|
||||
* These commands are run before pending commands.
|
||||
*
|
||||
|
|
@ -25,7 +43,12 @@ trait Processor extends NotNull
|
|||
* `sbt a cleanCompile b `
|
||||
* This runs `a`, `cleanCompile`, `clean`, `compile`, and finally `b`.
|
||||
* Commands are processed as if they were entered at the prompt or from the command line.*/
|
||||
final class ProcessorResult(insertArgs: String*) extends NotNull
|
||||
final class Success(val project: Project, val onFailure: Option[String], insertArgs: String*) extends ProcessorResult
|
||||
{
|
||||
val insertArguments = insertArgs.toList
|
||||
}
|
||||
final class Exit(val code: Int) extends ProcessorResult
|
||||
final class Reload(insertArgs: String*) extends ProcessorResult
|
||||
{
|
||||
val insertArguments = insertArgs.toList
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
project.name=Processor Test
|
||||
project.version=1.0
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import sbt._
|
||||
|
||||
class PTest(info: ProjectInfo) extends ProcessorProject(info)
|
||||
{
|
||||
val launcherJar = "org.scala-tools.sbt" % "launcher" % info.app.id.version % "test"
|
||||
val specs = "org.scala-tools.testing" % "specs" % "1.6.0" % "test"
|
||||
override def testClasspath = super.testClasspath +++ info.sbtClasspath
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package ptest
|
||||
|
||||
import sbt._
|
||||
import Path.fromFile
|
||||
import org.specs._
|
||||
|
||||
class ProcessorTest extends Specification
|
||||
{
|
||||
"basic processor " should {
|
||||
def success(f: processor.Success => Unit) = successOrFail(basicProcessorResult)(f)
|
||||
|
||||
"succeed" in {
|
||||
success(_ => ())
|
||||
}
|
||||
"not insert any arguments" in {
|
||||
success(_.insertArguments must_== Nil)
|
||||
}
|
||||
"preserve the fail handler" in {
|
||||
success(_.onFailure must_== basicFail)
|
||||
}
|
||||
}
|
||||
"full processor " should {
|
||||
def success(f: processor.Success => Unit) = successOrFail(fullProcessorResult)(f)
|
||||
"succeed" in {
|
||||
success(_ => ())
|
||||
}
|
||||
"insert correct arguments" in {
|
||||
success(_.insertArguments must_== testArgs)
|
||||
}
|
||||
"preserve the fail handler" in {
|
||||
success(_.onFailure must_== testFail)
|
||||
}
|
||||
}
|
||||
|
||||
def successOrFail(r: processor.ProcessorResult)(f: processor.Success => Unit) =
|
||||
r match
|
||||
{
|
||||
case s: processor.Success => f(s)
|
||||
case _ => error("Processor failed: " + r)
|
||||
}
|
||||
|
||||
def withProject[T](f: Project => T): T =
|
||||
{
|
||||
val log = new ConsoleLogger
|
||||
xsbt.FileUtilities.withTemporaryDirectory { tmp =>
|
||||
val app = xsbt.boot.Launcher.defaultAppProvider(tmp)
|
||||
val info = new ProjectInfo(tmp, Nil, None)(log, app, None)
|
||||
val project = new DefaultProject(info)
|
||||
f(project)
|
||||
}
|
||||
}
|
||||
def basicProcessorResult =
|
||||
{
|
||||
var ranBasicArgs: Option[String] = None
|
||||
val basic = new processor.BasicProcessor {
|
||||
def apply(p: Project, args: String) = { ranBasicArgs = Some(args) }
|
||||
}
|
||||
val result = withProject { project => basic("basic", project, basicFail, basicArgs) }
|
||||
ranBasicArgs must_== Some(basicArgs)
|
||||
result
|
||||
}
|
||||
def fullProcessorResult =
|
||||
{
|
||||
val full = new processor.Processor {
|
||||
def apply(label: String, p: Project, failAction: Option[String], args: String) = new processor.Success(p, failAction, args.split("""\s+"""): _*)
|
||||
}
|
||||
withProject { project => full("full", project, testFail, testArgs.mkString(" ")) }
|
||||
}
|
||||
|
||||
lazy val testFail = Some("fail")
|
||||
lazy val testArgs = List("a", "b")
|
||||
lazy val basicArgs = " a b c "
|
||||
lazy val basicFail = Some("basic-fail")
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
> update
|
||||
> test
|
||||
Loading…
Reference in New Issue