aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine/src/main
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2017-07-10 10:38:27 +0200
committerDuarte Meneses <duarte.meneses@sonarsource.com>2017-07-11 08:51:38 +0200
commit6f107dcbe90b0fea564e1ecaa96643bfc539329a (patch)
tree45478253f6006a0f1381fb506f92852ad2f5c5df /sonar-scanner-engine/src/main
parentf6a0f6bb86f7d244bec0b6781020e2ea066124c6 (diff)
downloadsonarqube-6f107dcbe90b0fea564e1ecaa96643bfc539329a.tar.gz
sonarqube-6f107dcbe90b0fea564e1ecaa96643bfc539329a.zip
SONAR-9477 Deprecate ProjectReactor and ProjectBuilder
Mark Immutable classes in the Plugin API and Scanner
Diffstat (limited to 'sonar-scanner-engine/src/main')
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java43
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectAnalysisInfo.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java9
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/DefaultAnalysisMode.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalMode.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java29
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdSettings.java52
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java16
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultIssueFilterChain.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java5
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java30
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java15
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java17
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java2
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java8
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/ServerIssueRepository.java23
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java7
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersExecutor.java6
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java5
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobsExecutor.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java2
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java7
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java7
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/report/AnalysisContextReportPublisher.java26
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java1
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java9
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java34
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ContextPropertiesCache.java5
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositories.java16
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesRepository.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/Language.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/LanguagesRepository.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ModuleQProfiles.java17
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfile.java84
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/RuleFinderCompatibility.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultInputModuleHierarchy.java66
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ImmutableProjectReactor.java71
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputModuleHierarchyProvider.java65
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.java30
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java2
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleSettingsProvider.java9
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectLock.java7
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java19
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java14
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoryCleaner.java9
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/BatchIdGenerator.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ExclusionFilters.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java12
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java26
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStoreProvider.java (renamed from sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ImmutableProjectReactorProvider.java)24
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java5
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/LanguageDetection.java44
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializer.java1
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DefaultMetricFinder.java11
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/report/RuleNameProvider.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmConfiguration.java18
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java117
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/coverage/CoverageExclusions.java30
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java8
64 files changed, 650 insertions, 472 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java
index 0c0b42bef0a..28d1af3517b 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java
@@ -19,12 +19,12 @@
*/
package org.sonar.scanner;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
+import static java.util.stream.Collectors.toMap;
+
+import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.sensor.SensorContext;
@@ -35,10 +35,11 @@ import org.sonar.api.utils.KeyValueFormat;
import org.sonar.api.utils.KeyValueFormat.Converter;
import org.sonar.scanner.scan.measure.MeasureCache;
-import static java.util.stream.Collectors.toMap;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
public class DefaultFileLinesContext implements FileLinesContext {
-
private final SensorContext context;
private final InputFile inputFile;
private final MetricFinder metricFinder;
@@ -47,7 +48,7 @@ public class DefaultFileLinesContext implements FileLinesContext {
/**
* metric key -> line -> value
*/
- private final Map<String, Map<Integer, Object>> map = Maps.newHashMap();
+ private final Map<String, Map<Integer, Object>> map = new HashMap<>();
public DefaultFileLinesContext(SensorContext context, InputFile inputFile, MetricFinder metricFinder, MeasureCache measureCache) {
this.context = context;
@@ -73,13 +74,7 @@ public class DefaultFileLinesContext implements FileLinesContext {
public Integer getIntValue(String metricKey, int line) {
Preconditions.checkNotNull(metricKey);
checkLineRange(line);
-
- Map<Integer, Object> lines = map.get(metricKey);
- if (lines == null) {
- // not in memory, so load
- lines = loadData(metricKey, KeyValueFormat.newIntegerConverter());
- map.put(metricKey, lines);
- }
+ Map<Integer, Object> lines = map.computeIfAbsent(metricKey, k -> loadData(k, KeyValueFormat.newIntegerConverter()));
return (Integer) lines.get(line);
}
@@ -96,27 +91,13 @@ public class DefaultFileLinesContext implements FileLinesContext {
public String getStringValue(String metricKey, int line) {
Preconditions.checkNotNull(metricKey);
checkLineRange(line);
-
- Map<Integer, Object> lines = map.get(metricKey);
- if (lines == null) {
- // not in memory, so load
- lines = loadData(metricKey, KeyValueFormat.newStringConverter());
- map.put(metricKey, lines);
- }
+ Map<Integer, Object> lines = map.computeIfAbsent(metricKey, k -> loadData(k, KeyValueFormat.newStringConverter()));
return (String) lines.get(line);
}
- private Map<Integer, Object> getOrCreateLines(String metricKey) {
- Map<Integer, Object> lines = map.get(metricKey);
- if (lines == null) {
- lines = Maps.newHashMap();
- map.put(metricKey, lines);
- }
- return lines;
- }
-
private void setValue(String metricKey, int line, Object value) {
- getOrCreateLines(metricKey).put(line, value);
+ map.computeIfAbsent(metricKey, k -> new HashMap<>())
+ .put(line, value);
}
@Override
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectAnalysisInfo.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectAnalysisInfo.java
index 40d7cbcd3c7..c0eed526886 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectAnalysisInfo.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectAnalysisInfo.java
@@ -21,6 +21,7 @@ package org.sonar.scanner;
import java.util.Date;
import java.util.Optional;
+
import org.picocontainer.Startable;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.ScannerSide;
@@ -31,6 +32,8 @@ import org.sonar.api.utils.System2;
/**
* @since 6.3
+ *
+ * Immutable after {@link #start()}
*/
@ScannerSide
public class ProjectAnalysisInfo implements Startable {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java
index dc4a860533c..1c0ec317ad7 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java
@@ -22,10 +22,11 @@ package org.sonar.scanner.analysis;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+
import org.picocontainer.ComponentLifecycle;
import org.picocontainer.PicoContainer;
import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.internal.DefaultTempFolder;
@@ -34,9 +35,9 @@ public class AnalysisTempFolderProvider extends ProviderAdapter implements Compo
private DefaultTempFolder projectTempFolder;
private boolean started = false;
- public TempFolder provide(ProjectReactor projectReactor) {
+ public TempFolder provide(InputModuleHierarchy moduleHierarchy) {
if (projectTempFolder == null) {
- Path workingDir = projectReactor.getRoot().getWorkDir().toPath();
+ Path workingDir = moduleHierarchy.root().getWorkDir().toPath();
Path tempDir = workingDir.normalize().resolve(TMP_NAME);
try {
Files.deleteIfExists(tempDir);
@@ -64,7 +65,7 @@ public class AnalysisTempFolderProvider extends ProviderAdapter implements Compo
@Override
public void dispose(PicoContainer container) {
- //nothing to do
+ // nothing to do
}
@Override
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/DefaultAnalysisMode.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/DefaultAnalysisMode.java
index 9414be0017f..28fefb1080a 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/DefaultAnalysisMode.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/DefaultAnalysisMode.java
@@ -21,6 +21,8 @@ package org.sonar.scanner.analysis;
import java.util.Map;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
@@ -30,6 +32,7 @@ import org.sonar.scanner.bootstrap.GlobalProperties;
/**
* @since 4.0
*/
+@Immutable
public class DefaultAnalysisMode extends AbstractAnalysisMode {
private static final Logger LOG = LoggerFactory.getLogger(DefaultAnalysisMode.class);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalMode.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalMode.java
index 76b37d87b29..743294be0f8 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalMode.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalMode.java
@@ -19,10 +19,13 @@
*/
package org.sonar.scanner.bootstrap;
+import javax.annotation.concurrent.Immutable;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
+@Immutable
public class GlobalMode extends AbstractAnalysisMode {
private static final Logger LOG = LoggerFactory.getLogger(GlobalMode.class);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java
index 70749f70fc0..0117f735ba6 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java
@@ -30,6 +30,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
+
import org.apache.commons.lang.ClassUtils;
import org.sonar.api.batch.CheckProject;
import org.sonar.api.batch.DependedUpon;
@@ -279,7 +280,7 @@ public class ScannerExtensionDictionnary {
|| (org.sonar.api.batch.Sensor.class.equals(type) && ClassUtils.isAssignable(extension.getClass(), Sensor.class)))
&& (matcher == null || matcher.accept(extension));
if (keep && module != null && ClassUtils.isAssignable(extension.getClass(), CheckProject.class)) {
- keep = ((CheckProject) extension).shouldExecuteOnProject(new Project(module.definition()));
+ keep = ((CheckProject) extension).shouldExecuteOnProject(new Project(module));
}
return keep;
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java
index 87a0794c1e5..e8e1d804b36 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java
@@ -19,9 +19,8 @@
*/
package org.sonar.scanner.cpd;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
+import static com.google.common.collect.FluentIterable.from;
+
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@@ -30,10 +29,10 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputComponent;
-import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.duplications.block.Block;
@@ -49,7 +48,9 @@ import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.util.ProgressReport;
-import static com.google.common.collect.FluentIterable.from;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
/**
* Runs on the root module, at the end of the project analysis.
@@ -66,12 +67,12 @@ public class CpdExecutor {
private final SonarCpdBlockIndex index;
private final ReportPublisher publisher;
private final InputComponentStore componentStore;
- private final Configuration settings;
private final ProgressReport progressReport;
+ private final CpdSettings settings;
private int count;
private int total;
- public CpdExecutor(Configuration settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) {
+ public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) {
this.settings = settings;
this.index = index;
this.publisher = publisher;
@@ -139,7 +140,8 @@ public class CpdExecutor {
List<CloneGroup> filtered;
if (!"java".equalsIgnoreCase(inputFile.language())) {
- Predicate<CloneGroup> minimumTokensPredicate = DuplicationPredicates.numberOfUnitsNotLessThan(getMinimumTokens(inputFile.language()));
+ int minTokens = settings.getMinimumTokens(inputFile.language());
+ Predicate<CloneGroup> minimumTokensPredicate = DuplicationPredicates.numberOfUnitsNotLessThan(minTokens);
filtered = from(duplications).filter(minimumTokensPredicate).toList();
} else {
filtered = duplications;
@@ -149,17 +151,6 @@ public class CpdExecutor {
}
@VisibleForTesting
- /**
- * Not applicable to Java, as the {@link BlockChunker} that it uses does not record start and end units of each block.
- * Also, it uses statements instead of tokens.
- * @param languageKey
- * @return
- */
- int getMinimumTokens(String languageKey) {
- return settings.getInt("sonar.cpd." + languageKey + ".minimumTokens").orElse(100);
- }
-
- @VisibleForTesting
final void saveDuplications(final DefaultInputComponent component, List<CloneGroup> duplications) {
if (duplications.size() > MAX_CLONE_GROUP_PER_FILE) {
LOG.warn("Too many duplication groups on file " + component + ". Keep only the first " + MAX_CLONE_GROUP_PER_FILE +
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdSettings.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdSettings.java
new file mode 100644
index 00000000000..7335d85ef88
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdSettings.java
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * 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 02110-1301, USA.
+ */
+package org.sonar.scanner.cpd;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.config.Configuration;
+import org.sonar.duplications.block.BlockChunker;
+
+public class CpdSettings {
+ private final Configuration settings;
+ private final String branch;
+
+ public CpdSettings(Configuration settings, InputModuleHierarchy hierarchy) {
+ this.settings = settings;
+ this.branch = hierarchy.root().getBranch();
+ }
+
+ public boolean isCrossProjectDuplicationEnabled() {
+ return settings.getBoolean(CoreProperties.CPD_CROSS_PROJECT).orElse(false)
+ // No cross project duplication for branches
+ && StringUtils.isBlank(branch);
+ }
+
+ /**
+ * Not applicable to Java, as the {@link BlockChunker} that it uses does not record start and end units of each block.
+ * Also, it uses statements instead of tokens.
+ * @param languageKey
+ * @return
+ */
+ int getMinimumTokens(String languageKey) {
+ return settings.getInt("sonar.cpd." + languageKey + ".minimumTokens").orElse(100);
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java
index 2a4cdf9eab0..a5bc77ba3e6 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/index/SonarCpdBlockIndex.java
@@ -24,10 +24,9 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.stream.Collectors;
-import org.sonar.api.CoreProperties;
+
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.duplications.block.Block;
@@ -36,6 +35,7 @@ import org.sonar.duplications.index.AbstractCloneIndex;
import org.sonar.duplications.index.CloneIndex;
import org.sonar.duplications.index.PackedMemoryCloneIndex;
import org.sonar.duplications.index.PackedMemoryCloneIndex.ResourceBlocks;
+import org.sonar.scanner.cpd.CpdSettings;
import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.report.ReportPublisher;
@@ -44,17 +44,17 @@ public class SonarCpdBlockIndex extends AbstractCloneIndex {
private static final Logger LOG = Loggers.get(SonarCpdBlockIndex.class);
private final CloneIndex mem = new PackedMemoryCloneIndex();
private final ReportPublisher publisher;
- private final Configuration settings;
// Files already tokenized
private final Set<InputFile> indexedFiles = new HashSet<>();
+ private final CpdSettings settings;
- public SonarCpdBlockIndex(ReportPublisher publisher, Configuration settings) {
+ public SonarCpdBlockIndex(ReportPublisher publisher, CpdSettings settings) {
this.publisher = publisher;
this.settings = settings;
}
public void insert(InputFile inputFile, Collection<Block> blocks) {
- if (isCrossProjectDuplicationEnabled(settings)) {
+ if (settings.isCrossProjectDuplicationEnabled()) {
int id = ((DefaultInputFile) inputFile).batchId();
if (publisher.getWriter().hasComponentData(FileStructure.Domain.CPD_TEXT_BLOCKS, id)) {
throw new UnsupportedOperationException("Trying to save CPD tokens twice for the same file is not supported: " + inputFile.absolutePath());
@@ -87,12 +87,6 @@ public class SonarCpdBlockIndex extends AbstractCloneIndex {
return indexedFiles.contains(inputFile);
}
- public static boolean isCrossProjectDuplicationEnabled(Configuration settings) {
- return settings.getBoolean(CoreProperties.CPD_CROSS_PROJECT).orElse(false)
- // No cross project duplication for branches
- && !settings.get(CoreProperties.PROJECT_BRANCH_PROPERTY).isPresent();
- }
-
public Collection<Block> getByInputFile(String resourceKey) {
return mem.getByResourceId(resourceKey);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java
index 1690a8a44be..14eb7316b40 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java
@@ -123,7 +123,7 @@ public class DefaultIndex {
if (component == null) {
throw new IllegalStateException("Invalid component key: " + key);
}
- if (sensorStorage.isDeprecatedMetric(measure.getMetricKey())) {
+ if (DefaultSensorStorage.isDeprecatedMetric(measure.getMetricKey())) {
// Ignore deprecated metrics
return measure;
}
@@ -187,7 +187,7 @@ public class DefaultIndex {
} else if (inputComponent instanceof InputFile) {
r = File.create(((InputFile) inputComponent).relativePath());
} else if (inputComponent instanceof InputModule) {
- r = new Project(((DefaultInputModule) inputComponent).definition());
+ r = new Project(((DefaultInputModule) inputComponent));
} else {
throw new IllegalArgumentException("Unknow input path type: " + inputComponent);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java
index ccc86732f23..a0331d07aa9 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java
@@ -20,6 +20,9 @@
package org.sonar.scanner.issue;
import java.util.Date;
+
+import javax.annotation.concurrent.ThreadSafe;
+
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.batch.fs.InputModule;
@@ -29,6 +32,7 @@ import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
+@ThreadSafe
public class DefaultFilterableIssue implements FilterableIssue {
private final Issue rawIssue;
private final ProjectAnalysisInfo projectAnalysisInfo;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultIssueFilterChain.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultIssueFilterChain.java
index d0f01cc432d..fb8105bfd58 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultIssueFilterChain.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultIssueFilterChain.java
@@ -22,10 +22,14 @@ package org.sonar.scanner.issue;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+
+import javax.annotation.concurrent.ThreadSafe;
+
import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.api.scan.issue.filter.IssueFilter;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
+@ThreadSafe
public class DefaultIssueFilterChain implements IssueFilterChain {
private final List<IssueFilter> filters;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
index db9105a3f90..f31865db0cf 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
@@ -30,14 +30,14 @@ import org.sonar.scanner.protocol.output.ScannerReport;
@ScannerSide
public class IssueFilters {
- private final IssueFilter[] filters;
+ private final IssueFilterChain filterChain;
private final org.sonar.api.issue.batch.IssueFilter[] deprecatedFilters;
private final DefaultInputModule module;
private final ProjectAnalysisInfo projectAnalysisInfo;
public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] exclusionFilters, org.sonar.api.issue.batch.IssueFilter[] filters) {
this.module = module;
- this.filters = exclusionFilters;
+ this.filterChain = new DefaultIssueFilterChain(exclusionFilters);
this.deprecatedFilters = filters;
this.projectAnalysisInfo = projectAnalysisInfo;
}
@@ -55,7 +55,6 @@ public class IssueFilters {
}
public boolean accept(String componentKey, ScannerReport.Issue rawIssue) {
- IssueFilterChain filterChain = new DefaultIssueFilterChain(filters);
FilterableIssue fIssue = new DefaultFilterableIssue(module, projectAnalysisInfo, rawIssue, componentKey);
if (filterChain.accept(fIssue)) {
return acceptDeprecated(componentKey, rawIssue);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java
index 874e4514cf9..279b003d933 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java
@@ -19,7 +19,8 @@
*/
package org.sonar.scanner.issue;
-import com.google.common.base.Strings;
+import javax.annotation.concurrent.ThreadSafe;
+
import org.sonar.api.batch.fs.TextRange;
import org.sonar.api.batch.fs.internal.DefaultInputComponent;
import org.sonar.api.batch.rule.ActiveRule;
@@ -35,9 +36,12 @@ import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.IssueLocation;
import org.sonar.scanner.report.ReportPublisher;
+import com.google.common.base.Strings;
+
/**
* Initialize the issues raised during scan.
*/
+@ThreadSafe
public class ModuleIssues {
private final ActiveRules activeRules;
@@ -62,9 +66,19 @@ public class ModuleIssues {
return false;
}
- String primaryMessage = Strings.isNullOrEmpty(issue.primaryLocation().message()) ? rule.name() : issue.primaryLocation().message();
+ ScannerReport.Issue rawIssue = createReportIssue(issue, inputComponent.batchId(), rule.name(), activeRule.severity());
+
+ if (filters.accept(inputComponent.key(), rawIssue)) {
+ write(inputComponent.batchId(), rawIssue);
+ return true;
+ }
+ return false;
+ }
+
+ private static ScannerReport.Issue createReportIssue(Issue issue, int batchId, String ruleName, String activeRuleSeverity) {
+ String primaryMessage = Strings.isNullOrEmpty(issue.primaryLocation().message()) ? ruleName : issue.primaryLocation().message();
org.sonar.api.batch.rule.Severity overriddenSeverity = issue.overriddenSeverity();
- Severity severity = overriddenSeverity != null ? Severity.valueOf(overriddenSeverity.name()) : Severity.valueOf(activeRule.severity());
+ Severity severity = overriddenSeverity != null ? Severity.valueOf(overriddenSeverity.name()) : Severity.valueOf(activeRuleSeverity);
ScannerReport.Issue.Builder builder = ScannerReport.Issue.newBuilder();
ScannerReport.IssueLocation.Builder locationBuilder = IssueLocation.newBuilder();
@@ -76,7 +90,7 @@ public class ModuleIssues {
builder.setMsg(primaryMessage);
locationBuilder.setMsg(primaryMessage);
- locationBuilder.setComponentRef(inputComponent.batchId());
+ locationBuilder.setComponentRef(batchId);
TextRange primaryTextRange = issue.primaryLocation().textRange();
if (primaryTextRange != null) {
builder.setTextRange(toProtobufTextRange(textRangeBuilder, primaryTextRange));
@@ -86,13 +100,7 @@ public class ModuleIssues {
builder.setGap(gap);
}
applyFlows(builder, locationBuilder, textRangeBuilder, issue);
- ScannerReport.Issue rawIssue = builder.build();
-
- if (filters.accept(inputComponent.key(), rawIssue)) {
- write(inputComponent.batchId(), rawIssue);
- return true;
- }
- return false;
+ return builder.build();
}
private static void applyFlows(ScannerReport.Issue.Builder builder, ScannerReport.IssueLocation.Builder locationBuilder,
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java
index 66efeb194f3..dc96c80d2d1 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java
@@ -19,7 +19,13 @@
*/
package org.sonar.scanner.issue.ignore;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.ThreadSafe;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.InputComponent;
@@ -31,14 +37,15 @@ import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
+@ThreadSafe
public class EnforceIssuesFilter implements IssueFilter {
private static final Logger LOG = LoggerFactory.getLogger(EnforceIssuesFilter.class);
- private IssueInclusionPatternInitializer patternInitializer;
- private InputComponentStore componentStore;
+ private final List<IssuePattern> multicriteriaPatterns;
+ private final InputComponentStore componentStore;
public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, InputComponentStore componentStore) {
- this.patternInitializer = patternInitializer;
+ this.multicriteriaPatterns = Collections.unmodifiableList(new ArrayList<>(patternInitializer.getMulticriteriaPatterns()));
this.componentStore = componentStore;
}
@@ -48,7 +55,7 @@ public class EnforceIssuesFilter implements IssueFilter {
boolean atLeastOnePatternFullyMatched = false;
IssuePattern matchingPattern = null;
- for (IssuePattern pattern : patternInitializer.getMulticriteriaPatterns()) {
+ for (IssuePattern pattern : multicriteriaPatterns) {
if (pattern.getRulePattern().match(issue.ruleKey().toString())) {
atLeastOneRuleMatched = true;
String relativePath = getRelativePath(issue.componentKey());
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java
index 4d326f7c198..689d4158d8d 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java
@@ -24,17 +24,20 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.WildcardPattern;
+@Immutable
public class IssuePattern {
private final WildcardPattern resourcePattern;
private final WildcardPattern rulePattern;
- private final Set<Integer> lines = new LinkedHashSet<>();
- private final Set<LineRange> lineRanges = new LinkedHashSet<>();
+ private final Set<Integer> lines;
+ private final Set<LineRange> lineRanges;
private final boolean checkLines;
public IssuePattern(String resourcePattern, String rulePattern) {
@@ -45,13 +48,19 @@ public class IssuePattern {
this.resourcePattern = WildcardPattern.create(resourcePattern);
this.rulePattern = WildcardPattern.create(rulePattern);
this.checkLines = !lineRanges.isEmpty();
+ Set<Integer> modifiableLines = new LinkedHashSet<>();
+ Set<LineRange> modifiableLineRanges = new LinkedHashSet<>();
+
for (LineRange range : lineRanges) {
if (range.from() == range.to()) {
- this.lines.add(range.from());
+ modifiableLines.add(range.from());
} else {
- this.lineRanges.add(range);
+ modifiableLineRanges.add(range);
}
}
+
+ this.lines = Collections.unmodifiableSet(modifiableLines);
+ this.lineRanges = Collections.unmodifiableSet(modifiableLineRanges);
}
public WildcardPattern getResourcePattern() {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java
index 4bdf149ec05..df5ce6c6f1d 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java
@@ -23,7 +23,7 @@ import java.util.ArrayList;
import java.util.List;
import javax.annotation.CheckForNull;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.fs.internal.FileMetadata.CharHandler;
+import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
import org.sonar.scanner.issue.ignore.pattern.BlockIssuePattern;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
index e0230681382..3611b6d7ea5 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
@@ -27,7 +27,7 @@ import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.fs.internal.FileMetadata.CharHandler;
+import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
import org.sonar.scanner.issue.ignore.pattern.LineRange;
import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
@@ -57,19 +57,19 @@ public class IssueExclusionsRegexpScanner extends CharHandler {
}
@Override
- protected void handleIgnoreEoL(char c) {
+ public void handleIgnoreEoL(char c) {
sb.append(c);
}
@Override
- protected void newLine() {
+ public void newLine() {
processLine(sb.toString());
sb.setLength(0);
lineIndex++;
}
@Override
- protected void eof() {
+ public void eof() {
processLine(sb.toString());
if (currentMatcher != null && !currentMatcher.hasSecondPattern()) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/ServerIssueRepository.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/ServerIssueRepository.java
index 1d659f99c9c..8671b672c74 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/ServerIssueRepository.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/ServerIssueRepository.java
@@ -21,16 +21,16 @@ package org.sonar.scanner.issue.tracking;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.fs.InputModule;
import org.sonar.api.batch.fs.internal.DefaultInputComponent;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.core.component.ComponentKeys;
import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue;
import org.sonar.scanner.repository.ServerIssuesLoader;
-import org.sonar.scanner.scan.ImmutableProjectReactor;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.storage.Storage;
import org.sonar.scanner.storage.Storages;
@@ -45,21 +45,20 @@ public class ServerIssueRepository {
private final Storages caches;
private Storage<ServerIssue> issuesCache;
private final ServerIssuesLoader previousIssuesLoader;
- private final ImmutableProjectReactor reactor;
- private final InputComponentStore resourceCache;
+ private final InputComponentStore componentStore;
- public ServerIssueRepository(Storages caches, ServerIssuesLoader previousIssuesLoader, ImmutableProjectReactor reactor, InputComponentStore resourceCache) {
+ public ServerIssueRepository(Storages caches, ServerIssuesLoader previousIssuesLoader, InputComponentStore componentStore) {
this.caches = caches;
this.previousIssuesLoader = previousIssuesLoader;
- this.reactor = reactor;
- this.resourceCache = resourceCache;
+ this.componentStore = componentStore;
}
public void load() {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
this.issuesCache = caches.createCache("previousIssues");
caches.registerValueCoder(ServerIssue.class, new ServerIssueValueCoder());
- previousIssuesLoader.load(reactor.getRoot().getKeyWithBranch(), this::store);
+ DefaultInputModule root = (DefaultInputModule) componentStore.root();
+ previousIssuesLoader.load(root.getKeyWithBranch(), this::store);
profiler.stopInfo();
}
@@ -69,10 +68,10 @@ public class ServerIssueRepository {
private void store(ServerIssue issue) {
String moduleKeyWithBranch = issue.getModuleKey();
- ProjectDefinition projectDefinition = reactor.getProjectDefinition(moduleKeyWithBranch);
- if (projectDefinition != null) {
- String componentKeyWithoutBranch = ComponentKeys.createEffectiveKey(projectDefinition.getKey(), issue.hasPath() ? issue.getPath() : null);
- DefaultInputComponent r = (DefaultInputComponent) resourceCache.getByKey(componentKeyWithoutBranch);
+ InputModule module = componentStore.getModule(moduleKeyWithBranch);
+ if (module != null) {
+ String componentKeyWithoutBranch = ComponentKeys.createEffectiveKey(module.key(), issue.hasPath() ? issue.getPath() : null);
+ DefaultInputComponent r = (DefaultInputComponent) componentStore.getByKey(componentKeyWithoutBranch);
if (r != null) {
issuesCache.put(r.batchId(), issue.getKey(), issue);
return;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java
index 46acfff0279..e4e5c81356e 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java
@@ -22,6 +22,7 @@ package org.sonar.scanner.phases;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.scanner.events.BatchStepEvent;
import org.sonar.scanner.events.EventBus;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
@@ -40,9 +41,10 @@ public abstract class AbstractPhaseExecutor {
private final DefaultModuleFileSystem fs;
private final QProfileVerifier profileVerifier;
private final IssueExclusionsLoader issueExclusionsLoader;
+ private final InputModuleHierarchy hierarchy;
public AbstractPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- SensorContext sensorContext, EventBus eventBus, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
+ SensorContext sensorContext, InputModuleHierarchy hierarchy, EventBus eventBus, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
IssueExclusionsLoader issueExclusionsLoader) {
this.postJobsExecutor = postJobsExecutor;
this.initializersExecutor = initializersExecutor;
@@ -53,6 +55,7 @@ public abstract class AbstractPhaseExecutor {
this.fs = fs;
this.profileVerifier = profileVerifier;
this.issueExclusionsLoader = issueExclusionsLoader;
+ this.hierarchy = hierarchy;
}
/**
@@ -76,7 +79,7 @@ public abstract class AbstractPhaseExecutor {
afterSensors();
- if (module.definition().getParent() == null) {
+ if (hierarchy.isRoot(module)) {
executeOnRoot();
postJobsExecutor.execute(sensorContext);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersExecutor.java
index b4d5818fc47..556e6298652 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/InitializersExecutor.java
@@ -19,8 +19,8 @@
*/
package org.sonar.scanner.phases;
-import com.google.common.collect.Lists;
import java.util.Collection;
+
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.Initializer;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
@@ -31,6 +31,8 @@ import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
import org.sonar.scanner.events.EventBus;
+import com.google.common.collect.Lists;
+
public class InitializersExecutor {
private static final Logger LOG = Loggers.get(SensorsExecutor.class);
@@ -52,7 +54,7 @@ public class InitializersExecutor {
LOG.debug("Initializers : {}", StringUtils.join(initializers, " -> "));
}
- Project project = new Project(module.definition());
+ Project project = new Project(module);
for (Initializer initializer : initializers) {
eventBus.fireEvent(new InitializerExecutionEvent(initializer, true));
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java
index 7893e6a0024..e2fd0aea9ff 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java
@@ -22,6 +22,7 @@ package org.sonar.scanner.phases;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.SensorContext;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.scanner.events.BatchStepEvent;
import org.sonar.scanner.events.EventBus;
import org.sonar.scanner.issue.IssueCallback;
@@ -43,8 +44,8 @@ public final class IssuesPhaseExecutor extends AbstractPhaseExecutor {
public IssuesPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, SensorContext sensorContext,
EventBus eventBus, FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
- IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, IssueCallback issueCallback) {
- super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader);
+ IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, IssueCallback issueCallback, InputModuleHierarchy moduleHierarchy) {
+ super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, moduleHierarchy, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader);
this.eventBus = eventBus;
this.issuesReport = jsonReport;
this.localIssueTracking = localIssueTracking;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobsExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobsExecutor.java
index b3b33277f66..d4b42a5f97c 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobsExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PostJobsExecutor.java
@@ -21,6 +21,7 @@ package org.sonar.scanner.phases;
import java.util.ArrayList;
import java.util.Collection;
+
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.PostJob;
import org.sonar.api.batch.ScannerSide;
@@ -58,7 +59,7 @@ public class PostJobsExecutor {
private void execute(SensorContext context, Collection<PostJob> postJobs) {
logPostJobs(postJobs);
- Project project = new Project(module.definition());
+ Project project = new Project(module);
for (PostJob postJob : postJobs) {
LOG.info("Executing post-job {}", ScannerUtils.describe(postJob));
eventBus.fireEvent(new PostJobExecutionEvent(postJob, true));
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java
index d8a5d9fcac8..63868c8e2cb 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/ProjectAnalysisEvent.java
@@ -34,7 +34,7 @@ class ProjectAnalysisEvent extends AbstractPhaseEvent<ProjectAnalysisHandler>
@Override
public Project getProject() {
- return new Project(module.definition());
+ return new Project(module);
}
@Override
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java
index 434c88a96dd..84ff4b4d4bc 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java
@@ -20,6 +20,7 @@
package org.sonar.scanner.phases;
import org.sonar.api.batch.SensorContext;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.scanner.cpd.CpdExecutor;
import org.sonar.scanner.events.BatchStepEvent;
import org.sonar.scanner.events.EventBus;
@@ -38,9 +39,9 @@ public final class PublishPhaseExecutor extends AbstractPhaseExecutor {
private final ScmPublisher scm;
public PublishPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, SensorContext sensorContext,
- EventBus eventBus, ReportPublisher reportPublisher, FileSystemLogger fsLogger, DefaultModuleFileSystem fs,
- QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, CpdExecutor cpdExecutor, ScmPublisher scm) {
- super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader);
+ EventBus eventBus, ReportPublisher reportPublisher, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
+ IssueExclusionsLoader issueExclusionsLoader, CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy) {
+ super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, hierarchy, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader);
this.eventBus = eventBus;
this.reportPublisher = reportPublisher;
this.cpdExecutor = cpdExecutor;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java
index c4b1805d3ba..88158bfb065 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/SensorsExecutor.java
@@ -27,6 +27,7 @@ import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.resources.Project;
import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
import org.sonar.scanner.events.EventBus;
@@ -40,12 +41,12 @@ public class SensorsExecutor {
private final SensorStrategy strategy;
private final boolean isRoot;
- public SensorsExecutor(ScannerExtensionDictionnary selector, DefaultInputModule module, EventBus eventBus, SensorStrategy strategy) {
+ public SensorsExecutor(ScannerExtensionDictionnary selector, DefaultInputModule module, InputModuleHierarchy hierarchy, EventBus eventBus, SensorStrategy strategy) {
this.selector = selector;
this.module = module;
this.eventBus = eventBus;
this.strategy = strategy;
- this.isRoot = module.definition().getParent() == null;
+ this.isRoot = hierarchy.isRoot(module);
}
public void execute(SensorContext context) {
@@ -84,7 +85,7 @@ public class SensorsExecutor {
private void executeSensor(SensorContext context, Sensor sensor) {
eventBus.fireEvent(new SensorExecutionEvent(sensor, true));
- sensor.analyse(new Project(module.definition()), context);
+ sensor.analyse(new Project(module), context);
eventBus.fireEvent(new SensorExecutionEvent(sensor, false));
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/AnalysisContextReportPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/AnalysisContextReportPublisher.java
index 4da1aeda04e..0ff003378b4 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/AnalysisContextReportPublisher.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/AnalysisContextReportPublisher.java
@@ -29,10 +29,12 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.TreeSet;
+
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -56,16 +58,18 @@ public class AnalysisContextReportPublisher {
private final System2 system;
private final ProjectRepositories projectRepos;
private final GlobalConfiguration globalSettings;
+ private final InputModuleHierarchy hierarchy;
private ScannerReportWriter writer;
public AnalysisContextReportPublisher(AnalysisMode mode, ScannerPluginRepository pluginRepo, System2 system,
- ProjectRepositories projectRepos, GlobalConfiguration globalSettings) {
+ ProjectRepositories projectRepos, GlobalConfiguration globalSettings, InputModuleHierarchy hierarchy) {
this.mode = mode;
this.pluginRepo = pluginRepo;
this.system = system;
this.projectRepos = projectRepos;
this.globalSettings = globalSettings;
+ this.hierarchy = hierarchy;
}
public void init(ScannerReportWriter writer) {
@@ -120,15 +124,15 @@ public class AnalysisContextReportPublisher {
}
}
- public void dumpModuleSettings(ProjectDefinition moduleDefinition) {
+ public void dumpModuleSettings(DefaultInputModule module) {
if (mode.isIssues()) {
return;
}
File analysisLog = writer.getFileStructure().analysisLog();
try (BufferedWriter fileWriter = Files.newBufferedWriter(analysisLog.toPath(), StandardCharsets.UTF_8, StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
- Map<String, String> moduleSpecificProps = collectModuleSpecificProps(moduleDefinition);
- fileWriter.append(String.format("Settings for module: %s", moduleDefinition.getKey())).append('\n');
+ Map<String, String> moduleSpecificProps = collectModuleSpecificProps(module);
+ fileWriter.append(String.format("Settings for module: %s", module.key())).append('\n');
for (String prop : new TreeSet<>(moduleSpecificProps.keySet())) {
if (isSystemProp(prop) || isEnvVariable(prop) || !isSqProp(prop)) {
continue;
@@ -147,17 +151,17 @@ public class AnalysisContextReportPublisher {
/**
* Only keep props that are not in parent
*/
- private Map<String, String> collectModuleSpecificProps(ProjectDefinition moduleDefinition) {
+ private Map<String, String> collectModuleSpecificProps(DefaultInputModule module) {
Map<String, String> moduleSpecificProps = new HashMap<>();
- if (projectRepos.moduleExists(moduleDefinition.getKeyWithBranch())) {
- moduleSpecificProps.putAll(projectRepos.settings(moduleDefinition.getKeyWithBranch()));
+ if (projectRepos.moduleExists(module.getKeyWithBranch())) {
+ moduleSpecificProps.putAll(projectRepos.settings(module.getKeyWithBranch()));
}
- ProjectDefinition parent = moduleDefinition.getParent();
+ DefaultInputModule parent = hierarchy.parent(module);
if (parent == null) {
- moduleSpecificProps.putAll(moduleDefinition.properties());
+ moduleSpecificProps.putAll(module.properties());
} else {
Map<String, String> parentProps = parent.properties();
- for (Map.Entry<String, String> entry : moduleDefinition.properties().entrySet()) {
+ for (Map.Entry<String, String> entry : module.properties().entrySet()) {
if (!parentProps.containsKey(entry.getKey()) || !parentProps.get(entry.getKey()).equals(entry.getValue())) {
moduleSpecificProps.put(entry.getKey(), entry.getValue());
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java
index 78fa6bea16c..395b6e4b63b 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java
@@ -22,6 +22,7 @@ package org.sonar.scanner.report;
import java.util.Collection;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
+
import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
index 9afa52f2ca8..871f65ca0f0 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
@@ -25,7 +25,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.config.Configuration;
import org.sonar.scanner.ProjectAnalysisInfo;
-import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
+import org.sonar.scanner.cpd.CpdSettings;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.rule.ModuleQProfiles;
@@ -37,12 +37,15 @@ public class MetadataPublisher implements ReportPublisherStep {
private final ModuleQProfiles qProfiles;
private final ProjectAnalysisInfo projectAnalysisInfo;
private final InputModuleHierarchy moduleHierarchy;
+ private final CpdSettings cpdSettings;
- public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, Configuration settings, ModuleQProfiles qProfiles) {
+ public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, Configuration settings,
+ ModuleQProfiles qProfiles, CpdSettings cpdSettings) {
this.projectAnalysisInfo = projectAnalysisInfo;
this.moduleHierarchy = moduleHierarchy;
this.settings = settings;
this.qProfiles = qProfiles;
+ this.cpdSettings = cpdSettings;
}
@Override
@@ -53,7 +56,7 @@ public class MetadataPublisher implements ReportPublisherStep {
.setAnalysisDate(projectAnalysisInfo.analysisDate().getTime())
// Here we want key without branch
.setProjectKey(rootDef.getKey())
- .setCrossProjectDuplicationActivated(SonarCpdBlockIndex.isCrossProjectDuplicationEnabled(settings))
+ .setCrossProjectDuplicationActivated(cpdSettings.isCrossProjectDuplicationEnabled())
.setRootComponentRef(rootProject.batchId());
settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).ifPresent(builder::setOrganizationKey);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java
index 487c48cd4e5..54fd94ca923 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java
@@ -19,8 +19,8 @@
*/
package org.sonar.scanner.report;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Throwables;
+import static org.sonar.core.util.FileUtils.deleteQuietly;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -31,13 +31,14 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.Map;
+
import javax.annotation.Nullable;
-import okhttp3.HttpUrl;
+
import org.apache.commons.io.FileUtils;
import org.picocontainer.Startable;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.config.Configuration;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.MessageException;
@@ -48,14 +49,16 @@ import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.analysis.DefaultAnalysisMode;
import org.sonar.scanner.bootstrap.ScannerWsClient;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
-import org.sonar.scanner.scan.ImmutableProjectReactor;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.WsCe;
import org.sonarqube.ws.client.HttpException;
import org.sonarqube.ws.client.PostRequest;
import org.sonarqube.ws.client.WsResponse;
-import static org.sonar.core.util.FileUtils.deleteQuietly;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Throwables;
+
+import okhttp3.HttpUrl;
@ScannerSide
public class ReportPublisher implements Startable {
@@ -69,7 +72,7 @@ public class ReportPublisher implements Startable {
private final Configuration settings;
private final ScannerWsClient wsClient;
private final AnalysisContextReportPublisher contextPublisher;
- private final ImmutableProjectReactor projectReactor;
+ private final InputModuleHierarchy moduleHierarchy;
private final DefaultAnalysisMode analysisMode;
private final TempFolder temp;
private final ReportPublisherStep[] publishers;
@@ -79,12 +82,12 @@ public class ReportPublisher implements Startable {
private ScannerReportWriter writer;
public ReportPublisher(Configuration settings, ScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher,
- ImmutableProjectReactor projectReactor, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers) {
+ InputModuleHierarchy moduleHierarchy, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers) {
this.settings = settings;
this.wsClient = wsClient;
this.server = server;
this.contextPublisher = contextPublisher;
- this.projectReactor = projectReactor;
+ this.moduleHierarchy = moduleHierarchy;
this.analysisMode = analysisMode;
this.temp = temp;
this.publishers = publishers;
@@ -92,7 +95,7 @@ public class ReportPublisher implements Startable {
@Override
public void start() {
- reportDir = new File(projectReactor.getRoot().getWorkDir(), "batch-report");
+ reportDir = new File(moduleHierarchy.root().getWorkDir(), "batch-report");
writer = new ScannerReportWriter(reportDir);
contextPublisher.init(writer);
@@ -165,14 +168,13 @@ public class ReportPublisher implements Startable {
String upload(File report) {
LOG.debug("Upload report");
long startTime = System.currentTimeMillis();
- ProjectDefinition projectDefinition = projectReactor.getRoot();
PostRequest.Part filePart = new PostRequest.Part(MediaTypes.ZIP, report);
PostRequest post = new PostRequest("api/ce/submit")
.setMediaType(MediaTypes.PROTOBUF)
.setParam("organization", settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).orElse(null))
- .setParam("projectKey", projectDefinition.getKey())
- .setParam("projectName", projectDefinition.getOriginalName())
- .setParam("projectBranch", projectDefinition.getBranch())
+ .setParam("projectKey", moduleHierarchy.root().key())
+ .setParam("projectName", moduleHierarchy.root().getOriginalName())
+ .setParam("projectBranch", moduleHierarchy.root().getBranch())
.setPart("report", filePart);
WsResponse response;
@@ -201,7 +203,7 @@ public class ReportPublisher implements Startable {
HttpUrl httpUrl = HttpUrl.parse(publicUrl);
Map<String, String> metadata = new LinkedHashMap<>();
- String effectiveKey = projectReactor.getRoot().getKeyWithBranch();
+ String effectiveKey = moduleHierarchy.root().getKeyWithBranch();
settings.get(CoreProperties.PROJECT_ORGANIZATION_PROPERTY).ifPresent(org -> metadata.put("organization", org));
metadata.put("projectKey", effectiveKey);
metadata.put("serverUrl", publicUrl);
@@ -230,7 +232,7 @@ public class ReportPublisher implements Startable {
}
private void dumpMetadata(Map<String, String> metadata) {
- Path file = projectReactor.getRoot().getWorkDir().toPath().resolve(METADATA_DUMP_FILENAME);
+ Path file = moduleHierarchy.root().getWorkDir().toPath().resolve(METADATA_DUMP_FILENAME);
try (Writer output = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
for (Map.Entry<String, String> entry : metadata.entrySet()) {
output.write(entry.getKey());
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ContextPropertiesCache.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ContextPropertiesCache.java
index c6c0015a88e..4c36c0991ad 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ContextPropertiesCache.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ContextPropertiesCache.java
@@ -19,11 +19,12 @@
*/
package org.sonar.scanner.repository;
+import static com.google.common.base.Preconditions.checkArgument;
+
import java.util.HashMap;
import java.util.Map;
-import org.sonar.api.batch.ScannerSide;
-import static com.google.common.base.Preconditions.checkArgument;
+import org.sonar.api.batch.ScannerSide;
@ScannerSide
public class ContextPropertiesCache {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositories.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositories.java
index 6c9921c53a2..ead8f33b909 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositories.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositories.java
@@ -19,30 +19,32 @@
*/
package org.sonar.scanner.repository;
-import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import java.util.Date;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+@Immutable
public class ProjectRepositories {
- private final Table<String, String, String> settingsByModule;
- private final Table<String, String, FileData> fileDataByModuleAndPath;
+ private final ImmutableTable<String, String, String> settingsByModule;
+ private final ImmutableTable<String, String, FileData> fileDataByModuleAndPath;
private final Date lastAnalysisDate;
private final boolean exists;
public ProjectRepositories() {
this.exists = false;
- this.settingsByModule = HashBasedTable.create();
- this.fileDataByModuleAndPath = HashBasedTable.create();
+ this.settingsByModule = new ImmutableTable.Builder<String, String, String>().build();
+ this.fileDataByModuleAndPath = new ImmutableTable.Builder<String, String, FileData>().build();
this.lastAnalysisDate = null;
}
public ProjectRepositories(Table<String, String, String> settingsByModule, Table<String, String, FileData> fileDataByModuleAndPath,
@Nullable Date lastAnalysisDate) {
- this.settingsByModule = settingsByModule;
- this.fileDataByModuleAndPath = fileDataByModuleAndPath;
+ this.settingsByModule = ImmutableTable.copyOf(settingsByModule);
+ this.fileDataByModuleAndPath = ImmutableTable.copyOf(fileDataByModuleAndPath);
this.lastAnalysisDate = lastAnalysisDate;
this.exists = true;
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesRepository.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesRepository.java
index 4af9e6a6e74..8866237e54c 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesRepository.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesRepository.java
@@ -21,7 +21,10 @@ package org.sonar.scanner.repository.language;
import java.util.ArrayList;
import java.util.Collection;
+
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+
import org.picocontainer.Startable;
import org.sonar.api.resources.Languages;
@@ -29,6 +32,7 @@ import org.sonar.api.resources.Languages;
* Languages repository using {@link Languages}
* @since 4.4
*/
+@Immutable
public class DefaultLanguagesRepository implements LanguagesRepository, Startable {
private Languages languages;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/Language.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/Language.java
index 8b90c65f57e..775c895bfdb 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/Language.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/Language.java
@@ -22,6 +22,9 @@ package org.sonar.scanner.repository.language;
import java.util.Arrays;
import java.util.Collection;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
public final class Language {
private final String key;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/LanguagesRepository.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/LanguagesRepository.java
index 626a3361f8f..d6f5046ea66 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/LanguagesRepository.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/LanguagesRepository.java
@@ -20,7 +20,10 @@
package org.sonar.scanner.repository.language;
import java.util.Collection;
+
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.api.batch.ScannerSide;
/**
@@ -28,6 +31,7 @@ import org.sonar.api.batch.ScannerSide;
* @since 4.4
*/
@ScannerSide
+@Immutable
public interface LanguagesRepository {
/**
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ModuleQProfiles.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ModuleQProfiles.java
index 013e22e352e..30d87568514 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ModuleQProfiles.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ModuleQProfiles.java
@@ -19,19 +19,24 @@
*/
package org.sonar.scanner.rule;
+import org.sonar.api.utils.DateUtils;
+
+import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile;
+import org.sonar.api.batch.ScannerSide;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-import javax.annotation.CheckForNull;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.utils.DateUtils;
-import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile;
/**
* Lists the Quality profiles enabled on the current module.
*/
@ScannerSide
+@Immutable
public class ModuleQProfiles {
public static final String SONAR_PROFILE_PROP = "sonar.profile";
@@ -42,11 +47,11 @@ public class ModuleQProfiles {
for (QualityProfile qProfile : profiles) {
map.put(qProfile.getLanguage(),
- new QProfile()
+ new QProfile.Builder()
.setKey(qProfile.getKey())
.setName(qProfile.getName())
.setLanguage(qProfile.getLanguage())
- .setRulesUpdatedAt(DateUtils.parseDateTime(qProfile.getRulesUpdatedAt())));
+ .setRulesUpdatedAt(DateUtils.parseDateTime(qProfile.getRulesUpdatedAt())).build());
}
byLanguage = Collections.unmodifiableMap(map);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfile.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfile.java
index a38f942b929..9568368b992 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfile.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfile.java
@@ -22,49 +22,38 @@ package org.sonar.scanner.rule;
import com.google.common.base.MoreObjects;
import java.util.Date;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
public class QProfile {
+ private final String key;
+ private final String name;
+ private final String language;
+ private final Date rulesUpdatedAt;
- private String key;
- private String name;
- private String language;
- private Date rulesUpdatedAt;
+ public QProfile(String key, String name, String language, Date rulesUpdatedAt) {
+ this.key = key;
+ this.name = name;
+ this.language = language;
+ this.rulesUpdatedAt = rulesUpdatedAt;
+ }
public String getKey() {
return key;
}
- public QProfile setKey(String key) {
- this.key = key;
- return this;
- }
-
public String getName() {
return name;
}
- public QProfile setName(String name) {
- this.name = name;
- return this;
- }
-
public String getLanguage() {
return language;
}
- public QProfile setLanguage(String language) {
- this.language = language;
- return this;
- }
-
public Date getRulesUpdatedAt() {
return rulesUpdatedAt;
}
- public QProfile setRulesUpdatedAt(Date d) {
- this.rulesUpdatedAt = d;
- return this;
- }
-
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -92,4 +81,51 @@ public class QProfile {
.add("rulesUpdatedAt", rulesUpdatedAt)
.toString();
}
+
+ public static class Builder {
+ private String key;
+ private String name;
+ private String language;
+ private Date rulesUpdatedAt;
+
+ public String getKey() {
+ return key;
+ }
+
+ public Builder setKey(String key) {
+ this.key = key;
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Builder setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public Builder setLanguage(String language) {
+ this.language = language;
+ return this;
+ }
+
+ public Date getRulesUpdatedAt() {
+ return rulesUpdatedAt;
+ }
+
+ public Builder setRulesUpdatedAt(Date d) {
+ this.rulesUpdatedAt = d;
+ return this;
+ }
+
+ public QProfile build() {
+ return new QProfile(key, name, language, rulesUpdatedAt);
+ }
+ }
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/RuleFinderCompatibility.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/RuleFinderCompatibility.java
index bd3d822bdec..2acf1e4e8f4 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/RuleFinderCompatibility.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/RuleFinderCompatibility.java
@@ -25,6 +25,8 @@ import java.util.Collections;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.batch.rule.Rules;
@@ -33,6 +35,7 @@ import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RuleQuery;
+@Immutable
public class RuleFinderCompatibility implements RuleFinder {
private final Rules rules;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultInputModuleHierarchy.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultInputModuleHierarchy.java
index ae7f1de06ec..4cf6dcbcab8 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultInputModuleHierarchy.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultInputModuleHierarchy.java
@@ -19,35 +19,68 @@
*/
package org.sonar.scanner.scan;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+
import javax.annotation.CheckForNull;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.api.batch.fs.InputModule;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.scan.filesystem.PathResolver;
+import com.google.common.collect.ImmutableMultimap;
+
+@Immutable
public class DefaultInputModuleHierarchy implements InputModuleHierarchy {
private final PathResolver pathResolver = new PathResolver();
- private DefaultInputModule root;
- private final Map<DefaultInputModule, DefaultInputModule> parents = new HashMap<>();
- private final Multimap<DefaultInputModule, DefaultInputModule> children = HashMultimap.create();
+ private final DefaultInputModule root;
+ private final Map<DefaultInputModule, DefaultInputModule> parents;
+ private final ImmutableMultimap<DefaultInputModule, DefaultInputModule> children;
- public void setRoot(DefaultInputModule root) {
+ public DefaultInputModuleHierarchy(DefaultInputModule parent, DefaultInputModule child) {
+ this(Collections.singletonMap(child, parent));
+ }
+
+ public DefaultInputModuleHierarchy(DefaultInputModule root) {
+ this.children = new ImmutableMultimap.Builder<DefaultInputModule, DefaultInputModule>().build();
+ this.parents = Collections.emptyMap();
this.root = root;
}
- public void index(DefaultInputModule child, DefaultInputModule parent) {
- Preconditions.checkNotNull(child);
- Preconditions.checkNotNull(parent);
- parents.put(child, parent);
- children.put(parent, child);
+ /**
+ * Map of child->parent. Neither the Keys or values can be null.
+ */
+ public DefaultInputModuleHierarchy(Map<DefaultInputModule, DefaultInputModule> parents) {
+ ImmutableMultimap.Builder<DefaultInputModule, DefaultInputModule> childrenBuilder = new ImmutableMultimap.Builder<>();
+
+ for (Map.Entry<DefaultInputModule, DefaultInputModule> e : parents.entrySet()) {
+ childrenBuilder.put(e.getValue(), e.getKey());
+ }
+
+ this.children = childrenBuilder.build();
+ this.parents = Collections.unmodifiableMap(new HashMap<>(parents));
+ this.root = findRoot(parents);
+ }
+
+ private static DefaultInputModule findRoot(Map<DefaultInputModule, DefaultInputModule> parents) {
+ DefaultInputModule r = null;
+ for (DefaultInputModule parent : parents.values()) {
+ if (!parents.containsKey(parent)) {
+ if (r != null && r != parent) {
+ throw new IllegalStateException(String.format("Found two modules without parent: '%s' and '%s'", r.key(), parent.key()));
+ }
+ r = parent;
+ }
+ }
+ if (r == null) {
+ throw new IllegalStateException("Found no root module");
+ }
+ return r;
}
@Override
@@ -78,11 +111,8 @@ public class DefaultInputModuleHierarchy implements InputModuleHierarchy {
return null;
}
DefaultInputModule inputModule = (DefaultInputModule) module;
-
- ProjectDefinition parentDefinition = parent.definition();
- Path parentBaseDir = parentDefinition.getBaseDir().toPath();
- ProjectDefinition moduleDefinition = inputModule.definition();
- Path moduleBaseDir = moduleDefinition.getBaseDir().toPath();
+ Path parentBaseDir = parent.getBaseDir().toPath();
+ Path moduleBaseDir = inputModule.getBaseDir().toPath();
return pathResolver.relativePath(parentBaseDir, moduleBaseDir);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ImmutableProjectReactor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ImmutableProjectReactor.java
deleted file mode 100644
index 6d5df79b123..00000000000
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ImmutableProjectReactor.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * 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 02110-1301, USA.
- */
-package org.sonar.scanner.scan;
-
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-
-/**
- * Immutable copy of project reactor after all modifications have been applied (see {@link ImmutableProjectReactorProvider}).
- */
-@ScannerSide
-public class ImmutableProjectReactor {
-
- private ProjectDefinition root;
- private Map<String, ProjectDefinition> byKey = new LinkedHashMap<>();
-
- public ImmutableProjectReactor(ProjectDefinition root) {
- if (root.getParent() != null) {
- throw new IllegalArgumentException("Not a root project: " + root);
- }
- this.root = root;
- collectProjects(root);
- }
-
- public Collection<ProjectDefinition> getProjects() {
- return byKey.values();
- }
-
- /**
- * Populates list of projects from hierarchy.
- */
- private void collectProjects(ProjectDefinition def) {
- if (byKey.containsKey(def.getKeyWithBranch())) {
- throw new IllegalStateException("Duplicate module key in reactor: " + def.getKeyWithBranch());
- }
- byKey.put(def.getKeyWithBranch(), def);
- for (ProjectDefinition child : def.getSubProjects()) {
- collectProjects(child);
- }
- }
-
- public ProjectDefinition getRoot() {
- return root;
- }
-
- @CheckForNull
- public ProjectDefinition getProjectDefinition(String keyWithBranch) {
- return byKey.get(keyWithBranch);
- }
-}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputModuleHierarchyProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputModuleHierarchyProvider.java
new file mode 100644
index 00000000000..aaa8cf5f54d
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputModuleHierarchyProvider.java
@@ -0,0 +1,65 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * 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 02110-1301, USA.
+ */
+package org.sonar.scanner.scan;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
+
+public class InputModuleHierarchyProvider extends ProviderAdapter {
+
+ private DefaultInputModuleHierarchy hierarchy = null;
+
+ public DefaultInputModuleHierarchy provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator,
+ ProjectReactor projectReactor, BatchIdGenerator batchIdGenerator) {
+ if (hierarchy == null) {
+ // 1 Apply project builders
+ projectBuildersExecutor.execute(projectReactor);
+
+ // 2 Validate final reactor
+ validator.validate(projectReactor);
+
+ // 3 Create modules and the hierarchy
+ DefaultInputModule root = new DefaultInputModule(projectReactor.getRoot(), batchIdGenerator.get());
+ Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, batchIdGenerator, new HashMap<>());
+ if (parents.isEmpty()) {
+ hierarchy = new DefaultInputModuleHierarchy(root);
+ } else {
+ hierarchy = new DefaultInputModuleHierarchy(parents);
+ }
+ }
+ return hierarchy;
+ }
+
+ private static Map<DefaultInputModule, DefaultInputModule> createChildren(DefaultInputModule parent, BatchIdGenerator batchIdGenerator,
+ Map<DefaultInputModule, DefaultInputModule> parents) {
+ for (ProjectDefinition def : parent.definition().getSubProjects()) {
+ DefaultInputModule child = new DefaultInputModule(def, batchIdGenerator.get());
+ parents.put(child, parent);
+ createChildren(child, batchIdGenerator, parents);
+ }
+ return parents;
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.java
index 5558d577ade..110baeb2287 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.java
@@ -20,9 +20,8 @@
package org.sonar.scanner.scan;
import org.picocontainer.Startable;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
/**
@@ -30,36 +29,27 @@ import org.sonar.scanner.scan.filesystem.InputComponentStore;
* project definitions provided by the {@link ImmutableProjectReactor}.
*/
public class ModuleIndexer implements Startable {
- private final ImmutableProjectReactor projectReactor;
private final DefaultComponentTree componentTree;
- private final DefaultInputModuleHierarchy moduleHierarchy;
- private final BatchIdGenerator batchIdGenerator;
+ private final InputModuleHierarchy moduleHierarchy;
private final InputComponentStore componentStore;
- public ModuleIndexer(ImmutableProjectReactor projectReactor, DefaultComponentTree componentTree,
- InputComponentStore componentStore, BatchIdGenerator batchIdGenerator, DefaultInputModuleHierarchy moduleHierarchy) {
- this.projectReactor = projectReactor;
+ public ModuleIndexer(DefaultComponentTree componentTree, InputComponentStore componentStore, InputModuleHierarchy moduleHierarchy) {
this.componentTree = componentTree;
this.componentStore = componentStore;
this.moduleHierarchy = moduleHierarchy;
- this.batchIdGenerator = batchIdGenerator;
}
@Override
public void start() {
- DefaultInputModule root = new DefaultInputModule(projectReactor.getRoot(), batchIdGenerator.get());
- moduleHierarchy.setRoot(root);
- componentStore.put(root);
- createChildren(root);
+ DefaultInputModule root = moduleHierarchy.root();
+ indexChildren(root);
}
- private void createChildren(DefaultInputModule parent) {
- for (ProjectDefinition def : parent.definition().getSubProjects()) {
- DefaultInputModule child = new DefaultInputModule(def, batchIdGenerator.get());
- moduleHierarchy.index(child, parent);
- componentTree.index(child, parent);
- componentStore.put(child);
- createChildren(child);
+ private void indexChildren(DefaultInputModule parent) {
+ for (DefaultInputModule module : moduleHierarchy.children(parent)) {
+ componentTree.index(module, parent);
+ componentStore.put(module);
+ indexChildren(module);
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
index 8305472e8aa..dbb3862d831 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
@@ -95,7 +95,7 @@ public class ModuleScanContainer extends ComponentContainer {
add(
module.definition(),
// still injected by some plugins
- new Project(module.definition()),
+ new Project(module),
module,
MutableModuleSettings.class,
new ModuleSettingsProvider());
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleSettingsProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleSettingsProvider.java
index d17a9c0916f..25db68aad37 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleSettingsProvider.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleSettingsProvider.java
@@ -27,6 +27,7 @@ import java.util.Map;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.report.AnalysisContextReportPublisher;
import org.sonar.scanner.repository.ProjectRepositories;
@@ -35,15 +36,15 @@ public class ModuleSettingsProvider extends ProviderAdapter {
private ModuleSettings projectSettings;
- public ModuleSettings provide(GlobalConfiguration globalSettings, ProjectDefinition moduleDefinition, ProjectRepositories projectRepos,
+ public ModuleSettings provide(GlobalConfiguration globalSettings, DefaultInputModule module, ProjectRepositories projectRepos,
AnalysisMode analysisMode, AnalysisContextReportPublisher contextReportPublisher) {
if (projectSettings == null) {
Map<String, String> settings = new LinkedHashMap<>();
settings.putAll(globalSettings.getProperties());
- settings.putAll(addServerSidePropertiesIfModuleExists(projectRepos, moduleDefinition));
- addScannerSideProperties(settings, moduleDefinition);
- contextReportPublisher.dumpModuleSettings(moduleDefinition);
+ settings.putAll(addServerSidePropertiesIfModuleExists(projectRepos, module.definition()));
+ addScannerSideProperties(settings, module.definition());
+ contextReportPublisher.dumpModuleSettings(module);
projectSettings = new ModuleSettings(globalSettings.getDefinitions(), globalSettings.getEncryption(), analysisMode, settings);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectLock.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectLock.java
index bddf206cc59..d8af158590d 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectLock.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectLock.java
@@ -23,16 +23,17 @@ import java.io.IOException;
import java.nio.channels.OverlappingFileLockException;
import java.nio.file.Files;
import java.nio.file.Path;
+
import org.picocontainer.Startable;
-import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.home.cache.DirectoryLock;
import org.sonar.scanner.bootstrap.Slf4jLogger;
public class ProjectLock implements Startable {
private final DirectoryLock lock;
- public ProjectLock(ProjectReactor projectReactor) {
- Path directory = projectReactor.getRoot().getWorkDir().toPath();
+ public ProjectLock(InputModuleHierarchy moduleHierarchy) {
+ Path directory = moduleHierarchy.root().getWorkDir().toPath();
try {
if (!directory.toFile().exists()) {
Files.createDirectories(directory);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java
index f5f9d0886e7..e69eb31916e 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java
@@ -19,30 +19,28 @@
*/
package org.sonar.scanner.scan;
-import com.google.common.base.Joiner;
import java.util.ArrayList;
import java.util.List;
+
import javax.annotation.Nullable;
+
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
-import org.sonar.api.config.Settings;
import org.sonar.api.utils.MessageException;
import org.sonar.core.component.ComponentKeys;
import org.sonar.scanner.analysis.DefaultAnalysisMode;
+import com.google.common.base.Joiner;
+
/**
* This class aims at validating project reactor
* @since 3.6
*/
public class ProjectReactorValidator {
-
- private static final String SONAR_PHASE = "sonar.phase";
- private final Settings settings;
private final DefaultAnalysisMode mode;
- public ProjectReactorValidator(Settings settings, DefaultAnalysisMode mode) {
- this.settings = settings;
+ public ProjectReactorValidator(DefaultAnalysisMode mode) {
this.mode = mode;
}
@@ -50,7 +48,6 @@ public class ProjectReactorValidator {
String branch = reactor.getRoot().getBranch();
List<String> validationMessages = new ArrayList<>();
- checkDeprecatedProperties(validationMessages);
for (ProjectDefinition moduleDef : reactor.getProjects()) {
if (mode.isIssues()) {
@@ -81,12 +78,6 @@ public class ProjectReactorValidator {
}
}
- private void checkDeprecatedProperties(List<String> validationMessages) {
- if (settings.getString(SONAR_PHASE) != null) {
- validationMessages.add(String.format("Property \"%s\" is deprecated. Please remove it from your configuration.", SONAR_PHASE));
- }
- }
-
private static void validateBranch(List<String> validationMessages, @Nullable String branch) {
if (StringUtils.isNotEmpty(branch) && !ComponentKeys.isValidBranch(branch)) {
validationMessages.add(String.format("\"%s\" is not a valid branch name. "
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
index 9720666b113..458239cc526 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
@@ -19,7 +19,6 @@
*/
package org.sonar.scanner.scan;
-import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.InstantiationStrategy;
@@ -42,6 +41,7 @@ import org.sonar.scanner.bootstrap.ExtensionMatcher;
import org.sonar.scanner.bootstrap.ExtensionUtils;
import org.sonar.scanner.bootstrap.MetricProvider;
import org.sonar.scanner.cpd.CpdExecutor;
+import org.sonar.scanner.cpd.CpdSettings;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
import org.sonar.scanner.deprecated.test.TestPlanBuilder;
import org.sonar.scanner.deprecated.test.TestableBuilder;
@@ -86,12 +86,14 @@ import org.sonar.scanner.rule.DefaultRulesLoader;
import org.sonar.scanner.rule.RulesLoader;
import org.sonar.scanner.rule.RulesProvider;
import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
-import org.sonar.scanner.scan.filesystem.InputComponentStore;
+import org.sonar.scanner.scan.filesystem.InputComponentStoreProvider;
import org.sonar.scanner.scan.measure.DefaultMetricFinder;
import org.sonar.scanner.scan.measure.DeprecatedMetricFinder;
import org.sonar.scanner.scan.measure.MeasureCache;
import org.sonar.scanner.storage.Storages;
+import com.google.common.annotations.VisibleForTesting;
+
public class ProjectScanContainer extends ComponentContainer {
private static final Logger LOG = Loggers.get(ProjectScanContainer.class);
@@ -106,10 +108,10 @@ public class ProjectScanContainer extends ComponentContainer {
@Override
protected void doBeforeStart() {
addBatchComponents();
+ addBatchExtensions();
ProjectLock lock = getComponentByType(ProjectLock.class);
lock.tryLock();
getComponentByType(WorkDirectoryCleaner.class).execute();
- addBatchExtensions();
Settings settings = getComponentByType(Settings.class);
if (settings != null && settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
add(PhasesSumUpTimeProfiler.class);
@@ -126,7 +128,6 @@ public class ProjectScanContainer extends ComponentContainer {
ProjectReactorBuilder.class,
WorkDirectoryCleaner.class,
new MutableProjectReactorProvider(),
- new ImmutableProjectReactorProvider(),
ProjectBuildersExecutor.class,
ProjectLock.class,
EventBus.class,
@@ -145,9 +146,9 @@ public class ProjectScanContainer extends ComponentContainer {
// file system
ModuleIndexer.class,
- InputComponentStore.class,
+ new InputComponentStoreProvider(),
PathResolver.class,
- DefaultInputModuleHierarchy.class,
+ new InputModuleHierarchyProvider(),
DefaultComponentTree.class,
BatchIdGenerator.class,
@@ -197,6 +198,7 @@ public class ProjectScanContainer extends ComponentContainer {
// Cpd
CpdExecutor.class,
+ CpdSettings.class,
SonarCpdBlockIndex.class,
ScanTaskObservers.class);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoryCleaner.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoryCleaner.java
index 607b7bb0397..277b230fd88 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoryCleaner.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoryCleaner.java
@@ -24,15 +24,16 @@ import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Iterator;
-import org.sonar.api.batch.bootstrap.ProjectReactor;
+
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.core.util.FileUtils;
import org.sonar.home.cache.DirectoryLock;
public class WorkDirectoryCleaner {
- private Path workDir;
+ private final Path workDir;
- public WorkDirectoryCleaner(ProjectReactor projectReactor) {
- workDir = projectReactor.getRoot().getWorkDir().toPath();
+ public WorkDirectoryCleaner(InputModuleHierarchy moduleHierarchy) {
+ workDir = moduleHierarchy.root().getWorkDir().toPath();
}
public void execute() {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/BatchIdGenerator.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/BatchIdGenerator.java
index 087f8445ad3..119d8d9bc9f 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/BatchIdGenerator.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/BatchIdGenerator.java
@@ -21,6 +21,9 @@ package org.sonar.scanner.scan.filesystem;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
+
+import javax.annotation.concurrent.ThreadSafe;
+
import org.sonar.api.batch.fs.InputComponent;
/**
@@ -28,6 +31,7 @@ import org.sonar.api.batch.fs.InputComponent;
* The IDs must be unique among all types of components and for all modules in the project.
* The ID should never be 0, as it is sometimes used to indicate invalid components.
*/
+@ThreadSafe
public class BatchIdGenerator implements Supplier<Integer> {
private AtomicInteger nextBatchId = new AtomicInteger(1);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ExclusionFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ExclusionFilters.java
index 0bebac55636..f84bec040cf 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ExclusionFilters.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ExclusionFilters.java
@@ -84,7 +84,7 @@ public class ExclusionFilters {
if (inclusionPatterns.length > 0) {
boolean matchInclusion = false;
for (PathPattern pattern : inclusionPatterns) {
- matchInclusion |= pattern.match(indexedFile);
+ matchInclusion |= pattern.match(indexedFile.absolutePath(), indexedFile.relativePath());
}
if (!matchInclusion) {
return false;
@@ -92,7 +92,7 @@ public class ExclusionFilters {
}
if (exclusionPatterns.length > 0) {
for (PathPattern pattern : exclusionPatterns) {
- if (pattern.match(indexedFile)) {
+ if (pattern.match(indexedFile.absolutePath(), indexedFile.relativePath())) {
return false;
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
index dd8a32e91e5..3af3741e987 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
@@ -157,9 +157,10 @@ public class FileIndexer {
DefaultInputFile inputFile = inputFileBuilder.create(realFile, type, fileSystem.encoding());
if (inputFile != null) {
if (exclusionFilters.accept(inputFile, type) && accept(inputFile)) {
+ String parentRelativePath = getParentRelativePath(fileSystem, inputFile);
synchronized (this) {
fileSystem.add(inputFile);
- indexParentDir(fileSystem, inputFile);
+ indexParentDir(fileSystem, inputFile, parentRelativePath);
progress.markAsIndexed(inputFile);
}
LOG.debug("'{}' indexed {}with language '{}'", inputFile.relativePath(), type == Type.TEST ? "as test " : "", inputFile.language());
@@ -171,16 +172,19 @@ public class FileIndexer {
return null;
}
- private void indexParentDir(DefaultModuleFileSystem fileSystem, InputFile inputFile) {
+ private static String getParentRelativePath(DefaultModuleFileSystem fileSystem, InputFile inputFile) {
Path parentDir = inputFile.path().getParent();
String relativePath = new PathResolver().relativePath(fileSystem.baseDirPath(), parentDir);
if (relativePath == null) {
throw new IllegalStateException("Failed to compute relative path of file: " + inputFile);
}
+ return relativePath;
+ }
- DefaultInputDir inputDir = (DefaultInputDir) componentStore.getDir(module.key(), relativePath);
+ private void indexParentDir(DefaultModuleFileSystem fileSystem, InputFile inputFile, String parentRelativePath) {
+ DefaultInputDir inputDir = (DefaultInputDir) componentStore.getDir(module.key(), parentRelativePath);
if (inputDir == null) {
- inputDir = new DefaultInputDir(fileSystem.moduleKey(), relativePath, batchIdGenerator.get());
+ inputDir = new DefaultInputDir(fileSystem.moduleKey(), parentRelativePath, batchIdGenerator.get());
inputDir.setModuleBaseDir(fileSystem.baseDirPath());
fileSystem.add(inputDir);
componentTree.index(inputDir, module);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java
index ff92762a405..6726cba970b 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java
@@ -58,14 +58,17 @@ public class InputComponentStore {
private final Table<String, String, InputFile> inputFileCache = TreeBasedTable.create();
private final Map<String, InputDir> globalInputDirCache = new HashMap<>();
private final Table<String, String, InputDir> inputDirCache = TreeBasedTable.create();
+ // indexed by key with branch
private final Map<String, InputModule> inputModuleCache = new HashMap<>();
private final Map<String, InputComponent> inputComponents = new HashMap<>();
private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create();
private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
- private InputModule root;
+ private final InputModule root;
- public InputComponentStore(PathResolver pathResolver) {
+ public InputComponentStore(PathResolver pathResolver, DefaultInputModule root) {
this.pathResolver = pathResolver;
+ this.root = root;
+ this.put(root);
}
public Collection<InputComponent> all() {
@@ -90,7 +93,6 @@ public class InputComponentStore {
return inputComponents.get(key);
}
- @CheckForNull
public InputModule root() {
return root;
}
@@ -157,7 +159,7 @@ public class InputComponentStore {
}
private Path getProjectBaseDir() {
- return ((DefaultInputModule) root).definition().getBaseDir().toPath();
+ return ((DefaultInputModule) root).getBaseDir().toPath();
}
@CheckForNull
@@ -181,22 +183,18 @@ public class InputComponentStore {
}
@CheckForNull
- public InputModule getModule(String moduleKey) {
- return inputModuleCache.get(moduleKey);
+ public InputModule getModule(String moduleKeyWithBranch) {
+ return inputModuleCache.get(moduleKeyWithBranch);
}
public void put(DefaultInputModule inputModule) {
String key = inputModule.key();
+ String keyWithBranch = inputModule.getKeyWithBranch();
+ Preconditions.checkNotNull(inputModule);
Preconditions.checkState(!inputComponents.containsKey(key), "Module '%s' already indexed", key);
- Preconditions.checkState(!inputModuleCache.containsKey(key), "Module '%s' already indexed", key);
+ Preconditions.checkState(!inputModuleCache.containsKey(keyWithBranch), "Module '%s' already indexed", keyWithBranch);
inputComponents.put(key, inputModule);
- inputModuleCache.put(key, inputModule);
- if (inputModule.definition().getParent() == null) {
- if (root != null) {
- throw new IllegalStateException("Root module already indexed: '" + root.key() + "', '" + key + "'");
- }
- root = inputModule;
- }
+ inputModuleCache.put(keyWithBranch, inputModule);
}
public Iterable<InputFile> getFilesByName(String filename) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ImmutableProjectReactorProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStoreProvider.java
index d3111db3a46..65e78e623e6 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ImmutableProjectReactorProvider.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStoreProvider.java
@@ -17,25 +17,19 @@
* 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.scanner.scan;
+package org.sonar.scanner.scan.filesystem;
import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.scan.filesystem.PathResolver;
-public class ImmutableProjectReactorProvider extends ProviderAdapter {
+public class InputComponentStoreProvider extends ProviderAdapter {
+ private InputComponentStore store;
- private ImmutableProjectReactor singleton;
-
- public ImmutableProjectReactor provide(ProjectReactor reactor, ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator) {
- if (singleton == null) {
- // 1 Apply project builders
- projectBuildersExecutor.execute(reactor);
-
- // 2 Validate final reactor
- validator.validate(reactor);
-
- singleton = new ImmutableProjectReactor(reactor.getRoot());
+ public InputComponentStore provide(PathResolver pathResolver, InputModuleHierarchy hierarchy) {
+ if (store == null) {
+ store = new InputComponentStore(pathResolver, hierarchy.root());
}
- return singleton;
+ return store;
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java
index c44e24f4942..fe8d125a5e9 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java
@@ -60,14 +60,13 @@ public class InputFileBuilder {
LOG.warn("File '{}' is ignored. It is not located in module basedir '{}'.", file.toAbsolutePath(), moduleBaseDir);
return null;
}
- DefaultIndexedFile indexedFile = new DefaultIndexedFile(moduleKey, moduleBaseDir, relativePath, type, idGenerator.get());
- String language = langDetection.language(indexedFile);
+ String language = langDetection.language(file.toAbsolutePath().normalize().toString(), relativePath);
if (language == null && langDetection.forcedLanguage() != null) {
LOG.warn("File '{}' is ignored because it doesn't belong to the forced language '{}'", file.toAbsolutePath(), langDetection.forcedLanguage());
return null;
}
- indexedFile.setLanguage(language);
+ DefaultIndexedFile indexedFile = new DefaultIndexedFile(moduleKey, moduleBaseDir, relativePath, type, language, idGenerator.get());
DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(f, defaultEncoding));
if (language != null) {
inputFile.setPublish(true);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/LanguageDetection.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/LanguageDetection.java
index 828a8403655..8267e4509c9 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/LanguageDetection.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/LanguageDetection.java
@@ -19,29 +19,34 @@
*/
package org.sonar.scanner.scan.filesystem;
-import com.google.common.base.Joiner;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.ThreadSafe;
+
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.batch.fs.internal.PathPattern;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.repository.language.Language;
import org.sonar.scanner.repository.language.LanguagesRepository;
+import com.google.common.base.Joiner;
+
/**
* Detect language of a source file based on its suffix and configured patterns.
*/
@ScannerSide
+@ThreadSafe
public class LanguageDetection {
private static final Logger LOG = LoggerFactory.getLogger(LanguageDetection.class);
@@ -49,16 +54,17 @@ public class LanguageDetection {
/**
* Lower-case extension -> languages
*/
- private final Map<String, PathPattern[]> patternsByLanguage = new LinkedHashMap<>();
- private final List<String> languagesToConsider = new ArrayList<>();
+ private final Map<String, PathPattern[]> patternsByLanguage;
+ private final List<String> languagesToConsider;
private final String forcedLanguage;
public LanguageDetection(Configuration settings, LanguagesRepository languages) {
+ Map<String, PathPattern[]> patternsByLanguageBuilder = new LinkedHashMap<>();
for (Language language : languages.all()) {
String[] filePatterns = settings.getStringArray(getFileLangPatternPropKey(language.key()));
PathPattern[] pathPatterns = PathPattern.create(filePatterns);
if (pathPatterns.length > 0) {
- patternsByLanguage.put(language.key(), pathPatterns);
+ patternsByLanguageBuilder.put(language.key(), pathPatterns);
} else {
// If no custom language pattern is defined then fallback to suffixes declared by language
String[] patterns = language.fileSuffixes().toArray(new String[language.fileSuffixes().size()]);
@@ -68,22 +74,24 @@ public class LanguageDetection {
patterns[i] = new StringBuilder().append("**/*.").append(extension).toString();
}
PathPattern[] defaultLanguagePatterns = PathPattern.create(patterns);
- patternsByLanguage.put(language.key(), defaultLanguagePatterns);
- LOG.debug("Declared extensions of language {} were converted to {}", language, getDetails(language.key()));
+ patternsByLanguageBuilder.put(language.key(), defaultLanguagePatterns);
+ LOG.debug("Declared extensions of language {} were converted to {}", language, getDetails(language.key(), defaultLanguagePatterns));
}
}
forcedLanguage = StringUtils.defaultIfBlank(settings.get(CoreProperties.PROJECT_LANGUAGE_PROPERTY).orElse(null), null);
// First try with lang patterns
if (forcedLanguage != null) {
- if (!patternsByLanguage.containsKey(forcedLanguage)) {
+ if (!patternsByLanguageBuilder.containsKey(forcedLanguage)) {
throw MessageException.of("You must install a plugin that supports the language '" + forcedLanguage + "'");
}
LOG.info("Language is forced to {}", forcedLanguage);
- languagesToConsider.add(forcedLanguage);
+ languagesToConsider = Collections.singletonList(forcedLanguage);
} else {
- languagesToConsider.addAll(patternsByLanguage.keySet());
+ languagesToConsider = Collections.unmodifiableList(new ArrayList<>(patternsByLanguageBuilder.keySet()));
}
+
+ patternsByLanguage = Collections.unmodifiableMap(patternsByLanguageBuilder);
}
public String forcedLanguage() {
@@ -95,16 +103,16 @@ public class LanguageDetection {
}
@CheckForNull
- String language(DefaultIndexedFile inputFile) {
+ String language(String absolutePath, String relativePath) {
String detectedLanguage = null;
for (String languageKey : languagesToConsider) {
- if (isCandidateForLanguage(inputFile, languageKey)) {
+ if (isCandidateForLanguage(absolutePath, relativePath, languageKey)) {
if (detectedLanguage == null) {
detectedLanguage = languageKey;
} else {
// Language was already forced by another pattern
throw MessageException.of(MessageFormat.format("Language of file ''{0}'' can not be decided as the file matches patterns of both {1} and {2}",
- inputFile.relativePath(), getDetails(detectedLanguage), getDetails(languageKey)));
+ relativePath, getDetails(detectedLanguage), getDetails(languageKey)));
}
}
}
@@ -120,11 +128,11 @@ public class LanguageDetection {
return null;
}
- private boolean isCandidateForLanguage(DefaultIndexedFile inputFile, String languageKey) {
+ private boolean isCandidateForLanguage(String absolutePath, String relativePath, String languageKey) {
PathPattern[] patterns = patternsByLanguage.get(languageKey);
if (patterns != null) {
for (PathPattern pathPattern : patterns) {
- if (pathPattern.match(inputFile, false)) {
+ if (pathPattern.match(absolutePath, relativePath, false)) {
return true;
}
}
@@ -137,7 +145,11 @@ public class LanguageDetection {
}
private String getDetails(String detectedLanguage) {
- return getFileLangPatternPropKey(detectedLanguage) + " : " + Joiner.on(",").join(patternsByLanguage.get(detectedLanguage));
+ return getDetails(detectedLanguage, patternsByLanguage.get(detectedLanguage));
+ }
+
+ private static String getDetails(String detectedLanguage, PathPattern[] patterns) {
+ return getFileLangPatternPropKey(detectedLanguage) + " : " + Joiner.on(",").join(patterns);
}
static String sanitizeExtension(String suffix) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializer.java
index 2c5c9e54e8d..f13b39b5325 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializer.java
@@ -22,6 +22,7 @@ package org.sonar.scanner.scan.filesystem;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+
import org.apache.commons.io.FileUtils;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java
index 851332f663d..ac11c11d3b8 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java
@@ -19,11 +19,14 @@
*/
package org.sonar.scanner.scan.filesystem;
+import javax.annotation.concurrent.Immutable;
+
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.scanner.repository.FileData;
import org.sonar.scanner.repository.ProjectRepositories;
+@Immutable
class StatusDetection {
private final ProjectRepositories projectSettings;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DefaultMetricFinder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DefaultMetricFinder.java
index 00d484ef598..c6655b7d570 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DefaultMetricFinder.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/DefaultMetricFinder.java
@@ -22,21 +22,28 @@ package org.sonar.scanner.scan.measure;
import com.google.common.collect.Lists;
import java.io.Serializable;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+
+import javax.annotation.concurrent.ThreadSafe;
+
import org.sonar.api.batch.measure.Metric;
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.scanner.repository.MetricsRepository;
+@ThreadSafe
public class DefaultMetricFinder implements MetricFinder {
- private Map<String, Metric<Serializable>> metricsByKey = new LinkedHashMap<>();
+ private Map<String, Metric<Serializable>> metricsByKey;
public DefaultMetricFinder(MetricsRepository metricsRepository) {
+ Map<String, Metric<Serializable>> metrics = new LinkedHashMap<>();
for (org.sonar.api.measures.Metric metric : metricsRepository.metrics()) {
- metricsByKey.put(metric.key(), new org.sonar.api.measures.Metric.Builder(metric.key(), metric.key(), metric.getType()).create());
+ metrics.put(metric.key(), new org.sonar.api.measures.Metric.Builder(metric.key(), metric.key(), metric.getType()).create());
}
+ metricsByKey = Collections.unmodifiableMap(metrics);
}
@Override
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/report/RuleNameProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/report/RuleNameProvider.java
index eaaf9b00b0e..46531e99c40 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/report/RuleNameProvider.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/report/RuleNameProvider.java
@@ -20,6 +20,8 @@
package org.sonar.scanner.scan.report;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+
import org.apache.commons.lang.StringEscapeUtils;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.rule.Rule;
@@ -27,6 +29,7 @@ import org.sonar.api.batch.rule.Rules;
import org.sonar.api.rule.RuleKey;
@ScannerSide
+@Immutable
public class RuleNameProvider {
private Rules rules;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmConfiguration.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmConfiguration.java
index 68c75b647a6..73f29557bc0 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmConfiguration.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmConfiguration.java
@@ -19,9 +19,9 @@
*/
package org.sonar.scanner.scm;
-import com.google.common.base.Joiner;
import java.util.LinkedHashMap;
import java.util.Map;
+
import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.CoreProperties;
@@ -31,11 +31,13 @@ import org.sonar.api.PropertyType;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.scan.ImmutableProjectReactor;
+
+import com.google.common.base.Joiner;
@Properties({
@Property(
@@ -56,15 +58,15 @@ public final class ScmConfiguration implements Startable {
public static final String FORCE_RELOAD_KEY = "sonar.scm.forceReloadAll";
- private final ImmutableProjectReactor projectReactor;
private final Configuration settings;
private final Map<String, ScmProvider> providerPerKey = new LinkedHashMap<>();
private final AnalysisMode analysisMode;
+ private final InputModuleHierarchy moduleHierarchy;
private ScmProvider provider;
- public ScmConfiguration(ImmutableProjectReactor projectReactor, AnalysisMode analysisMode, Configuration settings, ScmProvider... providers) {
- this.projectReactor = projectReactor;
+ public ScmConfiguration(InputModuleHierarchy moduleHierarchy, AnalysisMode analysisMode, Configuration settings, ScmProvider... providers) {
+ this.moduleHierarchy = moduleHierarchy;
this.analysisMode = analysisMode;
this.settings = settings;
for (ScmProvider scmProvider : providers) {
@@ -72,8 +74,8 @@ public final class ScmConfiguration implements Startable {
}
}
- public ScmConfiguration(ImmutableProjectReactor projectReactor, AnalysisMode analysisMode, Configuration settings) {
- this(projectReactor, analysisMode, settings, new ScmProvider[0]);
+ public ScmConfiguration(InputModuleHierarchy moduleHierarchy, AnalysisMode analysisMode, Configuration settings) {
+ this(moduleHierarchy, analysisMode, settings, new ScmProvider[0]);
}
@Override
@@ -121,7 +123,7 @@ public final class ScmConfiguration implements Startable {
private void autodetection() {
for (ScmProvider installedProvider : providerPerKey.values()) {
- if (installedProvider.supports(projectReactor.getRoot().getBaseDir())) {
+ if (installedProvider.supports(moduleHierarchy.root().getBaseDir())) {
if (this.provider == null) {
this.provider = installedProvider;
} else {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java
index 9467d96829a..1889bbaab94 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorContext.java
@@ -20,6 +20,9 @@
package org.sonar.scanner.sensor;
import java.io.Serializable;
+
+import javax.annotation.concurrent.ThreadSafe;
+
import org.sonar.api.SonarRuntime;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.fs.FileSystem;
@@ -50,6 +53,7 @@ import org.sonar.scanner.sensor.noop.NoOpNewCpdTokens;
import org.sonar.scanner.sensor.noop.NoOpNewHighlighting;
import org.sonar.scanner.sensor.noop.NoOpNewSymbolTable;
+@ThreadSafe
public class DefaultSensorContext implements SensorContext {
private static final NoOpNewHighlighting NO_OP_NEW_HIGHLIGHTING = new NoOpNewHighlighting();
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java
index ac966c2a855..c6fc08c8ce4 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java
@@ -19,52 +19,6 @@
*/
package org.sonar.scanner.sensor;
-import com.google.common.annotations.VisibleForTesting;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.sonar.api.batch.fs.InputComponent;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.measure.Metric;
-import org.sonar.api.batch.measure.MetricFinder;
-import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage;
-import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens;
-import org.sonar.api.batch.sensor.error.AnalysisError;
-import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.issue.Issue;
-import org.sonar.api.batch.sensor.measure.Measure;
-import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
-import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.metric.ScannerMetrics;
-import org.sonar.duplications.block.Block;
-import org.sonar.duplications.internal.pmd.PmdBlockChunker;
-import org.sonar.scanner.cpd.deprecated.DefaultCpdBlockIndexer;
-import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.issue.ModuleIssues;
-import org.sonar.scanner.protocol.output.FileStructure;
-import org.sonar.scanner.protocol.output.ScannerReport;
-import org.sonar.scanner.protocol.output.ScannerReportWriter;
-import org.sonar.scanner.report.ReportPublisher;
-import org.sonar.scanner.report.ScannerReportUtils;
-import org.sonar.scanner.repository.ContextPropertiesCache;
-import org.sonar.scanner.scan.measure.MeasureCache;
-import org.sonar.scanner.sensor.coverage.CoverageExclusions;
-
import static java.util.stream.Collectors.toList;
import static org.sonar.api.measures.CoreMetrics.BRANCH_COVERAGE;
import static org.sonar.api.measures.CoreMetrics.COMMENTED_OUT_CODE_LINES_KEY;
@@ -112,6 +66,54 @@ import static org.sonar.api.measures.CoreMetrics.TEST_SUCCESS_DENSITY_KEY;
import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS;
import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.measure.Metric;
+import org.sonar.api.batch.measure.MetricFinder;
+import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage;
+import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens;
+import org.sonar.api.batch.sensor.error.AnalysisError;
+import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.measure.Measure;
+import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
+import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.metric.ScannerMetrics;
+import org.sonar.duplications.block.Block;
+import org.sonar.duplications.internal.pmd.PmdBlockChunker;
+import org.sonar.scanner.cpd.deprecated.DefaultCpdBlockIndexer;
+import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
+import org.sonar.scanner.issue.ModuleIssues;
+import org.sonar.scanner.protocol.output.FileStructure;
+import org.sonar.scanner.protocol.output.ScannerReport;
+import org.sonar.scanner.protocol.output.ScannerReportWriter;
+import org.sonar.scanner.report.ReportPublisher;
+import org.sonar.scanner.report.ScannerReportUtils;
+import org.sonar.scanner.repository.ContextPropertiesCache;
+import org.sonar.scanner.scan.measure.MeasureCache;
+import org.sonar.scanner.sensor.coverage.CoverageExclusions;
+
+import com.google.common.annotations.VisibleForTesting;
+
public class DefaultSensorStorage implements SensorStorage {
private static final Logger LOG = Loggers.get(DefaultSensorStorage.class);
@@ -151,12 +153,10 @@ public class DefaultSensorStorage implements SensorStorage {
private final Map<Metric<?>, Metric<?>> deprecatedCoverageMetricMapping = new HashMap<>();
private final Set<Metric<?>> coverageMetrics = new HashSet<>();
private final Set<Metric<?>> byLineMetrics = new HashSet<>();
- private Set<String> alreadyLogged = new HashSet<>();
+ private final Set<String> alreadyLogged = new HashSet<>();
- public DefaultSensorStorage(MetricFinder metricFinder, ModuleIssues moduleIssues,
- Configuration settings,
- CoverageExclusions coverageExclusions, ReportPublisher reportPublisher,
- MeasureCache measureCache, SonarCpdBlockIndex index,
+ public DefaultSensorStorage(MetricFinder metricFinder, ModuleIssues moduleIssues, Configuration settings, CoverageExclusions coverageExclusions,
+ ReportPublisher reportPublisher, MeasureCache measureCache, SonarCpdBlockIndex index,
ContextPropertiesCache contextPropertiesCache, ScannerMetrics scannerMetrics) {
this.metricFinder = metricFinder;
this.moduleIssues = moduleIssues;
@@ -210,10 +210,12 @@ public class DefaultSensorStorage implements SensorStorage {
saveMeasure(newMeasure.inputComponent(), (DefaultMeasure<?>) newMeasure);
}
+ /**
+ * Thread safe
+ */
private void logOnce(String metricKey, String msg, Object... params) {
- if (!alreadyLogged.contains(metricKey)) {
+ if (alreadyLogged.add(metricKey)) {
LOG.warn(msg, params);
- alreadyLogged.add(metricKey);
}
}
@@ -313,11 +315,11 @@ public class DefaultSensorStorage implements SensorStorage {
}
}
- public boolean isDeprecatedMetric(String metricKey) {
+ public static boolean isDeprecatedMetric(String metricKey) {
return DEPRECATED_METRICS_KEYS.contains(metricKey);
}
- public boolean isPlatformMetric(String metricKey) {
+ public static boolean isPlatformMetric(String metricKey) {
return PLATFORM_METRICS_KEYS.contains(metricKey);
}
@@ -325,7 +327,7 @@ public class DefaultSensorStorage implements SensorStorage {
return this.byLineMetrics.contains(metric);
}
- public void validateCoverageMeasure(String value, InputFile inputFile) {
+ public static void validateCoverageMeasure(String value, InputFile inputFile) {
Map<Integer, Integer> m = KeyValueFormat.parseIntInt(value);
validatePositiveLine(m, inputFile.absolutePath());
validateMaxLine(m, inputFile);
@@ -349,6 +351,9 @@ public class DefaultSensorStorage implements SensorStorage {
}
}
+ /**
+ * Thread safe assuming that each issues for each file are only written once.
+ */
@Override
public void store(Issue issue) {
if (issue.primaryLocation().inputComponent() instanceof DefaultInputFile) {
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/coverage/CoverageExclusions.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/coverage/CoverageExclusions.java
index 490f067d764..5af99184414 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/coverage/CoverageExclusions.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/coverage/CoverageExclusions.java
@@ -19,11 +19,11 @@
*/
package org.sonar.scanner.sensor.coverage;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
import java.util.Collection;
import java.util.Iterator;
+
+import javax.annotation.concurrent.Immutable;
+
import org.picocontainer.Startable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,20 +32,26 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.WildcardPattern;
-public class CoverageExclusions implements Startable {
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+@Immutable
+public class CoverageExclusions implements Startable {
private static final Logger LOG = LoggerFactory.getLogger(CoverageExclusions.class);
- private final Configuration settings;
private Collection<WildcardPattern> exclusionPatterns;
public CoverageExclusions(Configuration settings) {
- this.settings = settings;
+ Builder<WildcardPattern> builder = ImmutableList.builder();
+ for (String pattern : settings.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY)) {
+ builder.add(WildcardPattern.create(pattern));
+ }
+ exclusionPatterns = builder.build();
}
@Override
public void start() {
- initPatterns();
+ log("Excluded sources for coverage: ", exclusionPatterns);
}
@Override
@@ -62,16 +68,6 @@ public class CoverageExclusions implements Startable {
return found;
}
- @VisibleForTesting
- final void initPatterns() {
- Builder<WildcardPattern> builder = ImmutableList.builder();
- for (String pattern : settings.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY)) {
- builder.add(WildcardPattern.create(pattern));
- }
- exclusionPatterns = builder.build();
- log("Excluded sources for coverage: ", exclusionPatterns);
- }
-
private static void log(String title, Collection<WildcardPattern> patterns) {
if (!patterns.isEmpty()) {
LOG.info(title);
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java
index 8e2cb47094e..a5128b5baf3 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java
@@ -19,12 +19,12 @@
*/
package org.sonar.scanner.storage;
-import com.google.common.collect.Sets;
import com.persistit.Exchange;
import com.persistit.Key;
import com.persistit.KeyFilter;
import com.persistit.exception.PersistitException;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.CheckForNull;
@@ -242,7 +242,7 @@ public class Storage<V> {
@SuppressWarnings("rawtypes")
public Set keySet(Object key) {
try {
- Set<Object> keys = Sets.newLinkedHashSet();
+ Set<Object> keys = new LinkedHashSet<>();
exchange.clear();
Exchange iteratorExchange = new Exchange(exchange);
iteratorExchange.append(key);
@@ -259,7 +259,7 @@ public class Storage<V> {
@SuppressWarnings("rawtypes")
public Set keySet(Object firstKey, Object secondKey) {
try {
- Set<Object> keys = Sets.newLinkedHashSet();
+ Set<Object> keys = new LinkedHashSet<>();
exchange.clear();
Exchange iteratorExchange = new Exchange(exchange);
iteratorExchange.append(firstKey);
@@ -281,7 +281,7 @@ public class Storage<V> {
*/
public Set<Object> keySet() {
try {
- Set<Object> keys = Sets.newLinkedHashSet();
+ Set<Object> keys = new LinkedHashSet<>();
exchange.clear();
Exchange iteratorExchange = new Exchange(exchange);
iteratorExchange.append(Key.BEFORE);