1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 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.apache.maven.plugins.annotations.LifecyclePhase; 25 import org.apache.maven.plugins.annotations.Mojo; 26 import org.codehaus.plexus.util.FileUtils; 27 import org.codehaus.plexus.util.IOUtil; 28 import org.jacoco.core.instr.Instrumenter; 29 import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator; 30 31 /** 32 * Performs offline instrumentation. Note that after execution of test you must 33 * restore original classes with help of "restore-instrumented-classes" goal. 34 * <p> 35 * <strong>Warning:</strong> The preferred way for code coverage analysis with 36 * JaCoCo is on-the-fly instrumentation. Offline instrumentation has several 37 * drawbacks and should only be used if a specific scenario explicitly requires 38 * this mode. Please consult <a href="offline.html">documentation</a> about 39 * offline instrumentation before using this mode. 40 * </p> 41 * 42 * @since 0.6.2 43 */ 44 @Mojo(name = "instrument", defaultPhase = LifecyclePhase.PROCESS_CLASSES, threadSafe = true) 45 public class InstrumentMojo extends AbstractJacocoMojo { 46 47 @Override 48 public void executeMojo() throws MojoExecutionException, 49 MojoFailureException { 50 final File originalClassesDir = new File(getProject().getBuild() 51 .getDirectory(), "generated-classes/jacoco"); 52 originalClassesDir.mkdirs(); 53 final File classesDir = new File( 54 getProject().getBuild().getOutputDirectory()); 55 if (!classesDir.exists()) { 56 getLog().info( 57 "Skipping JaCoCo execution due to missing classes directory:" + 58 classesDir); 59 return; 60 } 61 62 final List<String> fileNames; 63 try { 64 fileNames = new FileFilter(this.getIncludes(), this.getExcludes()) 65 .getFileNames(classesDir); 66 } catch (final IOException e1) { 67 throw new MojoExecutionException( 68 "Unable to get list of files to instrument.", e1); 69 } 70 71 final Instrumenter instrumenter = new Instrumenter( 72 new OfflineInstrumentationAccessGenerator()); 73 for (final String fileName : fileNames) { 74 if (fileName.endsWith(".class")) { 75 final File source = new File(classesDir, fileName); 76 final File backup = new File(originalClassesDir, fileName); 77 InputStream input = null; 78 OutputStream output = null; 79 try { 80 FileUtils.copyFile(source, backup); 81 input = new FileInputStream(backup); 82 output = new FileOutputStream(source); 83 instrumenter.instrument(input, output, source.getPath()); 84 } catch (final IOException e2) { 85 throw new MojoExecutionException( 86 "Unable to instrument file.", e2); 87 } finally { 88 IOUtil.close(input); 89 IOUtil.close(output); 90 } 91 } 92 } 93 } 94 95 } 96