Skip to content

Commit 159f7fd

Browse files
authored
Merge pull request #31 from salesforce/rsalvador/jacoco-skip-if-fail
Apply: Skip files that fail JaCoCo instrumentation PR
2 parents d6b2d21 + fd6ee8b commit 159f7fd

File tree

2 files changed

+44
-24
lines changed

2 files changed

+44
-24
lines changed

compiler/src/main/buildjar/com/google/devtools/build/buildjar/SimpleJavaLibraryBuilder.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.io.Closeable;
1919
import java.io.IOException;
2020
import java.io.OutputStream;
21+
import java.io.PrintWriter;
22+
import java.io.StringWriter;
2123
import java.nio.file.Files;
2224
import java.nio.file.Path;
2325
import java.util.ArrayList;
@@ -125,7 +127,13 @@ public BlazeJavacResult run(JavaLibraryBuildRequest build) throws Exception {
125127
try {
126128
result = compileJavaLibrary(build);
127129
if (result.isOk()) {
128-
buildJar(build);
130+
StringWriter errOutput = new StringWriter();
131+
PrintWriter errWriter = new PrintWriter(errOutput);
132+
buildJar(build, errWriter);
133+
String output = errOutput.toString().trim();
134+
if (output.length() > 0) {
135+
result = BlazeJavacResult.createFullResult(result.status(), result.diagnostics(), output, result.statistics());
136+
}
129137
nativeHeaderOutput(build);
130138
}
131139
if (!build.getProcessors().isEmpty()) {
@@ -145,7 +153,7 @@ public BlazeJavacResult run(JavaLibraryBuildRequest build) throws Exception {
145153
return result;
146154
}
147155

148-
public void buildJar(JavaLibraryBuildRequest build) throws IOException {
156+
public void buildJar(JavaLibraryBuildRequest build, PrintWriter errWriter) throws IOException {
149157
Files.createDirectories(build.getOutputJar().getParent());
150158
JarCreator jar = new JarCreator(build.getOutputJar());
151159
JacocoInstrumentationProcessor processor = null;
@@ -156,7 +164,7 @@ public void buildJar(JavaLibraryBuildRequest build) throws IOException {
156164
jar.setJarOwner(build.getTargetLabel(), build.getInjectingRuleKind());
157165
processor = build.getJacocoInstrumentationProcessor();
158166
if (processor != null) {
159-
processor.processRequest(build, processor.isNewCoverageImplementation() ? jar : null);
167+
processor.processRequest(build, processor.isNewCoverageImplementation() ? jar : null, errWriter);
160168
}
161169
} finally {
162170
jar.execute();

compiler/src/main/buildjar/com/google/devtools/build/buildjar/instrumentation/JacocoInstrumentationProcessor.java

+33-21
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.io.InputStream;
2121
import java.io.OutputStream;
22+
import java.io.PrintWriter;
2223
import java.nio.file.FileVisitResult;
2324
import java.nio.file.Files;
2425
import java.nio.file.Path;
@@ -30,6 +31,7 @@
3031
import org.jacoco.core.instr.Instrumenter;
3132
import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
3233

34+
import com.google.common.base.Throwables;
3335
import com.google.common.io.MoreFiles;
3436
import com.google.common.io.RecursiveDeleteOption;
3537
import com.google.devtools.build.buildjar.InvalidCommandLineException;
@@ -73,7 +75,7 @@ public boolean isNewCoverageImplementation() {
7375
* Instruments classes using Jacoco and keeps copies of uninstrumented class files in
7476
* jacocoMetadataDir, to be zipped up in the output file jacocoMetadataOutput.
7577
*/
76-
public void processRequest(JavaLibraryBuildRequest build, JarCreator jar) throws IOException {
78+
public void processRequest(JavaLibraryBuildRequest build, JarCreator jar, PrintWriter errWriter) throws IOException {
7779
// Use a directory for coverage metadata that is unique to each built jar. Avoids
7880
// multiple threads performing read/write/delete actions on the instrumented classes directory.
7981
instrumentedClassesDirectory = getMetadataDirRelativeToJar(build.getOutputJar());
@@ -84,7 +86,7 @@ public void processRequest(JavaLibraryBuildRequest build, JarCreator jar) throws
8486
jar.setNormalize(true);
8587
jar.setCompression(build.compressJar());
8688
Instrumenter instr = new Instrumenter(new OfflineInstrumentationAccessGenerator());
87-
instrumentRecursively(instr, build.getClassDir());
89+
instrumentRecursively(instr, build.getClassDir(), errWriter);
8890
jar.addDirectory(instrumentedClassesDirectory);
8991
if (isNewCoverageImplementation) {
9092
jar.addEntry(coverageInformation, coverageInformation);
@@ -109,7 +111,7 @@ private static Path getMetadataDirRelativeToJar(Path outputJar) {
109111
/**
110112
* Runs Jacoco instrumentation processor over all .class files recursively, starting with root.
111113
*/
112-
private void instrumentRecursively(Instrumenter instr, Path root) throws IOException {
114+
private void instrumentRecursively(Instrumenter instr, Path root, PrintWriter errWriter) throws IOException {
113115
Files.walkFileTree(
114116
root,
115117
new SimpleFileVisitor<Path>() {
@@ -123,24 +125,34 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
123125
// It's not clear whether there is any advantage in not instrumenting *Test classes,
124126
// apart from lowering the covered percentage in the aggregate statistics.
125127

126-
// We first move the original .class file to our metadata directory, then instrument it
127-
// and output the instrumented version in the regular classes output directory.
128-
Path instrumentedCopy = file;
129-
Path uninstrumentedCopy;
130-
if (isNewCoverageImplementation) {
131-
Path absoluteUninstrumentedCopy = Paths.get(file + ".uninstrumented");
132-
uninstrumentedCopy =
133-
instrumentedClassesDirectory.resolve(root.relativize(absoluteUninstrumentedCopy));
134-
} else {
135-
uninstrumentedCopy = instrumentedClassesDirectory.resolve(root.relativize(file));
136-
}
137-
Files.createDirectories(uninstrumentedCopy.getParent());
138-
Files.move(file, uninstrumentedCopy);
139-
try (InputStream input =
140-
new BufferedInputStream(Files.newInputStream(uninstrumentedCopy));
141-
OutputStream output =
142-
new BufferedOutputStream(Files.newOutputStream(instrumentedCopy))) {
143-
instr.instrument(input, output, file.toString());
128+
try {
129+
// We first move the original .class file to our metadata directory, then instrument
130+
// it and output the instrumented version in the regular classes output directory.
131+
Path instrumentedCopy = file;
132+
Path uninstrumentedCopy;
133+
if (isNewCoverageImplementation) {
134+
Path absoluteUninstrumentedCopy = Paths.get(file + ".uninstrumented");
135+
uninstrumentedCopy =
136+
instrumentedClassesDirectory.resolve(
137+
root.relativize(absoluteUninstrumentedCopy));
138+
} else {
139+
uninstrumentedCopy = instrumentedClassesDirectory.resolve(root.relativize(file));
140+
}
141+
Files.createDirectories(uninstrumentedCopy.getParent());
142+
Files.move(file, uninstrumentedCopy);
143+
try (InputStream input =
144+
new BufferedInputStream(Files.newInputStream(uninstrumentedCopy));
145+
OutputStream output =
146+
new BufferedOutputStream(Files.newOutputStream(instrumentedCopy))) {
147+
instr.instrument(input, output, file.toString());
148+
} catch (Exception e) {
149+
Files.delete(instrumentedCopy);
150+
Files.copy(uninstrumentedCopy, instrumentedCopy);
151+
throw e; // Bubble up to the outer broader safety catch block for logging.
152+
}
153+
} catch (Exception e) {
154+
errWriter.printf("WARNING: %s was not instrumented: %s\n", file, Throwables.getRootCause(e).toString());
155+
e.printStackTrace();
144156
}
145157
return FileVisitResult.CONTINUE;
146158
}

0 commit comments

Comments
 (0)