content: /*******************************************************************************
   * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *    Brock Janiczak - initial API and implementation
   *    
   *******************************************************************************/
  package org.jacoco.ant;
  
  import static java.lang.String.format;
  
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.Iterator;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.Task;
  import org.apache.tools.ant.types.Resource;
  import org.apache.tools.ant.types.ResourceCollection;
  import org.apache.tools.ant.types.resources.Union;
  import org.apache.tools.ant.util.FileUtils;
  import org.jacoco.core.instr.Instrumenter;
  import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
  
  /**
   * Task for offline instrumentation of class files.
   */
  public class InstrumentTask extends Task {
  
  	private File destdir;
  
  	private final Union files = new Union();
  
  	private boolean removesignatures = true;
  
  	/**
  	 * Sets the location of the instrumented classes.
  	 * 
  	 * @param destdir
  	 *            destination folder for instrumented classes
  	 */
  	public void setDestdir(final File destdir) {
  		this.destdir = destdir;
  	}
  
  	/**
  	 * Sets whether signatures should be removed from JAR files.
  	 * 
  	 * @param removesignatures
  	 *            <code>true</code> if signatures should be removed
  	 */
  	public void setRemovesignatures(final boolean removesignatures) {
  		this.removesignatures = removesignatures;
  	}
  
  	/**
  	 * This task accepts any number of class file resources.
  	 * 
  	 * @param resources
  	 *            Execution data resources
  	 */
  	public void addConfigured(final ResourceCollection resources) {
  		files.add(resources);
  	}
  
  	@Override
  	public void execute() throws BuildException {
  		if (destdir == null) {
  			throw new BuildException("Destination directory must be supplied",
  					getLocation());
  		}
  		int total = 0;
  		final Instrumenter instrumenter = new Instrumenter(
  				new OfflineInstrumentationAccessGenerator());
  		instrumenter.setRemoveSignatures(removesignatures);
  		final Iterator<?> resourceIterator = files.iterator();
  		while (resourceIterator.hasNext()) {
  			final Resource resource = (Resource) resourceIterator.next();
  			if (resource.isDirectory()) {
  				continue;
  			}
  			total += instrument(instrumenter, resource);
  		}
  		log(format("Instrumented %s classes to %s", Integer.valueOf(total),
  				destdir.getAbsolutePath()));
  	}
  
  	private int instrument(final Instrumenter instrumenter,
  			final Resource resource) {
  		final File file = new File(destdir, resource.getName());
  		file.getParentFile().mkdirs();
  		try {
  			InputStream input = null;
  			OutputStream output = null;
  			try {
  				input = resource.getInputStream();
  				output = new FileOutputStream(file);
  				return instrumenter.instrumentAll(input, output,
  						resource.getName());
  			} finally {
  				FileUtils.close(input);
  				FileUtils.close(output);
  			}
  		} catch (final Exception e) {
  			file.delete();
  			throw new BuildException(format("Error while instrumenting %s",
  					resource), e, getLocation());
  		}
  	}
  }
  