sbt.internal.librarymanagement.cross.CrossVersionUtil.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bleep-nosbt_3 Show documentation
Show all versions of bleep-nosbt_3 Show documentation
A bleeping fast scala build tool!
package bleep.nosbt.internal.librarymanagement
package cross
import bleep.nosbt.librarymanagement.ScalaArtifacts
object CrossVersionUtil {
val trueString = "true"
val falseString = "false"
val fullString = "full"
val noneString = "none"
val disabledString = "disabled"
val binaryString = "binary"
val TransitionScalaVersion = "2.10" // ...but scalac doesn't until Scala 2.10
val TransitionSbtVersion = "0.12"
def isFull(s: String): Boolean = (s == trueString) || (s == fullString)
def isDisabled(s: String): Boolean =
(s == falseString) || (s == noneString) || (s == disabledString)
def isBinary(s: String): Boolean = (s == binaryString)
private val longPattern = """\d{1,19}"""
private val basicVersion = raw"""($longPattern)\.($longPattern)\.($longPattern)"""
private val tagPattern = raw"""(?:\w+(?:\.\w+)*)"""
private val ReleaseV = raw"""$basicVersion(-\d+)?""".r
private[nosbt] val BinCompatV = raw"""$basicVersion(-$tagPattern)?-bin(-.*)?""".r
private val CandidateV = raw"""$basicVersion(-RC\d+)""".r
private val NonReleaseV_n = raw"""$basicVersion((?:-$tagPattern)*)""".r // 0-n word suffixes, with leading dashes
private val NonReleaseV_1 = raw"""$basicVersion(-$tagPattern)""".r // 1 word suffix, after a dash
private[nosbt] val PartialVersion = raw"""($longPattern)\.($longPattern)(?:\..+)?""".r
private[nosbt] def isSbtApiCompatible(v: String): Boolean = sbtApiVersion(v).isDefined
/**
* Returns sbt binary interface x.y API compatible with the given version string v.
* RCs for x.y.0 are considered API compatible.
* Compatible versions include 0.12.0-1 and 0.12.0-RC1 for Some(0, 12).
*/
private[nosbt] def sbtApiVersion(v: String): Option[(Long, Long)] = v match {
case ReleaseV(x, y, _, _) => Some(sbtApiVersion(x.toLong, y.toLong))
case CandidateV(x, y, _, _) => Some(sbtApiVersion(x.toLong, y.toLong))
case NonReleaseV_n(x, y, z, _) if x.toLong == 0 && z.toLong > 0 =>
Some(sbtApiVersion(x.toLong, y.toLong))
case NonReleaseV_n(x, y, z, _) if x.toLong > 0 && (y.toLong > 0 || z.toLong > 0) =>
Some(sbtApiVersion(x.toLong, y.toLong))
case _ => None
}
private def sbtApiVersion(x: Long, y: Long) = {
// Prior to sbt 1 the "sbt api version" was the X.Y in the X.Y.Z version.
// For example for sbt 0.13.x releases, the sbt api version is 0.13
// As of sbt 1 it is now X.0.
// This means, for example, that all versions of sbt 1.x have sbt api version 1.0
if (x > 0) (x, 0L) else (x, y)
}
private[nosbt] def isScalaApiCompatible(v: String): Boolean = scalaApiVersion(v).isDefined
/**
* Returns Scala binary interface x.y API compatible with the given version string v.
* Compatible versions include 2.10.0-1 and 2.10.1-M1 for Some(2, 10), but not 2.10.0-RC1.
*/
private[nosbt] def scalaApiVersion(v: String): Option[(Long, Long)] = v match {
case ReleaseV(x, y, _, _) => Some((x.toLong, y.toLong))
case BinCompatV(x, y, _, _, _) => Some((x.toLong, y.toLong))
case NonReleaseV_1(x, y, z, _) if z.toInt > 0 => Some((x.toLong, y.toLong))
case _ => None
}
private[nosbt] def partialVersion(s: String): Option[(Long, Long)] =
s match {
case PartialVersion(major, minor) => Some((major.toLong, minor.toLong))
case _ => None
}
private[nosbt] def binaryScala3Version(full: String): String = full match {
case ReleaseV(maj, _, _, _) => maj
case NonReleaseV_n(maj, min, patch, _) if min.toLong > 0 || patch.toLong > 0 => maj
case BinCompatV(maj, min, patch, stageOrNull, _) =>
val stage = if (stageOrNull != null) stageOrNull else ""
binaryScala3Version(s"$maj.$min.$patch$stage")
case _ => full
}
// Uses the following rules:
//
// - Forwards and backwards compatibility is guaranteed for Scala 2.N.x (https://docs.scala-lang.org/overviews/core/binary-compatibility-of-scala-releases.html)
//
// - A Scala compiler in version 3.x1.y1 is able to read TASTy files produced by another compiler in version 3.x2.y2 if x1 >= x2 (https://docs.scala-lang.org/scala3/reference/language-versions/binary-compatibility.html)
//
// - For non-stable Scala 3 versions, compiler versions can read TASTy in an older stable format but their TASTY versions are not compatible between each other even if the compilers have the same minor version (https://docs.scala-lang.org/scala3/reference/language-versions/binary-compatibility.html)
//
private[nosbt] def isScalaBinaryCompatibleWith(newVersion: String, origVersion: String): Boolean = {
(newVersion, origVersion) match {
case (NonReleaseV_n("2", _, _, _), NonReleaseV_n("2", _, _, _)) =>
val api1 = scalaApiVersion(newVersion)
val api2 = scalaApiVersion(origVersion)
(api1.isDefined && api1 == api2) || (newVersion == origVersion)
case (ReleaseV(nMaj, nMin, _, _), ReleaseV(oMaj, oMin, _, _))
if nMaj == oMaj && nMaj.toLong >= 3 =>
nMin.toInt >= oMin.toInt
case (NonReleaseV_1(nMaj, nMin, _, _), ReleaseV(oMaj, oMin, _, _))
if nMaj == oMaj && nMaj.toLong >= 3 =>
nMin.toInt > oMin.toInt
case _ =>
newVersion == origVersion
}
}
def binaryScalaVersion(full: String): String = {
if (ScalaArtifacts.isScala3(full)) binaryScala3Version(full)
else
binaryVersionWithApi(full, TransitionScalaVersion)(scalaApiVersion) // Scala 2 binary version
}
def binarySbtVersion(full: String): String =
binaryVersionWithApi(full, TransitionSbtVersion)(sbtApiVersion)
private[this] def isNewer(major: Long, minor: Long, minMajor: Long, minMinor: Long): Boolean =
major > minMajor || (major == minMajor && minor >= minMinor)
private[this] def binaryVersionWithApi(full: String, cutoff: String)(
apiVersion: String => Option[(Long, Long)]
): String = {
(apiVersion(full), partialVersion(cutoff)) match {
case (Some((major, minor)), None) => s"$major.$minor"
case (Some((major, minor)), Some((minMajor, minMinor)))
if isNewer(major, minor, minMajor, minMinor) =>
s"$major.$minor"
case _ => full
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy