Skip to content

Commit

Permalink
Ensure vague Scala versions are capped at defaults (#3259)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gedochao authored Nov 21, 2024
1 parent eec8bde commit e317435
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 89 deletions.
2 changes: 2 additions & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,8 @@ trait Core extends ScalaCliCrossSbtModule
| def defaultScalaVersion = "${Scala.defaultUser}"
| def defaultScala212Version = "${Scala.scala212}"
| def defaultScala213Version = "${Scala.scala213}"
| def scala3NextRcVersion = "${Scala.scala3NextRc}"
| def scala3NextPrefix = "${Scala.scala3NextPrefix}"
| def scala3LtsPrefix = "${Scala.scala3LtsPrefix}"
|
| def workspaceDirName = "$workspaceDirName"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import scala.build.internal.Regexes.scala2NightlyRegex
import scala.build.options.{
BuildOptions,
BuildRequirements,
ClassPathOptions,
InternalOptions,
MaybeScalaVersion,
ScalaOptions,
Expand Down Expand Up @@ -318,34 +319,61 @@ class BuildOptionsTests extends TestUtil.ScalaCliBuildSuite {
expect(scalaParams == expectedScalaParams)
}

for {
(prefix, defaultMatchingVersion) <- Seq(
"2.12" -> defaultScala212Version,
"2.13" -> defaultScala213Version,
"3" -> defaultScalaVersion
)
} {
val options = BuildOptions(
scalaOptions = ScalaOptions(
scalaVersion = Some(prefix).map(MaybeScalaVersion(_))
),
internal = InternalOptions(
cache = Some(FileCache().withTtl(0.seconds))
{
val cache = FileCache().withTtl(0.seconds)
val repositories = BuildOptions(
internal = InternalOptions(cache = Some(cache)),
classPathOptions =
ClassPathOptions(extraRepositories = Seq(coursier.Repositories.scalaIntegration.root))
).finalRepositories.orThrow
val allScalaVersions = ScalaVersionUtil.allMatchingVersions(None, cache, repositories)
for {
(prefix, defaultMatchingVersion, predefinedDefaultScalaVersion) <- {
val scala2Nightlies = allScalaVersions.filter(ScalaVersionUtil.isScala2Nightly)
val latest212Nightly = scala2Nightlies.filter(_.startsWith("2.12")).maxBy(Version(_))
val latest213Nightly = scala2Nightlies.filter(_.startsWith("2.13")).maxBy(Version(_))
val latestScala3NextNightly =
allScalaVersions
.filter(ScalaVersionUtil.isScala3Nightly)
.filter(_.startsWith(scala3NextPrefix))
.maxBy(Version(_))
Seq(
("2.12", defaultScala212Version, None),
("2.12", defaultScala212Version, Some(latest212Nightly)),
("2.13", defaultScala213Version, None),
("2.13", defaultScala213Version, Some(latest213Nightly)),
("3", defaultScalaVersion, None),
(scala3NextPrefix, defaultScalaVersion, None),
(scala3NextPrefix, defaultScalaVersion, Some(latestScala3NextNightly))
)
}
options = BuildOptions(
scalaOptions = ScalaOptions(
scalaVersion = Some(prefix).map(MaybeScalaVersion(_)),
defaultScalaVersion = predefinedDefaultScalaVersion
),
internal = InternalOptions(
cache = Some(cache)
),
classPathOptions = ClassPathOptions(
extraRepositories = Seq(coursier.Repositories.scalaIntegration.root)
)
)
)

val latestMatchingVersion = ScalaVersionUtil
.allMatchingVersions(None, options.finalCache, options.finalRepositories.orThrow)
.filter(ScalaVersionUtil.isStable)
.filter(_.startsWith(prefix))
.maxBy(Version(_))

test(
s"-S $prefix should chose the latest version ($latestMatchingVersion), not necessarily the default ($defaultMatchingVersion)"
) {
latestMatchingVersion = allScalaVersions
.filter(ScalaVersionUtil.isStable)
.filter(_.startsWith(prefix))
.maxBy(Version(_))
expectedVersion = predefinedDefaultScalaVersion.getOrElse(defaultMatchingVersion)
expectedVersionDescription =
if expectedVersion == defaultMatchingVersion then "default" else "overridden default"
launcherDefaultVersionDescription = if expectedVersion == defaultMatchingVersion then ""
else s"or the launcher default ($defaultMatchingVersion)"
testDescription =
s"-S $prefix should choose the $expectedVersionDescription version ($expectedVersion), not necessarily the latest stable ($latestMatchingVersion) $launcherDefaultVersionDescription"
} test(testDescription) {
val scalaParams = options.scalaParams.orThrow.getOrElse(???)

val expectedScalaParams = ScalaParameters(latestMatchingVersion)
val expectedScalaParams = ScalaParameters(expectedVersion)

expect(scalaParams == expectedScalaParams, s"expected $expectedScalaParams, got $scalaParams")
}
Expand Down
137 changes: 75 additions & 62 deletions modules/options/src/main/scala/scala/build/options/BuildOptions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -317,69 +317,82 @@ final case class BuildOptions(
scalaOptions.defaultScalaVersion.getOrElse(Constants.defaultScalaVersion)
)

val svOpt: Option[String] = scalaOptions.scalaVersion match {
case Some(MaybeScalaVersion(None)) =>
None
// Do not validate Scala version in offline mode
case Some(MaybeScalaVersion(Some(svInput))) if internal.offline.getOrElse(false) =>
Some(svInput)
// Do not validate Scala version if it is a default one
case Some(MaybeScalaVersion(Some(svInput))) if defaultVersions.contains(svInput) =>
Some(svInput)
case Some(MaybeScalaVersion(Some(svInput))) =>
val sv = value {
svInput match {
case sv if ScalaVersionUtil.scala3Lts.contains(sv) =>
ScalaVersionUtil.validateStable(
Constants.scala3LtsPrefix,
cache,
repositories
)
case sv if ScalaVersionUtil.scala2Lts.contains(sv) =>
Left(new ScalaVersionError(
s"Invalid Scala version: $sv. There is no official LTS version for Scala 2."
))
case sv if sv == ScalaVersionUtil.scala3Nightly =>
ScalaVersionUtil.GetNightly.scala3(cache)
case scala3NightlyNicknameRegex(threeSubBinaryNum) =>
ScalaVersionUtil.GetNightly.scala3X(
threeSubBinaryNum,
cache
)
case vs if ScalaVersionUtil.scala213Nightly.contains(vs) =>
ScalaVersionUtil.GetNightly.scala2("2.13", cache)
case sv if sv == ScalaVersionUtil.scala212Nightly =>
ScalaVersionUtil.GetNightly.scala2("2.12", cache)
case versionString if ScalaVersionUtil.isScala3Nightly(versionString) =>
ScalaVersionUtil.CheckNightly.scala3(
versionString,
cache
)
.map(_ => versionString)
case versionString if ScalaVersionUtil.isScala2Nightly(versionString) =>
ScalaVersionUtil.CheckNightly.scala2(
versionString,
cache
)
.map(_ => versionString)
case versionString if versionString.exists(_.isLetter) =>
ScalaVersionUtil.validateNonStable(
versionString,
cache,
repositories
)
case versionString =>
ScalaVersionUtil.validateStable(
versionString,
cache,
repositories
)
val svOpt: Option[String] =
scalaOptions.scalaVersion -> scalaOptions.defaultScalaVersion match {
case (Some(MaybeScalaVersion(None)), _) =>
None
// Do not validate Scala version in offline mode
case (Some(MaybeScalaVersion(Some(svInput))), _) if internal.offline.getOrElse(false) =>
Some(svInput)
// Do not validate Scala version if it is a default one
case (Some(MaybeScalaVersion(Some(svInput))), _) if defaultVersions.contains(svInput) =>
Some(svInput)
case (Some(MaybeScalaVersion(Some(svInput))), Some(predefinedScalaVersion))
if predefinedScalaVersion.startsWith(svInput) &&
(svInput == "3" || svInput == Constants.scala3NextPrefix ||
svInput == "2.13" || svInput == "2.12") =>
Some(predefinedScalaVersion)
case (Some(MaybeScalaVersion(Some(svInput))), None)
if svInput == "3" || svInput == Constants.scala3NextPrefix =>
Some(Constants.defaultScalaVersion)
case (Some(MaybeScalaVersion(Some(svInput))), None) if svInput == "2.13" =>
Some(Constants.defaultScala213Version)
case (Some(MaybeScalaVersion(Some(svInput))), None) if svInput == "2.12" =>
Some(Constants.defaultScala212Version)
case (Some(MaybeScalaVersion(Some(svInput))), _) =>
val sv = value {
svInput match {
case sv if ScalaVersionUtil.scala3Lts.contains(sv) =>
ScalaVersionUtil.validateStable(
Constants.scala3LtsPrefix,
cache,
repositories
)
case sv if ScalaVersionUtil.scala2Lts.contains(sv) =>
Left(new ScalaVersionError(
s"Invalid Scala version: $sv. There is no official LTS version for Scala 2."
))
case sv if sv == ScalaVersionUtil.scala3Nightly =>
ScalaVersionUtil.GetNightly.scala3(cache)
case scala3NightlyNicknameRegex(threeSubBinaryNum) =>
ScalaVersionUtil.GetNightly.scala3X(
threeSubBinaryNum,
cache
)
case vs if ScalaVersionUtil.scala213Nightly.contains(vs) =>
ScalaVersionUtil.GetNightly.scala2("2.13", cache)
case sv if sv == ScalaVersionUtil.scala212Nightly =>
ScalaVersionUtil.GetNightly.scala2("2.12", cache)
case versionString if ScalaVersionUtil.isScala3Nightly(versionString) =>
ScalaVersionUtil.CheckNightly.scala3(
versionString,
cache
)
.map(_ => versionString)
case versionString if ScalaVersionUtil.isScala2Nightly(versionString) =>
ScalaVersionUtil.CheckNightly.scala2(
versionString,
cache
)
.map(_ => versionString)
case versionString if versionString.exists(_.isLetter) =>
ScalaVersionUtil.validateNonStable(
versionString,
cache,
repositories
)
case versionString =>
ScalaVersionUtil.validateStable(
versionString,
cache,
repositories
)
}
}
}
Some(sv)

case None => Some(scalaOptions.defaultScalaVersion.getOrElse(Constants.defaultScalaVersion))
}
Some(sv)
case (None, Some(predefinedScalaVersion)) => Some(predefinedScalaVersion)
case _ => Some(Constants.defaultScalaVersion)
}

svOpt match {
case Some(scalaVersion) =>
Expand Down
5 changes: 3 additions & 2 deletions project/deps.sc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ object Scala {
def scala213 = "2.13.15"
def runnerScala3 = "3.0.2" // the newest version that is compatible with all Scala 3.x versions
def scala3LtsPrefix = "3.3" // used for the LTS version tags
def scala3Lts = s"$scala3LtsPrefix.4" // the LTS version currently used in the build
def scala3Next = "3.5.2" // the newest/next version of Scala
def scala3Lts = s"$scala3LtsPrefix.4" // the LTS version currently used in the build
def scala3NextPrefix = "3.5"
def scala3Next = s"$scala3NextPrefix.2" // the newest/next version of Scala
def scala3NextAnnounced = scala3Next // the newest/next version of Scala that's been announced
def scala3NextRc = "3.6.2-RC1" // the latest RC version of Scala Next

Expand Down

0 comments on commit e317435

Please sign in to comment.