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