Skip to content

Commit b1d406b

Browse files
Merge pull request #66 from Tinder/seed_hash_files
Seed Hashfiles
2 parents de74691 + d849d30 commit b1d406b

File tree

5 files changed

+161
-49
lines changed

5 files changed

+161
-49
lines changed

README.md

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -134,31 +134,39 @@ Writes to the file the modified filepaths between two revisions.
134134
`generate-hashes` Command
135135

136136
```terminal
137-
Usage: bazel-diff generate-hashes [-hV] -b=<bazelPath>
138-
[-co=<bazelCommandOptions>]
139-
[-m=<modifiedFilepaths>]
137+
Usage: bazel-diff generate-hashes [-m=<modifiedFilepaths> | -a] [-hV]
138+
-b=<bazelPath> [-co=<bazelCommandOptions>]
139+
[-s=<seedFilepaths>]
140140
[-so=<bazelStartupOptions>]
141141
-w=<workspacePath> <outputPath>
142142
Writes to a file the SHA256 hashes for each Bazel Target in the provided
143143
workspace.
144-
<outputPath> The filepath to write the resulting JSON of dictionary
145-
target => SHA-256 values
144+
<outputPath> The filepath to write the resulting JSON of
145+
dictionary target => SHA-256 values
146+
-a, --all-sourcefiles Experimental: Hash all sourcefile targets (instead of
147+
relying on --modifiedFilepaths), Warning:
148+
Performance may degrade from reading all source
149+
files
146150
-b, --bazelPath=<bazelPath>
147-
Path to Bazel binary
151+
Path to Bazel binary
148152
-co, --bazelCommandOptions=<bazelCommandOptions>
149-
Additional space separated Bazel command options used when
150-
invoking Bazel
151-
-h, --help Show this help message and exit.
153+
Additional space separated Bazel command options used
154+
when invoking Bazel
155+
-h, --help Show this help message and exit.
152156
-m, --modifiedFilepaths=<modifiedFilepaths>
153-
The path to a file containing the list of modified
154-
filepaths in the workspace, you can use the
155-
'modified-filepaths' command to get this list
157+
The path to a file containing the list of modified
158+
filepaths in the workspace, you can use the
159+
'modified-filepaths' command to get this list
160+
-s, --seed-filepaths=<seedFilepaths>
161+
A text file containing a newline separated list of
162+
filepaths, each of these filepaths will be read and
163+
used as a seed for all targets.
156164
-so, --bazelStartupOptions=<bazelStartupOptions>
157-
Additional space separated Bazel client startup options
158-
used when invoking Bazel
159-
-V, --version Print version information and exit.
165+
Additional space separated Bazel client startup
166+
options used when invoking Bazel
167+
-V, --version Print version information and exit.
160168
-w, --workspacePath=<workspacePath>
161-
Path to Bazel workspace directory.
169+
Path to Bazel workspace directory.
162170
```
163171

164172
## Installing
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.bazel_diff;
2+
3+
import java.nio.file.Path;
4+
import java.nio.file.Files;
5+
import java.io.IOException;
6+
7+
interface FilesClient {
8+
byte[] readFile(Path path) throws IOException;
9+
}
10+
11+
class FilesClientImp implements FilesClient {
12+
FilesClientImp() {}
13+
14+
@Override
15+
public byte[] readFile(Path path) throws IOException {
16+
if (path.toFile().exists() && path.toFile().canRead()) {
17+
return Files.readAllBytes(path);
18+
}
19+
return new byte[0];
20+
}
21+
}

src/main/java/com/bazel_diff/TargetHashingClient.java

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
package com.bazel_diff;
22

3+
import java.io.ByteArrayOutputStream;
34
import java.io.IOException;
45
import java.nio.file.Path;
56
import java.security.MessageDigest;
67
import java.security.NoSuchAlgorithmException;
78
import java.util.*;
89
import java.util.stream.Collectors;
10+
import com.google.common.primitives.Bytes;
911

1012
interface TargetHashingClient {
11-
Map<String, String> hashAllBazelTargets(Set<Path> modifiedFilepaths) throws IOException, NoSuchAlgorithmException;
12-
Map<String, String> hashAllBazelTargetsAndSourcefiles() throws IOException, NoSuchAlgorithmException;
13+
Map<String, String> hashAllBazelTargets(Set<Path> modifiedFilepaths, Set<Path> seedFilepaths) throws IOException, NoSuchAlgorithmException;
14+
Map<String, String> hashAllBazelTargetsAndSourcefiles(Set<Path> seedFilepaths) throws IOException, NoSuchAlgorithmException;
1315
Set<String> getImpactedTargets(Map<String, String> startHashes, Map<String, String> endHashes, String avoidQuery, Boolean hashAllTargets) throws IOException;
1416
}
1517

