Skip to content

Commit f0d352c

Browse files
committed
Extract initial BspReloadableOptions from sources in Bsp command
1 parent 6492a87 commit f0d352c

File tree

8 files changed

+112
-34
lines changed

8 files changed

+112
-34
lines changed

modules/build/src/main/scala/scala/build/Build.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ object Build {
197197
def diagnostics: None.type = None
198198
}
199199

200+
/** If some options are manually overridden, append a hash of the options to the project name
201+
* Using only the command-line options not the ones from the sources.
202+
*/
200203
def updateInputs(
201204
inputs: Inputs,
202205
options: BuildOptions,

modules/build/src/main/scala/scala/build/bsp/Bsp.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import scala.build.input.{Inputs, ScalaCliInvokeData}
77
import scala.concurrent.Future
88

99
trait Bsp {
10-
def run(initialInputs: Inputs): Future[Unit]
10+
def run(initialInputs: Inputs, initialBspOptions: BspReloadableOptions): Future[Unit]
1111
def shutdown(): Unit
1212
}
1313

modules/build/src/main/scala/scala/build/bsp/BspImpl.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -456,18 +456,17 @@ final class BspImpl(
456456
* the initial input sources passed upon initializing the BSP connection (which are subject to
457457
* change on subsequent workspace/reload requests)
458458
*/
459-
def run(initialInputs: Inputs): Future[Unit] = {
460-
val reloadableOptions = bspReloadableOptionsReference.get
461-
val logger = reloadableOptions.logger
462-
val verbosity = reloadableOptions.verbosity
459+
def run(initialInputs: Inputs, initialBspOptions: BspReloadableOptions): Future[Unit] = {
460+
val logger = initialBspOptions.logger
461+
val verbosity = initialBspOptions.verbosity
463462

464463
actualLocalClient = new BspClient(
465464
threads.buildThreads.bloop.jsonrpc, // meh
466465
logger
467466
)
468467
localClient = getLocalClient(verbosity)
469468

470-
val currentBloopSession = newBloopSession(initialInputs, reloadableOptions)
469+
val currentBloopSession = newBloopSession(initialInputs, initialBspOptions)
471470
bloopSession.update(null, currentBloopSession, "BSP server already initialized")
472471

473472
val actualLocalServer
@@ -507,7 +506,7 @@ final class BspImpl(
507506

508507
prepareBuild(
509508
currentBloopSession,
510-
reloadableOptions,
509+
initialBspOptions,
511510
maybeRecoverOnError = recoverOnError
512511
) match {
513512
case Left((ex, scope)) => recoverOnError(scope)(ex)
@@ -524,7 +523,7 @@ final class BspImpl(
524523
val f = launcher.startListening()
525524

526525
val initiateFirstBuild: Runnable = { () =>
527-
try build(currentBloopSession, actualLocalClient, notifyChanges = false, reloadableOptions)
526+
try build(currentBloopSession, actualLocalClient, notifyChanges = false, initialBspOptions)
528527
catch {
529528
case t: Throwable =>
530529
logger.debug(s"Caught $t during initial BSP build, ignoring it")

modules/build/src/main/scala/scala/build/bsp/BspReloadableOptions.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,4 @@ object BspReloadableOptions {
2929
def get: BspReloadableOptions = ref
3030
def reload(): Unit = ref = getReloaded()
3131
}
32-
object Reference {
33-
def apply(getReloaded: () => BspReloadableOptions): Reference = new Reference(getReloaded)
34-
}
3532
}

modules/cli/src/main/scala/scala/cli/commands/bsp/Bsp.scala

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import scala.build.*
88
import scala.build.bsp.{BspReloadableOptions, BspThreads}
99
import scala.build.errors.BuildException
1010
import scala.build.input.Inputs
11-
import scala.build.options.BuildOptions
11+
import scala.build.options.{BuildOptions, Scope}
1212
import scala.cli.CurrentParams
1313
import scala.cli.commands.ScalaCommand
1414
import scala.cli.commands.publish.ConfigUtil.*
@@ -38,7 +38,7 @@ object Bsp extends ScalaCommand[BspOptions] {
3838

3939
val getSharedOptions: () => SharedOptions = () => latestSharedOptions(options)
4040

41-
val argsToInputs: Seq[String] => Either[BuildException, Inputs] =
41+
val preprocessInputs: Seq[String] => Either[BuildException, (Inputs, BuildOptions)] =
4242
argsSeq =>
4343
either {
4444
val sharedOptions = getSharedOptions()
@@ -47,26 +47,54 @@ object Bsp extends ScalaCommand[BspOptions] {
4747
if (sharedOptions.logging.verbosity >= 3)
4848
pprint.err.log(initialInputs)
4949

50-
val buildOptions0 = buildOptions(sharedOptions)
50+
val baseOptions = buildOptions(sharedOptions)
5151
val latestLogger = sharedOptions.logging.logger
5252
val persistentLogger = new PersistentDiagnosticLogger(latestLogger)
5353

54-
val allInputs =
55-
CrossSources.forInputs(
56-
initialInputs,
57-
Sources.defaultPreprocessors(
58-
buildOptions0.archiveCache,
59-
buildOptions0.internal.javaClassNameVersionOpt,
60-
() => buildOptions0.javaHome().value.javaCommand
61-
),
62-
persistentLogger,
63-
buildOptions0.suppressWarningOptions,
64-
buildOptions0.internal.exclude
65-
).map(_._2).getOrElse(initialInputs)
66-
67-
Build.updateInputs(allInputs, buildOptions(sharedOptions))
54+
val crossResult = CrossSources.forInputs(
55+
initialInputs,
56+
Sources.defaultPreprocessors(
57+
baseOptions.archiveCache,
58+
baseOptions.internal.javaClassNameVersionOpt,
59+
() => baseOptions.javaHome().value.javaCommand
60+
),
61+
persistentLogger,
62+
baseOptions.suppressWarningOptions,
63+
baseOptions.internal.exclude
64+
)
65+
66+
val (allInputs, finalBuildOptions) = {
67+
for
68+
crossSourcesAndInputs <- crossResult
69+
// compiler bug, can't do :
70+
// (crossSources, crossInputs) <- crossResult
71+
(crossSources, crossInputs) = crossSourcesAndInputs
72+
sharedBuildOptions = crossSources.sharedOptions(baseOptions)
73+
scopedSources <- crossSources.scopedSources(sharedBuildOptions)
74+
resolvedBuildOptions =
75+
scopedSources.buildOptionsFor(Scope.Main).foldRight(sharedBuildOptions)(_ orElse _)
76+
yield (crossInputs, resolvedBuildOptions)
77+
}.getOrElse(initialInputs -> baseOptions)
78+
79+
Build.updateInputs(allInputs, baseOptions) -> finalBuildOptions
6880
}
6981

82+
val (inputs, finalBuildOptions) = preprocessInputs(args.all).orExit(logger)
83+
84+
/** values used for lauching the bsp, especially for launching a bloop server, they include
85+
* options extracted from sources
86+
*/
87+
val initialBspOptions = {
88+
val sharedOptions = getSharedOptions()
89+
BspReloadableOptions(
90+
buildOptions = buildOptions(sharedOptions) orElse finalBuildOptions,
91+
bloopRifleConfig = sharedOptions.bloopRifleConfig(Some(finalBuildOptions))
92+
.orExit(sharedOptions.logger),
93+
logger = sharedOptions.logging.logger,
94+
verbosity = sharedOptions.logging.verbosity
95+
)
96+
}
97+
7098
val bspReloadableOptionsReference = BspReloadableOptions.Reference { () =>
7199
val sharedOptions = getSharedOptions()
72100
BspReloadableOptions(
@@ -77,14 +105,13 @@ object Bsp extends ScalaCommand[BspOptions] {
77105
)
78106
}
79107

80-
val inputs = argsToInputs(args.all).orExit(logger)
81108
CurrentParams.workspaceOpt = Some(inputs.workspace)
82109
val actionableDiagnostics =
83110
options.shared.logging.verbosityOptions.actions
84111

85112
BspThreads.withThreads { threads =>
86113
val bsp = scala.build.bsp.Bsp.create(
87-
argsToInputs,
114+
preprocessInputs.andThen(_.map(_._1)),
88115
bspReloadableOptionsReference,
89116
threads,
90117
System.in,
@@ -93,7 +120,7 @@ object Bsp extends ScalaCommand[BspOptions] {
93120
)
94121

95122
try {
96-
val doneFuture = bsp.run(inputs)
123+
val doneFuture = bsp.run(inputs, initialBspOptions)
97124
Await.result(doneFuture, Duration.Inf)
98125
}
99126
finally bsp.shutdown()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ final case class SharedCompilationServerOptions(
276276
javaOpts =
277277
(if (bloopDefaultJavaOpts) baseConfig.javaOpts
278278
else Nil) ++ bloopJavaOpt ++ bloopDefaultJvmOptions(logger).getOrElse(Nil),
279-
minimumBloopJvm = javaV.getOrElse(8),
279+
minimumBloopJvm = javaV.getOrElse(17),
280280
retainedBloopVersion = retainedBloopVersion
281281
)
282282
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,9 @@ final case class SharedOptions(
518518
.getOrElse(None)
519519
)
520520

521-
def bloopRifleConfig(): Either[BuildException, BloopRifleConfig] = either {
522-
val options = value(buildOptions(false, None))
521+
def bloopRifleConfig(extraBuildOptions: Option[BuildOptions] = None)
522+
: Either[BuildException, BloopRifleConfig] = either {
523+
val options = extraBuildOptions.foldLeft(value(buildOptions(false, None)))(_ orElse _)
523524
lazy val defaultJvmHome = value {
524525
JvmUtils.downloadJvm(OsLibc.defaultJvm(OsLibc.jvmIndexOs), options)
525526
}

modules/integration/src/test/scala/scala/cli/integration/BspTestDefinitions.scala

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,57 @@ abstract class BspTestDefinitions(val scalaVersionOpt: Option[String])
11601160
}
11611161
}
11621162

1163+
test("bsp should start bloop with correct JVM version from directives") {
1164+
val sourceFilePath = os.rel / "ReloadTest.java"
1165+
val inputs = TestInputs(
1166+
sourceFilePath ->
1167+
s"""//> using jvm 19
1168+
|//> using javacOpt --enable-preview
1169+
|
1170+
|public class ReloadTest {
1171+
| public static void main(String[] args) {
1172+
| String a = "Hello World";
1173+
|
1174+
| switch (a) {
1175+
| case String s when s.length() > 6 -> System.out.println(s.toUpperCase());
1176+
| case String s -> System.out.println(s.toLowerCase());
1177+
| }
1178+
| }
1179+
|}
1180+
|""".stripMargin
1181+
)
1182+
inputs.fromRoot { root =>
1183+
os.proc(TestUtil.cli, "--power", "bloop", "exit")
1184+
.call(
1185+
cwd = root,
1186+
stdout = os.Inherit
1187+
)
1188+
os.proc(TestUtil.cli, "--power", "bloop", "start", "--jvm", "17")
1189+
.call(
1190+
cwd = root,
1191+
stdout = os.Inherit
1192+
)
1193+
os.proc(TestUtil.cli, "setup-ide", ".", extraOptions)
1194+
.call(
1195+
cwd = root,
1196+
stdout = os.Inherit
1197+
)
1198+
val ideOptionsPath = root / Constants.workspaceDirName / "ide-options-v2.json"
1199+
val jsonOptions = List("--json-options", ideOptionsPath.toString)
1200+
withBsp(inputs, Seq("."), bspOptions = jsonOptions, reuseRoot = Some(root)) {
1201+
(_, _, remoteServer) =>
1202+
async {
1203+
val buildTargetsResp = await(remoteServer.workspaceBuildTargets().asScala)
1204+
val targets = buildTargetsResp.getTargets.asScala.map(_.getId).toSeq
1205+
1206+
val resp =
1207+
await(remoteServer.buildTargetCompile(new b.CompileParams(targets.asJava)).asScala)
1208+
expect(resp.getStatusCode == b.StatusCode.OK)
1209+
}
1210+
}
1211+
}
1212+
}
1213+
11631214
test("bloop projects are initialised properly for an invalid directive value") {
11641215
val inputs = TestInputs(
11651216
os.rel / "InvalidUsingDirective.scala" ->

0 commit comments

Comments
 (0)