Home | History | Annotate | Download | only in ant
      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  *    Brock Janiczak - initial API and implementation
     10  *
     11  *******************************************************************************/
     12 package org.jacoco.ant;
     13 
     14 import static java.lang.String.format;
     15 
     16 import java.io.File;
     17 import java.io.FileOutputStream;
     18 import java.io.InputStream;
     19 import java.io.OutputStream;
     20 import java.util.Iterator;
     21 
     22 import org.apache.tools.ant.BuildException;
     23 import org.apache.tools.ant.Task;
     24 import org.apache.tools.ant.types.Resource;
     25 import org.apache.tools.ant.types.ResourceCollection;
     26 import org.apache.tools.ant.types.resources.Union;
     27 import org.apache.tools.ant.util.FileUtils;
     28 import org.jacoco.core.instr.Instrumenter;
     29 import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
     30 
     31 /**
     32  * Task for offline instrumentation of class files.
     33  */
     34 public class InstrumentTask extends Task {
     35 
     36 	private File destdir;
     37 
     38 	private final Union files = new Union();
     39 
     40 	private boolean removesignatures = true;
     41 
     42 	/**
     43 	 * Sets the location of the instrumented classes.
     44 	 *
     45 	 * @param destdir
     46 	 *            destination folder for instrumented classes
     47 	 */
     48 	public void setDestdir(final File destdir) {
     49 		this.destdir = destdir;
     50 	}
     51 
     52 	/**
     53 	 * Sets whether signatures should be removed from JAR files.
     54 	 *
     55 	 * @param removesignatures
     56 	 *            <code>true</code> if signatures should be removed
     57 	 */
     58 	public void setRemovesignatures(final boolean removesignatures) {
     59 		this.removesignatures = removesignatures;
     60 	}
     61 
     62 	/**
     63 	 * This task accepts any number of class file resources.
     64 	 *
     65 	 * @param resources
     66 	 *            Execution data resources
     67 	 */
     68 	public void addConfigured(final ResourceCollection resources) {
     69 		files.add(resources);
     70 	}
     71 
     72 	@Override
     73 	public void execute() throws BuildException {
     74 		if (destdir == null) {
     75 			throw new BuildException("Destination directory must be supplied",
     76 					getLocation());
     77 		}
     78 		int total = 0;
     79 		final Instrumenter instrumenter = new Instrumenter(
     80 				new OfflineInstrumentationAccessGenerator());
     81 		instrumenter.setRemoveSignatures(removesignatures);
     82 		final Iterator<?> resourceIterator = files.iterator();
     83 		while (resourceIterator.hasNext()) {
     84 			final Resource resource = (Resource) resourceIterator.next();
     85 			if (resource.isDirectory()) {
     86 				continue;
     87 			}
     88 			total += instrument(instrumenter, resource);
     89 		}
     90 		log(format("Instrumented %s classes to %s", Integer.valueOf(total),
     91 				destdir.getAbsolutePath()));
     92 	}
     93 
     94 	private int instrument(final Instrumenter instrumenter,
     95 			final Resource resource) {
     96 		final File file = new File(destdir, resource.getName());
     97 		file.getParentFile().mkdirs();
     98 		try {
     99 			InputStream input = null;
    100 			OutputStream output = null;
    101 			try {
    102 				input = resource.getInputStream();
    103 				output = new FileOutputStream(file);
    104 				return instrumenter.instrumentAll(input, output,
    105 						resource.getName());
    106 			} finally {
    107 				FileUtils.close(input);
    108 				FileUtils.close(output);
    109 			}
    110 		} catch (final Exception e) {
    111 			file.delete();
    112 			throw new BuildException(format("Error while instrumenting %s",
    113 					resource), e, getLocation());
    114 		}
    115 	}
    116 }
    117