Skip to content

Commit 6752eff

Browse files
Allows for controlling with attributes are ignored during rule hashing (#182)
* WIP: Ignore location attribute Related Different workspaces produce different hashes #180 * properly inject argument * get tests running
1 parent e226c1c commit 6752eff

File tree

9 files changed

+57
-21
lines changed

9 files changed

+57
-21
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ workspace.
121121
individual third party dependency change won't
122122
invalidate all targets in the mono repo.
123123
-h, --help Show this help message and exit.
124+
--ignoredRuleHashingAttributes=<ignoredRuleHashingAttributes>
125+
Attributes that should be ignored when hashing rule
126+
targets.
124127
-k, --[no-]keep_going This flag controls if `bazel query` will be executed
125128
with the `--keep_going` flag or not. Disabling this
126129
flag allows you to catch configuration issues in

cli/src/main/kotlin/com/bazel_diff/bazel/BazelRule.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ import com.google.devtools.build.lib.query2.proto.proto2api.Build
77
// Ignore generator_location when computing a target's hash since it is likely to change and does not
88
// affect a target's generated actions. Internally, Bazel also does this when computing a target's hash:
99
// https://github.com/bazelbuild/bazel/blob/6971b016f1e258e3bb567a0f9fe7a88ad565d8f2/src/main/java/com/google/devtools/build/lib/query2/query/output/SyntheticAttributeHashCalculator.java#L78-L81
10-
private val IGNORED_ATTRS = arrayOf("generator_location")
10+
private val DEFAULT_IGNORED_ATTRS = arrayOf("generator_location")
1111

1212
class BazelRule(private val rule: Build.Rule) {
13-
val digest: ByteArray by lazy {
14-
sha256 {
13+
fun digest(ignoredAttrs: Set<String>): ByteArray {
14+
return sha256 {
1515
safePutBytes(rule.ruleClassBytes.toByteArray())
1616
safePutBytes(rule.nameBytes.toByteArray())
1717
safePutBytes(rule.skylarkEnvironmentHashCodeBytes.toByteArray())
1818
for (attribute in rule.attributeList) {
19-
if (!IGNORED_ATTRS.contains(attribute.name))
19+
if (!DEFAULT_IGNORED_ATTRS.contains(attribute.name) && !ignoredAttrs.contains(attribute.name))
2020
safePutBytes(attribute.toByteArray())
2121
}
2222
}

cli/src/main/kotlin/com/bazel_diff/cli/GenerateHashesCommand.kt

+9-1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ class GenerateHashesCommand : Callable<Int> {
110110
)
111111
var outputPath: File? = null
112112

113+
@CommandLine.Option(
114+
names = ["--ignoredRuleHashingAttributes"],
115+
description = ["Attributes that should be ignored when hashing rule targets."],
116+
scope = CommandLine.ScopeType.INHERIT,
117+
converter = [OptionsConverter::class],
118+
)
119+
var ignoredRuleHashingAttributes: Set<String> = emptySet()
120+
113121
@CommandLine.Spec
114122
lateinit var spec: CommandLine.Model.CommandSpec
115123

@@ -134,7 +142,7 @@ class GenerateHashesCommand : Callable<Int> {
134142
)
135143
}
136144

137-
return when (GenerateHashesInteractor().execute(seedFilepaths, outputPath)) {
145+
return when (GenerateHashesInteractor().execute(seedFilepaths, outputPath, ignoredRuleHashingAttributes)) {
138146
true -> CommandLine.ExitCode.OK
139147
false -> CommandLine.ExitCode.SOFTWARE
140148
}.also { stopKoin() }

cli/src/main/kotlin/com/bazel_diff/hash/BuildGraphHasher.kt

+14-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ class BuildGraphHasher(private val bazelClient: BazelClient) : KoinComponent {
2626
private val sourceFileHasher: SourceFileHasher by inject()
2727
private val logger: Logger by inject()
2828

29-
fun hashAllBazelTargetsAndSourcefiles(seedFilepaths: Set<Path> = emptySet()): Map<String, String> {
29+
fun hashAllBazelTargetsAndSourcefiles(
30+
seedFilepaths: Set<Path> = emptySet(),
31+
ignoredAttrs: Set<String> = emptySet()
32+
): Map<String, String> {
3033
/**
3134
* Bazel will lock parallel queries but this is still allowing us to hash source files while executing a parallel query
3235
*/
@@ -56,7 +59,12 @@ class BuildGraphHasher(private val bazelClient: BazelClient) : KoinComponent {
5659
Pair(sourceDigestsFuture.await(), targetsTask.await())
5760
}
5861
val seedForFilepaths = createSeedForFilepaths(seedFilepaths)
59-
return hashAllTargets(seedForFilepaths, sourceDigests, allTargets)
62+
return hashAllTargets(
63+
seedForFilepaths,
64+
sourceDigests,
65+
allTargets,
66+
ignoredAttrs
67+
)
6068
}
6169

6270
private fun hashSourcefiles(targets: List<Build.Target>): ConcurrentMap<String, ByteArray> {
@@ -94,7 +102,8 @@ class BuildGraphHasher(private val bazelClient: BazelClient) : KoinComponent {
94102
private fun hashAllTargets(
95103
seedHash: ByteArray,
96104
sourceDigests: ConcurrentMap<String, ByteArray>,
97-
allTargets: List<BazelTarget>
105+
allTargets: List<BazelTarget>,
106+
ignoredAttrs: Set<String>
98107
): Map<String, String> {
99108
val ruleHashes: ConcurrentMap<String, ByteArray> = ConcurrentHashMap()
100109
val targetToRule: MutableMap<String, BazelRule> = HashMap()
@@ -107,7 +116,8 @@ class BuildGraphHasher(private val bazelClient: BazelClient) : KoinComponent {
107116
targetToRule,
108117
sourceDigests,
109118
ruleHashes,
110-
seedHash
119+
seedHash,
120+
ignoredAttrs
111121
)
112122
Pair(target.name, targetDigest.toHexString())
113123
}

cli/src/main/kotlin/com/bazel_diff/hash/RuleHasher.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class RuleHasher(private val useCquery: Boolean, private val fineGrainedHashExte
3030
ruleHashes: ConcurrentMap<String, ByteArray>,
3131
sourceDigests: ConcurrentMap<String, ByteArray>,
3232
seedHash: ByteArray?,
33-
depPath: LinkedHashSet<String>?
33+
depPath: LinkedHashSet<String>?,
34+
ignoredAttrs: Set<String>
3435
): ByteArray {
3536
val depPathClone = if (depPath != null) LinkedHashSet(depPath) else LinkedHashSet()
3637
if (depPathClone.contains(rule.name)) {
@@ -40,7 +41,7 @@ class RuleHasher(private val useCquery: Boolean, private val fineGrainedHashExte
4041
ruleHashes[rule.name]?.let { return it }
4142

4243
val finalHashValue = sha256 {
43-
safePutBytes(rule.digest)
44+
safePutBytes(rule.digest(ignoredAttrs))
4445
safePutBytes(seedHash)
4546

4647
for (ruleInput in rule.ruleInputList(useCquery, fineGrainedHashExternalRepos)) {
@@ -60,6 +61,7 @@ class RuleHasher(private val useCquery: Boolean, private val fineGrainedHashExte
6061
sourceDigests,
6162
seedHash,
6263
depPathClone,
64+
ignoredAttrs
6365
)
6466
safePutBytes(ruleInputHash)
6567
}

cli/src/main/kotlin/com/bazel_diff/hash/TargetHasher.kt

+13-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ class TargetHasher : KoinComponent {
1414
allRulesMap: Map<String, BazelRule>,
1515
sourceDigests: ConcurrentMap<String, ByteArray>,
1616
ruleHashes: ConcurrentMap<String, ByteArray>,
17-
seedHash: ByteArray?
17+
seedHash: ByteArray?,
18+
ignoredAttrs: Set<String>
1819
): ByteArray {
1920
return when (target) {
2021
is BazelTarget.GeneratedFile -> {
@@ -30,12 +31,21 @@ class TargetHasher : KoinComponent {
3031
ruleHashes,
3132
sourceDigests,
3233
seedHash,
33-
depPath = null
34+
depPath = null,
35+
ignoredAttrs
3436
)
3537
}
3638
}
3739
is BazelTarget.Rule -> {
38-
ruleHasher.digest(target.rule, allRulesMap, ruleHashes, sourceDigests, seedHash, depPath = null)
40+
ruleHasher.digest(
41+
target.rule,
42+
allRulesMap,
43+
ruleHashes,
44+
sourceDigests,
45+
seedHash,
46+
depPath = null,
47+
ignoredAttrs
48+
)
3949
}
4050
is BazelTarget.SourceFile -> sha256 {
4151
safePutBytes(sourceDigests[target.sourceFileName])

cli/src/main/kotlin/com/bazel_diff/interactor/GenerateHashesInteractor.kt

+5-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class GenerateHashesInteractor : KoinComponent {
1818
private val logger: Logger by inject()
1919
private val gson: Gson by inject()
2020

21-
fun execute(seedFilepaths: File?, outputPath: File?): Boolean {
21+
fun execute(seedFilepaths: File?, outputPath: File?, ignoredRuleHashingAttributes: Set<String>): Boolean {
2222
return try {
2323
val epoch = Calendar.getInstance().getTimeInMillis()
2424
var seedFilepathsSet: Set<Path> = when {
@@ -31,7 +31,10 @@ class GenerateHashesInteractor : KoinComponent {
3131
}
3232
else -> emptySet()
3333
}
34-
val hashes = buildGraphHasher.hashAllBazelTargetsAndSourcefiles(seedFilepathsSet)
34+
val hashes = buildGraphHasher.hashAllBazelTargetsAndSourcefiles(
35+
seedFilepathsSet,
36+
ignoredRuleHashingAttributes
37+
)
3538
when (outputPath) {
3639
null -> FileWriter(FileDescriptor.out)
3740
else -> FileWriter(outputPath)

cli/src/test/kotlin/com/bazel_diff/bazel/BazelRuleTest.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class BazelRuleTest {
1919
.setRuleClass("java_library")
2020
.setName("libbar")
2121
.build()
22-
assertThat(BazelRule(rule1Pb).digest).isNotEqualTo(BazelRule(rule2Pb).digest)
22+
assertThat(BazelRule(rule1Pb).digest(emptySet())).isNotEqualTo(BazelRule(rule2Pb).digest(emptySet()))
2323
}
2424
@Test
2525
fun testIgnoreAttributes() {
@@ -41,6 +41,6 @@ class BazelRuleTest {
4141
.setStringValue("path/to/BUILD:111:1").build())
4242
.build()
4343

44-
assertThat(BazelRule(rule1Pb).digest).isEqualTo(BazelRule(rule2Pb).digest)
44+
assertThat(BazelRule(rule1Pb).digest(emptySet())).isEqualTo(BazelRule(rule2Pb).digest(emptySet()))
4545
}
46-
}
46+
}

cli/src/test/kotlin/com/bazel_diff/hash/BuildGraphHasherTest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class BuildGraphHasherTest : KoinTest {
162162
assertThat(hash).hasSize(3)
163163
val oldHash = hash["rule3"]!!
164164

165-
whenever(generator.rule.digest).thenReturn("newDigest".toByteArray())
165+
whenever(generator.rule.digest(emptySet())).thenReturn("newDigest".toByteArray())
166166
hash = hasher.hashAllBazelTargetsAndSourcefiles()
167167
assertThat(hash).hasSize(3)
168168
val newHash = hash["rule3"]!!
@@ -175,7 +175,7 @@ class BuildGraphHasherTest : KoinTest {
175175
val rule = mock<BazelRule>()
176176
whenever(rule.name).thenReturn(name)
177177
whenever(rule.ruleInputList(false, emptySet())).thenReturn(inputs)
178-
whenever(rule.digest).thenReturn(digest.toByteArray())
178+
whenever(rule.digest(emptySet())).thenReturn(digest.toByteArray())
179179
whenever(target.rule).thenReturn(rule)
180180
whenever(target.name).thenReturn(name)
181181
return target

0 commit comments

Comments
 (0)