Skip to content

Commit

Permalink
Added support to set versions in plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
Luc Bourlier committed Oct 2, 2012
1 parent 8040014 commit 7dcc95b
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 70 deletions.
69 changes: 67 additions & 2 deletions src/main/scala/org/scalaide/buildtools/Ecosystem.scala
@@ -1,13 +1,78 @@
package org.scalaide.buildtools

import java.io.File
import java.io.FileWriter

import scala.io.Source
import scala.util.matching.Regex

object Ecosystem {


/** suffix used by eclipse to mark feature bundles */
final val FeatureSuffix = ".feature.group"
/** suffix used to mark the copy of the files which are modified */
final val OriginalSuffix = ".original"

/* osgi ids of the relevant bundles */
final val ScalaLibraryId = "org.scala-ide.scala.library"
final val ScalaCompilerId = "org.scala-ide.scala.compiler"
final val ScalaIDEId = "org.scala-ide.sdt.core"

final val ScalaIDEFeatureId = "org.scala-ide.sdt.feature"
final val ScalaIDEFeatureIdOsgi = ScalaIDEFeatureId + FeatureSuffix

/** default location of the manifest file in a bundle project */
final val PluginManifest = "META-INF/MANIFEST.MF"
/** default location of the feature description fise in a feature project */
final val FeatureDescriptor = "feature.xml"

/** regex to find the root option in the command line */
final val RootOption = "--root=(.*)".r

/** regex to find the given bundle id dependency in a manifest file */
final def idInManifest(id: String) = ("(.*" + id + ")(,?.*)").r
/** regex to find the given bundle id dependency, with a version number defined, in a manifest file */
final def idInManifestWithVersion(id: String) = ("(.*)" + id + """;bundle-version="([^"]*)"(,?.*)""").r

/** create the partial function finding the dependency line corresponding to the given id, and set the version */
def updateVersionInManifest(id: String, version: String): PartialFunction[String, String] =
updateVersionInManifest(idInManifestWithVersion(id), idInManifest(id), version)

/** method need to create the partial function */
private def updateVersionInManifest(idWithVersion: Regex, id: Regex, version: String): PartialFunction[String, String] = {
case line @ idWithVersion(_, currentVersion, _) =>
warning("%s has already a version number defined: %s".format(ScalaLibraryId, currentVersion))
line
case id(prefixWithId, suffix) =>
"""%s;bundle-version="[%s,%<s]"%s""".format(prefixWithId, version, suffix)
}

/** update the given manifest, using the provided version updater */
def updateBundleManifest(baseManifest: File, versionUpdater: PartialFunction[String, String]) {
val savedManifest= new File(baseManifest.getAbsolutePath() + OriginalSuffix)

// make a copy if needed
if (!savedManifest.exists) {
FileUtils.copyFile(baseManifest, savedManifest)
}

// get the content
val lines = Source.fromFile(savedManifest).getLines

// update the content
val newLines = lines.map(versionUpdater)

// save the new content
val writer = new FileWriter(baseManifest)
newLines foreach { s =>
writer.write(s)
writer.append('\n')
}
writer.flush()
writer.close()
}

private def warning(message: String) {
println("WARNING: %s".format(message))
}

}
102 changes: 85 additions & 17 deletions src/main/scala/org/scalaide/buildtools/UpdateAddonManifests.scala
@@ -1,12 +1,18 @@
package org.scalaide.buildtools

import dispatch.Http
import java.io.File

import scala.xml.Attribute
import scala.xml.Elem
import scala.xml.Null
import scala.xml.XML

import dispatch.Http

