1919import java .io .IOException ;
2020import java .io .InputStream ;
2121import java .io .OutputStream ;
22+ import java .io .PrintWriter ;
2223import java .nio .file .FileVisitResult ;
2324import java .nio .file .Files ;
2425import java .nio .file .Path ;
3031import org .jacoco .core .instr .Instrumenter ;
3132import org .jacoco .core .runtime .OfflineInstrumentationAccessGenerator ;
3233
34+ import com .google .common .base .Throwables ;
3335import com .google .common .io .MoreFiles ;
3436import com .google .common .io .RecursiveDeleteOption ;
3537import 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