org.sonar.scanner.scan.report.HtmlReport.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.scanner.scan.report.HtmlReport.java

Source

/*
 * SonarQube
 * Copyright (C) 2009-2017 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.scanner.scan.report;

import com.google.common.collect.Maps;
import freemarker.template.Template;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.Properties;
import org.sonar.api.Property;
import org.sonar.api.PropertyType;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.config.Settings;

@Properties({
        @Property(key = HtmlReport.HTML_REPORT_ENABLED_KEY, defaultValue = "false", name = "Enable HTML report", description = "Set this to true to generate an HTML report", type = PropertyType.BOOLEAN),
        @Property(key = HtmlReport.HTML_REPORT_LOCATION_KEY, defaultValue = HtmlReport.HTML_REPORT_LOCATION_DEFAULT, name = "HTML Report location", description = "Location of the generated report. Can be absolute or relative to working directory", project = false, global = false, type = PropertyType.STRING),
        @Property(key = HtmlReport.HTML_REPORT_NAME_KEY, defaultValue = HtmlReport.HTML_REPORT_NAME_DEFAULT, name = "HTML Report name", description = "Name of the generated report. Will be suffixed by .html or -light.html", project = false, global = false, type = PropertyType.STRING),
        @Property(key = HtmlReport.HTML_REPORT_LIGHTMODE_ONLY, defaultValue = "false", name = "Html report in light mode only", description = "Set this to true to only generate the new issues report (light report)", project = true, type = PropertyType.BOOLEAN) })
public class HtmlReport implements Reporter {
    private static final Logger LOG = LoggerFactory.getLogger(HtmlReport.class);

    public static final String HTML_REPORT_ENABLED_KEY = "sonar.issuesReport.html.enable";
    public static final String HTML_REPORT_LOCATION_KEY = "sonar.issuesReport.html.location";
    public static final String HTML_REPORT_LOCATION_DEFAULT = "issues-report";
    public static final String HTML_REPORT_NAME_KEY = "sonar.issuesReport.html.name";
    public static final String HTML_REPORT_NAME_DEFAULT = "issues-report";
    public static final String HTML_REPORT_LIGHTMODE_ONLY = "sonar.issuesReport.lightModeOnly";

    private final Settings settings;
    private final FileSystem fs;
    private final IssuesReportBuilder builder;
    private final SourceProvider sourceProvider;
    private final RuleNameProvider ruleNameProvider;

    public HtmlReport(Settings settings, FileSystem fs, IssuesReportBuilder builder, SourceProvider sourceProvider,
            RuleNameProvider ruleNameProvider) {
        this.settings = settings;
        this.fs = fs;
        this.builder = builder;
        this.sourceProvider = sourceProvider;
        this.ruleNameProvider = ruleNameProvider;
    }

    @Override
    public void execute() {
        if (settings.getBoolean(HTML_REPORT_ENABLED_KEY)) {
            LOG.warn("HTML report is deprecated. Use SonarLint CLI to have local reports of issues");
            IssuesReport report = builder.buildReport();
            print(report);
        }
    }

    public void print(IssuesReport report) {
        File reportFileDir = getReportFileDir();
        String reportName = settings.getString(HTML_REPORT_NAME_KEY);
        if (!isLightModeOnly()) {
            File reportFile = new File(reportFileDir, reportName + ".html");
            LOG.debug("Generating HTML Report to: " + reportFile.getAbsolutePath());
            writeToFile(report, reportFile, true);
            LOG.info("HTML Issues Report generated: " + reportFile.getAbsolutePath());
        }
        File lightReportFile = new File(reportFileDir, reportName + "-light.html");
        LOG.debug("Generating Light HTML Report to: " + lightReportFile.getAbsolutePath());
        writeToFile(report, lightReportFile, false);
        LOG.info("Light HTML Issues Report generated: " + lightReportFile.getAbsolutePath());
        try {
            copyDependencies(reportFileDir);
        } catch (Exception e) {
            throw new IllegalStateException("Fail to copy HTML report resources to: " + reportFileDir, e);
        }
    }

    private File getReportFileDir() {
        String reportFileDirStr = settings.getString(HTML_REPORT_LOCATION_KEY);
        File reportFileDir = new File(reportFileDirStr);
        if (!reportFileDir.isAbsolute()) {
            reportFileDir = new File(fs.workDir(), reportFileDirStr);
        }
        if (StringUtils.endsWith(reportFileDirStr, ".html")) {
            LOG.warn("{} should indicate a directory. Using parent folder.", HTML_REPORT_LOCATION_KEY);
            reportFileDir = reportFileDir.getParentFile();
        }
        try {
            FileUtils.forceMkdir(reportFileDir);
        } catch (IOException e) {
            throw new IllegalStateException("Fail to create the directory " + reportFileDirStr, e);
        }
        return reportFileDir;
    }

    public void writeToFile(IssuesReport report, File toFile, boolean complete) {
        try {
            freemarker.log.Logger.selectLoggerLibrary(freemarker.log.Logger.LIBRARY_NONE);
            freemarker.template.Configuration cfg = new freemarker.template.Configuration();
            cfg.setClassForTemplateLoading(HtmlReport.class, "");

            Map<String, Object> root = Maps.newHashMap();
            root.put("report", report);
            root.put("ruleNameProvider", ruleNameProvider);
            root.put("sourceProvider", sourceProvider);
            root.put("complete", complete);

            Template template = cfg.getTemplate("issuesreport.ftl");

            try (FileOutputStream fos = new FileOutputStream(toFile);
                    Writer writer = new OutputStreamWriter(fos, fs.encoding())) {
                template.process(root, writer);
                writer.flush();
            }
        } catch (Exception e) {
            throw new IllegalStateException("Fail to generate HTML Issues Report to: " + toFile, e);

        }
    }

    private void copyDependencies(File toDir) throws IOException {
        File target = new File(toDir, "issuesreport_files");
        FileUtils.forceMkdir(target);

        // I don't know how to extract a directory from classpath, that's why an exhaustive list of files
        // is provided here :
        copyDependency(target, "sonar.eot");
        copyDependency(target, "sonar.svg");
        copyDependency(target, "sonar.ttf");
        copyDependency(target, "sonar.woff");
        copyDependency(target, "favicon.ico");
        copyDependency(target, "PRJ.png");
        copyDependency(target, "DIR.png");
        copyDependency(target, "FIL.png");
        copyDependency(target, "jquery.min.js");
        copyDependency(target, "sep12.png");
        copyDependency(target, "sonar.css");
        copyDependency(target, "sonarqube-24x100.png");
    }

    private void copyDependency(File target, String filename) {
        try (InputStream input = getClass()
                .getResourceAsStream("/org/sonar/scanner/scan/report/issuesreport_files/" + filename);
                OutputStream output = new FileOutputStream(new File(target, filename))) {
            IOUtils.copy(input, output);
        } catch (IOException e) {
            throw new IllegalStateException("Fail to copy file " + filename + " to " + target, e);
        }
    }

    public boolean isLightModeOnly() {
        return settings.getBoolean(HTML_REPORT_LIGHTMODE_ONLY);
    }
}