Skip to content

Commit

Permalink
[feature] support bzlmod in rules detection | #BAZEL-700 Done
Browse files Browse the repository at this point in the history
- detect bzlmod
- support dynamic rules detection when on bzlmod

Merge-request: BAZEL-MR-578
Merged-by: Xuan Son Trinh <xuanson.trinh@jetbrains.com>
  • Loading branch information
xuansontrinh authored and Space Team committed Oct 31, 2023
1 parent 89beaf7 commit 47cdfa8
Show file tree
Hide file tree
Showing 22 changed files with 437 additions and 278 deletions.
2 changes: 2 additions & 0 deletions WORKSPACE
Expand Up @@ -215,7 +215,9 @@ maven_install(
"commons-cli:commons-cli:jar:1.6.0",
"org.apache.logging.log4j:log4j-api:2.21.1",
"org.apache.logging.log4j:log4j-core:2.21.1",
"org.apache.velocity:velocity-engine-core:2.3",
"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3",
"org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0",
"org.junit.jupiter:junit-jupiter:5.10.0",
"com.fasterxml.jackson.core:jackson-databind:2.15.3",
"com.fasterxml.jackson.module:jackson-module-kotlin:2.15.3",
Expand Down
@@ -1,8 +1,8 @@
load("@io_bazel_rules_kotlin//kotlin/internal:defs.bzl", "KtJvmInfo")
load("@io_bazel_rules_kotlin//kotlin/internal:opts.bzl", "KotlincOptions")
load("@${ruleName}//kotlin/internal:defs.bzl", "KtJvmInfo")
load("@${ruleName}//kotlin/internal:opts.bzl", "KotlincOptions")
load("//aspects:utils/utils.bzl", "convert_struct_to_dict", "create_proto", "create_struct")

KOTLIN_TOOLCHAIN_TYPE = "@io_bazel_rules_kotlin//kotlin/internal:kt_toolchain_type"
KOTLIN_TOOLCHAIN_TYPE = "@${ruleName}//kotlin/internal:kt_toolchain_type"

def extract_kotlin_info(target, ctx, **kwargs):
if KtJvmInfo not in target:
Expand Down
Expand Up @@ -9,16 +9,19 @@ interface BazelInfo {
val outputBase: Path
val workspaceRoot: Path
val release: BazelRelease
val isBzlModEnabled: Boolean
}

data class BazelRelease(
val major: Int
) {

fun mainRepositoryReferencePrefix() = when(major) {
fun mainRepositoryReferencePrefix(isBzlModEnabled: Boolean) = when (major) {
in 0..3 -> throw RuntimeException("Unsupported Bazel version, use Bazel 4 or newer")
in 4..5 -> "//"
else -> "@//"
else ->
if (isBzlModEnabled) "@@//"
else "@//"
}

companion object {
Expand All @@ -44,16 +47,17 @@ data class BazelRelease(
}
}


fun BazelRelease?.orLatestSupported() = this ?: BazelRelease.LATEST_SUPPORTED_MAJOR

data class BasicBazelInfo(
override val execRoot: String,
override val outputBase: Path,
override val workspaceRoot: Path,
override val release: BazelRelease
override val execRoot: String,
override val outputBase: Path,
override val workspaceRoot: Path,
override val release: BazelRelease,
override val isBzlModEnabled: Boolean,
) : BazelInfo


class LazyBazelInfo(bazelInfoSupplier: () -> BazelInfo) : BazelInfo {
private val bazelInfo: BazelInfo by lazy { bazelInfoSupplier() }

Expand All @@ -68,4 +72,7 @@ class LazyBazelInfo(bazelInfoSupplier: () -> BazelInfo) : BazelInfo {

override val release: BazelRelease
get() = bazelInfo.release

override val isBzlModEnabled: Boolean
get() = bazelInfo.isBzlModEnabled
}
@@ -1,50 +1,58 @@
package org.jetbrains.bsp.bazel.bazelrunner

import ch.epfl.scala.bsp4j.StatusCode
import org.eclipse.lsp4j.jsonrpc.CancelChecker
import org.jetbrains.bsp.bazel.commons.escapeNewLines
import java.nio.file.Paths

class BazelInfoResolver(
private val bazelRunner: BazelRunner,
private val storage: BazelInfoStorage
private val bazelRunner: BazelRunner,
private val storage: BazelInfoStorage
) {

fun resolveBazelInfo(cancelChecker: CancelChecker): BazelInfo {
return LazyBazelInfo { storage.load() ?: bazelInfoFromBazel(cancelChecker) }
}

private fun bazelInfoFromBazel(cancelChecker: CancelChecker): BazelInfo {
val isBzlModEnabled = calculateBzlModEnabled(cancelChecker)
val processResult = bazelRunner.commandBuilder()
.info().executeBazelCommand(useBuildFlags = false)
.waitAndGetResult(cancelChecker,true)
return parseBazelInfo(processResult).also { storage.store(it) }
return parseBazelInfo(processResult, isBzlModEnabled).also { storage.store(it) }
}

private fun parseBazelInfo(bazelProcessResult: BazelProcessResult): BasicBazelInfo {
private fun parseBazelInfo(bazelProcessResult: BazelProcessResult, isBzlModEnabled: Boolean): BasicBazelInfo {
val outputMap = bazelProcessResult
.stdoutLines
.mapNotNull { line ->
InfoLinePattern.matchEntire(line)?.let { it.groupValues[1] to it.groupValues[2] }
}.toMap()
.stdoutLines
.mapNotNull { line ->
InfoLinePattern.matchEntire(line)?.let { it.groupValues[1] to it.groupValues[2] }
}.toMap()

fun BazelProcessResult.meaningfulOutput() = if (isNotSuccess) stderr else stdout

fun extract(name: String): String =
outputMap[name]
?: error("Failed to resolve $name from bazel info in ${bazelRunner.workspaceRoot}. " +
"Bazel Info output: '${bazelProcessResult.meaningfulOutput().escapeNewLines()}'")
outputMap[name]
?: error("Failed to resolve $name from bazel info in ${bazelRunner.workspaceRoot}. " +
"Bazel Info output: '${bazelProcessResult.meaningfulOutput().escapeNewLines()}'")

fun obtainBazelReleaseVersion() = BazelRelease.fromReleaseString(extract("release")) ?:
bazelRunner.workspaceRoot?.let { BazelRelease.fromBazelVersionFile(it) }.orLatestSupported()

return BasicBazelInfo(
execRoot = extract("execution_root"),
outputBase = Paths.get(extract("output_base")),
workspaceRoot = Paths.get(extract("workspace")),
release = obtainBazelReleaseVersion()
execRoot = extract("execution_root"),
outputBase = Paths.get(extract("output_base")),
workspaceRoot = Paths.get(extract("workspace")),
release = obtainBazelReleaseVersion(),
isBzlModEnabled = isBzlModEnabled
)
}

// this method does a small check whether bzlmod is enabled in the project
// by running an arbitrary a bazel mod command and check for ok status code
private fun calculateBzlModEnabled(cancelChecker: CancelChecker) =
bazelRunner.commandBuilder().showRepo().executeBazelCommand(parseProcessOutput = false).waitAndGetResult(cancelChecker).statusCode == StatusCode.OK

companion object {
private val InfoLinePattern = "([\\w-]+): (.*)".toRegex()
}
Expand Down
Expand Up @@ -28,7 +28,7 @@ class BazelRunner private constructor(
fun commandBuilder(): BazelRunnerCommandBuilder = BazelRunnerCommandBuilder(this)

fun runBazelCommandBes(
command: String,
command: List<String>,
flags: List<String>,
arguments: List<String>,
originId: String?,
Expand All @@ -45,7 +45,7 @@ class BazelRunner private constructor(
}

fun runBazelCommand(
command: String,
command: List<String>,
flags: List<String>,
arguments: List<String>,
originId: String?,
Expand All @@ -55,7 +55,7 @@ class BazelRunner private constructor(
val workspaceContext = workspaceContextProvider.currentWorkspaceContext()
val usedBuildFlags = if (useBuildFlags) buildFlags(workspaceContext) else emptyList()
val processArgs =
listOf(bazel(workspaceContext), command) + usedBuildFlags + flags + arguments
listOf(bazel(workspaceContext)) + command + usedBuildFlags + flags + arguments
logInvocation(processArgs, originId)
val processBuilder = ProcessBuilder(processArgs)
val outputLogger = bspClientLogger.takeIf { parseProcessOutput }
Expand Down
Expand Up @@ -6,7 +6,7 @@ import org.jetbrains.bsp.bazel.workspacecontext.TargetsSpec

class BazelRunnerBuildBuilder(
bazelRunner: BazelRunner,
bazelBuildCommand: String
bazelBuildCommand: List<String>
) : BazelRunnerBuilder(bazelRunner, bazelBuildCommand) {

override fun withTargets(bazelTargets: List<String>): BazelRunnerBuilder {
Expand Down
Expand Up @@ -9,7 +9,7 @@ import java.nio.file.Path

open class BazelRunnerBuilder internal constructor(
private val bazelRunner: BazelRunner,
private val bazelCommand: String
private val bazelCommand: List<String>,
) {

private val flags = mutableListOf<String>()
Expand Down
@@ -1,12 +1,20 @@
package org.jetbrains.bsp.bazel.bazelrunner

class BazelRunnerCommandBuilder internal constructor(private val bazelRunner: BazelRunner) {
fun aquery() = BazelRunnerBuilder(bazelRunner, "aquery")
fun clean() = BazelRunnerBuilder(bazelRunner, "clean")
fun fetch() = BazelRunnerBuilder(bazelRunner, "fetch")
fun info() = BazelRunnerBuilder(bazelRunner, "info")
fun run() = BazelRunnerBuilder(bazelRunner, "run")
fun query() = BazelRunnerBuilder(bazelRunner, "query")
fun build() = BazelRunnerBuildBuilder(bazelRunner, "build")
fun test() = BazelRunnerBuildBuilder(bazelRunner, "test")
fun aquery() = BazelRunnerBuilder(bazelRunner, listOf("aquery"))
fun clean() = BazelRunnerBuilder(bazelRunner, listOf("clean"))
fun fetch() = BazelRunnerBuilder(bazelRunner, listOf("fetch"))
fun info() = BazelRunnerBuilder(bazelRunner, listOf("info"))
fun run() = BazelRunnerBuilder(bazelRunner, listOf("run"))
fun mod(subcommand: String) = BazelRunnerBuilder(bazelRunner, listOf("mod", subcommand))
fun graph() = mod("graph")
fun deps() = mod("deps")
fun allPaths() = mod("all_paths")
fun path() = mod("path")
fun explain() = mod("explain")
fun showRepo() = mod("show_repo")
fun showExtension() = mod("show_extension")
fun query() = BazelRunnerBuilder(bazelRunner, listOf("query"))
fun build() = BazelRunnerBuildBuilder(bazelRunner, listOf("build"))
fun test() = BazelRunnerBuildBuilder(bazelRunner, listOf("test"))
}
Expand Up @@ -17,7 +17,7 @@ class BazelReleaseTest {

// then
release?.major shouldBe 4
release?.mainRepositoryReferencePrefix() shouldBe "//"
release?.mainRepositoryReferencePrefix(false) shouldBe "//"
}

@Test
Expand All @@ -27,7 +27,7 @@ class BazelReleaseTest {

// then
release?.major shouldBe 6
release?.mainRepositoryReferencePrefix() shouldBe "@//"
release?.mainRepositoryReferencePrefix(false) shouldBe "@//"
}

@Test
Expand Down
Expand Up @@ -34,10 +34,12 @@ class StoredBazelInfoTest {

// when
val bazelInfo = BasicBazelInfo(
"/private/var/tmp/_bazel/125c7a6ca879ed16a4b4b1a74bc5f27b/execroot/bazel_bsp",
Paths.get("/private/var/tmp/_bazel/125c7a6ca879ed16a4b4b1a74bc5f27b"),
Paths.get("/Users/user/workspace/bazel-bsp"),
BazelRelease(6))
"/private/var/tmp/_bazel/125c7a6ca879ed16a4b4b1a74bc5f27b/execroot/bazel_bsp",
Paths.get("/private/var/tmp/_bazel/125c7a6ca879ed16a4b4b1a74bc5f27b"),
Paths.get("/Users/user/workspace/bazel-bsp"),
BazelRelease(6),
false
)

storage.store(bazelInfo)
val loaded = storage.load()
Expand Down
Expand Up @@ -44,7 +44,7 @@ class EnvironmentCreatorTest {
dotBazelBsp.resolve("aspects/utils/utils.bzl").exists() shouldBeEqual true
dotBazelBsp.resolve("aspects/rules/java/java_info.bzl").exists() shouldBeEqual true
dotBazelBsp.resolve("aspects/rules/jvm/jvm_info.bzl").exists() shouldBeEqual true
dotBazelBsp.resolve("aspects/rules/kt/kt_info.bzl").exists() shouldBeEqual true
dotBazelBsp.resolve("aspects/rules/kt/kt_info.bzl.template").exists() shouldBeEqual true
dotBazelBsp.resolve("aspects/rules/python/python_info.bzl").exists() shouldBeEqual true
dotBazelBsp.resolve("aspects/rules/scala/scala_info.bzl").exists() shouldBeEqual true
dotBazelBsp.resolve("aspects/rules/cpp/cpp_info.bzl").exists() shouldBeEqual true
Expand Down
Expand Up @@ -19,6 +19,8 @@ kt_jvm_library(
"@io_bazel//third_party/grpc:grpc-jar_checked_in",
"@maven//:com_google_guava_guava",
"@maven//:org_apache_logging_log4j_log4j_api",
"@maven//:org_apache_velocity_velocity_engine_core",
"@maven//:org_eclipse_lsp4j_org_eclipse_lsp4j_jsonrpc",
"@maven//:org_jetbrains_kotlinx_kotlinx_serialization_json",
],
)

0 comments on commit 47cdfa8

Please sign in to comment.