Skip to content

Commit

Permalink
Add a launcher option allowing to override the default Scala version
Browse files Browse the repository at this point in the history
  • Loading branch information
Gedochao committed Apr 17, 2024
1 parent d461812 commit 227da37
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,25 +158,23 @@ case object ScriptPreprocessor extends Preprocessor {
* code wrapper compatible with provided BuildOptions
*/
def getScriptWrapper(buildOptions: BuildOptions): CodeWrapper = {
val scalaVersionOpt = for {
maybeScalaVersion <- buildOptions.scalaOptions.scalaVersion
scalaVersion <- maybeScalaVersion.versionOpt
} yield scalaVersion
val effectiveScalaVersion =
buildOptions.scalaOptions.scalaVersion.flatMap(_.versionOpt)
.orElse(buildOptions.scalaOptions.defaultScalaVersion)
.getOrElse(Constants.defaultScalaVersion)

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

buildOptions.scriptOptions.forceObjectWrapper match {
case Some(true) => objectCodeWrapperForScalaVersion
case _ =>
buildOptions.scalaOptions.platform.map(_.value) match {
case Some(_: Platform.JS.type) => objectCodeWrapperForScalaVersion
case _ if scalaVersionOpt.exists(_.startsWith("2")) => AppCodeWrapper
case _ => ClassCodeWrapper
case Some(_: Platform.JS.type) => objectCodeWrapperForScalaVersion
case _ if effectiveScalaVersion.startsWith("2") => AppCodeWrapper
case _ => ClassCodeWrapper
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions modules/cli/src/main/scala/scala/cli/ScalaCli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ object ScalaCli {
private def isGraalvmNativeImage: Boolean =
sys.props.contains("org.graalvm.nativeimage.imagecode")

private var defaultScalaVersion: Option[String] = None

def getDefaultScalaVersion: String = defaultScalaVersion.getOrElse(Constants.defaultScalaVersion)

private def partitionArgs(args: Array[String]): (Array[String], Array[String]) = {
val systemProps = args.takeWhile(_.startsWith("-D"))
(systemProps, args.drop(systemProps.size))
Expand Down Expand Up @@ -237,6 +241,8 @@ object ScalaCli {
&& sys.props.get("scala-cli.kind").exists(_.startsWith("jvm")) =>
JavaLauncherCli.runAndExit(args)
case None =>
if launcherOpts.cliUserScalaVersion.nonEmpty then
defaultScalaVersion = launcherOpts.cliUserScalaVersion
if launcherOpts.powerOptions.power then
isSipScala = false
args0.toArray
Expand Down
22 changes: 15 additions & 7 deletions modules/cli/src/main/scala/scala/cli/commands/ScalaCommand.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ abstract class ScalaCommand[T <: HasGlobalOptions](implicit myParser: Parser[T],
private val globalOptionsAtomic: AtomicReference[GlobalOptions] =
new AtomicReference(GlobalOptions.default)

private def globalOptions: GlobalOptions = globalOptionsAtomic.get()
private def globalOptions: GlobalOptions = globalOptionsAtomic.get()
protected def defaultScalaVersion: String = ScalaCli.getDefaultScalaVersion

def sharedOptions(t: T): Option[SharedOptions] = // hello borked unused warning
None
Expand Down Expand Up @@ -133,7 +134,7 @@ abstract class ScalaCommand[T <: HasGlobalOptions](implicit myParser: Parser[T],
.toOption
.flatten
.map(_.scalaVersion)
.getOrElse(Constants.defaultScalaVersion)
.getOrElse(defaultScalaVersion)
val (fromIndex, completions) = cache.logger.use {
coursier.complete.Complete(cache)
.withInput(prefix)
Expand Down Expand Up @@ -313,13 +314,20 @@ abstract class ScalaCommand[T <: HasGlobalOptions](implicit myParser: Parser[T],
* change this behaviour.
*/
def buildOptions(options: T): Option[BuildOptions] =
sharedOptions(options).map(shared => shared.buildOptions().orExit(shared.logger))
sharedOptions(options)
.map(shared => shared.buildOptions().orExit(shared.logger))

protected def buildOptionsOrExit(options: T): BuildOptions =
buildOptions(options).getOrElse {
sharedOptions(options).foreach(_.logger.debug("build options could not be initialized"))
sys.exit(1)
}
buildOptions(options)
.map(bo =>
bo.copy(scalaOptions =
bo.scalaOptions.copy(defaultScalaVersion = Some(defaultScalaVersion))
)
)
.getOrElse {
sharedOptions(options).foreach(_.logger.debug("build options could not be initialized"))
sys.exit(1)
}
override def shouldSuppressExperimentalFeatureWarnings: Boolean =
globalOptions.globalSuppress.suppressExperimentalFeatureWarning
.orElse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,10 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
}

def finalBuildOptions(options: PackageOptions): BuildOptions = {
val finalBuildOptions = options.finalBuildOptions.orExit(options.shared.logger)
val initialOptions = options.finalBuildOptions.orExit(options.shared.logger)
val finalBuildOptions = initialOptions.copy(scalaOptions =
initialOptions.scalaOptions.copy(defaultScalaVersion = Some(defaultScalaVersion))
)
val buildOptions = finalBuildOptions.copy(
javaOptions = finalBuildOptions.javaOptions.copy(
javaOpts =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import caseapp.core.help.HelpFormat

import scala.build.Logger
import scala.build.internal.Constants
import scala.cli.CurrentParams
import scala.cli.commands.shared.{HelpCommandGroup, HelpGroup}
import scala.cli.commands.update.Update
import scala.cli.commands.{CommandUtils, ScalaCommand, SpecificationLevel}
import scala.cli.config.PasswordOption
import scala.cli.util.ArgHelpers.*
import scala.cli.{CurrentParams, ScalaCli}

object Version extends ScalaCommand[VersionOptions] {
override def group: String = HelpCommandGroup.Miscellaneous.toString
Expand All @@ -34,7 +34,7 @@ object Version extends ScalaCommand[VersionOptions] {
else None
}
if options.cliVersion then println(Constants.version)
else if options.scalaVersion then println(Constants.defaultScalaVersion)
else if options.scalaVersion then println(ScalaCli.getDefaultScalaVersion)
else {
println(versionInfo)
if !options.offline then
Expand All @@ -51,5 +51,5 @@ object Version extends ScalaCommand[VersionOptions] {
val version = Constants.version
val detailedVersionOpt = Constants.detailedVersion.filter(_ != version).fold("")(" (" + _ + ")")
s"""$fullRunnerName version: $version$detailedVersionOpt
|Scala version (default): ${Constants.defaultScalaVersion}""".stripMargin
|Scala version (default): ${ScalaCli.getDefaultScalaVersion}""".stripMargin
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package scala.cli.launcher
import caseapp.*

import scala.cli.commands.shared.HelpGroup
import scala.cli.commands.tags
import scala.cli.commands.{Constants, tags}

@HelpMessage("Run another Scala CLI version")
final case class LauncherOptions(
Expand All @@ -19,6 +19,15 @@ final case class LauncherOptions(
@Hidden
@Tag(tags.implementation)
cliScalaVersion: Option[String] = None,
@Group(HelpGroup.Launcher.toString)
@HelpMessage(
s"The default version of Scala used when processing user inputs (current default: ${Constants.defaultScalaVersion}). Can be overridden with --scala-version. "
)
@ValueDescription("version")
@Hidden
@Tag(tags.implementation)
@Name("cliDefaultScalaVersion")
cliUserScalaVersion: Option[String] = None,
@Recurse
powerOptions: PowerOptions = PowerOptions()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import scala.util.{Properties, Using}

abstract class PackageTestDefinitions extends ScalaCliSuite with TestScalaVersionArgs {
_: TestScalaVersion =>
private lazy val extraOptions = scalaVersionArgs ++ TestUtil.extraOptions
protected lazy val extraOptions: Seq[String] = scalaVersionArgs ++ TestUtil.extraOptions

def maybeUseBash(cmd: os.Shellable*)(cwd: os.Path = null): os.CommandResult = {
val res = os.proc(cmd*).call(cwd = cwd, check = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ class PackageTestsDefault extends PackageTestDefinitions with TestDefault {
|""".stripMargin
)
inputs.fromRoot { root =>
val runRes = os.proc(TestUtil.cli, "run", "--native", ".")
val runRes = os.proc(TestUtil.cli, "run", "--native", ".", extraOptions)
.call(cwd = root)
val runOutput = runRes.out.trim().linesIterator.filter(!_.startsWith("[info] ")).toVector
expect(runOutput == Seq("Hello"))

val packageRes = os.proc(TestUtil.cli, "--power", "package", "--native", ".", "-o", "hello")
.call(cwd = root, mergeErrIntoOut = true)
val packageRes =
os.proc(TestUtil.cli, "--power", "package", "--native", ".", "-o", "hello", extraOptions)
.call(cwd = root, mergeErrIntoOut = true)
val packageOutput = packageRes.out.trim()
val topPackageOutput = packageOutput.linesIterator.takeWhile(!_.startsWith("Wrote ")).toVector
// no compilation or Scala Native pipeline output, as this should just re-use what the run command wrote
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,4 +513,50 @@ class SipScalaTests extends ScalaCliSuite {
expect(res.err.trim().contains(expectedError))
}
}

for {
sv <- Seq(Constants.scala212, Constants.scala213, Constants.scala3NextRc)
code =
if (sv.startsWith("3")) "println(dotty.tools.dotc.config.Properties.simpleVersionString)"
else "println(scala.util.Properties.versionNumberString)"
} {
test(
s"default Scala version overridden with $sv by a launcher parameter is respected when running a script"
) {
TestInputs(os.rel / "simple.sc" -> code)
.fromRoot { root =>
val r = os.proc(
TestUtil.cli,
"--cli-default-scala-version",
sv,
"run",
"simple.sc",
"--with-compiler"
)
.call(cwd = root)
expect(r.out.trim() == sv)
}
}

test(
s"default Scala version overridden with $sv by a launcher parameter is respected when printing Scala version"
) {
TestInputs.empty.fromRoot { root =>
val r =
os.proc(TestUtil.cli, "--cli-default-scala-version", sv, "version", "--scala-version")
.call(cwd = root)
expect(r.out.trim() == sv)
}
}

test(
s"default Scala version overridden with $sv by a launcher parameter is respected when printing versions"
) {
TestInputs.empty.fromRoot { root =>
val r = os.proc(TestUtil.cli, "--cli-default-scala-version", sv, "version")
.call(cwd = root)
expect(r.out.trim().contains(sv))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,12 @@ final case class BuildOptions(

// used when downloading fails
private def defaultStableScalaVersions =
Seq(defaultScala212Version, defaultScala213Version, defaultScalaVersion)
Seq(
defaultScala212Version,
defaultScala213Version,
defaultScalaVersion,
scalaOptions.defaultScalaVersion.getOrElse(defaultScalaVersion)
).distinct

def javaHome(): Positioned[JavaHomeInfo] = javaCommand0

Expand Down Expand Up @@ -315,7 +320,8 @@ final case class BuildOptions(
val defaultVersions = Set(
Constants.defaultScalaVersion,
Constants.defaultScala212Version,
Constants.defaultScala213Version
Constants.defaultScala213Version,
scalaOptions.defaultScalaVersion.getOrElse(Constants.defaultScalaVersion)
)

val svOpt: Option[String] = scalaOptions.scalaVersion match {
Expand Down Expand Up @@ -379,7 +385,7 @@ final case class BuildOptions(
}
Some(sv)

case None => Some(Constants.defaultScalaVersion)
case None => Some(scalaOptions.defaultScalaVersion.getOrElse(Constants.defaultScalaVersion))
}

svOpt match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ final case class ScalaOptions(
extraScalaVersions: Set[String] = Set.empty,
compilerPlugins: Seq[Positioned[AnyDependency]] = Nil,
platform: Option[Positioned[Platform]] = None,
extraPlatforms: Map[Platform, Positioned[Unit]] = Map.empty
extraPlatforms: Map[Platform, Positioned[Unit]] = Map.empty,
defaultScalaVersion: Option[String] = None
) {
def normalize: ScalaOptions = {
var opt = this
Expand Down

0 comments on commit 227da37

Please sign in to comment.