forked from Tinder/bazel-diff
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.java
More file actions
209 lines (183 loc) · 9.23 KB
/
Copy pathmain.java
File metadata and controls
209 lines (183 loc) · 9.23 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
package com.bazel_diff;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import picocli.CommandLine.ParentCommand;
import com.google.gson.*;
import java.io.*;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import static picocli.CommandLine.*;
@Command(
name = "modified-filepaths",
mixinStandardHelpOptions = true,
description = "Writes to the file the modified filepaths between two revisions.",
versionProvider = VersionProvider.class
)
class FetchModifiedFilepaths implements Callable<Integer> {
@Parameters(index = "0", description = "The starting Git revision, e.g. \"HEAD^\"")
String startingGitRevision;
@Parameters(index = "1", description = "The final Git revision, e.g. \"HEAD\"")
String endingGitRevision;
@Parameters(index = "2", description = "Path that the list of modified files will be written to")
File outputPath;
@ParentCommand
private BazelDiff parent;
@Override
public Integer call() {
GitClient gitClient = new GitClientImpl(parent.workspacePath);
try {
gitClient.ensureAllChangesAreCommitted();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
return ExitCode.SOFTWARE;
} catch (GitClientException e) {
System.out.println(String.format("There are active changes in '%s', please commit these changes before running modified-filepaths", parent.workspacePath));
return ExitCode.USAGE;
}
try {
Set<String> modifiedFilepaths = gitClient
.getModifiedFilepaths(startingGitRevision, endingGitRevision)
.stream()
.map(Path::toString)
.collect(Collectors.toSet());
FileWriter myWriter = new FileWriter(outputPath);
myWriter.write(String.join(System.lineSeparator(), modifiedFilepaths));
myWriter.close();
return ExitCode.OK;
} catch (IOException | InterruptedException e) {
e.printStackTrace();
return ExitCode.SOFTWARE;
}
}
}
@Command(
name = "generate-hashes",
mixinStandardHelpOptions = true,
description = "Writes to a file the SHA256 hashes for each Bazel Target in the provided workspace.",
versionProvider = VersionProvider.class
)
class GenerateHashes implements Callable<Integer> {
@ParentCommand
private BazelDiff parent;
@Option(names = {"-m", "--modifiedFilepaths"}, description = "The path to a file containing the list of modified filepaths in the workspace, you can use the 'modified-filepaths' command to get this list")
File modifiedFilepaths;
@Parameters(index = "0", description = "The filepath to write the resulting JSON of dictionary target => SHA-256 values")
File outputPath;
@Override
public Integer call() {
GitClient gitClient = new GitClientImpl(parent.workspacePath);
BazelClient bazelClient = new BazelClientImpl(parent.workspacePath, parent.bazelPath, parent.bazelStartupOptions, parent.bazelCommandOptions);
TargetHashingClient hashingClient = new TargetHashingClientImpl(bazelClient);
try {
gitClient.ensureAllChangesAreCommitted();
Set<Path> modifiedFilepathsSet = new HashSet<>();
if (modifiedFilepaths != null) {
FileReader fileReader = new FileReader(modifiedFilepaths);
BufferedReader bufferedReader = new BufferedReader(fileReader);
modifiedFilepathsSet = bufferedReader
.lines()
.map( line -> new File(line).toPath())
.collect(Collectors.toSet());
}
Map<String, String> hashes = hashingClient.hashAllBazelTargets(modifiedFilepathsSet);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
FileWriter myWriter = new FileWriter(outputPath);
myWriter.write(gson.toJson(hashes));
myWriter.close();
return ExitCode.OK;
} catch (GitClientException e) {
System.out.println(String.format("There are active changes in '%s', please commit these changes before running generate-hashes", parent.workspacePath));
return ExitCode.USAGE;
} catch (IOException | InterruptedException | NoSuchAlgorithmException e) {
e.printStackTrace();
return ExitCode.SOFTWARE;
}
}
}
@Command(
name = "bazel-diff",
description = "Writes to a file the impacted targets between two Bazel graph JSON files",
subcommands = { GenerateHashes.class, FetchModifiedFilepaths.class },
mixinStandardHelpOptions = true,
versionProvider = VersionProvider.class
)
class BazelDiff implements Callable<Integer> {
@Option(names = {"-w", "--workspacePath"}, description = "Path to Bazel workspace directory.", scope = ScopeType.INHERIT, required = true)
Path workspacePath;
@Option(names = {"-b", "--bazelPath"}, description = "Path to Bazel binary", scope = ScopeType.INHERIT, required = true)
Path bazelPath;
@Option(names = {"-sh", "--startingHashes"}, scope = ScopeType.LOCAL, description = "The path to the JSON file of target hashes for the initial revision. Run 'generate-hashes' to get this value.")
File startingHashesJSONPath;
@Option(names = {"-fh", "--finalHashes"}, scope = ScopeType.LOCAL, description = "The path to the JSON file of target hashes for the final revision. Run 'generate-hashes' to get this value.")
File finalHashesJSONPath;
@Option(names = {"-o", "--output"}, scope = ScopeType.LOCAL, description = "Filepath to write the impacted Bazel targets to, newline separated")
File outputPath;
@Option(names = {"-aq", "--avoid-query"}, scope = ScopeType.LOCAL, description = "A Bazel query string, any targets that pass this query will be removed from the returned set of targets")
String avoidQuery;
@Option(names = {"-so", "--bazelStartupOptions"}, description = "Additional space separated Bazel client startup options used when invoking Bazel", scope = ScopeType.INHERIT)
String bazelStartupOptions;
@Option(names = {"-co", "--bazelCommandOptions"}, description = "Additional space separated Bazel command options used when invoking Bazel", scope = ScopeType.INHERIT)
String bazelCommandOptions;
@Override
public Integer call() throws IOException {
if (startingHashesJSONPath == null || !startingHashesJSONPath.canRead()) {
System.out.println("startingHashesJSONPath does not exist! Exiting");
return ExitCode.USAGE;
}
if (finalHashesJSONPath == null || !finalHashesJSONPath.canRead()) {
System.out.println("finalHashesJSONPath does not exist! Exiting");
return ExitCode.USAGE;
}
GitClient gitClient = new GitClientImpl(workspacePath);
BazelClient bazelClient = new BazelClientImpl(workspacePath, bazelPath, bazelStartupOptions, bazelCommandOptions);
TargetHashingClient hashingClient = new TargetHashingClientImpl(bazelClient);
try {
gitClient.ensureAllChangesAreCommitted();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
return ExitCode.SOFTWARE;
} catch (GitClientException e) {
System.out.println(String.format("There are active changes in '%s', please commit these changes before running bazel-diffs", workspacePath));
return ExitCode.USAGE;
}
Gson gson = new Gson();
FileReader startingFileReader;
FileReader finalFileReader;
try {
startingFileReader = new FileReader(startingHashesJSONPath);
} catch (FileNotFoundException e) {
System.out.println("Starting Hashes JSON filepath does not exist! Exiting");
return ExitCode.USAGE;
}
try {
finalFileReader = new FileReader(finalHashesJSONPath);
} catch (FileNotFoundException e) {
System.out.println("Final Hashes JSON filepath does not exist! Exiting");
return ExitCode.USAGE;
}
Map<String, String > gsonHash = new HashMap<>();
Map<String, String> startingHashes = gson.fromJson(startingFileReader, gsonHash.getClass());
Map<String, String> finalHashes = gson.fromJson(finalFileReader, gsonHash.getClass());
Set<String> impactedTargets = hashingClient.getImpactedTargets(startingHashes, finalHashes, avoidQuery);
try {
FileWriter myWriter = new FileWriter(outputPath);
myWriter.write(impactedTargets.stream().collect(Collectors.joining(System.lineSeparator())));
myWriter.close();
} catch (IOException e) {
System.out.println("Unable to write to output filepath! Exiting!");
return ExitCode.SOFTWARE;
}
return ExitCode.OK;
}
public static void main(String[] args) {
int exitCode = new CommandLine(new BazelDiff()).execute(args);
System.exit(exitCode);
}
}