project/Build.scala (157 lines of code) (raw):
// Copyright (c) 2017-2019 Twitter, Inc.
// Licensed under the Apache License, Version 2.0 (see LICENSE.md).
package rsc.build
import java.io.File.pathSeparator
import java.lang.ProcessBuilder._
import scala.collection.JavaConverters._
import scala.sys.process._
import sbt._
import sbt.Keys._
import sbt.plugins._
import complete.DefaultParsers._
object Build extends AutoPlugin {
override def requires: Plugins = JvmPlugin
override def trigger: PluginTrigger = allRequirements
import autoImport._
private lazy val buildRoot: File = file("").getAbsoluteFile
private lazy val scalafixRulesProject = ProjectRef(file(""), "scalafixRules")
private def command(commands: String*): String = command(commands.toList)
private def command(commands: List[String]): String = {
val buf = List.newBuilder[String]
commands.foreach { c =>
if (c.startsWith(";")) buf += c
else buf += s";$c"
}
buf.result.mkString(" ")
}
private def shellout(command: List[String], cwd: File): Unit = {
val builder = new java.lang.ProcessBuilder()
builder.command(command.asJava)
builder.directory(cwd)
builder.redirectOutput(Redirect.INHERIT)
builder.redirectError(Redirect.INHERIT)
val exitcode = builder.start().waitFor()
if (exitcode != 0) {
val what = command.mkString(" ")
sys.error(s"$what in $cwd has failed with code $exitcode")
}
}
private def scalafmt(args: List[String], cwd: File): Unit = {
val bin = new File(buildRoot, "bin/scalafmt").absolutePath
shellout(bin +: args, cwd)
}
private def scalafix(args: List[String], cwd: File): Unit = {
val bin = new File(buildRoot, "bin/scalafix").absolutePath
shellout(bin +: args, cwd)
}
private object projects {
def all: List[String] = List(
"bench",
"check",
"examplesCore",
"examplesOriginalCore",
"examplesDeps1",
"examplesDeps2",
"examplesDeps3",
"examplesFunction",
"examplesSemantic",
"rsc",
"scalafixInput",
"scalafixOutput",
"scalafixRules",
"scalafixTests",
"scalasig",
"scalap",
"tests"
)
def public: List[String] = List(
"check",
"rsc",
"scalafixRules",
"scalasig"
)
}
object autoImport {
val shell = inputKey[Unit]("Run shell command")
val scalafmtFormat = taskKey[Unit]("Automatically format all files")
val scalafmtTest = taskKey[Unit]("Test that all files are formatted")
val rewrite = taskKey[Unit]("Rewrite the project to be compatible with Rsc")
def computeScalaVersionFromTravisYml(prefix: String): String = {
val travisYml = IO.read(file(".travis.yml"))
val scalaRegex = (prefix + ".\\d+").r
val scalaMatch = scalaRegex.findFirstMatchIn(travisYml)
scalaMatch.map(_.group(0)).get
}
def computeScalafixVersionFromBinScalafix(): String = {
val binScalafix = IO.read(file("bin/scalafix"))
val scalaRegex = "VERSION=\"(.*?)\"".r
val scalaMatch = scalaRegex.findFirstMatchIn(binScalafix)
scalaMatch.map(_.group(1)).get
}
object ui {
lazy val ciFmt = "scalafmtTest"
lazy val ciFast = fastTest
lazy val ciSlow = slowTest
lazy val ciScalafix = scalafixTest
lazy val ci = command(ciFmt, ciFast, ciSlow, ciScalafix)
lazy val cleanAll = command(projects.all.map(_ + "/clean"))
lazy val compileAll = command(projects.all.map(_ + "/compile"))
lazy val fmtAll = "scalafmtFormat"
lazy val testAll = command("reload", "cleanAll", ci)
lazy val benchAll = command(
"cleanAll",
"compileAll",
"bench/jmh:run RscParse RscIndex RscOutline RscSemanticdb RscScalasig ScalacCompile"
)
lazy val publish = command(projects.public.map(_ + "/publish"))
lazy val publishLocal = command(projects.public.map(_ + "/publishLocal"))
lazy val publishSigned = command(projects.public.map(_ + "/publishSigned"))
lazy val compile = "tests/test:compile"
lazy val fastTest = "tests/fast:test"
lazy val slowTest = command("tests/slow:test")
lazy val scalafixTest = command(
"scalafixTests/test",
"scalafixOutput/compile"
)
lazy val test = fastTest
lazy val benchParse = "bench/jmh:run RscParse"
lazy val benchIndex = "bench/jmh:run RscIndex"
lazy val benchOutline = "bench/jmh:run RscOutline"
lazy val benchSemanticdb = "bench/jmh:run RscSemanticdb"
lazy val benchScalasig = "bench/jmh:run RscScalasig"
lazy val benchScalac = "bench/jmh:run ScalacCompile"
lazy val rewrite = "examplesCore/rewrite"
}
lazy val isCI = sys.env.contains("CI")
// https://stackoverflow.com/questions/41229451/how-to-disable-slow-tagged-scalatests-by-default-allow-execution-with-option
lazy val Fast = config("fast").extend(Test)
lazy val Slow = config("slow").extend(Test)
}
override lazy val globalSettings: Seq[Def.Setting[_]] = List(
scalafmtFormat := {
scalafmt(List("--non-interactive"), buildRoot)
},
scalafmtTest := {
scalafmt(List("--test", "--non-interactive", "--quiet"), buildRoot)
},
shell := {
val args = spaceDelimited("<arg>").parsed
val command = args.mkString(" ")
val retcode = command.!
if (retcode != 0) sys.error(s"$command returned $retcode")
}
)
override lazy val projectSettings: Seq[Def.Setting[_]] = List(
rewrite := {
val toolClasspath = fullClasspath.in(scalafixRulesProject, Compile).value
val args = List.newBuilder[String]
args += "--tool-classpath"
args += toolClasspath.map(_.data.absolutePath).mkString(pathSeparator)
args += "--classpath"
args += fullClasspath.in(Compile).value.map(_.data.absolutePath).mkString(pathSeparator)
args += "--sourceroot"
args += buildRoot.absolutePath
args += "--rules"
args += "scala:rsc.rules.RscCompat"
args += baseDirectory.value.absolutePath
scalafix(args.result, baseDirectory.value)
}
)
}