Skip to content

Commit

Permalink
Actually format code
Browse files Browse the repository at this point in the history
  • Loading branch information
honnix committed Oct 22, 2024
1 parent 37836a5 commit b22fa68
Show file tree
Hide file tree
Showing 48 changed files with 3,148 additions and 2,736 deletions.
14 changes: 7 additions & 7 deletions cli/src/main/kotlin/com/bazel_diff/Main.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package com.bazel_diff

import com.bazel_diff.cli.BazelDiff
import picocli.CommandLine
import kotlin.system.exitProcess
import picocli.CommandLine

class Main {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val exitCode = CommandLine(BazelDiff()).execute(*args)
exitProcess(exitCode)
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
val exitCode = CommandLine(BazelDiff()).execute(*args)
exitProcess(exitCode)
}
}
}
94 changes: 50 additions & 44 deletions cli/src/main/kotlin/com/bazel_diff/bazel/BazelClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,65 @@ package com.bazel_diff.bazel

import com.bazel_diff.log.Logger
import com.google.devtools.build.lib.query2.proto.proto2api.Build
import java.util.Calendar
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.util.Calendar

class BazelClient(
private val useCquery: Boolean,
private val fineGrainedHashExternalRepos: Set<String>,
private val excludeExternalTargets: Boolean
private val useCquery: Boolean,
private val fineGrainedHashExternalRepos: Set<String>,
private val excludeExternalTargets: Boolean
) : KoinComponent {
private val logger: Logger by inject()
private val queryService: BazelQueryService by inject()
private val logger: Logger by inject()
private val queryService: BazelQueryService by inject()

suspend fun queryAllTargets(): List<BazelTarget> {
val queryEpoch = Calendar.getInstance().getTimeInMillis()
suspend fun queryAllTargets(): List<BazelTarget> {
val queryEpoch = Calendar.getInstance().getTimeInMillis()

val repoTargetsQuery = if (excludeExternalTargets) emptyList() else listOf("//external:all-targets")
val targets = if (useCquery) {
// Explicitly listing external repos here sometimes causes issues mentioned at
// https://bazel.build/query/cquery#recursive-target-patterns. Hence, we query all dependencies with `deps`
// instead. However, we still need to append all "//external:*" targets because fine-grained hash
// computation depends on hashing of source files in external repos as well, which is limited to repos
// explicitly mentioned in `fineGrainedHashExternalRepos` flag. Therefore, for any repos not mentioned there
// we are still relying on the repo-generation target under `//external` to compute the hash.
//
// In addition, we must include all source dependencies in this query in order for them to show up in
// `configuredRuleInput`. Hence, one must not filter them out with `kind(rule, deps(..))`. However, these
// source targets are omitted inside BazelQueryService with the custom starlark function used to print
// labels.
(queryService.query("deps(//...:all-targets)", useCquery = true) +
queryService.query(repoTargetsQuery.joinToString(" + ") { "'$it'" }))
.distinctBy { it.rule.name }
val repoTargetsQuery =
if (excludeExternalTargets) emptyList() else listOf("//external:all-targets")
val targets =
if (useCquery) {
// Explicitly listing external repos here sometimes causes issues mentioned at
// https://bazel.build/query/cquery#recursive-target-patterns. Hence, we query all
// dependencies with `deps`
// instead. However, we still need to append all "//external:*" targets because
// fine-grained hash
// computation depends on hashing of source files in external repos as well, which is
// limited to repos
// explicitly mentioned in `fineGrainedHashExternalRepos` flag. Therefore, for any repos
// not mentioned there
// we are still relying on the repo-generation target under `//external` to compute the
// hash.
//
// In addition, we must include all source dependencies in this query in order for them to
// show up in
// `configuredRuleInput`. Hence, one must not filter them out with `kind(rule, deps(..))`.
// However, these
// source targets are omitted inside BazelQueryService with the custom starlark function
// used to print
// labels.
(queryService.query("deps(//...:all-targets)", useCquery = true) +
queryService.query(repoTargetsQuery.joinToString(" + ") { "'$it'" }))
.distinctBy { it.rule.name }
} else {
val buildTargetsQuery = listOf("//...:all-targets") + fineGrainedHashExternalRepos.map { "@$it//...:all-targets" }
queryService.query((repoTargetsQuery + buildTargetsQuery).joinToString(" + ") { "'$it'" })
val buildTargetsQuery =
listOf("//...:all-targets") +
fineGrainedHashExternalRepos.map { "@$it//...:all-targets" }
queryService.query((repoTargetsQuery + buildTargetsQuery).joinToString(" + ") { "'$it'" })
}
val queryDuration = Calendar.getInstance().getTimeInMillis() - queryEpoch
logger.i { "All targets queried in $queryDuration" }
return targets.mapNotNull { target: Build.Target ->
when (target.type) {
Build.Target.Discriminator.RULE -> BazelTarget.Rule(target)
Build.Target.Discriminator.SOURCE_FILE -> BazelTarget.SourceFile(
target
)

Build.Target.Discriminator.GENERATED_FILE -> BazelTarget.GeneratedFile(
target
)

else -> {
logger.w { "Unsupported target type in the build graph: ${target.type.name}" }
null
}
}
val queryDuration = Calendar.getInstance().getTimeInMillis() - queryEpoch
logger.i { "All targets queried in $queryDuration" }
return targets.mapNotNull { target: Build.Target ->
when (target.type) {
Build.Target.Discriminator.RULE -> BazelTarget.Rule(target)
Build.Target.Discriminator.SOURCE_FILE -> BazelTarget.SourceFile(target)
Build.Target.Discriminator.GENERATED_FILE -> BazelTarget.GeneratedFile(target)
else -> {
logger.w { "Unsupported target type in the build graph: ${target.type.name}" }
null
}
}
}
}
}
230 changes: 118 additions & 112 deletions cli/src/main/kotlin/com/bazel_diff/bazel/BazelQueryService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,97 +5,101 @@ import com.bazel_diff.process.Redirect
import com.bazel_diff.process.process
import com.google.devtools.build.lib.analysis.AnalysisProtosV2
import com.google.devtools.build.lib.query2.proto.proto2api.Build
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
import java.nio.file.Files
import java.nio.file.Path

class BazelQueryService(
private val workingDirectory: Path,
private val bazelPath: Path,
private val startupOptions: List<String>,
private val commandOptions: List<String>,
private val cqueryOptions: List<String>,
private val keepGoing: Boolean,
private val noBazelrc: Boolean,
private val workingDirectory: Path,
private val bazelPath: Path,
private val startupOptions: List<String>,
private val commandOptions: List<String>,
private val cqueryOptions: List<String>,
private val keepGoing: Boolean,
private val noBazelrc: Boolean,
) : KoinComponent {
private val logger: Logger by inject()
private val logger: Logger by inject()

suspend fun query(
query: String,
useCquery: Boolean = false)
: List<Build.Target> {
// Unfortunately, there is still no direct way to tell if a target is compatible or not with the proto output
// by itself. So we do an extra cquery with the trick at
// https://bazel.build/extending/platforms#cquery-incompatible-target-detection to first find all compatible
// targets.
val compatibleTargetSet =
if (useCquery) {
runQuery(query, useCquery = true, outputCompatibleTargets = true).useLines {
it.filter { it.isNotBlank() }.toSet()
}
} else {
emptySet()
}
val outputFile = runQuery(query, useCquery)
suspend fun query(query: String, useCquery: Boolean = false): List<Build.Target> {
// Unfortunately, there is still no direct way to tell if a target is compatible or not with the
// proto output
// by itself. So we do an extra cquery with the trick at
// https://bazel.build/extending/platforms#cquery-incompatible-target-detection to first find
// all compatible
// targets.
val compatibleTargetSet =
if (useCquery) {
runQuery(query, useCquery = true, outputCompatibleTargets = true).useLines {
it.filter { it.isNotBlank() }.toSet()
}
} else {
emptySet()
}
val outputFile = runQuery(query, useCquery)

val targets = outputFile.inputStream().buffered().use { proto ->
if (useCquery) {
val cqueryResult = AnalysisProtosV2.CqueryResult.parseFrom(proto)
cqueryResult.resultsList.filter { it.target.rule.name in compatibleTargetSet }.map { it.target }
} else {
mutableListOf<Build.Target>().apply {
while (true) {
val target = Build.Target.parseDelimitedFrom(proto) ?: break
// EOF
add(target)
}
}
val targets =
outputFile.inputStream().buffered().use { proto ->
if (useCquery) {
val cqueryResult = AnalysisProtosV2.CqueryResult.parseFrom(proto)
cqueryResult.resultsList
.filter { it.target.rule.name in compatibleTargetSet }
.map { it.target }
} else {
mutableListOf<Build.Target>().apply {
while (true) {
val target = Build.Target.parseDelimitedFrom(proto) ?: break
// EOF
add(target)
}
}
}
}

return targets
}
return targets
}

@OptIn(ExperimentalCoroutinesApi::class)
private suspend fun runQuery(
query: String,
useCquery: Boolean,
outputCompatibleTargets: Boolean = false
): File {
val queryFile = Files.createTempFile(null, ".txt").toFile()
queryFile.deleteOnExit()
val outputFile = Files.createTempFile(null, ".bin").toFile()
outputFile.deleteOnExit()
@OptIn(ExperimentalCoroutinesApi::class)
private suspend fun runQuery(
query: String,
useCquery: Boolean,
outputCompatibleTargets: Boolean = false
): File {
val queryFile = Files.createTempFile(null, ".txt").toFile()
queryFile.deleteOnExit()
val outputFile = Files.createTempFile(null, ".bin").toFile()
outputFile.deleteOnExit()

queryFile.writeText(query)
queryFile.writeText(query)

val cmd: MutableList<String> = ArrayList<String>().apply {
add(bazelPath.toString())
if (noBazelrc) {
add("--bazelrc=/dev/null")
val cmd: MutableList<String> =
ArrayList<String>().apply {
add(bazelPath.toString())
if (noBazelrc) {
add("--bazelrc=/dev/null")
}
addAll(startupOptions)
if (useCquery) {
add("cquery")
if (!outputCompatibleTargets) {
// There is no need to query the transitions when querying for compatible targets.
add("--transitions=lite")
}
addAll(startupOptions)
if (useCquery) {
add("cquery")
if (!outputCompatibleTargets) {
// There is no need to query the transitions when querying for compatible targets.
add("--transitions=lite")
}
} else {
add("query")
}
add("--output")
if (useCquery) {
if (outputCompatibleTargets) {
add("starlark")
add("--starlark:file")
val cqueryOutputFile = Files.createTempFile(null, ".cquery").toFile()
cqueryOutputFile.deleteOnExit()
cqueryOutputFile.writeText("""
} else {
add("query")
}
add("--output")
if (useCquery) {
if (outputCompatibleTargets) {
add("starlark")
add("--starlark:file")
val cqueryOutputFile = Files.createTempFile(null, ".cquery").toFile()
cqueryOutputFile.deleteOnExit()
cqueryOutputFile.writeText(
"""
def format(target):
if providers(target) == None:
# skip printing non-target results. That is, source files and generated files won't be
Expand All @@ -104,46 +108,48 @@ class BazelQueryService(
if "IncompatiblePlatformProvider" not in providers(target):
return str(target.label)
return ""
""".trimIndent())
add(cqueryOutputFile.toString())
} else {
// Unfortunately, cquery does not support streamed_proto yet.
// See https://github.com/bazelbuild/bazel/issues/17743. This poses an issue for large monorepos.
add("proto")
}
"""
.trimIndent())
add(cqueryOutputFile.toString())
} else {
add("streamed_proto")
}
if (!useCquery) {
add("--order_output=no")
// Unfortunately, cquery does not support streamed_proto yet.
// See https://github.com/bazelbuild/bazel/issues/17743. This poses an issue for large
// monorepos.
add("proto")
}
if (keepGoing) {
add("--keep_going")
}
if (useCquery) {
addAll(cqueryOptions)
add("--consistent_labels")
} else {
addAll(commandOptions)
}
add("--query_file")
add(queryFile.toString())
}

logger.i { "Executing Query: $query" }
logger.i { "Command: ${cmd.toTypedArray().joinToString()}" }
val result = runBlocking {
process(
*cmd.toTypedArray(),
stdout = Redirect.ToFile(outputFile),
workingDirectory = workingDirectory.toFile(),
stderr = Redirect.PRINT,
destroyForcibly = true,
)
} else {
add("streamed_proto")
}
if (!useCquery) {
add("--order_output=no")
}
if (keepGoing) {
add("--keep_going")
}
if (useCquery) {
addAll(cqueryOptions)
add("--consistent_labels")
} else {
addAll(commandOptions)
}
add("--query_file")
add(queryFile.toString())
}

if (result.resultCode != 0)
throw RuntimeException("Bazel query failed, exit code ${result.resultCode}")
return outputFile
logger.i { "Executing Query: $query" }
logger.i { "Command: ${cmd.toTypedArray().joinToString()}" }
val result = runBlocking {
process(
*cmd.toTypedArray(),
stdout = Redirect.ToFile(outputFile),
workingDirectory = workingDirectory.toFile(),
stderr = Redirect.PRINT,
destroyForcibly = true,
)
}

if (result.resultCode != 0)
throw RuntimeException("Bazel query failed, exit code ${result.resultCode}")
return outputFile
}
}
Loading

0 comments on commit b22fa68

Please sign in to comment.