1 /******************************************************************************* 2 * Copyright (c) 2009, 2015 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Evgeny Mandrikov - initial API and implementation 10 * 11 *******************************************************************************/ 12 package org.jacoco.maven; 13 14 import java.io.File; 15 import java.io.FileInputStream; 16 import java.io.FileOutputStream; 17 import java.io.IOException; 18 import java.io.InputStream; 19 import java.io.OutputStream; 20 import java.util.List; 21 22 import org.apache.maven.plugin.MojoExecutionException; 23 import org.apache.maven.plugin.MojoFailureException; 24 import org.codehaus.plexus.util.FileUtils; 25 import org.codehaus.plexus.util.IOUtil; 26 import org.jacoco.core.instr.Instrumenter; 27 import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator; 28 29 /** 30 * Performs offline instrumentation. Note that after execution of test you must 31 * restore original classes with help of "restore-instrumented-classes" goal. 32 * <p> 33 * <strong>Warning:</strong> The preferred way for code coverage analysis with 34 * JaCoCo is on-the-fly instrumentation. Offline instrumentation has several 35 * drawbacks and should only be used if a specific scenario explicitly requires 36 * this mode. Please consult <a href="offline.html">documentation</a> about 37 * offline instrumentation before using this mode. 38 * </p> 39 * 40 * @phase process-classes 41 * @goal instrument 42 * @requiresProject true 43 * @threadSafe 44 * @since 0.6.2 45 */ 46 public class InstrumentMojo extends AbstractJacocoMojo { 47 48 @Override 49 public void executeMojo() throws MojoExecutionException, 50 MojoFailureException { 51 final File originalClassesDir = new File(getProject().getBuild() 52 .getDirectory(), "generated-classes/jacoco"); 53 originalClassesDir.mkdirs(); 54 final File classesDir = new File( 55 getProject().getBuild().getOutputDirectory()); 56 if (!classesDir.exists()) { 57 getLog().info( 58 "Skipping JaCoCo execution due to missing classes directory:" + 59 classesDir); 60 return; 61 } 62 63 final List<String> fileNames; 64 try { 65 fileNames = new FileFilter(this.getIncludes(), this.getExcludes()) 66 .getFileNames(classesDir); 67 } catch (final IOException e1) { 68 throw new MojoExecutionException( 69 "Unable to get list of files to instrument.", e1); 70 } 71 72 final Instrumenter instrumenter = new Instrumenter( 73 new OfflineInstrumentationAccessGenerator()); 74 for (final String fileName : fileNames) { 75 if (fileName.endsWith(".class")) { 76 final File source = new File(classesDir, fileName); 77 final File backup = new File(originalClassesDir, fileName); 78 InputStream input = null; 79 OutputStream output = null; 80 try { 81 FileUtils.copyFile(source, backup); 82 input = new FileInputStream(backup); 83 output = new FileOutputStream(source); 84 instrumenter.instrument(input, output, source.getPath()); 85 } catch (final IOException e2) { 86 throw new MojoExecutionException( 87 "Unable to instrument file.", e2); 88 } finally { 89 IOUtil.close(input); 90 IOUtil.close(output); 91 } 92 } 93 } 94 } 95 96 } 97