Merge pull request #3189 from eed3si9n/wip/more-case-class

[sbt 1.0] migrate ForkOptions to Contraband
This commit is contained in:
Dale Wijnand 2017-05-12 11:12:48 +01:00 committed by GitHub
commit 50cc045a70
13 changed files with 255 additions and 70 deletions

View File

@ -167,9 +167,13 @@ lazy val stdTaskProj = (project in file("tasks-standard"))
// Embedded Scala code runner
lazy val runProj = (project in file("run"))
.enablePlugins(ContrabandPlugin)
.settings(
testedBaseSettings,
name := "Run"
name := "Run",
managedSourceDirectories in Compile +=
baseDirectory.value / "src" / "main" / "contraband-scala",
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala"
)
.configure(addSbtIO, addSbtUtilLogging, addSbtCompilerClasspath)

View File

@ -682,13 +682,13 @@ object Defaults extends BuildCommon {
def forkOptionsTask: Initialize[Task[ForkOptions]] =
Def.task {
ForkOptions(
// bootJars is empty by default because only jars on the user's classpath should be on the boot classpath
bootJars = Nil,
javaHome = javaHome.value,
connectInput = connectInput.value,
outputStrategy = outputStrategy.value,
runJVMOptions = javaOptions.value,
// bootJars is empty by default because only jars on the user's classpath should be on the boot classpath
bootJars = Vector(),
workingDirectory = Some(baseDirectory.value),
runJVMOptions = javaOptions.value.toVector,
connectInput = connectInput.value,
envVars = envVars.value
)
}

View File

@ -8,4 +8,4 @@ scalacOptions ++= Seq("-feature", "-language:postfixOps")
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.7.0-RC1")
// addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.2.0")
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.4.0")
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.0-M4")
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.0-M5")

View File

@ -0,0 +1,85 @@
/**
* This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package sbt
/** Configures forking. */
final class ForkOptions private (
/** The Java installation to use. If not defined, the Java home for the current process is used. */
val javaHome: Option[java.io.File],
/**
* Configures the forked standard output and error streams.
* If not defined, StdoutOutput is used, which maps the forked output to the output of
* this process and the forked error to the error stream of the forking process.
*/
val outputStrategy: Option[sbt.OutputStrategy],
/** The Vector of jars to put on the forked boot classpath. By default, this is empty. */
val bootJars: Vector[java.io.File],
/**
* The directory to use as the working directory for the forked process.
* By default, this is the working directory of the forking process.
*/
val workingDirectory: Option[java.io.File],
/** The options to prepend to all user-specified arguments. By default, this is empty. */
val runJVMOptions: Vector[String],
/**
* If true, the standard input of the forked process is connected to the standard input of this process. Otherwise, it is connected to an empty input stream.
* Connecting input streams can be problematic, especially on versions before Java 7.
*/
val connectInput: Boolean,
/** The environment variables to provide to the forked process. By default, none are provided. */
val envVars: scala.collection.immutable.Map[String, String]) extends Serializable {
private def this() = this(None, None, Vector(), None, Vector(), false, Map())
override def equals(o: Any): Boolean = o match {
case x: ForkOptions => (this.javaHome == x.javaHome) && (this.outputStrategy == x.outputStrategy) && (this.bootJars == x.bootJars) && (this.workingDirectory == x.workingDirectory) && (this.runJVMOptions == x.runJVMOptions) && (this.connectInput == x.connectInput) && (this.envVars == x.envVars)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + javaHome.##) + outputStrategy.##) + bootJars.##) + workingDirectory.##) + runJVMOptions.##) + connectInput.##) + envVars.##)
}
override def toString: String = {
"ForkOptions(" + javaHome + ", " + outputStrategy + ", " + bootJars + ", " + workingDirectory + ", " + runJVMOptions + ", " + connectInput + ", " + envVars + ")"
}
protected[this] def copy(javaHome: Option[java.io.File] = javaHome, outputStrategy: Option[sbt.OutputStrategy] = outputStrategy, bootJars: Vector[java.io.File] = bootJars, workingDirectory: Option[java.io.File] = workingDirectory, runJVMOptions: Vector[String] = runJVMOptions, connectInput: Boolean = connectInput, envVars: scala.collection.immutable.Map[String, String] = envVars): ForkOptions = {
new ForkOptions(javaHome, outputStrategy, bootJars, workingDirectory, runJVMOptions, connectInput, envVars)
}
def withJavaHome(javaHome: Option[java.io.File]): ForkOptions = {
copy(javaHome = javaHome)
}
def withJavaHome(javaHome: java.io.File): ForkOptions = {
copy(javaHome = Option(javaHome))
}
def withOutputStrategy(outputStrategy: Option[sbt.OutputStrategy]): ForkOptions = {
copy(outputStrategy = outputStrategy)
}
def withOutputStrategy(outputStrategy: sbt.OutputStrategy): ForkOptions = {
copy(outputStrategy = Option(outputStrategy))
}
def withBootJars(bootJars: Vector[java.io.File]): ForkOptions = {
copy(bootJars = bootJars)
}
def withWorkingDirectory(workingDirectory: Option[java.io.File]): ForkOptions = {
copy(workingDirectory = workingDirectory)
}
def withWorkingDirectory(workingDirectory: java.io.File): ForkOptions = {
copy(workingDirectory = Option(workingDirectory))
}
def withRunJVMOptions(runJVMOptions: Vector[String]): ForkOptions = {
copy(runJVMOptions = runJVMOptions)
}
def withConnectInput(connectInput: Boolean): ForkOptions = {
copy(connectInput = connectInput)
}
def withEnvVars(envVars: scala.collection.immutable.Map[String, String]): ForkOptions = {
copy(envVars = envVars)
}
}
object ForkOptions {
def apply(): ForkOptions = new ForkOptions(None, None, Vector(), None, Vector(), false, Map())
def apply(javaHome: Option[java.io.File], outputStrategy: Option[sbt.OutputStrategy], bootJars: Vector[java.io.File], workingDirectory: Option[java.io.File], runJVMOptions: Vector[String], connectInput: Boolean, envVars: scala.collection.immutable.Map[String, String]): ForkOptions = new ForkOptions(javaHome, outputStrategy, bootJars, workingDirectory, runJVMOptions, connectInput, envVars)
def apply(javaHome: java.io.File, outputStrategy: sbt.OutputStrategy, bootJars: Vector[java.io.File], workingDirectory: java.io.File, runJVMOptions: Vector[String], connectInput: Boolean, envVars: scala.collection.immutable.Map[String, String]): ForkOptions = new ForkOptions(Option(javaHome), Option(outputStrategy), bootJars, Option(workingDirectory), runJVMOptions, connectInput, envVars)
}

View File

@ -0,0 +1,30 @@
package sbt
@target(Scala)
## Configures forking.
type ForkOptions {
## The Java installation to use. If not defined, the Java home for the current process is used.
javaHome: java.io.File @since("0.1.0")
## Configures the forked standard output and error streams.
## If not defined, StdoutOutput is used, which maps the forked output to the output of
## this process and the forked error to the error stream of the forking process.
outputStrategy: sbt.OutputStrategy @since("0.1.0")
## The Vector of jars to put on the forked boot classpath. By default, this is empty.
bootJars: [java.io.File] @since("0.1.0")
## The directory to use as the working directory for the forked process.
## By default, this is the working directory of the forking process.
workingDirectory: java.io.File @since("0.1.0")
## The options to prepend to all user-specified arguments. By default, this is empty.
runJVMOptions: [String] @since("0.1.0")
## If true, the standard input of the forked process is connected to the standard input of this process. Otherwise, it is connected to an empty input stream.
## Connecting input streams can be problematic, especially on versions before Java 7.
connectInput: Boolean! = false @since("0.1.0")
## The environment variables to provide to the forked process. By default, none are provided.
envVars: StringStringMap! = raw"Map()" @since("0.1.0")
}

View File

@ -3,56 +3,10 @@
*/
package sbt
import java.io.{ File, OutputStream }
import java.io.File
import java.util.Locale
import sbt.util.Logger
import scala.sys.process.Process
/**
* Configures forking.
*
* @param javaHome The Java installation to use. If not defined, the Java home for the current process is used.
* @param outputStrategy Configures the forked standard output and error streams. If not defined, StdoutOutput is used, which maps the forked output to the output of this process and the forked error to the error stream of the forking process.
* @param bootJars The list of jars to put on the forked boot classpath. By default, this is empty.
* @param workingDirectory The directory to use as the working directory for the forked process. By default, this is the working directory of the forking process.
* @param runJVMOptions The options to prepend to all user-specified arguments. By default, this is empty.
* @param connectInput If true, the standard input of the forked process is connected to the standard input of this process. Otherwise, it is connected to an empty input stream. Connecting input streams can be problematic, especially on versions before Java 7.
* @param envVars The environment variables to provide to the forked process. By default, none are provided.
*/
final case class ForkOptions(
javaHome: Option[File] = None,
outputStrategy: Option[OutputStrategy] = None,
bootJars: Seq[File] = Nil,
workingDirectory: Option[File] = None,
runJVMOptions: Seq[String] = Nil,
connectInput: Boolean = false,
envVars: Map[String, String] = Map.empty
)
/** Configures where the standard output and error streams from a forked process go.*/
sealed abstract class OutputStrategy
/**
* Configures the forked standard output to go to standard output of this process and
* for the forked standard error to go to the standard error of this process.
*/
case object StdoutOutput extends OutputStrategy
/**
* Logs the forked standard output at the `info` level and the forked standard error at the `error` level.
* The output is buffered until the process completes, at which point the logger flushes it (to the screen, for example).
*/
case class BufferedOutput(logger: Logger) extends OutputStrategy
/** Logs the forked standard output at the `info` level and the forked standard error at the `error` level. */
case class LoggedOutput(logger: Logger) extends OutputStrategy
/**
* Configures the forked standard output to be sent to `output` and the forked standard error
* to be sent to the standard error of this process.
*/
case class CustomOutput(output: OutputStream) extends OutputStrategy
import OutputStrategy._
/**
* Represents a command that can be forked.
@ -83,14 +37,17 @@ final class Fork(val commandName: String, val runnerClass: Option[String]) {
val (classpathEnv, options) = Fork.fitClasspath(preOptions)
val command = executable +: options
val environment = env ++ classpathEnv.map(value => Fork.ClasspathEnvKey -> value)
val environment: List[(String, String)] = env.toList ++
(classpathEnv map { value =>
Fork.ClasspathEnvKey -> value
})
val process = Process(command, workingDirectory, environment.toList: _*)
outputStrategy.getOrElse(StdoutOutput) match {
case StdoutOutput => process.run(connectInput)
case BufferedOutput(logger) => logger.buffer { process.run(logger, connectInput) }
case LoggedOutput(logger) => process.run(logger, connectInput)
case CustomOutput(output) => (process #> output).run(connectInput)
case StdoutOutput => process.run(connectInput)
case out: BufferedOutput => out.logger.buffer { process.run(out.logger, connectInput) }
case out: LoggedOutput => process.run(out.logger, connectInput)
case out: CustomOutput => (process #> out.output).run(connectInput)
}
}
private[this] def makeOptions(jvmOptions: Seq[String],

View File

@ -0,0 +1,99 @@
package sbt
import sbt.util.Logger
import java.io.OutputStream
/** Configures where the standard output and error streams from a forked process go.*/
sealed abstract class OutputStrategy
object OutputStrategy {
/**
* Configures the forked standard output to go to standard output of this process and
* for the forked standard error to go to the standard error of this process.
*/
case object StdoutOutput extends OutputStrategy
/**
* Logs the forked standard output at the `info` level and the forked standard error at
* the `error` level. The output is buffered until the process completes, at which point
* the logger flushes it (to the screen, for example).
*/
final class BufferedOutput private (val logger: Logger)
extends OutputStrategy
with Serializable {
override def equals(o: Any): Boolean = o match {
case x: BufferedOutput => (this.logger == x.logger)
case _ => false
}
override def hashCode: Int = {
37 * (17 + logger.##) + "BufferedOutput".##
}
override def toString: String = {
"BufferedOutput(" + logger + ")"
}
protected[this] def copy(logger: Logger = logger): BufferedOutput = {
new BufferedOutput(logger)
}
def withLogger(logger: Logger): BufferedOutput = {
copy(logger = logger)
}
}
object BufferedOutput {
def apply(logger: Logger): BufferedOutput = new BufferedOutput(logger)
}
/**
* Logs the forked standard output at the `info` level and the forked standard error at
* the `error` level.
*/
final class LoggedOutput private (val logger: Logger) extends OutputStrategy with Serializable {
override def equals(o: Any): Boolean = o match {
case x: LoggedOutput => (this.logger == x.logger)
case _ => false
}
override def hashCode: Int = {
37 * (17 + logger.##) + "LoggedOutput".##
}
override def toString: String = {
"LoggedOutput(" + logger + ")"
}
protected[this] def copy(logger: Logger = logger): LoggedOutput = {
new LoggedOutput(logger)
}
def withLogger(logger: Logger): LoggedOutput = {
copy(logger = logger)
}
}
object LoggedOutput {
def apply(logger: Logger): LoggedOutput = new LoggedOutput(logger)
}
/**
* Configures the forked standard output to be sent to `output` and the forked standard error
* to be sent to the standard error of this process.
*/
final class CustomOutput private (val output: OutputStream)
extends OutputStrategy
with Serializable {
override def equals(o: Any): Boolean = o match {
case x: CustomOutput => (this.output == x.output)
case _ => false
}
override def hashCode: Int = {
37 * (17 + output.##) + "CustomOutput".##
}
override def toString: String = {
"CustomOutput(" + output + ")"
}
protected[this] def copy(output: OutputStream = output): CustomOutput = {
new CustomOutput(output)
}
def withOutput(output: OutputStream): CustomOutput = {
copy(output = output)
}
}
object CustomOutput {
def apply(output: OutputStream): CustomOutput = new CustomOutput(output)
}
}

View File

@ -44,7 +44,7 @@ class ForkRun(config: ForkOptions) extends ScalaRun {
val scalaOptions = classpathOption(classpath) ::: mainClass :: options.toList
val configLogged =
if (config.outputStrategy.isDefined) config
else config.copy(outputStrategy = Some(LoggedOutput(log)))
else config.withOutputStrategy(OutputStrategy.LoggedOutput(log))
// fork with Java because Scala introduces an extra class loader (#702)
Fork.java.fork(configLogged, scalaOptions)
}

View File

@ -7,6 +7,7 @@ import java.io.File
import sbt.internal.TestLogger
import sbt.io.{ IO, Path }
import OutputStrategy._
object ForkTest extends Properties("Fork") {
@ -39,7 +40,7 @@ object ForkTest extends Properties("Fork") {
val withScala = requiredEntries ::: relCP.map(rel => new File(dir, rel))
val absClasspath = trimClasspath(Path.makeString(withScala))
val args = optionName.map(_ :: absClasspath :: Nil).toList.flatten ++ mainAndArgs
val config = ForkOptions(outputStrategy = Some(LoggedOutput(log)))
val config = ForkOptions().withOutputStrategy(LoggedOutput(log))
val exitCode = try Fork.java(config, args)
catch { case e: Exception => e.printStackTrace; 1 }
val expectedCode = if (optionName.isEmpty) 1 else 0

View File

@ -8,6 +8,15 @@ trait Import {
type URI = java.net.URI
type URL = java.net.URL
// sbt
val StdoutOutput = sbt.OutputStrategy.StdoutOutput
type BufferedOutput = sbt.OutputStrategy.BufferedOutput
val BufferedOutput = sbt.OutputStrategy.BufferedOutput
type LoggedOutput = sbt.OutputStrategy.LoggedOutput
val LoggedOutput = sbt.OutputStrategy.LoggedOutput
type CustomOutput = sbt.OutputStrategy.CustomOutput
val CustomOutput = sbt.OutputStrategy.CustomOutput
// sbt.testing
type TestResult = sbt.protocol.testing.TestResult
val TestResult = sbt.protocol.testing.TestResult

View File

@ -4,7 +4,7 @@ testGrouping := {
new Tests.Group(
name = test.name,
tests = Seq(test),
runPolicy = Tests.SubProcess(ForkOptions(runJVMOptions = Seq.empty[String]))
runPolicy = Tests.SubProcess(ForkOptions().withRunJVMOptions(Vector()))
)
}
}

View File

@ -4,13 +4,13 @@ libraryDependencies += "org.specs2" %% "specs2-core" % "3.8.4" % Test
inConfig(Test)(Seq(
testGrouping := definedTests.value.map { test => new Tests.Group(test.name, Seq(test), Tests.SubProcess(
ForkOptions(
javaHome.value,
outputStrategy.value,
Nil,
Some(baseDirectory.value),
javaOptions.value,
connectInput.value,
envVars.value
javaHome = javaHome.value,
outputStrategy = outputStrategy.value,
bootJars = Vector(),
workingDirectory = Some(baseDirectory.value),
runJVMOptions = javaOptions.value.toVector,
connectInput = connectInput.value,
envVars = envVars.value
)
))},
TaskKey[Unit]("test-failure") := test.failure.value

View File

@ -19,7 +19,7 @@ lazy val root = (project in file(".")).
new Group(
groupId(idx),
tests,
SubProcess(ForkOptions(runJVMOptions = Seq("-Dgroup.prefix=" + groupPrefix(idx))))
SubProcess(ForkOptions().withRunJVMOptions(Vector("-Dgroup.prefix=" + groupPrefix(idx))))
)
},
check := {