From caca31e14771fe5b70297bae7dc5b4a6aa0aba09 Mon Sep 17 00:00:00 2001 From: Katarzyna Marek Date: Tue, 27 Jun 2023 15:28:01 +0100 Subject: [PATCH] improvement: restart sbt server on java home change --- .../meta/internal/bsp/BspConnector.scala | 12 +++++++ .../scala/meta/internal/bsp/BspServers.scala | 8 ++++- .../meta/internal/builds/SbtBuildTool.scala | 33 +++++++++++++++++++ .../internal/metals/MetalsLspService.scala | 3 +- 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/metals/src/main/scala/scala/meta/internal/bsp/BspConnector.scala b/metals/src/main/scala/scala/meta/internal/bsp/BspConnector.scala index ed64bc8c0b9..ff2e1009947 100644 --- a/metals/src/main/scala/scala/meta/internal/bsp/BspConnector.scala +++ b/metals/src/main/scala/scala/meta/internal/bsp/BspConnector.scala @@ -9,8 +9,10 @@ import scala.meta.internal.bsp.BspConfigGenerationStatus._ import scala.meta.internal.builds.BuildServerProvider import scala.meta.internal.builds.BuildTools import scala.meta.internal.builds.SbtBuildTool +import scala.meta.internal.builds.ShellRunner import scala.meta.internal.metals.BloopServers import scala.meta.internal.metals.BuildServerConnection +import scala.meta.internal.metals.JdkSources import scala.meta.internal.metals.Messages import scala.meta.internal.metals.Messages.BspSwitch import scala.meta.internal.metals.MetalsEnrichments._ @@ -73,6 +75,7 @@ class BspConnector( def connect( workspace: AbsolutePath, userConfiguration: UserConfiguration, + shellRunner: ShellRunner, )(implicit ec: ExecutionContext): Future[Option[BspSession]] = { def connect( workspace: AbsolutePath @@ -88,8 +91,17 @@ class BspConnector( if details.getName() == SbtBuildTool.name => tables.buildServers.chooseServer(SbtBuildTool.name) val shouldReload = SbtBuildTool.writeSbtMetalsPlugins(workspace) + val shouldShutdownOldServer = !SbtBuildTool.checkCorrectJavaVersion( + workspace, + userConfiguration.javaHome.orElse(JdkSources.defaultJavaHome), + ) val connectionF = for { + _ <- + if (shouldShutdownOldServer) + SbtBuildTool(workspace, () => userConfiguration) + .shutdownBspServer(shellRunner, workspace) + else Future.successful(()) connection <- bspServers.newServer(workspace, details) _ <- if (shouldReload) connection.workspaceReload() diff --git a/metals/src/main/scala/scala/meta/internal/bsp/BspServers.scala b/metals/src/main/scala/scala/meta/internal/bsp/BspServers.scala index a741572c940..83dd9e5b51c 100644 --- a/metals/src/main/scala/scala/meta/internal/bsp/BspServers.scala +++ b/metals/src/main/scala/scala/meta/internal/bsp/BspServers.scala @@ -14,12 +14,14 @@ import scala.meta.internal.io.FileIO import scala.meta.internal.metals.BuildServerConnection import scala.meta.internal.metals.Cancelable import scala.meta.internal.metals.ClosableOutputStream +import scala.meta.internal.metals.JdkSources import scala.meta.internal.metals.MetalsBuildClient import scala.meta.internal.metals.MetalsEnrichments._ import scala.meta.internal.metals.MetalsServerConfig import scala.meta.internal.metals.QuietInputStream import scala.meta.internal.metals.SocketConnection import scala.meta.internal.metals.Tables +import scala.meta.internal.metals.UserConfiguration import scala.meta.internal.metals.clients.language.MetalsLanguageClient import scala.meta.internal.mtags.MD5 import scala.meta.internal.mtags.URIEncoderDecoder @@ -43,6 +45,7 @@ final class BspServers( tables: Tables, bspGlobalInstallDirectories: List[AbsolutePath], config: MetalsServerConfig, + userConfig: () => UserConfiguration, )(implicit ec: ExecutionContextExecutorService) { def resolve(): BspResolvedResult = { @@ -92,7 +95,10 @@ final class BspServers( args, projectDirectory, redirectErrorOutput = false, - Map(), + userConfig().javaHome + .orElse(JdkSources.defaultJavaHome) + .map("JAVA_HOME" -> _) + .toMap, processOut = None, processErr = Some(l => scribe.info("BSP server: " + l)), discardInput = false, diff --git a/metals/src/main/scala/scala/meta/internal/builds/SbtBuildTool.scala b/metals/src/main/scala/scala/meta/internal/builds/SbtBuildTool.scala index a3205c54ea7..1df6a68c855 100644 --- a/metals/src/main/scala/scala/meta/internal/builds/SbtBuildTool.scala +++ b/metals/src/main/scala/scala/meta/internal/builds/SbtBuildTool.scala @@ -382,4 +382,37 @@ object SbtBuildTool { val prepend = autoImports.mkString("", "\n", "\n") prepend + text } + + def checkCorrectJavaVersion( + workspace: AbsolutePath, + optJavaHome: Option[String], + ): Boolean = { + val bspConfigFile = workspace.resolve(".bsp").resolve("sbt.json") + if (bspConfigFile.isFile) { + val matchesSbtJavaHome = + for { + javaHome <- optJavaHome + javaHomePath <- (s"file://$javaHome").toAbsolutePathSafe + text <- bspConfigFile.readTextOpt + json = ujson.read(text) + args <- json("argv").arrOpt + firstArg <- args.headOption + javaArg <- firstArg.strOpt + } yield { + val possibleJavaBinaries = + List(javaHomePath, javaHomePath.resolve("jre")) + .map(_.resolve("bin/java")) + .flatMap(path => List(path, path.dealias)) + val sbtJavaHomeIsCorrect = + possibleJavaBinaries.exists(_.toString == javaArg) + if (!sbtJavaHomeIsCorrect) { + scribe.debug( + s"Java binary used by sbt server $javaArg doesn't match the expected java home. Possible paths considered: $possibleJavaBinaries" + ) + } + sbtJavaHomeIsCorrect + } + matchesSbtJavaHome.getOrElse(true) + } else true + } } diff --git a/metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala b/metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala index b01be5a413e..50553b19fb0 100644 --- a/metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala +++ b/metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala @@ -412,6 +412,7 @@ class MetalsLspService( tables, bspGlobalDirectories, clientConfig.initialConfig, + userConfig, ) private val bspConnector: BspConnector = new BspConnector( @@ -2060,7 +2061,7 @@ class MetalsLspService( (for { _ <- disconnectOldBuildServer() maybeSession <- timerProvider.timed("Connected to build server", true) { - bspConnector.connect(folder, userConfig()) + bspConnector.connect(folder, userConfig(), shellRunner) } result <- maybeSession match { case Some(session) =>