diff options
Diffstat (limited to 'project')
-rw-r--r-- | project/BuildSettings.scala | 11 | ||||
-rw-r--r-- | project/MiMa.scala | 95 | ||||
-rw-r--r-- | project/Osgi.scala | 4 | ||||
-rw-r--r-- | project/Quiet.scala | 2 | ||||
-rw-r--r-- | project/ScalaTool.scala | 12 | ||||
-rw-r--r-- | project/ScriptCommands.scala | 22 | ||||
-rw-r--r-- | project/VersionUtil.scala | 34 | ||||
-rw-r--r-- | project/plugins.sbt | 5 |
8 files changed, 168 insertions, 17 deletions
diff --git a/project/BuildSettings.scala b/project/BuildSettings.scala new file mode 100644 index 0000000000..76cd888a2d --- /dev/null +++ b/project/BuildSettings.scala @@ -0,0 +1,11 @@ +import sbt._ + +/** This object defines keys that should be visible with an unqualified name in all .sbt files and the command line */ +object BuildSettings extends AutoPlugin { + object autoImport { + lazy val antStyle = settingKey[Boolean]("Use ant-style incremental builds instead of name-hashing") + lazy val baseVersion = settingKey[String]("The base version number from which all others are derived") + lazy val baseVersionSuffix = settingKey[String]("Identifies the kind of version to build") + lazy val mimaReferenceVersion = settingKey[Option[String]]("Scala version number to run MiMa against") + } +} diff --git a/project/MiMa.scala b/project/MiMa.scala new file mode 100644 index 0000000000..66442fc725 --- /dev/null +++ b/project/MiMa.scala @@ -0,0 +1,95 @@ +// It would be nice to use sbt-mima-plugin here, but the plugin is missing +// at least two features we need: +// * ability to run MiMa twice, swapping `curr` and `prev`, to detect +// both forwards and backwards incompatibilities (possibly fixed as of +// https://github.com/typesafehub/migration-manager/commit/2844ffa48b6d2255aa64bd687703aec21dadd55e) +// * ability to pass a filter file (https://github.com/typesafehub/migration-manager/issues/102) +// So we invoke the MiMa CLI directly; it's also what the Ant build did. + +import sbt._ +import sbt.Keys._ +import BuildSettings.autoImport._ + +object MiMa { + lazy val mima = + taskKey[Unit]("run Migration Manager to detect binary incompatibilities") + + lazy val settings = + Seq( + mima := { + val log = streams.value.log + mimaReferenceVersion.value.fold { + log.info(s"No reference version defined - skipping binary compatibility checks") + } { refVersion => + def runOnce(prev: java.io.File, curr: java.io.File, isForward: Boolean): Unit = { + val direction = if (isForward) "forward" else "backward" + log.info(s"Checking $direction binary compatibility") + log.debug(s"prev = $prev, curr = $curr") + runMima( + prev = if (isForward) curr else prev, + curr = if (isForward) prev else curr, + // TODO: it would be nicer if each subproject had its own whitelist, but for now + // for compatibility with how Ant did things, there's just one at the root. + // once Ant is gone we'd be free to split it up. + filter = (baseDirectory in ThisBuild).value / s"bincompat-$direction.whitelist.conf", + log) + } + val artifact = + getPreviousArtifact( + "org.scala-lang" % s"${name.value}" % refVersion, + ivySbt.value, streams.value) + for (isForward <- Seq(false, true)) + runOnce(artifact, (packageBin in Compile).value, isForward) + } + } + ) + + def runMima(prev: java.io.File, curr: java.io.File, filter: java.io.File, log: Logger): Unit = { + val args = Array( + "--prev", prev.getAbsolutePath, + "--curr", curr.getAbsolutePath, + "--filters", filter.getAbsolutePath, + "--generate-filters" + ) + val exitCode = TrapExit(com.typesafe.tools.mima.cli.Main.main(args), log) + if (exitCode != 0) + throw new RuntimeException(s"MiMa failed with exit code $exitCode") + } + + // cribbed from https://github.com/typesafehub/migration-manager/blob/master/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/SbtMima.scala + def getPreviousArtifact(m: ModuleID, ivy: IvySbt, s: TaskStreams): File = { + val moduleSettings = InlineConfiguration( + "dummy" % "test" % "version", + ModuleInfo("dummy-test-project-for-resolving"), + dependencies = Seq(m)) + val module = new ivy.Module(moduleSettings) + val report = Deprecated.Inner.ivyUpdate(ivy)(module, s) + val optFile = (for { + config <- report.configurations + module <- config.modules + (artifact, file) <- module.artifacts + // TODO - Hardcode this? + if artifact.name == m.name + } yield file).headOption + optFile getOrElse sys.error("Could not resolve previous artifact: " + m) + } + +} + +// use the SI-7934 workaround to silence a deprecation warning on an sbt API +// we have no choice but to call. on the lack of any suitable alternative, +// see https://gitter.im/sbt/sbt-dev?at=5616e2681b0e279854bd74a4 : +// "it's my intention to eventually come up with a public API" says Eugene Y +object Deprecated { + @deprecated("", "") class Inner { + def ivyUpdate(ivy: IvySbt)(module: ivy.Module, s: TaskStreams) = + IvyActions.update( + module, + new UpdateConfiguration( + retrieve = None, + missingOk = false, + logging = UpdateLogging.DownloadOnly), + s.log) + } + object Inner extends Inner +} diff --git a/project/Osgi.scala b/project/Osgi.scala index 9b00379760..4177251aa4 100644 --- a/project/Osgi.scala +++ b/project/Osgi.scala @@ -28,8 +28,8 @@ object Osgi { "Bundle-Name" -> bundleName.value, "Bundle-SymbolicName" -> bundleSymbolicName.value, "ver" -> v, - "Export-Package" -> ("*;version=${ver}"), - "Import-Package" -> ("scala.*;version=\"${range;[==,=+);${ver}}\",*"), + "Export-Package" -> "*;version=${ver};-split-package:=merge-first", + "Import-Package" -> "scala.*;version=\"${range;[==,=+);${ver}}\",*", "Bundle-Version" -> v, "Bundle-RequiredExecutionEnvironment" -> "JavaSE-1.8", "-eclipse" -> "false" diff --git a/project/Quiet.scala b/project/Quiet.scala index de30ebe6ab..84d01d5544 100644 --- a/project/Quiet.scala +++ b/project/Quiet.scala @@ -28,6 +28,4 @@ object Quiet { case x => x } } - - def silenceIvyUpdateInfoLogging = logLevel in update := Level.Warn } diff --git a/project/ScalaTool.scala b/project/ScalaTool.scala index e9531f229e..5e3f20b1ba 100644 --- a/project/ScalaTool.scala +++ b/project/ScalaTool.scala @@ -27,12 +27,12 @@ case class ScalaTool(mainClass: String, } else classpath.mkString(":").replace('\\', '/').replaceAll(varRegex, """\${$1}""") val variables = Map( - ("@@" -> "@"), // for backwards compatibility - ("@class@" -> mainClass), - ("@properties@" -> (properties map { case (k, v) => s"""-D$k="$v""""} mkString " ")), - ("@javaflags@" -> javaOpts), - ("@toolflags@" -> toolFlags), - ("@classpath@" -> platformClasspath) + "@@" -> "@", // for backwards compatibility + "@class@" -> mainClass, + "@properties@" -> (properties map { case (k, v) => s"""-D$k="$v""""} mkString " "), + "@javaflags@" -> javaOpts, + "@toolflags@" -> toolFlags, + "@classpath@" -> platformClasspath ) val (from, to) = variables.unzip diff --git a/project/ScriptCommands.scala b/project/ScriptCommands.scala index 537990d985..e5ff38617e 100644 --- a/project/ScriptCommands.scala +++ b/project/ScriptCommands.scala @@ -1,19 +1,33 @@ import sbt._ import Keys._ -import complete.DefaultParsers._ +import BuildSettings.autoImport._ /** Custom commands for use by the Jenkins scripts. This keeps the surface area and call syntax small. */ object ScriptCommands { - def all = Seq(setupPublishCore) + def all = Seq(setupPublishCore, setupValidateTest) /** Set up the environment for `validate/publish-core`. The argument is the Artifactory snapshot repository URL. */ def setupPublishCore = Command.single("setupPublishCore") { case (state, url) => Project.extract(state).append(Seq( - VersionUtil.baseVersionSuffix in Global := "SHA-SNAPSHOT", + baseVersionSuffix in Global := "SHA-SNAPSHOT", // Append build.timestamp to Artifactory URL to get consistent build numbers (see https://github.com/sbt/sbt/issues/2088): publishTo in Global := Some("scala-pr" at url.replaceAll("/$", "") + ";build.timestamp=" + System.currentTimeMillis), publishArtifact in (Compile, packageDoc) in ThisBuild := false, - scalacOptions in Compile in ThisBuild += "-optimise" + scalacOptions in Compile in ThisBuild += "-Yopt:l:classpath", + logLevel in ThisBuild := Level.Info, + logLevel in update in ThisBuild := Level.Warn ), state) } + + /** Set up the environment for `validate/test`. The argument is the Artifactory snapshot repository URL. */ + def setupValidateTest = Command.single("setupValidateTest") { case (state, url) => + //TODO When ant is gone, pass starr version as an argument to this command instead of using version.properties + Project.extract(state).append(Seq( + resolvers in Global += "scala-pr" at url, + scalacOptions in Compile in ThisBuild += "-opt:l:classpath", + testOptions in IntegrationTest in LocalProject("test") ++= Seq(Tests.Argument("--show-log"), Tests.Argument("--show-diff")), + logLevel in ThisBuild := Level.Info, + logLevel in update in ThisBuild := Level.Warn + ), state) + } } diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala index 6c8aebf74f..4705bbb6ce 100644 --- a/project/VersionUtil.scala +++ b/project/VersionUtil.scala @@ -1,12 +1,11 @@ import sbt._ import Keys._ import java.util.Properties -import java.io.FileInputStream +import java.io.{File, FileInputStream} import scala.collection.JavaConverters._ +import BuildSettings.autoImport._ object VersionUtil { - lazy val baseVersion = settingKey[String]("The base version number from which all others are derived") - lazy val baseVersionSuffix = settingKey[String]("Identifies the kind of version to build") lazy val copyrightString = settingKey[String]("Copyright string.") lazy val versionProperties = settingKey[Versions]("Version properties.") lazy val generateVersionPropertiesFile = taskKey[File]("Generating version properties file.") @@ -123,4 +122,33 @@ object VersionUtil { /** Get a subproject version number from `versionProps` */ def versionNumber(name: String): String = versionProps(s"$name.version.number") + + /** Build a dependency to a Scala module with the given group and artifact ID */ + def scalaDep(group: String, artifact: String, versionProp: String = null, scope: String = null, compatibility: String = "binary") = { + val vp = if(versionProp eq null) artifact else versionProp + val m = group % (artifact + "_" + versionProps(s"scala.$compatibility.version")) % versionNumber(vp) + val m2 = if(scope eq null) m else m % scope + // exclusion of the scala-library transitive dependency avoids eviction warnings during `update`: + m2.exclude("org.scala-lang", "*") + } + + private def bootstrapOrganization(path: String) = + "org.scala-lang.scala-sha-bootstrap." + path.replace('/', '.') + + /** Build a dependency to a JAR file in the bootstrap repository */ + def bootstrapDep(baseDir: File, path: String, libName: String): ModuleID = { + val sha = IO.read(baseDir / path / s"$libName.jar.desired.sha1").split(' ')(0) + bootstrapOrganization(path) % libName % sha from + s"https://dl.bintray.com/typesafe/scala-sha-bootstrap/org/scala-lang/bootstrap/$sha/$path/$libName.jar" + } + + /** Copy a boostrap dependency JAR that is on the classpath to a file */ + def copyBootstrapJar(cp: Seq[Attributed[File]], baseDir: File, path: String, libName: String): Unit = { + val org = bootstrapOrganization(path) + val resolved = cp.find { a => + val mod = a.get(moduleID.key) + mod.map(_.organization) == Some(org) && mod.map(_.name) == Some(libName) + }.map(_.data).get + IO.copyFile(resolved, baseDir / path / s"$libName.jar") + } } diff --git a/project/plugins.sbt b/project/plugins.sbt index ac60cd3dd2..98ec8f16ed 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,6 @@ +scalacOptions ++= Seq("-unchecked", "-feature", /*"-deprecation",*/ + "-Xlint" /*, "-Xfatal-warnings"*/) + libraryDependencies += "org.apache.commons" % "commons-lang3" % "3.3.2" libraryDependencies += "org.pantsbuild" % "jarjar" % "1.6.3" @@ -15,3 +18,5 @@ buildClasspath := (externalDependencyClasspath in Compile).value.map(_.data).mkS buildInfoKeys := Seq[BuildInfoKey](buildClasspath) buildInfoPackage := "scalabuild" + +libraryDependencies += "com.typesafe" %% "mima-reporter" % "0.1.8" |