blob: 69f0dad620151f18b7fddcd88747a06a43e0d959 [file] [log] [blame]
import sbt._
import Keys._
import de.johoop.jacoco4sbt._
import JacocoPlugin._
import com.typesafe.sbt.SbtStartScript
object DaffodilBuild extends Build {
var s = Defaults.defaultSettings
lazy val nopub = Seq(publish := {}, publishLocal := {})
// sbt uses reflection to find suprojects. we need to also add the projects
// in daffodil-extra, which can't be detected via reflection
override def projects: Seq[Project] = super.projects ++ extraProjects
// daffodil projects
lazy val root = {
val r = Project(id = "daffodil", base = file("."), settings = s ++ nopub)
.configs(DebugTest)
.configs(NewTest)
.configs(CliTest)
.aggregate(propgen, lib, core, runtime1, tdml, testIBM1, cli, test)
extraProjects.foldLeft(r) { (r, p) => r.aggregate(p) }
}
lazy val propgen = Project(id = "daffodil-propgen", base = file("daffodil-propgen"), settings = s ++ nopub)
.configs(DebugTest)
.configs(NewTest)
lazy val lib = Project(id = "daffodil-lib", base = file("daffodil-lib"), settings = s ++ propgenSettings)
.configs(DebugTest)
.configs(NewTest)
lazy val core = Project(id = "daffodil-core", base = file("daffodil-core"), settings = s)
.configs(DebugTest)
.configs(NewTest)
.dependsOn(lib)
lazy val runtime1 = Project(id = "daffodil-runtime1", base = file("daffodil-runtime1"), settings = s)
.configs(DebugTest)
.configs(NewTest)
.dependsOn(core)
lazy val tdml = Project(id = "daffodil-tdml", base = file("daffodil-tdml"), settings = s)
.configs(DebugTest)
.configs(NewTest)
.dependsOn(runtime1)
lazy val cli = Project(id = "daffodil-cli", base = file("daffodil-cli"), settings = s ++ startScriptSettings ++ stageTaskSettings)
.configs(DebugTest)
.configs(NewTest)
.configs(CliTest)
.dependsOn(tdml)
lazy val test = Project(id = "daffodil-test", base = file("daffodil-test"), settings = s ++ nopub)
.configs(DebugTest)
.configs(NewTest)
.dependsOn(tdml)
lazy val perf = Project(id = "daffodil-perf", base = file("daffodil-perf"), settings = s ++ nopub)
.configs(DebugTest)
.configs(NewTest)
.dependsOn(tdml)
lazy val testIBM1 = Project(id = "daffodil-test-ibm1", base = file("daffodil-test-ibm1"), settings = s ++ nopub)
.configs(DebugTest)
.configs(NewTest)
.dependsOn(tdml)
// any directories in daffodil-extra are treated as subprojects. this is
// useful for symlinking tests that should not be committed to the git repo
// but still be compiled/tested as part of daffodil
lazy val extrasDir = new File("daffodil-extra")
lazy val extraProjects = extrasDir.listFiles.filter { _.isDirectory }.map { dir =>
Project(id = dir.name, base = dir, settings = s ++ nopub)
.configs(DebugTest)
.configs(NewTest)
.dependsOn(tdml)
}
//set up 'sbt stage' as a dependency
//TODO: find a way to clean this up and reduce repetition
lazy val testTask = Keys.test in CliTest
lazy val testOnlyTask = Keys.testOnly in CliTest
lazy val testQuickTask = Keys.testQuick in CliTest
lazy val testTaskNew = Keys.test in NewTest
lazy val testOnlyTaskNew = Keys.testOnly in NewTest
lazy val testQuickTaskNew = Keys.testQuick in NewTest
lazy val testTaskDebug = Keys.test in DebugTest
lazy val testOnlyTaskDebug = Keys.testOnly in DebugTest
lazy val testQuickTaskDebug = Keys.testQuick in DebugTest
lazy val stageTask = SbtStartScript.stage in Compile // in cli
lazy val stageTaskSettings = Seq(
//cli test tasks
(testTask <<= testTask.dependsOn(stageTask)),
(testOnlyTask <<= testOnlyTask.dependsOn(stageTask)),
(testQuickTask <<= testQuickTask.dependsOn(stageTask)),
//new test tasks
(testTaskNew <<= testTaskNew.dependsOn(stageTask)),
(testOnlyTaskNew <<= testOnlyTaskNew.dependsOn(stageTask)),
(testQuickTaskNew <<= testQuickTaskNew.dependsOn(stageTask)),
//debug test tasks
(testTaskDebug <<= testTaskDebug.dependsOn(stageTask)),
(testOnlyTaskDebug <<= testOnlyTaskDebug.dependsOn(stageTask)),
(testQuickTaskDebug <<= testQuickTaskDebug.dependsOn(stageTask)),
//cli, new, and debug tasks
(debugTask <<= debugTask.dependsOn(stageTask)),
(newTask <<= newTask.dependsOn(stageTask)),
(cliTask <<= cliTask.dependsOn(stageTask))
)
val propertyGenerator = TaskKey[Seq[File]]("gen-props", "Generate properties scala source")
lazy val propgenSettings = Seq(
sourceGenerators in Compile <+= (propertyGenerator in Compile),
propertyGenerator in Compile <<=
(cacheDirectory, sourceManaged in Compile, dependencyClasspath in Runtime in propgen, sources in Compile in propgen, resources in Compile in propgen, streams in propgen) map {
(cache, outdir, cp, inSrc, inRSrc, stream) => {
// FileFunction.cached will only run the property generator if any
// source or resources in propgen subproject changed
val filesToWatch = (inSrc ++ inRSrc).toSet
val cachedFun = FileFunction.cached(cache / "propgen", FilesInfo.lastModified, FilesInfo.exists) {
(in: Set[File]) => runPropertyGenerator(outdir, cp.files, stream.log)
}
cachedFun(filesToWatch).toSeq
}
}
)
def runPropertyGenerator(outdir: File, cp: Seq[File], log: Logger): Set[File] = {
val mainClass = "edu.illinois.ncsa.daffodil.propGen.PropertyGenerator"
val out = new java.io.ByteArrayOutputStream()
val ret = new Fork.ForkScala(mainClass).fork(None, Nil, cp, Seq(outdir.toString), None, false, CustomOutput(out)).exitValue()
if (ret != 0) {
sys.error("Failed to generate code")
}
val in = new java.io.InputStreamReader(new java.io.ByteArrayInputStream(out.toByteArray))
val bin = new java.io.BufferedReader(in)
val iterator = Iterator.continually(bin.readLine()).takeWhile(_ != null)
val files = iterator.map { f =>
log.info("Generated %s".format(f))
new File(f)
}.toSet
files
}
// modify the managed source directories so that any generated code can be more easily included in IDE's
s ++= Seq(sourceManaged <<= baseDirectory(_ / "src_managed"))
// creates 'sbt debug:*' tasks, using src/test/scala-debug as the source directory
lazy val DebugTest = config("debug") extend(Runtime)
lazy val debugSettings: Seq[Setting[_]] = inConfig(DebugTest)(Defaults.testSettings ++ Seq(
sourceDirectory <<= baseDirectory(_ / "src" / "test"),
scalaSource <<= sourceDirectory(_ / "scala-debug"),
javaSource <<= sourceDirectory(_ / "java-debug"),
exportJars := false,
publishArtifact := false
))
s ++= Seq(debugSettings : _*)
// creates 'sbt debug' task, which is essentially an alias for 'sbt debug:test'
lazy val debugTask = TaskKey[Unit]("debug", "Executes all debug tests")
lazy val debugTaskSettings = debugTask <<= (executeTests in DebugTest, streams in DebugTest, resolvedScoped in DebugTest, state in DebugTest) map {
(results, s, scoped, state) => {
val display = Project.showContextKey(state)
Tests.showResults(s.log, results, "No tests to run for " + display(scoped))
}
}
s ++= Seq(debugTaskSettings)
// creates 'sbt new:*' tasks, using src/test/scala-new as the source directory
lazy val NewTest = config("new") extend(Runtime)
lazy val newSettings: Seq[Setting[_]] = inConfig(NewTest)(Defaults.testSettings ++ Seq(
sourceDirectory <<= baseDirectory(_ / "src" / "test"),
scalaSource <<= sourceDirectory(_ / "scala-new"),
javaSource <<= sourceDirectory(_ / "java-new"),
exportJars := false,
publishArtifact := false
))
s ++= Seq(newSettings : _*)
// creates 'sbt new' task, which is essentially an alias for 'sbt new:test'
lazy val newTask = TaskKey[Unit]("new", "Executes all new tests")
lazy val newTaskSettings = newTask <<= (executeTests in NewTest, streams in NewTest, resolvedScoped in NewTest, state in NewTest) map {
(results, s, scoped, state) => {
val display = Project.showContextKey(state)
Tests.showResults(s.log, results, "No tests to run for " + display(scoped))
}
}
s ++= Seq(newTaskSettings)
// add scala-new as a source test directory for the 'sbt test' commands
lazy val buildNewWithTestSettings = unmanagedSourceDirectories in Test <++= baseDirectory { base =>
Seq(base / "src/test/scala-new")
}
s ++= Seq(buildNewWithTestSettings)
// creates 'sbt cli:*' tasks, using src/test/scala-cli as the source directory
lazy val CliTest = config("cli") extend(Runtime)
lazy val cliSettings: Seq[Setting[_]] = inConfig(CliTest)(Defaults.testSettings ++ Seq(
sourceDirectory <<= baseDirectory(_ / "src" / "test"),
scalaSource <<= sourceDirectory(_ / "scala-cli"),
javaSource <<= sourceDirectory(_ / "java-cli"),
exportJars := false,
publishArtifact := false
))
s ++= Seq(cliSettings : _*)
// creates 'sbt cli' task, which is essentially an alias for 'sbt cli:test'
lazy val cliTask = TaskKey[Unit]("cli", "Executes all CLI tests")
lazy val cliTaskSettings = cliTask <<= (executeTests in CliTest, streams in CliTest, resolvedScoped in CliTest, state in CliTest) map {
(results, s, scoped, state) => {
val display = Project.showContextKey(state)
Tests.showResults(s.log, results, "No tests to run for " + display(scoped))
}
}
s ++= Seq(cliTaskSettings)
// jacoco configuration
s ++= Seq(jacoco.settings : _*)
// start-script configuration
lazy val startScriptSettings = Seq(SbtStartScript.startScriptForJarSettings : _*) ++
Seq(mainClass in Compile := Some("edu.illinois.ncsa.daffodil.Main"))
def exec(cmd: String): Seq[String] = {
val r = java.lang.Runtime.getRuntime()
val p = r.exec(cmd)
p.waitFor()
val ret = p.exitValue()
if (ret != 0) {
sys.error("Command failed: " + cmd)
}
val is = p.getInputStream
val res = scala.io.Source.fromInputStream(is).getLines()
res.toSeq
}
// get the version from the latest tag
s ++= Seq(version := {
val describe = exec("git describe --long HEAD")
assert(describe.length == 1)
val DescribeRegex = """^(.+)-(.+)-(.+)$""".r
val res = describe(0) match {
case DescribeRegex(taggedVersion, "0", hash) => {
// we are on a tag, build a tag release
val status = exec("git status --porcelain")
if (status.length > 0) {
taggedVersion + "-SNAPSHOT"
} else {
taggedVersion
}
}
case DescribeRegex(version, _, hash) => {
// not on a tag
// get the current branch
val branch = exec("git rev-parse --abbrev-ref HEAD")
assert(branch.length == 1)
val VersionBranchRegex = """^\d+\.\d+\.\d+$""".r
branch(0) match {
case VersionBranchRegex => {
// we are developing on a version branch, create a snapshot
branch + "-SNAPSHOT"
}
case _ => {
// not on a version branch (e.g. a review branch), try to figure
// out the tracking branch
val trackingBranch = exec("git for-each-ref --format=%(upstream:short) refs/heads/" + branch(0))
assert(trackingBranch.length == 1)
val TrackingBranchRegex = """^[^/]+/(.+)$""".r
trackingBranch(0) match {
case TrackingBranchRegex(trackingVersion) => {
trackingVersion + "-SNAPSHOT"
}
case _ => {
// no idea what the version is, set it to a fefault
"0.0.0-SNAPSHOT"
}
}
}
}
}
}
res
})
def gitShortHash(): String = {
val hash = exec("git rev-parse --short HEAD")
assert(hash.length == 1)
hash(0)
}
// update the manifest version to include the git hash
lazy val manifestVersion = packageOptions in (Compile, packageBin) <++= version map { v => {
val version = "%s-%s".format(v, gitShortHash)
Seq(
Package.ManifestAttributes(java.util.jar.Attributes.Name.IMPLEMENTATION_VERSION -> version),
Package.ManifestAttributes(java.util.jar.Attributes.Name.SPECIFICATION_VERSION -> version)
)
}}
s ++= manifestVersion
}