1d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann/*******************************************************************************
2d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors
3d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann * All rights reserved. This program and the accompanying materials
4d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann * are made available under the terms of the Eclipse Public License v1.0
5d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann * which accompanies this distribution, and is available at
6d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann * http://www.eclipse.org/legal/epl-v10.html
7d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann *
8d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann * Contributors:
9d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann *    John Keeping - initial implementation
10d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann *    Marc R. Hoffmann - rework
11d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann *
12d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann *******************************************************************************/
13d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannpackage org.jacoco.cli.internal.commands;
14d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
15d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.io.File;
16d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.io.FileInputStream;
17d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.io.FileOutputStream;
18d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.io.IOException;
19d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.io.InputStream;
20d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.io.OutputStream;
21d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.io.PrintWriter;
22d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.util.ArrayList;
23d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport java.util.List;
24d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
25d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport org.jacoco.cli.internal.Command;
26d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport org.jacoco.core.instr.Instrumenter;
27d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
28d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport org.kohsuke.args4j.Argument;
29d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannimport org.kohsuke.args4j.Option;
30d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
31d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann/**
32d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann * The <code>instrument</code> command.
33d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann */
34d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmannpublic class Instrument extends Command {
35d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
365653302c6febde3d8f507bcf8b1778fe1b6bbebcMarc R. Hoffmann	@Option(name = "-dest", usage = "path to write instrumented Java classes to", metaVar = "<dir>", required = true)
375653302c6febde3d8f507bcf8b1778fe1b6bbebcMarc R. Hoffmann	File dest;
38d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
39d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	@Argument(usage = "list of folder or files to instrument recusively", metaVar = "<sourcefiles>")
40d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	List<File> source = new ArrayList<File>();
41d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
42d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	private Instrumenter instrumenter;
43d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
44d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	@Override
45d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	public String description() {
46d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		return "Off-line instrumentation of Java class files and JAR files.";
47d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	}
48d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
49d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	@Override
50d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	public int execute(final PrintWriter out, final PrintWriter err)
51d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			throws IOException {
52d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		instrumenter = new Instrumenter(
53d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann				new OfflineInstrumentationAccessGenerator());
54d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		int total = 0;
55d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		for (final File s : source) {
565653302c6febde3d8f507bcf8b1778fe1b6bbebcMarc R. Hoffmann			total += instrumentRecursive(s, dest);
57d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		}
58d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		out.printf("[INFO] %s classes instrumented to %s.%n",
595653302c6febde3d8f507bcf8b1778fe1b6bbebcMarc R. Hoffmann				Integer.valueOf(total), dest.getAbsolutePath());
60d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		return 0;
61d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	}
62d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
63d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	private int instrumentRecursive(final File src, final File dest)
64d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			throws IOException {
65d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		int total = 0;
66d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		if (src.isDirectory()) {
67d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			for (final File child : src.listFiles()) {
68d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann				total += instrumentRecursive(child,
69d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann						new File(dest, child.getName()));
70d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			}
71d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		} else {
72d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			total += instrument(src, dest);
73d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		}
74d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		return total;
75d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	}
76d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
77d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	private int instrument(final File src, final File dest) throws IOException {
78d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		dest.getParentFile().mkdirs();
79d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		final InputStream input = new FileInputStream(src);
80d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		try {
81d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			final OutputStream output = new FileOutputStream(dest);
82d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			try {
83d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann				return instrumenter.instrumentAll(input, output,
84d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann						src.getAbsolutePath());
85d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			} finally {
86d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann				output.close();
87d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			}
88d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		} catch (final IOException e) {
89d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			dest.delete();
90d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			throw e;
91d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		} finally {
92d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann			input.close();
93d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann		}
94d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann	}
95d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann
96d850ed49b22d2a0c84a3b317acec8df7e7159016Marc R. Hoffmann}
97