Package org.sonar.plugins.cxx.utils

Source Code of org.sonar.plugins.cxx.utils.CxxReportSensor

/*
* Sonar C++ Plugin (Community)
* Copyright (C) 2010 Neticoa SAS France
* dev@sonar.codehaus.org
*
* 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  02
*/
package org.sonar.plugins.cxx.utils;

import org.apache.tools.ant.DirectoryScanner;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.config.Settings;
import org.sonar.api.issue.Issuable;
import org.sonar.api.issue.Issue;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.Project;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.SonarException;
import org.sonar.plugins.cxx.CxxLanguage;
import org.sonar.api.scan.filesystem.ModuleFileSystem;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.sonar.api.resources.Resource;

/**
* {@inheritDoc}
*/
public abstract class CxxReportSensor implements Sensor {
  private ResourcePerspectives perspectives;
  protected Settings conf;
  private HashSet<String> notFoundFiles = new HashSet<String>();
  private HashSet<String> uniqueIssues = new HashSet<String>();
  protected ModuleFileSystem fs;

  private final Metric metric;
  private int violationsCount;

  /**
   * {@inheritDoc}
   */
  public CxxReportSensor(Settings conf, ModuleFileSystem fs) {
    this(null, conf, fs);
  }

  /**
   * {@inheritDoc}
   */
  public CxxReportSensor(ResourcePerspectives perspectives, Settings conf, ModuleFileSystem fs) {
    this.perspectives = perspectives;
    this.conf = conf;
    this.fs = fs;
    this.metric = null;
  }

  /**
   * {@inheritDoc}
   */
  public CxxReportSensor(ResourcePerspectives perspectives, Settings conf, ModuleFileSystem fs, Metric metric) {
    this.perspectives = perspectives;
    this.conf = conf;
    this.fs = fs;
    this.metric = metric;
  }

  /**
   * {@inheritDoc}
   */
  public boolean shouldExecuteOnProject(Project project) {
    return !project.getFileSystem().mainFiles(CxxLanguage.KEY).isEmpty();
  }

  /**
   * {@inheritDoc}
   */
  public void analyse(Project project, SensorContext context) {
    try {
      List<File> reports = getReports(conf, fs.baseDir().getPath(),
          reportPathKey(), defaultReportPath());

      violationsCount = 0;

      for (File report : reports) {
        CxxUtils.LOG.info("Processing report '{}'", report);
        try{
          int prevViolationsCount = violationsCount;
          processReport(project, context, report);
          CxxUtils.LOG.info("{} processed = {}", metric == null ? "Issues" : metric.getName(),
                            violationsCount - prevViolationsCount);
        }
        catch(EmptyReportException e){
          CxxUtils.LOG.warn("The report '{}' seems to be empty, ignoring.", report);
        }
      }

      if (reports.isEmpty()) {
        handleNoReportsCase(context);
      }

      if (metric != null) {
        Measure measure = new Measure(metric);
        measure.setIntValue(violationsCount);
        context.saveMeasure(measure);
      }
    } catch (Exception e) {
      String msg = new StringBuilder()
          .append("Cannot feed the data into sonar, details: '")
          .append(e)
          .append("'")
          .toString();
      throw new SonarException(msg, e);
    }
  }

  @Override
  public String toString() {
    return getClass().getSimpleName();
  }

  public String getStringProperty(String name, String def) {
      String value = conf.getString(name);
      if (value == null)
          value = def;
      return value;
  }

  protected List<File> getReports(Settings conf,
      String baseDirPath,
      String reportPathPropertyKey,
      String defaultReportPath) {
    String reportPath = conf.getString(reportPathPropertyKey);
    if (reportPath == null) {
      reportPath = defaultReportPath;
    }

    CxxUtils.LOG.debug("Using pattern '{}' to find reports", reportPath);

    DirectoryScanner scanner = new DirectoryScanner();
    String[] includes = new String[1];
    includes[0] = reportPath;
    scanner.setIncludes(includes);
    scanner.setBasedir(new File(baseDirPath));
    scanner.scan();
    String[] relPaths = scanner.getIncludedFiles();

    List<File> reports = new ArrayList<File>();
    for (String relPath : relPaths) {
      reports.add(new File(baseDirPath, relPath));
    }

    return reports;
  }

  /**
   * Saves code violation only if unique.
   * Compares file, line, ruleId and msg.
   */
  public boolean saveUniqueViolation(Project project, SensorContext context, String ruleRepoKey,
                                        String file, String line, String ruleId, String msg) {

    if (uniqueIssues.add(file + line + ruleId + msg)) { // StringBuilder is slower
      return saveViolation(project, context, ruleRepoKey, file, line, ruleId, msg);
    }
    return false;
  }

  /**
   * Saves a code violation which is detected in the given file/line and has
   * given ruleId and message. Saves it to the given project and context.
   * Project or file-level violations can be saved by passing null for the
   * according parameters ('file' = null for project level, 'line' = null for
   * file-level)
   */
  public boolean saveViolation(Project project, SensorContext context, String ruleRepoKey,
    String filename, String line, String ruleId, String msg) {
    boolean add = false;
    Resource resource = null;
    int lineNr = 0;

    if ((filename != null) && (filename.length() > 0)) { // file level
      String normalPath = CxxUtils.normalizePath(filename);
      if (normalPath != null) {
        if (!notFoundFiles.contains(normalPath)) {
          org.sonar.api.resources.File file
            = org.sonar.api.resources.File.fromIOFile(new File(normalPath), project);
          if (context.getResource(file) != null) {
            lineNr = getLineAsInt(line);
            resource = file;
            add = true;
          } else {
            CxxUtils.LOG.warn("Cannot find the file '{}', skipping violations", normalPath);
            notFoundFiles.add(normalPath);
          }
        }
      }
    } else { // project level
      resource = project;
      add = true;
    }

    if (add) {
      add = contextSaveViolation(resource, lineNr, RuleKey.of(ruleRepoKey, ruleId), msg);
    }

    return add;
  }

  private boolean contextSaveViolation(Resource resource, int lineNr, RuleKey rule, String msg) {
    Issuable issuable = perspectives.as(Issuable.class, resource);
    boolean result = false;
    if (issuable != null) {
      Issuable.IssueBuilder issueBuilder = issuable.newIssueBuilder()
          .ruleKey(rule)
          .message(msg);
      if (lineNr > 0) {
        issueBuilder = issueBuilder.line(lineNr);
      }
      Issue issue = issueBuilder.build();
      result = issuable.addIssue(issue);
      if (result)
        violationsCount++;
    }
    return result;
  }

  private int getLineAsInt(String line) {
    int lineNr = 0;
    if (line != null) {
      try {
        lineNr = Integer.parseInt(line);
        lineNr = lineNr == 0 ? 1 : lineNr;
      } catch (java.lang.NumberFormatException nfe) {
        CxxUtils.LOG.warn("Skipping invalid line number: {}", line);
        lineNr = -1;
      }
    }
    return lineNr;
  }

  protected void processReport(Project project, SensorContext context, File report)
      throws Exception
  {
  }

  protected void handleNoReportsCase(SensorContext context) {
  }

  protected String reportPathKey() {
    return "";
  };

  protected String defaultReportPath() {
    return "";
  };
}
TOP

Related Classes of org.sonar.plugins.cxx.utils.CxxReportSensor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.