summaryrefslogtreecommitdiff
path: root/project/Osgi.scala
diff options
context:
space:
mode:
authorStefan Zeiger <szeiger@novocode.com>2015-11-13 14:00:50 +0100
committerStefan Zeiger <szeiger@novocode.com>2015-11-24 12:44:44 +0100
commit2803d0ad50e94a3a88d98d709b7a38a5bbb6a383 (patch)
treed15e97ee879e7f752d9c3c9b93b74bc07220681f /project/Osgi.scala
parent18e261ba7a34825b519a865d8dd72b987f73b5bf (diff)
downloadscala-2803d0ad50e94a3a88d98d709b7a38a5bbb6a383.tar.gz
scala-2803d0ad50e94a3a88d98d709b7a38a5bbb6a383.tar.bz2
scala-2803d0ad50e94a3a88d98d709b7a38a5bbb6a383.zip
[nomerge] Create a full Scala distribution from sbt
This replicates the results of `ant -Dlocker.skip=1 distpack` with the following differences: - The POM files produced by the ant build under dists/maven still contain unresolved variables like `@VERSION@`. The ant build resolves them in the actual publishing process. The sbt build generates the correct version numbers directly. - Scaladoc sets in the ant build are created with the scaladoc tool from “quick”. The sbt build uses the STARR scaladoc. - The scaladoc sets for scala-actors, scala-compiler, scala-reflect and scalap from the ant build contain documentation for the classes `Null`, `Nothing`, `Any` and `AnyRef`. The sbt build omits those classes from all doc sets (except for scala-library, of course) under the assumption that this is a bug in the ant build. Other idiosyncracies of the ant build like declaring a packaging type of `jar` (instead of `bundle`) for OSGi bundles, or using slightly different module names and descriptions in scaladocs, OSGi bundles and POMs, are reproduced faithfully for now. Publishing from the sbt build is done in the usual sbt way. No actual publishing targets are currently defined in the build. In order to test stability of the publishing process, the `publishDists` task can be used to publish to dists/maven-sbt with the same directory layout and naming conventions employed by the ant build for publishing to dists/maven. Source and binary JARs are OSGi-enabled. For the source JARs this is done by hand-crafting the appropriate MANIFEST.MF entries (like the ant build does). Binary JARs are packaged with BND, using the same outdated BND version as the ant build for now to get identical results. We do not use sbt-osgi because it depends on a newer version of BND (probably OK to upgrade in the future) and does not allow a crucial bit of configuration that we need: Setting the classpath for BND. In sbt-osgi this is always `fullClasspath in Compile` whereas we really want `products in Compile in packageBin` to keep things simple.
Diffstat (limited to 'project/Osgi.scala')
-rw-r--r--project/Osgi.scala68
1 files changed, 68 insertions, 0 deletions
diff --git a/project/Osgi.scala b/project/Osgi.scala
new file mode 100644
index 0000000000..6c0ef74ef5
--- /dev/null
+++ b/project/Osgi.scala
@@ -0,0 +1,68 @@
+import aQute.lib.osgi.Builder
+import aQute.lib.osgi.Constants._
+import java.util.Properties
+import sbt._
+import sbt.Keys._
+import scala.collection.JavaConversions._
+import VersionUtil.versionProperties
+
+/** OSGi packaging for the Scala build, distilled from sbt-osgi. We do not use sbt-osgi because it
+ * depends on a newer version of BND which gives slightly different output (probably OK to upgrade
+ * in the future but for now it would make comparing the sbt and ant build output harder) and does
+ * not allow a crucial bit of configuration that we need: Setting the classpath for BND. In sbt-osgi
+ * this is always `fullClasspath in Compile` whereas we want `products in Compile in packageBin`. */
+object Osgi {
+ val bundle = TaskKey[File]("osgiBundle", "Create an OSGi bundle.")
+ val bundleName = SettingKey[String]("osgiBundleName", "The Bundle-Name for the manifest.")
+ val bundleSymbolicName = SettingKey[String]("osgiBundleSymbolicName", "The Bundle-SymbolicName for the manifest.")
+ val headers = SettingKey[Seq[(String, String)]]("osgiHeaders", "Headers and processing instructions for BND.")
+
+ def settings: Seq[Setting[_]] = Seq(
+ bundleName := description.value,
+ bundleSymbolicName := organization.value + "." + name.value,
+ headers := {
+ val v = VersionUtil.versionProperties.value.osgiVersion
+ Seq(
+ "Bundle-Name" -> bundleName.value,
+ "Bundle-SymbolicName" -> bundleSymbolicName.value,
+ "ver" -> v,
+ "Export-Package" -> ("*;version=${ver}"),
+ "Import-Package" -> ("scala.*;version=\"${range;[==,=+);${ver}}\",*"),
+ "Bundle-Version" -> v,
+ "Bundle-RequiredExecutionEnvironment" -> "JavaSE-1.6, JavaSE-1.7",
+ "-eclipse" -> "false"
+ )
+ },
+ bundle <<= Def.task {
+ bundleTask(headers.value.toMap, (products in Compile in packageBin).value,
+ (artifactPath in (Compile, packageBin)).value, Nil, streams.value)
+ },
+ packagedArtifact in (Compile, packageBin) <<= (artifact in (Compile, packageBin), bundle).identityMap,
+ // Also create OSGi source bundles:
+ artifact in (Compile, packageBin) ~= (_.copy(`type` = "bundle")),
+ packageOptions in (Compile, packageSrc) += Package.ManifestAttributes(
+ "Bundle-Name" -> (description.value + " Sources"),
+ "Bundle-SymbolicName" -> (bundleSymbolicName.value + ".source"),
+ "Bundle-Version" -> versionProperties.value.osgiVersion,
+ "Eclipse-SourceBundle" -> (bundleSymbolicName.value + ";version=\"" + versionProperties.value.osgiVersion + "\";roots:=\".\"")
+ )
+ )
+
+ def bundleTask(headers: Map[String, String], fullClasspath: Seq[File], artifactPath: File,
+ resourceDirectories: Seq[File], streams: TaskStreams): File = {
+ val log = streams.log
+ val builder = new Builder
+ builder.setClasspath(fullClasspath.toArray)
+ headers foreach { case (k, v) => builder.setProperty(k, v) }
+ val includeRes = resourceDirectories.filter(_.exists).map(_.getAbsolutePath).mkString(",")
+ if(!includeRes.isEmpty) builder.setProperty(INCLUDERESOURCE, includeRes)
+ builder.getProperties.foreach { case (k, v) => log.debug(s"bnd: $k: $v") }
+ // builder.build is not thread-safe because it uses a static SimpleDateFormat. This ensures
+ // that all calls to builder.build are serialized.
+ val jar = synchronized { builder.build }
+ builder.getWarnings.foreach(s => log.warn(s"bnd: $s"))
+ builder.getErrors.foreach(s => log.error(s"bnd: $s"))
+ jar.write(artifactPath)
+ artifactPath
+ }
+}