| /* |
| * 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()); |
| } |
| } |