Skip to content
This repository was archived by the owner on Aug 5, 2024. It is now read-only.

Commit f6823e7

Browse files
Tomasz PasternakSpace Team
authored andcommitted
[fix] Compute classpath lazily in JvmEnvironment requests
Merge-request: BAZEL-MR-658 Merged-by: Tomasz Pasternak <[email protected]>
1 parent 24aa30d commit f6823e7

File tree

11 files changed

+74
-33
lines changed

11 files changed

+74
-33
lines changed

aspects/runtime_classpath_query.bzl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
def format(target):
2+
provider = providers(target)["JavaInfo"]
3+
compilation_info = getattr(provider, "compilation_info", None)
4+
5+
result = []
6+
if compilation_info:
7+
result = compilation_info.runtime_classpath.to_list()
8+
elif hasattr(provider, "transitive_runtime_jars"):
9+
result = provider.transitive_runtime_jars.to_list()
10+
return "\n".join([f.path for f in result])

bazelrunner/src/main/kotlin/org/jetbrains/bsp/bazel/bazelrunner/BazelRunnerCommandBuilder.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class BazelRunnerCommandBuilder internal constructor(private val bazelRunner: Ba
1515
fun showRepo() = mod("show_repo")
1616
fun showExtension() = mod("show_extension")
1717
fun query() = BazelRunnerBuilder(bazelRunner, listOf("query"))
18+
fun cquery() = BazelRunnerBuilder(bazelRunner, listOf("cquery"))
19+
1820
fun build() = BazelRunnerBuildBuilder(bazelRunner, listOf("build")).withUseBuildFlags()
1921
fun test() = BazelRunnerBuildBuilder(bazelRunner, listOf("test")).withUseBuildFlags()
2022
}

bspcli/src/main/kotlin/org/jetbrains/bsp/cli/Main.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ch.epfl.scala.bsp4j.DidChangeBuildTarget
77
import ch.epfl.scala.bsp4j.InitializeBuildParams
88
import ch.epfl.scala.bsp4j.JavaBuildServer
99
import ch.epfl.scala.bsp4j.JvmBuildServer
10+
import ch.epfl.scala.bsp4j.JvmRunEnvironmentParams
1011
import ch.epfl.scala.bsp4j.LogMessageParams
1112
import ch.epfl.scala.bsp4j.PrintParams
1213
import ch.epfl.scala.bsp4j.PublishDiagnosticsParams

server/src/main/kotlin/org/jetbrains/bsp/bazel/server/BazelBspServer.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ class BazelBspServer(
4747
)
4848

4949
val bspProjectMapper = BspProjectMapper(
50-
serverContainer.languagePluginsService, workspaceContextProvider
50+
serverContainer.languagePluginsService,
51+
workspaceContextProvider,
52+
serverContainer.bazelPathsResolver,
53+
bazelRunner,
54+
bspInfo
5155
)
5256
val projectSyncService =
5357
ProjectSyncService(bspProjectMapper, serverContainer.projectProvider)

server/src/main/kotlin/org/jetbrains/bsp/bazel/server/common/ServerContainer.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ class ServerContainer internal constructor(
4040
val bazelInfo: BazelInfo,
4141
val bazelRunner: BazelRunner,
4242
val compilationManager: BazelBspCompilationManager,
43-
val languagePluginsService: LanguagePluginsService
43+
val languagePluginsService: LanguagePluginsService,
44+
val bazelPathsResolver: BazelPathsResolver,
4445
) {
4546
companion object {
4647
@JvmStatic
@@ -105,7 +106,8 @@ class ServerContainer internal constructor(
105106
bazelInfo,
106107
bazelRunner,
107108
compilationManager,
108-
languagePluginsService
109+
languagePluginsService,
110+
bazelPathsResolver,
109111
)
110112
}
111113
}

