mirror of https://github.com/sbt/sbt.git
Merge branch '1.x' into global-eviction-warning-options
This commit is contained in:
commit
68f58aba87
|
|
@ -246,3 +246,12 @@ cd vscode-sbt-scala/client
|
|||
$ vsce package
|
||||
$ vsce publish
|
||||
```
|
||||
|
||||
## Signing the CLA
|
||||
|
||||
Contributing to sbt requires you or your employer to sign the
|
||||
[Lightbend Contributor License Agreement](https://www.lightbend.com/contribute/cla).
|
||||
|
||||
To make it easier to respect our license agreements, we have added an sbt task
|
||||
that takes care of adding the LICENSE headers to new files. Run `headerCreate`
|
||||
and sbt will put a copyright notice into it.
|
||||
|
|
|
|||
73
build.sbt
73
build.sbt
|
|
@ -24,10 +24,12 @@ def buildLevelSettings: Seq[Setting[_]] =
|
|||
Developer("eed3si9n", "Eugene Yokota", "@eed3si9n", url("https://github.com/eed3si9n")),
|
||||
Developer("jsuereth", "Josh Suereth", "@jsuereth", url("https://github.com/jsuereth")),
|
||||
Developer("dwijnand", "Dale Wijnand", "@dwijnand", url("https://github.com/dwijnand")),
|
||||
Developer("gkossakowski",
|
||||
"Grzegorz Kossakowski",
|
||||
"@gkossakowski",
|
||||
url("https://github.com/gkossakowski")),
|
||||
Developer(
|
||||
"gkossakowski",
|
||||
"Grzegorz Kossakowski",
|
||||
"@gkossakowski",
|
||||
url("https://github.com/gkossakowski")
|
||||
),
|
||||
Developer("Duhemm", "Martin Duhem", "@Duhemm", url("https://github.com/Duhemm"))
|
||||
),
|
||||
homepage := Some(url("https://github.com/sbt/sbt")),
|
||||
|
|
@ -38,32 +40,31 @@ def buildLevelSettings: Seq[Setting[_]] =
|
|||
scalafmtVersion := "1.3.0",
|
||||
))
|
||||
|
||||
def commonSettings: Seq[Setting[_]] =
|
||||
Seq[SettingsDefinition](
|
||||
headerLicense := Some(HeaderLicense.Custom(
|
||||
"""|sbt
|
||||
|Copyright 2011 - 2017, Lightbend, Inc.
|
||||
|Copyright 2008 - 2010, Mark Harrah
|
||||
|Licensed under BSD-3-Clause license (see LICENSE)
|
||||
|""".stripMargin
|
||||
)),
|
||||
scalaVersion := baseScalaVersion,
|
||||
componentID := None,
|
||||
resolvers += Resolver.typesafeIvyRepo("releases"),
|
||||
resolvers += Resolver.sonatypeRepo("snapshots"),
|
||||
resolvers += "bintray-sbt-maven-releases" at "https://dl.bintray.com/sbt/maven-releases/",
|
||||
addCompilerPlugin("org.spire-math" % "kind-projector" % "0.9.4" cross CrossVersion.binary),
|
||||
concurrentRestrictions in Global += Util.testExclusiveRestriction,
|
||||
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-w", "1"),
|
||||
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "2"),
|
||||
javacOptions in compile ++= Seq("-Xlint", "-Xlint:-serial"),
|
||||
crossScalaVersions := Seq(baseScalaVersion),
|
||||
bintrayPackage := (bintrayPackage in ThisBuild).value,
|
||||
bintrayRepository := (bintrayRepository in ThisBuild).value,
|
||||
publishArtifact in Test := false,
|
||||
fork in compile := true,
|
||||
fork in run := true
|
||||
) flatMap (_.settings)
|
||||
def commonSettings: Seq[Setting[_]] = Def.settings(
|
||||
headerLicense := Some(HeaderLicense.Custom(
|
||||
"""|sbt
|
||||
|Copyright 2011 - 2017, Lightbend, Inc.
|
||||
|Copyright 2008 - 2010, Mark Harrah
|
||||
|Licensed under BSD-3-Clause license (see LICENSE)
|
||||
|""".stripMargin
|
||||
)),
|
||||
scalaVersion := baseScalaVersion,
|
||||
componentID := None,
|
||||
resolvers += Resolver.typesafeIvyRepo("releases"),
|
||||
resolvers += Resolver.sonatypeRepo("snapshots"),
|
||||
resolvers += "bintray-sbt-maven-releases" at "https://dl.bintray.com/sbt/maven-releases/",
|
||||
addCompilerPlugin("org.spire-math" % "kind-projector" % "0.9.4" cross CrossVersion.binary),
|
||||
concurrentRestrictions in Global += Util.testExclusiveRestriction,
|
||||
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-w", "1"),
|
||||
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "2"),
|
||||
javacOptions in compile ++= Seq("-Xlint", "-Xlint:-serial"),
|
||||
crossScalaVersions := Seq(baseScalaVersion),
|
||||
bintrayPackage := (bintrayPackage in ThisBuild).value,
|
||||
bintrayRepository := (bintrayRepository in ThisBuild).value,
|
||||
publishArtifact in Test := false,
|
||||
fork in compile := true,
|
||||
fork in run := true
|
||||
)
|
||||
|
||||
def minimalSettings: Seq[Setting[_]] =
|
||||
commonSettings ++ customCommands ++
|
||||
|
|
@ -213,6 +214,11 @@ lazy val testingProj = (project in file("testing"))
|
|||
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
|
||||
contrabandFormatsForType in generateContrabands in Compile := ContrabandConfig.getFormats,
|
||||
mimaSettings,
|
||||
mimaBinaryIssueFilters ++= Seq(
|
||||
// private[sbt]
|
||||
ProblemFilters.exclude[IncompatibleMethTypeProblem]("sbt.TestStatus.write"),
|
||||
ProblemFilters.exclude[IncompatibleResultTypeProblem]("sbt.TestStatus.read"),
|
||||
),
|
||||
)
|
||||
.configure(addSbtIO, addSbtCompilerClasspath, addSbtUtilLogging)
|
||||
|
||||
|
|
@ -557,7 +563,6 @@ lazy val vscodePlugin = (project in file("vscode-sbt-scala"))
|
|||
)
|
||||
|
||||
def scriptedTask: Def.Initialize[InputTask[Unit]] = Def.inputTask {
|
||||
val result = scriptedSource(dir => (s: State) => Scripted.scriptedParser(dir)).parsed
|
||||
// publishLocalBinAll.value // TODO: Restore scripted needing only binary jars.
|
||||
publishAll.value
|
||||
(sbtProj / Test / compile).value // make sure sbt.RunFromSourceMain is compiled
|
||||
|
|
@ -567,21 +572,20 @@ def scriptedTask: Def.Initialize[InputTask[Unit]] = Def.inputTask {
|
|||
(scalaInstance in scriptedSbtProj).value,
|
||||
scriptedSource.value,
|
||||
scriptedBufferLog.value,
|
||||
result,
|
||||
Def.setting(Scripted.scriptedParser(scriptedSource.value)).parsed,
|
||||
scriptedPrescripted.value,
|
||||
scriptedLaunchOpts.value
|
||||
)
|
||||
}
|
||||
|
||||
def scriptedUnpublishedTask: Def.Initialize[InputTask[Unit]] = Def.inputTask {
|
||||
val result = scriptedSource(dir => (s: State) => Scripted.scriptedParser(dir)).parsed
|
||||
Scripted.doScripted(
|
||||
(sbtLaunchJar in bundledLauncherProj).value,
|
||||
(fullClasspath in scriptedSbtProj in Test).value,
|
||||
(scalaInstance in scriptedSbtProj).value,
|
||||
scriptedSource.value,
|
||||
scriptedBufferLog.value,
|
||||
result,
|
||||
Def.setting(Scripted.scriptedParser(scriptedSource.value)).parsed,
|
||||
scriptedPrescripted.value,
|
||||
scriptedLaunchOpts.value
|
||||
)
|
||||
|
|
@ -624,7 +628,6 @@ def otherRootSettings =
|
|||
aggregate in bintrayRelease := false
|
||||
) ++ inConfig(Scripted.RepoOverrideTest)(
|
||||
Seq(
|
||||
scriptedPrescripted := (_ => ()),
|
||||
scriptedLaunchOpts := List(
|
||||
"-Xmx1500M",
|
||||
"-Xms512M",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ sealed trait AttributeKey[T] {
|
|||
def description: Option[String]
|
||||
|
||||
/**
|
||||
* In environments that support delegation, looking up this key when it has no associated value will delegate to the values associated with these keys.
|
||||
* In environments that support delegation, looking up this key when it has no associated value
|
||||
* will delegate to the values associated with these keys.
|
||||
* The delegation proceeds in order the keys are returned here.
|
||||
*/
|
||||
def extend: Seq[AttributeKey[_]]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ package sbt.internal.util
|
|||
package complete
|
||||
|
||||
import java.io.File
|
||||
import org.scalatest.Assertion
|
||||
import sbt.io.IO
|
||||
|
||||
class FileExamplesTest extends UnitSpec {
|
||||
|
|
@ -57,7 +58,8 @@ class FileExamplesTest extends UnitSpec {
|
|||
}
|
||||
|
||||
def withDirectoryStructure[A](withCompletionPrefix: String = "")(
|
||||
thunk: DirectoryStructure => A): Unit = {
|
||||
thunk: DirectoryStructure => Assertion
|
||||
): Assertion = {
|
||||
IO.withTemporaryDirectory { tempDir =>
|
||||
val ds = new DirectoryStructure(withCompletionPrefix)
|
||||
ds.createSampleDirStructure(tempDir)
|
||||
|
|
|
|||
|
|
@ -238,14 +238,16 @@ object State {
|
|||
def process(f: (Exec, State) => State): State = {
|
||||
def runCmd(cmd: Exec, remainingCommands: List[Exec]) = {
|
||||
log.debug(s"> $cmd")
|
||||
f(cmd,
|
||||
s.copy(remainingCommands = remainingCommands,
|
||||
currentCommand = Some(cmd),
|
||||
history = cmd :: s.history))
|
||||
val s1 = s.copy(
|
||||
remainingCommands = remainingCommands,
|
||||
currentCommand = Some(cmd),
|
||||
history = cmd :: s.history,
|
||||
)
|
||||
f(cmd, s1)
|
||||
}
|
||||
s.remainingCommands match {
|
||||
case List() => exit(true)
|
||||
case List(x, xs @ _*) => runCmd(x, xs.toList)
|
||||
case Nil => exit(true)
|
||||
case x :: xs => runCmd(x, xs)
|
||||
}
|
||||
}
|
||||
def :::(newCommands: List[String]): State = ++:(newCommands map { Exec(_, s.source) })
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ private[sbt] object Server {
|
|||
val maxSocketLength = new UnixDomainSocketLibrary.SockaddrUn().sunPath.length - 1
|
||||
val path = socketfile.getAbsolutePath
|
||||
if (path.length > maxSocketLength)
|
||||
sys.error("socket file absolute path too long; " +
|
||||
sys.error(
|
||||
"socket file absolute path too long; " +
|
||||
"either switch to another connection type " +
|
||||
"or define a short \"SBT_GLOBAL_SERVER_DIR\" value. " +
|
||||
s"Current path: ${path}")
|
||||
|
|
|
|||
|
|
@ -10,47 +10,57 @@ package xsbt
|
|||
import java.io.{ BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter }
|
||||
import java.net.{ InetAddress, ServerSocket, Socket }
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
object IPC {
|
||||
private val portMin = 1025
|
||||
private val portMax = 65536
|
||||
private val loopback = InetAddress.getByName(null) // loopback
|
||||
private val loopback = InetAddress.getByName(null)
|
||||
|
||||
def client[T](port: Int)(f: IPC => T): T =
|
||||
ipc(new Socket(loopback, port))(f)
|
||||
def client[T](port: Int)(f: IPC => T): T = ipc(new Socket(loopback, port))(f)
|
||||
|
||||
def pullServer[T](f: Server => T): T = {
|
||||
val server = makeServer
|
||||
try { f(new Server(server)) } finally { server.close() }
|
||||
try f(new Server(server))
|
||||
finally server.close()
|
||||
}
|
||||
|
||||
def unmanagedServer: Server = new Server(makeServer)
|
||||
|
||||
def makeServer: ServerSocket = {
|
||||
val random = new java.util.Random
|
||||
def nextPort = random.nextInt(portMax - portMin + 1) + portMin
|
||||
|
||||
def createServer(attempts: Int): ServerSocket =
|
||||
if (attempts > 0)
|
||||
try { new ServerSocket(nextPort, 1, loopback) } catch {
|
||||
case NonFatal(_) => createServer(attempts - 1)
|
||||
} else
|
||||
sys.error("Could not connect to socket: maximum attempts exceeded")
|
||||
if (attempts > 0) {
|
||||
try new ServerSocket(nextPort, 1, loopback)
|
||||
catch { case NonFatal(_) => createServer(attempts - 1) }
|
||||
} else sys.error("Could not connect to socket: maximum attempts exceeded")
|
||||
|
||||
createServer(10)
|
||||
}
|
||||
|
||||
def server[T](f: IPC => Option[T]): T = serverImpl(makeServer, f)
|
||||
|
||||
def server[T](port: Int)(f: IPC => Option[T]): T =
|
||||
serverImpl(new ServerSocket(port, 1, loopback), f)
|
||||
|
||||
private def serverImpl[T](server: ServerSocket, f: IPC => Option[T]): T = {
|
||||
def listen(): T = {
|
||||
@tailrec def listen(): T = {
|
||||
ipc(server.accept())(f) match {
|
||||
case Some(done) => done
|
||||
case None => listen()
|
||||
}
|
||||
}
|
||||
|
||||
try { listen() } finally { server.close() }
|
||||
try listen()
|
||||
finally server.close()
|
||||
}
|
||||
|
||||
private def ipc[T](s: Socket)(f: IPC => T): T =
|
||||
try { f(new IPC(s)) } finally { s.close() }
|
||||
try f(new IPC(s))
|
||||
finally s.close()
|
||||
|
||||
final class Server private[IPC] (s: ServerSocket) {
|
||||
def port = s.getLocalPort
|
||||
|
|
@ -59,6 +69,7 @@ object IPC {
|
|||
def connection[T](f: IPC => T): T = IPC.ipc(s.accept())(f)
|
||||
}
|
||||
}
|
||||
|
||||
final class IPC private (s: Socket) {
|
||||
def port = s.getLocalPort
|
||||
private val in = new BufferedReader(new InputStreamReader(s.getInputStream))
|
||||
|
|
|
|||
|
|
@ -338,6 +338,11 @@ object Scoped {
|
|||
(this.? zipWith i)((x, y) => (x, y) map { case (a, b) => a getOrElse b })
|
||||
}
|
||||
|
||||
/** Enriches `Initialize[Task[S]]` types.
|
||||
*
|
||||
* @param i the original `Initialize[Task[S]]` value to enrich
|
||||
* @tparam S the type of the underlying value
|
||||
*/
|
||||
final class RichInitializeTask[S](i: Initialize[Task[S]]) extends RichInitTaskBase[S, Task] {
|
||||
protected def onTask[T](f: Task[S] => Task[T]): Initialize[Task[T]] = i apply f
|
||||
|
||||
|
|
@ -367,8 +372,14 @@ object Scoped {
|
|||
}
|
||||
}
|
||||
|
||||
/** Enriches `Initialize[InputTask[S]]` types.
|
||||
*
|
||||
* @param i the original `Initialize[InputTask[S]]` value to enrich
|
||||
* @tparam S the type of the underlying value
|
||||
*/
|
||||
final class RichInitializeInputTask[S](i: Initialize[InputTask[S]])
|
||||
extends RichInitTaskBase[S, InputTask] {
|
||||
|
||||
protected def onTask[T](f: Task[S] => Task[T]): Initialize[InputTask[T]] = i(_ mapTask f)
|
||||
|
||||
def dependsOn(tasks: AnyInitTask*): Initialize[InputTask[S]] = {
|
||||
|
|
@ -378,6 +389,11 @@ object Scoped {
|
|||
}
|
||||
}
|
||||
|
||||
/** Enriches `Initialize[R[S]]` types. Abstracts over the specific task-like type constructor.
|
||||
*
|
||||
* @tparam S the type of the underlying vault
|
||||
* @tparam R the task-like type constructor (either Task or InputTask)
|
||||
*/
|
||||
sealed abstract class RichInitTaskBase[S, R[_]] {
|
||||
protected def onTask[T](f: Task[S] => Task[T]): Initialize[R[T]]
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
package sbt
|
||||
package std
|
||||
|
||||
import reflect.macros._
|
||||
import scala.reflect.macros._
|
||||
|
||||
import Def.Initialize
|
||||
import sbt.internal.util.complete.Parser
|
||||
import sbt.internal.util.appmacro.{ Convert, Converted }
|
||||
import Def.Initialize
|
||||
|
||||
object InputInitConvert extends Convert {
|
||||
def apply[T: c.WeakTypeTag](c: blackbox.Context)(nme: String, in: c.Tree): Converted[c.type] =
|
||||
|
|
@ -46,14 +46,13 @@ object TaskConvert extends Convert {
|
|||
|
||||
/** Converts an input `Tree` of type `Initialize[T]`, `Initialize[Task[T]]`, or `Task[T]` into a `Tree` of type `Initialize[Task[T]]`.*/
|
||||
object FullConvert extends Convert {
|
||||
import InputWrapper._
|
||||
def apply[T: c.WeakTypeTag](c: blackbox.Context)(nme: String, in: c.Tree): Converted[c.type] =
|
||||
nme match {
|
||||
case WrapInitTaskName => Converted.Success[c.type](in)
|
||||
case WrapPreviousName => Converted.Success[c.type](in)
|
||||
case WrapInitName => wrapInit[T](c)(in)
|
||||
case WrapTaskName => wrapTask[T](c)(in)
|
||||
case _ => Converted.NotApplicable[c.type]
|
||||
case InputWrapper.WrapInitTaskName => Converted.Success[c.type](in)
|
||||
case InputWrapper.WrapPreviousName => Converted.Success[c.type](in)
|
||||
case InputWrapper.WrapInitName => wrapInit[T](c)(in)
|
||||
case InputWrapper.WrapTaskName => wrapTask[T](c)(in)
|
||||
case _ => Converted.NotApplicable[c.type]
|
||||
}
|
||||
|
||||
private def wrapInit[T: c.WeakTypeTag](c: blackbox.Context)(tree: c.Tree): Converted[c.type] = {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@
|
|||
package sbt
|
||||
package std
|
||||
|
||||
import language.experimental.macros
|
||||
import reflect.macros._
|
||||
import reflect.internal.annotations.compileTimeOnly
|
||||
import scala.language.experimental.macros
|
||||
|
||||
import scala.annotation.compileTimeOnly
|
||||
import scala.reflect.macros._
|
||||
|
||||
import Def.Initialize
|
||||
import sbt.internal.util.appmacro.ContextUtil
|
||||
|
|
|
|||
|
|
@ -7,15 +7,19 @@
|
|||
|
||||
package sbt.std.neg
|
||||
|
||||
import scala.tools.reflect.ToolBoxError
|
||||
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
import sbt.std.TaskLinterDSLFeedback
|
||||
import sbt.std.TestUtil._
|
||||
|
||||
class TaskNegSpec extends FunSuite {
|
||||
import tools.reflect.ToolBoxError
|
||||
def expectError(errorSnippet: String,
|
||||
compileOptions: String = "",
|
||||
baseCompileOptions: String = s"-cp $toolboxClasspath")(code: String) = {
|
||||
def expectError(
|
||||
errorSnippet: String,
|
||||
compileOptions: String = "",
|
||||
baseCompileOptions: String = s"-cp $toolboxClasspath",
|
||||
)(code: String) = {
|
||||
val errorMessage = intercept[ToolBoxError] {
|
||||
eval(code, s"$compileOptions $baseCompileOptions")
|
||||
println(s"Test failed -- compilation was successful! Expected:\n$errorSnippet")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
package sbt
|
||||
|
||||
import sbt.internal.{ Load, BuildStructure, Act, Aggregation, SessionSettings }
|
||||
import Project._
|
||||
import Scope.GlobalScope
|
||||
import Def.{ ScopedKey, Setting }
|
||||
import sbt.internal.util.complete.Parser
|
||||
|
|
@ -43,7 +42,7 @@ final case class Extracted(structure: BuildStructure,
|
|||
structure.data.get(inCurrent(key.scope), key.key)
|
||||
|
||||
private[this] def inCurrent[T](scope: Scope): Scope =
|
||||
if (scope.project == This) scope.copy(project = Select(currentRef)) else scope
|
||||
if (scope.project == This) scope in currentRef else scope
|
||||
|
||||
/**
|
||||
* Runs the task specified by `key` and returns the transformed State and the resulting value of the task.
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ import xsbti.compile.CompilerCache
|
|||
import scala.annotation.tailrec
|
||||
import sbt.io.IO
|
||||
import sbt.io.syntax._
|
||||
import StandardMain._
|
||||
|
||||
import java.io.{ File, IOException }
|
||||
import java.net.URI
|
||||
|
|
@ -69,34 +68,35 @@ final class xMain extends xsbti.AppMain {
|
|||
import BasicCommandStrings.runEarly
|
||||
import BuiltinCommands.defaults
|
||||
import sbt.internal.CommandStrings.{ BootCommand, DefaultsCommand, InitCommand }
|
||||
val state = initialState(
|
||||
val state = StandardMain.initialState(
|
||||
configuration,
|
||||
Seq(defaults, early),
|
||||
runEarly(DefaultsCommand) :: runEarly(InitCommand) :: BootCommand :: Nil)
|
||||
runManaged(state)
|
||||
StandardMain.runManaged(state)
|
||||
}
|
||||
}
|
||||
|
||||
final class ScriptMain extends xsbti.AppMain {
|
||||
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult = {
|
||||
import BasicCommandStrings.runEarly
|
||||
runManaged(
|
||||
initialState(
|
||||
configuration,
|
||||
BuiltinCommands.ScriptCommands,
|
||||
runEarly(Level.Error.toString) :: Script.Name :: Nil
|
||||
))
|
||||
val state = StandardMain.initialState(
|
||||
configuration,
|
||||
BuiltinCommands.ScriptCommands,
|
||||
runEarly(Level.Error.toString) :: Script.Name :: Nil
|
||||
)
|
||||
StandardMain.runManaged(state)
|
||||
}
|
||||
}
|
||||
|
||||
final class ConsoleMain extends xsbti.AppMain {
|
||||
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
||||
runManaged(
|
||||
initialState(
|
||||
configuration,
|
||||
BuiltinCommands.ConsoleCommands,
|
||||
IvyConsole.Name :: Nil
|
||||
))
|
||||
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult = {
|
||||
val state = StandardMain.initialState(
|
||||
configuration,
|
||||
BuiltinCommands.ConsoleCommands,
|
||||
IvyConsole.Name :: Nil
|
||||
)
|
||||
StandardMain.runManaged(state)
|
||||
}
|
||||
}
|
||||
|
||||
object StandardMain {
|
||||
|
|
|
|||
|
|
@ -8,44 +8,44 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import Def.Initialize
|
||||
import Keys._
|
||||
import sbt.internal.util.complete.{ Parser, DefaultParsers }
|
||||
import sbt.internal.inc.classpath.ClasspathUtilities
|
||||
import sbt.internal.inc.ModuleUtilities
|
||||
import java.lang.reflect.Method
|
||||
import sbt.librarymanagement._
|
||||
import sbt.librarymanagement.syntax._
|
||||
|
||||
import sbt.io._
|
||||
import sbt.io.syntax._
|
||||
import Project._
|
||||
|
||||
import sbt.internal.util.complete.{ Parser, DefaultParsers }
|
||||
|
||||
import sbt.librarymanagement._
|
||||
import sbt.librarymanagement.syntax._
|
||||
|
||||
import sbt.internal.inc.classpath.ClasspathUtilities
|
||||
import sbt.internal.inc.ModuleUtilities
|
||||
|
||||
import Def._
|
||||
import Keys._
|
||||
import Project._
|
||||
|
||||
object ScriptedPlugin extends AutoPlugin {
|
||||
override def requires = plugins.JvmPlugin
|
||||
|
||||
object autoImport {
|
||||
val ScriptedConf = Configurations.config("scripted-sbt") hide
|
||||
val ScriptedLaunchConf = Configurations.config("scripted-sbt-launch") hide
|
||||
val scriptedSbt = SettingKey[String]("scripted-sbt")
|
||||
val sbtLauncher = TaskKey[File]("sbt-launcher")
|
||||
val sbtTestDirectory = SettingKey[File]("sbt-test-directory")
|
||||
val scriptedBufferLog = SettingKey[Boolean]("scripted-buffer-log")
|
||||
val scriptedClasspath = TaskKey[PathFinder]("scripted-classpath")
|
||||
val scriptedTests = TaskKey[AnyRef]("scripted-tests")
|
||||
|
||||
val scriptedSbt = settingKey[String]("")
|
||||
val sbtLauncher = taskKey[File]("")
|
||||
val sbtTestDirectory = settingKey[File]("")
|
||||
val scriptedBufferLog = settingKey[Boolean]("")
|
||||
val scriptedClasspath = taskKey[PathFinder]("")
|
||||
val scriptedTests = taskKey[AnyRef]("")
|
||||
val scriptedBatchExecution =
|
||||
settingKey[Boolean]("Enables or disables batch execution for scripted.")
|
||||
val scriptedParallelInstances =
|
||||
settingKey[Int](
|
||||
"Configures the number of scripted instances for parallel testing, only used in batch mode.")
|
||||
val scriptedRun = TaskKey[Method]("scripted-run")
|
||||
val scriptedLaunchOpts = SettingKey[Seq[String]](
|
||||
"scripted-launch-opts",
|
||||
"options to pass to jvm launching scripted tasks")
|
||||
val scriptedDependencies = TaskKey[Unit]("scripted-dependencies")
|
||||
val scripted = InputKey[Unit]("scripted")
|
||||
val scriptedParallelInstances = settingKey[Int](
|
||||
"Configures the number of scripted instances for parallel testing, only used in batch mode.")
|
||||
val scriptedRun = taskKey[Method]("")
|
||||
val scriptedLaunchOpts =
|
||||
settingKey[Seq[String]]("options to pass to jvm launching scripted tasks")
|
||||
val scriptedDependencies = taskKey[Unit]("")
|
||||
val scripted = inputKey[Unit]("")
|
||||
}
|
||||
|
||||
import autoImport._
|
||||
|
||||
override lazy val globalSettings = Seq(
|
||||
|
|
@ -114,10 +114,10 @@ object ScriptedPlugin extends AutoPlugin {
|
|||
Def.task(method)
|
||||
}
|
||||
|
||||
import DefaultParsers._
|
||||
private[sbt] case class ScriptedTestPage(page: Int, total: Int)
|
||||
private[sbt] final case class ScriptedTestPage(page: Int, total: Int)
|
||||
|
||||
private[sbt] def scriptedParser(scriptedBase: File): Parser[Seq[String]] = {
|
||||
import DefaultParsers._
|
||||
|
||||
val scriptedFiles: NameFilter = ("test": NameFilter) | "pending"
|
||||
val pairs = (scriptedBase * AllPassFilter * AllPassFilter * scriptedFiles).get map {
|
||||
|
|
@ -125,15 +125,16 @@ object ScriptedPlugin extends AutoPlugin {
|
|||
val p = f.getParentFile
|
||||
(p.getParentFile.getName, p.getName)
|
||||
}
|
||||
val pairMap = pairs.groupBy(_._1).mapValues(_.map(_._2).toSet);
|
||||
val pairMap = pairs.groupBy(_._1).mapValues(_.map(_._2).toSet)
|
||||
|
||||
val id = charClass(c => !c.isWhitespace && c != '/').+.string
|
||||
val groupP = token(id.examples(pairMap.keySet.toSet)) <~ token('/')
|
||||
val groupP = token(id.examples(pairMap.keySet)) <~ token('/')
|
||||
|
||||
// A parser for page definitions
|
||||
val pageP: Parser[ScriptedTestPage] = ("*" ~ NatBasic ~ "of" ~ NatBasic) map {
|
||||
case _ ~ page ~ _ ~ total => ScriptedTestPage(page, total)
|
||||
}
|
||||
|
||||
// Grabs the filenames from a given test group in the current page definition.
|
||||
def pagedFilenames(group: String, page: ScriptedTestPage): Seq[String] = {
|
||||
val files = pairMap(group).toSeq.sortBy(_.toLowerCase)
|
||||
|
|
@ -143,9 +144,11 @@ object ScriptedPlugin extends AutoPlugin {
|
|||
if (page.page == page.total) dropped
|
||||
else dropped.take(pageSize)
|
||||
}
|
||||
|
||||
def nameP(group: String) = {
|
||||
token("*".id | id.examples(pairMap.getOrElse(group, Set.empty[String])))
|
||||
}
|
||||
|
||||
val PagedIds: Parser[Seq[String]] =
|
||||
for {
|
||||
group <- groupP
|
||||
|
|
@ -153,10 +156,11 @@ object ScriptedPlugin extends AutoPlugin {
|
|||
files = pagedFilenames(group, page)
|
||||
// TODO - Fail the parser if we don't have enough files for the given page size
|
||||
//if !files.isEmpty
|
||||
} yield files map (f => group + '/' + f)
|
||||
} yield files map (f => s"$group/$f")
|
||||
|
||||
val testID = (for (group <- groupP; name <- nameP(group)) yield (group, name))
|
||||
val testIdAsGroup = matched(testID) map (test => Seq(test))
|
||||
|
||||
//(token(Space) ~> matched(testID)).*
|
||||
(token(Space) ~> (PagedIds | testIdAsGroup)).* map (_.flatten)
|
||||
}
|
||||
|
|
@ -168,15 +172,16 @@ object ScriptedPlugin extends AutoPlugin {
|
|||
val method = scriptedRun.value
|
||||
val scriptedInstance = scriptedTests.value
|
||||
val dir = sbtTestDirectory.value
|
||||
val log: java.lang.Boolean = scriptedBufferLog.value
|
||||
val log = Boolean box scriptedBufferLog.value
|
||||
val launcher = sbtLauncher.value
|
||||
val opts = scriptedLaunchOpts.value.toArray
|
||||
val empty = new java.util.ArrayList[File]()
|
||||
val instances: java.lang.Integer = scriptedParallelInstances.value
|
||||
val instances = Int box scriptedParallelInstances.value
|
||||
|
||||
if (scriptedBatchExecution.value)
|
||||
method.invoke(scriptedInstance, dir, log, args.toArray, launcher, opts, empty, instances)
|
||||
else method.invoke(scriptedInstance, dir, log, args.toArray, launcher, opts, empty)
|
||||
()
|
||||
} catch { case e: java.lang.reflect.InvocationTargetException => throw e.getCause }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,8 @@ case class DetectedAutoPlugin(name: String, value: AutoPlugin, hasAutoImport: Bo
|
|||
* Auto-discovered modules for the build definition project. These include modules defined in build definition sources
|
||||
* as well as modules in binary dependencies.
|
||||
*
|
||||
* @param builds The [[Build]]s detected in the build definition. This does not include the default [[Build]] that sbt creates if none is defined.
|
||||
* @param builds The [[BuildDef]]s detected in the build definition.
|
||||
* This does not include the default [[BuildDef]] that sbt creates if none is defined.
|
||||
*/
|
||||
final class DetectedPlugins(val autoPlugins: Seq[DetectedAutoPlugin],
|
||||
val builds: DetectedModules[BuildDef]) {
|
||||
|
|
|
|||
|
|
@ -5,14 +5,12 @@ import sbt.librarymanagement.ConfigRef
|
|||
|
||||
/** This local plugin provides ways of publishing just the binary jar. */
|
||||
object PublishBinPlugin extends AutoPlugin {
|
||||
override def requires = plugins.JvmPlugin
|
||||
override def trigger = allRequirements
|
||||
|
||||
object autoImport {
|
||||
val publishLocalBin = taskKey[Unit]("")
|
||||
val publishLocalBinConfig = taskKey[PublishConfiguration]("")
|
||||
}
|
||||
|
||||
import autoImport._
|
||||
|
||||
override def globalSettings = Seq(publishLocalBin := (()))
|
||||
|
|
@ -20,22 +18,17 @@ object PublishBinPlugin extends AutoPlugin {
|
|||
override def projectSettings = Def settings (
|
||||
publishLocalBin := Classpaths.publishTask(publishLocalBinConfig, deliverLocal).value,
|
||||
publishLocalBinConfig := {
|
||||
val _ = deliverLocal.value
|
||||
Classpaths.publishConfig(
|
||||
publishMavenStyle.value,
|
||||
deliverPattern(crossTarget.value),
|
||||
false, // publishMavenStyle.value,
|
||||
Classpaths.deliverPattern(crossTarget.value),
|
||||
if (isSnapshot.value) "integration" else "release",
|
||||
ivyConfigurations.value.map(c => ConfigRef(c.name)).toVector,
|
||||
(packagedArtifacts in publishLocalBin).value.toVector,
|
||||
(checksums in publishLocalBin).value.toVector,
|
||||
resolverName = "local",
|
||||
logging = ivyLoggingLevel.value,
|
||||
overwrite = isSnapshot.value
|
||||
)
|
||||
},
|
||||
packagedArtifacts in publishLocalBin := Classpaths.packaged(Seq(packageBin in Compile)).value
|
||||
)
|
||||
|
||||
def deliverPattern(outputPath: File): String =
|
||||
(outputPath / "[artifact]-[revision](-[classifier]).[ext]").absolutePath
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,34 @@
|
|||
import java.lang.reflect.InvocationTargetException
|
||||
|
||||
import sbt._
|
||||
import Keys._
|
||||
import Def.Initialize
|
||||
import sbt.internal.inc.ScalaInstance
|
||||
import sbt.internal.inc.classpath
|
||||
import sbt.internal.inc.classpath.{ ClasspathUtilities, FilteredLoader }
|
||||
|
||||
import scala.language.reflectiveCalls
|
||||
|
||||
object ScriptedPlugin extends sbt.AutoPlugin {
|
||||
object ScriptedPlugin extends AutoPlugin {
|
||||
override def requires = plugins.JvmPlugin
|
||||
|
||||
object autoImport extends ScriptedKeys {
|
||||
def scriptedPath = file("scripted")
|
||||
}
|
||||
|
||||
import autoImport._
|
||||
import Scripted._
|
||||
override def projectSettings = Seq(
|
||||
|
||||
override def globalSettings = super.globalSettings ++ Seq(
|
||||
scriptedBufferLog := true,
|
||||
scriptedPrescripted := { _ =>
|
||||
}
|
||||
scriptedPrescripted := { _ => },
|
||||
)
|
||||
}
|
||||
|
||||
trait ScriptedKeys {
|
||||
lazy val publishAll = TaskKey[Unit]("publish-all")
|
||||
lazy val publishLocalBinAll = taskKey[Unit]("")
|
||||
lazy val scripted = InputKey[Unit]("scripted")
|
||||
lazy val scriptedUnpublished = InputKey[Unit](
|
||||
"scripted-unpublished",
|
||||
"Execute scripted without publishing SBT first. Saves you some time when only your test has changed.")
|
||||
lazy val scriptedSource = SettingKey[File]("scripted-source")
|
||||
lazy val scriptedPrescripted = TaskKey[File => Unit]("scripted-prescripted")
|
||||
lazy val scriptedBufferLog = SettingKey[Boolean]("scripted-buffer-log")
|
||||
lazy val scriptedLaunchOpts = SettingKey[Seq[String]](
|
||||
"scripted-launch-opts",
|
||||
"options to pass to jvm launching scripted tasks")
|
||||
val publishAll = taskKey[Unit]("")
|
||||
val publishLocalBinAll = taskKey[Unit]("")
|
||||
val scripted = inputKey[Unit]("")
|
||||
val scriptedUnpublished = inputKey[Unit]("Execute scripted without publishing sbt first. " +
|
||||
"Saves you some time when only your test has changed")
|
||||
val scriptedSource = settingKey[File]("")
|
||||
val scriptedPrescripted = taskKey[File => Unit]("")
|
||||
val scriptedBufferLog = settingKey[Boolean]("")
|
||||
val scriptedLaunchOpts = settingKey[Seq[String]]("options to pass to jvm launching scripted tasks")
|
||||
}
|
||||
|
||||
object Scripted {
|
||||
|
|
@ -43,27 +38,31 @@ object Scripted {
|
|||
val RepoOverrideTest = config("repoOverrideTest") extend Compile
|
||||
|
||||
import sbt.complete._
|
||||
import DefaultParsers._
|
||||
|
||||
// Paging, 1-index based.
|
||||
case class ScriptedTestPage(page: Int, total: Int)
|
||||
final case class ScriptedTestPage(page: Int, total: Int)
|
||||
|
||||
// FIXME: Duplicated with ScriptedPlugin.scriptedParser, this can be
|
||||
// avoided once we upgrade build.properties to 0.13.14
|
||||
def scriptedParser(scriptedBase: File): Parser[Seq[String]] = {
|
||||
import DefaultParsers._
|
||||
|
||||
val scriptedFiles: NameFilter = ("test": NameFilter) | "pending"
|
||||
val pairs = (scriptedBase * AllPassFilter * AllPassFilter * scriptedFiles).get map {
|
||||
(f: File) =>
|
||||
val p = f.getParentFile
|
||||
(p.getParentFile.getName, p.getName)
|
||||
}
|
||||
val pairMap = pairs.groupBy(_._1).mapValues(_.map(_._2).toSet);
|
||||
val pairMap = pairs.groupBy(_._1).mapValues(_.map(_._2).toSet)
|
||||
|
||||
val id = charClass(c => !c.isWhitespace && c != '/').+.string
|
||||
val groupP = token(id.examples(pairMap.keySet.toSet)) <~ token('/')
|
||||
val groupP = token(id.examples(pairMap.keySet)) <~ token('/')
|
||||
|
||||
// A parser for page definitions
|
||||
val pageP: Parser[ScriptedTestPage] = ("*" ~ NatBasic ~ "of" ~ NatBasic) map {
|
||||
case _ ~ page ~ _ ~ total => ScriptedTestPage(page, total)
|
||||
}
|
||||
|
||||
// Grabs the filenames from a given test group in the current page definition.
|
||||
def pagedFilenames(group: String, page: ScriptedTestPage): Seq[String] = {
|
||||
val files = pairMap(group).toSeq.sortBy(_.toLowerCase)
|
||||
|
|
@ -73,9 +72,11 @@ object Scripted {
|
|||
if (page.page == page.total) dropped
|
||||
else dropped.take(pageSize)
|
||||
}
|
||||
|
||||
def nameP(group: String) = {
|
||||
token("*".id | id.examples(pairMap.getOrElse(group, Set.empty[String])))
|
||||
}
|
||||
|
||||
val PagedIds: Parser[Seq[String]] =
|
||||
for {
|
||||
group <- groupP
|
||||
|
|
@ -83,55 +84,64 @@ object Scripted {
|
|||
files = pagedFilenames(group, page)
|
||||
// TODO - Fail the parser if we don't have enough files for the given page size
|
||||
//if !files.isEmpty
|
||||
} yield files map (f => group + '/' + f)
|
||||
} yield files map (f => s"$group/$f")
|
||||
|
||||
val testID = (for (group <- groupP; name <- nameP(group)) yield (group, name))
|
||||
val testIdAsGroup = matched(testID) map (test => Seq(test))
|
||||
|
||||
//(token(Space) ~> matched(testID)).*
|
||||
(token(Space) ~> (PagedIds | testIdAsGroup)).* map (_.flatten)
|
||||
}
|
||||
|
||||
// Interface to cross class loader
|
||||
type SbtScriptedRunner = {
|
||||
def runInParallel(resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File]): Unit
|
||||
}
|
||||
|
||||
def doScripted(launcher: File,
|
||||
scriptedSbtClasspath: Seq[Attributed[File]],
|
||||
scriptedSbtInstance: ScalaInstance,
|
||||
sourcePath: File,
|
||||
bufferLog: Boolean,
|
||||
args: Seq[String],
|
||||
prescripted: File => Unit,
|
||||
launchOpts: Seq[String]): Unit = {
|
||||
def doScripted(
|
||||
launcher: File,
|
||||
scriptedSbtClasspath: Seq[Attributed[File]],
|
||||
scriptedSbtInstance: ScalaInstance,
|
||||
sourcePath: File,
|
||||
bufferLog: Boolean,
|
||||
args: Seq[String],
|
||||
prescripted: File => Unit,
|
||||
launchOpts: Seq[String],
|
||||
): Unit = {
|
||||
System.err.println(s"About to run tests: ${args.mkString("\n * ", "\n * ", "\n")}")
|
||||
|
||||
// Force Log4J to not use a thread context classloader otherwise it throws a CCE
|
||||
sys.props(org.apache.logging.log4j.util.LoaderUtil.IGNORE_TCCL_PROPERTY) = "true"
|
||||
val noJLine = new classpath.FilteredLoader(scriptedSbtInstance.loader, "jline." :: Nil)
|
||||
val loader = classpath.ClasspathUtilities.toLoader(scriptedSbtClasspath.files, noJLine)
|
||||
|
||||
val noJLine = new FilteredLoader(scriptedSbtInstance.loader, "jline." :: Nil)
|
||||
val loader = ClasspathUtilities.toLoader(scriptedSbtClasspath.files, noJLine)
|
||||
val bridgeClass = Class.forName("sbt.scriptedtest.ScriptedRunner", true, loader)
|
||||
|
||||
// Interface to cross class loader
|
||||
type SbtScriptedRunner = {
|
||||
def runInParallel(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
): Unit
|
||||
}
|
||||
|
||||
val bridge = bridgeClass.getDeclaredConstructor().newInstance().asInstanceOf[SbtScriptedRunner]
|
||||
|
||||
try {
|
||||
// Using java.util.List to encode File => Unit.
|
||||
val callback = new java.util.AbstractList[File] {
|
||||
override def add(x: File): Boolean = {
|
||||
prescripted(x)
|
||||
false
|
||||
}
|
||||
override def add(x: File): Boolean = { prescripted(x); false }
|
||||
def get(x: Int): sbt.File = ???
|
||||
def size(): Int = 0
|
||||
}
|
||||
bridge.runInParallel(sourcePath,
|
||||
bufferLog,
|
||||
args.toArray,
|
||||
launcher,
|
||||
launchOpts.toArray,
|
||||
callback)
|
||||
} catch { case ite: java.lang.reflect.InvocationTargetException => throw ite.getCause }
|
||||
import scala.language.reflectiveCalls
|
||||
bridge.runInParallel(
|
||||
sourcePath,
|
||||
bufferLog,
|
||||
args.toArray,
|
||||
launcher,
|
||||
launchOpts.toArray,
|
||||
callback,
|
||||
)
|
||||
} catch { case ite: InvocationTargetException => throw ite.getCause }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
object A extends App {
|
||||
if(args(0).toBoolean) () else sys.error("Fail")
|
||||
object A {
|
||||
def main(args: Array[String]): Unit = {
|
||||
if (args(0).toBoolean) () else sys.error("Fail")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
addCommandAlias("demo-success", "run true") ++
|
||||
addCommandAlias("demo-success", "run true")
|
||||
addCommandAlias("demo-failure", "run false")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
lazy val a = project.settings(
|
||||
scalaVersion := "2.12.2",
|
||||
scalaInstance in (Compile,doc) := (scalaInstance in b).value,
|
||||
scalaInstance in (Compile, doc) := (scalaInstance in b).value,
|
||||
// 2.10.1-only, so this will only succeed if `doc` recognizes the more specific scalaInstance scoped to `doc`
|
||||
scalacOptions in (Compile,doc) += "-implicits"
|
||||
scalacOptions in (Compile, doc) += "-implicits"
|
||||
)
|
||||
|
||||
lazy val b = project.settings(
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
lazy val buildInfo = taskKey[Seq[File]]("The task that generates the build info.")
|
||||
scalaVersion := "2.11.8"
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.settings(
|
||||
scalaVersion := "2.11.8",
|
||||
buildInfo := {
|
||||
val x = sourceManaged.value / "BuildInfo.scala"
|
||||
IO.write(x, """object BuildInfo""")
|
||||
x :: Nil
|
||||
},
|
||||
sourceGenerators in Compile += buildInfo,
|
||||
sourceGenerators in Compile += Def.task { Nil }
|
||||
)
|
||||
val buildInfo = taskKey[Seq[File]]("generates the build info")
|
||||
buildInfo := {
|
||||
val file = sourceManaged.value / "BuildInfo.scala"
|
||||
IO.write(file, "object BuildInfo")
|
||||
file :: Nil
|
||||
}
|
||||
|
||||
sourceGenerators in Compile += buildInfo
|
||||
sourceGenerators in Compile += Def.task { Nil }
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
lazy val root = (project in file(".")).
|
||||
settings(
|
||||
myRun,
|
||||
fork in demo := true,
|
||||
javaOptions in demo := "-Dsbt.check.forked=true" :: Nil,
|
||||
myIn
|
||||
)
|
||||
val demo = taskKey[Unit]("Demo run task")
|
||||
fullRunTask(demo, Compile, "A", "1", "1")
|
||||
fork in demo := true
|
||||
javaOptions in demo := "-Dsbt.check.forked=true" :: Nil
|
||||
|
||||
lazy val demoIn = InputKey[Unit]("demoIn", "Demo run input task", demo)
|
||||
lazy val demo = taskKey[Unit]("Demo run task")
|
||||
|
||||
def myRun = fullRunTask(demo, Compile, "A", "1", "1")
|
||||
def myIn = fullRunInputTask(demoIn, Compile, "A", "1")
|
||||
val demoIn = InputKey[Unit]("demoIn", "Demo run input task", demo)
|
||||
fullRunInputTask(demoIn, Compile, "A", "1")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
val commonSettings = Seq(
|
||||
crossScalaVersions := (0 to 6).map(i => s"2.10.$i") ++ (0 to 11).map(i => s"2.11.$i") ++ (0 to 2).map(i => s"2.12.$i")
|
||||
)
|
||||
|
||||
val p1 = project.in(file("p1")).settings(commonSettings)
|
||||
val p2 = project.in(file("p2")).settings(commonSettings)
|
||||
val p3 = project.in(file("p3")).settings(commonSettings)
|
||||
val p4 = project.in(file("p4")).settings(commonSettings)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object B {
|
||||
def show(what: String): String = s"String interpolation is ${what.toUpperCase}!"
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
class A {
|
||||
def show(what: String): Unit = println(what)
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object B {
|
||||
def show(what: String): String = s"String interpolation is ${what.toUpperCase}!"
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
class A {
|
||||
def show(what: String): Unit = println(what)
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object B {
|
||||
def show(what: String): String = s"String interpolation is ${what.toUpperCase}!"
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
class A {
|
||||
def show(what: String): Unit = println(what)
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
object B {
|
||||
def show(what: String): String = s"String interpolation is ${what.toUpperCase}!"
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
class A {
|
||||
def show(what: String): Unit = println(what)
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# https://github.com/sbt/sbt/issues/3143
|
||||
> crossScalaVersions
|
||||
> +version
|
||||
|
|
@ -8,11 +8,17 @@
|
|||
package sbt
|
||||
package scriptedtest
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
import sbt.internal.scripted._
|
||||
import sbt.scriptedtest.BatchScriptRunner.States
|
||||
|
||||
private[sbt] object BatchScriptRunner {
|
||||
type States = mutable.HashMap[StatementHandler, StatementHandler#State]
|
||||
}
|
||||
|
||||
/** Defines an alternative script runner that allows batch execution. */
|
||||
private[sbt] class BatchScriptRunner extends ScriptRunner {
|
||||
import BatchScriptRunner.States
|
||||
|
||||
/** Defines a method to run batched execution.
|
||||
*
|
||||
|
|
@ -37,9 +43,8 @@ private[sbt] class BatchScriptRunner extends ScriptRunner {
|
|||
def processStatement(handler: StatementHandler, statement: Statement, states: States): Unit = {
|
||||
val state = states(handler).asInstanceOf[handler.State]
|
||||
val nextState =
|
||||
try { Right(handler(statement.command, statement.arguments, state)) } catch {
|
||||
case e: Exception => Left(e)
|
||||
}
|
||||
try Right(handler(statement.command, statement.arguments, state))
|
||||
catch { case e: Exception => Left(e) }
|
||||
nextState match {
|
||||
case Left(err) =>
|
||||
if (statement.successExpected) {
|
||||
|
|
@ -58,8 +63,3 @@ private[sbt] class BatchScriptRunner extends ScriptRunner {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private[sbt] object BatchScriptRunner {
|
||||
import scala.collection.mutable
|
||||
type States = mutable.HashMap[StatementHandler, Any]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,41 +22,40 @@ final case class SbtInstance(process: Process, server: IPC.Server)
|
|||
final class SbtHandler(remoteSbtCreator: RemoteSbtCreator) extends StatementHandler {
|
||||
|
||||
type State = Option[SbtInstance]
|
||||
|
||||
def initialState = None
|
||||
|
||||
def apply(command: String, arguments: List[String], i: Option[SbtInstance]): Option[SbtInstance] =
|
||||
onSbtInstance(i) { (process, server) =>
|
||||
onSbtInstance(i) { (_, server) =>
|
||||
send((command :: arguments.map(escape)).mkString(" "), server)
|
||||
receive(command + " failed", server)
|
||||
receive(s"$command failed", server)
|
||||
}
|
||||
|
||||
def onSbtInstance(i: Option[SbtInstance])(f: (Process, IPC.Server) => Unit): Option[SbtInstance] =
|
||||
i match {
|
||||
case Some(SbtInstance(_, server)) if server.isClosed =>
|
||||
finish(i)
|
||||
onNewSbtInstance(f)
|
||||
case Some(SbtInstance(process, server)) =>
|
||||
f(process, server)
|
||||
i
|
||||
case None =>
|
||||
onNewSbtInstance(f)
|
||||
case Some(SbtInstance(_, server)) if server.isClosed => finish(i); onNewSbtInstance(f)
|
||||
case Some(SbtInstance(process, server)) => f(process, server); i
|
||||
case None => onNewSbtInstance(f)
|
||||
}
|
||||
|
||||
private[this] def onNewSbtInstance(f: (Process, IPC.Server) => Unit): Option[SbtInstance] = {
|
||||
val server = IPC.unmanagedServer
|
||||
val p = try newRemote(server)
|
||||
catch { case e: Throwable => server.close(); throw e }
|
||||
val ai = Some(SbtInstance(p, server))
|
||||
val p =
|
||||
try newRemote(server)
|
||||
catch { case e: Throwable => server.close(); throw e }
|
||||
val i = Some(SbtInstance(p, server))
|
||||
try f(p, server)
|
||||
catch {
|
||||
case e: Throwable =>
|
||||
// TODO: closing is necessary only because StatementHandler uses exceptions for signaling errors
|
||||
finish(ai); throw e
|
||||
finish(i)
|
||||
throw e
|
||||
}
|
||||
ai
|
||||
i
|
||||
}
|
||||
|
||||
def finish(state: Option[SbtInstance]) = state match {
|
||||
def finish(state: State) = state match {
|
||||
case None =>
|
||||
case Some(SbtInstance(process, server)) =>
|
||||
try {
|
||||
send("exit", server)
|
||||
|
|
@ -65,24 +64,28 @@ final class SbtHandler(remoteSbtCreator: RemoteSbtCreator) extends StatementHand
|
|||
} catch {
|
||||
case _: IOException => process.destroy()
|
||||
}
|
||||
case None =>
|
||||
}
|
||||
def send(message: String, server: IPC.Server) = server.connection { _.send(message) }
|
||||
|
||||
def send(message: String, server: IPC.Server) = server.connection(_.send(message))
|
||||
|
||||
def receive(errorMessage: String, server: IPC.Server) =
|
||||
server.connection { ipc =>
|
||||
val resultMessage = ipc.receive
|
||||
if (!resultMessage.toBoolean) throw new TestFailed(errorMessage)
|
||||
}
|
||||
|
||||
def newRemote(server: IPC.Server): Process = {
|
||||
val p = remoteSbtCreator.newRemote(server)
|
||||
try receive("Remote sbt initialization failed", server)
|
||||
catch { case _: SocketException => throw new TestFailed("Remote sbt initialization failed") }
|
||||
p
|
||||
}
|
||||
import java.util.regex.Pattern.{ quote => q }
|
||||
|
||||
// if the argument contains spaces, enclose it in quotes, quoting backslashes and quotes
|
||||
def escape(argument: String) =
|
||||
def escape(argument: String) = {
|
||||
import java.util.regex.Pattern.{ quote => q }
|
||||
if (argument.contains(" "))
|
||||
"\"" + argument.replaceAll(q("""\"""), """\\""").replaceAll(q("\""), "\\\"") + "\""
|
||||
else argument
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,27 +9,31 @@ package sbt
|
|||
package scriptedtest
|
||||
|
||||
import java.io.File
|
||||
import java.net.SocketException
|
||||
import java.util.Properties
|
||||
import java.util.concurrent.ForkJoinPool
|
||||
|
||||
import scala.util.control.NonFatal
|
||||
import sbt.internal.scripted._
|
||||
import sbt.io.{ DirectoryFilter, HiddenFileFilter, IO }
|
||||
import sbt.io.IO.wrapNull
|
||||
import sbt.io.FileFilter._
|
||||
import sbt.internal.io.Resources
|
||||
import sbt.internal.util.{ BufferedLogger, ConsoleLogger, FullLogger }
|
||||
import sbt.util.{ AbstractLogger, Logger }
|
||||
|
||||
import scala.collection.GenSeq
|
||||
import scala.collection.mutable
|
||||
import scala.collection.parallel.ForkJoinTaskSupport
|
||||
import scala.collection.parallel.mutable.ParSeq
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
import sbt.internal.scripted._
|
||||
import sbt.internal.io.Resources
|
||||
import sbt.internal.util.{ BufferedLogger, ConsoleLogger, FullLogger }
|
||||
import sbt.io.syntax._
|
||||
import sbt.io.{ DirectoryFilter, HiddenFileFilter, IO }
|
||||
import sbt.io.FileFilter._
|
||||
import sbt.util.{ AbstractLogger, Logger }
|
||||
|
||||
final class ScriptedTests(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
launcher: File,
|
||||
launchOpts: Seq[String],
|
||||
) {
|
||||
import ScriptedTests.{ TestRunner, emptyCallback }
|
||||
|
||||
final class ScriptedTests(resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
launcher: File,
|
||||
launchOpts: Seq[String]) {
|
||||
import sbt.io.syntax._
|
||||
import ScriptedTests._
|
||||
private val testResources = new Resources(resourceBaseDirectory)
|
||||
|
||||
val ScriptFilename = "test"
|
||||
|
|
@ -37,14 +41,17 @@ final class ScriptedTests(resourceBaseDirectory: File,
|
|||
|
||||
def scriptedTest(group: String, name: String, log: xsbti.Logger): Seq[TestRunner] =
|
||||
scriptedTest(group, name, Logger.xlog2Log(log))
|
||||
|
||||
def scriptedTest(group: String, name: String, log: Logger): Seq[TestRunner] =
|
||||
singleScriptedTest(group, name, emptyCallback, log)
|
||||
|
||||
/** Returns a sequence of test runners that have to be applied in the call site. */
|
||||
def singleScriptedTest(group: String,
|
||||
name: String,
|
||||
prescripted: File => Unit,
|
||||
log: Logger): Seq[TestRunner] = {
|
||||
def singleScriptedTest(
|
||||
group: String,
|
||||
name: String,
|
||||
prescripted: File => Unit,
|
||||
log: Logger,
|
||||
): Seq[TestRunner] = {
|
||||
|
||||
// Test group and names may be file filters (like '*')
|
||||
for (groupDir <- (resourceBaseDirectory * group).get; nme <- (groupDir * name).get) yield {
|
||||
|
|
@ -60,7 +67,7 @@ final class ScriptedTests(resourceBaseDirectory: File,
|
|||
val handlers =
|
||||
createScriptedHandlers(testDirectory, buffer, RemoteSbtCreatorKind.LauncherBased)
|
||||
val runner = new BatchScriptRunner
|
||||
val states = new mutable.HashMap[StatementHandler, Any]()
|
||||
val states = new mutable.HashMap[StatementHandler, StatementHandler#State]()
|
||||
commonRunTest(label, testDirectory, prescripted, handlers, runner, states, buffer)
|
||||
}
|
||||
runOrHandleDisabled(label, testDirectory, singleTestRunner, buffer)
|
||||
|
|
@ -97,8 +104,8 @@ final class ScriptedTests(resourceBaseDirectory: File,
|
|||
val groupAndNameDirs = {
|
||||
for {
|
||||
(group, name) <- testGroupAndNames
|
||||
groupDir <- resourceBaseDirectory.*(group).get
|
||||
testDir <- groupDir.*(name).get
|
||||
groupDir <- (resourceBaseDirectory * group).get
|
||||
testDir <- (groupDir * name).get
|
||||
} yield (groupDir, testDir)
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +316,7 @@ final class ScriptedTests(resourceBaseDirectory: File,
|
|||
def runBatchTests = {
|
||||
groupedTests.map {
|
||||
case ((group, name), originalDir) =>
|
||||
val label = s"$group / $name"
|
||||
val label = s"$group/$name"
|
||||
println(s"Running $label")
|
||||
// Copy test's contents and reload the sbt instance to pick them up
|
||||
IO.copyDirectory(originalDir, tempTestDir)
|
||||
|
|
@ -318,8 +325,8 @@ final class ScriptedTests(resourceBaseDirectory: File,
|
|||
// Reload and initialize (to reload contents of .sbtrc files)
|
||||
val pluginImplementation = createAutoPlugin(name)
|
||||
IO.write(tempTestDir / "project" / "InstrumentScripted.scala", pluginImplementation)
|
||||
val sbtHandlerError = "Missing sbt handler. Scripted is misconfigured."
|
||||
val sbtHandler = handlers.getOrElse('>', sbtHandlerError).asInstanceOf[SbtHandler]
|
||||
def sbtHandlerError = sys error "Missing sbt handler. Scripted is misconfigured."
|
||||
val sbtHandler = handlers.getOrElse('>', sbtHandlerError)
|
||||
val commandsToRun = ";reload;setUpScripted"
|
||||
val statement = Statement(commandsToRun, Nil, successExpected = true, line = -1)
|
||||
|
||||
|
|
@ -368,7 +375,7 @@ final class ScriptedTests(resourceBaseDirectory: File,
|
|||
label: String,
|
||||
testDirectory: File,
|
||||
preScriptedHook: File => Unit,
|
||||
createHandlers: Map[Char, StatementHandler],
|
||||
handlers: Map[Char, StatementHandler],
|
||||
runner: BatchScriptRunner,
|
||||
states: BatchScriptRunner.States,
|
||||
log: BufferedLogger
|
||||
|
|
@ -382,15 +389,15 @@ final class ScriptedTests(resourceBaseDirectory: File,
|
|||
}
|
||||
|
||||
val pendingMark = if (pending) PendingLabel else ""
|
||||
|
||||
def testFailed(t: Throwable): Option[String] = {
|
||||
if (pending) log.clear() else log.stop()
|
||||
log.error(s"x $label $pendingMark")
|
||||
if (!NonFatal(t)) throw t // We make sure fatal errors are rethrown
|
||||
if (t.isInstanceOf[TestException]) {
|
||||
t.getCause match {
|
||||
case null | _: java.net.SocketException =>
|
||||
log.error(" Cause of test exception: " + t.getMessage)
|
||||
case _ => t.printStackTrace()
|
||||
case null | _: SocketException => log.error(s" Cause of test exception: ${t.getMessage}")
|
||||
case _ => t.printStackTrace()
|
||||
}
|
||||
}
|
||||
if (pending) None else Some(label)
|
||||
|
|
@ -399,7 +406,6 @@ final class ScriptedTests(resourceBaseDirectory: File,
|
|||
import scala.util.control.Exception.catching
|
||||
catching(classOf[TestException]).withApply(testFailed).andFinally(log.clear).apply {
|
||||
preScriptedHook(testDirectory)
|
||||
val handlers = createHandlers
|
||||
val parser = new TestScriptParser(handlers)
|
||||
val handlersAndStatements = parser.parse(file)
|
||||
runner.apply(handlersAndStatements, states)
|
||||
|
|
@ -421,6 +427,7 @@ object ScriptedTests extends ScriptedRunner {
|
|||
type TestRunner = () => Seq[Option[String]]
|
||||
|
||||
val emptyCallback: File => Unit = _ => ()
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val directory = new File(args(0))
|
||||
val buffer = args(1).toBoolean
|
||||
|
|
@ -432,48 +439,52 @@ object ScriptedTests extends ScriptedRunner {
|
|||
val logger = ConsoleLogger()
|
||||
run(directory, buffer, tests, logger, bootProperties, Array(), emptyCallback)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Runner for `scripted`. Not be confused with ScriptRunner. */
|
||||
class ScriptedRunner {
|
||||
// This is called by project/Scripted.scala
|
||||
// Using java.util.List[File] to encode File => Unit
|
||||
def run(resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File]): Unit = {
|
||||
|
||||
// Force Log4J to not use a thread context classloader otherwise it throws a CCE
|
||||
sys.props(org.apache.logging.log4j.util.LoaderUtil.IGNORE_TCCL_PROPERTY) = "true"
|
||||
|
||||
run(resourceBaseDirectory, bufferLog, tests, ConsoleLogger(), bootProperties, launchOpts, {
|
||||
f: File =>
|
||||
prescripted.add(f); ()
|
||||
}) //new FullLogger(Logger.xlog2Log(log)))
|
||||
def run(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
): Unit = {
|
||||
val logger = ConsoleLogger()
|
||||
val addTestFile = (f: File) => { prescripted.add(f); () }
|
||||
run(resourceBaseDirectory, bufferLog, tests, logger, bootProperties, launchOpts, addTestFile)
|
||||
//new FullLogger(Logger.xlog2Log(log)))
|
||||
}
|
||||
|
||||
// This is called by sbt-scripted 0.13.x and 1.x (see https://github.com/sbt/sbt/issues/3245)
|
||||
def run(resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String]): Unit =
|
||||
run(resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests,
|
||||
ConsoleLogger(),
|
||||
bootProperties,
|
||||
launchOpts,
|
||||
ScriptedTests.emptyCallback)
|
||||
def run(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String],
|
||||
): Unit = {
|
||||
val logger = ConsoleLogger()
|
||||
val prescripted = ScriptedTests.emptyCallback
|
||||
run(resourceBaseDirectory, bufferLog, tests, logger, bootProperties, launchOpts, prescripted)
|
||||
}
|
||||
|
||||
def run(
|
||||
resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
logger: AbstractLogger,
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: File => Unit,
|
||||
): Unit = {
|
||||
// Force Log4J to not use a thread context classloader otherwise it throws a CCE
|
||||
sys.props(org.apache.logging.log4j.util.LoaderUtil.IGNORE_TCCL_PROPERTY) = "true"
|
||||
|
||||
def run(resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
logger: AbstractLogger,
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: File => Unit): Unit = {
|
||||
val runner = new ScriptedTests(resourceBaseDirectory, bufferLog, bootProperties, launchOpts)
|
||||
val sbtVersion = bootProperties.getName.dropWhile(!_.isDigit).dropRight(".jar".length)
|
||||
val accept = isTestCompatible(resourceBaseDirectory, sbtVersion) _
|
||||
|
|
@ -484,22 +495,15 @@ class ScriptedRunner {
|
|||
runAll(allTests)
|
||||
}
|
||||
|
||||
def runInParallel(resourceBaseDirectory: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
bootProperties: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File]): Unit = {
|
||||
val logger = ConsoleLogger()
|
||||
val addTestFile = (f: File) => { prescripted.add(f); () }
|
||||
runInParallel(resourceBaseDirectory,
|
||||
bufferLog,
|
||||
tests,
|
||||
logger,
|
||||
bootProperties,
|
||||
launchOpts,
|
||||
addTestFile,
|
||||
1)
|
||||
def runInParallel(
|
||||
baseDir: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
bootProps: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: java.util.List[File],
|
||||
): Unit = {
|
||||
runInParallel(baseDir, bufferLog, tests, bootProps, launchOpts, prescripted, 1)
|
||||
}
|
||||
|
||||
// This is used by sbt-scripted sbt 1.x
|
||||
|
|
@ -518,54 +522,54 @@ class ScriptedRunner {
|
|||
}
|
||||
|
||||
def runInParallel(
|
||||
resourceBaseDirectory: File,
|
||||
baseDir: File,
|
||||
bufferLog: Boolean,
|
||||
tests: Array[String],
|
||||
logger: AbstractLogger,
|
||||
bootProperties: File,
|
||||
bootProps: File,
|
||||
launchOpts: Array[String],
|
||||
prescripted: File => Unit,
|
||||
instances: Int
|
||||
): Unit = {
|
||||
val runner = new ScriptedTests(resourceBaseDirectory, bufferLog, bootProperties, launchOpts)
|
||||
val sbtVersion = bootProperties.getName.dropWhile(!_.isDigit).dropRight(".jar".length)
|
||||
val accept = isTestCompatible(resourceBaseDirectory, sbtVersion) _
|
||||
val runner = new ScriptedTests(baseDir, bufferLog, bootProps, launchOpts)
|
||||
val sbtVersion = bootProps.getName.dropWhile(!_.isDigit).dropRight(".jar".length)
|
||||
val accept = isTestCompatible(baseDir, sbtVersion) _
|
||||
// The scripted tests mapped to the inputs that the user wrote after `scripted`.
|
||||
val scriptedTests =
|
||||
get(tests, resourceBaseDirectory, accept, logger).map(st => (st.group, st.name))
|
||||
get(tests, baseDir, accept, logger).map(st => (st.group, st.name))
|
||||
val scriptedRunners = runner.batchScriptedRunner(scriptedTests, prescripted, instances, logger)
|
||||
val parallelRunners = scriptedRunners.toParArray
|
||||
val pool = new java.util.concurrent.ForkJoinPool(instances)
|
||||
parallelRunners.tasksupport = new ForkJoinTaskSupport(pool)
|
||||
runAllInParallel(parallelRunners)
|
||||
parallelRunners.tasksupport = new ForkJoinTaskSupport(new ForkJoinPool(instances))
|
||||
runAll(parallelRunners)
|
||||
}
|
||||
|
||||
private def reportErrors(errors: Seq[String]): Unit =
|
||||
private def reportErrors(errors: GenSeq[String]): Unit =
|
||||
if (errors.nonEmpty) sys.error(errors.mkString("Failed tests:\n\t", "\n\t", "\n")) else ()
|
||||
|
||||
def runAll(toRun: Seq[ScriptedTests.TestRunner]): Unit =
|
||||
reportErrors(toRun.flatMap(test => test.apply().flatten.toSeq))
|
||||
|
||||
// We cannot reuse `runAll` because parallel collections != collections
|
||||
def runAllInParallel(tests: ParSeq[ScriptedTests.TestRunner]): Unit = {
|
||||
reportErrors(tests.flatMap(test => test.apply().flatten.toSeq).toList)
|
||||
}
|
||||
def runAll(toRun: GenSeq[ScriptedTests.TestRunner]): Unit =
|
||||
reportErrors(toRun.flatMap(test => test.apply().flatten))
|
||||
|
||||
@deprecated("No longer used", "1.1.0")
|
||||
def get(tests: Seq[String], baseDirectory: File, log: Logger): Seq[ScriptedTest] =
|
||||
get(tests, baseDirectory, _ => true, log)
|
||||
def get(tests: Seq[String],
|
||||
baseDirectory: File,
|
||||
accept: ScriptedTest => Boolean,
|
||||
log: Logger): Seq[ScriptedTest] =
|
||||
|
||||
def get(
|
||||
tests: Seq[String],
|
||||
baseDirectory: File,
|
||||
accept: ScriptedTest => Boolean,
|
||||
log: Logger,
|
||||
): Seq[ScriptedTest] =
|
||||
if (tests.isEmpty) listTests(baseDirectory, accept, log) else parseTests(tests)
|
||||
|
||||
@deprecated("No longer used", "1.1.0")
|
||||
def listTests(baseDirectory: File, log: Logger): Seq[ScriptedTest] =
|
||||
listTests(baseDirectory, _ => true, log)
|
||||
def listTests(baseDirectory: File,
|
||||
accept: ScriptedTest => Boolean,
|
||||
log: Logger): Seq[ScriptedTest] =
|
||||
|
||||
def listTests(
|
||||
baseDirectory: File,
|
||||
accept: ScriptedTest => Boolean,
|
||||
log: Logger,
|
||||
): Seq[ScriptedTest] =
|
||||
(new ListTests(baseDirectory, accept, log)).listTests
|
||||
|
||||
def parseTests(in: Seq[String]): Seq[ScriptedTest] =
|
||||
|
|
@ -575,7 +579,8 @@ class ScriptedRunner {
|
|||
}
|
||||
|
||||
private def isTestCompatible(resourceBaseDirectory: File, sbtVersion: String)(
|
||||
test: ScriptedTest): Boolean = {
|
||||
test: ScriptedTest
|
||||
): Boolean = {
|
||||
import sbt.internal.librarymanagement.cross.CrossVersionUtil.binarySbtVersion
|
||||
val buildProperties = new Properties()
|
||||
val testDir = new File(new File(resourceBaseDirectory, test.group), test.name)
|
||||
|
|
@ -592,36 +597,38 @@ class ScriptedRunner {
|
|||
}
|
||||
|
||||
final case class ScriptedTest(group: String, name: String) {
|
||||
override def toString = group + "/" + name
|
||||
override def toString = s"$group/$name"
|
||||
}
|
||||
private[sbt] object ListTests {
|
||||
def list(directory: File, filter: java.io.FileFilter) = wrapNull(directory.listFiles(filter))
|
||||
}
|
||||
import ListTests._
|
||||
private[sbt] final class ListTests(baseDirectory: File,
|
||||
accept: ScriptedTest => Boolean,
|
||||
log: Logger) {
|
||||
|
||||
private[sbt] final class ListTests(
|
||||
baseDirectory: File,
|
||||
accept: ScriptedTest => Boolean,
|
||||
log: Logger,
|
||||
) {
|
||||
|
||||
def filter = DirectoryFilter -- HiddenFileFilter
|
||||
|
||||
def listTests: Seq[ScriptedTest] = {
|
||||
list(baseDirectory, filter) flatMap { group =>
|
||||
IO.listFiles(baseDirectory, filter) flatMap { group =>
|
||||
val groupName = group.getName
|
||||
listTests(group).map(ScriptedTest(groupName, _))
|
||||
}
|
||||
}
|
||||
|
||||
private[this] def listTests(group: File): Set[String] = {
|
||||
val groupName = group.getName
|
||||
val allTests = list(group, filter)
|
||||
val allTests = IO.listFiles(group, filter)
|
||||
if (allTests.isEmpty) {
|
||||
log.warn("No tests in test group " + groupName)
|
||||
log.warn(s"No tests in test group $groupName")
|
||||
Set.empty
|
||||
} else {
|
||||
val (included, skipped) =
|
||||
allTests.toList.partition(test => accept(ScriptedTest(groupName, test.getName)))
|
||||
if (included.isEmpty)
|
||||
log.warn("Test group " + groupName + " skipped.")
|
||||
log.warn(s"Test group $groupName skipped.")
|
||||
else if (skipped.nonEmpty) {
|
||||
log.warn("Tests skipped in group " + group.getName + ":")
|
||||
skipped.foreach(testName => log.warn(" " + testName.getName))
|
||||
log.warn(s"Tests skipped in group $groupName:")
|
||||
skipped.foreach(testName => log.warn(s" ${testName.getName}"))
|
||||
}
|
||||
Set(included.map(_.getName): _*)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ object TaskRunnerForkTest extends Properties("TaskRunner Fork") {
|
|||
def runDoubleJoin(a: Int, b: Int, workers: Int): Unit = {
|
||||
def inner = List.range(0, b).map(j => task(j).named(j.toString)).join
|
||||
tryRun(List.range(0, a).map(_ => inner).join, false, workers)
|
||||
()
|
||||
}
|
||||
property("fork and reduce") = forAll(TaskListGen, MaxWorkersGen) { (m: List[Int], workers: Int) =>
|
||||
m.nonEmpty ==> {
|
||||
|
|
|
|||
|
|
@ -8,14 +8,16 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import sbt.io.IO
|
||||
|
||||
import scala.collection.mutable.Map
|
||||
import sbt.io.IO
|
||||
import sbt.protocol.testing.TestResult
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
import scala.collection.concurrent
|
||||
|
||||
// Assumes exclusive ownership of the file.
|
||||
private[sbt] class TestStatusReporter(f: File) extends TestsListener {
|
||||
private lazy val succeeded = TestStatus.read(f)
|
||||
private lazy val succeeded: concurrent.Map[String, Long] = TestStatus.read(f)
|
||||
|
||||
def doInit = ()
|
||||
def startGroup(name: String): Unit = { succeeded remove name; () }
|
||||
|
|
@ -32,13 +34,16 @@ private[sbt] class TestStatusReporter(f: File) extends TestsListener {
|
|||
|
||||
private[sbt] object TestStatus {
|
||||
import java.util.Properties
|
||||
def read(f: File): Map[String, Long] = {
|
||||
def read(f: File): concurrent.Map[String, Long] = {
|
||||
import scala.collection.JavaConverters._
|
||||
val properties = new Properties
|
||||
IO.load(properties, f)
|
||||
properties.asScala map { case (k, v) => (k, v.toLong) }
|
||||
val result = new ConcurrentHashMap[String, Long]()
|
||||
properties.asScala.iterator.foreach { case (k, v) => result.put(k, v.toLong) }
|
||||
result.asScala
|
||||
}
|
||||
def write(map: Map[String, Long], label: String, f: File): Unit = {
|
||||
|
||||
def write(map: collection.Map[String, Long], label: String, f: File): Unit = {
|
||||
val properties = new Properties
|
||||
for ((test, lastSuccessTime) <- map)
|
||||
properties.setProperty(test, lastSuccessTime.toString)
|
||||
|
|
|
|||
Loading…
Reference in New Issue