Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 142 lines (119 sloc) 6.695 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
import sbt._
import Keys._
import java.util.Properties
import scala.util.control.Exception.catching
import java.lang.{NumberFormatException => NFE}
import java.io.FileInputStream
import com.jsuereth.git.GitRunner
import com.jsuereth.git.GitKeys.gitRunner

case class VersionInfo(canonical: String,
                       maven: String,
                       osgi: String)

/** this file is responsible for setting up Scala versioning schemes and updating all the necessary bits. */
object Versions {
  val buildNumberFile = SettingKey[File]("scala-build-number-file")
  // TODO - Make this a setting?
  val buildNumberProps = SettingKey[BaseBuildNumber]("scala-build-number-props")
  val buildRelease = SettingKey[Boolean]("scala-build-release", "This is set to true if we're building a release.")
  val mavenSuffix = SettingKey[String]("scala-maven-suffix", "This is set to whatever maven suffix is required.")

  val gitSha = TaskKey[String]("scala-git-sha", "The sha of the current git commit.")
  val gitDate = TaskKey[String]("scala-git-date", "The date of the current git commit.")

  val mavenVersion = SettingKey[String]("scala-maven-version", "The maven version number.")
  val osgiVersion = TaskKey[String]("scala-osgi-version", "The OSGi version number.")
  val canonicalVersion = TaskKey[String]("scala-canonical-version", "The canonical version number.")

  val scalaVersions = TaskKey[VersionInfo]("scala-version-info", "The scala versions used for this build.")
  

  
  def settings: Seq[Setting[_]] = Seq(
    buildNumberFile <<= baseDirectory apply (_ / "build.number"),
    buildNumberProps <<= buildNumberFile apply loadBuildNumberProps,
    buildRelease := Option(System.getProperty("build.release")) map (!_.isEmpty) getOrElse false,
    mavenSuffix <<= buildRelease apply pickMavenSuffix,
    mavenVersion <<= (buildNumberProps, mavenSuffix) apply makeMavenVersion,
    gitSha <<= (gitRunner, baseDirectory, streams) map getGitSha,
    gitDate <<= (gitRunner, baseDirectory, streams) map getGitDate,
    osgiVersion <<= (buildNumberProps, gitDate, gitSha) map makeOsgiVersion,
    canonicalVersion <<= (buildRelease, mavenVersion, buildNumberProps, gitDate, gitSha) map makeCanonicalVersion,
    scalaVersions <<= (canonicalVersion, mavenVersion, osgiVersion) map VersionInfo.apply
  )


  /** This generates a properties file, if it does not already exist, with the maximum lastmodified timestamp
* of any source file. */
  def generateVersionPropertiesFile(name: String)(dir: File, versions: VersionInfo, skip: Boolean, s: TaskStreams): Seq[File] = {
    // TODO - We can probably clean this up by moving caching bits elsewhere perhaps....
    val target = dir / name
    // TODO - Regenerate on triggers, like recompilation or something...
    def hasSameVersion: Boolean = {
      val props = new java.util.Properties
      val in = new java.io.FileInputStream(target)
      try props.load(in) finally in.close()
      versions.canonical == (props getProperty "version.number")
    }
    if (!target.exists || !(skip || hasSameVersion)) {
      makeVersionPropertiesFile(target, versions)
    }
    target :: Nil
  }
  
  // This creates the *.properties file used to determine the current version of scala at runtime. TODO - move these somewhere utility like.
  def makeVersionPropertiesFile(f: File, versions: VersionInfo): Unit =
    IO.write(f, "version.number = "+versions.canonical+"\n"+
                "osgi.number = "+versions.osgi+"\n"+
                "maven.number = "+versions.maven+"\n"+
                "copyright.string = Copyright 2002-2013, LAMP/EPFL")

  def makeCanonicalVersion(isRelease: Boolean, mvnVersion: String, base: BaseBuildNumber, gitDate: String, gitSha: String): String =
    if(isRelease) mvnVersion
    else {
      val suffix = if(base.bnum > 0) "-%d".format(base.bnum) else ""
      "%s.%s.%s%s-%s-%s" format (base.major, base.minor, base.patch, suffix, gitDate, gitSha)
    }

  def makeMavenVersion(base: BaseBuildNumber, suffix: String): String = {
    val firstSuffix = if(base.bnum > 0) "-%d".format(base.bnum) else ""
    "%d.%d.%d%s%s" format (base.major, base.minor, base.patch, firstSuffix, suffix)
  }

  def makeOsgiVersion(base: BaseBuildNumber, gitDate: String, gitSha: String): String = {
    val suffix = if(base.bnum > 0) "-%d".format(base.bnum) else ""
    "%s.%s.%s.v%s%s-%s" format (base.major, base.minor, base.patch, gitDate, suffix, gitSha)
  }

  /** Determines what the maven sufffix should be for this build. */
  def pickMavenSuffix(isRelease: Boolean): String = {
    def default = if(isRelease) "" else "-SNAPSHOT"
    Option(System.getProperty("maven.version.suffix")) getOrElse default
  }

  /** Loads the build.number properties file into SBT. */
  def loadBuildNumberProps(file: File): BaseBuildNumber = {
    val fin = new FileInputStream(file)
    try {
      val props = new Properties()
      props.load(fin)
      def getProp(name: String): Int =
        (for {
          v <- Option(props.getProperty(name))
          v2 <- catching(classOf[NFE]) opt v.toInt
        } yield v2) getOrElse sys.error("Could not convert %s to integer!" format (name))

      BaseBuildNumber(
        major=getProp("version.major"),
        minor=getProp("version.minor"),
        patch=getProp("version.patch"),
        bnum =getProp("version.bnum")
      )
    } finally fin.close()
  }


  def getGitDate(git: GitRunner, baseDirectory: File, s: TaskStreams): String = {
    val lines = getGitLines("log","-1","--format=\"%ci\"")(git,baseDirectory, s)
    val line = if(lines.isEmpty) sys.error("Could not retreive git commit sha!") else lines.head
    // Lines *always* start with " for some reason...
    line drop 1 split "\\s+" match {
      case Array(date, time, _*) => "%s-%s" format (date.replaceAll("\\-", ""), time.replaceAll(":",""))
      case _ => sys.error("Could not parse git date: " + line)
    }
  }

  def getGitSha(git: GitRunner, baseDirectory: File, s: TaskStreams): String = {
    val lines = getGitLines("log","-1","--format=\"%H\"", "HEAD")(git,baseDirectory, s)
    val line = if(lines.isEmpty) sys.error("Could not retreive git commit sha!") else lines.head
    val noquote = if(line startsWith "\"") line drop 1 else line
    val nog = if(noquote startsWith "g") noquote drop 1 else noquote
    nog take 10
  }

  def getGitLines(args: String*)(git: GitRunner, baseDirectory: File, s: TaskStreams): Seq[String] =
     git(args: _*)(baseDirectory, s.log) split "[\r\n]+"
}


case class BaseBuildNumber(major: Int, minor: Int, patch: Int, bnum: Int) {
  override def toString = "BaseBuildNumber(%d.%d.%d-%d)" format (major, minor, patch, bnum)
}
Something went wrong with that request. Please try again.