1/*******************************************************************************
2 * Copyright (c) 2009, 2017 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 *******************************************************************************/
13package org.jacoco.cli.internal.commands;
14
15import java.io.File;
16import java.io.FileInputStream;
17import java.io.FileOutputStream;
18import java.io.IOException;
19import java.io.InputStream;
20import java.io.OutputStream;
21import java.io.PrintWriter;
22import java.util.ArrayList;
23import java.util.List;
24
25import org.jacoco.cli.internal.Command;
26import org.jacoco.core.instr.Instrumenter;
27import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
28import org.kohsuke.args4j.Argument;
29import org.kohsuke.args4j.Option;
30
31/**
32 * The <code>instrument</code> command.
33 */
34public 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		instrumenter = new Instrumenter(
53				new OfflineInstrumentationAccessGenerator());
54		int total = 0;
55		for (final File s : source) {
56			total += instrumentRecursive(s, dest);
57		}
58		out.printf("[INFO] %s classes instrumented to %s.%n",
59				Integer.valueOf(total), dest.getAbsolutePath());
60		return 0;
61	}
62
63	private int instrumentRecursive(final File src, final File dest)
64			throws IOException {
65		int total = 0;
66		if (src.isDirectory()) {
67			for (final File child : src.listFiles()) {
68				total += instrumentRecursive(child,
69						new File(dest, child.getName()));
70			}
71		} else {
72			total += instrument(src, dest);
73		}
74		return total;
75	}
76
77	private int instrument(final File src, final File dest) throws IOException {
78		dest.getParentFile().mkdirs();
79		final InputStream input = new FileInputStream(src);
80		try {
81			final OutputStream output = new FileOutputStream(dest);
82			try {
83				return instrumenter.instrumentAll(input, output,
84						src.getAbsolutePath());
85			} finally {
86				output.close();
87			}
88		} catch (final IOException e) {
89			dest.delete();
90			throw e;
91		} finally {
92			input.close();
93		}
94	}
95
96}
97