Skip to content

Commit 7248894

Browse files
committed
Improve version handling and scaladoc generation in sbt build
- Move version-related code into a separate VersionUtil object - Fix the canonical version. The sbt build previously took the full version including the suffix (plus timestamp and hash) whereas the ant build uses the version without the suffix - Include the version number in the generated scaladocs - Add project descriptions and include them in the scaladocs (like the ant build does) - Add other missing scaladoc options to the sbt build - Copy resources in all subprojects when building dist/mkQuick and fix `includeFilter` settings to include all required files
1 parent 3cddb7f commit 7248894

File tree

2 files changed

+167
-91
lines changed

2 files changed

+167
-91
lines changed

build.sbt

Lines changed: 64 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
* https://groups.google.com/d/topic/scala-internals/gp5JsM1E0Fo/discussion
5353
*/
5454

55+
import VersionUtil.{versionProps, versionNumber, generatePropertiesFileSettings, versionProperties, versionPropertiesSettings}
56+
5557
val bootstrapScalaVersion = versionProps("starr.version")
5658

5759
def withoutScalaLang(moduleId: ModuleID): ModuleID = moduleId exclude("org.scala-lang", "*")
@@ -71,8 +73,9 @@ val jlineDep = "jline" % "jline" % versionProps("jline.version")
7173
val antDep = "org.apache.ant" % "ant" % "1.9.4"
7274
val scalacheckDep = withoutScalaLang("org.scalacheck" %% "scalacheck" % versionNumber("scalacheck") % "it")
7375

