sbt/project/Util.scala

201 lines
6.6 KiB
Scala
Raw Normal View History

2016-07-07 00:56:31 +02:00
import scala.util.control.NonFatal
2014-05-01 18:50:07 +02:00
import sbt._
import Keys._
Upgrade the build to sbt 1.0.0-M5 Some plugins remain commented out, for now. sbt-doge is no longer needed because a variant of it has been folded into sbt 1. For some reason scripted requires src/doc jars of sbt, so switch back to using `publishAll` rather than `publishLocalBinAll`. :( Also, the sys.prop change in scripted is to force log4j2 to not use a thread context classloader, and avoid the following: ERROR StatusLogger Unable to create custom ContextSelector. Falling back to default. java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.core.async.AsyncLoggerContextSelector to org.apache.logging.log4j.core.selector.ContextSelector at java.lang.Class.cast(Class.java:3369) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOf(LoaderUtil.java:201) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:226) at org.apache.logging.log4j.core.impl.Log4jContextFactory.createContextSelector(Log4jContextFactory.java:97) at org.apache.logging.log4j.core.impl.Log4jContextFactory.<init>(Log4jContextFactory.java:58) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at java.lang.Class.newInstance(Class.java:442) at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:94) at org.apache.logging.log4j.spi.ThreadContextMapFactory.createThreadContextMap(ThreadContextMapFactory.java:73) at org.apache.logging.log4j.ThreadContext.init(ThreadContext.java:223) at org.apache.logging.log4j.ThreadContext.<clinit>(ThreadContext.java:202) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:83) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:67) at org.apache.logging.log4j.core.lookup.ContextMapLookup.<init>(ContextMapLookup.java:34) at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:117) at org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(AbstractConfiguration.java:125) at org.apache.logging.log4j.core.config.DefaultConfiguration.<init>(DefaultConfiguration.java:46) at org.apache.logging.log4j.core.layout.PatternLayout$Builder.build(PatternLayout.java:650) at org.apache.logging.log4j.core.layout.PatternLayout.createDefaultLayout(PatternLayout.java:487) at sbt.internal.util.ConsoleAppender.<init>(ConsoleAppender.scala:245) at sbt.internal.util.ConsoleAppender$.apply(ConsoleAppender.scala:196) at sbt.internal.util.ConsoleLogger.<init>(ConsoleAppender.scala:42) at sbt.internal.util.ConsoleLogger$.apply(ConsoleAppender.scala:34) at sbt.test.ScriptedRunner.run(ScriptedTests.scala:221) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at Scripted$.doScripted(Scripted.scala:125) at $0483e89d182e9d240274$.$anonfun$scriptedTask$5(build.sbt:301)
2017-05-03 16:52:36 +02:00
import sbt.internal.inc.Analysis
2014-05-01 18:50:07 +02:00
object Util {
2017-03-29 15:43:38 +02:00
val ExclusiveTest: Tags.Tag = Tags.Tag("exclusive-test")
val componentID: SettingKey[Option[String]] = settingKey[Option[String]]("")
val scalaKeywords: TaskKey[Set[String]] = taskKey[Set[String]]("")
val generateKeywords: TaskKey[File] = taskKey[File]("")
2014-05-01 18:50:07 +02:00
2014-12-18 05:38:10 +01:00
def noPublishSettings: Seq[Setting[_]] = Seq(publish := {})
2014-05-01 18:50:07 +02:00
def crossBuild: Seq[Setting[_]] =
Seq(
crossPaths := true
)
2014-05-01 18:50:07 +02:00
2017-03-29 15:43:38 +02:00
lazy val javaOnlySettings: Seq[Setting[_]] = Seq(
// crossPaths := false,
compileOrder := CompileOrder.JavaThenScala,
unmanagedSourceDirectories in Compile := Seq((javaSource in Compile).value)
)
2014-05-01 18:50:07 +02:00
lazy val baseScalacOptions = Seq(
scalacOptions ++= Seq(
2018-09-18 23:45:24 +02:00
"-Xelide-below",
"0",
"-language:existentials",
"-language:postfixOps",
2018-10-07 21:25:17 +02:00
"-Yrangepos",
2018-09-18 23:45:24 +02:00
),
Compile / doc / scalacOptions -= "-Xlint",
Compile / doc / scalacOptions -= "-Xfatal-warnings",
2014-05-01 18:50:07 +02:00
)
2017-04-21 09:14:31 +02:00
def projectComponent: Setting[_] =
projectID := (componentID.value match {
case Some(id) => projectID.value extra ("e:component" -> id)
case None => projectID.value
})
2014-05-01 18:50:07 +02:00
lazy val apiDefinitions = TaskKey[Seq[File]]("api-definitions")
def generateAPICached(
defs: Seq[File],
cp: Classpath,
out: File,
main: Option[String],
run: ScalaRun,
s: TaskStreams
): Seq[File] = {
2017-04-21 09:14:31 +02:00
def gen() = generateAPI(defs, cp, out, main, run, s)
val f = FileFunction.cached(s.cacheDirectory / "gen-api", FilesInfo.hash) { _ =>
gen().toSet
} // TODO: check if output directory changed
f(defs.toSet).toSeq
}
def generateAPI(
defs: Seq[File],
cp: Classpath,
out: File,
main: Option[String],
run: ScalaRun,
s: TaskStreams
): Seq[File] = {
2017-04-21 09:14:31 +02:00
IO.delete(out)
IO.createDirectory(out)
val args = "xsbti.api" :: out.getAbsolutePath :: defs.map(_.getAbsolutePath).toList
val mainClass = main getOrElse "No main class defined for datatype generator"
Upgrade the build to sbt 1.0.0-M5 Some plugins remain commented out, for now. sbt-doge is no longer needed because a variant of it has been folded into sbt 1. For some reason scripted requires src/doc jars of sbt, so switch back to using `publishAll` rather than `publishLocalBinAll`. :( Also, the sys.prop change in scripted is to force log4j2 to not use a thread context classloader, and avoid the following: ERROR StatusLogger Unable to create custom ContextSelector. Falling back to default. java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.core.async.AsyncLoggerContextSelector to org.apache.logging.log4j.core.selector.ContextSelector at java.lang.Class.cast(Class.java:3369) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOf(LoaderUtil.java:201) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:226) at org.apache.logging.log4j.core.impl.Log4jContextFactory.createContextSelector(Log4jContextFactory.java:97) at org.apache.logging.log4j.core.impl.Log4jContextFactory.<init>(Log4jContextFactory.java:58) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at java.lang.Class.newInstance(Class.java:442) at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:94) at org.apache.logging.log4j.spi.ThreadContextMapFactory.createThreadContextMap(ThreadContextMapFactory.java:73) at org.apache.logging.log4j.ThreadContext.init(ThreadContext.java:223) at org.apache.logging.log4j.ThreadContext.<clinit>(ThreadContext.java:202) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:83) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:67) at org.apache.logging.log4j.core.lookup.ContextMapLookup.<init>(ContextMapLookup.java:34) at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:117) at org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(AbstractConfiguration.java:125) at org.apache.logging.log4j.core.config.DefaultConfiguration.<init>(DefaultConfiguration.java:46) at org.apache.logging.log4j.core.layout.PatternLayout$Builder.build(PatternLayout.java:650) at org.apache.logging.log4j.core.layout.PatternLayout.createDefaultLayout(PatternLayout.java:487) at sbt.internal.util.ConsoleAppender.<init>(ConsoleAppender.scala:245) at sbt.internal.util.ConsoleAppender$.apply(ConsoleAppender.scala:196) at sbt.internal.util.ConsoleLogger.<init>(ConsoleAppender.scala:42) at sbt.internal.util.ConsoleLogger$.apply(ConsoleAppender.scala:34) at sbt.test.ScriptedRunner.run(ScriptedTests.scala:221) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at Scripted$.doScripted(Scripted.scala:125) at $0483e89d182e9d240274$.$anonfun$scriptedTask$5(build.sbt:301)
2017-05-03 16:52:36 +02:00
run.run(mainClass, cp.files, args, s.log).failed foreach (e => sys error e.getMessage)
2017-04-21 09:14:31 +02:00
(out ** "*.java").get
}
Upgrade the build to sbt 1.0.0-M5 Some plugins remain commented out, for now. sbt-doge is no longer needed because a variant of it has been folded into sbt 1. For some reason scripted requires src/doc jars of sbt, so switch back to using `publishAll` rather than `publishLocalBinAll`. :( Also, the sys.prop change in scripted is to force log4j2 to not use a thread context classloader, and avoid the following: ERROR StatusLogger Unable to create custom ContextSelector. Falling back to default. java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.core.async.AsyncLoggerContextSelector to org.apache.logging.log4j.core.selector.ContextSelector at java.lang.Class.cast(Class.java:3369) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOf(LoaderUtil.java:201) at org.apache.logging.log4j.util.LoaderUtil.newCheckedInstanceOfProperty(LoaderUtil.java:226) at org.apache.logging.log4j.core.impl.Log4jContextFactory.createContextSelector(Log4jContextFactory.java:97) at org.apache.logging.log4j.core.impl.Log4jContextFactory.<init>(Log4jContextFactory.java:58) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at java.lang.Class.newInstance(Class.java:442) at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:94) at org.apache.logging.log4j.spi.ThreadContextMapFactory.createThreadContextMap(ThreadContextMapFactory.java:73) at org.apache.logging.log4j.ThreadContext.init(ThreadContext.java:223) at org.apache.logging.log4j.ThreadContext.<clinit>(ThreadContext.java:202) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createDefaultInjector(ContextDataInjectorFactory.java:83) at org.apache.logging.log4j.core.impl.ContextDataInjectorFactory.createInjector(ContextDataInjectorFactory.java:67) at org.apache.logging.log4j.core.lookup.ContextMapLookup.<init>(ContextMapLookup.java:34) at org.apache.logging.log4j.core.lookup.Interpolator.<init>(Interpolator.java:117) at org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(AbstractConfiguration.java:125) at org.apache.logging.log4j.core.config.DefaultConfiguration.<init>(DefaultConfiguration.java:46) at org.apache.logging.log4j.core.layout.PatternLayout$Builder.build(PatternLayout.java:650) at org.apache.logging.log4j.core.layout.PatternLayout.createDefaultLayout(PatternLayout.java:487) at sbt.internal.util.ConsoleAppender.<init>(ConsoleAppender.scala:245) at sbt.internal.util.ConsoleAppender$.apply(ConsoleAppender.scala:196) at sbt.internal.util.ConsoleLogger.<init>(ConsoleAppender.scala:42) at sbt.internal.util.ConsoleLogger$.apply(ConsoleAppender.scala:34) at sbt.test.ScriptedRunner.run(ScriptedTests.scala:221) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at Scripted$.doScripted(Scripted.scala:125) at $0483e89d182e9d240274$.$anonfun$scriptedTask$5(build.sbt:301)
2017-05-03 16:52:36 +02:00
def lastCompilationTime(analysis: Analysis): Long = {
2017-04-21 09:14:31 +02:00
val lastCompilation = analysis.compilations.allCompilations.lastOption
lastCompilation.map(_.getStartTime) getOrElse 0L
2017-04-21 09:14:31 +02:00
}
def generateVersionFile(
version: String,
dir: File,
s: TaskStreams,
analysis: Analysis
): Seq[File] = {
2017-04-21 09:14:31 +02:00
import java.util.{ Date, TimeZone }
val formatter = new java.text.SimpleDateFormat("yyyyMMdd'T'HHmmss")
formatter.setTimeZone(TimeZone.getTimeZone("GMT"))
val timestamp = formatter.format(new Date)
val content = versionLine(version) + "\ntimestamp=" + timestamp
val f = dir / "xsbt.version.properties"
2017-12-22 01:49:59 +01:00
// TODO: replace lastModified() with sbt.io.IO.getModifiedTimeOrZero(), once the build
// has been upgraded to a version of sbt that includes that call.
if (!f.exists || f.lastModified < lastCompilationTime(analysis) || !containsVersion(f, version)) {
2017-04-21 09:14:31 +02:00
s.log.info("Writing version information to " + f + " :\n" + content)
IO.write(f, content)
2014-05-01 18:50:07 +02:00
}
2017-04-21 09:14:31 +02:00
f :: Nil
}
2014-05-01 18:50:07 +02:00
def versionLine(version: String): String = "version=" + version
2017-04-21 09:14:31 +02:00
def containsVersion(propFile: File, version: String): Boolean =
IO.read(propFile).contains(versionLine(version))
2014-05-01 18:50:07 +02:00
def binID = "compiler-interface-bin"
def srcID = "compiler-interface-src"
def publishPomSettings: Seq[Setting[_]] = Seq(
pomPostProcess := cleanPom _
)
2017-04-21 09:14:31 +02:00
def cleanPom(pomNode: scala.xml.Node) = {
import scala.xml._
def cleanNodes(nodes: Seq[Node]): Seq[Node] = nodes flatMap {
case elem @ Elem(_, "dependency", _, _, _*) if excludePomDependency(elem) =>
2017-04-21 09:14:31 +02:00
NodeSeq.Empty
2019-11-28 19:05:49 +01:00
case Elem(_, "classifier", _, _, _*) =>
2017-04-21 09:14:31 +02:00
NodeSeq.Empty
case Elem(prefix, label, attributes, scope, children @ _*) =>
val cleanedNodes = cleanNodes(children)
Elem(prefix, label, attributes, scope, cleanedNodes.isEmpty, cleanedNodes: _*).theSeq
case other => other
2014-05-01 18:50:07 +02:00
}
2017-04-21 09:14:31 +02:00
cleanNodes(pomNode.theSeq)(0)
}
2014-05-01 18:50:07 +02:00
2017-04-21 09:14:31 +02:00
def excludePomDependency(node: scala.xml.Node) = node \ "artifactId" exists { n =>
excludePomArtifact(n.text)
}
2014-05-01 18:50:07 +02:00
2016-05-08 22:18:23 +02:00
def excludePomArtifact(artifactId: String) = (artifactId startsWith "compiler-bridge")
2014-05-01 18:50:07 +02:00
val testExclusive = tags in test += ((ExclusiveTest, 1))
// TODO: replace with Tags.exclusive after 0.12.0
val testExclusiveRestriction = Tags.customLimit { (tags: Map[Tags.Tag, Int]) =>
val exclusive = tags.getOrElse(ExclusiveTest, 0)
val all = tags.getOrElse(Tags.All, 0)
exclusive == 0 || all == 1
}
2017-04-21 09:14:31 +02:00
def getScalaKeywords: Set[String] = {
val g = new scala.tools.nsc.Global(new scala.tools.nsc.Settings)
g.nme.keywords.map(_.toString)
}
2017-03-29 15:43:38 +02:00
2017-04-21 09:14:31 +02:00
def writeScalaKeywords(base: File, keywords: Set[String]): File = {
val init = keywords.map(tn => '"' + tn + '"').mkString("Set(", ", ", ")")
val ObjectName = "ScalaKeywords"
val PackageName = "sbt.internal.util"
val keywordsSrc = s"""
|package $PackageName
|object $ObjectName {
| val values = $init
|}
""".trim.stripMargin
val out = base / PackageName.replace('.', '/') / s"$ObjectName.scala"
2017-04-21 09:14:31 +02:00
IO.write(out, keywordsSrc)
out
}
2017-03-29 15:43:38 +02:00
2017-04-21 09:14:31 +02:00
def keywordsSettings: Seq[Setting[_]] =
inConfig(Compile)(
Seq(
scalaKeywords := getScalaKeywords,
generateKeywords := writeScalaKeywords(sourceManaged.value, scalaKeywords.value),
sourceGenerators += Def.task(Seq(generateKeywords.value)).taskValue
)
)
}
2014-05-01 18:50:07 +02:00
object Licensed {
lazy val notice = SettingKey[File]("notice")
lazy val extractLicenses = TaskKey[Seq[File]]("extract-licenses")
lazy val seeRegex = """\(see (.*?)\)""".r
2017-04-21 09:14:31 +02:00
def licensePath(base: File, str: String): File = {
val path = base / str;
if (path.exists) path else sys.error("Referenced license '" + str + "' not found at " + path)
}
def seePaths(base: File, noticeString: String): Seq[File] =
seeRegex.findAllIn(noticeString).matchData.map(d => licensePath(base, d.group(1))).toList
2014-05-01 18:50:07 +02:00
def settings: Seq[Setting[_]] = Seq(
2017-03-29 15:43:38 +02:00
notice := (baseDirectory.value / "NOTICE"),
unmanagedResources in Compile ++= notice.value +: extractLicenses.value,
extractLicenses := extractLicenses0(
(baseDirectory in ThisBuild).value,
notice.value,
streams.value
)
2014-05-01 18:50:07 +02:00
)
def extractLicenses0(base: File, note: File, s: TaskStreams): Seq[File] =
2017-04-21 09:14:31 +02:00
if (!note.exists) Nil
else
try {
seePaths(base, IO.read(note))
} catch {
2019-11-28 19:05:49 +01:00
case NonFatal(_) => s.log.warn("Could not read NOTICE"); Nil
2017-04-21 09:14:31 +02:00
}
}