Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate Scala REPL classpath from user dependencies #2607

Merged
merged 1 commit into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 35 additions & 22 deletions modules/build/src/main/scala/scala/build/ReplArtifacts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ import scala.build.internal.CsLoggerUtil._

final case class ReplArtifacts(
replArtifacts: Seq[(String, os.Path)],
depArtifacts: Seq[(String, os.Path)],
extraClassPath: Seq[os.Path],
extraSourceJars: Seq[os.Path],
replMainClass: String,
replJavaOpts: Seq[String],
addSourceJars: Boolean
addSourceJars: Boolean,
includeExtraCpOnReplCp: Boolean = false
) {
lazy val replClassPath: Seq[os.Path] = {
val cp =
if (addSourceJars)
extraClassPath ++ extraSourceJars ++ replArtifacts.map(_._2)
else
extraClassPath ++ replArtifacts.map(_._2)
cp.distinct
}
private lazy val fullExtraClassPath: Seq[os.Path] =
if addSourceJars then extraClassPath ++ extraSourceJars else extraClassPath
lazy val replClassPath: Seq[os.Path] =
(if includeExtraCpOnReplCp then fullExtraClassPath ++ replArtifacts.map(_._2).distinct
else replArtifacts.map(_._2))
.distinct
lazy val depsClassPath: Seq[os.Path] = (fullExtraClassPath ++ depArtifacts.map(_._2)).distinct
}

object ReplArtifacts {
Expand Down Expand Up @@ -68,12 +69,16 @@ object ReplArtifacts {
classifiersOpt = Some(Set("sources"))
)
ReplArtifacts(
value(replArtifacts) ++ value(replSourceArtifacts),
extraClassPath,
extraSourceJars,
"ammonite.Main",
Nil,
addSourceJars = true
replArtifacts = value(replArtifacts) ++ value(replSourceArtifacts),
depArtifacts =
Nil, // amm does not support a -cp option, deps are passed directly to Ammonite cp
extraClassPath = extraClassPath,
extraSourceJars = extraSourceJars,
replMainClass = "ammonite.Main",
replJavaOpts = Nil,
addSourceJars = true,
includeExtraCpOnReplCp =
true // extra cp & source jars have to be passed directly to Ammonite cp
)
}

Expand All @@ -92,24 +97,32 @@ object ReplArtifacts {
else dep"org.scala-lang::scala3-compiler:${scalaParams.scalaVersion}"
val scalapyDeps =
addScalapy.map(ver => dep"${Artifacts.scalaPyOrganization(ver)}::scalapy-core::$ver").toSeq
val allDeps = dependencies ++ Seq(replDep) ++ scalapyDeps
val externalDeps = dependencies ++ scalapyDeps
val replArtifacts =
Artifacts.artifacts(
allDeps.map(Positioned.none),
Seq(replDep).map(Positioned.none),
repositories,
Some(scalaParams),
logger,
cache.withMessage(s"Downloading Scala compiler ${scalaParams.scalaVersion}")
)
val depArtifacts = Artifacts.artifacts(
externalDeps.map(Positioned.none),
repositories,
Some(scalaParams),
logger,
cache.withMessage(s"Downloading REPL dependencies")
)
val mainClass =
if (isScala2) "scala.tools.nsc.MainGenericRunner"
else "dotty.tools.repl.Main"
ReplArtifacts(
value(replArtifacts),
extraClassPath,
Nil,
mainClass,
Seq("-Dscala.usejavacp=true"),
replArtifacts = value(replArtifacts),
depArtifacts = value(depArtifacts),
extraClassPath = extraClassPath,
extraSourceJars = Nil,
replMainClass = mainClass,
replJavaOpts = Seq("-Dscala.usejavacp=true"),
addSourceJars = false
)
}
Expand Down
22 changes: 15 additions & 7 deletions modules/cli/src/main/scala/scala/cli/commands/repl/Repl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import coursier.cache.FileCache
import coursier.error.{FetchError, ResolutionError}
import dependency.*

import java.io.File
import java.util.zip.ZipFile

import scala.build.EitherCps.{either, value}
Expand All @@ -29,7 +30,7 @@ import scala.cli.config.{ConfigDb, Keys}
import scala.cli.packaging.Library
import scala.cli.util.ArgHelpers.*
import scala.cli.util.ConfigDbUtils
import scala.jdk.CollectionConverters._
import scala.jdk.CollectionConverters.*
import scala.util.Properties

object Repl extends ScalaCommand[ReplOptions] {
Expand Down Expand Up @@ -380,16 +381,23 @@ object Repl extends ScalaCommand[ReplOptions] {
if (dryRun)
logger.message("Dry run, not running REPL.")
else {
val depClassPathArgs: Seq[String] =
if replArtifacts.depsClassPath.nonEmpty && !replArtifacts.replMainClass.startsWith("ammonite") then
Seq(
"-classpath",
replArtifacts.depsClassPath.map(_.toString).mkString(File.pathSeparator)
)
else Nil
val retCode = Runner.runJvm(
options.javaHome().value.javaCommand,
scalapyJavaOpts ++
javaCommand = options.javaHome().value.javaCommand,
javaArgs = scalapyJavaOpts ++
replArtifacts.replJavaOpts ++
options.javaOptions.javaOpts.toSeq.map(_.value.value) ++
extraProps.toVector.sorted.map { case (k, v) => s"-D$k=$v" },
mainJarOrClassDir.toSeq ++ replArtifacts.replClassPath,
replArtifacts.replMainClass,
maybeAdaptForWindows(replArgs),
logger,
classPath = mainJarOrClassDir.toSeq ++ replArtifacts.replClassPath,
mainClass = replArtifacts.replMainClass,
args = maybeAdaptForWindows(depClassPathArgs ++ replArgs),
logger = logger,
allowExecve = allowExit,
extraEnv = scalapyExtraEnv ++ extraEnv
).waitFor()
Expand Down