Skip to content

Commit c41468d

Browse files
committed
Restart bloop on workspace/reload when its JVM version is too low
Add test for restarting bloop with the correct JVM version after workspace/reload Add test for starting bsp while bloop is running with JVM version too low Change the warning message
1 parent f0d352c commit c41468d

File tree

4 files changed

+184
-6
lines changed

4 files changed

+184
-6
lines changed

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

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package scala.build.bsp
22

3-
import bloop.rifle.BloopServer
3+
import bloop.rifle.{BloopRifleConfig, BloopServer}
44
import ch.epfl.scala.bsp4j as b
55
import com.github.plokhotnyuk.jsoniter_scala.core.{JsonReaderException, readFromArray}
66
import dependency.ScalaParameters
@@ -566,9 +566,10 @@ final class BspImpl(
566566
): CompletableFuture[AnyRef] = {
567567
val previousTargetIds = currentBloopSession.bspServer.targetIds
568568
val wasIntelliJ = currentBloopSession.bspServer.isIntelliJ
569-
val newBloopSession0 = newBloopSession(newInputs, reloadableOptions, wasIntelliJ)
570-
bloopSession.update(currentBloopSession, newBloopSession0, "Concurrent reload of workspace")
569+
571570
currentBloopSession.dispose()
571+
val newBloopSession0 = newBloopSession(newInputs, reloadableOptions, wasIntelliJ)
572+
bloopSession.update(currentBloopSession, newBloopSession0, "Concurrent reload of workspace")
572573
actualLocalClient.newInputs(newInputs)
573574

574575
newBloopSession0.resetDiagnostics(actualLocalClient)
@@ -580,9 +581,42 @@ final class BspImpl(
580581
)
581582
)
582583
case Right(preBuildProject) =>
584+
lazy val projectJavaHome = preBuildProject.mainScope.buildOptions
585+
.javaHome()
586+
.value
587+
588+
val finalBloopSession =
589+
if (
590+
bloopSession.get().remoteServer.jvmVersion.exists(_.value < projectJavaHome.version)
591+
) {
592+
reloadableOptions.logger.log(
593+
s"Bloop JVM version too low, current ${bloopSession.get().remoteServer.jvmVersion.get.value} expected ${projectJavaHome.version}, restarting server"
594+
)
595+
// RelodableOptions don't take into account buildOptions from sources
596+
val updatedReloadableOptions = reloadableOptions.copy(
597+
buildOptions =
598+
reloadableOptions.buildOptions orElse preBuildProject.mainScope.buildOptions,
599+
bloopRifleConfig = reloadableOptions.bloopRifleConfig.copy(
600+
javaPath = projectJavaHome.javaCommand,
601+
minimumBloopJvm = projectJavaHome.version
602+
)
603+
)
604+
605+
newBloopSession0.dispose()
606+
val bloopSessionWithJvmOkay =
607+
newBloopSession(newInputs, updatedReloadableOptions, wasIntelliJ)
608+
bloopSession.update(
609+
newBloopSession0,
610+
bloopSessionWithJvmOkay,
611+
"Concurrent reload of workspace"
612+
)
613+
bloopSessionWithJvmOkay
614+
}
615+
else newBloopSession0
616+
583617
if (previousInputs.projectName != preBuildProject.mainScope.project.projectName)
584-
for (client <- newBloopSession0.bspServer.clientOpt) {
585-
val newTargetIds = newBloopSession0.bspServer.targetIds
618+
for (client <- finalBloopSession.bspServer.clientOpt) {
619+
val newTargetIds = finalBloopSession.bspServer.targetIds
586620
val events =
587621
newTargetIds.map(buildTargetIdToEvent(_, b.BuildTargetEventKind.CREATED)) ++
588622
previousTargetIds.map(buildTargetIdToEvent(_, b.BuildTargetEventKind.DELETED))

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ object Bsp extends ScalaCommand[BspOptions] {
9797

9898
val bspReloadableOptionsReference = BspReloadableOptions.Reference { () =>
9999
val sharedOptions = getSharedOptions()
100+
val bloopRifleConfig = sharedOptions.bloopRifleConfig(Some(finalBuildOptions))
101+
.orExit(sharedOptions.logger)
102+
100103
BspReloadableOptions(
101104
buildOptions = buildOptions(sharedOptions),
102105
bloopRifleConfig = sharedOptions.bloopRifleConfig().orExit(sharedOptions.logger),

modules/core/src/main/scala/scala/build/errors/Diagnostic.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ object Diagnostic {
1414
case class TextEdit(title: String, newText: String)
1515
object Messages {
1616
val bloopTooOld =
17-
"JVM that is hosting bloop is older than the requested runtime. Please run command `bloop exit`, and then use `--jvm` flag to restart Bloop"
17+
"""JVM that is hosting bloop is older than the requested runtime. Please restart the Build Server from your IDE.
18+
|Or run the command `bloop exit`, and then use `--jvm` flag to request a sufficient JVM version.
19+
|""".stripMargin
1820
}
1921

2022
private case class ADiagnostic(

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

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

1163+
test("workspace/reload should restart bloop with correct JVM version from options") {
1164+
val sourceFilePath = os.rel / "ReloadTest.java"
1165+
val inputs = TestInputs(
1166+
sourceFilePath ->
1167+
s"""public class ReloadTest {
1168+
| public static void main(String[] args) {
1169+
| String a = "Hello World";
1170+
|
1171+
| switch (a) {
1172+
| case String s when s.length() > 6 -> System.out.println(s.toUpperCase());
1173+
| case String s -> System.out.println(s.toLowerCase());
1174+
| }
1175+
| }
1176+
|}""".stripMargin
1177+
)
1178+
inputs.fromRoot { root =>
1179+
os.proc(TestUtil.cli, "--power", "bloop", "exit")
1180+
.call(
1181+
cwd = root,
1182+
stdout = os.Inherit
1183+
)
1184+
os.proc(TestUtil.cli, "setup-ide", ".", "--jvm", "11", extraOptions)
1185+
.call(
1186+
cwd = root,
1187+
stdout = os.Inherit
1188+
)
1189+
val ideOptionsPath = root / Constants.workspaceDirName / "ide-options-v2.json"
1190+
val jsonOptions = List("--json-options", ideOptionsPath.toString)
1191+
withBsp(inputs, Seq("."), bspOptions = jsonOptions, reuseRoot = Some(root)) {
1192+
(_, _, remoteServer) =>
1193+
async {
1194+
val buildTargetsResp = await(remoteServer.workspaceBuildTargets().asScala)
1195+
val targets = buildTargetsResp.getTargets.asScala.map(_.getId).toSeq
1196+
1197+
val errorResponse =
1198+
await(remoteServer.buildTargetCompile(new b.CompileParams(targets.asJava)).asScala)
1199+
expect(errorResponse.getStatusCode == b.StatusCode.ERROR)
1200+
1201+
val javacOptions = Seq("--javac-opt", "--enable-preview")
1202+
1203+
os.proc(TestUtil.cli, "setup-ide", ".", "--jvm", "19", javacOptions, extraOptions)
1204+
.call(
1205+
cwd = root,
1206+
stdout = os.Inherit
1207+
)
1208+
1209+
val reloadResponse =
1210+
extractWorkspaceReloadResponse(await(remoteServer.workspaceReload().asScala))
1211+
expect(reloadResponse.isEmpty)
1212+
1213+
val buildTargetsResp0 = await(remoteServer.workspaceBuildTargets().asScala)
1214+
val reloadedTargets = buildTargetsResp0.getTargets.asScala.map(_.getId).toSeq
1215+
1216+
val okResponse =
1217+
await(
1218+
remoteServer.buildTargetCompile(new b.CompileParams(reloadedTargets.asJava)).asScala
1219+
)
1220+
expect(okResponse.getStatusCode == b.StatusCode.OK)
1221+
}
1222+
}
1223+
1224+
}
1225+
}
1226+
1227+
test("workspace/reload should restart bloop with correct JVM version from directives") {
1228+
val sourceFilePath = os.rel / "ReloadTest.java"
1229+
val inputs = TestInputs(
1230+
sourceFilePath ->
1231+
s"""//> using jvm 11
1232+
|
1233+
|public class ReloadTest {
1234+
| public static void main(String[] args) {
1235+
| System.out.println("Hello World");
1236+
| }
1237+
|}
1238+
|""".stripMargin
1239+
)
1240+
inputs.fromRoot { root =>
1241+
os.proc(TestUtil.cli, "--power", "bloop", "exit")
1242+
.call(
1243+
cwd = root,
1244+
stdout = os.Inherit
1245+
)
1246+
os.proc(TestUtil.cli, "setup-ide", ".", extraOptions)
1247+
.call(
1248+
cwd = root,
1249+
stdout = os.Inherit
1250+
)
1251+
val ideOptionsPath = root / Constants.workspaceDirName / "ide-options-v2.json"
1252+
val jsonOptions = List("--json-options", ideOptionsPath.toString)
1253+
withBsp(inputs, Seq("."), bspOptions = jsonOptions, reuseRoot = Some(root)) {
1254+
(_, _, remoteServer) =>
1255+
async {
1256+
val buildTargetsResp = await(remoteServer.workspaceBuildTargets().asScala)
1257+
val targets = buildTargetsResp.getTargets.asScala.map(_.getId).toSeq
1258+
1259+
val resp =
1260+
await(remoteServer.buildTargetCompile(new b.CompileParams(targets.asJava)).asScala)
1261+
expect(resp.getStatusCode == b.StatusCode.OK)
1262+
1263+
val updatedSourceFile =
1264+
s"""//> using jvm 19
1265+
|//> using javacOpt --enable-preview
1266+
|
1267+
|public class ReloadTest {
1268+
| public static void main(String[] args) {
1269+
| String a = "Hello World";
1270+
|
1271+
| switch (a) {
1272+
| case String s when s.length() > 6 -> System.out.println(s.toUpperCase());
1273+
| case String s -> System.out.println(s.toLowerCase());
1274+
| }
1275+
| }
1276+
|}
1277+
|""".stripMargin
1278+
os.write.over(root / sourceFilePath, updatedSourceFile)
1279+
1280+
val errorResponse =
1281+
await(remoteServer.buildTargetCompile(new b.CompileParams(targets.asJava)).asScala)
1282+
expect(errorResponse.getStatusCode == b.StatusCode.ERROR)
1283+
1284+
val reloadResponse =
1285+
extractWorkspaceReloadResponse(await(remoteServer.workspaceReload().asScala))
1286+
expect(reloadResponse.isEmpty)
1287+
1288+
val buildTargetsResp0 = await(remoteServer.workspaceBuildTargets().asScala)
1289+
val reloadedTargets = buildTargetsResp0.getTargets.asScala.map(_.getId).toSeq
1290+
1291+
val okResponse =
1292+
await(
1293+
remoteServer.buildTargetCompile(new b.CompileParams(reloadedTargets.asJava)).asScala
1294+
)
1295+
expect(okResponse.getStatusCode == b.StatusCode.OK)
1296+
}
1297+
}
1298+
1299+
}
1300+
}
1301+
11631302
test("bsp should start bloop with correct JVM version from directives") {
11641303
val sourceFilePath = os.rel / "ReloadTest.java"
11651304
val inputs = TestInputs(

0 commit comments

Comments
 (0)