Skip to content

Commit 3afca5f

Browse files
authored
Merge pull request #2860 from Gedochao/feature/override-default-scala-launcher-option
Add launcher options allowing to override the default Scala version
2 parents 3e59ef1 + d5a0190 commit 3afca5f

File tree

20 files changed

+341
-85
lines changed

20 files changed

+341
-85
lines changed

modules/build/src/main/scala/scala/build/preprocessing/ScriptPreprocessor.scala

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,25 +158,23 @@ case object ScriptPreprocessor extends Preprocessor {
158158
* code wrapper compatible with provided BuildOptions
159159
*/
160160
def getScriptWrapper(buildOptions: BuildOptions): CodeWrapper = {
161-
val scalaVersionOpt = for {
162-
maybeScalaVersion <- buildOptions.scalaOptions.scalaVersion
163-
scalaVersion <- maybeScalaVersion.versionOpt
164-
} yield scalaVersion
161+
val effectiveScalaVersion =
162+
buildOptions.scalaOptions.scalaVersion.flatMap(_.versionOpt)
163+
.orElse(buildOptions.scalaOptions.defaultScalaVersion)
164+
.getOrElse(Constants.defaultScalaVersion)
165165

166166
def objectCodeWrapperForScalaVersion =
167167
// AppObjectWrapper only introduces the 'main.sc' restriction when used in Scala 3, there's no gain in using it with Scala 3
168-
if (scalaVersionOpt.exists(_.startsWith("2")))
169-
AppCodeWrapper
170-
else
171-
ObjectCodeWrapper
168+
if effectiveScalaVersion.startsWith("2") then AppCodeWrapper
169+
else ObjectCodeWrapper
172170

173171
buildOptions.scriptOptions.forceObjectWrapper match {
174172
case Some(true) => objectCodeWrapperForScalaVersion
175173
case _ =>
176174
buildOptions.scalaOptions.platform.map(_.value) match {
177-
case Some(_: Platform.JS.type) => objectCodeWrapperForScalaVersion
178-
case _ if scalaVersionOpt.exists(_.startsWith("2")) => AppCodeWrapper
179-
case _ => ClassCodeWrapper
175+
case Some(_: Platform.JS.type) => objectCodeWrapperForScalaVersion
176+
case _ if effectiveScalaVersion.startsWith("2") => AppCodeWrapper
177+
case _ => ClassCodeWrapper
180178
}
181179
}
182180
}

modules/cli/src/main/scala/scala/cli/ScalaCli.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import scala.cli.javaLauncher.JavaLauncherCli
1616
import scala.cli.launcher.{LauncherCli, LauncherOptions, PowerOptions}
1717
import scala.cli.publish.BouncycastleSignerMaker
1818
import scala.cli.util.ConfigDbUtils
19+
import scala.collection.mutable.ListBuffer
1920
import scala.util.Properties
2021

2122
object ScalaCli {
@@ -53,6 +54,11 @@ object ScalaCli {
5354
private def isGraalvmNativeImage: Boolean =
5455
sys.props.contains("org.graalvm.nativeimage.imagecode")
5556

57+
private var defaultScalaVersion: Option[String] = None
58+
val launcherPredefinedRepositories: ListBuffer[String] = ListBuffer.empty
59+
60+
def getDefaultScalaVersion: String = defaultScalaVersion.getOrElse(Constants.defaultScalaVersion)
61+
5662
private def partitionArgs(args: Array[String]): (Array[String], Array[String]) = {
5763
val systemProps = args.takeWhile(_.startsWith("-D"))
5864
(systemProps, args.drop(systemProps.size))
@@ -237,6 +243,10 @@ object ScalaCli {
237243
&& sys.props.get("scala-cli.kind").exists(_.startsWith("jvm")) =>
238244
JavaLauncherCli.runAndExit(args)
239245
case None =>
246+
if launcherOpts.cliUserScalaVersion.nonEmpty then
247+
defaultScalaVersion = launcherOpts.cliUserScalaVersion
248+
if launcherOpts.cliPredefinedRepository.nonEmpty then
249+
launcherPredefinedRepositories.addAll(launcherOpts.cliPredefinedRepository)
240250
if launcherOpts.powerOptions.power then
241251
isSipScala = false
242252
args0.toArray

modules/cli/src/main/scala/scala/cli/commands/ScalaCommand.scala

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ abstract class ScalaCommand[T <: HasGlobalOptions](implicit myParser: Parser[T],
3838
private val globalOptionsAtomic: AtomicReference[GlobalOptions] =
3939
new AtomicReference(GlobalOptions.default)
4040

41-
private def globalOptions: GlobalOptions = globalOptionsAtomic.get()
41+
private def globalOptions: GlobalOptions = globalOptionsAtomic.get()
42+
protected def defaultScalaVersion: String = ScalaCli.getDefaultScalaVersion
4243

4344
def sharedOptions(t: T): Option[SharedOptions] = // hello borked unused warning
4445
None
@@ -133,7 +134,7 @@ abstract class ScalaCommand[T <: HasGlobalOptions](implicit myParser: Parser[T],
133134
.toOption
134135
.flatten
135136
.map(_.scalaVersion)
136-
.getOrElse(Constants.defaultScalaVersion)
137+
.getOrElse(defaultScalaVersion)
137138
val (fromIndex, completions) = cache.logger.use {
138139
coursier.complete.Complete(cache)
139140
.withInput(prefix)
@@ -313,13 +314,20 @@ abstract class ScalaCommand[T <: HasGlobalOptions](implicit myParser: Parser[T],
313314
* change this behaviour.
314315
*/
315316
def buildOptions(options: T): Option[BuildOptions] =
316-
sharedOptions(options).map(shared => shared.buildOptions().orExit(shared.logger))
317+
sharedOptions(options)
318+
.map(shared => shared.buildOptions().orExit(shared.logger))
317319

318320
protected def buildOptionsOrExit(options: T): BuildOptions =
319-
buildOptions(options).getOrElse {
320-
sharedOptions(options).foreach(_.logger.debug("build options could not be initialized"))
321-
sys.exit(1)
322-
}
321+
buildOptions(options)
322+
.map(bo =>
323+
bo.copy(scalaOptions =
324+
bo.scalaOptions.copy(defaultScalaVersion = Some(defaultScalaVersion))
325+
)
326+
)
327+
.getOrElse {
328+
sharedOptions(options).foreach(_.logger.debug("build options could not be initialized"))
329+
sys.exit(1)
330+
}
323331
override def shouldSuppressExperimentalFeatureWarnings: Boolean =
324332
globalOptions.globalSuppress.suppressExperimentalFeatureWarning
325333
.orElse {

modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,10 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
166166
}
167167

168168
def finalBuildOptions(options: PackageOptions): BuildOptions = {
169-
val finalBuildOptions = options.finalBuildOptions.orExit(options.shared.logger)
169+
val initialOptions = options.finalBuildOptions.orExit(options.shared.logger)
170+
val finalBuildOptions = initialOptions.copy(scalaOptions =
171+
initialOptions.scalaOptions.copy(defaultScalaVersion = Some(defaultScalaVersion))
172+
)
170173
val buildOptions = finalBuildOptions.copy(
171174
javaOptions = finalBuildOptions.javaOptions.copy(
172175
javaOpts =

modules/cli/src/main/scala/scala/cli/commands/repl/Repl.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import scala.build.errors.{BuildException, CantDownloadAmmoniteError, FetchingDe
1616
import scala.build.input.Inputs
1717
import scala.build.internal.{Constants, Runner}
1818
import scala.build.options.{BuildOptions, JavaOpt, MaybeScalaVersion, Scope}
19-
import scala.cli.CurrentParams
2019
import scala.cli.commands.publish.ConfigUtil.*
2120
import scala.cli.commands.run.Run.{
2221
maybePrintSimpleScalacOutput,
@@ -30,6 +29,7 @@ import scala.cli.config.{ConfigDb, Keys}
3029
import scala.cli.packaging.Library
3130
import scala.cli.util.ArgHelpers.*
3231
import scala.cli.util.ConfigDbUtils
32+
import scala.cli.{CurrentParams, ScalaCli}
3333
import scala.jdk.CollectionConverters.*
3434
import scala.util.Properties
3535

@@ -62,7 +62,7 @@ object Repl extends ScalaCommand[ReplOptions] {
6262
scalaOptions = baseOptions.scalaOptions.copy(
6363
scalaVersion = baseOptions.scalaOptions.scalaVersion
6464
.orElse {
65-
val defaultScalaVer = scala.build.internal.Constants.defaultScalaVersion
65+
val defaultScalaVer = ScalaCli.getDefaultScalaVersion
6666
val shouldDowngrade = {
6767
def needsDowngradeForAmmonite = {
6868
import coursier.core.Version

modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,10 @@ final case class SharedOptions(
406406
extraClassPath = extraRegularJarsAndClasspath,
407407
extraCompileOnlyJars = extraCompileOnlyClassPath,
408408
extraSourceJars = extraSourceJars.extractedClassPath ++ assumedSourceJars,
409-
extraRepositories = dependencies.repository.map(_.trim).filter(_.nonEmpty),
409+
extraRepositories =
410+
(dependencies.repository ++ ScalaCli.launcherPredefinedRepositories).map(_.trim).filter(
411+
_.nonEmpty
412+
),
410413
extraDependencies = ShadowingSeq.from(
411414
SharedOptions.parseDependencies(
412415
dependencies.dependency.map(Positioned.none),

modules/cli/src/main/scala/scala/cli/commands/version/Version.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import caseapp.core.help.HelpFormat
55

66
import scala.build.Logger
77
import scala.build.internal.Constants
8-
import scala.cli.CurrentParams
98
import scala.cli.commands.shared.{HelpCommandGroup, HelpGroup}
109
import scala.cli.commands.update.Update
1110
import scala.cli.commands.{CommandUtils, ScalaCommand, SpecificationLevel}
1211
import scala.cli.config.PasswordOption
1312
import scala.cli.util.ArgHelpers.*
13+
import scala.cli.{CurrentParams, ScalaCli}
1414

1515
object Version extends ScalaCommand[VersionOptions] {
1616
override def group: String = HelpCommandGroup.Miscellaneous.toString
@@ -34,7 +34,7 @@ object Version extends ScalaCommand[VersionOptions] {
3434
else None
3535
}
3636
if options.cliVersion then println(Constants.version)
37-
else if options.scalaVersion then println(Constants.defaultScalaVersion)
37+
else if options.scalaVersion then println(ScalaCli.getDefaultScalaVersion)
3838
else {
3939
println(versionInfo)
4040
if !options.offline then
@@ -51,5 +51,5 @@ object Version extends ScalaCommand[VersionOptions] {
5151
val version = Constants.version
5252
val detailedVersionOpt = Constants.detailedVersion.filter(_ != version).fold("")(" (" + _ + ")")
5353
s"""$fullRunnerName version: $version$detailedVersionOpt
54-
|Scala version (default): ${Constants.defaultScalaVersion}""".stripMargin
54+
|Scala version (default): ${ScalaCli.getDefaultScalaVersion}""".stripMargin
5555
}

modules/cli/src/main/scala/scala/cli/exportCmd/MillProjectDescriptor.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import scala.build.internal.Runner.frameworkName
1313
import scala.build.options.{BuildOptions, Platform, ScalaJsOptions, ScalaNativeOptions, Scope}
1414
import scala.build.testrunner.AsmTestRunner
1515
import scala.build.{Logger, Sources}
16+
import scala.cli.ScalaCli
1617
import scala.cli.util.SeqHelpers.*
1718

1819
final case class MillProjectDescriptor(
@@ -39,7 +40,7 @@ final case class MillProjectDescriptor(
3940

4041
val sv = options.scalaOptions.scalaVersion
4142
.flatMap(_.versionOpt) // FIXME If versionOpt is empty, the project is pure Java
42-
.getOrElse(Constants.defaultScalaVersion)
43+
.getOrElse(ScalaCli.getDefaultScalaVersion)
4344

4445
if (pureJava)
4546
MillProject()

modules/cli/src/main/scala/scala/cli/exportCmd/SbtProjectDescriptor.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import scala.build.options.{
2121
}
2222
import scala.build.testrunner.AsmTestRunner
2323
import scala.build.{Logger, Positioned, Sources}
24+
import scala.cli.ScalaCli
2425

2526
final case class SbtProjectDescriptor(
2627
sbtVersion: String,
@@ -122,7 +123,7 @@ final case class SbtProjectDescriptor(
122123
val scalaVerSetting = {
123124
val sv = options.scalaOptions.scalaVersion
124125
.flatMap(_.versionOpt) // FIXME If versionOpt is empty, the project is pure Java
125-
.getOrElse(Constants.defaultScalaVersion)
126+
.getOrElse(ScalaCli.getDefaultScalaVersion)
126127
s"""scalaVersion := "$sv""""
127128
}
128129

modules/cli/src/main/scala/scala/cli/launcher/LauncherOptions.scala

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package scala.cli.launcher
33
import caseapp.*
44

55
import scala.cli.commands.shared.HelpGroup
6-
import scala.cli.commands.tags
6+
import scala.cli.commands.{Constants, tags}
77

88
@HelpMessage("Run another Scala CLI version")
99
final case class LauncherOptions(
@@ -19,6 +19,24 @@ final case class LauncherOptions(
1919
@Hidden
2020
@Tag(tags.implementation)
2121
cliScalaVersion: Option[String] = None,
22+
@Group(HelpGroup.Launcher.toString)
23+
@HelpMessage(
24+
s"The default version of Scala used when processing user inputs (current default: ${Constants.defaultScalaVersion}). Can be overridden with --scala-version. "
25+
)
26+
@ValueDescription("version")
27+
@Hidden
28+
@Tag(tags.implementation)
29+
@Name("cliDefaultScalaVersion")
30+
cliUserScalaVersion: Option[String] = None,
31+
@Group(HelpGroup.Launcher.toString)
32+
@HelpMessage("")
33+
@Hidden
34+
@Tag(tags.implementation)
35+
@Name("r")
36+
@Name("repo")
37+
@Name("repository")
38+
@Name("predefinedRepository")
39+
cliPredefinedRepository: List[String] = Nil,
2240
@Recurse
2341
powerOptions: PowerOptions = PowerOptions()
2442
)

0 commit comments

Comments
 (0)