1618
class TargetHashingClientImpl implements TargetHashingClient {
1719
private BazelClient bazelClient;
20+
private FilesClient files;
1821

19-
TargetHashingClientImpl(BazelClient bazelClient) {
22+
TargetHashingClientImpl(BazelClient bazelClient, FilesClient files) {
2023
this.bazelClient = bazelClient;
24+
this.files = files;
2125
}
2226

2327
@Override
24-
public Map<String, String> hashAllBazelTargets(Set<Path> modifiedFilepaths) throws IOException, NoSuchAlgorithmException {
28+
public Map<String, String> hashAllBazelTargets(Set<Path> modifiedFilepaths, Set<Path> seedFilepaths) throws IOException, NoSuchAlgorithmException {
2529
Set<BazelSourceFileTarget> bazelSourcefileTargets = bazelClient.convertFilepathsToSourceTargets(modifiedFilepaths);
26-
return hashAllTargets(bazelSourcefileTargets);
30+
return hashAllTargets(createSeedForFilepaths(seedFilepaths), bazelSourcefileTargets);
2731
}
2832

2933
@Override
30-
public Map<String, String> hashAllBazelTargetsAndSourcefiles() throws IOException, NoSuchAlgorithmException {
34+
public Map<String, String> hashAllBazelTargetsAndSourcefiles(Set<Path> seedFilepaths) throws IOException, NoSuchAlgorithmException {
3135
Set<BazelSourceFileTarget> bazelSourcefileTargets = bazelClient.queryAllSourcefileTargets();
32-
return hashAllTargets(bazelSourcefileTargets);
36+
return hashAllTargets(createSeedForFilepaths(seedFilepaths), bazelSourcefileTargets);
3337
}
3438

3539
@Override
@@ -56,7 +60,8 @@ private byte[] createDigestForTarget(
5660
BazelTarget target,
5761
Map<String, BazelRule> allRulesMap,
5862
Set<BazelSourceFileTarget> bazelSourcefileTargets,
59-
Map<String, byte[]> ruleHashes
63+
Map<String, byte[]> ruleHashes,
64+
byte[] seedHash
6065
) throws NoSuchAlgorithmException {
6166
BazelRule targetRule = target.getRule();
6267
if (target.hasSourceFile()) {
@@ -67,24 +72,31 @@ private byte[] createDigestForTarget(
6772
if (sourceTargetDigestBytes != null) {
6873
digest.update(sourceTargetDigestBytes);
6974
}
75+
if (seedHash != null) {
76+
digest.update(seedHash);
77+
}
7078
return digest.digest().clone();
7179
}
7280
}
73-
return createDigestForRule(targetRule, allRulesMap, ruleHashes, bazelSourcefileTargets);
81+
return createDigestForRule(targetRule, allRulesMap, ruleHashes, bazelSourcefileTargets, seedHash);
7482
}
7583

7684
private byte[] createDigestForRule(
7785
BazelRule rule,
7886
Map<String, BazelRule> allRulesMap,
7987
Map<String, byte[]> ruleHashes,
80-
Set<BazelSourceFileTarget> bazelSourcefileTargets
88+
Set<BazelSourceFileTarget> bazelSourcefileTargets,
89+
byte[] seedHash
8190
) throws NoSuchAlgorithmException {
8291
byte[] existingByteArray = ruleHashes.get(rule.getName());
8392
if (existingByteArray != null) {
8493
return existingByteArray;
8594
}
8695
MessageDigest digest = MessageDigest.getInstance("SHA-256");
8796
digest.update(rule.getDigest());
97+
if (seedHash != null) {
98+
digest.update(seedHash);
99+
}
88100
for (String ruleInput : rule.getRuleInputList()) {
89101
digest.update(ruleInput.getBytes());
90102
BazelRule inputRule = allRulesMap.get(ruleInput);
@@ -94,7 +106,8 @@ private byte[] createDigestForRule(
94106
inputRule,
95107
allRulesMap,
96108
ruleHashes,
97-
bazelSourcefileTargets
109+
bazelSourcefileTargets,
110+
seedHash
98111
);
99112
if (ruleInputHash != null) {
100113
digest.update(ruleInputHash);
@@ -108,6 +121,17 @@ private byte[] createDigestForRule(
108121
return finalHashValue;
109122
}
110123

124+
private byte[] createSeedForFilepaths(Set<Path> seedFilepaths) throws IOException, NoSuchAlgorithmException {
125+
if (seedFilepaths == null || seedFilepaths.size() == 0) {
126+
return new byte[0];
127+
}
128+
MessageDigest digest = MessageDigest.getInstance("SHA-256");
129+
for (Path path: seedFilepaths) {
130+
digest.update(this.files.readFile(path));
131+
}
132+
return digest.digest().clone();
133+
}
134+
111135
private byte[] getDigestForSourceTargetName(
112136
String sourceTargetName,
113137
Set<BazelSourceFileTarget> bazelSourcefileTargets
@@ -138,7 +162,7 @@ private String getNameForTarget(BazelTarget target) {
138162
return null;
139163
}
140164

141-
private Map<String, String> hashAllTargets(Set<BazelSourceFileTarget> bazelSourcefileTargets) throws IOException, NoSuchAlgorithmException {
165+
private Map<String, String> hashAllTargets(byte[] seedHash, Set<BazelSourceFileTarget> bazelSourcefileTargets) throws IOException, NoSuchAlgorithmException {
142166
List<BazelTarget> allTargets = bazelClient.queryAllTargets();
143167
Map<String, String> targetHashes = new HashMap<>();
144168
Map<String, byte[]> ruleHashes = new HashMap<>();
@@ -159,10 +183,13 @@ private Map<String, String> hashAllTargets(Set<BazelSourceFileTarget> bazelSourc
159183
target,
160184
allRulesMap,
161185
bazelSourcefileTargets,
162-
ruleHashes
186+
ruleHashes,
187+
seedHash
163188
);
164189
if (targetDigest != null) {
165-
targetHashes.put(targetName, convertByteArrayToString(targetDigest));
190+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
191+
outputStream.write(targetDigest);
192+
targetHashes.put(targetName, convertByteArrayToString(outputStream.toByteArray()));
166193
}
167194
}
168195
return targetHashes;

src/main/java/com/bazel_diff/main.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,28 @@ static class Exclusive {
9292
Boolean hashAllSourcefiles;
9393
}
9494

95+
@Option(names = {"-s", "--seed-filepaths"}, description = "A text file containing a newline separated list of filepaths, each of these filepaths will be read and used as a seed for all targets.")
96+
File seedFilepaths;
97+
9598
@Parameters(index = "0", description = "The filepath to write the resulting JSON of dictionary target => SHA-256 values")
9699
File outputPath;
97100

98101
@Override
99102
public Integer call() {
100103
GitClient gitClient = new GitClientImpl(parent.workspacePath);
101104
BazelClient bazelClient = new BazelClientImpl(parent.workspacePath, parent.bazelPath, parent.bazelStartupOptions, parent.bazelCommandOptions, BazelDiff.isVerbose());
102-
TargetHashingClient hashingClient = new TargetHashingClientImpl(bazelClient);
105+
TargetHashingClient hashingClient = new TargetHashingClientImpl(bazelClient, new FilesClientImp());
103106
try {
104107
gitClient.ensureAllChangesAreCommitted();
105108
Set<Path> modifiedFilepathsSet = new HashSet<>();
109+
Set<Path> seedFilepathsSet = new HashSet<>();
110+
if (seedFilepaths != null) {
111+
FileReader fileReader = new FileReader(seedFilepaths);
112+
BufferedReader bufferedReader = new BufferedReader(fileReader);
113+
seedFilepathsSet = bufferedReader.lines()
114+
.map( line -> new File(line).toPath())
115+
.collect(Collectors.toSet());
116+
}
106117
Map<String, String> hashes = new HashMap<>();
107118
if (exclusive != null) {
108119
if (exclusive.modifiedFilepaths != null) {
@@ -112,12 +123,12 @@ public Integer call() {
112123
.lines()
113124
.map( line -> new File(line).toPath())
114125
.collect(Collectors.toSet());
115-
hashes = hashingClient.hashAllBazelTargets(modifiedFilepathsSet);
126+
hashes = hashingClient.hashAllBazelTargets(modifiedFilepathsSet, seedFilepathsSet);
116127
} else if (exclusive.hashAllSourcefiles) {
117-
hashes = hashingClient.hashAllBazelTargetsAndSourcefiles();
128+
hashes = hashingClient.hashAllBazelTargetsAndSourcefiles(seedFilepathsSet);
118129
}
119130
} else {
120-
hashes = hashingClient.hashAllBazelTargets(modifiedFilepathsSet);
131+
hashes = hashingClient.hashAllBazelTargets(modifiedFilepathsSet, seedFilepathsSet);
121132
}
122133
Gson gson = new GsonBuilder().setPrettyPrinting().create();
123134
FileWriter myWriter = new FileWriter(outputPath);
@@ -182,7 +193,7 @@ public Integer call() throws IOException {
182193
}
183194
GitClient gitClient = new GitClientImpl(workspacePath);
184195
BazelClient bazelClient = new BazelClientImpl(workspacePath, bazelPath, bazelStartupOptions, bazelCommandOptions, BazelDiff.isVerbose());
185-
TargetHashingClient hashingClient = new TargetHashingClientImpl(bazelClient);
196+
TargetHashingClient hashingClient = new TargetHashingClientImpl(bazelClient, new FilesClientImp());
186197
try {
187198
gitClient.ensureAllChangesAreCommitted();
188199
} catch (IOException | InterruptedException e) {

0 commit comments

Comments
 (0)