Home | History | Annotate | Download | only in maven
      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