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;
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);
}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+
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;
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);
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;
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;
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) {
storeDuplication(container);
storeTestCases(container);
storeCoveragePerTest(container);
+ storeDependencies(container);
+
}
private void storeCoveragePerTest(ProjectScanContainer container) {
}
}
+ 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;
}
}
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 {
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;
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;
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) {
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));
+ }
+
}
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;
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;
this.issueFilters = issueFilters;
this.testCaseCache = testCaseCache;
this.coveragePerTestCache = coveragePerTestCache;
+ this.dependencyCache = dependencyCache;
}
@Override
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);
+ }
+
}
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;
TestCaseCache.class,
CoveragePerTestCache.class,
+ // Dependencies
+ DependencyCache.class,
+
ScanTaskObservers.class);
}
*
* @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);
/**
* zero if the file is empty.
*/
int lines();
+
}
*/
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);
+
}
*/
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;
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;
package org.sonar.api.resources;
import com.google.common.base.Objects;
-
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
/**
* @since 2.8
+ * @deprecated since 5.0 as {@link InputFile} is deprecated
*/
+@Deprecated
public final class InputFileUtils {
private InputFileUtils() {