Explicitly, optimistically close export streams early: workaround for #937

This is a temporary workaround: it assumes nothing else uses these streams later.
This condition is ok for 'export' and test streams, since these are unlikely to
reuse these streams.  However, the proper fix is for the TaskStreams methods
to be smarter- they could open in append mode if the stream was closed.  The
streams associated with a task could be optimistically closed after it finishes executing.
(Any task can write to another task's streams, which is why it is an optimization only.)
This commit is contained in:
Mark Harrah 2013-11-04 11:45:23 -05:00
parent a92b883e23
commit ca7e78d03d
3 changed files with 20 additions and 12 deletions

View File

@ -35,6 +35,7 @@ $ShowCommand <task>
val LastCommand = "last"
val LastGrepCommand = "last-grep"
val ExportCommand = "export"
val ExportStream = "export"
val lastGrepBrief = (LastGrepCommand, "Shows lines from the last output for 'key' that match 'pattern'.")
val lastGrepDetailed =

View File

@ -26,6 +26,7 @@ package sbt
import java.util.concurrent.Callable
import sbinary.DefaultProtocol.StringFormat
import Cache.seqFormat
import CommandStrings.ExportStream
import Types._
import Path._
@ -401,7 +402,7 @@ object Defaults extends BuildCommon
val opts = forkOptions.value
Seq(new Tests.Group("<default>", tests, if(fk) Tests.SubProcess(opts) else Tests.InProcess))
}
private[this] def forkOptions: Initialize[Task[ForkOptions]] =
private[this] def forkOptions: Initialize[Task[ForkOptions]] =
(baseDirectory, javaOptions, outputStrategy, envVars, javaHome, connectInput) map {
(base, options, strategy, env, javaHomeDir, connectIn) =>
// bootJars is empty by default because only jars on the user's classpath should be on the boot classpath
@ -460,7 +461,7 @@ object Defaults extends BuildCommon
val newConfig = config.copy(options = modifiedOpts)
val output = allTestGroupsTask(s, loadedTestFrameworks.value, testLoader.value, testGrouping.value, newConfig, fullClasspath.value, javaHome.value)
val processed =
for(out <- output) yield
for(out <- output) yield
Tests.showResults(s.log, out, noTestsMessage(resolvedScoped.value))
Def.value(processed)
}
@ -491,8 +492,8 @@ object Defaults extends BuildCommon
}
}
val output = Tests.foldTasks(groupTasks, config.parallel)
output map { out =>
val summaries =
output map { out =>
val summaries =
runners map { case (tf, r) =>
Tests.Summary(frameworks(tf).name, r.done())
}
@ -708,8 +709,11 @@ object Defaults extends BuildCommon
private[this] def exported(w: PrintWriter, command: String): Seq[String] => Unit = args =>
w.println( (command +: args).mkString(" ") )
private[this] def exported(s: TaskStreams, command: String): Seq[String] => Unit = args =>
exported(s.text("export"), command)
private[this] def exported(s: TaskStreams, command: String): Seq[String] => Unit = args => {
val w = s.text(ExportStream)
try exported(w, command)
finally w.close() // workaround for #937
}
@deprecated("Use inTask(compile)(compileInputsSettings)", "0.13.0")
def compileTaskSettings: Seq[Setting[_]] = inTask(compile)(compileInputsSettings)
@ -717,10 +721,11 @@ object Defaults extends BuildCommon
def compileTask: Initialize[Task[inc.Analysis]] = Def.task { compileTaskImpl(streams.value, (compileInputs in compile).value) }
private[this] def compileTaskImpl(s: TaskStreams, ci: Compiler.Inputs): inc.Analysis =
{
lazy val x = s.text("export")
lazy val x = s.text(ExportStream)
def onArgs(cs: Compiler.Compilers) = cs.copy(scalac = cs.scalac.onArgs(exported(x, "scalac")), javac = cs.javac.onArgs(exported(x, "javac")))
val i = ci.copy(compilers = onArgs(ci.compilers))
Compiler(i,s.log)
try Compiler(i,s.log)
finally x.close() // workaround for #937
}
def compileIncSetupTask =
(dependencyClasspath, skip in compile, definesClass, compilerCache, streams, incOptions) map { (cp, skip, definesC, cache, s, incOptions) =>
@ -882,7 +887,9 @@ object Classpaths
s.mapInitialize(init => Def.task { exportClasspath(streams.value, init.value) })
private[this] def exportClasspath(s: TaskStreams, cp: Classpath): Classpath =
{
s.text("export").println(Path.makeString(data(cp)))
val w = s.text(ExportStream)
try w.println(Path.makeString(data(cp)))
finally w.close() // workaround for #937
cp
}
@ -1403,7 +1410,7 @@ object Classpaths
plugins.map("-Xplugin:" + _.getAbsolutePath).toSeq
}
private[this] lazy val internalCompilerPluginClasspath: Initialize[Task[Classpath]] =
private[this] lazy val internalCompilerPluginClasspath: Initialize[Task[Classpath]] =
(thisProjectRef, settingsData, buildDependencies) flatMap { (ref, data, deps) =>
internalDependencies0(ref, CompilerPlugin, CompilerPlugin, data, deps)
}
@ -1564,7 +1571,7 @@ trait BuildExtra extends BuildCommon
}
}
private[this] def inBase(name: String): Initialize[File] = Def.setting { baseDirectory.value / name }
def externalIvyFile(file: Initialize[File] = inBase("ivy.xml"), iScala: Initialize[Option[IvyScala]] = ivyScala): Setting[Task[ModuleSettings]] =
moduleSettings := new IvyFileConfiguration(file.value, iScala.value, ivyValidate.value, managedScalaInstance.value)
def externalPom(file: Initialize[File] = inBase("pom.xml"), iScala: Initialize[Option[IvyScala]] = ivyScala): Setting[Task[ModuleSettings]] =

View File

@ -307,7 +307,7 @@ object BuiltinCommands
kvs = Act.keyValues(structure)(lastOnly_keys._2)
f <- if(lastOnly_keys._1) success(() => s) else Aggregation.evaluatingParser(s, structure, show)(kvs)
} yield () => {
def export0(s: State): State = lastImpl(s, kvs, Some("export"))
def export0(s: State): State = lastImpl(s, kvs, Some(ExportStream))
val newS = try f() catch { case e: Exception =>
try export0(s)
finally { throw e }