]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5389 Add a new dependency API
authorJulien HENRY <julien.henry@sonarsource.com>
Thu, 11 Sep 2014 21:53:19 +0000 (23:53 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Fri, 12 Sep 2014 07:11:12 +0000 (09:11 +0200)
14 files changed:
sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java
sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/dependency/OutgoingDependency.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/dependency/package-info.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java
sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java
sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
sonar-plugin-api/src/main/java/org/sonar/api/issue/NoSonarFilter.java
sonar-plugin-api/src/main/java/org/sonar/api/resources/InputFileUtils.java

index 4152792943126e3a4c10a33b6a84577e1f5f34a9..33172ca4aaa3366358fc8444afcb250072241361 100644 (file)
@@ -26,7 +26,6 @@ import org.sonar.api.batch.DecoratorContext;
 import org.sonar.api.batch.Event;
 import org.sonar.api.batch.SonarIndex;
 import org.sonar.api.design.Dependency;
-import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.MeasuresFilter;
 import org.sonar.api.measures.MeasuresFilters;
@@ -156,9 +155,6 @@ public class DefaultDecoratorContext implements DecoratorContext {
         if (index > -1) {
           if (metricMeasures.get(index) == measure) {
             add = false;
-          } else if (measure.getMetric().equals(CoreMetrics.TESTS)) {
-            // Hack for SONAR-5212
-            measuresByMetric.remove(measure.getMetric().getKey(), metricMeasures.get(index));
           } else {
             throw new SonarException("Can not add twice the same measure on " + resource + ": " + measure);
           }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java b/sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java
new file mode 100644 (file)
index 0000000..18dab70
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.dependency;
+
+import com.google.common.base.Preconditions;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.batch.index.Cache;
+import org.sonar.batch.index.Cache.Entry;
+import org.sonar.batch.index.Caches;
+import org.sonar.batch.scan.filesystem.InputPathCache;
+
+import javax.annotation.CheckForNull;
+
+/**
+ * Cache of all dependencies. This cache is shared amongst all project modules.
+ * module key -> from key -> to key -> OutgoingDependency
+ */
+public class DependencyCache implements BatchComponent {
+
+  private final Cache<OutgoingDependency> cache;
+
+  public DependencyCache(Caches caches, InputPathCache inputPathCache) {
+    cache = caches.createCache("dependencies");
+  }
+
+  public Iterable<Entry<OutgoingDependency>> entries() {
+    return cache.entries();
+  }
+
+  @CheckForNull
+  public OutgoingDependency get(String moduleKey, InputFile from, InputFile to) {
+    Preconditions.checkNotNull(moduleKey);
+    Preconditions.checkNotNull(from);
+    Preconditions.checkNotNull(to);
+    return cache.get(moduleKey, ((DefaultInputFile) from).key(), ((DefaultInputFile) to).key());
+  }
+
+  public DependencyCache put(String moduleKey, InputFile from, OutgoingDependency dependency) {
+    Preconditions.checkNotNull(moduleKey);
+    Preconditions.checkNotNull(from);
+    Preconditions.checkNotNull(dependency);
+    cache.put(moduleKey, ((DefaultInputFile) from).key(), ((DefaultInputFile) dependency.to()).key(), dependency);
+    return this;
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/dependency/OutgoingDependency.java b/sonar-batch/src/main/java/org/sonar/batch/dependency/OutgoingDependency.java
new file mode 100644 (file)
index 0000000..b768687
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.dependency;
+
+import org.sonar.api.batch.fs.InputFile;
+
+public class OutgoingDependency {
+
+  private final InputFile to;
+  private final String usage;
+
+  public OutgoingDependency(InputFile to, String usage) {
+    this.to = to;
+    this.usage = usage;
+  }
+
+  public InputFile to() {
+    return to;
+  }
+
+  public String usage() {
+    return usage;
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/dependency/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/dependency/package-info.java
new file mode 100644 (file)
index 0000000..56e93fe
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.batch.dependency;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
index 088a0fbda43219a37be877672ad53964f14d1cbf..17d935699cd72d6facc633ca9245694d114db00b 100644 (file)
@@ -31,7 +31,6 @@ import org.sonar.api.batch.SonarIndex;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.database.model.Snapshot;
 import org.sonar.api.design.Dependency;
-import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.MeasuresFilter;
 import org.sonar.api.measures.MeasuresFilters;
@@ -216,9 +215,7 @@ public class DefaultIndex extends SonarIndex {
         throw new SonarException("Unknown metric: " + measure.getMetricKey());
       }
       measure.setMetric(metric);
-      if (measureCache.contains(resource, measure)
-        // Hack for SONAR-5212
-        && !measure.getMetric().equals(CoreMetrics.TESTS)) {
+      if (measureCache.contains(resource, measure)) {
         throw new SonarException("Can not add the same measure twice on " + resource + ": " + measure);
       }
       measureCache.put(resource, measure);
index 16f058187a076f2584780652bd81e21b6c714afa..e17c5a087d57495398cdf9585dfeb922490261ac 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.batch.mediumtest;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.SonarPlugin;
@@ -42,6 +43,8 @@ import org.sonar.batch.bootstrap.PluginsReferential;
 import org.sonar.batch.bootstrap.TaskProperties;
 import org.sonar.batch.bootstrapper.Batch;
 import org.sonar.batch.bootstrapper.EnvironmentInformation;
+import org.sonar.batch.dependency.DependencyCache;
+import org.sonar.batch.dependency.OutgoingDependency;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.highlighting.SyntaxHighlightingData;
 import org.sonar.batch.highlighting.SyntaxHighlightingRule;
@@ -232,6 +235,7 @@ public class BatchMediumTester {
     private Map<InputFile, SymbolData> symbolTablePerFile = new HashMap<InputFile, SymbolData>();
     private Map<String, Map<String, TestCase>> testCasesPerFile = new HashMap<String, Map<String, TestCase>>();
     private Map<String, Map<String, Map<String, List<Integer>>>> coveragePerTest = new HashMap<String, Map<String, Map<String, List<Integer>>>>();
+    private Map<String, Map<String, String>> dependencies = new HashMap<String, Map<String, String>>();
 
     @Override
     public void scanTaskCompleted(ProjectScanContainer container) {
@@ -249,6 +253,8 @@ public class BatchMediumTester {
       storeDuplication(container);
       storeTestCases(container);
       storeCoveragePerTest(container);
+      storeDependencies(container);
+
     }
 
     private void storeCoveragePerTest(ProjectScanContainer container) {
@@ -310,6 +316,18 @@ public class BatchMediumTester {
       }
     }
 
+    private void storeDependencies(ProjectScanContainer container) {
+      DependencyCache dependencyCache = container.getComponentByType(DependencyCache.class);
+      for (Entry<OutgoingDependency> entry : dependencyCache.entries()) {
+        String fromKey = entry.key()[1].toString();
+        String toKey = entry.key()[2].toString();
+        if (!dependencies.containsKey(fromKey)) {
+          dependencies.put(fromKey, new HashMap<String, String>());
+        }
+        dependencies.get(fromKey).put(toKey, StringUtils.trimToEmpty(entry.value().usage()));
+      }
+    }
+
     public List<Issue> issues() {
       return issues;
     }
@@ -389,6 +407,16 @@ public class BatchMediumTester {
       }
       return null;
     }
+
+    /**
+     * @return null if no dependency else return dependency usage.
+     */
+    @CheckForNull
+    public String dependencyUsage(InputFile from, InputFile to) {
+      String fromKey = ((DefaultInputFile) from).key();
+      String toKey = ((DefaultInputFile) to).key();
+      return dependencies.containsKey(fromKey) ? dependencies.get(fromKey).get(toKey) : null;
+    }
   }
 
   private static class FakeGlobalReferentialsLoader implements GlobalReferentialsLoader {
index 37fe0b134bfcb69e18146724c5d9588063384733..59375015b11afc41efea23ad4c66795e0a7a93a3 100644 (file)
@@ -35,6 +35,7 @@ import org.sonar.api.batch.sensor.test.TestCase;
 import org.sonar.api.batch.sensor.test.internal.DefaultTestCase;
 import org.sonar.api.component.ResourcePerspectives;
 import org.sonar.api.config.Settings;
+import org.sonar.api.design.Dependency;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.measures.Formula;
@@ -56,6 +57,7 @@ import org.sonar.batch.duplication.BlockCache;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.batch.scan2.BaseSensorContext;
+import org.sonar.core.component.ComponentKeys;
 
 import java.io.Serializable;
 import java.util.List;
@@ -204,7 +206,7 @@ public class SensorContextAdaptor extends BaseSensorContext {
     if (issuable == null) {
       return false;
     }
-    return issuable.addIssue(toDefaultIssue(project.getKey(), r.getKey(), issue));
+    return issuable.addIssue(toDefaultIssue(project.getKey(), ComponentKeys.createEffectiveKey(project, r), issue));
   }
 
   public static DefaultIssue toDefaultIssue(String projectKey, String componentKey, Issue issue) {
@@ -286,4 +288,28 @@ public class SensorContextAdaptor extends BaseSensorContext {
     return mainRes;
   }
 
+  private File getFile(InputFile file) {
+    if (file.type() == InputFile.Type.MAIN) {
+      return getMainResource(file);
+    } else {
+      return getTestResource(file);
+    }
+  }
+
+  @Override
+  public void saveDependency(InputFile from, InputFile to, String usage) {
+    File fromResource = getFile(from);
+    File toResource = getFile(to);
+    Directory fromParent = fromResource.getParent();
+    Directory toParent = toResource.getParent();
+    Dependency parentDep = null;
+    if (!fromParent.equals(toParent)) {
+      parentDep = new Dependency(fromParent, toParent).setUsage("USES");
+      parentDep = sensorContext.saveDependency(parentDep);
+    }
+    sensorContext.saveDependency(new Dependency(fromResource, toResource)
+      .setUsage(usage)
+      .setParent(parentDep));
+  }
+
 }
index e995b80549068190b533cd52542f1f66e9866137..1ceee76c6d79a7d88e84765497ac33c624598585 100644 (file)
@@ -37,6 +37,8 @@ import org.sonar.api.batch.sensor.test.internal.DefaultTestCase;
 import org.sonar.api.config.Settings;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.MessageException;
+import org.sonar.batch.dependency.DependencyCache;
+import org.sonar.batch.dependency.OutgoingDependency;
 import org.sonar.batch.duplication.BlockCache;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.ComponentDataCache;
@@ -58,10 +60,11 @@ public class DefaultSensorContext extends BaseSensorContext {
   private final IssueFilters issueFilters;
   private final TestCaseCache testCaseCache;
   private final CoveragePerTestCache coveragePerTestCache;
+  private final DependencyCache dependencyCache;
 
   public DefaultSensorContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, AnalyzerIssueCache issueCache,
     Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters, ComponentDataCache componentDataCache,
-    BlockCache blockCache, DuplicationCache duplicationCache, TestCaseCache testCaseCache, CoveragePerTestCache coveragePerTestCache) {
+    BlockCache blockCache, DuplicationCache duplicationCache, TestCaseCache testCaseCache, CoveragePerTestCache coveragePerTestCache, DependencyCache dependencyCache) {
     super(settings, fs, activeRules, componentDataCache, blockCache, duplicationCache);
     this.def = def;
     this.measureCache = measureCache;
@@ -70,6 +73,7 @@ public class DefaultSensorContext extends BaseSensorContext {
     this.issueFilters = issueFilters;
     this.testCaseCache = testCaseCache;
     this.coveragePerTestCache = coveragePerTestCache;
+    this.dependencyCache = dependencyCache;
   }
 
   @Override
@@ -160,4 +164,12 @@ public class DefaultSensorContext extends BaseSensorContext {
     coveragePerTestCache.put(testCase, coveredFile, coveredLines);
   }
 
+  @Override
+  public void saveDependency(InputFile from, InputFile to, String usage) {
+    Preconditions.checkNotNull(from);
+    Preconditions.checkNotNull(to);
+    OutgoingDependency dep = new OutgoingDependency(to, usage);
+    dependencyCache.put(def.getKey(), from, dep);
+  }
+
 }
index 5922b613ffb0a8a84c00c90f99ed7bfbea67eb3b..d5d7ffa6a99787191e09a300a3e8595a84c9c18c 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.api.scan.filesystem.PathResolver;
 import org.sonar.batch.bootstrap.ExtensionInstaller;
 import org.sonar.batch.bootstrap.ExtensionMatcher;
 import org.sonar.batch.bootstrap.ExtensionUtils;
+import org.sonar.batch.dependency.DependencyCache;
 import org.sonar.batch.duplication.BlockCache;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.Caches;
@@ -120,6 +121,9 @@ public class ProjectScanContainer extends ComponentContainer {
       TestCaseCache.class,
       CoveragePerTestCache.class,
 
+      // Dependencies
+      DependencyCache.class,
+
       ScanTaskObservers.class);
   }
 
index adf80cf8cf8ae4fce95b45d61844e51f18718a58..ea96a8678b17f7d00ea30a25125b75c115c5a502 100644 (file)
@@ -170,7 +170,9 @@ public interface SensorContext {
    *
    * @param force allows to force creation of violation even if it was supressed by {@link org.sonar.api.rules.ViolationFilter}
    * @since 2.5
+   * @deprecated since 5.0 but force parameter was ignored for a long time anyway
    */
+  @Deprecated
   void saveViolation(Violation violation, boolean force);
 
   /**
index 32ea0e3cf2e01f8b6fac9cad30e72f6a0db2e4dd..357a7c991035055413a6e7f67d945615df218bbe 100644 (file)
@@ -90,4 +90,5 @@ public interface InputFile extends InputPath {
    * zero if the file is empty.
    */
   int lines();
+
 }
index f2102986b382da252cb69fcd822ae217823802d5..1729795b06d00d8fb21af2e2b64717c00cb11dff 100644 (file)
@@ -190,4 +190,13 @@ public interface SensorContext {
    */
   void saveCoveragePerTest(TestCase testCase, InputFile coveredFile, List<Integer> coveredLines);
 
+  // ------------ DEPENDENCIES ------------
+
+  /**
+   * Declare a dependency between 2 files.
+   * @param usage A qualifier for the dependency. 
+   * @since 5.0
+   */
+  void saveDependency(InputFile from, InputFile to, String usage);
+
 }
index 9331dcac10f23ce6baf9b39d4f4aedba4d216404..591aa0f539b6e1421d62b7de7ce15784abdfb00e 100644 (file)
  */
 package org.sonar.api.issue;
 
-import org.sonar.api.issue.batch.IssueFilterChain;
-
 import com.google.common.collect.Maps;
 import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.issue.batch.IssueFilterChain;
 
 import java.util.Map;
 import java.util.Set;
@@ -40,11 +41,26 @@ public class NoSonarFilter implements org.sonar.api.issue.batch.IssueFilter {
 
   private final Map<String, Set<Integer>> noSonarLinesByResource = Maps.newHashMap();
 
+  /**
+   * @deprecated since 5.0 use {@link #noSonarInFile(InputFile, Set)}
+   */
+  @Deprecated
   public NoSonarFilter addComponent(String componentKey, Set<Integer> noSonarLines) {
     noSonarLinesByResource.put(componentKey, noSonarLines);
     return this;
   }
 
+  /**
+   * Register lines in a file that contains the NOSONAR flag.
+   * @param inputFile
+   * @param noSonarLines Line number starts at 1 in a file
+   * @since 5.0
+   */
+  public NoSonarFilter noSonarInFile(InputFile inputFile, Set<Integer> noSonarLines) {
+    noSonarLinesByResource.put(((DefaultInputFile) inputFile).key(), noSonarLines);
+    return this;
+  }
+
   @Override
   public boolean accept(Issue issue, IssueFilterChain chain) {
     boolean accepted = true;
index 50915f36312cd844c9cfa4b670f12385cf6ce344..d8f49ceb2016ca5ffbb702abd5d00917f34a373c 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.api.resources;
 
 import com.google.common.base.Objects;
-
 import com.google.common.collect.Lists;
 import org.apache.commons.lang.StringUtils;
 
@@ -34,7 +33,9 @@ import java.util.List;
 
 /**
  * @since 2.8
+ * @deprecated since 5.0 as {@link InputFile} is deprecated
  */
+@Deprecated
 public final class InputFileUtils {
 
   private InputFileUtils() {