mirror of https://github.com/sbt/sbt.git
cleanup
This commit is contained in:
parent
4ce57596d9
commit
7b4c16f294
|
|
@ -2,7 +2,6 @@
|
|||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
package build
|
||||
|
||||
import inc._
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ object Compiler
|
|||
import in.config._
|
||||
import in.incSetup._
|
||||
|
||||
val agg = new build.AggressiveCompile(cacheDirectory)
|
||||
val agg = new AggressiveCompile(cacheDirectory)
|
||||
agg(scalac, javac, sources, classpath, classesDirectory, options, javacOptions, analysisMap, maxErrors)(log)
|
||||
}
|
||||
}
|
||||
|
|
@ -26,14 +26,8 @@ final class Console(compiler: AnalyzingCompiler)
|
|||
}
|
||||
object Console
|
||||
{
|
||||
def apply(conf: build.Compile)(implicit log: Logger): Console = new Console( compiler(conf) )
|
||||
def apply(conf: Compiler.Inputs): Console = new Console( conf.compilers.scalac )
|
||||
|
||||
def compiler(conf: build.Compile)(implicit log: Logger): AnalyzingCompiler =
|
||||
{
|
||||
val componentManager = new ComponentManager(conf.launcher.globalLock, conf.configuration.provider.components, log)
|
||||
new AnalyzingCompiler(conf.instance, componentManager, log)
|
||||
}
|
||||
def sbt(state: State, extra: String)(implicit log: Logger)
|
||||
{
|
||||
val extracted = Project extract state
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ package sbt
|
|||
import Execute.NodeView
|
||||
import complete.HistoryCommands
|
||||
import HistoryCommands.{Start => HistoryPrefix}
|
||||
import sbt.build.{AggressiveCompile, Auto, BuildException, LoadCommand, Parse, ParseException, ProjectLoad, SourceLoad}
|
||||
import compiler.EvalImports
|
||||
import sbt.complete.{DefaultParsers, Parser}
|
||||
|
||||
|
|
@ -60,7 +59,7 @@ class xMain extends xsbti.AppMain
|
|||
import CommandSupport._
|
||||
object BuiltinCommands
|
||||
{
|
||||
def DefaultCommands: Seq[Command] = Seq(ignore, help, reboot, read, history, continuous, exit, loadCommands, loadProject, loadProjectImpl, loadFailed, compile, discover,
|
||||
def DefaultCommands: Seq[Command] = Seq(ignore, help, reboot, read, history, continuous, exit, loadProject, loadProjectImpl, loadFailed,
|
||||
projects, project, setOnFailure, clearOnFailure, ifLast, multi, shell, set, inspect, eval, alias, append, last, lastGrep, nop, sessionCommand, act)
|
||||
def DefaultBootCommands: Seq[String] = LoadProject :: (IfLast + " " + Shell) :: Nil
|
||||
|
||||
|
|
@ -294,24 +293,6 @@ object BuiltinCommands
|
|||
|
||||
def doExit(s: State): State = s.runExitHooks().exit(true)
|
||||
|
||||
// TODO: tab completion, low priority
|
||||
def discover = Command.single(Discover, DiscoverBrief, DiscoverDetailed) { (s, arg) =>
|
||||
withAttribute(s, analysis, "No analysis to process.") { a =>
|
||||
val command = Parse.discover(arg)
|
||||
val discovered = build.Build.discover(a, command)
|
||||
println(discovered.mkString("\n"))
|
||||
s
|
||||
}
|
||||
}
|
||||
// TODO: tab completion, low priority
|
||||
def compile = Command.single(CompileName, CompileBrief, CompileDetailed ) { (s, arg) =>
|
||||
val command = Parse.compile(arg)(s.baseDir)
|
||||
try {
|
||||
val a = build.Build.compile(command, s.configuration)
|
||||
s.put(analysis, a)
|
||||
} catch { case e: xsbti.CompileFailed => s.fail /* already logged */ }
|
||||
}
|
||||
|
||||
def loadFailed = Command.command(LoadFailed)(handleLoadFailed)
|
||||
@tailrec def handleLoadFailed(s: State): State =
|
||||
{
|
||||
|
|
@ -349,57 +330,6 @@ object BuiltinCommands
|
|||
s.fail
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
def buildCommands(arguments: String, configuration: xsbti.AppConfiguration): Either[Throwable, Seq[Any]] =
|
||||
loadCommand(arguments, configuration, true, classOf[CommandDefinitions].getName)
|
||||
|
||||
def applyCommands(s: State, commands: Either[Throwable, Seq[Any]]): State =
|
||||
commands match {
|
||||
case Right(newCommands) =>
|
||||
val asCommands = newCommands flatMap {
|
||||
case c: CommandDefinitions => c.commands
|
||||
case x => error("Not an instance of CommandDefinitions: " + x.asInstanceOf[AnyRef].getClass)
|
||||
}
|
||||
s.copy(processors = asCommands ++ s.processors)
|
||||
case Left(e) => handleException(e, s, false)
|
||||
}
|
||||
|
||||
def loadCommand(line: String, configuration: xsbti.AppConfiguration, allowMultiple: Boolean, defaultSuper: String): Either[Throwable, Seq[Any]] =
|
||||
try
|
||||
{
|
||||
val parsed = Parse(line)(configuration.baseDirectory)
|
||||
Right( build.Build( translateEmpty(parsed, defaultSuper), configuration, allowMultiple) )
|
||||
}
|
||||
catch { case e @ (_: ParseException | _: BuildException | _: xsbti.CompileFailed) => Left(e) }
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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() }
|
||||
}
|
||||
def processResult[State](result: Result[State], original: State, onFailure: => State): State =
|
||||
result match
|
||||
{
|
||||
case Value(v) => v
|
||||
case Inc(inc) =>
|
||||
println(Incomplete.show(inc, true))
|
||||
println("Task did not complete successfully")
|
||||
onFailure
|
||||
}
|
||||
|
||||
def addAlias(s: State, name: String, value: String): State =
|
||||
if(Command validID name) {
|
||||
val removed = removeAlias(s, name)
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
package build
|
||||
|
||||
import java.io.File
|
||||
import classpath.ClasspathUtilities.toLoader
|
||||
import ModuleUtilities.getObject
|
||||
import compiler.{AnalyzingCompiler, Discovery, JavaCompiler}
|
||||
import inc.Analysis
|
||||
import Path._
|
||||
import GlobFilter._
|
||||
|
||||
final class BuildException(msg: String) extends RuntimeException(msg)
|
||||
|
||||
object Build
|
||||
{
|
||||
def loader(configuration: xsbti.AppConfiguration): ClassLoader =
|
||||
configuration.provider.mainClass.getClassLoader
|
||||
|
||||
def apply(command: LoadCommand, configuration: xsbti.AppConfiguration, allowMultiple: Boolean): Seq[Any] =
|
||||
command match
|
||||
{
|
||||
case BinaryLoad(classpath, module, name) =>
|
||||
binary(classpath, module, name, loader(configuration), allowMultiple)
|
||||
case SourceLoad(classpath, sourcepath, output, module, auto, name) =>
|
||||
source(classpath, sourcepath, output, module, auto, name, configuration, allowMultiple)
|
||||
case ProjectLoad(base, auto, name) =>
|
||||
project(base, auto, name, configuration, allowMultiple)
|
||||
}
|
||||
|
||||
def project(base: File, auto: Auto.Value, name: String, configuration: xsbti.AppConfiguration, allowMultiple: Boolean): Seq[Any] =
|
||||
{
|
||||
val buildDir = base / "project" / "build"
|
||||
val sources = (buildDir * "*.scala") +++ (buildDir / "src" / "main" / "scala" ** "*.scala")
|
||||
source(Nil, sources.get.toSeq, Some(buildDir / "target" asFile), None, auto, name, configuration, allowMultiple)
|
||||
}
|
||||
|
||||
def binary(classpath: Seq[File], module: Boolean, name: String, parent: ClassLoader, allowMultiple: Boolean): Seq[Any] =
|
||||
{
|
||||
if(name.isEmpty)
|
||||
error("Class name required to load binary project.")
|
||||
else
|
||||
{
|
||||
val names = if(allowMultiple) name.split(",").toSeq else Seq(name)
|
||||
binaries(classpath, names.map(n => ToLoad(n,module)), parent)(_.newInstance)
|
||||
}
|
||||
}
|
||||
|
||||
def compile(command: CompileCommand, configuration: xsbti.AppConfiguration): Analysis =
|
||||
{
|
||||
import command._
|
||||
compile(classpath, sources, output, options, configuration)
|
||||
}
|
||||
def compile(classpath: Seq[File], sources: Seq[File], output: Option[File], options: Seq[String], configuration: xsbti.AppConfiguration): Analysis =
|
||||
compile(new Compile(classpath, sources, output, options, configuration))
|
||||
|
||||
def compile(conf : Compile): Analysis =
|
||||
{
|
||||
import conf._
|
||||
// TODO: accept Logger as an argument
|
||||
val log = ConsoleLogger()
|
||||
|
||||
val componentManager = new ComponentManager(launcher.globalLock, configuration.provider.components, log)
|
||||
val compiler = new AnalyzingCompiler(instance, componentManager, log)
|
||||
val javac = JavaCompiler.directOrFork(compiler.cp, compiler.scalaInstance)( (args: Seq[String], log: Logger) => Process("javac", args) ! log )
|
||||
|
||||
val agg = new AggressiveCompile(cacheDirectory)
|
||||
agg(compiler, javac, sources, compileClasspath, outputDirectory, Nil, options)(log)
|
||||
}
|
||||
def source(classpath: Seq[File], sources: Seq[File], output: Option[File], module: Option[Boolean], auto: Auto.Value, name: String, configuration: xsbti.AppConfiguration, allowMultiple: Boolean = false): Seq[Any] =
|
||||
{
|
||||
val conf = new Compile(classpath, sources, output, Nil, configuration)
|
||||
val analysis = compile(conf)
|
||||
val discovered = discover(analysis, module, auto, name)
|
||||
binaries(conf.projectClasspath, check(discovered, allowMultiple), loader(configuration))( constructCompiled(new Compiled(conf, analysis) ) )
|
||||
}
|
||||
def constructCompiled(compiled: Compiled): Class[_] => Any = clazz =>
|
||||
constructor(clazz, classOf[Compiled]) match {
|
||||
case Some(c) => c.newInstance(compiled)
|
||||
case None => clazz.newInstance
|
||||
}
|
||||
|
||||
def constructor(c: Class[_], args: Class[_]*): Option[java.lang.reflect.Constructor[_]] =
|
||||
try { Some( c.getConstructor( args : _*) ) }
|
||||
catch { case e: NoSuchMethodException => None }
|
||||
|
||||
def discover(analysis: inc.Analysis, module: Option[Boolean], auto: Auto.Value, name: String): Seq[ToLoad] =
|
||||
{
|
||||
import Auto.{Annotation, Explicit, Subclass}
|
||||
auto match {
|
||||
case Explicit => if(name.isEmpty) error("No name specified to load explicitly.") else Seq(new ToLoad(name))
|
||||
case Subclass => discover(analysis, module, new Discovery(Set(name), Set.empty))
|
||||
case Annotation => discover(analysis, module, new Discovery(Set.empty, Set(name)))
|
||||
}
|
||||
}
|
||||
def discover(analysis: inc.Analysis, command: DiscoverCommand): Seq[ToLoad] =
|
||||
discover(analysis, command.module, command.discovery)
|
||||
|
||||
def discover(analysis: inc.Analysis, module: Option[Boolean], discovery: Discovery): Seq[ToLoad] =
|
||||
{
|
||||
for(src <- analysis.apis.internal.values.toSeq;
|
||||
(df, found) <- discovery(src.definitions) if !found.isEmpty && moduleMatches(found.isModule, module))
|
||||
yield
|
||||
new ToLoad(df.name, found.isModule)
|
||||
}
|
||||
def moduleMatches(isModule: Boolean, expected: Option[Boolean]): Boolean =
|
||||
expected.isEmpty || (Some(isModule) == expected)
|
||||
|
||||
def binaries(classpath: Seq[File], toLoad: Seq[ToLoad], parent: ClassLoader)(newImpl: Class[_] => Any): Seq[Any] =
|
||||
loadBinaries(toLoad, toLoader(classpath, parent))(newImpl)
|
||||
|
||||
def loadBinaries(toLoad: Seq[ToLoad], loader: ClassLoader)(newImpl: Class[_] => Any): Seq[Any] =
|
||||
for(ToLoad(name, module) <- toLoad if !name.isEmpty) yield
|
||||
loadBinary(name, module, loader)(newImpl)
|
||||
|
||||
def loadBinary(name: String, module: Boolean, loader: ClassLoader)(newImpl: Class[_] => Any): Any =
|
||||
if(module)
|
||||
getObject(name, loader)
|
||||
else
|
||||
newImpl( Class.forName(name, true, loader) )
|
||||
|
||||
def check[T](discovered: Seq[T], allowMultiple: Boolean): Seq[T] =
|
||||
discovered match
|
||||
{
|
||||
case Seq() => error("No project found")
|
||||
case Seq(x) => discovered
|
||||
case _ => if(allowMultiple) discovered else error("Multiple projects found: " + discovered.mkString(", "))
|
||||
}
|
||||
|
||||
def error(msg: String) = throw new BuildException(msg)
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
package build
|
||||
|
||||
import inc.Analysis
|
||||
import java.io.File
|
||||
import Path._
|
||||
|
||||
final class Compile(val classpath: Seq[File], val sources: Seq[File], output: Option[File], val options: Seq[String], val configuration: xsbti.AppConfiguration)
|
||||
{
|
||||
val scalaProvider = configuration.provider.scalaProvider
|
||||
val launcher = scalaProvider.launcher
|
||||
val instance = ScalaInstance(scalaProvider.version, scalaProvider)
|
||||
|
||||
val out = output.getOrElse(configuration.baseDirectory / "target" asFile)
|
||||
val target = out / ("scala_" + instance.actualVersion)
|
||||
val outputDirectory = target / "classes"
|
||||
val cacheDirectory = target / "cache"
|
||||
val projectClasspath = outputDirectory.asFile +: classpath
|
||||
val compileClasspath = projectClasspath ++ configuration.provider.mainClasspath.toSeq
|
||||
}
|
||||
final class Compiled(val config: Compile, val analysis: Analysis)
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
package build
|
||||
|
||||
import java.io.File
|
||||
import compiler.Discovery
|
||||
|
||||
sealed trait LoadCommand
|
||||
final case class BinaryLoad(classpath: Seq[File], module: Boolean, name: String) extends LoadCommand
|
||||
final case class SourceLoad(classpath: Seq[File], sourcepath: Seq[File], output: Option[File], module: Option[Boolean], auto: Auto.Value, name: String) extends LoadCommand
|
||||
final case class ProjectLoad(base: File, auto: Auto.Value, name: String) extends LoadCommand
|
||||
|
||||
object Auto extends Enumeration
|
||||
{
|
||||
val Subclass, Annotation, Explicit = Value
|
||||
}
|
||||
|
||||
final case class CompileCommand(classpath: Seq[File], sources: Seq[File], output: Option[File], options: Seq[String])
|
||||
final case class DiscoverCommand(module: Option[Boolean], discovery: Discovery)
|
||||
|
||||
final case class ToLoad(name: String, isModule: Boolean = false)
|
||||
{
|
||||
override def toString = tpe + " " + name
|
||||
def tpe = if(isModule) "object" else "class"
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
package build
|
||||
|
||||
import compiler.Discovery
|
||||
import java.io.File
|
||||
|
||||
final class ParseException(msg: String) extends RuntimeException(msg)
|
||||
|
||||
/** Parses a load command. The implementation is a quick hack.
|
||||
It is not robust and errors are not helpful.*/
|
||||
object Parse
|
||||
{
|
||||
def helpBrief(name: String, label: String): (String, String) = (name + " <options>", "Loads " + label + " according to the specified options.")
|
||||
def helpDetail(name: String, label: String, multiple: Boolean) =
|
||||
"Loads " + label + """ by one of the following methods:
|
||||
1) binary: loads a class from an existing classpath
|
||||
2) source: compiles provided sources and loads a specific class
|
||||
3) project: builds from source using default settings
|
||||
|
||||
The command has the following syntax:
|
||||
|
||||
load ::= """ + name + """ ('-help' | binary | source | project)
|
||||
|
||||
binary ::= classpath module? name
|
||||
source ::= classpath? sources out? module? (detect | name)
|
||||
project ::= base? name?
|
||||
|
||||
base ::= '-project' path
|
||||
sources ::= '-src' paths
|
||||
out ::= '-d' dir
|
||||
detect ::= '-auto' ('sub' | 'annot')
|
||||
name ::= '-name' nameString
|
||||
module ::= '-module' ('true'|'false')
|
||||
classpath ::= '-cp' paths
|
||||
path ::= pathChar+
|
||||
paths ::= path (pathSep path)*
|
||||
""" +
|
||||
( if(multiple) "\nTo specify multiple names, separate them by commas." else "")
|
||||
|
||||
import File.{pathSeparatorChar => sep}
|
||||
|
||||
def error(msg: String) = throw new ParseException(msg)
|
||||
def apply(commandString: String)(implicit base: File): LoadCommand =
|
||||
{
|
||||
val args = arguments(commandString)
|
||||
val srcs = sourcepath(args)
|
||||
val nme = name(args)
|
||||
|
||||
lazy val cp = classpath(args)
|
||||
lazy val mod = module(args)
|
||||
lazy val proj = project(args).getOrElse(base)
|
||||
|
||||
if(!srcs.isEmpty)
|
||||
SourceLoad(cp, srcs, output(args), mod, auto(args), nme)
|
||||
else if(!cp.isEmpty)
|
||||
BinaryLoad(cp, mod.getOrElse(false), nme)
|
||||
else
|
||||
ProjectLoad(proj, auto(args), nme)
|
||||
}
|
||||
|
||||
def arguments(in: String) = in.split("""\s+""").toSeq
|
||||
|
||||
def compile(commandString: String)(implicit base: File): CompileCommand =
|
||||
{
|
||||
val args = arguments(commandString)
|
||||
CompileCommand(classpath(args), sourcepath(args), output(args), Nil)
|
||||
}
|
||||
def discover(commandString: String): DiscoverCommand =
|
||||
{
|
||||
val args = arguments(commandString)
|
||||
val subs = names("sub", args)
|
||||
val annots = names("annot", args)
|
||||
DiscoverCommand(module(args), new Discovery(subs, annots))
|
||||
}
|
||||
|
||||
def auto(args: Seq[String]): Auto.Value =
|
||||
getArg(args, "auto") match {
|
||||
case None => Auto.Explicit
|
||||
case Some("sub") => Auto.Subclass
|
||||
case Some("annot") => Auto.Annotation
|
||||
case Some(x) => error("Illegal auto argument '" + x + "'")
|
||||
}
|
||||
|
||||
def module(args: Seq[String]): Option[Boolean] =
|
||||
getArg(args, "module") map {
|
||||
case "false" => false
|
||||
case "true" => true
|
||||
case x => error("Expected boolean, got '" + x + "'")
|
||||
}
|
||||
|
||||
def names(label: String, args: Seq[String]): Set[String] =
|
||||
getArg(args, label) match { case Some(ns) => ns.split(",").toSet; case None => Set.empty }
|
||||
|
||||
def name(args: Seq[String]): String =
|
||||
getArg(args, "name") getOrElse("")
|
||||
|
||||
def output(args: Seq[String])(implicit base: File): Option[File] =
|
||||
getArg(args, "d") map file(base)
|
||||
|
||||
def project(args: Seq[String])(implicit base: File): Option[File] =
|
||||
getArg(args, "project") map file(base)
|
||||
|
||||
def pathArg(args: Seq[String], name: String)(implicit base: File): Seq[File] =
|
||||
getArg(args, name).toSeq flatMap paths
|
||||
|
||||
def classpath(args: Seq[String])(implicit base: File): Seq[File] = pathArg(args, "cp")
|
||||
def sourcepath(args: Seq[String])(implicit base: File): Seq[File] = pathArg(args, "src")
|
||||
|
||||
def getArg(args: Seq[String], name: String): Option[String] =
|
||||
{
|
||||
val opt = "-" + name
|
||||
val found = args.dropWhile(_ != opt)
|
||||
|
||||
if(found.isEmpty)
|
||||
None
|
||||
else
|
||||
found.drop(1).headOption match
|
||||
{
|
||||
case x @ Some(arg) if !arg.startsWith("-") => x
|
||||
case _ => error("No argument provided for -" + name)
|
||||
}
|
||||
}
|
||||
|
||||
def paths(implicit base: File): String => Seq[File] =
|
||||
_ split sep flatMap files(base)
|
||||
|
||||
def files(base: File)(path: String): Seq[File] = readFinder(Path.fromFile(base), path).getFiles
|
||||
|
||||
def file(base: File) = (path: String) => Path.fromString(base, path).asFile
|
||||
|
||||
def readFinder(base: File, s: String): PathFinder =
|
||||
{
|
||||
val f = new File(s)
|
||||
asFinder( if(f.isAbsolute) f else new File(base, s) )
|
||||
}
|
||||
def asFinder(f: File): PathFinder =
|
||||
{
|
||||
val parent = f.getParentFile
|
||||
if(parent eq null)
|
||||
Path.fromFile(f)
|
||||
else
|
||||
{
|
||||
val finder = asFinder(parent)
|
||||
val sub = f.getName
|
||||
if(sub == "**") (finder ***) else if(sub contains "*") finder * GlobFilter(sub) else finder / sub
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
|
||||
import std._
|
||||
import compile.{Discovered,Discovery}
|
||||
|
||||
abstract class BasicProject
|
||||
{
|
||||
override def watchPaths: PathFinder = (info.projectDirectory: Path) * sourceFilter +++ descendents("src","*")
|
||||
|
||||
def javapCompiledTask(conf: Configuration): Task[Unit] =
|
||||
javapTask(taskData(fullClasspath(conf)), buildScalaInstance)
|
||||
|
||||
// lazy val test-quick, test-failed, javap, javap-quick, jetty-{run,stop,restart}, prepare-webapp, watch paths
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2010 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
|
||||
import std._
|
||||
import Path._
|
||||
import TaskExtra._
|
||||
import Types._
|
||||
import OutputUtil._
|
||||
import java.io.{BufferedReader,File}
|
||||
import java.util.regex.Pattern
|
||||
|
||||
trait LastOutput
|
||||
{
|
||||
def input: Task[Input]
|
||||
def streams: Task[TaskStreams]
|
||||
def context: Task[Transform.Context[Project]]
|
||||
|
||||
lazy val last = (streams, input, context) flatMap { case s :+: i :+: ctx :+: HNil =>
|
||||
mapLast(s, ctx, i.arguments) { reader =>
|
||||
val out = s.text()
|
||||
foreachLine(reader) { line =>
|
||||
out.println(line)
|
||||
println(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lazy val grepLast = (streams, input, context) flatMap { case s :+: i :+: ctx :+: HNil =>
|
||||
val i2 = new Input(i.arguments, None)
|
||||
val pattern = Pattern.compile(i2.arguments)
|
||||
mapLast(s, ctx, i2.name) { reader =>
|
||||
val out = s.text()
|
||||
foreachLine(reader) { line =>
|
||||
showMatches(pattern, line) foreach { line =>
|
||||
out.println(line)
|
||||
println(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
object OutputUtil
|
||||
{
|
||||
def showMatches(pattern: Pattern, line: String): Option[String] =
|
||||
{
|
||||
val matcher = pattern.matcher(line)
|
||||
if(ConsoleLogger.formatEnabled)
|
||||
{
|
||||
val highlighted = matcher.replaceAll(scala.Console.RED + "$0" + scala.Console.RESET)
|
||||
if(highlighted == line) None else Some(highlighted)
|
||||
}
|
||||
else if(matcher.find)
|
||||
Some(line)
|
||||
else
|
||||
None
|
||||
}
|
||||
def mapLast[T](s: TaskStreams, ctx: Transform.Context[Project], taskName: String)(f: BufferedReader => T): Task[Task.Cross[T]] =
|
||||
{
|
||||
val task = taskForName(ctx, taskName)
|
||||
s.readText( task, update = false ).map( f ).merge
|
||||
}
|
||||
def foreachLine(reader: BufferedReader)(f: String => Unit)
|
||||
{
|
||||
def readL()
|
||||
{
|
||||
val line = reader.readLine()
|
||||
if(line ne null) {
|
||||
f(line)
|
||||
readL()
|
||||
}
|
||||
}
|
||||
readL()
|
||||
}
|
||||
def taskForName(ctx: Transform.Context[Project], name: String): Task[_] =
|
||||
ctx.static(ctx.rootOwner, MultiProject.transformName(name)).getOrElse(error("No task '" + name + "'"))
|
||||
}
|
||||
trait Exec
|
||||
{
|
||||
def input: Task[Input]
|
||||
def streams: Task[TaskStreams]
|
||||
def fork(p: Seq[String], log: Logger): Unit = fork(Process(p), log)
|
||||
def fork(p: ProcessBuilder, log: Logger): Unit =
|
||||
{
|
||||
val exitValue = p ! log
|
||||
if(exitValue != 0) error("Nonzero exit value: " + exitValue)
|
||||
}
|
||||
def forkWithCode(p: ProcessBuilder, log: Logger): Task[Int] = streams map { s => p ! log }
|
||||
|
||||
lazy val sh = (input, streams) map { case in :+: s :+: HNil => fork("sh" :: "-c" :: in.arguments :: Nil, s.log) }
|
||||
lazy val exec = (input, streams) map { case in :+: s :+: HNil => fork( Process(in.splitArgs), s.log ) }
|
||||
}
|
||||
trait Javap extends Exec
|
||||
{
|
||||
def javapTask(classpath: Task[Seq[File]], scalaInstance: Task[ScalaInstance]): Task[Unit] =
|
||||
javapTask( (classpath, scalaInstance) map { case cp :+: si :+: HNil => cp ++ si.jars } )
|
||||
def javapTask(classpath: Task[Seq[File]]): Task[Unit] =
|
||||
(input, classpath, streams) map { case in :+: cp :+: s :+: HNil =>
|
||||
val args = in.splitArgs
|
||||
val argsWithClasspath = if(cp.isEmpty) args else "-classpath" +: Path.makeString(cp) +: args
|
||||
fork("javap" +: argsWithClasspath, s.log)
|
||||
}
|
||||
}
|
||||
|
|
@ -74,11 +74,6 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
|
|||
// Searches the source API data structures, currently looks for subclasses and annotations
|
||||
val discoverySub = project(compilePath / "discover", "Discovery", new DiscoveryProject(_), compileIncrementalSub, apiSub)
|
||||
|
||||
|
||||
// mostly for implementing 'load' command, could perhaps be trimmed and merged into 'main'
|
||||
val buildSub = baseProject("main" / "build", "Project Builder",
|
||||
classfileSub, classpathSub, compilePersistSub, compilerSub, compileIncrementalSub, interfaceSub, ivySub, launchInterfaceSub, logSub, discoverySub, processSub)
|
||||
|
||||
val scriptedBaseSub = project("scripted" / "base", "Scripted Framework", new TestProject(_), ioSub, processSub)
|
||||
val scriptedSbtSub = baseProject("scripted" / "sbt", "Scripted sbt", ioSub, logSub, processSub, scriptedBaseSub, launchInterfaceSub /*should really be a 'provided' dependency*/)
|
||||
val scriptedPluginSub = project("scripted" / "plugin", "Scripted Plugin", new Scripted(_))
|
||||
|
|
@ -87,8 +82,8 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
|
|||
val stdTaskSub = testedBase(tasksPath / "standard", "Task System", taskSub, collectionSub, logSub, ioSub, processSub)
|
||||
// The main integration project for sbt. It brings all of the subsystems together, configures them, and provides for overriding conventions.
|
||||
val mainSub = baseProject("main", "Main",
|
||||
buildSub, compileIncrementalSub, compilerSub, completeSub, discoverySub,
|
||||
ioSub, logSub, processSub, taskSub, stdTaskSub, runSub, trackingSub, testingSub)
|
||||
classfileSub, classpathSub, compileIncrementalSub, compilePersistSub, compilerSub, completeSub, discoverySub,
|
||||
interfaceSub, ioSub, ivySub, launchInterfaceSub, logSub, processSub, taskSub, stdTaskSub, runSub, trackingSub, testingSub)
|
||||
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
|
||||
val sbtSub = project(sbtPath, "Simple Build Tool", new Sbt(_), mainSub) // technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue