1
1
package scala .build .options
2
-
3
2
import coursier .cache .{ArchiveCache , FileCache }
4
- import coursier .core .Version
3
+ import coursier .core .{ Version , Versions => CoreVersions }
5
4
import coursier .jvm .{JavaHome , JvmCache , JvmIndex }
6
5
import coursier .util .{Artifact , Task }
6
+ import coursier .{Module , Versions }
7
7
import dependency ._
8
8
9
9
import java .math .BigInteger
@@ -13,15 +13,10 @@ import java.security.MessageDigest
13
13
14
14
import scala .build .EitherCps .{either , value }
15
15
import scala .build .blooprifle .VersionUtil .parseJavaVersion
16
- import scala .build .errors .{
17
- BuildException ,
18
- Diagnostic ,
19
- InvalidBinaryScalaVersionError ,
20
- NoValidScalaVersionFoundError ,
21
- UnsupportedScalaVersionError
22
- }
16
+ import scala .build .errors ._
23
17
import scala .build .internal .Constants ._
24
18
import scala .build .internal .CsLoggerUtil ._
19
+ import scala .build .internal .ScalaParse .scala2NightlyRegex
25
20
import scala .build .internal .{OsLibc , StableScalaVersion , Util }
26
21
import scala .build .options .validation .BuildOptionsRule
27
22
import scala .build .{Artifacts , Logger , Os , Position , Positioned }
@@ -230,7 +225,7 @@ final case class BuildOptions(
230
225
private def defaultStableScalaVersions =
231
226
Seq (defaultScala212Version, defaultScala213Version, defaultScalaVersion)
232
227
233
- private def latestSupportedScalaVersion (): Seq [Version ] = {
228
+ private def latestSupportedStableScalaVersion (): Seq [Version ] = {
234
229
235
230
val cache = finalCache.withMessage(" Getting list of Scala CLI-supported Scala versions" )
236
231
val supportedScalaVersionsUrl = scalaOptions.scalaVersionsUrl
@@ -298,30 +293,42 @@ final case class BuildOptions(
298
293
def finalRepositories : Seq [String ] =
299
294
classPathOptions.extraRepositories ++ internal.localRepository.toSeq
300
295
301
- private def computeScalaVersions (
302
- scalaVersion : Option [String ],
303
- scalaBinaryVersion : Option [String ]
296
+ private lazy val maxSupportedStableScalaVersions = latestSupportedStableScalaVersion()
297
+
298
+ private lazy val latestSupportedStableVersions = maxSupportedStableScalaVersions.map(_.repr)
299
+
300
+ /** @param scalaVersionArg
301
+ * the command line, using directive, or default argument passed as scala version
302
+ * @param scalaBinaryVersionArg
303
+ * the command line, using directive, or default argument passed as scala Binary version
304
+ * @return
305
+ * Either a BuildException or the calculated (ScalaVersion, ScalaBinaryVersion) tuple
306
+ */
307
+ private def turnScalaVersionArgToScalaVersions (
308
+ scalaVersionArg : Option [String ],
309
+ scalaBinaryVersionArg : Option [String ]
304
310
): Either [BuildException , (String , String )] = either {
305
- lazy val allVersions = {
311
+ def isSupportedVersion (version : String ): Boolean =
312
+ version.startsWith(" 2.12." ) || version.startsWith(" 2.13." ) || version.startsWith(" 3." )
313
+ lazy val allStableVersions = {
306
314
import coursier ._
307
- import scala .concurrent .ExecutionContext .{global => ec }
308
315
val modules = {
309
316
def scala2 = mod " org.scala-lang:scala-library "
310
317
// No unstable, that *ought* not to be a problem down-the-line…?
311
318
def scala3 = mod " org.scala-lang:scala3-library_3 "
312
- if (scalaVersion.contains(" 2" ) || scalaVersion.exists(_.startsWith(" 2." ))) Seq (scala2)
313
- else if (scalaVersion.contains(" 3" ) || scalaVersion.exists(_.startsWith(" 3." ))) Seq (scala3)
319
+ if (scalaVersionArg.contains(" 2" ) || scalaVersionArg.exists(_.startsWith(" 2." ))) Seq (scala2)
320
+ else if (scalaVersionArg.contains(" 3" ) || scalaVersionArg.exists(_.startsWith(" 3." )))
321
+ Seq (scala3)
314
322
else Seq (scala2, scala3)
315
323
}
316
324
def isStable (v : String ): Boolean =
317
325
! v.endsWith(" -NIGHTLY" ) && ! v.contains(" -RC" )
318
326
def moduleVersions (mod : Module ): Seq [String ] = {
319
- val cache = finalCache.withMessage(" Getting Scala version list" )
320
- val res = cache.logger.use {
321
- try Versions (cache)
327
+ val res = finalCache.logger.use {
328
+ try Versions (finalCache)
322
329
.withModule(mod)
323
330
.result()
324
- .unsafeRun()(ec)
331
+ .unsafeRun()(finalCache. ec)
325
332
catch {
326
333
case NonFatal (e) => throw new Exception (e)
327
334
}
@@ -330,53 +337,187 @@ final case class BuildOptions(
330
337
}
331
338
modules.flatMap(moduleVersions).distinct
332
339
}
333
- def matchNewestScalaVersion (sv : Option [String ]) = {
334
- lazy val maxSupportedScalaVersions = latestSupportedScalaVersion()
335
340
336
- sv match {
337
- case Some (sv0) =>
338
- val prefix = if (sv0.endsWith(" ." )) sv0 else sv0 + " ."
339
- val matchingVersions = allVersions.filter(_.startsWith(prefix)).map(Version (_))
341
+ def matchNewestStableScalaVersion (maybeScalaVersionStringArg : Option [String ])
342
+ : Either [ScalaVersionError , String ] =
343
+ maybeScalaVersionStringArg match {
344
+ case Some (scalaVersionStringArg) =>
345
+ val prefix =
346
+ if (Util .isFullScalaVersion(scalaVersionStringArg)) scalaVersionStringArg
347
+ else if (scalaVersionStringArg.endsWith(" ." )) scalaVersionStringArg
348
+ else scalaVersionStringArg + " ."
349
+ val matchingVersions = allStableVersions.filter(_.startsWith(prefix)).map(Version (_))
340
350
if (matchingVersions.isEmpty)
341
- Left (new InvalidBinaryScalaVersionError (sv0))
351
+ Left (new InvalidBinaryScalaVersionError (
352
+ scalaVersionStringArg,
353
+ latestSupportedStableVersions
354
+ ))
342
355
else {
343
- val validMaxVersions = maxSupportedScalaVersions
356
+ val validMaxVersions = maxSupportedStableScalaVersions
344
357
.filter(_.repr.startsWith(prefix))
345
358
val validMatchingVersions = {
346
359
val filtered = matchingVersions.filter(v => validMaxVersions.exists(v <= _))
347
360
if (filtered.isEmpty) matchingVersions
348
361
else filtered
349
- }
362
+ }.filter(v => isSupportedVersion(v.repr))
350
363
if (validMatchingVersions.isEmpty)
351
- Left (new UnsupportedScalaVersionError (sv0))
364
+ Left (new UnsupportedScalaVersionError (
365
+ scalaVersionStringArg,
366
+ latestSupportedStableVersions
367
+ ))
352
368
else
353
369
Right (validMatchingVersions.max.repr)
354
370
}
355
371
case None =>
356
- val validVersions = allVersions
372
+ val validVersions = allStableVersions
357
373
.map(Version (_))
358
- .filter(v => maxSupportedScalaVersions .exists(v <= _))
374
+ .filter(v => maxSupportedStableScalaVersions .exists(v <= _))
359
375
if (validVersions.isEmpty)
360
- Left (new NoValidScalaVersionFoundError (allVersions))
376
+ Left (new NoValidScalaVersionFoundError (
377
+ allStableVersions,
378
+ latestSupportedStableVersions
379
+ ))
361
380
else
362
381
Right (validVersions.max.repr)
363
382
}
383
+
384
+ val scalaVersion = value(matchNewestStableScalaVersion(scalaVersionArg))
385
+ val scalaBinaryVersion = scalaBinaryVersionArg.getOrElse(ScalaVersion .binary(scalaVersion))
386
+ (scalaVersion, scalaBinaryVersion)
387
+ }
388
+
389
+ private def latestScalaVersionFrom (
390
+ versions : CoreVersions ,
391
+ desc : String
392
+ ): Either [scala.build.errors.ScalaVersionError , String ] =
393
+ versions.latest(coursier.core.Latest .Release ) match {
394
+ case Some (versionString) => Right (versionString)
395
+ case None =>
396
+ val msg =
397
+ s " Unable to find matching version for $desc in available version: ${versions.available.mkString(" , " )}. " +
398
+ " This error may indicate a network or other problem accessing repository."
399
+ Left (new ScalaVersionError (msg))
364
400
}
365
- val maybeSv = scalaVersion match {
366
- case None => matchNewestScalaVersion(None )
367
- case Some (sv0) =>
368
- if (Util .isFullScalaVersion(sv0)) Right (sv0)
369
- else matchNewestScalaVersion(Some (sv0))
401
+
402
+ /** @return
403
+ * Either a BuildException or the calculated (ScalaVersion, ScalaBinaryVersion) tuple
404
+ */
405
+ private def computeLatestScalaThreeNightlyVersions (): Either [BuildException , (String , String )] =
406
+ either {
407
+ import coursier .Versions
408
+ import coursier ._
409
+
410
+ val moduleVersion : Either [ScalaVersionError , String ] = {
411
+ def scala3 = mod " org.scala-lang:scala3-library_3 "
412
+ val res = finalCache.logger.use {
413
+ Versions (finalCache)
414
+ .withModule(scala3)
415
+ .result()
416
+ .unsafeRun()(finalCache.ec)
417
+ }
418
+ latestScalaVersionFrom(res.versions, " latest Scala 3 nightly build" )
419
+ }
420
+
421
+ val scalaVersion = value(moduleVersion)
422
+ val scalaBinaryVersion = ScalaVersion .binary(scalaVersion)
423
+ (scalaVersion, scalaBinaryVersion)
370
424
}
371
425
372
- val sv = value(maybeSv)
373
- val sbv = scalaBinaryVersion.getOrElse(ScalaVersion .binary(sv))
374
- (sv, sbv)
426
+ /** @return
427
+ * Either a BuildException or the calculated (ScalaVersion, ScalaBinaryVersion) tuple
428
+ */
429
+ private def computeLatestScalaTwoNightlyVersions (): Either [BuildException , (String , String )] =
430
+ either {
431
+ import coursier .Versions
432
+ import coursier ._
433
+
434
+ val moduleVersion : Either [ScalaVersionError , String ] = {
435
+ def scalaNightly2Module : Module = mod " org.scala-lang:scala-library "
436
+ val res = finalCache.logger.use {
437
+ Versions (finalCache)
438
+ .withModule(scalaNightly2Module)
439
+ .withRepositories(Seq (coursier.Repositories .scalaIntegration))
440
+ .result()
441
+ .unsafeRun()(finalCache.ec)
442
+ }
443
+ latestScalaVersionFrom(res.versions, " latest Scala 2 nightly build" )
444
+ }
445
+
446
+ val scalaVersion = value(moduleVersion)
447
+ val scalaBinaryVersion = ScalaVersion .binary(scalaVersion)
448
+ (scalaVersion, scalaBinaryVersion)
449
+ }
450
+
451
+ private def turnScala2NightlyVersionArgToVersions (versionString : String )
452
+ : Either [BuildException , (String , String )] = either {
453
+
454
+ val moduleVersion : Either [ScalaVersionError , String ] = {
455
+ import coursier ._
456
+ def scalaNightly2Module : Module = mod " org.scala-lang:scala-library "
457
+ val res = finalCache.logger.use {
458
+ Versions (finalCache)
459
+ .withModule(scalaNightly2Module)
460
+ .withRepositories(Seq (coursier.Repositories .scalaIntegration))
461
+ .result()
462
+ .unsafeRun()(finalCache.ec)
463
+ }
464
+ if (res.versions.available.contains(versionString)) Right (versionString)
465
+ else
466
+ Left (
467
+ new NoValidScalaVersionFoundError (res.versions.available, latestSupportedStableVersions)
468
+ )
469
+ }
470
+
471
+ val scalaVersion = value(moduleVersion)
472
+ val scalaBinaryVersion = ScalaVersion .binary(scalaVersion)
473
+ (scalaVersion, scalaBinaryVersion)
474
+ }
475
+
476
+ private def turnScala3NightlyVersionArgIntoVersion (versionString : String )
477
+ : Either [BuildException , (String , String )] = either {
478
+ val moduleVersion : Either [ScalaVersionError , String ] = {
479
+ import coursier ._
480
+ def scala3 = mod " org.scala-lang:scala3-library_3 "
481
+ val res = finalCache.logger.use {
482
+ Versions (finalCache)
483
+ .withModule(scala3)
484
+ .result()
485
+ .unsafeRun()(finalCache.ec)
486
+ }
487
+ if (res.versions.available.contains(versionString)) Right (versionString)
488
+ else
489
+ Left (
490
+ new NoValidScalaVersionFoundError (res.versions.available, latestSupportedStableVersions)
491
+ )
492
+ }
493
+
494
+ val scalaVersion = value(moduleVersion)
495
+ val scalaBinaryVersion = ScalaVersion .binary(scalaVersion)
496
+ (scalaVersion, scalaBinaryVersion)
375
497
}
376
498
377
499
lazy val scalaParams : Either [BuildException , ScalaParameters ] = either {
500
+ def isScala2Nightly (version : String ): Boolean =
501
+ scala2NightlyRegex.unapplySeq(version).isDefined
502
+ def isScala3Nightly (version : String ): Boolean =
503
+ version.startsWith(" 3" ) && version.endsWith(" -NIGHTLY" )
504
+
378
505
val (scalaVersion, scalaBinaryVersion) =
379
- value(computeScalaVersions(scalaOptions.scalaVersion, scalaOptions.scalaBinaryVersion))
506
+ value {
507
+ scalaOptions.scalaVersion match {
508
+ case Some (" 3.nightly" ) => computeLatestScalaThreeNightlyVersions()
509
+ case Some (" 2.nightly" ) => computeLatestScalaTwoNightlyVersions()
510
+ case Some (versionString) if isScala3Nightly(versionString) =>
511
+ turnScala3NightlyVersionArgIntoVersion(versionString)
512
+ case Some (versionString) if isScala2Nightly(versionString) =>
513
+ turnScala2NightlyVersionArgToVersions(versionString)
514
+ case _ => turnScalaVersionArgToScalaVersions(
515
+ scalaOptions.scalaVersion,
516
+ scalaOptions.scalaBinaryVersion
517
+ )
518
+ }
519
+ }
520
+
380
521
val maybePlatformSuffix = platform.value match {
381
522
case Platform .JVM => None
382
523
case Platform .JS => Some (scalaJsOptions.platformSuffix)
0 commit comments