Skip to content

Commit

Permalink
Inverse sources with query
Browse files Browse the repository at this point in the history
refactor throw -> error

fixup! Typo fix
fixup! Typo fix
Typo fix

Tiny cleanup

Fix unit tests

[fix] Support bazel 5 in inverse sources query

WIP Inverse sources with query


Co-authored-by: Xuan Son Trinh <xuanson.trinh@jetbrains.com>


Merge-request: BAZEL-MR-771
Merged-by: Tomasz Pasternak <Tomasz.Pasternak@jetbrains.com>
  • Loading branch information
tpasternak authored and qodana-bot committed Jan 22, 2024
1 parent a2f623b commit 26ef246
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class BazelProjectMapper(
targets: Map<String, TargetInfo>,
rootTargets: Set<String>,
allTargetNames: List<String>,
workspaceContext: WorkspaceContext
workspaceContext: WorkspaceContext,
bazelInfo: BazelInfo
): Project {
languagePluginsService.prepareSync(targets.values.asSequence())
val dependencyTree = measure("Build dependency tree") {
Expand Down Expand Up @@ -106,7 +107,7 @@ class BazelProjectMapper(
createRustExternalModules(rustExternalTargetsToImport, dependencyTree, librariesFromDeps)
}
val allModules = modulesFromBazel + rustExternalModules
return Project(workspaceRoot, allModules.toList(), sourceToTarget, librariesToImport, invalidTargets)
return Project(workspaceRoot, allModules.toList(), sourceToTarget, librariesToImport, invalidTargets, bazelInfo.release)
}

private fun <K, V> concatenateMaps(vararg maps: Map<K, List<V>>): Map<K, List<V>> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import java.net.URI
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.name
import kotlin.io.path.relativeToOrNull
import kotlin.io.path.toPath

class BspProjectMapper(
Expand Down Expand Up @@ -243,13 +244,13 @@ class BspProjectMapper(
}

fun inverseSources(
project: Project, inverseSourcesParams: InverseSourcesParams
project: Project, inverseSourcesParams: InverseSourcesParams, cancelChecker: CancelChecker
): InverseSourcesResult {
val documentUri = BspMappings.toUri(inverseSourcesParams.textDocument)
val targets = project.findTargetBySource(documentUri)
?.let { listOf(BspMappings.toBspId(it)) }
.orEmpty()
return InverseSourcesResult(targets)
val documentRelativePath = documentUri
.toPath()
.relativeToOrNull(project.workspaceRoot.toPath()) ?: throw RuntimeException("File path outside of project root")
return InverseSourcesQuery.inverseSourcesQuery(documentRelativePath, bazelRunner, project.bazelRelease, cancelChecker)
}

fun dependencySources(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.jetbrains.bsp.bazel.server.sync

import ch.epfl.scala.bsp4j.BuildTargetIdentifier
import ch.epfl.scala.bsp4j.InverseSourcesResult
import ch.epfl.scala.bsp4j.StatusCode
import org.eclipse.lsp4j.jsonrpc.CancelChecker
import org.jetbrains.bsp.bazel.bazelrunner.BazelRelease
import org.jetbrains.bsp.bazel.bazelrunner.BazelRunner
import java.nio.file.Path

object InverseSourcesQuery {
fun inverseSourcesQuery(
documentRelativePath: Path,
bazelRunner: BazelRunner,
bazelInfo: BazelRelease,
cancelChecker: CancelChecker
): InverseSourcesResult {
val fileLabel = fileLabel(documentRelativePath, bazelRunner, cancelChecker)
?: return InverseSourcesResult(
emptyList()
)
val listOfLabels = targetLabels(fileLabel, bazelRunner, bazelInfo, cancelChecker)
return InverseSourcesResult(listOfLabels.map { BuildTargetIdentifier(it) })
}

/**
* @return list of targets that contain `fileLabel` in their `srcs` attribute
*/
private fun targetLabels(
fileLabel: String,
bazelRunner: BazelRunner,
bazelRelease: BazelRelease,
cancelChecker: CancelChecker
): List<String> {
val packageLabel = fileLabel.replace(":.*".toRegex(), ":*")
val consistentLabelsArg = listOfNotNull(if (bazelRelease.major >= 6) "--consistent_labels" else null) // #bazel5
val targetLabelsQuery =
bazelRunner.commandBuilder().query()
.withArgument("attr('srcs', ${fileLabel}, ${packageLabel})")
.withArguments(consistentLabelsArg)
.executeBazelCommand(null).waitAndGetResult(cancelChecker)
if (targetLabelsQuery.statusCode == StatusCode.OK) {
return targetLabelsQuery.stdoutLines
} else {
error("Could not retrieve inverse sources")
}
}

/**
* @return Bazel label corresponding to file path
*
* For example when you pass a relative path like "foo/Lib.kt", you will receive "//foo:Lib.kt".
* Null is returned in case the file does not exist or does not belong to any target's sources list
*/
private fun fileLabel(
relativePath: Path,
bazelRunner: BazelRunner,
cancelChecker: CancelChecker
): String? {
val fileLabelResult = bazelRunner.commandBuilder().query().withTargets(listOf(relativePath.toString()))
.executeBazelCommand(null).waitAndGetResult(cancelChecker)
return if (fileLabelResult.statusCode == StatusCode.OK && fileLabelResult.stdoutLines.size == 1) {
fileLabelResult.stdoutLines.first()
} else if (fileLabelResult.stderrLines.first().startsWith("ERROR: no such target '")) {
null
} else {
throw RuntimeException("Could not find file. Bazel query failed:\n ${fileLabelResult.stderrLines.joinToString { "\n" }}\n")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class ProjectResolver(
) { targetInfoReader.readTargetMapFromAspectOutputs(aspectOutputs) }
return measured(
"Mapping to internal model"
) { bazelProjectMapper.createProject(targets, rootTargets.toSet(), allTargetNames, workspaceContext) }
) { bazelProjectMapper.createProject(targets, rootTargets.toSet(), allTargetNames, workspaceContext, bazelInfo) }
}

private fun buildProjectWithAspect(cancelChecker: CancelChecker, workspaceContext: WorkspaceContext): BazelBspAspectsManagerResult =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class ProjectSyncService(private val bspMapper: BspProjectMapper, private val pr
inverseSourcesParams: InverseSourcesParams
): InverseSourcesResult {
val project = projectProvider.get(cancelChecker)
return bspMapper.inverseSources(project, inverseSourcesParams)
return bspMapper.inverseSources(project, inverseSourcesParams, cancelChecker)
}

fun buildTargetDependencySources(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jetbrains.bsp.bazel.server.sync.model

import org.jetbrains.bsp.bazel.bazelrunner.BazelInfo
import org.jetbrains.bsp.bazel.bazelrunner.BazelRelease
import org.jetbrains.bsp.bazel.server.sync.languages.rust.RustModule
import java.net.URI

Expand All @@ -10,6 +12,7 @@ data class Project(
val sourceToTarget: Map<URI, Label>,
val libraries: Map<String, Library>,
val invalidTargets: List<Label>,
val bazelRelease: BazelRelease
) {
private val moduleMap: Map<Label, Module> = modules.associateBy(Module::label)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jetbrains.bsp.bazel.server.sync

import io.kotest.matchers.shouldBe
import org.jetbrains.bsp.bazel.bazelrunner.BazelRelease
import java.io.IOException
import java.net.URI
import org.jetbrains.bsp.bazel.logger.BspClientLogger
Expand Down Expand Up @@ -64,6 +65,7 @@ class ProjectStorageTest {
mapOf(URI.create("file:///root/project/Lib.java") to Label("file:///root")),
emptyMap(),
emptyList(),
BazelRelease(7),
)
storage.store(project)
val loaded = storage.load()
Expand Down

0 comments on commit 26ef246

Please sign in to comment.