in src/java/io/bazel/rulesscala/coverage/instrumenter/JacocoInstrumenter.java [36:89]
private void processArg(Instrumenter jacoco, String[] args) throws Exception {
if (args.length < 3) {
throw new Exception(
"expected format `in_path out_path src1 src2 ... srcN` for arguments: "
+ Arrays.asList(args));
}
Path inPath = Paths.get(args[0]);
Path outPath = Paths.get(args[1]);
String[] srcs = Arrays.copyOfRange(args, 2, args.length);
// Use a directory for coverage metadata that is unique to each built jar. Avoids
// multiple threads performing read/write/delete actions on the instrumented classes directory.
Path instrumentedClassesDirectory = getMetadataDirRelativeToJar(outPath);
Files.createDirectories(instrumentedClassesDirectory);
JarCreator jarCreator = new JarCreator(outPath);
try (FileSystem inFS = FileSystems.newFileSystem(inPath, null)) {
FileVisitor fileVisitor =
createInstrumenterVisitor(jacoco, instrumentedClassesDirectory, jarCreator);
inFS.getRootDirectories()
.forEach(
root -> {
try {
Files.walkFileTree(root, fileVisitor);
} catch (final Exception e) {
throw new RuntimeException(e);
}
});
/*
* https://github.com/bazelbuild/bazel/blob/567ca633d016572f5760bfd027c10616f2b8c2e4/src/java_tools/junitrunner/java/com/google/testing/coverage/JacocoCoverageRunner.java#L411
*
* Bazel / JacocoCoverageRunner will look for any file that ends with '-paths-for-coverage.txt' within the JAR to be later used for reconstructing the path for source files.
* This is a fairly undocumented feature within bazel at this time, but in essence, it opens all the jars, searches for all files matching '-paths-for-coverage.txt'
* and then adds them to a single in memory set.
*
* https://github.com/bazelbuild/bazel/blob/567ca633d016572f5760bfd027c10616f2b8c2e4/src/java_tools/junitrunner/java/com/google/testing/coverage/JacocoLCOVFormatter.java#L70
* Which is then used in the formatter to find the corresponding source file from the set of sources we wrote in all the JARs.
*/
Path pathsForCoverage = instrumentedClassesDirectory.resolve("-paths-for-coverage.txt");
Files.write(
pathsForCoverage,
String.join("\n", srcs).getBytes(java.nio.charset.StandardCharsets.UTF_8));
jarCreator.addEntry(
instrumentedClassesDirectory.relativize(pathsForCoverage).toString(), pathsForCoverage);
jarCreator.setCompression(true);
jarCreator.execute();
} finally {
DeleteRecursively.run(instrumentedClassesDirectory);
}
}