diff --git a/src/main/scala/sbt/DefaultProject.scala b/src/main/scala/sbt/DefaultProject.scala index bba9655df..b7e9f6a77 100644 --- a/src/main/scala/sbt/DefaultProject.scala +++ b/src/main/scala/sbt/DefaultProject.scala @@ -292,6 +292,9 @@ abstract class BasicScalaProject extends ScalaProject with BasicDependencyProjec lazy val testFailed = testFailedAction lazy val testOnly = testOnlyAction + lazy val javap = javapTask(runClasspath, mainCompileConditional, mainCompilePath) + lazy val testJavap = javapTask(testClasspath, testCompileConditional, testCompilePath) + def jarsOfProjectDependencies = Path.lazyPathFinder { topologicalSort.dropRight(1) flatMap { p => p match @@ -318,7 +321,7 @@ abstract class BasicWebScalaProject extends BasicScalaProject with WebScalaProje protected def prepareWebappAction = prepareWebappTask(webappResources, temporaryWarPath, webappClasspath, mainDependencies.scalaJars) dependsOn(compile, copyResources) - private lazy val jettyInstance = new JettyRunner(jettyConfiguration) + lazy val jettyInstance = new JettyRunner(jettyConfiguration) def jettyConfiguration = new DefaultJettyConfiguration diff --git a/src/main/scala/sbt/ScalaProject.scala b/src/main/scala/sbt/ScalaProject.scala index 5fa96e7b3..b3112db6d 100644 --- a/src/main/scala/sbt/ScalaProject.scala +++ b/src/main/scala/sbt/ScalaProject.scala @@ -8,7 +8,7 @@ import java.io.File import java.util.jar.{Attributes, Manifest} import scala.collection.mutable.ListBuffer -trait SimpleScalaProject extends Project +trait SimpleScalaProject extends ExecProject { def errorTask(message: String) = task{ Some(message) } @@ -53,19 +53,8 @@ trait SimpleScalaProject extends Project pathClean orElse restored } } - def execTask(buildCommand: => ProcessBuilder): Task = - task - { - val command = buildCommand - log.debug("Executing command " + command) - val exitValue = command.run(log).exitValue() // don't buffer output - if(exitValue == 0) - None - else - Some("Nonzero exit value: " + exitValue) - } } -trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProject +trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProject with Exec { import ScalaProject._ @@ -124,6 +113,17 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje val Private = Value("private") } + def javapTask(classpath: PathFinder, conditional: CompileConditional, outputPath: Path) = + task { args => + val cp = classpath +++ Path.fromFile(FileUtilities.scalaLibraryJar) +++ Path.fromFile(FileUtilities.scalaCompilerJar) + execOut { Process("javap" :: "-classpath" :: Path.makeString(cp.get) :: args.toList) } + } completeWith(classNames(conditional, outputPath)) + private def classNames(conditional: CompileConditional, outputPath: Path) = + { + val classes = conditional.analysis.allProducts.flatMap(Path.relativize(outputPath, _)) + classes.map(_.relativePath.replace(java.io.File.separatorChar, '.').toList.dropRight(".class".length).mkString).toSeq + } + def consoleTask(classpath : PathFinder): Task = consoleTask(classpath, Run) def consoleTask(classpath : PathFinder, runner: ScalaRun): Task = @@ -363,4 +363,32 @@ trait MultiTaskProject extends Project run(includeFunction) } completeWith allTests +} +trait ExecProject extends Project +{ + def execOut(p: => ProcessBuilder) = + task + { + val exitValue = (p !) + if(exitValue == 0) + None + else + Some("Nonzero exit value: " + exitValue) + } + def execTask(buildCommand: => ProcessBuilder): Task = + task + { + val command = buildCommand + log.debug("Executing command " + command) + val exitValue = command.run(log).exitValue() // don't buffer output + if(exitValue == 0) + None + else + Some("Nonzero exit value: " + exitValue) + } +} +trait Exec extends SimpleScalaProject +{ + lazy val sh = task { args => execOut { Process("sh" :: "-c" :: args.mkString(" ") :: Nil) } } + lazy val exec = task { args => execOut { Process(args) } } } \ No newline at end of file diff --git a/src/main/scala/sbt/TestReportListener.scala b/src/main/scala/sbt/TestReportListener.scala index 09e2a97d0..2f664937c 100644 --- a/src/main/scala/sbt/TestReportListener.scala +++ b/src/main/scala/sbt/TestReportListener.scala @@ -22,8 +22,6 @@ trait TestsListener extends TestReportListener def doInit /** called once, at end. */ def doComplete(finalResult: Result.Value) - /** called once, at end, if the test framework throws an exception. */ - @deprecated def doComplete(t: Throwable) } abstract class WriterReportListener(val log: Logger) extends TestsListener @@ -281,7 +279,7 @@ class SpecsOutput(val log: Logger) extends EventOutput[SpecsEvent] } } -class LogTestReportListener(val log: Logger) extends TestReportListener +class LogTestReportListener(val log: Logger) extends TestsListener { lazy val scalaCheckOutput: EventOutput[ScalaCheckEvent] = createScalaCheckOutput lazy val scalaTestOutput: EventOutput[ScalaTestEvent] = createScalaTestOutput @@ -295,6 +293,7 @@ class LogTestReportListener(val log: Logger) extends TestReportListener def testEvent(event: TestEvent) { log.debug("in testEvent:" + event) + count(event) event match { case sce: ScalaCheckEvent => scalaCheckOutput.output(sce) @@ -313,4 +312,28 @@ class LogTestReportListener(val log: Logger) extends TestReportListener { log.debug("in endGroup:" + result) } + protected def count(event: TestEvent): Unit = + { + for(result <- event.result) + { + totalTests += 1 + result match + { + case Result.Error => errors += 1 + case Result.Failed => failed += 1 + case Result.Passed => passed += 1 + } + } + } + protected var totalTests, errors, passed, failed = 0 + def doInit + { + totalTests = 0 + errors = 0 + passed = 0 + failed = 0 + } + /** called once, at end. */ + def doComplete(finalResult: Result.Value): Unit = + log.info(Run: {totalTests.toString}, Passed: {passed.toString}, Errors: {errors.toString}, Failed: {failed.toString}.text) } diff --git a/src/main/scala/sbt/impl/ProcessImpl.scala b/src/main/scala/sbt/impl/ProcessImpl.scala index 325cabf15..af7c7dd90 100644 --- a/src/main/scala/sbt/impl/ProcessImpl.scala +++ b/src/main/scala/sbt/impl/ProcessImpl.scala @@ -9,7 +9,6 @@ import java.io.{FilterInputStream, FilterOutputStream, PipedInputStream, PipedOu import java.io.{File, FileInputStream, FileOutputStream} import java.net.URL -import scala.concurrent.ops.future import scala.concurrent.SyncVar /** Runs provided code in a new Thread and returns the Thread instance. */ @@ -24,6 +23,23 @@ private object Spawn thread } } +private object Future +{ + def apply[T](f: => T): () => T = + { + val result = new SyncVar[Either[Throwable, T]] + def run: Unit = + try { result.set(Right(f)) } + catch { case e: Exception => result.set(Left(e)) } + Spawn(run) + () => + result.get match + { + case Right(value) => value + case Left(exception) => throw exception + } + } +} private object BasicIO { @@ -156,7 +172,7 @@ private abstract class CompoundProcess extends BasicProcess val thread = Spawn(code.set(runAndExitValue())) ( - future { thread.join(); code.get }, + Future { thread.join(); code.get }, () => thread.interrupt() ) } @@ -312,7 +328,7 @@ private[sbt] class DummyProcessBuilder(override val toString: String, exitValue * The implementation of `exitValue` waits until these threads die before returning. */ private class DummyProcess(action: => Int) extends Process { - private[this] val exitCode = scala.concurrent.ops.future(action) + private[this] val exitCode = Future(action) override def exitValue() = exitCode() override def destroy() {} } diff --git a/src/main/scala/sbt/wrap/Wrappers.scala b/src/main/scala/sbt/wrap/Wrappers.scala index e78ca2207..d5cfd4b93 100644 --- a/src/main/scala/sbt/wrap/Wrappers.scala +++ b/src/main/scala/sbt/wrap/Wrappers.scala @@ -80,6 +80,7 @@ private[sbt] sealed abstract class Map[K,V] extends Iterable[(K,V)] { def apply(key: K): V def get(key: K): Option[V] + def containsKey(key: K): Boolean final def getOrElse[V2 >: V](key: K, default: => V2): V2 = get(key) match { @@ -98,6 +99,7 @@ private[sbt] sealed abstract class MapWrapper[K,V](val underlying: JMap[K,V]) ex else Some(value) } + final def containsKey(key: K) = underlying.containsKey(key) final def toList = Wrappers.toList(underlying) final def values = toList.map(_._2) } @@ -116,5 +118,6 @@ private[sbt] sealed class MutableMapWrapper[K,V](wrapped: JMap[K,V]) extends Map final def update(key: K, value: V) { underlying.put(key, value) } final def +=(pair: (K, V) ) { update(pair._1, pair._2) } final def -=(key: K) { underlying.remove(key) } + final def remove(key: K) = underlying.remove(key) final def readOnly: Map[K,V] = this } \ No newline at end of file