74-
lazy val commonSettings = clearSourceAndResourceDirectories ++ Seq[Setting[_]](
76+
lazy val commonSettings = clearSourceAndResourceDirectories ++ versionPropertiesSettings ++ Seq[Setting[_]](
7577
organization := "org.scala-lang",
78+
// The ANT build uses the file "build.number" and the property "build.release" to compute the version
7679
version := "2.11.8-SNAPSHOT",
7780
scalaVersion := bootstrapScalaVersion,
7881
// we don't cross build Scala itself
@@ -95,6 +98,7 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ Seq[Setting[_]](
9598
unmanagedJars in Compile := Seq.empty,
9699
sourceDirectory in Compile := baseDirectory.value,
97100
unmanagedSourceDirectories in Compile := List(baseDirectory.value),
101+
unmanagedResourceDirectories in Compile += (baseDirectory in ThisBuild).value / "src" / thisProject.value.id,
98102
scalaSource in Compile := (sourceDirectory in Compile).value,
99103
javaSource in Compile := (sourceDirectory in Compile).value,
100104
// resources are stored along source files in our current layout
@@ -108,7 +112,17 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ Seq[Setting[_]](
108112
// to make sure they are being cleaned properly
109113
cleanFiles += (classDirectory in Compile).value,
110114
cleanFiles += (target in Compile in doc).value,
111-
fork in run := true
115+
fork in run := true,
116+
scalacOptions in Compile in doc ++= Seq(
117+
"-doc-footer", "epfl",
118+
"-diagrams",
119+
"-implicits",
120+
"-groups",
121+
"-doc-version", versionProperties.value.canonicalVersion,
122+
"-doc-title", description.value,
123+
"-sourcepath", (baseDirectory in ThisBuild).value.toString,
124+
"-doc-source-url", s"https://github.com/scala/scala/tree/${versionProperties.value.githubTree}€{FILE_PATH}.scala#L1"
125+
)
112126
)
113127

114128
// disable various tasks that are not needed for projects that are used
@@ -134,13 +148,7 @@ lazy val setJarLocation: Setting[_] =
134148
val resolvedArtifactName = s"${resolvedArtifact.name}.${resolvedArtifact.extension}"
135149
buildDirectory.value / "pack/lib" / resolvedArtifactName
136150
}
137-
lazy val scalaSubprojectSettings: Seq[Setting[_]] = commonSettings :+ setJarLocation
138-
139-
lazy val generatePropertiesFileSettings = Seq[Setting[_]](
140-
copyrightString := "Copyright 2002-2015, LAMP/EPFL",
141-
resourceGenerators in Compile += generateVersionPropertiesFile.map(file => Seq(file)).taskValue,
142-
generateVersionPropertiesFile := generateVersionPropertiesFileImpl.value
143-
)
151+
lazy val scalaSubprojectSettings: Seq[Setting[_]] = commonSettings ++ generatePropertiesFileSettings :+ setJarLocation
144152

145153
def filterDocSources(ff: FileFilter): Seq[Setting[_]] = Seq(
146154
sources in (Compile, doc) ~= (_.filter(ff.accept _)),
@@ -160,19 +168,21 @@ def regexFileFilter(s: String): FileFilter = new FileFilter {
160168
def accept(f: File) = pat.matcher(f.getAbsolutePath.replace('\\', '/')).matches()
161169
}
162170

163-
val libIncludes: FileFilter = "*.tmpl" | "*.xml" | "*.js" | "*.css" | "rootdoc.txt"
164-
165171
lazy val library = configureAsSubproject(project)
166172
.settings(generatePropertiesFileSettings: _*)
167173
.settings(
168174
name := "scala-library",
175+
description := "Scala Standard Library",
169176
scalacOptions in Compile ++= Seq[String]("-sourcepath", (scalaSource in Compile).value.toString),
170177
scalacOptions in Compile in doc ++= {
171178
val libraryAuxDir = (baseDirectory in ThisBuild).value / "src/library-aux"
172-
Seq("-doc-no-compile", libraryAuxDir.toString)
179+
Seq(
180+
"-doc-no-compile", libraryAuxDir.toString,
181+
"-skip-packages", "scala.concurrent.impl",
182+
"-doc-root-content", (sourceDirectory in Compile).value + "/rootdoc.txt"
183+
)
173184
},
174-
unmanagedResourceDirectories in Compile += (baseDirectory in ThisBuild).value / "src" / project.id,
175-
includeFilter in unmanagedResources in Compile := libIncludes,
185+
includeFilter in unmanagedResources in Compile := "*.tmpl" | "*.xml" | "*.js" | "*.css" | "rootdoc.txt",
176186
// Include forkjoin classes in scala-library.jar
177187
mappings in Compile in packageBin ++=
178188
(mappings in Compile in packageBin in LocalProject("forkjoin")).value
@@ -184,17 +194,20 @@ lazy val library = configureAsSubproject(project)
184194

185195
lazy val reflect = configureAsSubproject(project)
186196
.settings(generatePropertiesFileSettings: _*)
187-
.settings(name := "scala-reflect")
197+
.settings(
198+
name := "scala-reflect",
199+
description := "Scala Reflection Library",
200+
scalacOptions in Compile in doc ++= Seq(
201+
"-skip-packages", "scala.reflect.macros.internal:scala.reflect.internal:scala.reflect.io"
202+
)
203+
)
188204
.dependsOn(library)
189205

190-
val compilerIncludes: FileFilter =
191-
"*.tmpl" | "*.xml" | "*.js" | "*.css" | "*.html" | "*.properties" | "*.swf" |
192-
"*.png" | "*.gif" | "*.gif" | "*.txt"
193-
194206
lazy val compiler = configureAsSubproject(project)
195207
.settings(generatePropertiesFileSettings: _*)
196208
.settings(
197209
name := "scala-compiler",
210+
description := "Scala Compiler",
198211
libraryDependencies ++= Seq(antDep, asmDep),
199212
// this a way to make sure that classes from interactive and scaladoc projects
200213
// end up in compiler jar (that's what Ant build does)
@@ -209,12 +222,21 @@ lazy val compiler = configureAsSubproject(project)
209222
(mappings in Compile in packageBin in LocalProject("interactive")).value ++
210223
(mappings in Compile in packageBin in LocalProject("scaladoc")).value ++
211224
(mappings in Compile in packageBin in LocalProject("repl")).value,
212-
unmanagedResourceDirectories in Compile += (baseDirectory in ThisBuild).value / "src" / project.id,
213-
includeFilter in unmanagedResources in Compile := compilerIncludes)
225+
includeFilter in unmanagedResources in Compile :=
226+
"*.tmpl" | "*.xml" | "*.js" | "*.css" | "*.html" | "*.properties" | "*.swf" |
227+
"*.png" | "*.gif" | "*.gif" | "*.txt",
228+
scalacOptions in Compile in doc ++= Seq(
229+
"-doc-root-content", (sourceDirectory in Compile).value + "/rootdoc.txt"
230+
)
231+
)
214232
.dependsOn(library, reflect)
215233

216234
lazy val interactive = configureAsSubproject(project)
217235
.settings(disableDocsAndPublishingTasks: _*)
236+
.settings(
237+
name := "scala-compiler-interactive",
238+
description := "Scala Interactive Compiler"
239+
)
218240
.dependsOn(compiler)
219241

220242
lazy val repl = configureAsSubproject(project)
@@ -272,18 +294,29 @@ lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target"
272294

273295
lazy val scaladoc = configureAsSubproject(project)
274296
.settings(
275-
libraryDependencies ++= Seq(scalaXmlDep, scalaParserCombinatorsDep, partestDep)
297+
name := "scala-compiler-doc",
298+
description := "Scala Documentation Generator",
299+
libraryDependencies ++= Seq(scalaXmlDep, scalaParserCombinatorsDep, partestDep),
300+
includeFilter in unmanagedResources in Compile := "*.html" | "*.css" | "*.gif" | "*.png" | "*.js" | "*.txt"
276301
)
277302
.settings(disableDocsAndPublishingTasks: _*)
278303
.dependsOn(compiler)
279304

280305
lazy val scalap = configureAsSubproject(project).
281-
dependsOn(compiler)
306+
settings(
307+
description := "Scala Bytecode Parser",
308+
// Include decoder.properties
309+
includeFilter in unmanagedResources in Compile := "*.properties"
310+
)
311+
.dependsOn(compiler)
282312

283313
// deprecated Scala Actors project
284314
lazy val actors = configureAsSubproject(project)
285315
.settings(generatePropertiesFileSettings: _*)
286-
.settings(name := "scala-actors")
316+
.settings(
317+
name := "scala-actors",
318+
description := "Scala Actors Library"
319+
)
287320
.settings(filterDocSources("*.scala"): _*)
288321
.dependsOn(library)
289322

@@ -294,6 +327,7 @@ lazy val partestExtras = configureAsSubproject(Project("partest-extras", file(".
294327
.settings(clearSourceAndResourceDirectories: _*)
295328
.settings(
296329
name := "scala-partest-extras",
330+
description := "Scala Compiler Testing Tool (compiler-specific extras)",
297331
libraryDependencies += partestDep,
298332
unmanagedSourceDirectories in Compile := List(baseDirectory.value),
299333
doc := file("!!! NO DOCS !!!")
@@ -311,15 +345,17 @@ lazy val junit = project.in(file("test") / "junit")
311345
doc := file("!!! NO DOCS !!!")
312346
)
313347

314-
lazy val partestJavaAgent = (project in file(".") / "src" / "partest-javaagent").
315-
settings(commonSettings: _*).
316-
settings(
348+
lazy val partestJavaAgent = Project("partest-javaagent", file(".") / "src" / "partest-javaagent")
349+
.settings(commonSettings: _*)
350+
.settings(generatePropertiesFileSettings: _*)
351+
.settings(
317352
libraryDependencies += asmDep,
318353
doc := file("!!! NO DOCS !!!"),
319354
publishLocal := {},
320355
publish := {},
321356
// Setting name to "scala-partest-javaagent" so that the jar file gets that name, which the Runner relies on
322357
name := "scala-partest-javaagent",
358+
description := "Scala Compiler Testing Tool (compiler-specific java agent)",
323359
// writing jar file to $buildDirectory/pack/lib because that's where it's expected to be found
324360
setJarLocation,
325361
// add required manifest entry - previously included from file
@@ -377,7 +413,7 @@ lazy val dist = (project in file("dist"))
377413
.settings(
378414
libraryDependencies ++= Seq(scalaContinuationsLibraryDep, scalaContinuationsPluginDep, scalaSwingDep, jlineDep),
379415
mkBin := mkBinImpl.value,
380-
mkQuick <<= Def.task {} dependsOn ((distDependencies.map(compile in Compile in _) :+ mkBin): _*),
416+
mkQuick <<= Def.task {} dependsOn ((distDependencies.map(products in Runtime in _) :+ mkBin): _*),
381417
mkPack <<= Def.task {} dependsOn (packageBin in Compile, mkBin),
382418
target := (baseDirectory in ThisBuild).value / "target" / thisProject.value.id,
383419
packageBin in Compile := {
@@ -438,59 +474,10 @@ def configureAsForkOfJavaProject(project: Project): Project = {
438474
}
439475

440476
lazy val buildDirectory = settingKey[File]("The directory where all build products go. By default ./build")
441-
lazy val copyrightString = settingKey[String]("Copyright string.")
442-
lazy val generateVersionPropertiesFile = taskKey[File]("Generating version properties file.")
443477
lazy val mkBin = taskKey[Seq[File]]("Generate shell script (bash or Windows batch).")
444478
lazy val mkQuick = taskKey[Unit]("Generate a full build, including scripts, in build-sbt/quick")
445479
lazy val mkPack = taskKey[Unit]("Generate a full build, including scripts, in build-sbt/pack")
446480

447-
lazy val generateVersionPropertiesFileImpl: Def.Initialize[Task[File]] = Def.task {
448-
val propFile = (resourceManaged in Compile).value / s"${thisProject.value.id}.properties"
449-
val props = new java.util.Properties
450-
451-
/**
452-
* Regexp that splits version number split into two parts: version and suffix.
453-
* Examples of how the split is performed:
454-
*
455-
* "2.11.5": ("2.11.5", null)
456-
* "2.11.5-acda7a": ("2.11.5", "-acda7a")
457-
* "2.11.5-SNAPSHOT": ("2.11.5", "-SNAPSHOT")
458-
*
459-
*/
460-
val versionSplitted = """([\w+\.]+)(-[\w+\.]+)??""".r
461-
462-
val versionSplitted(ver, suffixOrNull) = version.value
463-
val osgiSuffix = suffixOrNull match {
464-
case null => "-VFINAL"
465-
case "-SNAPSHOT" => ""
466-
case suffixStr => suffixStr
467-
}
468-
469-
def executeTool(tool: String) = {
470-
val cmd =
471-
if (System.getProperty("os.name").toLowerCase.contains("windows"))
472-
s"cmd.exe /c tools\\$tool.bat -p"
473-
else s"tools/$tool"
474-
Process(cmd).lines.head
475-
}
476-
477-
val commitDate = executeTool("get-scala-commit-date")
478-
val commitSha = executeTool("get-scala-commit-sha")
479-
480-
props.put("version.number", s"${version.value}-$commitDate-$commitSha")
481-
props.put("maven.version.number", s"${version.value}")
482-
props.put("osgi.version.number", s"$ver.v$commitDate$osgiSuffix-$commitSha")
483-
props.put("copyright.string", copyrightString.value)
484-
485-
// unfortunately, this will write properties in arbitrary order
486-
// this makes it harder to test for stability of generated artifacts
487-
// consider using https://github.com/etiennestuder/java-ordered-properties
488-
// instead of java.util.Properties
489-
IO.write(props, null, propFile)
490-
491-
propFile
492-
}
493-
494481
/**
495482
* Extract selected dependencies to the `cacheDirectory` and return a mapping for the content.
496483
* Heavily inspired by sbt-assembly (https://github.com/sbt/sbt-assembly/blob/0.13.0/src/main/scala/sbtassembly/Assembly.scala#L157)
@@ -582,17 +569,3 @@ lazy val mkBinImpl: Def.Initialize[Task[Seq[File]]] = Def.task {
582569
}
583570

584571
buildDirectory in ThisBuild := (baseDirectory in ThisBuild).value / "build-sbt"
585-
586-
lazy val versionProps: Map[String, String] = {
587-
import java.io.FileInputStream
588-
import java.util.Properties
589-
val props = new Properties()
590-
val in = new FileInputStream(file("versions.properties"))
591-
try props.load(in)
592-
finally in.close()
593-
import scala.collection.JavaConverters._
594-
props.asScala.toMap
595-
}
596-
597-
def versionNumber(name: String): String =
598-
versionProps(s"$name.version.number")

project/VersionUtil.scala

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import sbt._
2+
import Keys._
3+
import java.util.Properties
4+
import java.io.FileInputStream
5+
import scala.collection.JavaConverters._
6+
7+
object VersionUtil {
8+
lazy val copyrightString = settingKey[String]("Copyright string.")
9+
lazy val versionProperties = settingKey[Versions]("Version properties.")
10+
lazy val generateVersionPropertiesFile = taskKey[File]("Generating version properties file.")
11+
12+
lazy val versionPropertiesSettings = Seq[Setting[_]](
13+
versionProperties := versionPropertiesImpl.value
14+
)
15+
16+
lazy val generatePropertiesFileSettings = Seq[Setting[_]](
17+
copyrightString := "Copyright 2002-2015, LAMP/EPFL",
18+
resourceGenerators in Compile += generateVersionPropertiesFile.map(file => Seq(file)).taskValue,
19+
versionProperties := versionPropertiesImpl.value,
20+
generateVersionPropertiesFile := generateVersionPropertiesFileImpl.value
21+
)
22+
23+
case class Versions(canonicalVersion: String, mavenVersion: String, osgiVersion: String, commitSha: String, commitDate: String, isRelease: Boolean) {
24+
val githubTree =
25+
if(isRelease) "v" + mavenVersion
26+
else if(commitSha != "unknown") commitSha
27+
else "master"
28+
29+
override def toString = s"Canonical: $canonicalVersion, Maven: $mavenVersion, OSGi: $osgiVersion, github: $githubTree"
30+
31+
def toProperties: Properties = {
32+
val props = new Properties
33+
props.put("version.number", canonicalVersion)
34+
props.put("maven.version.number", mavenVersion)
35+
props.put("osgi.version.number", osgiVersion)
36+
props
37+
}
38+
}
39+
40+
lazy val versionPropertiesImpl: Def.Initialize[Versions] = Def.setting {
41+
/** Regexp that splits version number split into two parts: version and suffix.
42+
* Examples of how the split is performed:
43+
*
44+
* "2.11.5": ("2.11.5", null)
45+
* "2.11.5-acda7a": ("2.11.5", "-acda7a")
46+
* "2.11.5-SNAPSHOT": ("2.11.5", "-SNAPSHOT") */
47+
val versionSplitted = """([\w+\.]+)(-[\w+\.]+)??""".r
48+
49+
val versionSplitted(ver, suffixOrNull) = version.value
50+
51+
val osgiSuffix = suffixOrNull match {
52+
case null => "-VFINAL"
53+
case "-SNAPSHOT" => ""
54+
case suffixStr => suffixStr
55+
}
56+
57+
def executeTool(tool: String) = {
58+
val cmd =
59+
if (System.getProperty("os.name").toLowerCase.contains("windows"))
60+
s"cmd.exe /c tools\\$tool.bat -p"
61+
else s"tools/$tool"
62+
Process(cmd).lines.head
63+
}
64+
65+
val commitDate = executeTool("get-scala-commit-date")
66+
val commitSha = executeTool("get-scala-commit-sha")
67+
68+
Versions(
69+
canonicalVersion = s"$ver-$commitDate-$commitSha",
70+
mavenVersion = s"${version.value}",
71+
osgiVersion = s"$ver.v$commitDate$osgiSuffix-$commitSha",
72+
commitSha = commitSha,
73+
commitDate = commitDate,
74+
isRelease = !osgiSuffix.isEmpty
75+
)
76+
}
77+
78+
lazy val generateVersionPropertiesFileImpl: Def.Initialize[Task[File]] = Def.task {
79+
val props = versionProperties.value.toProperties
80+
val propFile = (resourceManaged in Compile).value / s"${thisProject.value.id}.properties"
81+
props.put("copyright.string", copyrightString.value)
82+
83+
// unfortunately, this will write properties in arbitrary order
84+
// this makes it harder to test for stability of generated artifacts
85+
// consider using https://github.com/etiennestuder/java-ordered-properties
86+
// instead of java.util.Properties
87+
IO.write(props, null, propFile)
88+
propFile
89+
}
90+
91+
/** The global versions.properties data */
92+
lazy val versionProps: Map[String, String] = {
93+
val props = new Properties()
94+
val in = new FileInputStream(file("versions.properties"))
95+
try props.load(in)
96+
finally in.close()
97+
props.asScala.toMap
98+
}
99+
100+
/** Get a subproject version number from `versionProps` */
101+
def versionNumber(name: String): String =
102+
versionProps(s"$name.version.number")
103+
}

0 commit comments

Comments
 (0)