2014-12-18 05:38:10 +01:00
|
|
|
import sbt._
|
|
|
|
|
import Keys._
|
|
|
|
|
import Def.Initialize
|
2017-05-03 16:52:36 +02:00
|
|
|
import sbt.internal.inc.ScalaInstance
|
|
|
|
|
import sbt.internal.inc.classpath
|
2014-12-18 05:38:10 +01:00
|
|
|
|
2015-07-10 11:53:48 +02:00
|
|
|
import scala.language.reflectiveCalls
|
|
|
|
|
|
2016-03-31 05:48:20 +02:00
|
|
|
object ScriptedPlugin extends sbt.AutoPlugin {
|
|
|
|
|
override def requires = plugins.JvmPlugin
|
|
|
|
|
object autoImport extends ScriptedKeys {
|
|
|
|
|
def scriptedPath = file("scripted")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
import autoImport._
|
|
|
|
|
import Scripted._
|
|
|
|
|
override def projectSettings = Seq(
|
|
|
|
|
scriptedBufferLog := true,
|
2017-04-21 09:14:31 +02:00
|
|
|
scriptedPrescripted := { _ =>
|
|
|
|
|
}
|
2016-03-31 05:48:20 +02:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trait ScriptedKeys {
|
|
|
|
|
lazy val publishAll = TaskKey[Unit]("publish-all")
|
2016-09-01 02:14:14 +02:00
|
|
|
lazy val publishLocalBinAll = taskKey[Unit]("")
|
2014-12-18 05:38:10 +01:00
|
|
|
lazy val scripted = InputKey[Unit]("scripted")
|
2017-04-21 09:14:31 +02:00
|
|
|
lazy val scriptedUnpublished = InputKey[Unit](
|
|
|
|
|
"scripted-unpublished",
|
|
|
|
|
"Execute scripted without publishing SBT first. Saves you some time when only your test has changed.")
|
2014-12-18 05:38:10 +01:00
|
|
|
lazy val scriptedSource = SettingKey[File]("scripted-source")
|
2015-01-13 04:01:16 +01:00
|
|
|
lazy val scriptedPrescripted = TaskKey[File => Unit]("scripted-prescripted")
|
2016-03-31 05:48:20 +02:00
|
|
|
lazy val scriptedBufferLog = SettingKey[Boolean]("scripted-buffer-log")
|
2017-04-21 09:14:31 +02:00
|
|
|
lazy val scriptedLaunchOpts = SettingKey[Seq[String]](
|
|
|
|
|
"scripted-launch-opts",
|
|
|
|
|
"options to pass to jvm launching scripted tasks")
|
2016-03-31 05:48:20 +02:00
|
|
|
}
|
2015-01-13 04:01:16 +01:00
|
|
|
|
2016-03-31 05:48:20 +02:00
|
|
|
object Scripted {
|
2017-12-21 06:08:56 +01:00
|
|
|
// This is to workaround https://github.com/sbt/io/issues/110
|
|
|
|
|
sys.props.put("jna.nosys", "true")
|
|
|
|
|
|
2015-01-13 04:01:16 +01:00
|
|
|
lazy val MavenResolverPluginTest = config("mavenResolverPluginTest") extend Compile
|
2016-04-24 20:23:48 +02:00
|
|
|
lazy val RepoOverrideTest = config("repoOverrideTest") extend Compile
|
2014-12-18 05:38:10 +01:00
|
|
|
|
|
|
|
|
import sbt.complete._
|
|
|
|
|
import DefaultParsers._
|
|
|
|
|
// Paging, 1-index based.
|
|
|
|
|
case class ScriptedTestPage(page: Int, total: Int)
|
2017-03-14 16:53:06 +01:00
|
|
|
// FIXME: Duplicated with ScriptedPlugin.scriptedParser, this can be
|
|
|
|
|
// avoided once we upgrade build.properties to 0.13.14
|
2017-04-21 09:14:31 +02:00
|
|
|
def scriptedParser(scriptedBase: File): Parser[Seq[String]] = {
|
|
|
|
|
val scriptedFiles: NameFilter = ("test": NameFilter) | "pending"
|
|
|
|
|
val pairs = (scriptedBase * AllPassFilter * AllPassFilter * scriptedFiles).get map {
|
|
|
|
|
(f: File) =>
|
2014-12-18 05:38:10 +01:00
|
|
|
val p = f.getParentFile
|
|
|
|
|
(p.getParentFile.getName, p.getName)
|
2017-04-21 09:14:31 +02:00
|
|
|
}
|
|
|
|
|
val pairMap = pairs.groupBy(_._1).mapValues(_.map(_._2).toSet);
|
2014-12-18 05:38:10 +01:00
|
|
|
|
2017-04-21 09:14:31 +02:00
|
|
|
val id = charClass(c => !c.isWhitespace && c != '/').+.string
|
|
|
|
|
val groupP = token(id.examples(pairMap.keySet.toSet)) <~ token('/')
|
2014-12-18 05:38:10 +01:00
|
|
|
|
2017-04-21 09:14:31 +02:00
|
|
|
// 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)
|
|
|
|
|
val pageSize = files.size / page.total
|
|
|
|
|
// The last page may loose some values, so we explicitly keep them
|
|
|
|
|
val dropped = files.drop(pageSize * (page.page - 1))
|
|
|
|
|
if (page.page == page.total) dropped
|
|
|
|
|
else dropped.take(pageSize)
|
|
|
|
|
}
|
|
|
|
|
def nameP(group: String) = {
|
2017-05-01 23:31:47 +02:00
|
|
|
token("*".id | id.examples(pairMap.getOrElse(group, Set.empty[String])))
|
2014-12-18 05:38:10 +01:00
|
|
|
}
|
2017-04-21 09:14:31 +02:00
|
|
|
val PagedIds: Parser[Seq[String]] =
|
|
|
|
|
for {
|
|
|
|
|
group <- groupP
|
|
|
|
|
page <- pageP
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
2014-12-18 05:38:10 +01:00
|
|
|
|
2015-06-19 19:40:10 +02:00
|
|
|
// Interface to cross class loader
|
|
|
|
|
type SbtScriptedRunner = {
|
2017-04-28 11:41:22 +02:00
|
|
|
def runInParallel(resourceBaseDirectory: File,
|
|
|
|
|
bufferLog: Boolean,
|
|
|
|
|
tests: Array[String],
|
|
|
|
|
bootProperties: File,
|
|
|
|
|
launchOpts: Array[String],
|
|
|
|
|
prescripted: java.util.List[File]): Unit
|
2015-06-19 19:40:10 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-21 09:14:31 +02:00
|
|
|
def doScripted(launcher: File,
|
|
|
|
|
scriptedSbtClasspath: Seq[Attributed[File]],
|
|
|
|
|
scriptedSbtInstance: ScalaInstance,
|
|
|
|
|
sourcePath: File,
|
|
|
|
|
bufferLog: Boolean,
|
|
|
|
|
args: Seq[String],
|
|
|
|
|
prescripted: File => Unit,
|
|
|
|
|
launchOpts: Seq[String]): Unit = {
|
2014-12-18 05:38:10 +01:00
|
|
|
System.err.println(s"About to run tests: ${args.mkString("\n * ", "\n * ", "\n")}")
|
2017-11-16 15:09:25 +01:00
|
|
|
// 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"
|
2014-12-18 05:38:10 +01:00
|
|
|
val noJLine = new classpath.FilteredLoader(scriptedSbtInstance.loader, "jline." :: Nil)
|
|
|
|
|
val loader = classpath.ClasspathUtilities.toLoader(scriptedSbtClasspath.files, noJLine)
|
2015-06-19 19:40:10 +02:00
|
|
|
val bridgeClass = Class.forName("sbt.test.ScriptedRunner", true, loader)
|
2017-03-15 03:10:15 +01:00
|
|
|
val bridge = bridgeClass.getDeclaredConstructor().newInstance().asInstanceOf[SbtScriptedRunner]
|
2015-06-19 19:40:10 +02:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
def get(x: Int): sbt.File = ???
|
|
|
|
|
def size(): Int = 0
|
|
|
|
|
}
|
2017-04-28 11:41:22 +02:00
|
|
|
bridge.runInParallel(sourcePath,
|
|
|
|
|
bufferLog,
|
|
|
|
|
args.toArray,
|
|
|
|
|
launcher,
|
|
|
|
|
launchOpts.toArray,
|
|
|
|
|
callback)
|
2015-06-19 19:40:10 +02:00
|
|
|
} catch { case ite: java.lang.reflect.InvocationTargetException => throw ite.getCause }
|
2014-12-18 05:38:10 +01:00
|
|
|
}
|
2015-06-19 19:40:10 +02:00
|
|
|
}
|