Home | History | Annotate | Download | only in commands
      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  *    John Keeping - initial implementation
     10  *    Marc R. Hoffmann - rework
     11  *
     12  *******************************************************************************/
     13 package org.jacoco.cli.internal.commands;
     14 
     15 import java.io.File;
     16 import java.io.FileInputStream;
     17 import java.io.FileOutputStream;
     18 import java.io.IOException;
     19 import java.io.InputStream;
     20 import java.io.OutputStream;
     21 import java.io.PrintWriter;
     22 import java.util.ArrayList;
     23 import java.util.List;
     24 
     25 import org.jacoco.cli.internal.Command;
     26 import org.jacoco.core.instr.Instrumenter;
     27 import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
     28 import org.kohsuke.args4j.Argument;
     29 import org.kohsuke.args4j.Option;
     30 
     31 /**
     32  * The <code>instrument</code> command.
     33  */
     34 public class Instrument extends Command {
     35 
     36 	@Option(name = "--dest", usage = "path to write instrumented Java classes to", metaVar = "<dir>", required = true)
     37 	File dest;
     38 
     39 	@Argument(usage = "list of folder or files to instrument recusively", metaVar = "<sourcefiles>")
     40 	List<File> source = new ArrayList<File>();
     41 
     42 	private Instrumenter instrumenter;
     43 
     44 	@Override
     45 	public String description() {
     46 		return "Off-line instrumentation of Java class files and JAR files.";
     47 	}
     48 
     49 	@Override
     50 	public int execute(final PrintWriter out, final PrintWriter err)
     51 			throws IOException {
     52 		final File absoluteDest = dest.getAbsoluteFile();
     53 		instrumenter = new Instrumenter(
     54 				new OfflineInstrumentationAccessGenerator());
     55 		int total = 0;
     56 		for (final File s : source) {
     57 			if (s.isFile()) {
     58 				total += instrument(s, new File(absoluteDest, s.getName()));
     59 			} else {
     60 				total += instrumentRecursive(s, absoluteDest);
     61 			}
     62 		}
     63 		out.printf("[INFO] %s classes instrumented to %s.%n",
     64 				Integer.valueOf(total), absoluteDest);
     65 		return 0;
     66 	}
     67 
     68 	private int instrumentRecursive(final File src, final File dest)
     69 			throws IOException {
     70 		int total = 0;
     71 		if (src.isDirectory()) {
     72 			for (final File child : src.listFiles()) {
     73 				total += instrumentRecursive(child,
     74 						new File(dest, child.getName()));
     75 			}
     76 		} else {
     77 			total += instrument(src, dest);
     78 		}
     79 		return total;
     80 	}
     81 
     82 	private int instrument(final File src, final File dest) throws IOException {
     83 		dest.getParentFile().mkdirs();
     84 		final InputStream input = new FileInputStream(src);
     85 		try {
     86 			final OutputStream output = new FileOutputStream(dest);
     87 			try {
     88 				return instrumenter.instrumentAll(input, output,
     89 						src.getAbsolutePath());
     90 			} finally {
     91 				output.close();
     92 			}
     93 		} catch (final IOException e) {
     94 			dest.delete();
     95 			throw e;
     96 		} finally {
     97 			input.close();
     98 		}
     99 	}
    100 
    101 }
    102