Skip to content
This repository has been archived by the owner on Aug 24, 2019. It is now read-only.

replace OCLint report parser implementation #61

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* backelite-sonar-objective-c-plugin - Enables analysis of Objective-C projects into SonarQube.
* Copyright © 2012 OCTO Technology, Backelite (${email})
*
* 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, see <http://www.gnu.org/licenses/>.
*/
package org.sonar.plugins.objectivec.violations.oclint;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.annotation.Nonnull;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

final class OCLintReportParser {
private static final Logger LOGGER = LoggerFactory.getLogger(OCLintReportParser.class);

private static final String VIOLATION = "violation";
private static final String PATH = "path";
private static final String START_LINE = "startline";
private static final String RULE = "rule";
private static final String MESSAGE = "message";

@Nonnull
private static NodeList getViolationElements(@Nonnull Document document) {
return document.getElementsByTagName(VIOLATION);
}

@Nonnull
List<Violation> parse(@Nonnull final File xmlFile) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(xmlFile);

return parse(document);
} catch (final FileNotFoundException e){
LOGGER.error("OCLint report not found {}", xmlFile, e);
} catch (final ParserConfigurationException e) {
LOGGER.error("Error parsing file named {}", xmlFile, e);
} catch (final IOException | SAXException e) {
LOGGER.error("Error processing file named {}", xmlFile, e);
}

return Collections.emptyList();
}

@Nonnull
List<Violation> parse(@Nonnull final Document document) {
List<Violation> violations = new ArrayList<>();

NodeList violationElements = getViolationElements(document);
for (int i = 0; i < violationElements.getLength(); i++) {
Node node = violationElements.item(i);
if (isNotElement(node)) {
continue;
}

Element element = (Element) node;
violations.add(buildViolation(element));
}

return violations;
}

private boolean isNotElement(@Nonnull Node item) {
return item.getNodeType() != Node.ELEMENT_NODE;
}

@Nonnull
private Violation buildViolation(@Nonnull Element element) {
return Violation.builder()
.setPath(element.getAttribute(PATH))
.setStartLine(Integer.parseInt(element.getAttribute(START_LINE)))
.setRule(element.getAttribute(RULE))
.setMessage(element.getAttribute(MESSAGE))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.sonar.plugins.objectivec.core.ObjectiveC;
import org.sonar.squidbridge.rules.SqaleXmlLoader;

import javax.annotation.Nonnull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
Expand All @@ -47,7 +48,7 @@ public class OCLintRulesDefinition implements RulesDefinition {
private static final String RULES_FILE = "/org/sonar/plugins/oclint/rules.txt";

@Override
public void define(Context context) {
public void define(@Nonnull Context context) {

NewRepository repository = context
.createRepository(REPOSITORY_KEY, ObjectiveC.KEY)
Expand All @@ -73,7 +74,7 @@ private void loadRules(NewRepository repository) throws IOException {
final List<String> listLines = IOUtils.readLines(reader);

String previousLine = null;
Map<String, String> rule = new HashMap<String, String>();
Map<String, String> rule = new HashMap<>();
boolean inDescription = false;
for (String line : listLines) {

Expand All @@ -86,7 +87,7 @@ private void loadRules(NewRepository repository) throws IOException {
// Remove the rule name from the description of the previous
// rule
if (rule.get("description") != null) {
String description = rule.get("description").toString();
String description = rule.get("description");
final int index = description.lastIndexOf(previousLine);
if (index > 0) {
rule.put("description", description.substring(0, index));
Expand All @@ -107,10 +108,10 @@ private void loadRules(NewRepository repository) throws IOException {
inDescription = true;

// Create rule when last filed found
RulesDefinition.NewRule newRule = repository.createRule(rule.get("key").toString());
newRule.setName(rule.get("name").toString());
newRule.setSeverity(rule.get("severity").toString());
newRule.setHtmlDescription(rule.get("description").toString());
RulesDefinition.NewRule newRule = repository.createRule(rule.get("key"));
newRule.setName(rule.get("name"));
newRule.setSeverity(rule.get("severity"));
newRule.setHtmlDescription(rule.get("description"));

} else if (line.matches("Severity:.*")) {
inDescription = false;
Expand All @@ -119,7 +120,7 @@ private void loadRules(NewRepository repository) throws IOException {
} else {
if (inDescription) {
line = ruleDescriptionLink(line);
String description = (String)rule.get("description");
String description = rule.get("description");
rule.put("description", description + "<br>" + line);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,66 +18,77 @@
package org.sonar.plugins.objectivec.violations.oclint;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.tools.ant.DirectoryScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.config.Settings;
import org.sonar.api.resources.Project;
import org.sonar.plugins.objectivec.ObjectiveCPlugin;
import org.sonar.plugins.objectivec.core.ObjectiveC;

import javax.annotation.Nonnull;

public final class OCLintSensor implements Sensor {
public static final String REPORT_PATH_KEY = ObjectiveCPlugin.PROPERTY_PREFIX + ".oclint.report";
public static final String DEFAULT_REPORT_PATH = "sonar-reports/*oclint.xml";

private static final Logger LOGGER = LoggerFactory.getLogger(OCLintSensor.class);
private static final String NAME = "OCLint violation sensor";

private final OCLintReportParser parser = new OCLintReportParser();
private final Settings conf;
private final FileSystem fileSystem;
private final ResourcePerspectives resourcePerspectives;

public OCLintSensor(final FileSystem fileSystem, final Settings config, final ResourcePerspectives resourcePerspectives) {
public OCLintSensor(final FileSystem fileSystem, final Settings config) {
this.conf = config;
this.fileSystem = fileSystem;
this.resourcePerspectives = resourcePerspectives;
}

public boolean shouldExecuteOnProject(final Project project) {

return project.isRoot() && fileSystem.languages().contains(ObjectiveC.KEY);

@Override
public void describe(@Nonnull SensorDescriptor descriptor) {
descriptor.name(NAME);
descriptor.onlyOnLanguage(ObjectiveC.KEY);
}

public void analyse(final Project project, final SensorContext context) {
@Override
public void execute(@Nonnull org.sonar.api.batch.sensor.SensorContext context) {
final String projectBaseDir = fileSystem.baseDir().getPath();
final OCLintParser parser = new OCLintParser(project, context, resourcePerspectives, fileSystem);

parseReportIn(projectBaseDir, parser);

parseReportIn(projectBaseDir, OCLintViolationPersistor.create(context));
}

private void parseReportIn(final String baseDir, final OCLintParser parser) {

private void parseReportIn(final String baseDir, OCLintViolationPersistor persistor) {
DirectoryScanner scanner = new DirectoryScanner();
scanner.setIncludes(new String[]{reportPath()});
scanner.setIncludes(new String[]{buildReportPath()});
scanner.setBasedir(baseDir);
scanner.setCaseSensitive(false);
scanner.scan();
String[] files = scanner.getIncludedFiles();

List<Violation> violations = new ArrayList<>();

for(String filename : files) {
LoggerFactory.getLogger(getClass()).info("Processing OCLint report {}", filename);
parser.parseReport(new File(filename));
LOGGER.info("Processing OCLint report {}", filename);

violations.addAll(parser.parse(new File(filename)));
}

persistor.saveViolations(violations);
}

private String reportPath() {
private String buildReportPath() {
String reportPath = conf.getString(REPORT_PATH_KEY);

if (reportPath == null) {
LOGGER.debug("No value specified for \"" + REPORT_PATH_KEY + "\" using default path");
reportPath = DEFAULT_REPORT_PATH;
}

return reportPath;
}
}
Loading