summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Zeiger <szeiger@novocode.com>2016-06-14 12:38:58 +0200
committerStefan Zeiger <szeiger@novocode.com>2016-06-14 15:54:01 +0200
commitf2d0f1e85d8b348cd2506a45502e4e59f9ec8e49 (patch)
tree340370a3c4cac8da3a43886d1edffd1bac636bdf
parent91b6944480a3b37f1d62a8a2ed3c332ce02a835a (diff)
downloadscala-f2d0f1e85d8b348cd2506a45502e4e59f9ec8e49.tar.gz
scala-f2d0f1e85d8b348cd2506a45502e4e59f9ec8e49.tar.bz2
scala-f2d0f1e85d8b348cd2506a45502e4e59f9ec8e49.zip
Use sbt for PR validation
- Support directories in `-doc-external-doc`: It is documented as accepting a “classpath_entry_path” for the keys but this only worked for JARs and not for individual class files. When checking for external-doc mappings for a Symbol, we now find the root directory relative to a class file instead of using the full class file path. The corresponding tests for SI-191 and SI8557 are also fixed to support individual class files instead of JARs in partest. This is required for the sbt build which runs partest on “quick” instead of “pack”. - Fix version and repository handling for bootstrapping. The bootstrap `scalaInstance` can now be resolved from any repository added to the project (not just the bootstrap repositories) by using a different workaround for https://github.com/sbt/sbt/issues/1872. - Workaround for https://github.com/sbt/sbt/issues/2640 (putting the wrong `scalaInstance` on partest’s classpath). The required `ScalaInstance` constructor is deprecated, so we have to disable deprecation warnings and fatal warnings until there is a better fix. - Add MiMa to the sbt build (port of the old `test.bc` ant task). The sbt-mima plugin doesn’t have all the features we need, so we do it manually in a similar way to what the plugin does. Checks are done in both directions for the `library` and `compiler` projects. The base version has to be set in `build.sbt`. When set to `None`, MiMa checks are skipped. MiMa checks are run sequentially to avoid spurious errors (see https://github.com/typesafehub/migration-manager/issues/115). - Port the OSGi tests to the sbt build. The set of JARs that gets copied into build/osgi as bundles is a bit different from the ant build. We omit the source JARs but add additional modules that are part of the Scala distribution, which seems more correct. - Get rid up `pull-binary-libs.sh` for the sbt build. Add artifacts are resolved from the special bootstrap repository through Ivy. The special `code.jar` and `instrumented.jar` artifacts are copied to the location where partest expects them (because these paths are hardcoded in partest). Other extra JARs for partest in `test/files/lib` are referenced directly from the Ivy cache. - Move common settings that should be available with unqualified names in local `.sbt` files and on the command line into an auto-plugin. - Add an `antStyle` setting to sbt to allow users to easily enable ant-style incremental compilation instead of sbt’s standard name hashing with `set antStyle := true`. - Disable verbose `info`-level logging during sbt startup for both, `validate/test` and `validate/publish-core` jobs. Update logging is no longer disabled when running locally (where it is useful and doesn’t generate excessive output). - Pass optimization flags for scalac down to partest, using the new partest version 1.0.15\6. - Call the new sbt-based PR validation from `scripts/jobs/validate/test`. - Disable the tests `run/t7843-jsr223-service` and `run/t7933` from https://github.com/scala/scala/pull/4959 for now. We need to set up a new test project (either partest or junit) that can run them on a packaged version of Scala, or possibly move them into a separate project that would naturally run from a packaged Scala as part of the community build.
-rw-r--r--build.sbt187
-rw-r--r--project/BuildSettings.scala11
-rw-r--r--project/MiMa.scala95
-rw-r--r--project/Osgi.scala4
-rw-r--r--project/Quiet.scala2
-rw-r--r--project/ScalaTool.scala12
-rw-r--r--project/ScriptCommands.scala21
-rw-r--r--project/VersionUtil.scala34
-rw-r--r--project/plugins.sbt5
-rwxr-xr-xscripts/jobs/validate/publish-core4
-rwxr-xr-xscripts/jobs/validate/test35
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala18
-rw-r--r--test/disabled/run/t7843-jsr223-service.check (renamed from test/files/run/t7843-jsr223-service.check)0
-rw-r--r--test/disabled/run/t7843-jsr223-service.scala (renamed from test/files/run/t7843-jsr223-service.scala)0
-rw-r--r--test/disabled/run/t7933.check (renamed from test/files/run/t7933.check)0
-rw-r--r--test/disabled/run/t7933.scala (renamed from test/files/run/t7933.scala)0
-rw-r--r--test/osgi/src/logback.xml10
-rw-r--r--test/scaladoc/.gitignore2
-rw-r--r--test/scaladoc/run/SI-191.scala12
-rw-r--r--test/scaladoc/run/t8557.scala20
-rw-r--r--versions.properties2
21 files changed, 382 insertions, 92 deletions
diff --git a/build.sbt b/build.sbt
index 13bbd8be03..3df0d43c00 100644
--- a/build.sbt
+++ b/build.sbt
@@ -55,25 +55,23 @@
import VersionUtil._
-val bootstrapScalaVersion = versionProps("starr.version")
-
-def withoutScalaLang(moduleId: ModuleID): ModuleID = moduleId exclude("org.scala-lang", "*")
-
-// exclusion of the scala-library transitive dependency avoids eviction warnings during `update`.
-val actorsMigrationDep = withoutScalaLang("org.scala-lang" %% "scala-actors-migration" % versionNumber("actors-migration"))
-val akkaActorDep = withoutScalaLang("com.typesafe.akka" %% "akka-actor" % versionNumber("akka-actor"))
-val scalaContinuationsLibraryDep = withoutScalaLang("org.scala-lang.plugins" %% "scala-continuations-library" % versionNumber("scala-continuations-library"))
-val scalaContinuationsPluginDep = withoutScalaLang("org.scala-lang.plugins" % ("scala-continuations-plugin_" + versionProps("scala.full.version")) % versionNumber("scala-continuations-plugin"))
-val scalaParserCombinatorsDep = withoutScalaLang("org.scala-lang.modules" %% "scala-parser-combinators" % versionNumber("scala-parser-combinators"))
-val scalaSwingDep = withoutScalaLang("org.scala-lang.modules" %% "scala-swing" % versionNumber("scala-swing"))
-val scalaXmlDep = withoutScalaLang("org.scala-lang.modules" %% "scala-xml" % versionNumber("scala-xml"))
-val partestDep = withoutScalaLang("org.scala-lang.modules" %% "scala-partest" % versionNumber("partest"))
-val junitDep = "junit" % "junit" % "4.11"
-val junitInterfaceDep = "com.novocode" % "junit-interface" % "0.11" % "test"
-val asmDep = "org.scala-lang.modules" % "scala-asm" % versionProps("scala-asm.version")
-val jlineDep = "jline" % "jline" % versionProps("jline.version")
-val antDep = "org.apache.ant" % "ant" % "1.9.4"
-val scalacheckDep = withoutScalaLang("org.scalacheck" %% "scalacheck" % versionNumber("scalacheck") % "it")
+// Scala dependencies:
+val scalaContinuationsPluginDep = scalaDep("org.scala-lang.plugins", "scala-continuations-plugin", compatibility = "full")
+val scalaContinuationsLibraryDep = scalaDep("org.scala-lang.plugins", "scala-continuations-library")
+val scalaParserCombinatorsDep = scalaDep("org.scala-lang.modules", "scala-parser-combinators")
+val scalaSwingDep = scalaDep("org.scala-lang.modules", "scala-swing")
+val scalaXmlDep = scalaDep("org.scala-lang.modules", "scala-xml")
+val partestDep = scalaDep("org.scala-lang.modules", "scala-partest", versionProp = "partest")
+val akkaActorDep = scalaDep("com.typesafe.akka", "akka-actor")
+val actorsMigrationDep = scalaDep("org.scala-lang", "scala-actors-migration", versionProp = "actors-migration")
+val scalacheckDep = scalaDep("org.scalacheck", "scalacheck", scope = "it")
+
+// Non-Scala dependencies:
+val junitDep = "junit" % "junit" % "4.11"
+val junitInterfaceDep = "com.novocode" % "junit-interface" % "0.11" % "test"
+val asmDep = "org.scala-lang.modules" % "scala-asm" % versionProps("scala-asm.version")
+val jlineDep = "jline" % "jline" % versionProps("jline.version")
+val antDep = "org.apache.ant" % "ant" % "1.9.4"
/** Publish to ./dists/maven-sbt, similar to the ANT build which publishes to ./dists/maven. This
* can be used to compare the output of the sbt and ANT builds during the transition period. Any
@@ -117,20 +115,27 @@ lazy val publishSettings : Seq[Setting[_]] = Seq(
globalVersionSettings
baseVersion in Global := "2.11.9"
baseVersionSuffix in Global := "SNAPSHOT"
+mimaReferenceVersion in Global := Some("2.11.0")
lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings ++ Seq[Setting[_]](
organization := "org.scala-lang",
- scalaVersion := bootstrapScalaVersion,
// we don't cross build Scala itself
crossPaths := false,
// do not add Scala library jar as a dependency automatically
autoScalaLibrary := false,
- // we also do not add scala instance automatically because it introduces
- // a circular instance, see: https://github.com/sbt/sbt/issues/1872
+ // Avoid circular dependencies for scalaInstance (see https://github.com/sbt/sbt/issues/1872)
managedScalaInstance := false,
- // this is a way to workaround issue described in https://github.com/sbt/sbt/issues/1872
- // check it out for more details
- scalaInstance := ScalaInstance(scalaVersion.value, appConfiguration.value.provider.scalaProvider.launcher getScala scalaVersion.value),
+ scalaInstance := {
+ val s = (scalaInstance in bootstrap).value
+ // sbt claims that s.isManagedVersion is false even though s was resolved by Ivy
+ // We create a managed copy to prevent sbt from putting it on the classpath where we don't want it
+ if(s.isManagedVersion) s else {
+ val s2 = new ScalaInstance(s.version, s.loader, s.libraryJar, s.compilerJar, s.extraJars, Some(s.actualVersion))
+ assert(s2.isManagedVersion)
+ s2
+ }
+ },
+ scalaVersion := (scalaVersion in bootstrap).value,
// we always assume that Java classes are standalone and do not have any dependency
// on Scala classes
compileOrder := CompileOrder.JavaThenScala,
@@ -151,7 +156,7 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
target := (baseDirectory in ThisBuild).value / "target" / thisProject.value.id,
classDirectory in Compile := buildDirectory.value / "quick/classes" / thisProject.value.id,
target in Compile in doc := buildDirectory.value / "scaladoc" / thisProject.value.id,
- // given that classDirectory and doc target are overriden to be _outside_ of target directory, we have
+ // given that classDirectory and doc target are overridden to be _outside_ of target directory, we have
// to make sure they are being cleaned properly
cleanFiles += (classDirectory in Compile).value,
cleanFiles += (target in Compile in doc).value,
@@ -166,9 +171,10 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
"-sourcepath", (baseDirectory in ThisBuild).value.toString,
"-doc-source-url", s"https://github.com/scala/scala/tree/${versionProperties.value.githubTree}€{FILE_PATH}.scala#L1"
),
+ incOptions <<= (incOptions in LocalProject("root")),
homepage := Some(url("http://www.scala-lang.org")),
startYear := Some(2002),
- licenses += ("BSD 3-Clause", url("http://www.scala-lang.org/license.html")),
+ licenses += (("BSD 3-Clause", url("http://www.scala-lang.org/license.html"))),
apiURL := Some(url("http://www.scala-lang.org/api/" + versionProperties.value.mavenVersion + "/")),
pomIncludeRepository := { _ => false },
pomExtra := {
@@ -213,8 +219,7 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
// Don't log process output (e.g. of forked `compiler/runMain ...Main`), just pass it
// directly to stdout
outputStrategy in run := Some(StdoutOutput),
- Quiet.silenceScalaBinaryVersionWarning,
- Quiet.silenceIvyUpdateInfoLogging
+ Quiet.silenceScalaBinaryVersionWarning
)
/** Extra post-processing for the published POM files. These are needed to create POMs that
@@ -250,7 +255,7 @@ def removePomDependencies(deps: (String, String)*): Seq[Setting[_]] = Seq(
val n2 = pomPostProcess.value.apply(n)
import scala.xml._
import scala.xml.transform._
- (new RuleTransformer(new RewriteRule {
+ new RuleTransformer(new RewriteRule {
override def transform(node: Node) = node match {
case e: Elem if e.label == "dependency" &&
deps.exists { case (g, a) =>
@@ -259,13 +264,13 @@ def removePomDependencies(deps: (String, String)*): Seq[Setting[_]] = Seq(
} => Seq.empty
case n => Seq(n)
}
- })).transform(Seq(n2)).head
+ }).transform(Seq(n2)).head
},
deliverLocal := {
import scala.xml._
import scala.xml.transform._
val f = deliverLocal.value
- val e = (new RuleTransformer(new RewriteRule {
+ val e = new RuleTransformer(new RewriteRule {
override def transform(node: Node) = node match {
case e: Elem if e.label == "dependency" && {
val org = e.attribute("org").getOrElse("").toString
@@ -276,7 +281,7 @@ def removePomDependencies(deps: (String, String)*): Seq[Setting[_]] = Seq(
} => Seq.empty
case n => Seq(n)
}
- })).transform(Seq(XML.loadFile(f))).head
+ }).transform(Seq(XML.loadFile(f))).head
XML.save(f.getAbsolutePath, e, xmlDecl = true)
f
}
@@ -309,7 +314,7 @@ lazy val setJarLocation: Setting[_] =
lazy val scalaSubprojectSettings: Seq[Setting[_]] = commonSettings :+ setJarLocation
def filterDocSources(ff: FileFilter): Seq[Setting[_]] = Seq(
- sources in (Compile, doc) ~= (_.filter(ff.accept _)),
+ sources in (Compile, doc) ~= (_.filter(ff.accept)),
// Excluded sources may still be referenced by the included sources, so we add the compiler
// output to the scaladoc classpath to resolve them. For the `library` project this is
// always required because otherwise the compiler cannot even initialize Definitions without
@@ -326,6 +331,11 @@ def regexFileFilter(s: String): FileFilter = new FileFilter {
def accept(f: File) = pat.matcher(f.getAbsolutePath.replace('\\', '/')).matches()
}
+// This project provides the STARR scalaInstance for bootstrapping
+lazy val bootstrap = (project in file("target/bootstrap")).settings(
+ scalaVersion := versionProps("starr.version")
+)
+
lazy val library = configureAsSubproject(project)
.settings(generatePropertiesFileSettings: _*)
.settings(Osgi.settings: _*)
@@ -363,6 +373,7 @@ lazy val library = configureAsSubproject(project)
.settings(filterDocSources("*.scala" -- (regexFileFilter(".*/runtime/.*\\$\\.scala") ||
regexFileFilter(".*/runtime/ScalaRunTime\\.scala") ||
regexFileFilter(".*/runtime/StringAdd\\.scala"))): _*)
+ .settings(MiMa.settings: _*)
.dependsOn(forkjoin)
lazy val reflect = configureAsSubproject(project)
@@ -385,6 +396,7 @@ lazy val reflect = configureAsSubproject(project)
"/project/packaging" -> <packaging>jar</packaging>
)
)
+ .settings(MiMa.settings: _*)
.dependsOn(library)
lazy val compiler = configureAsSubproject(project)
@@ -581,6 +593,56 @@ lazy val junit = project.in(file("test") / "junit")
unmanagedSourceDirectories in Test := List(baseDirectory.value)
)
+lazy val osgiTestFelix = osgiTestProject(
+ project.in(file(".") / "target" / "osgiTestFelix"),
+ "org.apache.felix" % "org.apache.felix.framework" % "4.4.0")
+
+lazy val osgiTestEclipse = osgiTestProject(
+ project.in(file(".") / "target" / "osgiTestEclipse"),
+ "org.eclipse.osgi" % "org.eclipse.osgi" % "3.7.1")
+
+def osgiTestProject(p: Project, framework: ModuleID) = p
+ .dependsOn(library, reflect, compiler, actors, forkjoin)
+ .settings(clearSourceAndResourceDirectories: _*)
+ .settings(commonSettings: _*)
+ .settings(disableDocs: _*)
+ .settings(disablePublishing: _*)
+ .settings(
+ fork in Test := true,
+ parallelExecution in Test := false,
+ libraryDependencies ++= {
+ val paxExamVersion = "3.5.0" // Last version which supports Java 6
+ Seq(
+ junitDep,
+ junitInterfaceDep,
+ "org.ops4j.pax.exam" % "pax-exam-container-native" % paxExamVersion
+ exclude("org.osgi", "org.osgi.core"), // Avoid dragging in a dependency which requires Java >6
+ "org.osgi" % "org.osgi.core" % "4.2.0" % "provided", // The framework (Felix / Eclipse) provides the classes
+ "org.ops4j.pax.exam" % "pax-exam-junit4" % paxExamVersion,
+ "org.ops4j.pax.exam" % "pax-exam-link-assembly" % paxExamVersion,
+ "org.ops4j.pax.url" % "pax-url-aether" % "2.2.0",
+ "org.ops4j.pax.swissbox" % "pax-swissbox-tracker" % "1.8.0",
+ "ch.qos.logback" % "logback-core" % "1.1.2",
+ "ch.qos.logback" % "logback-classic" % "1.1.2",
+ framework % "test"
+ )
+ },
+ Keys.test in Test <<= Keys.test in Test dependsOn (packageBin in Compile),
+ testOptions += Tests.Argument(TestFrameworks.JUnit, "-a", "-v", "-q"),
+ unmanagedSourceDirectories in Test := List((baseDirectory in ThisBuild).value / "test" / "osgi" / "src"),
+ unmanagedResourceDirectories in Compile := (unmanagedSourceDirectories in Test).value,
+ includeFilter in unmanagedResources in Compile := "*.xml",
+ packageBin in Compile := { // Put the bundle JARs required for the tests into build/osgi
+ val targetDir = (buildDirectory in ThisBuild).value / "osgi"
+ val mappings = ((mkPack in dist).value / "lib").listFiles.collect {
+ case f if f.getName.startsWith("scala-") && f.getName.endsWith(".jar") => (f, targetDir / f.getName)
+ }
+ IO.copy(mappings, overwrite = true)
+ targetDir
+ },
+ cleanFiles += (buildDirectory in ThisBuild).value / "osgi"
+ )
+
lazy val partestJavaAgent = Project("partest-javaagent", file(".") / "src" / "partest-javaagent")
.settings(commonSettings: _*)
.settings(generatePropertiesFileSettings: _*)
@@ -610,8 +672,15 @@ lazy val test = project
.settings(Defaults.itSettings: _*)
.settings(
libraryDependencies ++= Seq(asmDep, partestDep, scalaXmlDep, scalacheckDep),
- unmanagedBase in IntegrationTest := baseDirectory.value / "files" / "lib",
- unmanagedJars in IntegrationTest <+= (unmanagedBase) (j => Attributed.blank(j)) map(identity),
+ libraryDependencies ++= {
+ // Resolve the JARs for all test/files/lib/*.jar.desired.sha1 files through Ivy
+ val baseDir = (baseDirectory in ThisBuild).value
+ (baseDir / "test/files/lib").list.toSeq.filter(_.endsWith(".jar.desired.sha1"))
+ .map(f => bootstrapDep(baseDir, "test/files/lib", f.dropRight(17)))
+ },
+ // Two hardcoded depenencies in partest, resolved in the otherwise unused scope "test":
+ libraryDependencies += bootstrapDep((baseDirectory in ThisBuild).value, "test/files/codelib", "code") % "test",
+ libraryDependencies += bootstrapDep((baseDirectory in ThisBuild).value, "test/files/speclib", "instrumented") % "test",
// no main sources
sources in Compile := Seq.empty,
// test sources are compiled in partest run, not here
@@ -619,18 +688,24 @@ lazy val test = project
fork in IntegrationTest := true,
javaOptions in IntegrationTest += "-Xmx1G",
testFrameworks += new TestFramework("scala.tools.partest.sbt.Framework"),
- testOptions in IntegrationTest += Tests.Setup( () => root.base.getAbsolutePath + "/pull-binary-libs.sh" ! ),
testOptions in IntegrationTest += Tests.Argument("-Dpartest.java_opts=-Xmx1024M -Xms64M -XX:MaxPermSize=128M"),
- definedTests in IntegrationTest += (
- new sbt.TestDefinition(
- "partest",
- // marker fingerprint since there are no test classes
- // to be discovered by sbt:
- new sbt.testing.AnnotatedFingerprint {
- def isModule = true
- def annotationName = "partest"
- }, true, Array())
- )
+ testOptions in IntegrationTest += Tests.Argument("-Dpartest.scalac_opts=" + (scalacOptions in Compile).value.mkString(" ")),
+ testOptions in IntegrationTest += Tests.Setup { () =>
+ val cp = (dependencyClasspath in Test).value
+ val baseDir = (baseDirectory in ThisBuild).value
+ // Copy code.jar and instrumented.jar to the location where partest expects them
+ copyBootstrapJar(cp, baseDir, "test/files/codelib", "code")
+ copyBootstrapJar(cp, baseDir, "test/files/speclib", "instrumented")
+ },
+ definedTests in IntegrationTest += new sbt.TestDefinition(
+ "partest",
+ // marker fingerprint since there are no test classes
+ // to be discovered by sbt:
+ new sbt.testing.AnnotatedFingerprint {
+ def isModule = true
+ def annotationName = "partest"
+ }, true, Array()
+ )
)
lazy val manual = configureAsSubproject(project)
@@ -704,7 +779,7 @@ lazy val scalaDist = Project("scala-dist", file(".") / "target" / "scala-dist-di
)
.dependsOn(libraryAll, compiler, scalap)
-lazy val root = (project in file("."))
+lazy val root: Project = (project in file("."))
.settings(disableDocs: _*)
.settings(disablePublishing: _*)
.settings(generateBuildCharacterFileSettings: _*)
@@ -712,8 +787,9 @@ lazy val root = (project in file("."))
publish := {},
publishLocal := {},
commands ++= ScriptCommands.all,
- Quiet.silenceIvyUpdateInfoLogging
-)
+ antStyle := false,
+ incOptions := incOptions.value.withNameHashing(!antStyle.value).withAntStyle(antStyle.value)
+ )
.aggregate(library, forkjoin, reflect, compiler, interactive, repl, replJline, replJlineEmbedded,
scaladoc, scalap, actors, partestExtras, junit, libraryAll, scalaDist).settings(
sources in Compile := Seq.empty,
@@ -737,8 +813,9 @@ lazy val dist = (project in file("dist"))
val props = new java.util.Properties()
props.setProperty("partest.classpath", cp.map(_.data.getAbsolutePath).mkString(sys.props("path.separator")))
IO.write(props, null, propsFile)
+ (buildDirectory in ThisBuild).value / "quick"
} dependsOn ((distDependencies.map(products in Runtime in _) :+ mkBin): _*),
- mkPack <<= Def.task {} dependsOn (packagedArtifact in (Compile, packageBin), mkBin),
+ mkPack <<= Def.task { (buildDirectory in ThisBuild).value / "pack" } dependsOn (packagedArtifact in (Compile, packageBin), mkBin),
target := (baseDirectory in ThisBuild).value / "target" / thisProject.value.id,
packageBin in Compile := {
val extraDeps = Set(scalaContinuationsLibraryDep, scalaContinuationsPluginDep, scalaSwingDep, scalaParserCombinatorsDep, scalaXmlDep)
@@ -749,7 +826,7 @@ lazy val dist = (project in file("dist"))
case (Some(m), f) if extraModules contains uniqueModule(m) => f
}
val jlineJAR = (dependencyClasspath in Compile).value.find(_.get(moduleID.key) == Some(jlineDep)).get.data
- val mappings = extraJars.map(f => (f, targetDir / f.getName)) :+ (jlineJAR, targetDir / "jline.jar")
+ val mappings = extraJars.map(f => (f, targetDir / f.getName)) :+ ((jlineJAR, targetDir / "jline.jar"))
IO.copy(mappings, overwrite = true)
targetDir
},
@@ -802,8 +879,8 @@ def configureAsForkOfJavaProject(project: Project): Project = {
lazy val buildDirectory = settingKey[File]("The directory where all build products go. By default ./build")
lazy val mkBin = taskKey[Seq[File]]("Generate shell script (bash or Windows batch).")
-lazy val mkQuick = taskKey[Unit]("Generate a full build, including scripts, in build/quick")
-lazy val mkPack = taskKey[Unit]("Generate a full build, including scripts, in build/pack")
+lazy val mkQuick = taskKey[File]("Generate a full build, including scripts, in build/quick")
+lazy val mkPack = taskKey[File]("Generate a full build, including scripts, in build/pack")
// Defining these settings is somewhat redundant as we also redefine settings that depend on them.
// However, IntelliJ's project import works better when these are set correctly.
@@ -929,7 +1006,7 @@ intellij := {
def moduleDep(name: String, jars: Seq[File]) = {
val entries = jars.map(f => s""" <root url="jar://${f.toURI.getRawPath}!/" />""").mkString("\n")
- s"""| <library name="${name}-deps">
+ s"""| <library name="$name-deps">
| <CLASSES>
|$entries
| </CLASSES>
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 d780be2f78..b557df1688 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}",
+ "Import-Package" -> "scala.*;version=\"${range;[==,=+);${ver}}\",*",
"Bundle-Version" -> v,
"Bundle-RequiredExecutionEnvironment" -> "JavaSE-1.6, JavaSE-1.7",
"-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..efeac95e6d 100644
--- a/project/ScriptCommands.scala
+++ b/project/ScriptCommands.scala
@@ -1,19 +1,32 @@
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 += "-optimise",
+ 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 += "-optimise",
+ 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 46203565b4..4c0a6e7b8a 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"
diff --git a/scripts/jobs/validate/publish-core b/scripts/jobs/validate/publish-core
index bb0056722d..b0bfd48083 100755
--- a/scripts/jobs/validate/publish-core
+++ b/scripts/jobs/validate/publish-core
@@ -16,7 +16,7 @@ case $prDryRun in
;;
*)
echo ">>> Getting Scala version number."
- $SBT_CMD "setupPublishCore $prRepoUrl" generateBuildCharacterPropertiesFile
+ $SBT_CMD --warn "setupPublishCore $prRepoUrl" generateBuildCharacterPropertiesFile
parseScalaProperties buildcharacter.properties # produce maven_version_number
echo ">>> Checking availability of Scala ${maven_version_number} in $prRepoUrl."
@@ -27,7 +27,7 @@ case $prDryRun in
if $libraryAvailable && $reflectAvailable && $compilerAvailable; then
echo "Scala core already built!"
else
- $SBT_CMD "setupPublishCore $prRepoUrl" $antBuildArgs publish
+ $SBT_CMD --warn "setupPublishCore $prRepoUrl" publish
fi
mv buildcharacter.properties jenkins.properties # parsed by the jenkins job
diff --git a/scripts/jobs/validate/test b/scripts/jobs/validate/test
index bedef2e458..3cd8af5608 100755
--- a/scripts/jobs/validate/test
+++ b/scripts/jobs/validate/test
@@ -1,17 +1,36 @@
-#!/bin/bash -e
+#!/bin/bash -e -v -x
+
+baseDir=${WORKSPACE-`pwd`}
+scriptsDir="$baseDir/scripts"
+. $scriptsDir/common
case $prDryRun in
+
yep)
echo "DRY RUN"
;;
+
*)
- ./pull-binary-libs.sh
# build quick using STARR built upstream, as specified by scalaVersion
- # (in that sense it's locker, since it was built with starr by that upstream job)
- ant -Dstarr.version=$scalaVersion \
- -Dscalac.args.optimise=-optimise \
- -Dlocker.skip=1 -Dextra.repo.url=$prRepoUrl \
- $testExtraArgs ${testTarget-test.core docs.done}
+ # (in that sense it's locker, since it was built with starr by that upstream job);
+ # and run JUnit tests, partest, OSGi tests, MiMa and scaladoc
+ $SBT_CMD \
+ -Dstarr.version=$scalaVersion \
+ --warn \
+ "setupValidateTest $prRepoUrl" \
+ $testExtraArgs \
+ "test" \
+ "partest run pos neg jvm" \
+ "partest res scalap specialized scalacheck" \
+ "partest instrumented presentation" \
+ "partest --srcpath scaladoc" \
+ osgiTestFelix/test \
+ osgiTestEclipse/test \
+ library/mima \
+ reflect/mima \
+ doc
+
;;
-esac \ No newline at end of file
+
+esac
diff --git a/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala b/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala
index 64eb1adbea..a649c175d0 100644
--- a/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala
@@ -44,8 +44,22 @@ trait MemberLookup extends base.MemberLookupBase {
/* Get package object which has associatedFile ne null */
sym.info.member(newTermName("package"))
else sym
- Option(sym1.associatedFile) flatMap (_.underlyingSource) flatMap { src =>
- val path = src.canonicalPath
+ def classpathEntryFor(s: Symbol): Option[String] = {
+ Option(s.associatedFile).flatMap(_.underlyingSource).map { src =>
+ val path = src.canonicalPath
+ if(path.endsWith(".class")) { // Individual class file -> Classpath entry is root dir
+ var nesting = s.ownerChain.count(_.hasPackageFlag)
+ if(nesting > 0) {
+ val p = 0.until(nesting).foldLeft(src) {
+ case (null, _) => null
+ case (f, _) => f.container
+ }
+ if(p eq null) path else p.canonicalPath
+ } else path
+ } else path // JAR file (and fallback option)
+ }
+ }
+ classpathEntryFor(sym1) flatMap { path =>
settings.extUrlMapping get path map { url =>
LinkToExternal(name, url + "#" + name)
}
diff --git a/test/files/run/t7843-jsr223-service.check b/test/disabled/run/t7843-jsr223-service.check
index a668df3567..a668df3567 100644
--- a/test/files/run/t7843-jsr223-service.check
+++ b/test/disabled/run/t7843-jsr223-service.check
diff --git a/test/files/run/t7843-jsr223-service.scala b/test/disabled/run/t7843-jsr223-service.scala
index 3c853878ba..3c853878ba 100644
--- a/test/files/run/t7843-jsr223-service.scala
+++ b/test/disabled/run/t7843-jsr223-service.scala
diff --git a/test/files/run/t7933.check b/test/disabled/run/t7933.check
index 317e9677c3..317e9677c3 100644
--- a/test/files/run/t7933.check
+++ b/test/disabled/run/t7933.check
diff --git a/test/files/run/t7933.scala b/test/disabled/run/t7933.scala
index 58e39dd384..58e39dd384 100644
--- a/test/files/run/t7933.scala
+++ b/test/disabled/run/t7933.scala
diff --git a/test/osgi/src/logback.xml b/test/osgi/src/logback.xml
new file mode 100644
index 0000000000..692ccbfdd9
--- /dev/null
+++ b/test/osgi/src/logback.xml
@@ -0,0 +1,10 @@
+<configuration>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>*** \(%logger{30}\)%green(%X{debugId}) %msg%n</pattern>
+ </encoder>
+ </appender>
+ <root level="${log.root:-warn}">
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration>
diff --git a/test/scaladoc/.gitignore b/test/scaladoc/.gitignore
new file mode 100644
index 0000000000..161be5b55f
--- /dev/null
+++ b/test/scaladoc/.gitignore
@@ -0,0 +1,2 @@
+*.log
+*.obj/
diff --git a/test/scaladoc/run/SI-191.scala b/test/scaladoc/run/SI-191.scala
index 29b1e7dd29..f3d269ceb0 100644
--- a/test/scaladoc/run/SI-191.scala
+++ b/test/scaladoc/run/SI-191.scala
@@ -33,10 +33,14 @@ object Test extends ScaladocModelTest {
def scalaURL = "http://bog.us"
override def scaladocSettings = {
- val scalaLibUri = getClass.getClassLoader.getResource("scala/Function1.class").getPath.split("!")(0)
- val scalaLibPath = new URI(scalaLibUri).getPath
- val externalArg = s"$scalaLibPath#$scalaURL"
- "-no-link-warnings -doc-external-doc " + externalArg
+ val samplePath = getClass.getClassLoader.getResource("scala/Function1.class").getPath
+ val scalaLibPath = if(samplePath.contains("!")) { // in scala-library.jar
+ val scalaLibUri = samplePath.split("!")(0)
+ new URI(scalaLibUri).getPath
+ } else { // individual class files on disk
+ samplePath.replace('\\', '/').dropRight("scala/Function1.class".length)
+ }
+ s"-no-link-warnings -doc-external-doc $scalaLibPath#$scalaURL"
}
def testModel(rootPackage: Package) {
diff --git a/test/scaladoc/run/t8557.scala b/test/scaladoc/run/t8557.scala
index 451f004d7d..7876896bb7 100644
--- a/test/scaladoc/run/t8557.scala
+++ b/test/scaladoc/run/t8557.scala
@@ -1,3 +1,5 @@
+import java.net.URI
+
import scala.tools.nsc.doc.base._
import scala.tools.nsc.doc.model._
import scala.tools.partest.ScaladocModelTest
@@ -15,10 +17,22 @@ object Test extends ScaladocModelTest {
class A
"""
+ def scalaURL = "http://www.scala-lang.org/api/current/"
+
// a non-canonical path to scala-library.jar should still work
- // this is a bit fragile (depends on the current directory being the root of the repo ;
- // ant & partest seem to do that properly)
- def scaladocSettings = "-doc-external-doc build/pack/bin/../lib/scala-library.jar#http://www.scala-lang.org/api/current/"
+ override def scaladocSettings = {
+ val samplePath = getClass.getClassLoader.getResource("scala/Function1.class").getPath.replace('\\', '/')
+ val scalaLibPath = if(samplePath.contains("!")) { // in scala-library.jar
+ val scalaLibUri = samplePath.split("!")(0)
+ val p = new URI(scalaLibUri).getPath
+ // this is a bit fragile (depends on the scala library being in build/pack as produced by ant)
+ p.replace("/pack/lib/scala-library.jar", "/pack/bin/../lib/scala-library.jar")
+ } else { // individual class files on disk
+ val p = samplePath.dropRight("scala/Function1.class".length + 1)
+ p + "/.." + p.takeRight(p.length - p.lastIndexOf('/'))
+ }
+ s"-doc-external-doc $scalaLibPath#$scalaURL"
+ }
def testModel(rootPackage: Package) = {
// get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s))
diff --git a/versions.properties b/versions.properties
index afea93f666..9cfd359800 100644
--- a/versions.properties
+++ b/versions.properties
@@ -36,7 +36,7 @@ jline.version=2.12.1
scala-asm.version=5.0.4-scala-3
# external modules, used internally (not shipped)
-partest.version.number=1.0.13
+partest.version.number=1.0.16
scalacheck.version.number=1.11.6
# TODO: modularize the compiler