2010-07-17 18:07:41 +02:00
|
|
|
/* sbt -- Simple Build Tool
|
2011-01-22 20:01:59 +01:00
|
|
|
* Copyright 2008, 2009, 2010, 2011 Mark Harrah
|
2010-07-17 18:07:41 +02:00
|
|
|
*/
|
|
|
|
|
package sbt
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
import Execute.NodeView
|
|
|
|
|
import complete.HistoryCommands
|
|
|
|
|
import HistoryCommands.{Start => HistoryPrefix}
|
|
|
|
|
import Project.{SessionKey, StructureKey}
|
|
|
|
|
import sbt.build.{AggressiveCompile, Auto, BuildException, LoadCommand, Parse, ParseException, ProjectLoad, SourceLoad}
|
2011-01-27 01:49:54 +01:00
|
|
|
import compile.EvalImports
|
2011-01-22 20:01:59 +01:00
|
|
|
import sbt.complete.{DefaultParsers, Parser}
|
2010-07-28 05:01:45 +02:00
|
|
|
|
2011-01-22 21:07:59 +01:00
|
|
|
import Command.{applyEffect,Analysis,HistoryPath,Logged,Watch}
|
2011-01-22 20:01:59 +01:00
|
|
|
import scala.annotation.tailrec
|
|
|
|
|
import scala.collection.JavaConversions._
|
|
|
|
|
import Function.tupled
|
2011-01-24 04:34:17 +01:00
|
|
|
import java.net.URI
|
2011-01-22 20:01:59 +01:00
|
|
|
import Path._
|
|
|
|
|
|
|
|
|
|
import java.io.File
|
2010-07-17 18:07:41 +02:00
|
|
|
|
|
|
|
|
/** This class is the entry point for sbt.*/
|
|
|
|
|
class xMain extends xsbti.AppMain
|
|
|
|
|
{
|
|
|
|
|
final def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
|
|
|
|
{
|
2010-07-28 05:01:45 +02:00
|
|
|
import Commands.{initialize, defaults}
|
|
|
|
|
import CommandSupport.{DefaultsCommand, InitCommand}
|
|
|
|
|
val initialCommandDefs = Seq(initialize, defaults)
|
|
|
|
|
val commands = DefaultsCommand :: InitCommand :: configuration.arguments.map(_.trim).toList
|
2010-12-19 18:03:10 +01:00
|
|
|
val state = State( configuration, initialCommandDefs, Set.empty, None, commands, initialAttributes, Next.Continue )
|
2010-07-17 18:07:41 +02:00
|
|
|
run(state)
|
|
|
|
|
}
|
2010-12-19 18:03:10 +01:00
|
|
|
def initialAttributes = AttributeMap.empty.put(Logged, ConsoleLogger())
|
2010-07-17 18:07:41 +02:00
|
|
|
|
|
|
|
|
@tailrec final def run(state: State): xsbti.MainResult =
|
|
|
|
|
{
|
|
|
|
|
import Next._
|
|
|
|
|
state.next match
|
|
|
|
|
{
|
|
|
|
|
case Continue => run(next(state))
|
|
|
|
|
case Fail => Exit(1)
|
|
|
|
|
case Done => Exit(0)
|
|
|
|
|
case Reload =>
|
|
|
|
|
val app = state.configuration.provider
|
|
|
|
|
new Reboot(app.scalaProvider.version, state.commands, app.id, state.configuration.baseDirectory)
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-08-05 01:41:11 +02:00
|
|
|
def next(state: State): State =
|
2011-01-22 20:01:59 +01:00
|
|
|
ErrorHandling.wideConvert { state.process(Command.process) } match
|
2010-08-05 01:41:11 +02:00
|
|
|
{
|
|
|
|
|
case Right(s) => s
|
|
|
|
|
case Left(t) => Commands.handleException(t, state)
|
|
|
|
|
}
|
2010-07-17 18:07:41 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
import DefaultParsers._
|
|
|
|
|
import CommandSupport._
|
2010-07-17 18:07:41 +02:00
|
|
|
object Commands
|
|
|
|
|
{
|
2010-12-19 18:03:10 +01:00
|
|
|
def DefaultCommands: Seq[Command] = Seq(ignore, help, reload, read, history, continuous, exit, loadCommands, loadProject, compile, discover,
|
2011-02-03 04:56:11 +01:00
|
|
|
projects, project, setOnFailure, ifLast, multi, shell, set, get, eval, alias, append, nop, sessionCommand, act)
|
2010-09-05 17:16:53 +02:00
|
|
|
|
2011-01-22 21:01:10 +01:00
|
|
|
def nop = Command.custom(s => success(() => s), Nil)
|
2011-01-22 20:01:59 +01:00
|
|
|
def ignore = Command.command(FailureWall)(identity)
|
2010-07-28 05:01:45 +02:00
|
|
|
|
|
|
|
|
def detail(selected: Iterable[String])(h: Help): Option[String] =
|
|
|
|
|
h.detail match { case (commands, value) => if( selected exists commands ) Some(value) else None }
|
|
|
|
|
|
2011-01-24 04:34:17 +01:00
|
|
|
def help = Command(HelpCommand, helpBrief, helpDetailed)(helpParser)
|
2010-07-28 05:01:45 +02:00
|
|
|
|
2011-01-24 04:34:17 +01:00
|
|
|
def helpParser(s: State) =
|
|
|
|
|
{
|
2011-01-22 20:01:59 +01:00
|
|
|
val h = s.processors.flatMap(_.help)
|
2011-01-24 04:34:17 +01:00
|
|
|
val helpCommands = h.flatMap(_.detail._1)
|
|
|
|
|
val args = (token(Space) ~> token( OpOrID.examples(helpCommands : _*) )).*
|
|
|
|
|
applyEffect(args)(runHelp(s, h))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def runHelp(s: State, h: Seq[Help])(args: Seq[String]): State =
|
|
|
|
|
{
|
2010-07-28 05:01:45 +02:00
|
|
|
val message =
|
2011-01-22 20:01:59 +01:00
|
|
|
if(args.isEmpty)
|
2010-07-28 05:01:45 +02:00
|
|
|
h.map( _.brief match { case (a,b) => a + " : " + b } ).mkString("\n", "\n", "\n")
|
|
|
|
|
else
|
2011-01-22 20:01:59 +01:00
|
|
|
h flatMap detail(args) mkString("\n", "\n\n", "\n")
|
2010-07-17 18:07:41 +02:00
|
|
|
System.out.println(message)
|
|
|
|
|
s
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def alias = Command(AliasCommand, AliasBrief, AliasDetailed) { s =>
|
|
|
|
|
val name = token(OpOrID.examples( aliasNames(s) : _*) )
|
2011-01-24 04:34:17 +01:00
|
|
|
val assign = token(Space ~ '=' ~ OptSpace)
|
|
|
|
|
val sfree = removeAliases(s)
|
|
|
|
|
val to = matched(Command.combine(sfree.processors)(sfree), partial = true) | any.+.string
|
|
|
|
|
val base = (OptSpace ~> (name ~ (assign ~> to.?).?).?)
|
2011-01-22 21:01:10 +01:00
|
|
|
applyEffect(base)(t => runAlias(s, t) )
|
|
|
|
|
}
|
2011-01-24 04:34:17 +01:00
|
|
|
|
|
|
|
|
def runAlias(s: State, args: Option[(String, Option[Option[String]])]): State =
|
2011-01-22 21:01:10 +01:00
|
|
|
args match
|
|
|
|
|
{
|
2011-01-22 20:01:59 +01:00
|
|
|
case None => printAliases(s); s
|
2011-01-24 04:34:17 +01:00
|
|
|
case Some(x ~ None) if !x.isEmpty => printAlias(s, x.trim); s
|
|
|
|
|
case Some(name ~ Some(None)) => removeAlias(s, name.trim)
|
|
|
|
|
case Some(name ~ Some(Some(value))) => addAlias(s, name.trim, value.trim)
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def shell = Command.command(Shell, ShellBrief, ShellDetailed) { s =>
|
2011-01-19 00:24:11 +01:00
|
|
|
val historyPath = (s get HistoryPath.key) getOrElse Some((s.baseDir / ".history").asFile)
|
2011-01-22 20:01:59 +01:00
|
|
|
val parser = Command.combine(s.processors)
|
|
|
|
|
val reader = new FullReader(historyPath, parser(s))
|
2010-07-28 05:01:45 +02:00
|
|
|
val line = reader.readLine("> ")
|
2010-08-05 01:41:46 +02:00
|
|
|
line match {
|
2010-12-19 18:03:10 +01:00
|
|
|
case Some(line) => s.copy(onFailure = Some(Shell), commands = line +: Shell +: s.commands)
|
2010-08-05 01:41:46 +02:00
|
|
|
case None => s
|
|
|
|
|
}
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
// TODO: this should nest Parsers for other commands
|
|
|
|
|
def multi = Command.single(Multi, MultiBrief, MultiDetailed) { (s,arg) =>
|
|
|
|
|
arg.split(";").toSeq ::: s
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
// TODO: nest
|
|
|
|
|
def ifLast = Command.single(IfLast, IfLastBrief, IfLastDetailed) { (s, arg) =>
|
|
|
|
|
if(s.commands.isEmpty) arg :: s else s
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
2011-01-22 20:01:59 +01:00
|
|
|
// TODO: nest
|
|
|
|
|
def append = Command.single(Append, AppendLastBrief, AppendLastDetailed) { (s, arg) =>
|
|
|
|
|
s.copy(commands = s.commands :+ arg)
|
2010-08-05 01:41:46 +02:00
|
|
|
}
|
2010-07-28 05:01:45 +02:00
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
// TODO: nest
|
|
|
|
|
def setOnFailure = Command.single(OnFailure, OnFailureBrief, OnFailureDetailed) { (s, arg) =>
|
|
|
|
|
s.copy(onFailure = Some(arg))
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def reload = Command.command(ReloadCommand, ReloadBrief, ReloadDetailed) { s =>
|
2010-07-28 05:01:45 +02:00
|
|
|
runExitHooks(s).reload
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def defaults = Command.command(DefaultsCommand) { s =>
|
2010-07-28 05:01:45 +02:00
|
|
|
s ++ DefaultCommands
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def initialize = Command.command(InitCommand) { s =>
|
2010-08-05 01:41:46 +02:00
|
|
|
/*"load-commands -base ~/.sbt/commands" :: */readLines( readable( sbtRCs(s) ) ) ::: s
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def readParser(s: State) =
|
|
|
|
|
{
|
|
|
|
|
val files = (token(Space) ~> fileParser(s.baseDir)).+
|
|
|
|
|
val portAndSuccess = token(OptSpace) ~> Port
|
|
|
|
|
portAndSuccess || files
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-22 21:01:10 +01:00
|
|
|
def read = Command(ReadCommand, ReadBrief, ReadDetailed)(s => applyEffect(readParser(s))(doRead(s)) )
|
2011-01-22 20:01:59 +01:00
|
|
|
|
|
|
|
|
def doRead(s: State)(arg: Either[Int, Seq[File]]): State =
|
|
|
|
|
arg match
|
2010-09-28 00:59:35 +02:00
|
|
|
{
|
|
|
|
|
case Left(portAndSuccess) =>
|
|
|
|
|
val port = math.abs(portAndSuccess)
|
|
|
|
|
val previousSuccess = portAndSuccess >= 0
|
|
|
|
|
readMessage(port, previousSuccess) match
|
|
|
|
|
{
|
2010-12-19 18:03:10 +01:00
|
|
|
case Some(message) => (message :: (ReadCommand + " " + port) :: s).copy(onFailure = Some(ReadCommand + " " + (-port)))
|
2010-09-28 00:59:35 +02:00
|
|
|
case None =>
|
|
|
|
|
System.err.println("Connection closed.")
|
|
|
|
|
s.fail
|
|
|
|
|
}
|
|
|
|
|
case Right(from) =>
|
|
|
|
|
val notFound = notReadable(from)
|
|
|
|
|
if(notFound.isEmpty)
|
|
|
|
|
readLines(from) ::: s // this means that all commands from all files are loaded, parsed, and inserted before any are executed
|
|
|
|
|
else {
|
|
|
|
|
logger(s).error("Command file(s) not readable: \n\t" + notFound.mkString("\n\t"))
|
|
|
|
|
s
|
|
|
|
|
}
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
2010-09-28 00:59:35 +02:00
|
|
|
private def readMessage(port: Int, previousSuccess: Boolean): Option[String] =
|
|
|
|
|
{
|
|
|
|
|
// split into two connections because this first connection ends the previous communication
|
|
|
|
|
xsbt.IPC.client(port) { _.send(previousSuccess.toString) }
|
|
|
|
|
// and this second connection starts the next communication
|
|
|
|
|
xsbt.IPC.client(port) { ipc =>
|
|
|
|
|
val message = ipc.receive
|
|
|
|
|
if(message eq null) None else Some(message)
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-01-22 20:01:59 +01:00
|
|
|
|
|
|
|
|
// TODO: nest
|
2010-12-19 18:03:10 +01:00
|
|
|
def continuous =
|
2011-01-22 20:01:59 +01:00
|
|
|
Command.single(ContinuousExecutePrefix, Help(continuousBriefHelp) ) { (s, arg) =>
|
2011-01-19 00:24:11 +01:00
|
|
|
withAttribute(s, Watch.key, "Continuous execution not configured.") { w =>
|
2011-01-22 20:01:59 +01:00
|
|
|
val repeat = ContinuousExecutePrefix + (if(arg.startsWith(" ")) arg else " " + arg)
|
|
|
|
|
Watched.executeContinuously(w, s, arg, repeat)
|
2010-12-19 18:03:10 +01:00
|
|
|
}
|
2010-09-05 17:19:19 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def history = Command.command("!!")(s => s)
|
|
|
|
|
//TODO: convert
|
|
|
|
|
/*def history = Command( historyHelp: _* ) { case (in, s) if in.line startsWith "!" =>
|
2010-12-19 18:03:10 +01:00
|
|
|
val logError = (msg: String) => CommandSupport.logger(s).error(msg)
|
2011-01-19 00:24:11 +01:00
|
|
|
HistoryCommands(in.line.substring(HistoryPrefix.length).trim, (s get HistoryPath.key) getOrElse None, 500/*JLine.MaxHistorySize*/, logError) match
|
2010-12-19 18:03:10 +01:00
|
|
|
{
|
|
|
|
|
case Some(commands) =>
|
|
|
|
|
commands.foreach(println) //printing is more appropriate than logging
|
|
|
|
|
(commands ::: s).continue
|
|
|
|
|
case None => s.fail
|
2010-07-17 18:07:41 +02:00
|
|
|
}
|
2011-01-22 20:01:59 +01:00
|
|
|
}*/
|
2010-07-28 05:01:45 +02:00
|
|
|
|
2011-01-25 13:24:52 +01:00
|
|
|
def eval = Command.single(EvalCommand, evalBrief, evalDetailed) { (s, arg) =>
|
|
|
|
|
val log = logger(s)
|
|
|
|
|
val extracted = Project extract s
|
|
|
|
|
import extracted._
|
2011-01-27 01:49:54 +01:00
|
|
|
val result = session.currentEval().eval(arg, srcName = "<eval>", imports = autoImports(extracted))
|
|
|
|
|
log.info("ans: " + result.tpe + " = " + result.value.toString)
|
2011-01-25 13:24:52 +01:00
|
|
|
s
|
|
|
|
|
}
|
2011-02-03 04:56:11 +01:00
|
|
|
def sessionCommand = Command(SessionCommand, sessionBrief, SessionSettings.Help)(SessionSettings.command)
|
|
|
|
|
def reapply(newSession: SessionSettings, structure: Load.BuildStructure, s: State): State =
|
|
|
|
|
{
|
|
|
|
|
logger(s).info("Reapplying settings...")
|
|
|
|
|
val newStructure = Load.reapply(newSession.mergeSettings, structure)
|
|
|
|
|
setProject(newSession, newStructure, s)
|
|
|
|
|
}
|
2011-01-25 13:24:52 +01:00
|
|
|
def set = Command.single(SetCommand, setBrief, setDetailed) { (s, arg) =>
|
|
|
|
|
val extracted = Project extract s
|
|
|
|
|
import extracted._
|
2011-01-27 01:49:54 +01:00
|
|
|
val setting = EvaluateConfigurations.evaluateSetting(session.currentEval(), "<set>", imports(extracted), arg, 0)
|
2011-01-25 13:24:52 +01:00
|
|
|
val append = Load.transformSettings(Load.projectScope(curi, cid), curi, rootProject, setting :: Nil)
|
|
|
|
|
val newSession = session.appendSettings( append map (a => (a, arg)))
|
2011-02-03 04:56:11 +01:00
|
|
|
reapply(newSession, structure, s)
|
2011-01-25 13:24:52 +01:00
|
|
|
}
|
|
|
|
|
def get = Command.single(GetCommand, getBrief, getDetailed) { (s, arg) =>
|
|
|
|
|
val extracted = Project extract s
|
|
|
|
|
import extracted._
|
2011-01-27 01:49:54 +01:00
|
|
|
val result = session.currentEval().eval(arg, srcName = "get", imports = autoImports(extracted), tpeName = Some("sbt.ScopedSetting[_]"))
|
|
|
|
|
val scoped = result.value.asInstanceOf[ScopedSetting[_]]
|
2011-01-25 13:24:52 +01:00
|
|
|
val resolve = Scope.resolveScope(Load.projectScope(curi, cid), curi, rootProject)
|
|
|
|
|
(structure.data.get(resolve(scoped.scope), scoped.key)) match {
|
|
|
|
|
case None => logger(s).error("No entry for key."); s.fail
|
|
|
|
|
case Some(v) => logger(s).info(v.toString); s
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-01-27 01:49:54 +01:00
|
|
|
def autoImports(extracted: Extracted): EvalImports = new EvalImports(imports(extracted), "<auto-imports>")
|
|
|
|
|
def imports(extracted: Extracted): Seq[(String,Int)] =
|
|
|
|
|
{
|
|
|
|
|
import extracted._
|
|
|
|
|
structure.units(curi).imports.map(s => (s, -1))
|
|
|
|
|
}
|
2011-01-25 13:24:52 +01:00
|
|
|
|
2011-01-24 04:34:17 +01:00
|
|
|
def listBuild(uri: URI, build: Load.LoadedBuildUnit, current: Boolean, currentID: String, log: Logger) =
|
|
|
|
|
{
|
|
|
|
|
log.info("In " + uri)
|
|
|
|
|
def prefix(id: String) = if(currentID != id) " " else if(current) " * " else "(*)"
|
|
|
|
|
for(id <- build.defined.keys) log.info("\t" + prefix(id) + id)
|
|
|
|
|
}
|
2010-07-28 05:01:45 +02:00
|
|
|
|
2011-01-26 04:23:03 +01:00
|
|
|
def act = Command.custom(Act.actParser, Nil)
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def projects = Command.command(ProjectsCommand, projectsBrief, projectsDetailed ) { s =>
|
2011-01-25 13:24:52 +01:00
|
|
|
val extracted = Project extract s
|
|
|
|
|
import extracted._
|
2010-12-19 18:03:10 +01:00
|
|
|
val log = logger(s)
|
2011-01-24 04:34:17 +01:00
|
|
|
listBuild(curi, structure.units(curi), true, cid, log)
|
|
|
|
|
for( (uri, build) <- structure.units if curi != uri) listBuild(uri, build, false, cid, log)
|
2011-01-19 00:24:11 +01:00
|
|
|
s
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
2010-12-19 18:03:10 +01:00
|
|
|
def withAttribute[T](s: State, key: AttributeKey[T], ifMissing: String)(f: T => State): State =
|
|
|
|
|
(s get key) match {
|
|
|
|
|
case None => logger(s).error(ifMissing); s.fail
|
|
|
|
|
case Some(nav) => f(nav)
|
|
|
|
|
}
|
2010-07-28 05:01:45 +02:00
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def project = Command(ProjectCommand, projectBrief, projectDetailed)(ProjectNavigation.command)
|
2010-10-30 19:24:23 +02:00
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def exit = Command.command(TerminateAction, Help(exitBrief) :: Nil ) ( doExit )
|
|
|
|
|
|
|
|
|
|
def doExit(s: State): State = runExitHooks(s).exit(true)
|
2010-07-19 18:38:42 +02:00
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
// TODO: tab completion, low priority
|
|
|
|
|
def discover = Command.single(Discover, DiscoverBrief, DiscoverDetailed) { (s, arg) =>
|
2010-12-19 18:03:10 +01:00
|
|
|
withAttribute(s, Analysis, "No analysis to process.") { analysis =>
|
2011-01-22 20:01:59 +01:00
|
|
|
val command = Parse.discover(arg)
|
2011-01-19 00:24:11 +01:00
|
|
|
val discovered = build.Build.discover(analysis, command)
|
2010-08-05 01:41:46 +02:00
|
|
|
println(discovered.mkString("\n"))
|
|
|
|
|
s
|
2010-12-19 18:03:10 +01:00
|
|
|
}
|
2010-08-05 01:41:46 +02:00
|
|
|
}
|
2011-01-22 20:01:59 +01:00
|
|
|
// TODO: tab completion, low priority
|
|
|
|
|
def compile = Command.single(CompileName, CompileBrief, CompileDetailed ) { (s, arg) =>
|
|
|
|
|
val command = Parse.compile(arg)(s.baseDir)
|
2010-08-10 14:46:27 +02:00
|
|
|
try {
|
2011-01-19 00:24:11 +01:00
|
|
|
val analysis = build.Build.compile(command, s.configuration)
|
2010-12-19 18:03:10 +01:00
|
|
|
s.put(Analysis, analysis)
|
2010-08-10 14:46:27 +02:00
|
|
|
} catch { case e: xsbti.CompileFailed => s.fail /* already logged */ }
|
2010-08-05 01:41:46 +02:00
|
|
|
}
|
2010-09-05 17:12:44 +02:00
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
def loadProject = Command.command(LoadProject, LoadProjectBrief, LoadProjectDetailed) { s =>
|
2011-01-25 13:24:52 +01:00
|
|
|
val (eval, structure) = Load.defaultLoad(s, logger(s))
|
|
|
|
|
val session = Load.initialSession(structure, eval)
|
|
|
|
|
setProject(session, structure, s)
|
|
|
|
|
}
|
|
|
|
|
def setProject(session: SessionSettings, structure: Load.BuildStructure, s: State): State =
|
|
|
|
|
{
|
2011-01-19 00:24:11 +01:00
|
|
|
val newAttrs = s.attributes.put(StructureKey, structure).put(SessionKey, session)
|
|
|
|
|
val newState = s.copy(attributes = newAttrs)
|
2011-01-22 20:01:59 +01:00
|
|
|
Project.updateCurrent(runExitHooks(newState))
|
2011-01-19 00:24:11 +01:00
|
|
|
}
|
2010-07-17 18:07:41 +02:00
|
|
|
|
2010-08-10 14:46:27 +02:00
|
|
|
def handleException(e: Throwable, s: State, trace: Boolean = true): State = {
|
2010-12-19 18:03:10 +01:00
|
|
|
val log = logger(s)
|
|
|
|
|
if(trace) log.trace(e)
|
|
|
|
|
log.error(e.toString)
|
2010-08-05 01:41:11 +02:00
|
|
|
s.fail
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-28 05:01:45 +02:00
|
|
|
def runExitHooks(s: State): State = {
|
|
|
|
|
ExitHooks.runExitHooks(s.exitHooks.toSeq)
|
2010-12-19 18:03:10 +01:00
|
|
|
s.copy(exitHooks = Set.empty)
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
// TODO: tab completion, low priority
|
|
|
|
|
def loadCommands = Command.single(LoadCommand, Parse.helpBrief(LoadCommand, LoadCommandLabel), Parse.helpDetail(LoadCommand, LoadCommandLabel, true) ) { (s, arg) =>
|
|
|
|
|
applyCommands(s, buildCommands(arg, s.configuration))
|
2010-08-05 01:41:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def buildCommands(arguments: String, configuration: xsbti.AppConfiguration): Either[Throwable, Seq[Any]] =
|
2010-08-10 14:44:34 +02:00
|
|
|
loadCommand(arguments, configuration, true, classOf[CommandDefinitions].getName)
|
2010-08-05 01:41:46 +02:00
|
|
|
|
|
|
|
|
def applyCommands(s: State, commands: Either[Throwable, Seq[Any]]): State =
|
|
|
|
|
commands match {
|
2010-07-28 05:01:45 +02:00
|
|
|
case Right(newCommands) =>
|
2010-08-10 14:44:34 +02:00
|
|
|
val asCommands = newCommands flatMap {
|
|
|
|
|
case c: CommandDefinitions => c.commands
|
|
|
|
|
case x => error("Not an instance of CommandDefinitions: " + x.asInstanceOf[AnyRef].getClass)
|
|
|
|
|
}
|
2010-12-19 18:03:10 +01:00
|
|
|
s.copy(processors = asCommands ++ s.processors)
|
2010-08-10 14:46:27 +02:00
|
|
|
case Left(e) => handleException(e, s, false)
|
2010-07-17 18:07:41 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-28 05:01:45 +02:00
|
|
|
def loadCommand(line: String, configuration: xsbti.AppConfiguration, allowMultiple: Boolean, defaultSuper: String): Either[Throwable, Seq[Any]] =
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
val parsed = Parse(line)(configuration.baseDirectory)
|
2011-01-19 00:24:11 +01:00
|
|
|
Right( build.Build( translateEmpty(parsed, defaultSuper), configuration, allowMultiple) )
|
2010-07-28 05:01:45 +02:00
|
|
|
}
|
2010-07-17 18:07:41 +02:00
|
|
|
catch { case e @ (_: ParseException | _: BuildException | _: xsbti.CompileFailed) => Left(e) }
|
2010-07-19 18:38:42 +02:00
|
|
|
|
2010-07-28 05:01:45 +02:00
|
|
|
def translateEmpty(load: LoadCommand, defaultSuper: String): LoadCommand =
|
|
|
|
|
load match {
|
|
|
|
|
case ProjectLoad(base, Auto.Explicit, "") => ProjectLoad(base, Auto.Subclass, defaultSuper)
|
|
|
|
|
case s @ SourceLoad(_, _, _, _, Auto.Explicit, "") => s.copy(auto = Auto.Subclass, name = defaultSuper)
|
|
|
|
|
case x => x
|
|
|
|
|
}
|
2010-07-19 18:38:42 +02:00
|
|
|
|
|
|
|
|
def runTask[Task[_] <: AnyRef](root: Task[State], checkCycles: Boolean, maxWorkers: Int)(implicit taskToNode: NodeView[Task]): Result[State] =
|
|
|
|
|
{
|
|
|
|
|
val (service, shutdown) = CompletionService[Task[_], Completed](maxWorkers)
|
|
|
|
|
|
|
|
|
|
val x = new Execute[Task](checkCycles)(taskToNode)
|
|
|
|
|
try { x.run(root)(service) } finally { shutdown() }
|
|
|
|
|
}
|
2010-09-28 00:59:14 +02:00
|
|
|
def processResult[State](result: Result[State], original: State, onFailure: => State): State =
|
2010-07-19 18:38:42 +02:00
|
|
|
result match
|
|
|
|
|
{
|
|
|
|
|
case Value(v) => v
|
2010-09-13 04:43:42 +02:00
|
|
|
case Inc(inc) =>
|
|
|
|
|
println(Incomplete.show(inc, true))
|
|
|
|
|
println("Task did not complete successfully")
|
2010-09-28 00:59:14 +02:00
|
|
|
onFailure
|
2010-07-19 18:38:42 +02:00
|
|
|
}
|
2010-07-28 05:01:45 +02:00
|
|
|
|
|
|
|
|
def addAlias(s: State, name: String, value: String): State =
|
2011-01-22 20:01:59 +01:00
|
|
|
if(Command validID name) {
|
2010-07-28 05:01:45 +02:00
|
|
|
val removed = removeAlias(s, name)
|
2011-01-22 20:01:59 +01:00
|
|
|
if(value.isEmpty) removed else removed.copy(processors = newAlias(name, value) +: removed.processors)
|
2010-07-28 05:01:45 +02:00
|
|
|
} else {
|
|
|
|
|
System.err.println("Invalid alias name '" + name + "'.")
|
|
|
|
|
s.fail
|
|
|
|
|
}
|
2011-01-24 04:34:17 +01:00
|
|
|
|
|
|
|
|
def removeAliases(s: State): State = s.copy(processors = removeAliases(s.processors))
|
|
|
|
|
def removeAliases(as: Seq[Command]): Seq[Command] = as.filter(c => ! (c.tags contains CommandAliasKey))
|
2011-01-22 20:01:59 +01:00
|
|
|
def removeAlias(s: State, name: String): State = s.copy(processors = s.processors.filter(c => !isAliasNamed(name, c)) )
|
|
|
|
|
def isAliasNamed(name: String, c: Command): Boolean = isNamed(name, getAlias(c))
|
2011-01-24 04:34:17 +01:00
|
|
|
def isNamed(name: String, alias: Option[(String,String)]): Boolean = alias match { case None => false; case Some((n,_)) => name == n }
|
2011-01-22 20:01:59 +01:00
|
|
|
|
|
|
|
|
def getAlias(c: Command): Option[(String,String)] = c.tags get CommandAliasKey
|
|
|
|
|
def printAlias(s: State, name: String): Unit = printAliases(aliases(s,(n,v) => n == name) )
|
|
|
|
|
def printAliases(s: State): Unit = printAliases(allAliases(s))
|
|
|
|
|
def printAliases(as: Seq[(String,String)]): Unit =
|
|
|
|
|
for( (name,value) <- as)
|
|
|
|
|
println("\t" + name + " = " + value)
|
|
|
|
|
|
|
|
|
|
def aliasNames(s: State): Seq[String] = allAliases(s).map(_._1)
|
|
|
|
|
def allAliases(s: State): Seq[(String,String)] = aliases(s, (n,v) => true)
|
|
|
|
|
def aliases(s: State, pred: (String,String) => Boolean): Seq[(String,String)] =
|
|
|
|
|
s.processors.flatMap(c => getAlias(c).filter(tupled(pred)))
|
|
|
|
|
|
|
|
|
|
def newAlias(name: String, value: String): Command =
|
2011-01-24 04:34:17 +01:00
|
|
|
Command(name, (name, "'" + value + "'"), "Alias of '" + value + "'")(aliasBody(name, value)).tag(CommandAliasKey, (name, value))
|
2011-01-22 21:01:10 +01:00
|
|
|
def aliasBody(name: String, value: String)(state: State): Parser[() => State] =
|
2011-01-24 04:34:17 +01:00
|
|
|
Parser(Command.combine(state.processors)(state))(value)
|
|
|
|
|
|
2011-01-22 20:01:59 +01:00
|
|
|
val CommandAliasKey = AttributeKey[(String,String)]("is-command-alias")
|
2010-07-17 18:07:41 +02:00
|
|
|
}
|