server/src/main/kotlin/org/jetbrains/bsp/bazel/server/sync/BazelPathsResolver.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ class BazelPathsResolver(private val bazelInfo: BazelInfo) {
1717

1818
fun resolveUri(path: Path): URI = uris.computeIfAbsent(path, Path::toUri)
1919

20+
fun unresolvedWorkspaceRoot(): Path = bazelInfo.workspaceRoot
21+
2022
fun workspaceRoot(): URI = resolveUri(bazelInfo.workspaceRoot.toAbsolutePath())
2123

2224
fun resolveUris(fileLocations: List<FileLocation>, shouldFilterExisting: Boolean = false): List<URI> =

server/src/main/kotlin/org/jetbrains/bsp/bazel/server/sync/BspProjectMapper.kt

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import ch.epfl.scala.bsp4j.JavacOptionsItem
1717
import ch.epfl.scala.bsp4j.JavacOptionsParams
1818
import ch.epfl.scala.bsp4j.JavacOptionsResult
1919
import ch.epfl.scala.bsp4j.JvmEnvironmentItem
20+
import ch.epfl.scala.bsp4j.JvmMainClass
2021
import ch.epfl.scala.bsp4j.JvmRunEnvironmentParams
2122
import ch.epfl.scala.bsp4j.JvmRunEnvironmentResult
2223
import ch.epfl.scala.bsp4j.JvmTestEnvironmentParams
@@ -26,7 +27,6 @@ import ch.epfl.scala.bsp4j.OutputPathItemKind
2627
import ch.epfl.scala.bsp4j.OutputPathsItem
2728
import ch.epfl.scala.bsp4j.OutputPathsParams
2829
import ch.epfl.scala.bsp4j.OutputPathsResult
29-
import ch.epfl.scala.bsp4j.PythonBuildTarget
3030
import ch.epfl.scala.bsp4j.PythonOptionsItem
3131
import ch.epfl.scala.bsp4j.PythonOptionsParams
3232
import ch.epfl.scala.bsp4j.PythonOptionsResult
@@ -47,13 +47,16 @@ import ch.epfl.scala.bsp4j.SourcesParams
4747
import ch.epfl.scala.bsp4j.SourcesResult
4848
import ch.epfl.scala.bsp4j.TestProvider
4949
import ch.epfl.scala.bsp4j.WorkspaceBuildTargetsResult
50+
import org.eclipse.lsp4j.jsonrpc.CancelChecker
5051
import org.jetbrains.bsp.BazelBuildServerCapabilities
5152
import org.jetbrains.bsp.DirectoryItem
5253
import org.jetbrains.bsp.LibraryItem
5354
import org.jetbrains.bsp.WorkspaceDirectoriesResult
5455
import org.jetbrains.bsp.WorkspaceInvalidTargetsResult
5556
import org.jetbrains.bsp.WorkspaceLibrariesResult
57+
import org.jetbrains.bsp.bazel.bazelrunner.BazelRunner
5658
import org.jetbrains.bsp.bazel.commons.Constants
59+
import org.jetbrains.bsp.bazel.server.bsp.info.BspInfo
5760
import org.jetbrains.bsp.bazel.server.sync.languages.LanguagePluginsService
5861
import org.jetbrains.bsp.bazel.server.sync.languages.jvm.javaModule
5962
import org.jetbrains.bsp.bazel.server.sync.model.Label
@@ -64,12 +67,16 @@ import org.jetbrains.bsp.bazel.server.sync.model.Tag
6467
import org.jetbrains.bsp.bazel.workspacecontext.WorkspaceContextProvider
6568
import java.net.URI
6669
import java.nio.file.Path
70+
import java.nio.file.Paths
6771
import kotlin.io.path.name
6872
import kotlin.io.path.toPath
6973

7074
class BspProjectMapper(
71-
private val languagePluginsService: LanguagePluginsService,
72-
private val workspaceContextProvider: WorkspaceContextProvider
75+
private val languagePluginsService: LanguagePluginsService,
76+
private val workspaceContextProvider: WorkspaceContextProvider,
77+
private val bazelPathsResolver: BazelPathsResolver,
78+
private val bazelRunner: BazelRunner,
79+
private val bspInfo: BspInfo,
7380
) {
7481

7582
fun initializeServer(supportedLanguages: Set<Language>): InitializeBuildResult {
@@ -269,35 +276,62 @@ class BspProjectMapper(
269276
}
270277

271278
fun jvmRunEnvironment(
272-
project: Project, params: JvmRunEnvironmentParams
279+
project: Project, params: JvmRunEnvironmentParams, cancelChecker: CancelChecker
273280
): JvmRunEnvironmentResult {
274281
val targets = params.targets
275-
val result = getJvmEnvironmentItems(project, targets)
282+
val result = getJvmEnvironmentItems(project, targets, cancelChecker)
276283
return JvmRunEnvironmentResult(result)
277284
}
278285

279286
fun jvmTestEnvironment(
280-
project: Project, params: JvmTestEnvironmentParams
287+
project: Project, params: JvmTestEnvironmentParams, cancelChecker: CancelChecker
281288
): JvmTestEnvironmentResult {
282289
val targets = params.targets
283-
val result = getJvmEnvironmentItems(project, targets)
290+
val result = getJvmEnvironmentItems(project, targets, cancelChecker)
284291
return JvmTestEnvironmentResult(result)
285292
}
286293

287294
private fun getJvmEnvironmentItems(
288-
project: Project, targets: List<BuildTargetIdentifier>
295+
project: Project, targets: List<BuildTargetIdentifier>, cancelChecker: CancelChecker
289296
): List<JvmEnvironmentItem> {
290-
fun extractJvmEnvironmentItem(module: Module): JvmEnvironmentItem? =
291-
module.javaModule?.let {
292-
languagePluginsService.javaLanguagePlugin.toJvmEnvironmentItem(module, it)
297+
fun extractJvmEnvironmentItem(module: Module, runtimeClasspath: List<URI>): JvmEnvironmentItem? {
298+
return module.javaModule?.let { javaModule ->
299+
JvmEnvironmentItem(
300+
BspMappings.toBspId(module),
301+
runtimeClasspath.map { it.toString() },
302+
javaModule.jvmOps.toList(),
303+
bazelPathsResolver.unresolvedWorkspaceRoot().toString(),
304+
module.environmentVariables
305+
).apply {
306+
mainClasses = javaModule.mainClass?.let { listOf(JvmMainClass(it, javaModule.args)) }.orEmpty()
307+
}
293308
}
309+
}
294310

295-
val labels = BspMappings.toLabels(targets)
296-
return labels.mapNotNull {
297-
project.findModule(it)?.let(::extractJvmEnvironmentItem)
311+
return targets.mapNotNull {
312+
val label = Label(it.uri)
313+
val module = project.findModule(label)
314+
val runtimeClasspath = getRuntimeClasspath(cancelChecker, it)
315+
module?.let { extractJvmEnvironmentItem(module, runtimeClasspath) }
298316
}
299317
}
300318

319+
private fun getRuntimeClasspath(cancelChecker: CancelChecker, target: BuildTargetIdentifier): List<URI> {
320+
val queryFile = bspInfo.bazelBspDir().resolve("aspects/runtime_classpath_query.bzl")
321+
val cqueryResult = bazelRunner.commandBuilder().cquery()
322+
.withTargets(listOf(target.uri))
323+
.withFlags(listOf("--starlark:file=$queryFile", "--output=starlark"))
324+
.executeBazelCommand(parseProcessOutput = false)
325+
.waitAndGetResult(cancelChecker, ensureAllOutputRead = true)
326+
if (cqueryResult.isNotSuccess) throw RuntimeException("Could not query target '${target.uri}' for runtime classpath")
327+
val runtimeClasspath = cqueryResult.stdoutLines
328+
.filterNot { it.isEmpty() }
329+
.map { bazelPathsResolver.resolveOutput(Paths.get(it))}
330+
.filter { it.toFile().exists() } // I'm surprised this is needed, but we literally test it in e2e tests
331+
.map { it.toUri() }
332+
return runtimeClasspath
333+
}
334+
301335
fun buildTargetJavacOptions(project: Project, params: JavacOptionsParams): JavacOptionsResult {
302336
fun extractJavacOptionsItem(module: Module): JavacOptionsItem? =
303337
module.javaModule?.let {

server/src/main/kotlin/org/jetbrains/bsp/bazel/server/sync/ProjectSyncService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,12 @@ class ProjectSyncService(private val bspMapper: BspProjectMapper, private val pr
103103

104104
fun jvmRunEnvironment(cancelChecker: CancelChecker, params: JvmRunEnvironmentParams): JvmRunEnvironmentResult {
105105
val project = projectProvider.get(cancelChecker)
106-
return bspMapper.jvmRunEnvironment(project, params)
106+
return bspMapper.jvmRunEnvironment(project, params, cancelChecker)
107107
}
108108

109109
fun jvmTestEnvironment(cancelChecker: CancelChecker, params: JvmTestEnvironmentParams): JvmTestEnvironmentResult {
110110
val project = projectProvider.get(cancelChecker)
111-
return bspMapper.jvmTestEnvironment(project, params)
111+
return bspMapper.jvmTestEnvironment(project, params, cancelChecker)
112112
}
113113

114114
fun buildTargetJavacOptions(cancelChecker: CancelChecker, params: JavacOptionsParams): JavacOptionsResult {

server/src/main/kotlin/org/jetbrains/bsp/bazel/server/sync/languages/java/JavaLanguagePlugin.kt

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ class JavaLanguagePlugin(
5757
allOutputs,
5858
mainClass,
5959
argsList,
60-
runtimeClasspath,
6160
compileClasspath,
6261
sourcesClasspath,
6362
ideClasspath
@@ -112,17 +111,6 @@ class JavaLanguagePlugin(
112111
}
113112
}
114113

115-
fun toJvmEnvironmentItem(module: Module, javaModule: JavaModule): JvmEnvironmentItem =
116-
JvmEnvironmentItem(
117-
BspMappings.toBspId(module),
118-
javaModule.runtimeClasspath.map { it.toString() }.toList(),
119-
javaModule.jvmOps.toList(),
120-
bazelInfo.workspaceRoot.toString(),
121-
module.environmentVariables
122-
).apply {
123-
mainClasses = javaModule.mainClass?.let { listOf(JvmMainClass(it, javaModule.args)) }.orEmpty()
124-
}
125-
126114
fun toJavacOptionsItem(module: Module, javaModule: JavaModule): JavacOptionsItem =
127115
JavacOptionsItem(
128116
BspMappings.toBspId(module),

server/src/main/kotlin/org/jetbrains/bsp/bazel/server/sync/languages/java/JavaModule.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ data class JavaModule(
1818
val allOutputs: List<URI>,
1919
val mainClass: String?,
2020
val args: List<String>,
21-
val runtimeClasspath: List<URI>,
2221
val compileClasspath: List<URI>,
2322
val sourcesClasspath: List<URI>,
2423
val ideClasspath: List<URI>

server/src/test/kotlin/org/jetbrains/bsp/bazel/server/sync/ProjectStorageTest.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ class ProjectStorageTest {
4040
emptyList(),
4141
emptyList(),
4242
emptyList(),
43-
emptyList(),
4443
emptyList()
4544
)
4645
)

0 commit comments

Comments
 (0)