mirror of https://github.com/sbt/sbt.git
processors
This commit is contained in:
parent
ff6395fc35
commit
522b412d14
|
|
@ -221,4 +221,14 @@ class PluginProject(info: ProjectInfo) extends DefaultProject(info)
|
|||
/* Some setup to make publishing quicker to configure. */
|
||||
override def useMavenConfigurations = true
|
||||
override def managedStyle = ManagedStyle.Maven
|
||||
}
|
||||
class ProcessorProject(info: ProjectInfo) extends DefaultProject(info)
|
||||
{
|
||||
/* Fix the version used to build to the version currently running sbt. */
|
||||
override def buildScalaVersion = defScalaVersion.value
|
||||
/* Add sbt to the classpath */
|
||||
override def unmanagedClasspath = super.unmanagedClasspath +++ info.sbtClasspath
|
||||
/* Some setup to make publishing quicker to configure. */
|
||||
override def useMavenConfigurations = true
|
||||
override def managedStyle = ManagedStyle.Maven
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Steven Blundy, Mark Harrah, David MacIver, Mikko Peltonen
|
||||
* Copyright 2008, 2009, 2010 Steven Blundy, Mark Harrah, David MacIver, Mikko Peltonen
|
||||
*/
|
||||
package sbt
|
||||
|
||||
|
|
@ -117,6 +117,7 @@ class xMain extends xsbti.AppMain
|
|||
def ExitOnFailure = None
|
||||
lazy val interactiveContinue = Some( InteractiveCommand )
|
||||
def remoteContinue(port: Int) = Some( FileCommandsPrefix + "-" + port )
|
||||
lazy val PHandler = new processor.Handler(baseProject)
|
||||
|
||||
// replace in 2.8
|
||||
trait Trampoline
|
||||
|
|
@ -134,6 +135,7 @@ class xMain extends xsbti.AppMain
|
|||
def rememberCurrent(newArgs: List[String]) = rememberProject(rememberFail(newArgs))
|
||||
def rememberProject(newArgs: List[String]) = if(baseProject.name != project.name) (ProjectAction + " " + project.name) :: newArgs else newArgs
|
||||
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 failed(code: Int) =
|
||||
failAction match
|
||||
{
|
||||
|
|
@ -204,7 +206,21 @@ class xMain extends xsbti.AppMain
|
|||
case action :: tail if action.startsWith(FailureHandlerPrefix) =>
|
||||
val errorAction = action.substring(FailureHandlerPrefix.length).trim
|
||||
continue(project, tail, if(errorAction.isEmpty) None else Some(errorAction) )
|
||||
|
||||
|
||||
case action :: tail if action.startsWith(ProcessorPrefix) =>
|
||||
val processorCommand = action.substring(ProcessorPrefix.length).trim
|
||||
val runner = processor.CommandRunner(PHandler.manager, PHandler.defParser, ProcessorPrefix, project.log)
|
||||
tryOrFail {
|
||||
runner(processorCommand)
|
||||
continue(project, tail, failAction)
|
||||
}
|
||||
|
||||
case PHandler(processor, arguments) :: tail =>
|
||||
tryOrFail {
|
||||
val result =processor(project, arguments)
|
||||
continue(project, result.insertArguments ::: tail, failAction)
|
||||
}
|
||||
|
||||
case action :: tail =>
|
||||
val success = processAction(baseProject, project, action, failAction == interactiveContinue)
|
||||
if(success) continue(project, tail, failAction)
|
||||
|
|
@ -356,6 +372,8 @@ class xMain extends xsbti.AppMain
|
|||
val FileCommandsPrefix = "<"
|
||||
/** The prefix used to identify the action to run after an error*/
|
||||
val FailureHandlerPrefix = "!"
|
||||
/** The prefix used to identify commands for managing processors.*/
|
||||
val ProcessorPrefix = "*"
|
||||
|
||||
/** The number of seconds between polling by the continuous compile command.*/
|
||||
val ContinuousCompilePollDelaySeconds = 1
|
||||
|
|
@ -387,7 +405,7 @@ class xMain extends xsbti.AppMain
|
|||
handleCommand(currentProject, action)
|
||||
}
|
||||
|
||||
private def printCmd(name:String, desc:String) = Console.println("\t" + name + " : " + desc)
|
||||
private def printCmd(name:String, desc:String) = Console.println(" " + name + " : " + desc)
|
||||
val BatchHelpHeader = "You may execute any project action or method or one of the commands described below."
|
||||
val InteractiveHelpHeader = "You may execute any project action or one of the commands described below. Only one action " +
|
||||
"may be executed at a time in interactive mode and is entered by name, as it would be at the command line." +
|
||||
|
|
@ -399,10 +417,12 @@ class xMain extends xsbti.AppMain
|
|||
|
||||
printCmd("<action name>", "Executes the project specified action.")
|
||||
printCmd("<method name> <parameter>*", "Executes the project specified method.")
|
||||
printCmd("<processor label> <arguments>", "Runs the specified processor.")
|
||||
printCmd(ContinuousExecutePrefix + " <command>", "Executes the project specified action or method whenever source files change.")
|
||||
printCmd(FileCommandsPrefix + " file", "Executes the commands in the given file. Each command should be on its own line. Empty lines and lines beginning with '#' are ignored")
|
||||
printCmd(CrossBuildPrefix + " <command>", "Executes the project specified action or method for all versions of Scala defined in crossScalaVersions.")
|
||||
printCmd(SpecificBuildPrefix + "<version> <command>", "Changes the version of Scala building the project and executes the provided command. <command> is optional.")
|
||||
printCmd(ProcessorPrefix, "Prefix for commands for managing processors. Run '" + ProcessorPrefix + "help' for details.")
|
||||
printCmd(ShowActions, "Shows all available actions.")
|
||||
printCmd(RebootCommand, "Reloads sbt, picking up modifications to sbt.version or scala.version and recompiling modified project definitions.")
|
||||
printCmd(HelpAction, "Displays this help message.")
|
||||
|
|
@ -504,7 +524,7 @@ class xMain extends xsbti.AppMain
|
|||
}
|
||||
private def printTraceEnabled(project: Project)
|
||||
{
|
||||
def traceLevel(level: Int) = if(level == 0) " (no stack elements)" else if(level == MaxInt) "" else " (maximum " + level + " stack elements per exception)"
|
||||
def traceLevel(level: Int) = if(level == 0) " (no sbt stack elements)" else if(level == MaxInt) "" else " (maximum " + level + " stack elements per exception)"
|
||||
Console.println("Stack traces are " + (if(project.log.traceEnabled) "enabled" + traceLevel(project.log.getTrace) else "disabled"))
|
||||
}
|
||||
/** Sets the logging level on the given project.*/
|
||||
|
|
@ -700,4 +720,14 @@ class xMain extends xsbti.AppMain
|
|||
private def setProjectError(log: Logger) = logError(log)("Invalid arguments for 'project': expected project name.")
|
||||
private def logError(log: Logger)(s: String) = { log.error(s); false }
|
||||
|
||||
private def logCommandError(log: Logger, e: Throwable) =
|
||||
e match
|
||||
{
|
||||
case pe: processor.ProcessorException =>
|
||||
if(pe.getCause ne null) log.trace(pe.getCause)
|
||||
log.error(e.getMessage)
|
||||
case e =>
|
||||
log.trace(e)
|
||||
log.error(e.toString)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
/** Parses and executes a command (connects a parser to a runner). */
|
||||
class CommandRunner(parser: CommandParsing, execute: Executing)
|
||||
{
|
||||
def apply(processorCommand: String): Unit =
|
||||
parser.parseCommand(processorCommand) match
|
||||
{
|
||||
case Left(err) => throw new ProcessorException(err)
|
||||
case Right(command) => execute(command)
|
||||
}
|
||||
}
|
||||
object CommandRunner
|
||||
{
|
||||
/** Convenience method for constructing a CommandRunner with the minimal information required.*/
|
||||
def apply(manager: Manager, defParser: DefinitionParser, prefix: String, log: Logger): CommandRunner =
|
||||
{
|
||||
val parser = new CommandParser(defaultErrorMessage(prefix), defParser)
|
||||
val info = new InfoImpl(manager, prefix, parser, System.out.println)
|
||||
val execute = new Execute(manager, info, log)
|
||||
new CommandRunner(parser, execute)
|
||||
}
|
||||
def defaultErrorMessage(prefix: String) =
|
||||
"Invalid processor command. Run " + prefix + "help to see valid commands."
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
/** Executes a parsed command. */
|
||||
class Execute(manager: Manager, info: Info, log: Logger) extends Executing
|
||||
{
|
||||
def apply(command: Command): Unit =
|
||||
command match
|
||||
{
|
||||
case dr: DefineRepository =>
|
||||
manager.defineRepository(dr.repo)
|
||||
log.info("Defined new processor repository '" + dr.repo + "'")
|
||||
case dp: DefineProcessor =>
|
||||
manager.defineProcessor(dp.pdef)
|
||||
log.info("Defined new processor '" + dp.pdef + "'")
|
||||
case rd: RemoveDefinition =>
|
||||
val removed = manager.removeDefinition(rd.label)
|
||||
log.info("Removed '" + removed + "'")
|
||||
case Help => info.help()
|
||||
case Show => info.show()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
class Handler(baseProject: Project) extends NotNull
|
||||
{
|
||||
def unapply(line: String): Option[(Processor, String)] =
|
||||
line.split("""\s+""", 2) match
|
||||
{
|
||||
case Array(GetProcessor(processor), args @ _*) => Some( (processor, args.mkString) )
|
||||
case _ => None
|
||||
}
|
||||
private object GetProcessor
|
||||
{
|
||||
def unapply(name: String): Option[Processor] =
|
||||
manager.processorDefinition(name).flatMap(manager.processor)
|
||||
}
|
||||
|
||||
def lock = baseProject.info.launcher.globalLock
|
||||
|
||||
lazy val scalaVersion = baseProject.defScalaVersion.value
|
||||
lazy val base = baseProject.info.bootPath / ("scala-" + scalaVersion) / "sbt-processors"
|
||||
lazy val persistBase = Path.userHome / ".ivy2" / "sbt"
|
||||
|
||||
def retrieveLockFile = base / lockName
|
||||
def persistLockFile = persistBase / lockName
|
||||
def lockName = "processors.lock"
|
||||
def definitionsFile = persistBase / "processors.properties"
|
||||
def files = new ManagerFiles(base.asFile, retrieveLockFile.asFile, definitionsFile.asFile)
|
||||
|
||||
lazy val defParser = new DefinitionParser
|
||||
lazy val manager = new ManagerImpl(files, scalaVersion, new Persist(lock, persistLockFile.asFile, defParser), baseProject.log)
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
class InfoImpl(manager: Manager, prefix: String, parser: CommandParser, print: String => Unit) extends Info
|
||||
{
|
||||
def show()
|
||||
{
|
||||
print("Processors:\n\t" + manager.processors.values.mkString("\n\t"))
|
||||
print("\nProcessor repositories:\n\t" + manager.repositories.values.mkString("\n\t"))
|
||||
}
|
||||
def help()
|
||||
{
|
||||
import parser.{ShowCommand, HelpCommand, ProcessorCommand, RemoveCommand, RepositoryCommand}
|
||||
val usage =
|
||||
(HelpCommand -> "Display this help message") ::
|
||||
(ShowCommand -> "Display defined processors and repositories") ::
|
||||
(ProcessorCommand -> "Define 'label' to be the processor with the given ID") ::
|
||||
(RepositoryCommand -> "Add a repository for searching for processors") ::
|
||||
(RemoveCommand -> "Undefine the repository or processor with the given 'label'") ::
|
||||
Nil
|
||||
|
||||
print("Processor management commands:\n " + (usage.map{ case (c,d) => prefix + "" + c + " " + d}).mkString("\n "))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
import java.io.File
|
||||
import java.net.{URL, URLClassLoader}
|
||||
import xsbt.FileUtilities.read
|
||||
import xsbt.OpenResource.urlInputStream
|
||||
import xsbt.Paths._
|
||||
import xsbt.GlobFilter._
|
||||
|
||||
import ProcessorException.error
|
||||
|
||||
class Loader extends NotNull
|
||||
{
|
||||
def classNameResource = "sbt.processor"
|
||||
def getProcessor(directory: File): Either[Throwable, Processor] = getProcessor( getLoader(directory) )
|
||||
private def getProcessor(loader: ClassLoader): Either[Throwable, Processor] =
|
||||
{
|
||||
val resource = loader.getResource(classNameResource)
|
||||
if(resource eq null) Left(new ProcessorException("Processor existed but did not contain '" + classNameResource + "' descriptor."))
|
||||
else loadProcessor(loader, resource)
|
||||
}
|
||||
private def loadProcessor(loader: ClassLoader, resource : URL): Either[Throwable, Processor] =
|
||||
try { Right(loadProcessor(loader, className(resource))) }
|
||||
catch { case e: Exception => Left(e) }
|
||||
|
||||
private def loadProcessor(loader: ClassLoader, className: String): Processor =
|
||||
{
|
||||
val processor = Class.forName(className, true, loader).newInstance
|
||||
classOf[Processor].cast(processor)
|
||||
}
|
||||
private def className(resource: URL): String = urlInputStream(resource) { in => read(in).trim }
|
||||
private def getLoader(dir: File) =
|
||||
{
|
||||
val jars = dir ** "*.jar"
|
||||
val jarURLs = jars.files.toArray[File].map(_.toURI.toURL)
|
||||
new URLClassLoader(jarURLs, getClass.getClassLoader)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
import java.io.File
|
||||
import xsbt.Paths._
|
||||
import ProcessorException.error
|
||||
|
||||
/** Files needed by ManagerImpl.
|
||||
* `retrieveBaseDirectory` is the directory that processors are retrieved under.
|
||||
* `retrieveLockFile` is used to synchronize access to that directory.
|
||||
* `definitionsFile` is the file to save repository and processor definitions to. It is usually per-user instead of per-project.*/
|
||||
class ManagerFiles(val retrieveBaseDirectory: File, val retrieveLockFile: File, val definitionsFile: File)
|
||||
|
||||
class ManagerImpl(files: ManagerFiles, scalaVersion: String, persist: Persist, log: Logger) extends Manager
|
||||
{
|
||||
import files._
|
||||
|
||||
def processorDefinition(label: String): Option[ProcessorDefinition] = processors.get(label)
|
||||
def processor(pdef: ProcessorDefinition): Option[Processor] =
|
||||
{
|
||||
def tryProcessor: Either[Throwable, Processor] =
|
||||
(new Loader).getProcessor( retrieveDirectory(pdef) )
|
||||
|
||||
// try to load the processor. It will succeed here if the processor has already been retrieved
|
||||
tryProcessor.left.flatMap { _ =>
|
||||
// if it hasn't been retrieved, retrieve the processor and its dependencies
|
||||
retrieveProcessor(pdef)
|
||||
// try to load the processor now that it has been retrieved
|
||||
tryProcessor.left.map { // if that fails, log a warning
|
||||
case p: ProcessorException => log.warn(p.getMessage)
|
||||
case t => log.trace(t); log.warn(t.toString)
|
||||
}
|
||||
}.right.toOption
|
||||
}
|
||||
def defineProcessor(p: ProcessorDefinition)
|
||||
{
|
||||
checkExisting(p)
|
||||
retrieveProcessor(p)
|
||||
add(p)
|
||||
}
|
||||
def defineRepository(r: RepositoryDefinition)
|
||||
{
|
||||
checkExisting(r)
|
||||
add(r)
|
||||
}
|
||||
def removeDefinition(label: String): Definition =
|
||||
definitions.removeKey(label) match
|
||||
{
|
||||
case Some(removed) =>
|
||||
saveDefinitions()
|
||||
removed
|
||||
case None => error("Label '" + label + "' not defined.")
|
||||
}
|
||||
|
||||
private def retrieveProcessor(p: ProcessorDefinition): Unit =
|
||||
{
|
||||
val resolvers = repositories.values.toList.map(toResolver)
|
||||
val module = p.toModuleID(scalaVersion)
|
||||
( new Retrieve(retrieveDirectory(p), module, persist.lock, retrieveLockFile, resolvers, log) ).retrieve()
|
||||
}
|
||||
private def add(d: Definition)
|
||||
{
|
||||
definitions(d.label) = d
|
||||
saveDefinitions()
|
||||
}
|
||||
|
||||
private lazy val definitions = loadDefinitions(definitionsFile)
|
||||
def repositories = Map() ++ partialMap(definitions) { case (label, d: RepositoryDefinition) => (label, d) }
|
||||
def processors = Map() ++ partialMap(definitions) { case (label, p: ProcessorDefinition) => (label, p) }
|
||||
|
||||
private def checkExisting(p: Definition): Unit = definitions.get(p.label) map { d => error ("Label '" + p.label + "' already in use: " + d) }
|
||||
private def partialMap[T,S](i: Iterable[T])(f: PartialFunction[T,S]) = i.filter(f.isDefinedAt).map(f)
|
||||
private def toResolver(repo: RepositoryDefinition): Resolver = new MavenRepository(repo.label, repo.url)
|
||||
|
||||
def retrieveDirectory(p: ProcessorDefinition) = retrieveBaseDirectory / p.group / p.module / p.rev
|
||||
|
||||
private def saveDefinitions(): Unit = saveDefinitions(definitionsFile)
|
||||
private def saveDefinitions(file: File): Unit = persist.save(file)(definitions.values.toList)
|
||||
private def loadDefinitions(file: File): scala.collection.mutable.Map[String, Definition] =
|
||||
scala.collection.mutable.HashMap( (if(file.exists) rawLoad(file) else Nil) : _*)
|
||||
private def rawLoad(file: File): Seq[(String, Definition)] = persist.load(definitionsFile).map { d => (d.label, d) }
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
/** Parses commands. `errorMessage` is the String used when a command is invalid.
|
||||
* There is no detailed error reporting.
|
||||
* Input Strings are assumed to be trimmed.*/
|
||||
class CommandParser(errorMessage: String, defParser: DefinitionParsing) extends CommandParsing
|
||||
{
|
||||
def parseCommand(line: String): Either[String, Command] =
|
||||
defParser.parseDefinition(line) match
|
||||
{
|
||||
case Some(p: ProcessorDefinition) => Right(new DefineProcessor(p))
|
||||
case Some(r: RepositoryDefinition) => Right(new DefineRepository(r))
|
||||
case None => parseOther(line)
|
||||
}
|
||||
|
||||
def parseOther(line: String) =
|
||||
line match
|
||||
{
|
||||
case RemoveRegex(label) => Right(new RemoveDefinition(label))
|
||||
case HelpCommand | "" => Right(Help)
|
||||
case ShowCommand => Right(Show)
|
||||
case _ => Left(errorMessage)
|
||||
}
|
||||
|
||||
val ShowCommand = "show"
|
||||
val HelpCommand = "help"
|
||||
val ProcessorCommand = "<label> is <group> <module> <rev>"
|
||||
val RepositoryCommand = "<label> at <url>"
|
||||
val RemoveCommand = "remove <label>"
|
||||
|
||||
val RemoveRegex = """remove\s+(\w+)""".r
|
||||
}
|
||||
|
||||
/** Parses the String representation of definitions.*/
|
||||
class DefinitionParser extends DefinitionParsing
|
||||
{
|
||||
def parseDefinition(line: String): Option[Definition] =
|
||||
line match
|
||||
{
|
||||
case ProcessorRegex(label, group, name, rev) => Some( new ProcessorDefinition(label, group, name, rev) )
|
||||
case RepositoryRegex(label, url) => Some( new RepositoryDefinition(label, url) )
|
||||
case _ => None
|
||||
}
|
||||
|
||||
val ProcessorRegex = """(\w+)\s+is\s+(\S+)\s+(\S+)\s+(\S+)""".r
|
||||
val RepositoryRegex = """(\w+)\s+at\s+(\S+)""".r
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
import java.io.File
|
||||
|
||||
import xsbt.FileUtilities.{readLines, write}
|
||||
|
||||
// lock file should be for synchronizing access to the persisted files
|
||||
class Persist(val lock: xsbti.GlobalLock, lockFile: File, defParser: DefinitionParser) extends Persisting
|
||||
{
|
||||
private def withDefinitionsLock[T](f: => T): T = lock(lockFile,Callable(f))
|
||||
|
||||
def save(file: File)(definitions: Iterable[Definition])
|
||||
{
|
||||
val lines = definitions.mkString(LineSeparator)
|
||||
withDefinitionsLock { write(file, lines) }
|
||||
}
|
||||
def load(file: File): Seq[Definition] =
|
||||
{
|
||||
def parseLine(line: String) = defParser.parseDefinition(line).toList
|
||||
withDefinitionsLock { if(file.exists) readLines(file) else Nil } flatMap(parseLine)
|
||||
}
|
||||
private final val LineSeparator = System.getProperty("line.separator", "\n")
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
import java.io.File
|
||||
|
||||
/** An interface for code that operates on an sbt `Project`.*/
|
||||
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
|
||||
}
|
||||
/** The result of a Processor run.
|
||||
* `insertArgs` allows the Processor to insert additional commands to run.
|
||||
* These commands are run before pending commands.
|
||||
*
|
||||
* For example, consider a Processor bound to 'cleanCompile' that returns
|
||||
* `ProcessorResult("clean", "compile")`
|
||||
*
|
||||
* If a user runs:
|
||||
* `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
|
||||
{
|
||||
val insertArguments = insertArgs.toList
|
||||
}
|
||||
|
||||
/** Manages the processor and repository definitions.*/
|
||||
trait Manager extends NotNull
|
||||
{
|
||||
def defineProcessor(pdef: ProcessorDefinition)
|
||||
def removeDefinition(label: String): Definition
|
||||
def defineRepository(repo: RepositoryDefinition)
|
||||
def processor(pdef: ProcessorDefinition): Option[Processor]
|
||||
def processorDefinition(label: String): Option[ProcessorDefinition]
|
||||
|
||||
def processors: Map[String, ProcessorDefinition]
|
||||
def repositories: Map[String, RepositoryDefinition]
|
||||
}
|
||||
|
||||
/** Executes a parsed command. */
|
||||
trait Executing extends NotNull
|
||||
{
|
||||
def apply(command: Command)
|
||||
}
|
||||
/** Prints information about processors. */
|
||||
trait Info extends NotNull
|
||||
{
|
||||
/** Prints available processors and defined repositories.*/
|
||||
def show()
|
||||
/** Prints usage of processor management commands.*/
|
||||
def help()
|
||||
}
|
||||
|
||||
/** Parses a command String */
|
||||
trait CommandParsing extends NotNull
|
||||
{
|
||||
/** Parses a command String that has been preprocessed.
|
||||
* It should have any prefix (like the * used by Main) removed
|
||||
* and whitespace trimmed
|
||||
*
|
||||
* If parsing is successful, a `Command` instance is returned wrapped in `Right`.
|
||||
* Otherwise, an error message is returned wrapped in `Left`.*/
|
||||
def parseCommand(line: String): Either[String, Command]
|
||||
}
|
||||
/** Parses a definition `String`.*/
|
||||
trait DefinitionParsing extends NotNull
|
||||
{
|
||||
/** Parses the given definition `String`.
|
||||
* The result is wrapped in `Some` if successful, or `None` if the string is not of the correct form. */
|
||||
def parseDefinition(line: String): Option[Definition]
|
||||
}
|
||||
/** Handles serializing `Definition`s.*/
|
||||
trait Persisting extends NotNull
|
||||
{
|
||||
def save(file: File)(definitions: Iterable[Definition])
|
||||
def load(file: File): Seq[Definition]
|
||||
}
|
||||
|
||||
sealed trait Definition extends NotNull
|
||||
{
|
||||
def label: String
|
||||
}
|
||||
final class ProcessorDefinition(val label: String, val group: String, val module: String, val rev: String) extends Definition
|
||||
{
|
||||
override def toString = Seq(label, "is", group, module, rev).mkString(" ")
|
||||
def idString = Seq(group, module, rev).mkString(" ")
|
||||
def toModuleID(scalaVersion: String) = ModuleID(group, module + "_" + scalaVersion, rev)
|
||||
}
|
||||
// maven-style repositories only right now
|
||||
final class RepositoryDefinition(val label: String, val url: String) extends Definition
|
||||
{
|
||||
override def toString = Seq(label, "at", url).mkString(" ")
|
||||
}
|
||||
|
||||
/** Data type representing a runnable command related to processor management.*/
|
||||
sealed trait Command extends NotNull
|
||||
/** A command to add the given processor definition. */
|
||||
final class DefineProcessor(val pdef: ProcessorDefinition) extends Command
|
||||
/** A command to remove the processor or repository definition currently associated with the given `label`.
|
||||
* If the definition is associated with other labels, those are not affected.*/
|
||||
final class RemoveDefinition(val label: String) extends Command
|
||||
/** A command to register the given repository to be used for obtaining `Processor`s. */
|
||||
final class DefineRepository(val repo: RepositoryDefinition) extends Command
|
||||
/** A command to show help for processor management command usage. */
|
||||
object Help extends Command
|
||||
/** A command to show available processors and repositories.*/
|
||||
object Show extends Command
|
||||
|
||||
/** An exception used when a `Processor` wants to terminate with an error message, but the stack trace is not important.
|
||||
* If a `cause` is provided, its stack trace is assumed to be important.*/
|
||||
final class ProcessorException(val message: String, cause: Throwable) extends RuntimeException(message, cause)
|
||||
{
|
||||
def this(message: String) = this(message, null)
|
||||
}
|
||||
object ProcessorException
|
||||
{
|
||||
def error(msg: String): Nothing = throw new ProcessorException(msg)
|
||||
def error(msg: String, t: Throwable): Nothing = throw new ProcessorException(msg, t)
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt.processor
|
||||
|
||||
import java.io.File
|
||||
|
||||
class Retrieve(retrieveDirectory: File, module: ModuleID, lock: xsbti.GlobalLock, lockFile: File, repositories: Seq[Resolver], log: IvyLogger) extends NotNull
|
||||
{
|
||||
def retrieve()
|
||||
{
|
||||
val paths = new IvyPaths(retrieveDirectory, None)
|
||||
val ivyScala = new IvyScala("", Nil, false, true)
|
||||
val fullRepositories = Resolver.withDefaultResolvers(repositories) // TODO: move this somewhere under user control
|
||||
val configuration = new InlineIvyConfiguration(paths, fullRepositories, Nil, Some(lock), log)
|
||||
val moduleConfiguration = new InlineConfiguration(thisID, module :: Nil, scala.xml.NodeSeq.Empty, Nil, None, Some(ivyScala), false)
|
||||
val update = new UpdateConfiguration(retrieveDirectory, retrievePattern, true, true)
|
||||
val ivySbt = new IvySbt(configuration)
|
||||
val ivyModule = new ivySbt.Module(moduleConfiguration)
|
||||
|
||||
lock(lockFile, Callable { IvyActions.update(ivyModule, update) } )
|
||||
}
|
||||
def thisID = ModuleID("org.scala-tools.sbt", "retrieve-processor", "1.0")
|
||||
def retrievePattern = "[artifact](-[revision])(-[classifier]).[ext]"
|
||||
}
|
||||
|
||||
object Callable
|
||||
{
|
||||
def apply[T](f: => T): java.util.concurrent.Callable[T] = new java.util.concurrent.Callable[T] { def call = f }
|
||||
}
|
||||
Loading…
Reference in New Issue