diff --git a/pom.xml b/pom.xml
index 314ca34..d7b0bef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,8 +45,6 @@
2.10.4
2.10
-
- 3.3.2
scala
@@ -62,11 +60,6 @@
scala-library
${scala.version}
-
- org.codehaus.sonar.plugins
- sonar-cobertura-plugin
- ${cobertura.version}
-
org.scala-lang
scala-compiler
diff --git a/src/main/java/org/sonar/plugins/scala/cobertura/CoberturaSensor.java b/src/main/java/org/sonar/plugins/scala/cobertura/CoberturaSensor.java
index 58e523a..cf3da99 100644
--- a/src/main/java/org/sonar/plugins/scala/cobertura/CoberturaSensor.java
+++ b/src/main/java/org/sonar/plugins/scala/cobertura/CoberturaSensor.java
@@ -27,46 +27,55 @@
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.config.Settings;
import org.sonar.api.resources.Project;
-import org.sonar.plugins.cobertura.api.AbstractCoberturaParser;
-import org.sonar.plugins.cobertura.api.CoberturaUtils;
+import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.plugins.scala.language.Scala;
public class CoberturaSensor implements Sensor, CoverageExtension {
- private static final Logger LOG = LoggerFactory.getLogger(CoberturaSensor.class);
-
- private final FileSystem fileSystem;
- private static final AbstractCoberturaParser COBERTURA_PARSER = new ScalaCoberturaParser();
+ private static final Logger LOG = LoggerFactory.getLogger(CoberturaSensor.class);
+
+ public static final String COBERTURA_REPORTS_PATH_PROPERTY ="sonar.cobertura.reportPath";
+ private FileSystem fileSystem;;
+ private PathResolver pathResolver;
+ private Settings settings;
- public CoberturaSensor(FileSystem fileSystem) {
- this.fileSystem = fileSystem;
- }
-
- public boolean shouldExecuteOnProject(Project project) {
- if(fileSystem.languages().contains(Scala.KEY)){
- LOG.info("CoberturaSensor will be executed");
- return true;
- } else {
- LOG.info("CoberturaSensor will NOT be executed");
- return false;
- }
- }
-
- public void analyse(Project project, SensorContext context) {
- File report = CoberturaUtils.getReport(project);
- if (report != null) {
- parseReport(report, context);
- }
- }
- protected void parseReport(File xmlFile, final SensorContext context) {
- LOG.info("parsing {}", xmlFile);
- COBERTURA_PARSER.parseReport(xmlFile, context);
+ public CoberturaSensor(FileSystem fileSystem, PathResolver pathResolver, Settings settings) {
+ this.pathResolver = pathResolver;
+ this.settings = settings;
+ this.fileSystem = fileSystem;
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ if(fileSystem.languages().contains(Scala.KEY)){
+ LOG.info("CoberturaSensor will be executed");
+ return true;
+ } else {
+ LOG.info("CoberturaSensor will NOT be executed");
+ return false;
}
+ }
- @Override
- public String toString() {
- return "Scala CoberturaSensor";
+ public void analyse(Project project, SensorContext context) {
+ String path = settings.getString(COBERTURA_REPORTS_PATH_PROPERTY);
+ File report = pathResolver.relativeFile(fileSystem.baseDir(), path);
+ if (!report.isFile()) {
+ LOG.warn("Cobertura report not found at {}", report);
+ return;
}
+ parseReport(report, context);
+ }
+
+ protected void parseReport(File xmlFile, SensorContext context) {
+ LOG.info("parsing {}", xmlFile);
+ ScalaCoberturaReportParser.parseReport(xmlFile, context, fileSystem);
+ }
+
+ @Override
+ public String toString() {
+ return "Scala CoberturaSensor";
+ }
+
}
diff --git a/src/main/java/org/sonar/plugins/scala/cobertura/ScalaCoberturaParser.java b/src/main/java/org/sonar/plugins/scala/cobertura/ScalaCoberturaParser.java
deleted file mode 100644
index 7f1212d..0000000
--- a/src/main/java/org/sonar/plugins/scala/cobertura/ScalaCoberturaParser.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Sonar Scala Plugin
- * Copyright (C) 2011 - 2014 All contributors
- * 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.scala.cobertura;
-
-import org.sonar.api.resources.Resource;
-import org.sonar.plugins.cobertura.api.AbstractCoberturaParser;
-import org.sonar.plugins.scala.language.ScalaFile;
-
-public class ScalaCoberturaParser extends AbstractCoberturaParser {
- @Override
- protected Resource getResource(String fileName) {
- // TODO update the sbt scct plugin to provide the correct fully qualified class name.
- if (fileName.startsWith("src.main.scala."))
- fileName = fileName.replace("src.main.scala.", "");
- else if (fileName.startsWith("app."))
- fileName = fileName.replace("app.", "");
- int packageTerminator = fileName.lastIndexOf('.');
- if (packageTerminator < 0) {
- return new ScalaFile(null, fileName, false);
- } else {
- String packageName = fileName.substring(0, packageTerminator);
- String className = fileName.substring(packageTerminator + 1, fileName.length());
- return new ScalaFile(packageName, className, false);
- }
- }
-}
diff --git a/src/main/java/org/sonar/plugins/scala/cobertura/ScalaCoberturaReportParser.java b/src/main/java/org/sonar/plugins/scala/cobertura/ScalaCoberturaReportParser.java
new file mode 100644
index 0000000..54d2b01
--- /dev/null
+++ b/src/main/java/org/sonar/plugins/scala/cobertura/ScalaCoberturaReportParser.java
@@ -0,0 +1,143 @@
+/*
+ * Sonar Scala Plugin
+ * Copyright (C) 2011 - 2014 All contributors
+ * 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.scala.cobertura;
+
+import static java.util.Locale.ENGLISH;
+import static org.sonar.api.utils.ParsingUtils.parseNumber;
+
+import java.io.File;
+import java.text.ParseException;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.staxmate.in.SMHierarchicCursor;
+import org.codehaus.staxmate.in.SMInputCursor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.measures.CoverageMeasuresBuilder;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.utils.StaxParser;
+import org.sonar.api.utils.XmlParserException;
+
+import com.google.common.collect.Maps;
+
+public class ScalaCoberturaReportParser {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ScalaCoberturaReportParser.class);
+ private final SensorContext context;
+ private FileSystem fileSystem;
+
+ private ScalaCoberturaReportParser(SensorContext context, FileSystem fileSystem) {
+ this.context = context;
+ this.fileSystem = fileSystem;
+ }
+
+ /**
+ * Parse a Cobertura xml report and create measures accordingly
+ * @param fileSystem
+ */
+ public static void parseReport(File xmlFile, SensorContext context, FileSystem fileSystem) {
+ new ScalaCoberturaReportParser(context, fileSystem).parse(xmlFile);
+ }
+
+ private void parse(File xmlFile) {
+ try {
+ StaxParser parser = new StaxParser(new StaxParser.XmlStreamHandler() {
+
+ public void stream(SMHierarchicCursor rootCursor) throws XMLStreamException {
+ rootCursor.advance();
+ collectPackageMeasures(rootCursor.descendantElementCursor("package"));
+ }
+ });
+ parser.parse(xmlFile);
+ } catch (XMLStreamException e) {
+ throw new XmlParserException(e);
+ }
+ }
+
+ private void collectPackageMeasures(SMInputCursor pack) throws XMLStreamException {
+ while (pack.getNext() != null) {
+ Map builderByFilename = Maps.newHashMap();
+ collectFileMeasures(pack.descendantElementCursor("class"), builderByFilename);
+ for (Map.Entry entry : builderByFilename.entrySet()) {
+ String className = sanitizeFilename(entry.getKey());
+ String filename = className.replace('.', '/') + ".scala";
+ FilePredicates filePredicates = fileSystem.predicates();
+ InputFile resource = fileSystem.inputFile(filePredicates.matchesPathPattern("**/*" + filename));
+ if (resource != null){
+ for (Measure measure : entry.getValue().createMeasures()) {
+ context.saveMeasure(resource, measure);
+ }
+ }else{
+ LOG.warn("Resource not found: {}", entry.getKey());
+ }
+ }
+ }
+ }
+
+// private boolean resourceExists(Resource file) {
+// return context.getResource(file) != null;
+// }
+
+ private void collectFileMeasures(SMInputCursor clazz, Map builderByFilename) throws XMLStreamException {
+ while (clazz.getNext() != null) {
+ String fileName = clazz.getAttrValue("filename");
+ CoverageMeasuresBuilder builder = builderByFilename.get(fileName);
+ if (builder == null) {
+ builder = CoverageMeasuresBuilder.create();
+ builderByFilename.put(fileName, builder);
+ }
+ collectFileData(clazz, builder);
+ }
+ }
+
+ private void collectFileData(SMInputCursor clazz, CoverageMeasuresBuilder builder) throws XMLStreamException {
+ SMInputCursor line = clazz.childElementCursor("lines").advance().childElementCursor("line");
+ while (line.getNext() != null) {
+ int lineId = Integer.parseInt(line.getAttrValue("number"));
+ try {
+ builder.setHits(lineId, (int) parseNumber(line.getAttrValue("hits"), ENGLISH));
+ } catch (ParseException e) {
+ throw new XmlParserException(e);
+ }
+
+ String isBranch = line.getAttrValue("branch");
+ String text = line.getAttrValue("condition-coverage");
+ if (StringUtils.equals(isBranch, "true") && StringUtils.isNotBlank(text)) {
+ String[] conditions = StringUtils.split(StringUtils.substringBetween(text, "(", ")"), "/");
+ builder.setConditions(lineId, Integer.parseInt(conditions[1]), Integer.parseInt(conditions[0]));
+ }
+ }
+ }
+
+ private static String sanitizeFilename(String s) {
+ String fileName = FilenameUtils.removeExtension(s);
+ fileName = fileName.replace('/', '.').replace('\\', '.');
+ return fileName;
+ }
+
+}