object UpdateAddonManifests {
import Ecosystem._

final val usage = "Usage: app [--root=<Scala IDE root folder>] <repository URL>"
final val usage = "Usage: app [--root=<Addon root folder>] <repository URL>"

def main(args: Array[String]) {
// parse arguments
Expand Down Expand Up @@ -49,60 +55,122 @@ class UpdateAddonManifests(repoURL: String, rootFolder: String) {
P2Repository.fromUrl(repoURL).right.flatMap(updateVersions(_))
}

/**
* Set strict version dependency to Scala IDE in the plugin and features found under the root, using the
* version numbers found in the given p2 repository
*/
private def updateVersions(p2Repo: P2Repository): Either[String, String] = {
for {
scalaIDEVersion <- getOneVersion(p2Repo, ScalaIDEId).right
scalaLibraryVersion <- getOneVersion(p2Repo, ScalaLibraryId).right
scalaCompilerVersion <- getOneVersion(p2Repo, ScalaCompilerId).right
result <- updateVersions(scalaIDEVersion, scalaLibraryVersion, scalaCompilerVersion).right
scalaIDEFeatureVersion <- getOneVersion(p2Repo, ScalaIDEFeatureIdOsgi).right
result <- updateVersions(scalaIDEVersion, scalaLibraryVersion, scalaCompilerVersion, scalaIDEFeatureVersion).right
} yield result

}

private def updateVersions(scalaIDEVersion: String, scalaLibraryVersion: String, scalaCompilerVersion: String): Either[String, String] = {
println("%s, %s, %s".format(scalaIDEVersion, scalaLibraryVersion, scalaCompilerVersion))
/**
* Set strict version dependency to Scala IDE in the plugin and features found under the root.
*/
private def updateVersions(scalaIDEVersion: String, scalaLibraryVersion: String, scalaCompilerVersion: String, scalaIDEFeatureVersion: String): Either[String, String] = {
println("%s, %s, %s, %s".format(scalaIDEVersion, scalaLibraryVersion, scalaCompilerVersion, scalaIDEFeatureVersion))

val root = new File(rootFolder)


if (root.exists && root.isDirectory) {
val pluginManifestsResult = findPlugins(root).foldLeft[Either[String, String]](
Right("no plugin"))(
(res, manifest) => res.right.flatMap(r => updateVersionInPluginManifest(manifest, scalaIDEVersion, scalaLibraryVersion, scalaCompilerVersion)))
findFeatures(root).foldLeft(
pluginManifestsResult)(
(res, feature) => res.right.flatMap(r => updateVersionInFeature(feature, scalaIDEVersion, scalaLibraryVersion, scalaCompilerVersion)))
// update the plugin manifest files
val versionUpdater: PartialFunction[String, String] = updateVersionInManifest(ScalaLibraryId, scalaLibraryVersion).
orElse(updateVersionInManifest(ScalaCompilerId, scalaCompilerVersion)).
orElse(updateVersionInManifest(ScalaIDEId, scalaIDEVersion)).
orElse {
case line =>
line
}
findPlugins(root).foreach(updateVersionInPluginManifest(_, versionUpdater))

// update the feature definition files
findFeatures(root).foreach(updateVersionInFeature(_, scalaIDEFeatureVersion))

Right("OK")
} else {
Left("%s doesn't exist or is not a directory".format(root.getAbsolutePath()))
}
}

private def updateVersionInPluginManifest(manifest: File, scalaIDEVersion: String, scalaLibraryVersion: String, scalaCompilerVersion: String): Either[String, String] = {

/**
* Set strict version dependency to the Scala IDE plugin in the given manifest file.
*/
private def updateVersionInPluginManifest(manifest: File, versionUpdater: PartialFunction[String, String]) {
println(manifest.getAbsoluteFile())
Right("OK")

updateBundleManifest(manifest, versionUpdater)
}

private def updateVersionInFeature(feature: File, scalaIDEVersion: String, scalaLibraryVersion: String, scalaCompilerVersion: String): Either[String, String] = {

/**
* Go through the feature definition XML tree, and add version and match attribute for the reference to the scala IDE feature.
*/
private def transformXML(e: Elem, version: String): Elem = {
if (e.attributes.get("feature").exists(_.text == ScalaIDEFeatureId)) {
e.copy(attributes = e.attributes.append(Attribute(null, "version", version, Attribute(null, "match", "perfect", Null))))
} else {
e.copy(child = e.child.map(_ match {
case e: Elem => transformXML(e, version)
case o => o
}))
}
}

/**
* Set strict version dependency to Scala IDE feature in the given feature file.
*/
private def updateVersionInFeature(feature: File, scalaIDEFeatureVersion: String): Either[String, String] = {
println(feature.getAbsoluteFile())

val savedFeature= new File(feature.getAbsolutePath() + OriginalSuffix)

if (!savedFeature.exists) {
FileUtils.copyFile(feature, savedFeature)
}

val xml= transformXML(XML.loadFile(savedFeature), scalaIDEFeatureVersion)

XML.save(feature.getAbsolutePath(), xml, "UTF-8", true)

Right("OK")
}

/**
* Return the unique version of a plugin available in the repository.
* Return an error if the plugin is not available, or more than one version is available.
*/
private def getOneVersion(p2Repo: P2Repository, pluginId: String): Either[String, String] = {
p2Repo.findIU(pluginId) match {
case Seq(iu) =>
Right(iu.version)
case _ =>
case s =>
Left("More than one version found for %s. You may not be using the right repository.".format(pluginId))
}
}

/**
* Return the list of manifest files found in the direct subfolders of the root
*/
private def findPlugins(root: File): List[File] = {
findFileInSubFolders(root, PluginManifest)
}

/**
* Return the list of feature definition files found in the direct subfolders of the root
*/
private def findFeatures(root: File): List[File] = {
findFileInSubFolders(root, FeatureDescriptor)
}

/**
* Return the list of instances of the given file existing in the direct subfolders of the root
*/
private def findFileInSubFolders(root: File, fileName: String): List[File] = {
(for {
folder <- root.listFiles().toList if (folder.isDirectory())
Expand Down
Expand Up @@ -7,20 +7,13 @@ import java.io.FileWriter
object UpdateScalaIDEManifests {

import Ecosystem._

final val Usage = "Usage: app [--root=<Scala IDE root folder>]"

final val PackagedManifestPath = "target/META-INF/MANIFEST.MF"
final val BaseManifestPath = "META-INF/MANIFEST.MF"
final val SavedManifestPath = "META-INF/MANIFEST.MF.original"
final val PackagedManifestPath = "target/" + PluginManifest

final val BundleVersion = "Bundle-Version: (.*)".r

final val ScalaLibraryInManifest = ("(.*)" + ScalaLibraryId + "(,?.*)").r
final val ScalaLibraryInManifestWithVersion = ("(.*)" + ScalaLibraryId + """;bundle-version="([^"]*)"(,?.*)""").r
final val ScalaCompilerInManifest = ("(.*)" + ScalaCompilerId + "(,?.*)").r
final val ScalaCompilerInManifestWithVersion = ("(.*)" + ScalaCompilerId + """;bundle-version="([^"]*)"(,?.*)""").r

final val projectsToUpdate = List(ScalaIDEId, "org.scala-ide.sdt.debug")

def main(args: Array[String]) {
Expand All @@ -43,16 +36,16 @@ class UpdateScalaIDEManifests(root: String) {
val rootFolder = new File(root)

def apply() {

println("Build tools: Updating versions in Scala IDE manifests.")

val scalaLibraryVersion = getPackagedBundleVersion(ScalaLibraryId)
val scalaCompilerVersion = getPackagedBundleVersion(ScalaCompilerId)

projectsToUpdate foreach {
update(_, scalaLibraryVersion, scalaCompilerVersion)
updateManifest(_, scalaLibraryVersion, scalaCompilerVersion)
}

println("Build tools: Updating versions in Scala IDE manifests - Done.")
}

Expand All @@ -74,45 +67,20 @@ class UpdateScalaIDEManifests(root: String) {
version.get
}

private def update(projectPath: String, scalaLibraryVersion: String, scalaCompilerVersion: String) {
/**
* Set strict version dependency to Scala library and compiler in the given project.
*/
private def updateManifest(projectPath: String, scalaLibraryVersion: String, scalaCompilerVersion: String) {
val projectFolder = new File(rootFolder, projectPath)
val baseManifest = new File(projectFolder, BaseManifestPath)
val savedManifest = new File(projectFolder, SavedManifestPath)

// TODO: check if base file exists

if (!savedManifest.exists()) {
FileUtils.copyFile(baseManifest, savedManifest)
}

val lines = Source.fromFile(savedManifest).getLines
val newLines = lines.map {
case line @ ScalaLibraryInManifestWithVersion(_, version, _) =>
warning("%s has already a version number defined: %s".format(ScalaLibraryId, version))
line
case ScalaLibraryInManifest(prefix, suffix) =>
(prefix, suffix)
"%s%s;bundle-version=%s%s".format(prefix, ScalaLibraryId, scalaLibraryVersion, suffix)
case line @ ScalaCompilerInManifestWithVersion(_, version, _) =>
warning("%s has already a version number defined: %s".format(ScalaCompilerId, version))
line
case ScalaCompilerInManifest(prefix, suffix) =>
(prefix, suffix)
"%s%s;bundle-version=%s%s".format(prefix, ScalaCompilerId, scalaCompilerVersion, suffix)
case line =>
line
}

val writer = new FileWriter(baseManifest)

newLines foreach { s =>
writer.write(s)
writer.append('\n')
}

writer.flush()
writer.close()

val baseManifest = new File(projectFolder, PluginManifest)

updateBundleManifest(baseManifest,
updateVersionInManifest(ScalaLibraryId, scalaLibraryVersion).
orElse(updateVersionInManifest(ScalaCompilerId, scalaCompilerVersion)).
orElse {
case line =>
line
})
}

private def warning(message: String) {
Expand Down

0 comments on commit 7dcc95b

Please sign in to comment.