19
19
import java .io .IOException ;
20
20
import java .io .InputStream ;
21
21
import java .io .OutputStream ;
22
+ import java .io .PrintWriter ;
22
23
import java .nio .file .FileVisitResult ;
23
24
import java .nio .file .Files ;
24
25
import java .nio .file .Path ;
30
31
import org .jacoco .core .instr .Instrumenter ;
31
32
import org .jacoco .core .runtime .OfflineInstrumentationAccessGenerator ;
32
33
34
+ import com .google .common .base .Throwables ;
33
35
import com .google .common .io .MoreFiles ;
34
36
import com .google .common .io .RecursiveDeleteOption ;
35
37
import com .google .devtools .build .buildjar .InvalidCommandLineException ;
@@ -73,7 +75,7 @@ public boolean isNewCoverageImplementation() {
73
75
* Instruments classes using Jacoco and keeps copies of uninstrumented class files in
74
76
* jacocoMetadataDir, to be zipped up in the output file jacocoMetadataOutput.
75
77
*/
76
- public void processRequest (JavaLibraryBuildRequest build , JarCreator jar ) throws IOException {
78
+ public void processRequest (JavaLibraryBuildRequest build , JarCreator jar , PrintWriter errWriter ) throws IOException {
77
79
// Use a directory for coverage metadata that is unique to each built jar. Avoids
78
80
// multiple threads performing read/write/delete actions on the instrumented classes directory.
79
81
instrumentedClassesDirectory = getMetadataDirRelativeToJar (build .getOutputJar ());
@@ -84,7 +86,7 @@ public void processRequest(JavaLibraryBuildRequest build, JarCreator jar) throws
84
86
jar .setNormalize (true );
85
87
jar .setCompression (build .compressJar ());
86
88
Instrumenter instr = new Instrumenter (new OfflineInstrumentationAccessGenerator ());
87
- instrumentRecursively (instr , build .getClassDir ());
89
+ instrumentRecursively (instr , build .getClassDir (), errWriter );
88
90
jar .addDirectory (instrumentedClassesDirectory );
89
91
if (isNewCoverageImplementation ) {
90
92
jar .addEntry (coverageInformation , coverageInformation );
@@ -109,7 +111,7 @@ private static Path getMetadataDirRelativeToJar(Path outputJar) {
109
111
/**
110
112
* Runs Jacoco instrumentation processor over all .class files recursively, starting with root.
111
113
*/
112
- private void instrumentRecursively (Instrumenter instr , Path root ) throws IOException {
114
+ private void instrumentRecursively (Instrumenter instr , Path root , PrintWriter errWriter ) throws IOException {
113
115
Files .walkFileTree (
114
116
root ,
115
117
new SimpleFileVisitor <Path >() {
@@ -123,24 +125,34 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
123
125
// It's not clear whether there is any advantage in not instrumenting *Test classes,
124
126
// apart from lowering the covered percentage in the aggregate statistics.
125
127
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 ();
144
156
}
145
157
return FileVisitResult .CONTINUE ;
146
158
}
0 commit comments