forked from Tinder/bazel-diff
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBazelClient.java
More file actions
140 lines (123 loc) · 5.73 KB
/
Copy pathBazelClient.java
File metadata and controls
140 lines (123 loc) · 5.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.bazel_diff;
import com.google.devtools.build.lib.query2.proto.proto2api.Build;
import com.google.common.collect.Iterables;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.Arrays;
interface BazelClient {
List<BazelTarget> queryAllTargets() throws IOException;
Set<Path> queryAllSourceFiles() throws IOException;
Set<String> queryForImpactedTargets(Set<String> impactedTargets, String avoidQuery) throws IOException;
Set<BazelSourceFileTarget> convertFilepathsToSourceTargets(Set<Path> filepaths) throws IOException, NoSuchAlgorithmException;
}
class BazelClientImpl implements BazelClient {
private Path workingDirectory;
private Path bazelPath;
private List<String> startupOptions;
private List<String> commandOptions;
BazelClientImpl(Path workingDirectory, Path bazelPath, String startupOptions, String commandOptions) {
this.workingDirectory = workingDirectory.normalize();
this.bazelPath = bazelPath;
this.startupOptions = startupOptions != null ? Arrays.asList(startupOptions.split(" ")): new ArrayList<String>();
this.commandOptions = commandOptions != null ? Arrays.asList(commandOptions.split(" ")): new ArrayList<String>();
}
@Override
public List<BazelTarget> queryAllTargets() throws IOException {
List<Build.Target> targets = performBazelQuery("'//external:all-targets' + '//...:all-targets'");
return targets.stream().map( target -> new BazelTargetImpl(target)).collect(Collectors.toList());
}
@Override
public Set<Path> queryAllSourceFiles() throws IOException {
List<Build.Target> sources = performBazelQuery("kind('source file', deps(//...))");
return sources.stream()
.map(source -> source.getSourceFile().getName())
.filter(name -> !name.startsWith("@"))
.map(bazelName -> bazelName.replaceFirst("//", "").replace(":", "/"))
.map(Paths::get)
.collect(Collectors.toSet());
}
@Override
public Set<String> queryForImpactedTargets(Set<String> impactedTargets, String avoidQuery) throws IOException {
Set<String> impactedTestTargets = new HashSet<>();
String targetQuery = impactedTargets.stream().collect(Collectors.joining(" + "));
String query = String.format("rdeps(//..., %s)", targetQuery);
if (avoidQuery != null) {
query = String.format("(%s) except %s", query, avoidQuery);
}
List<Build.Target> targets = performBazelQuery(query);
for (Build.Target target : targets) {
if (target.hasRule()) {
impactedTestTargets.add(target.getRule().getName());
}
}
return impactedTestTargets;
}
@Override
public Set<BazelSourceFileTarget> convertFilepathsToSourceTargets(Set<Path> filepaths) throws IOException, NoSuchAlgorithmException {
Set<BazelSourceFileTarget> sourceTargets = new HashSet<>();
// filter out only valid bazel source files
Set<Path> allSources = this.queryAllSourceFiles();
Set<Path> validFilePaths = new HashSet<>(allSources);
validFilePaths.retainAll(filepaths);
for (List<Path> partition : Iterables.partition(validFilePaths, 100)) {
String targetQuery = partition
.stream()
.map(path -> path.toString())
.collect(Collectors.joining(" + "));
List<Build.Target> targets = performBazelQuery(targetQuery);
for (Build.Target target : targets) {
Build.SourceFile sourceFile = target.getSourceFile();
if (sourceFile != null) {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(sourceFile.getNameBytes().toByteArray());
for (String subinclude : sourceFile.getSubincludeList()) {
digest.update(subinclude.getBytes());
}
BazelSourceFileTargetImpl sourceFileTarget = new BazelSourceFileTargetImpl(
sourceFile.getName(),
digest
);
sourceTargets.add(sourceFileTarget);
}
}
}
return sourceTargets;
}
private List<Build.Target> performBazelQuery(String query) throws IOException {
Path tempFile = Files.createTempFile(null, ".txt");
Files.write(tempFile, query.getBytes(StandardCharsets.UTF_8));
List<String> cmd = new ArrayList<String>();
cmd.add((bazelPath.toString()));
cmd.addAll(this.startupOptions);
cmd.add("query");
cmd.add("--output");
cmd.add("streamed_proto");
cmd.add("--order_output=no");
cmd.add("--show_progress=false");
cmd.add("--show_loading_progress=false");
cmd.addAll(this.commandOptions);
cmd.add("--query_file");
cmd.add(tempFile.toString());
ProcessBuilder pb = new ProcessBuilder(cmd).directory(workingDirectory.toFile());
Process process = pb.start();
ArrayList<Build.Target> targets = new ArrayList<>();
while (true) {
Build.Target target = Build.Target.parseDelimitedFrom(process.getInputStream());
if (target == null) break; // EOF
targets.add(target);
}
Files.delete(tempFile);
return targets;
}
}