blob: 604cf7e996c7d88ad9c878a530aa8f86b083636a [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.jack.tools.jacoco;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.tools.ExecFileLoader;
import org.jacoco.report.DirectorySourceFileLocator;
import org.jacoco.report.FileMultiReportOutput;
import org.jacoco.report.IReportVisitor;
import org.jacoco.report.MultiSourceFileLocator;
import org.jacoco.report.csv.CSVFormatter;
import org.jacoco.report.html.HTMLFormatter;
import org.jacoco.report.xml.XMLFormatter;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.ParserProperties;
import org.kohsuke.args4j.spi.OptionHandler;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nonnull;
/**
* Jack code coverage reporter.
*/
public class Main {
public static void main(String[] args) {
try {
Options options = parseCommandLine(Arrays.asList(args));
if (options.isHelpRequested()) {
printUsage(System.out);
} else {
createReport(options);
}
} catch (CmdLineException e) {
System.err.println(e.getMessage());
CmdLineParser parser = e.getParser();
if (parser != null) {
printUsage(System.err);
} else {
System.err.println("Try --help for help.");
}
} catch (IOException e) {
e.printStackTrace(System.err);
printErrorAndExit(ErrorCode.INERNAL_ERROR, e.getMessage());
}
}
@Nonnull
private static Options parseCommandLine(@Nonnull List<String> list) throws CmdLineException {
Options options = new Options();
CmdLineParser parser =
new CmdLineParser(options, ParserProperties.defaults().withUsageWidth(100));
parser.parseArgument(list);
parser.stopOptionParsing();
return options;
}
private static void printUsage(@Nonnull PrintStream printStream) {
CmdLineParser parser =
new CmdLineParser(new Options(), ParserProperties.defaults().withUsageWidth(100));
// Prints one line with all required options.
StringBuilder oneLineUsage = new StringBuilder("Usage:");
for (OptionHandler<?> optionHandler : parser.getOptions()) {
if (optionHandler.option.required()) {
oneLineUsage.append(' ');
oneLineUsage.append(optionHandler.option.toString());
oneLineUsage.append(' ');
oneLineUsage.append(optionHandler.option.metaVar());
if (optionHandler.option.isMultiValued()) {
oneLineUsage.append(" ...");
}
}
}
oneLineUsage.append(" [<options>]");
printStream.println(oneLineUsage.toString());
// Print all options with their usage.
printStream.println();
printStream.println("Options:");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
parser.printUsage(outputStream);
printStream.append(outputStream.toString());
}
private static void createReport(@Nonnull Options options) throws IOException {
File coverageDescriptionFile = options.getCoverageDescriptionFile();
assert coverageDescriptionFile != null;
checkFileExists(coverageDescriptionFile);
checkCanReadFromFile(coverageDescriptionFile);
File coverageExecutionDataFile = options.getCoverageExecutionFile();
assert coverageExecutionDataFile != null;
checkFileExists(coverageExecutionDataFile);
checkCanReadFromFile(coverageExecutionDataFile);
File reportOutputFile = options.getReportOutputDirectory();
checkDirectoryExists(reportOutputFile);
checkCanWriteToFile(reportOutputFile);
List<File> sourceFilesDirectories = options.getSourceFilesDirectories();
for (File sourceFilesDirectory : sourceFilesDirectories) {
checkDirectoryExists(sourceFilesDirectory);
checkCanReadFromFile(sourceFilesDirectory);
}
String reportName = options.getReportName();
ReportType reportType = options.getReportType();
String outputEncoding = options.getOutputReportEncoding();
// Load coverage execution file.
ExecFileLoader loader = new ExecFileLoader();
loader.load(coverageExecutionDataFile);
// Analyze coverage.
CoverageBuilder coverageBuilder = new CoverageBuilder();
JackCoverageAnalyzer analyzer =
new JackCoverageAnalyzer(loader.getExecutionDataStore(), coverageBuilder);
analyzer.analyze(coverageDescriptionFile);
IBundleCoverage bundleCoverage = coverageBuilder.getBundle(reportName);
// Create report.
IReportVisitor visitor = null;
switch (reportType) {
case HTML:
HTMLFormatter htmlFormatter = new HTMLFormatter();
htmlFormatter.setOutputEncoding(outputEncoding);
visitor = htmlFormatter.createVisitor(new FileMultiReportOutput(reportOutputFile));
break;
case XML:
XMLFormatter xmlFormatter = new XMLFormatter();
xmlFormatter.setOutputEncoding(outputEncoding);
File xmlReportFile = new File(reportOutputFile, "report.xml");
visitor = xmlFormatter.createVisitor(new FileOutputStream(xmlReportFile));
break;
case CSV:
CSVFormatter csvFormatter = new CSVFormatter();
csvFormatter.setOutputEncoding(outputEncoding);
File csvReportFile = new File(reportOutputFile, "report.csv");
visitor = csvFormatter.createVisitor(new FileOutputStream(csvReportFile));
break;
default:
throw new IllegalArgumentException("Unknown report type");
}
if (visitor == null) {
throw new NullPointerException("Report's visitor has not been created");
}
// Initialize the report with all of the execution and session
// information. At this point the report doesn't know about the
// structure of the report being created
visitor.visitInfo(
loader.getSessionInfoStore().getInfos(), loader.getExecutionDataStore().getContents());
// Populate the report structure with the bundle coverage information.
// Call visitGroup if you need groups in your report.
int tabWidth = options.getTabWidth();
MultiSourceFileLocator sourceFileLocator = new MultiSourceFileLocator(tabWidth);
final String sourceFilesEncoding = options.getInputSourceFilesEncoding();
for (File sourceFilesDirectory : sourceFilesDirectories) {
sourceFileLocator.add(
new DirectorySourceFileLocator(sourceFilesDirectory, sourceFilesEncoding, tabWidth));
}
visitor.visitBundle(bundleCoverage, sourceFileLocator);
// Signal end of structure information to allow report to write all
// information out
visitor.visitEnd();
System.out.println("Created report at " + reportOutputFile);
}
private static void checkFileExists(@Nonnull File file) {
if (!file.exists()) {
printErrorAndExit(
ErrorCode.USAGE_ERROR, MessageFormat.format("File {0} does not exist", file));
}
}
private static void checkCanReadFromFile(@Nonnull File file) {
if (!file.canRead()) {
printErrorAndExit(
ErrorCode.USAGE_ERROR, MessageFormat.format("Cannot read from file {0}", file));
}
}
private static void checkCanWriteToFile(@Nonnull File file) {
if (!file.canWrite()) {
printErrorAndExit(
ErrorCode.USAGE_ERROR, MessageFormat.format("Cannot write to file {0}", file));
}
}
private static void checkDirectoryExists(@Nonnull File file) {
checkFileExists(file);
if (!file.isDirectory()) {
printErrorAndExit(
ErrorCode.USAGE_ERROR, MessageFormat.format("File {0} is not a directory", file));
}
}
private static void printErrorAndExit(@Nonnull ErrorCode error, String msg) {
System.err.println(msg);
System.exit(error.getErrorCode());
}
}