aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/LineMeasureSensor.java4
-rw-r--r--sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java4
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/SonarRuntime.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectBuilder.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectDefinition.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectReactor.java5
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/internal/ProjectBuilderContext.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtRemediationFunction.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java24
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java97
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java232
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/InputModuleHierarchy.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java7
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPattern.java28
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPatternPredicate.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java14
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/CharHandler.java35
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/FileHashComputer.java85
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/IntArrayList.java (renamed from sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/IntArrayList.java)7
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineCounter.java83
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineHashComputer.java82
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineOffsetCounter.java60
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/package-info.java24
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/measure/MetricFinder.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRule.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRules.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/RuleParam.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rules.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultActiveRules.java27
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRules.java5
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java5
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilter.java7
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilterChain.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/WildcardPattern.java14
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java36
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/PathPatternTest.java40
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/charhandler/IntArrayListTest.java (renamed from sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/IntArrayListTest.java)3
-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
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/AnalysisTempFolderProviderTest.java25
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java41
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdSettingsTest.java63
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/index/DefaultIndexTest.java16
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java7
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/tracking/SourceHashHolderTest.java23
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java1
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/SensorsExecutorTest.java30
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java8
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/profiling/PhasesSumUpTimeProfilerTest.java3
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/report/AnalysisContextReportPublisherTest.java34
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java5
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java3
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java46
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java51
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java5
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileTest.java15
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java4
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/RulesProfileProviderTest.java6
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/DefaultInputModuleHierarchyTest.java50
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java63
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectLockTest.java23
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java30
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoryCleanerTest.java27
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ExclusionFiltersTest.java26
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java23
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/LanguageDetectionTest.java69
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializerTest.java7
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java5
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java20
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/coverage/CoverageExclusionsTest.java5
-rw-r--r--sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java3
-rw-r--r--sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java4
140 files changed, 1720 insertions, 1123 deletions
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/LineMeasureSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/LineMeasureSensor.java
index fb8f267eca2..7d4c2bc0273 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/LineMeasureSensor.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/LineMeasureSensor.java
@@ -26,7 +26,6 @@ import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
@@ -46,13 +45,10 @@ public class LineMeasureSensor implements Sensor {
private static final String MEASURES_EXTENSION = ".linemeasures";
- private MetricFinder metricFinder;
-
private FileLinesContextFactory contextFactory;
public LineMeasureSensor(FileLinesContextFactory contextFactory) {
this.contextFactory = contextFactory;
- this.metricFinder = metricFinder;
}
private void processFileMeasures(InputFile inputFile, SensorContext context) {
diff --git a/sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java b/sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java
index 6406336c580..3052cefcffb 100644
--- a/sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java
+++ b/sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java
@@ -24,6 +24,9 @@ import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
+
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.measures.Metric;
@@ -70,6 +73,7 @@ import static org.sonar.core.util.stream.MoreCollectors.toSet;
* <p/>
* Scanners should not send other metrics, and the Compute Engine should not allow other metrics.
*/
+@Immutable
@ComputeEngineSide
@ScannerSide
public class ScannerMetrics {
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java b/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java
index f992b942982..4438e197abe 100644
--- a/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java
+++ b/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java
@@ -21,6 +21,9 @@ package org.sonar.duplications.internal.pmd;
import java.util.ArrayList;
import java.util.List;
+
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.ByteArray;
@@ -29,6 +32,7 @@ import org.sonar.duplications.block.ByteArray;
* works with {@link TokensLine},
* sets {@link Block#getStartUnit() startUnit} and {@link Block#getEndUnit() endUnit} - indexes of first and last token for this block.
*/
+@Immutable
public class PmdBlockChunker {
private static final long PRIME_BASE = 31;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/SonarRuntime.java b/sonar-plugin-api/src/main/java/org/sonar/api/SonarRuntime.java
index bea756e4bc2..de0cfa41cee 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/SonarRuntime.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/SonarRuntime.java
@@ -19,6 +19,8 @@
*/
package org.sonar.api;
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
@@ -141,6 +143,7 @@ import org.sonarsource.api.sonarlint.SonarLintSide;
@ServerSide
@ComputeEngineSide
@SonarLintSide
+@Immutable
public interface SonarRuntime {
/**
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectBuilder.java
index eac17aefa31..7d557241ee0 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectBuilder.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectBuilder.java
@@ -33,17 +33,20 @@ import org.sonar.api.batch.ScannerSide;
* <li>Change project metadata like description or source directories.</li>
* </ul>
*
+ * @deprecated since 6.5. It won't be possible to manipulate the project's structure.
* @since 2.9
*/
@ScannerSide
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
@ExtensionPoint
+@Deprecated
public abstract class ProjectBuilder {
/**
* Plugins can use the implementation {@link org.sonar.api.batch.bootstrap.internal.ProjectBuilderContext}
* for their unit tests.
*/
+ @Deprecated
public interface Context {
ProjectReactor projectReactor();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectDefinition.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectDefinition.java
index 19cc04bdaaf..c3c75506131 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectDefinition.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectDefinition.java
@@ -36,6 +36,8 @@ import org.sonar.api.CoreProperties;
* {@link org.sonar.api.batch.bootstrap.ProjectBuilder extension point} and must not be used
* by other standard extensions.
*
+ * Since 6.5, plugins should no longer manipulate the project's structure.
+ *
* @since 2.9
*/
public class ProjectDefinition {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectReactor.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectReactor.java
index 46ea9aba68a..8aba5c679a2 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectReactor.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectReactor.java
@@ -26,8 +26,11 @@ import java.util.List;
/**
* Mutable project definitions that can be modified by {@link ProjectBuilder} extensions.
+ *
+ * @deprecated since 6.5 plugins should no longer modify the project's structure
* @since 2.9
*/
+@Deprecated
@ScannerSide
public class ProjectReactor implements ProjectKey {
@@ -41,7 +44,7 @@ public class ProjectReactor implements ProjectKey {
}
public List<ProjectDefinition> getProjects() {
- return collectProjects(root, new ArrayList<ProjectDefinition>());
+ return collectProjects(root, new ArrayList<>());
}
/**
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/internal/ProjectBuilderContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/internal/ProjectBuilderContext.java
index 6d2024037ba..b3093aa7011 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/internal/ProjectBuilderContext.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/internal/ProjectBuilderContext.java
@@ -27,8 +27,10 @@ import org.sonar.api.batch.bootstrap.ProjectReactor;
* Context that is passed to {@link org.sonar.api.batch.bootstrap.ProjectBuilder} as parameter.
* Important - plugins must use this class only for unit test needs.
*
+ * @deprecated since 6.5
* @since 3.7
*/
+@Deprecated
public class ProjectBuilderContext implements ProjectBuilder.Context {
private final ProjectReactor reactor;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtRemediationFunction.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtRemediationFunction.java
index a0b2e24404d..cbfc1368779 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtRemediationFunction.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtRemediationFunction.java
@@ -22,12 +22,14 @@ package org.sonar.api.batch.debt;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.utils.Duration;
+import javax.annotation.concurrent.Immutable;
/**
* @since 4.3
* @deprecated since 6.5 debt model will soon be unavailable on batch side
*/
@Deprecated
+@Immutable
public class DebtRemediationFunction {
public enum Type {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java
index 373ba890055..c1aaf9fa36f 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputModule.java
@@ -19,6 +19,9 @@
*/
package org.sonar.api.batch.fs;
+
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.api.batch.sensor.SensorContext;
/**
@@ -26,5 +29,6 @@ import org.sonar.api.batch.sensor.SensorContext;
*
* @since 5.2
*/
+@Immutable
public interface InputModule extends InputComponent {
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java
index d526e7f57cc..b3a0dbbe9ee 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java
@@ -24,8 +24,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.api.batch.fs.IndexedFile;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.utils.PathUtils;
@@ -33,35 +36,34 @@ import org.sonar.api.utils.PathUtils;
/**
* @since 6.3
*/
+@Immutable
public class DefaultIndexedFile extends DefaultInputComponent implements IndexedFile {
private final String relativePath;
private final String moduleKey;
private final Path moduleBaseDir;
- private String language;
+ private final String language;
private final Type type;
+ private final Path path;
/**
* Testing purposes only!
*/
- public DefaultIndexedFile(String moduleKey, Path moduleBaseDir, String relativePath) {
- this(moduleKey, moduleBaseDir, relativePath, TestInputFileBuilder.nextBatchId());
+ public DefaultIndexedFile(String moduleKey, Path moduleBaseDir, String relativePath, @Nullable String language) {
+ this(moduleKey, moduleBaseDir, relativePath, language, TestInputFileBuilder.nextBatchId());
}
- public DefaultIndexedFile(String moduleKey, Path moduleBaseDir, String relativePath, int batchId) {
- this(moduleKey, moduleBaseDir, relativePath, Type.MAIN, batchId);
+ public DefaultIndexedFile(String moduleKey, Path moduleBaseDir, String relativePath, @Nullable String language, int batchId) {
+ this(moduleKey, moduleBaseDir, relativePath, Type.MAIN, language, batchId);
}
- public DefaultIndexedFile(String moduleKey, Path moduleBaseDir, String relativePath, Type type, int batchId) {
+ public DefaultIndexedFile(String moduleKey, Path moduleBaseDir, String relativePath, Type type, @Nullable String language, int batchId) {
super(batchId);
this.moduleKey = moduleKey;
this.relativePath = PathUtils.sanitize(relativePath);
this.moduleBaseDir = moduleBaseDir.normalize();
this.type = type;
- }
-
- public DefaultIndexedFile setLanguage(@Nullable String language) {
this.language = language;
- return this;
+ this.path = this.moduleBaseDir.resolve(this.relativePath);
}
@Override
@@ -81,7 +83,7 @@ public class DefaultIndexedFile extends DefaultInputComponent implements Indexed
@Override
public Path path() {
- return moduleBaseDir.resolve(relativePath);
+ return path;
}
@Override
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
index ff881a6f75d..b3ea8263c0d 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
@@ -47,12 +47,13 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
private final DefaultIndexedFile indexedFile;
+ private final String contents;
private final Consumer<DefaultInputFile> metadataGenerator;
+
private Status status;
private Charset charset;
private Metadata metadata;
private boolean publish;
- private String contents;
public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator) {
this(indexedFile, metadataGenerator, null);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java
index ac8eced2bbd..1165e54d494 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputModule.java
@@ -19,13 +19,36 @@
*/
package org.sonar.api.batch.fs.internal;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputModule;
/**
* @since 5.2
*/
+@Immutable
public class DefaultInputModule extends DefaultInputComponent implements InputModule {
+ private final File baseDir;
+ private final File workDir;
+ private final String name;
+ private final String version;
+ private final String originalName;
+ private final String originalVersion;
+ private final String description;
+ private final String keyWithBranch;
+ private final String branch;
+ private final List<String> sources;
+ private final List<String> tests;
+ private final Map<String, String> properties;
private final String moduleKey;
private final ProjectDefinition definition;
@@ -36,9 +59,29 @@ public class DefaultInputModule extends DefaultInputComponent implements InputMo
public DefaultInputModule(String moduleKey) {
this(ProjectDefinition.create().setKey(moduleKey), TestInputFileBuilder.nextBatchId());
}
+
+ /**
+ * For testing only!
+ */
+ public DefaultInputModule(ProjectDefinition definition) {
+ this(definition, TestInputFileBuilder.nextBatchId());
+ }
public DefaultInputModule(ProjectDefinition definition, int batchId) {
super(batchId);
+ this.baseDir = definition.getBaseDir();
+ this.workDir = definition.getWorkDir();
+ this.name = definition.getName();
+ this.originalName = definition.getOriginalName();
+ this.version = definition.getVersion();
+ this.originalVersion = definition.getOriginalVersion();
+ this.description = definition.getDescription();
+ this.keyWithBranch = definition.getKeyWithBranch();
+ this.branch = definition.getBranch();
+ this.sources = Collections.unmodifiableList(new ArrayList<>(definition.sources()));
+ this.tests = Collections.unmodifiableList(new ArrayList<>(definition.tests()));
+ this.properties = Collections.unmodifiableMap(new HashMap<>(definition.properties()));
+
this.definition = definition;
this.moduleKey = definition.getKey();
}
@@ -59,5 +102,59 @@ public class DefaultInputModule extends DefaultInputComponent implements InputMo
public ProjectDefinition definition() {
return definition;
}
+
+ public File getBaseDir() {
+ return baseDir;
+ }
+
+ public File getWorkDir() {
+ return workDir;
+ }
+
+ public String getKeyWithBranch() {
+ return keyWithBranch;
+ }
+
+ @CheckForNull
+ public String getBranch() {
+ return branch;
+ }
+
+ public Map<String, String> properties() {
+ return properties;
+ }
+
+ @CheckForNull
+ public String getOriginalVersion() {
+ return originalVersion;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ @CheckForNull
+ public String getOriginalName() {
+ return originalName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * @return Source files and folders.
+ */
+ public List<String> sources() {
+ return sources;
+ }
+
+ public List<String> tests() {
+ return tests;
+ }
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java
index f444c26bd0d..4a96ce61591 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java
@@ -20,252 +20,34 @@
package org.sonar.api.batch.fs.internal;
import java.io.BufferedReader;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.sonar.api.CoreProperties;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
+import org.sonar.api.batch.fs.internal.charhandler.FileHashComputer;
+import org.sonar.api.batch.fs.internal.charhandler.LineCounter;
+import org.sonar.api.batch.fs.internal.charhandler.LineHashComputer;
+import org.sonar.api.batch.fs.internal.charhandler.LineOffsetCounter;
/**
* Computes hash of files. Ends of Lines are ignored, so files with
* same content but different EOL encoding have the same hash.
*/
@ScannerSide
+@Immutable
public class FileMetadata {
-
- private static final Logger LOG = Loggers.get(FileMetadata.class);
-
private static final char LINE_FEED = '\n';
private static final char CARRIAGE_RETURN = '\r';
- public abstract static class CharHandler {
-
- protected void handleAll(char c) {
- }
-
- protected void handleIgnoreEoL(char c) {
- }
-
- protected void newLine() {
- }
-
- protected void eof() {
- }
- }
-
- private static class LineCounter extends CharHandler {
- private int lines = 1;
- private int nonBlankLines = 0;
- private boolean blankLine = true;
- boolean alreadyLoggedInvalidCharacter = false;
- private final String filePath;
- private final Charset encoding;
-
- LineCounter(String filePath, Charset encoding) {
- this.filePath = filePath;
- this.encoding = encoding;
- }
-
- @Override
- protected void handleAll(char c) {
- if (!alreadyLoggedInvalidCharacter && c == '\ufffd') {
- LOG.warn("Invalid character encountered in file {} at line {} for encoding {}. Please fix file content or configure the encoding to be used using property '{}'.", filePath,
- lines, encoding, CoreProperties.ENCODING_PROPERTY);
- alreadyLoggedInvalidCharacter = true;
- }
- }
-
- @Override
- protected void newLine() {
- lines++;
- if (!blankLine) {
- nonBlankLines++;
- }
- blankLine = true;
- }
-
- @Override
- protected void handleIgnoreEoL(char c) {
- if (!Character.isWhitespace(c)) {
- blankLine = false;
- }
- }
-
- @Override
- protected void eof() {
- if (!blankLine) {
- nonBlankLines++;
- }
- }
-
- public int lines() {
- return lines;
- }
-
- public int nonBlankLines() {
- return nonBlankLines;
- }
-
- }
-
- private static class FileHashComputer extends CharHandler {
- private MessageDigest globalMd5Digest = DigestUtils.getMd5Digest();
- private StringBuilder sb = new StringBuilder();
- private final CharsetEncoder encoder;
- private final String filePath;
-
- public FileHashComputer(String filePath) {
- encoder = StandardCharsets.UTF_8.newEncoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- this.filePath = filePath;
- }
-
- @Override
- protected void handleIgnoreEoL(char c) {
- sb.append(c);
- }
-
- @Override
- protected void newLine() {
- sb.append(LINE_FEED);
- processBuffer();
- sb.setLength(0);
- }
-
- @Override
- protected void eof() {
- if (sb.length() > 0) {
- processBuffer();
- }
- }
-
- private void processBuffer() {
- try {
- if (sb.length() > 0) {
- ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb));
- globalMd5Digest.update(encoded.array(), 0, encoded.limit());
- }
- } catch (CharacterCodingException e) {
- throw new IllegalStateException("Error encoding line hash in file: " + filePath, e);
- }
- }
-
- @CheckForNull
- public String getHash() {
- return Hex.encodeHexString(globalMd5Digest.digest());
- }
- }
-
- private static class LineHashComputer extends CharHandler {
- private final MessageDigest lineMd5Digest = DigestUtils.getMd5Digest();
- private final CharsetEncoder encoder;
- private final StringBuilder sb = new StringBuilder();
- private final LineHashConsumer consumer;
- private final File file;
- private int line = 1;
-
- public LineHashComputer(LineHashConsumer consumer, File f) {
- this.consumer = consumer;
- this.file = f;
- this.encoder = StandardCharsets.UTF_8.newEncoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- }
-
- @Override
- protected void handleIgnoreEoL(char c) {
- if (!Character.isWhitespace(c)) {
- sb.append(c);
- }
- }
-
- @Override
- protected void newLine() {
- processBuffer();
- sb.setLength(0);
- line++;
- }
-
- @Override
- protected void eof() {
- if (this.line > 0) {
- processBuffer();
- }
- }
-
- private void processBuffer() {
- try {
- if (sb.length() > 0) {
- ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb));
- lineMd5Digest.update(encoded.array(), 0, encoded.limit());
- consumer.consume(line, lineMd5Digest.digest());
- }
- } catch (CharacterCodingException e) {
- throw new IllegalStateException("Error encoding line hash in file: " + file.getAbsolutePath(), e);
- }
- }
- }
-
- private static class LineOffsetCounter extends CharHandler {
- private long currentOriginalOffset = 0;
- private IntArrayList originalLineOffsets = new IntArrayList();
- private long lastValidOffset = 0;
-
- public LineOffsetCounter() {
- originalLineOffsets.add(0);
- }
-
- @Override
- protected void handleAll(char c) {
- currentOriginalOffset++;
- }
-
- @Override
- protected void newLine() {
- if (currentOriginalOffset > Integer.MAX_VALUE) {
- throw new IllegalStateException("File is too big: " + currentOriginalOffset);
- }
- originalLineOffsets.add((int) currentOriginalOffset);
- }
-
- @Override
- protected void eof() {
- lastValidOffset = currentOriginalOffset;
- }
-
- public int[] getOriginalLineOffsets() {
- return originalLineOffsets.trimAndGet();
- }
-
- public int getLastValidOffset() {
- if (lastValidOffset > Integer.MAX_VALUE) {
- throw new IllegalStateException("File is too big: " + lastValidOffset);
- }
- return (int) lastValidOffset;
- }
-
- }
-
/**
* Compute hash of a file ignoring line ends differences.
* Maximum performance is needed.
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/InputModuleHierarchy.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/InputModuleHierarchy.java
index 468a052f507..b258fb04dd2 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/InputModuleHierarchy.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/InputModuleHierarchy.java
@@ -22,10 +22,11 @@ package org.sonar.api.batch.fs.internal;
import java.util.Collection;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
import org.sonar.api.batch.fs.InputModule;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
+@Immutable
public interface InputModuleHierarchy {
DefaultInputModule root();
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java
index 71d79d1007a..9323c73b062 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/Metadata.java
@@ -19,6 +19,11 @@
*/
package org.sonar.api.batch.fs.internal;
+import java.util.Arrays;
+
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
public class Metadata {
private final int lines;
private final int nonBlankLines;
@@ -30,7 +35,7 @@ public class Metadata {
this.lines = lines;
this.nonBlankLines = nonBlankLines;
this.hash = hash;
- this.originalLineOffsets = originalLineOffsets;
+ this.originalLineOffsets = Arrays.copyOf(originalLineOffsets, originalLineOffsets.length);
this.lastValidOffset = lastValidOffset;
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPattern.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPattern.java
index 556ce3f5de0..5ec259f0021 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPattern.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPattern.java
@@ -19,11 +19,13 @@
*/
package org.sonar.api.batch.fs.internal;
+import javax.annotation.concurrent.ThreadSafe;
+
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.fs.IndexedFile;
import org.sonar.api.utils.WildcardPattern;
+@ThreadSafe
public abstract class PathPattern {
final WildcardPattern pattern;
@@ -32,9 +34,9 @@ public abstract class PathPattern {
this.pattern = WildcardPattern.create(pattern);
}
- public abstract boolean match(IndexedFile inputFile);
+ public abstract boolean match(String absolutePath, String relativePath);
- public abstract boolean match(IndexedFile inputFile, boolean caseSensitiveFileExtension);
+ public abstract boolean match(String absolutePath, String relativePath, boolean caseSensitiveFileExtension);
public static PathPattern create(String s) {
String trimmed = StringUtils.trim(s);
@@ -58,15 +60,15 @@ public abstract class PathPattern {
}
@Override
- public boolean match(IndexedFile inputFile) {
- return match(inputFile, true);
+ public boolean match(String absolutePath, String relativePath) {
+ return match(absolutePath, relativePath, true);
}
@Override
- public boolean match(IndexedFile inputFile, boolean caseSensitiveFileExtension) {
- String path = inputFile.absolutePath();
+ public boolean match(String absolutePath, String relativePath, boolean caseSensitiveFileExtension) {
+ String path = absolutePath;
if (!caseSensitiveFileExtension) {
- String extension = sanitizeExtension(FilenameUtils.getExtension(inputFile.file().getName()));
+ String extension = sanitizeExtension(FilenameUtils.getExtension(relativePath));
if (StringUtils.isNotBlank(extension)) {
path = StringUtils.removeEndIgnoreCase(path, extension);
path = path + extension;
@@ -90,15 +92,15 @@ public abstract class PathPattern {
}
@Override
- public boolean match(IndexedFile inputFile) {
- return match(inputFile, true);
+ public boolean match(String absolutePath, String relativePath) {
+ return match(absolutePath, relativePath, true);
}
@Override
- public boolean match(IndexedFile inputFile, boolean caseSensitiveFileExtension) {
- String path = inputFile.relativePath();
+ public boolean match(String absolutePath, String relativePath, boolean caseSensitiveFileExtension) {
+ String path = relativePath;
if (!caseSensitiveFileExtension) {
- String extension = sanitizeExtension(FilenameUtils.getExtension(inputFile.file().getName()));
+ String extension = sanitizeExtension(FilenameUtils.getExtension(relativePath));
if (StringUtils.isNotBlank(extension)) {
path = StringUtils.removeEndIgnoreCase(path, extension);
path = path + extension;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPatternPredicate.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPatternPredicate.java
index 400fd64f37b..e6b4a9246e3 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPatternPredicate.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPatternPredicate.java
@@ -34,7 +34,7 @@ class PathPatternPredicate extends AbstractFilePredicate {
@Override
public boolean apply(InputFile f) {
- return pattern.match(f);
+ return pattern.match(f.absolutePath(), f.relativePath());
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java
index 6fc584fdfbc..fa86a9e17e6 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TestInputFileBuilder.java
@@ -66,7 +66,7 @@ public class TestInputFileBuilder {
private int lastValidOffset = -1;
private String hash;
private int nonBlankLines;
- private int[] originalLineOffsets;
+ private int[] originalLineOffsets = new int[0];
private boolean publish = true;
private String contents;
@@ -194,8 +194,7 @@ public class TestInputFileBuilder {
}
public DefaultInputFile build() {
- DefaultIndexedFile indexedFile = new DefaultIndexedFile(moduleKey, moduleBaseDir, relativePath, type, id);
- indexedFile.setLanguage(language);
+ DefaultIndexedFile indexedFile = new DefaultIndexedFile(moduleKey, moduleBaseDir, relativePath, type, language, id);
DefaultInputFile inputFile = new DefaultInputFile(indexedFile,
f -> f.setMetadata(new Metadata(lines, nonBlankLines, hash, originalLineOffsets, lastValidOffset)),
contents);
@@ -206,8 +205,11 @@ public class TestInputFileBuilder {
}
public static DefaultInputModule newDefaultInputModule(String moduleKey, File baseDir) {
- ProjectDefinition definition = ProjectDefinition.create().setKey(moduleKey);
- definition.setBaseDir(baseDir);
- return new DefaultInputModule(definition, TestInputFileBuilder.nextBatchId());
+ ProjectDefinition definition = ProjectDefinition.create().setKey(moduleKey).setBaseDir(baseDir);
+ return newDefaultInputModule(definition);
+ }
+
+ public static DefaultInputModule newDefaultInputModule(ProjectDefinition projectDefinition) {
+ return new DefaultInputModule(projectDefinition, TestInputFileBuilder.nextBatchId());
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/CharHandler.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/CharHandler.java
new file mode 100644
index 00000000000..76941323906
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/CharHandler.java
@@ -0,0 +1,35 @@
+/*
+ * 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.api.batch.fs.internal.charhandler;
+
+public abstract class CharHandler {
+
+ public void handleAll(char c) {
+ }
+
+ public void handleIgnoreEoL(char c) {
+ }
+
+ public void newLine() {
+ }
+
+ public void eof() {
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/FileHashComputer.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/FileHashComputer.java
new file mode 100644
index 00000000000..d1bfa79207e
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/FileHashComputer.java
@@ -0,0 +1,85 @@
+/*
+ * 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.api.batch.fs.internal.charhandler;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+
+import javax.annotation.CheckForNull;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+
+public class FileHashComputer extends CharHandler {
+ private static final char LINE_FEED = '\n';
+
+
+ private MessageDigest globalMd5Digest = DigestUtils.getMd5Digest();
+ private StringBuilder sb = new StringBuilder();
+ private final CharsetEncoder encoder;
+ private final String filePath;
+
+ public FileHashComputer(String filePath) {
+ encoder = StandardCharsets.UTF_8.newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ this.filePath = filePath;
+ }
+
+ @Override
+ public void handleIgnoreEoL(char c) {
+ sb.append(c);
+ }
+
+ @Override
+ public void newLine() {
+ sb.append(LINE_FEED);
+ processBuffer();
+ sb.setLength(0);
+ }
+
+ @Override
+ public void eof() {
+ if (sb.length() > 0) {
+ processBuffer();
+ }
+ }
+
+ private void processBuffer() {
+ try {
+ if (sb.length() > 0) {
+ ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb));
+ globalMd5Digest.update(encoded.array(), 0, encoded.limit());
+ }
+ } catch (CharacterCodingException e) {
+ throw new IllegalStateException("Error encoding line hash in file: " + filePath, e);
+ }
+ }
+
+ @CheckForNull
+ public String getHash() {
+ return Hex.encodeHexString(globalMd5Digest.digest());
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/IntArrayList.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/IntArrayList.java
index 913c0a2433b..2bdcfb6a852 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/IntArrayList.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/IntArrayList.java
@@ -17,7 +17,7 @@
* 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.api.batch.fs.internal;
+package org.sonar.api.batch.fs.internal.charhandler;
import java.util.Arrays;
import java.util.Collection;
@@ -72,11 +72,12 @@ class IntArrayList {
}
private void ensureCapacityInternal(int minCapacity) {
+ int capacity = minCapacity;
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
- minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
+ capacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
- ensureExplicitCapacity(minCapacity);
+ ensureExplicitCapacity(capacity);
}
private void ensureExplicitCapacity(int minCapacity) {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineCounter.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineCounter.java
new file mode 100644
index 00000000000..c17a867f295
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineCounter.java
@@ -0,0 +1,83 @@
+/*
+ * 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.api.batch.fs.internal.charhandler;
+
+import java.nio.charset.Charset;
+
+import org.sonar.api.CoreProperties;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+public class LineCounter extends CharHandler {
+ private static final Logger LOG = Loggers.get(LineCounter.class);
+
+ private int lines = 1;
+ private int nonBlankLines = 0;
+ private boolean blankLine = true;
+ boolean alreadyLoggedInvalidCharacter = false;
+ private final String filePath;
+ private final Charset encoding;
+
+ public LineCounter(String filePath, Charset encoding) {
+ this.filePath = filePath;
+ this.encoding = encoding;
+ }
+
+ @Override
+ public void handleAll(char c) {
+ if (!alreadyLoggedInvalidCharacter && c == '\ufffd') {
+ LOG.warn("Invalid character encountered in file {} at line {} for encoding {}. Please fix file content or configure the encoding to be used using property '{}'.", filePath,
+ lines, encoding, CoreProperties.ENCODING_PROPERTY);
+ alreadyLoggedInvalidCharacter = true;
+ }
+ }
+
+ @Override
+ public void newLine() {
+ lines++;
+ if (!blankLine) {
+ nonBlankLines++;
+ }
+ blankLine = true;
+ }
+
+ @Override
+ public void handleIgnoreEoL(char c) {
+ if (!Character.isWhitespace(c)) {
+ blankLine = false;
+ }
+ }
+
+ @Override
+ public void eof() {
+ if (!blankLine) {
+ nonBlankLines++;
+ }
+ }
+
+ public int lines() {
+ return lines;
+ }
+
+ public int nonBlankLines() {
+ return nonBlankLines;
+ }
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineHashComputer.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineHashComputer.java
new file mode 100644
index 00000000000..f371c71f5a1
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineHashComputer.java
@@ -0,0 +1,82 @@
+/*
+ * 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.api.batch.fs.internal.charhandler;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.sonar.api.batch.fs.internal.FileMetadata.LineHashConsumer;
+
+public class LineHashComputer extends CharHandler {
+ private final MessageDigest lineMd5Digest = DigestUtils.getMd5Digest();
+ private final CharsetEncoder encoder;
+ private final StringBuilder sb = new StringBuilder();
+ private final LineHashConsumer consumer;
+ private final File file;
+ private int line = 1;
+
+ public LineHashComputer(LineHashConsumer consumer, File f) {
+ this.consumer = consumer;
+ this.file = f;
+ this.encoder = StandardCharsets.UTF_8.newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+
+ @Override
+ public void handleIgnoreEoL(char c) {
+ if (!Character.isWhitespace(c)) {
+ sb.append(c);
+ }
+ }
+
+ @Override
+ public void newLine() {
+ processBuffer();
+ sb.setLength(0);
+ line++;
+ }
+
+ @Override
+ public void eof() {
+ if (this.line > 0) {
+ processBuffer();
+ }
+ }
+
+ private void processBuffer() {
+ try {
+ if (sb.length() > 0) {
+ ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb));
+ lineMd5Digest.update(encoded.array(), 0, encoded.limit());
+ consumer.consume(line, lineMd5Digest.digest());
+ }
+ } catch (CharacterCodingException e) {
+ throw new IllegalStateException("Error encoding line hash in file: " + file.getAbsolutePath(), e);
+ }
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineOffsetCounter.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineOffsetCounter.java
new file mode 100644
index 00000000000..cf39d16267f
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/LineOffsetCounter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.api.batch.fs.internal.charhandler;
+
+public class LineOffsetCounter extends CharHandler {
+ private long currentOriginalOffset = 0;
+ private IntArrayList originalLineOffsets = new IntArrayList();
+ private long lastValidOffset = 0;
+
+ public LineOffsetCounter() {
+ originalLineOffsets.add(0);
+ }
+
+ @Override
+ public void handleAll(char c) {
+ currentOriginalOffset++;
+ }
+
+ @Override
+ public void newLine() {
+ if (currentOriginalOffset > Integer.MAX_VALUE) {
+ throw new IllegalStateException("File is too big: " + currentOriginalOffset);
+ }
+ originalLineOffsets.add((int) currentOriginalOffset);
+ }
+
+ @Override
+ public void eof() {
+ lastValidOffset = currentOriginalOffset;
+ }
+
+ public int[] getOriginalLineOffsets() {
+ return originalLineOffsets.trimAndGet();
+ }
+
+ public int getLastValidOffset() {
+ if (lastValidOffset > Integer.MAX_VALUE) {
+ throw new IllegalStateException("File is too big: " + lastValidOffset);
+ }
+ return (int) lastValidOffset;
+ }
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/package-info.java
new file mode 100644
index 00000000000..b8d3c63fcff
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/charhandler/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.batch.fs.internal.charhandler;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/measure/MetricFinder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/measure/MetricFinder.java
index 7e8dffb5903..c51c5ddf969 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/measure/MetricFinder.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/measure/MetricFinder.java
@@ -23,12 +23,15 @@ import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.ThreadSafe;
+
import org.sonar.api.batch.ScannerSide;
/**
* @since 4.5
*/
@ScannerSide
+@ThreadSafe
public interface MetricFinder {
@CheckForNull
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRule.java
index bf96a7a1103..c0df514efc0 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRule.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRule.java
@@ -21,12 +21,15 @@ package org.sonar.api.batch.rule;
import java.util.Map;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.api.rule.RuleKey;
/**
* Configuration of a rule activated on a Quality profile
* @since 4.2
*/
+@Immutable
public interface ActiveRule {
RuleKey ruleKey();
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRules.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRules.java
index 1ea2b013ed7..f25c75a5af8 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRules.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/ActiveRules.java
@@ -23,6 +23,7 @@ import org.sonar.api.batch.ScannerSide;
import org.sonar.api.rule.RuleKey;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
import java.util.Collection;
@@ -35,6 +36,7 @@ import java.util.Collection;
*
* @since 4.2
*/
+@Immutable
@ScannerSide
public interface ActiveRules {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/RuleParam.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/RuleParam.java
index 7c06501dfbe..4781bb39fdd 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/RuleParam.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/RuleParam.java
@@ -19,10 +19,14 @@
*/
package org.sonar.api.batch.rule;
+import javax.annotation.concurrent.Immutable;
+
/**
* @since 4.2
*/
+@Immutable
public interface RuleParam {
String key();
+
String description();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rules.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rules.java
index 20b755c6fc7..c73cc867eee 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rules.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rules.java
@@ -23,6 +23,7 @@ import org.sonar.api.batch.ScannerSide;
import org.sonar.api.rule.RuleKey;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
import java.util.Collection;
@@ -33,6 +34,7 @@ import java.util.Collection;
* @since 4.2
*/
@ScannerSide
+@Immutable
public interface Rules {
/**
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultActiveRules.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultActiveRules.java
index 9f4fd4bdbb0..981ebbbedde 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultActiveRules.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultActiveRules.java
@@ -20,7 +20,6 @@
package org.sonar.api.batch.rule.internal;
import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ListMultimap;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.rule.RuleKey;
@@ -28,35 +27,32 @@ import org.sonar.api.rule.RuleKey;
import javax.annotation.concurrent.Immutable;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Immutable
public class DefaultActiveRules implements ActiveRules {
-
- // TODO use disk-backed cache (persistit) instead of full in-memory cache ?
- private final ListMultimap<String, ActiveRule> activeRulesByRepository;
+ private final ImmutableListMultimap<String, ActiveRule> activeRulesByRepository;
private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndKey = new HashMap<>();
private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndInternalKey = new HashMap<>();
- private final ListMultimap<String, ActiveRule> activeRulesByLanguage;
+ private final ImmutableListMultimap<String, ActiveRule> activeRulesByLanguage;
public DefaultActiveRules(Collection<NewActiveRule> newActiveRules) {
ImmutableListMultimap.Builder<String, ActiveRule> repoBuilder = ImmutableListMultimap.builder();
ImmutableListMultimap.Builder<String, ActiveRule> langBuilder = ImmutableListMultimap.builder();
for (NewActiveRule newAR : newActiveRules) {
DefaultActiveRule ar = new DefaultActiveRule(newAR);
- repoBuilder.put(ar.ruleKey().repository(), ar);
+ String repo = ar.ruleKey().repository();
+ repoBuilder.put(repo, ar);
if (ar.language() != null) {
langBuilder.put(ar.language(), ar);
}
- if (!activeRulesByRepositoryAndKey.containsKey(ar.ruleKey().repository())) {
- activeRulesByRepositoryAndKey.put(ar.ruleKey().repository(), new HashMap<String, ActiveRule>());
- activeRulesByRepositoryAndInternalKey.put(ar.ruleKey().repository(), new HashMap<String, ActiveRule>());
- }
- activeRulesByRepositoryAndKey.get(ar.ruleKey().repository()).put(ar.ruleKey().rule(), ar);
+
+ activeRulesByRepositoryAndKey.computeIfAbsent(repo, r -> new HashMap<>()).put(ar.ruleKey().rule(), ar);
String internalKey = ar.internalKey();
if (internalKey != null) {
- activeRulesByRepositoryAndInternalKey.get(ar.ruleKey().repository()).put(internalKey, ar);
+ activeRulesByRepositoryAndInternalKey.computeIfAbsent(repo, r -> new HashMap<>()).put(internalKey, ar);
}
}
activeRulesByRepository = repoBuilder.build();
@@ -65,11 +61,8 @@ public class DefaultActiveRules implements ActiveRules {
@Override
public ActiveRule find(RuleKey ruleKey) {
- Map<String, ActiveRule> map = activeRulesByRepositoryAndKey.get(ruleKey.repository());
- if(map != null) {
- return map.get(ruleKey.rule());
- }
- return null;
+ return activeRulesByRepositoryAndKey.getOrDefault(ruleKey.repository(), Collections.emptyMap())
+ .get(ruleKey.rule());
}
@Override
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRules.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRules.java
index 37795039e83..1b46101fe24 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRules.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRules.java
@@ -25,7 +25,6 @@ import com.google.common.collect.HashBasedTable;
import org.sonar.api.batch.rule.Rule;
import com.google.common.collect.Table;
import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ListMultimap;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.rule.Rules;
import org.sonar.api.rule.RuleKey;
@@ -39,9 +38,7 @@ import java.util.List;
@Immutable
class DefaultRules implements Rules {
-
- // TODO use disk-backed cache (persistit) instead of full in-memory cache ?
- private final ListMultimap<String, Rule> rulesByRepository;
+ private final ImmutableListMultimap<String, Rule> rulesByRepository;
private final ImmutableTable<String, String, List<Rule>> rulesByRepositoryAndInternalKey;
DefaultRules(Collection<NewRule> newRules) {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java
index abdb03c9ecc..88e9c1d6b13 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java
@@ -57,7 +57,7 @@ public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
this.inputFile = requireNonNull(inputFile, "file can't be null");
String[] cpdExclusions = config.getStringArray(CoreProperties.CPD_EXCLUSIONS);
for (PathPattern cpdExclusion : PathPattern.create(cpdExclusions)) {
- if (cpdExclusion.match(inputFile)) {
+ if (cpdExclusion.match(inputFile.absolutePath(), inputFile.relativePath())) {
this.excluded = true;
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
index 4cb9ded0ef5..65752a177c6 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
@@ -28,6 +28,7 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.component.Component;
import org.sonar.api.scan.filesystem.PathResolver;
@@ -39,6 +40,10 @@ import org.sonar.api.scan.filesystem.PathResolver;
public class Project extends Resource implements Component {
private final ProjectDefinition definition;
+ public Project(DefaultInputModule module) {
+ this(module.definition());
+ }
+
public Project(ProjectDefinition definition) {
this.definition = definition;
this.setKey(definition.getKey());
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java
index fdc1dd19afd..17698835e8e 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java
@@ -25,6 +25,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+
import org.apache.commons.io.FilenameUtils;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.utils.PathUtils;
@@ -35,6 +37,7 @@ import static java.util.stream.Collectors.joining;
* @since 3.5
*/
@ScannerSide
+@Immutable
public class PathResolver {
public File relativeFile(File dir, String path) {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java
index 6928b75e036..76e1a74ec29 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java
@@ -22,12 +22,14 @@ package org.sonar.api.scan.issue.filter;
import java.util.Date;
import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.ThreadSafe;
import org.sonar.api.rule.RuleKey;
/**
* @since 5.3
*/
+@ThreadSafe
public interface FilterableIssue {
String componentKey();
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilter.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilter.java
index 230ad24605d..0c2847f7a1e 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilter.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilter.java
@@ -19,6 +19,9 @@
*/
package org.sonar.api.scan.issue.filter;
+
+import javax.annotation.concurrent.ThreadSafe;
+
import org.sonar.api.ExtensionPoint;
import org.sonar.api.batch.ScannerSide;
import org.sonarsource.api.sonarlint.SonarLintSide;
@@ -27,6 +30,7 @@ import org.sonarsource.api.sonarlint.SonarLintSide;
@SonarLintSide
@ExtensionPoint
@FunctionalInterface
+@ThreadSafe
/**
* @since 5.3
*/
@@ -40,6 +44,9 @@ public interface IssueFilter {
* </ul>
* The <code>chain</code> parameter allows for fine control of the filtering logic: it is each filter's duty to either pass the issue to the next filter, by calling
* the {@link IssueFilterChain#accept} method, or return directly if the issue has to be accepted or not
+ *
+ * Implementations should be thread safe.
+ *
* @param issue the issue being filtered
* @param chain the rest of the filters
* @return <code>true</code> to accept the issue, <code>false</code> to reject it, {@link IssueFilterChain#accept} to let the other filters decide.
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilterChain.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilterChain.java
index aab918618ce..02b6943b63f 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilterChain.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/IssueFilterChain.java
@@ -19,6 +19,8 @@
*/
package org.sonar.api.scan.issue.filter;
+import javax.annotation.concurrent.ThreadSafe;
+
/**
* A filter chain is an object provided to issues filters for fine control over the filtering logic. Each filter has the choice to:
* <ul>
@@ -29,6 +31,7 @@ package org.sonar.api.scan.issue.filter;
*
* @since 5.3
*/
+@ThreadSafe
public interface IssueFilterChain {
/**
* Called by a filter to let downstream filters decide the fate of the issue
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/WildcardPattern.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/WildcardPattern.java
index a1a0f064569..310e788d36d 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/WildcardPattern.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/WildcardPattern.java
@@ -19,10 +19,13 @@
*/
package org.sonar.api.utils;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
import org.apache.commons.lang.StringUtils;
/**
@@ -54,12 +57,12 @@ import org.apache.commons.lang.StringUtils;
* <a href="https://github.com/JetBrains/intellij-community/blob/idea/107.743/platform/util/src/com/intellij/openapi/util/io/FileUtil.java#L847">FileUtil</a>
* from IntelliJ OpenAPI.
*
- *
* @since 1.10
*/
+@ThreadSafe
public class WildcardPattern {
- private static final Map<String, WildcardPattern> CACHE = new HashMap<>();
+ private static final Map<String, WildcardPattern> CACHE = Collections.synchronizedMap(new HashMap<>());
private static final String SPECIAL_CHARS = "()[]^$.{}+|";
private Pattern pattern;
@@ -196,11 +199,6 @@ public class WildcardPattern {
*/
public static WildcardPattern create(String pattern, String directorySeparator) {
String key = pattern + directorySeparator;
- WildcardPattern wildcardPattern = CACHE.get(key);
- if (wildcardPattern == null) {
- wildcardPattern = new WildcardPattern(pattern, directorySeparator);
- CACHE.put(key, wildcardPattern);
- }
- return wildcardPattern;
+ return CACHE.computeIfAbsent(key, k -> new WildcardPattern(pattern, directorySeparator));
}
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java
index 0ae07c5e8d9..82ccf11b3e8 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java
@@ -54,7 +54,7 @@ public class DefaultInputFileTest {
Path baseDir = temp.newFolder().toPath();
Metadata metadata = new Metadata(42, 42, "", new int[0], 0);
- DefaultIndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/Foo.php", InputFile.Type.TEST, 0).setLanguage("php");
+ DefaultIndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/Foo.php", InputFile.Type.TEST, "php", 0);
DefaultInputFile inputFile = new DefaultInputFile(indexedFile, (f) -> f.setMetadata(metadata))
.setStatus(InputFile.Status.ADDED)
.setCharset(StandardCharsets.ISO_8859_1);
@@ -82,10 +82,9 @@ public class DefaultInputFileTest {
Metadata metadata = new Metadata(42, 30, "", new int[0], 0);
- DefaultInputFile inputFile = new DefaultInputFile(new DefaultIndexedFile("ABCDE", baseDir, "src/Foo.php", InputFile.Type.TEST, 0)
- .setLanguage("php"), f -> f.setMetadata(metadata))
- .setStatus(InputFile.Status.ADDED)
- .setCharset(StandardCharsets.ISO_8859_1);
+ DefaultInputFile inputFile = new DefaultInputFile(new DefaultIndexedFile("ABCDE", baseDir, "src/Foo.php", InputFile.Type.TEST, "php", 0), f -> f.setMetadata(metadata))
+ .setStatus(InputFile.Status.ADDED)
+ .setCharset(StandardCharsets.ISO_8859_1);
assertThat(inputFile.contents()).isEqualTo(content);
try (InputStream inputStream = inputFile.inputStream()) {
@@ -110,10 +109,9 @@ public class DefaultInputFileTest {
Metadata metadata = new Metadata(42, 30, "", new int[0], 0);
- DefaultInputFile inputFile = new DefaultInputFile(new DefaultIndexedFile("ABCDE", baseDir, "src/Foo.php", InputFile.Type.TEST, 0)
- .setLanguage("php"), f -> f.setMetadata(metadata))
- .setStatus(InputFile.Status.ADDED)
- .setCharset(StandardCharsets.UTF_8);
+ DefaultInputFile inputFile = new DefaultInputFile(new DefaultIndexedFile("ABCDE", baseDir, "src/Foo.php", InputFile.Type.TEST, "php", 0), f -> f.setMetadata(metadata))
+ .setStatus(InputFile.Status.ADDED)
+ .setCharset(StandardCharsets.UTF_8);
assertThat(inputFile.contents()).isEqualTo(content);
try (InputStream inputStream = inputFile.inputStream()) {
@@ -125,9 +123,9 @@ public class DefaultInputFileTest {
@Test
public void test_equals_and_hashcode() throws Exception {
- DefaultInputFile f1 = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), (f) -> mock(Metadata.class));
- DefaultInputFile f1a = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), (f) -> mock(Metadata.class));
- DefaultInputFile f2 = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Bar.php"), (f) -> mock(Metadata.class));
+ DefaultInputFile f1 = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), (f) -> mock(Metadata.class));
+ DefaultInputFile f1a = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), (f) -> mock(Metadata.class));
+ DefaultInputFile f2 = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Bar.php", null), (f) -> mock(Metadata.class));
assertThat(f1).isEqualTo(f1);
assertThat(f1).isEqualTo(f1a);
@@ -141,14 +139,14 @@ public class DefaultInputFileTest {
@Test
public void test_toString() throws Exception {
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), (f) -> mock(Metadata.class));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), (f) -> mock(Metadata.class));
assertThat(file.toString()).isEqualTo("[moduleKey=ABCDE, relative=src/Foo.php, basedir=module]");
}
@Test
public void checkValidPointer() {
Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, 15);
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), f -> f.setMetadata(metadata));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), f -> f.setMetadata(metadata));
assertThat(file.newPointer(1, 0).line()).isEqualTo(1);
assertThat(file.newPointer(1, 0).lineOffset()).isEqualTo(0);
// Don't fail
@@ -185,7 +183,7 @@ public class DefaultInputFileTest {
@Test
public void checkValidPointerUsingGlobalOffset() {
Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, 15);
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), f -> f.setMetadata(metadata));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), f -> f.setMetadata(metadata));
assertThat(file.newPointer(0).line()).isEqualTo(1);
assertThat(file.newPointer(0).lineOffset()).isEqualTo(0);
@@ -216,7 +214,7 @@ public class DefaultInputFileTest {
@Test
public void checkValidRange() {
Metadata metadata = new FileMetadata().readMetadata(new StringReader("bla bla a\nabcde"));
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), f -> f.setMetadata(metadata));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), f -> f.setMetadata(metadata));
assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(2, 1)).start().line()).isEqualTo(1);
// Don't fail
@@ -242,7 +240,7 @@ public class DefaultInputFileTest {
@Test
public void selectLine() {
Metadata metadata = new FileMetadata().readMetadata(new StringReader("bla bla a\nabcde\n\nabc"));
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), f -> f.setMetadata(metadata));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), f -> f.setMetadata(metadata));
assertThat(file.selectLine(1).start().line()).isEqualTo(1);
assertThat(file.selectLine(1).start().lineOffset()).isEqualTo(0);
@@ -266,7 +264,7 @@ public class DefaultInputFileTest {
@Test
public void checkValidRangeUsingGlobalOffset() {
Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, 15);
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), f -> f.setMetadata(metadata));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), f -> f.setMetadata(metadata));
TextRange newRange = file.newRange(10, 13);
assertThat(newRange.start().line()).isEqualTo(2);
assertThat(newRange.start().lineOffset()).isEqualTo(0);
@@ -277,7 +275,7 @@ public class DefaultInputFileTest {
@Test
public void testRangeOverlap() {
Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, 15);
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php"), f -> f.setMetadata(metadata));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Foo.php", null), f -> f.setMetadata(metadata));
// Don't fail
assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)))).isTrue();
assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 2)))).isTrue();
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/PathPatternTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/PathPatternTest.java
index 0337f6044b1..fac72032858 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/PathPatternTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/PathPatternTest.java
@@ -45,26 +45,26 @@ public class PathPatternTest {
PathPattern pattern = PathPattern.create("**/*Foo.java");
assertThat(pattern.toString()).isEqualTo("**/*Foo.java");
- IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.java");
- assertThat(pattern.match(indexedFile)).isTrue();
+ IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.java", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath())).isTrue();
// case sensitive by default
- indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.JAVA");
- assertThat(pattern.match(indexedFile)).isFalse();
+ indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.JAVA", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath())).isFalse();
- indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/Other.java");
- assertThat(pattern.match(indexedFile)).isFalse();
+ indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/Other.java", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath())).isFalse();
}
@Test
public void match_relative_path_and_insensitive_file_extension() throws Exception {
PathPattern pattern = PathPattern.create("**/*Foo.java");
- IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.JAVA");
- assertThat(pattern.match(indexedFile, false)).isTrue();
+ IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.JAVA", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath(), false)).isTrue();
- indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/Other.java");
- assertThat(pattern.match(indexedFile, false)).isFalse();
+ indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/Other.java", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath(), false)).isFalse();
}
@Test
@@ -72,15 +72,15 @@ public class PathPatternTest {
PathPattern pattern = PathPattern.create("file:**/src/main/**Foo.java");
assertThat(pattern.toString()).isEqualTo("file:**/src/main/**Foo.java");
- IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.java");
- assertThat(pattern.match(indexedFile)).isTrue();
+ IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.java", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath())).isTrue();
// case sensitive by default
- indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.JAVA");
- assertThat(pattern.match(indexedFile)).isFalse();
+ indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.JAVA", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath())).isFalse();
- indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/Other.java");
- assertThat(pattern.match(indexedFile)).isFalse();
+ indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/Other.java", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath())).isFalse();
}
@Test
@@ -88,11 +88,11 @@ public class PathPatternTest {
PathPattern pattern = PathPattern.create("file:**/src/main/**Foo.java");
assertThat(pattern.toString()).isEqualTo("file:**/src/main/**Foo.java");
- IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.JAVA");
- assertThat(pattern.match(indexedFile, false)).isTrue();
+ IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/MyFoo.JAVA", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath(), false)).isTrue();
- indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/Other.JAVA");
- assertThat(pattern.match(indexedFile, false)).isFalse();
+ indexedFile = new DefaultIndexedFile("ABCDE", moduleBasePath, "src/main/java/org/Other.JAVA", null);
+ assertThat(pattern.match(indexedFile.absolutePath(), indexedFile.relativePath(), false)).isFalse();
}
@Test
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/IntArrayListTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/charhandler/IntArrayListTest.java
index c9c7e1912d0..a4e931e1e30 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/IntArrayListTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/charhandler/IntArrayListTest.java
@@ -17,9 +17,10 @@
* 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.api.batch.fs.internal;
+package org.sonar.api.batch.fs.internal.charhandler;
import org.junit.Test;
+import org.sonar.api.batch.fs.internal.charhandler.IntArrayList;
import static org.assertj.core.api.Assertions.assertThat;
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);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/AnalysisTempFolderProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/AnalysisTempFolderProviderTest.java
index 60a8f7140bb..ce458c8bb3a 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/AnalysisTempFolderProviderTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/analysis/AnalysisTempFolderProviderTest.java
@@ -19,42 +19,43 @@
*/
package org.sonar.scanner.analysis;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.io.File;
import java.io.IOException;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-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.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.utils.TempFolder;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class AnalysisTempFolderProviderTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
private AnalysisTempFolderProvider tempFolderProvider;
- private ProjectReactor projectReactor;
+ private InputModuleHierarchy moduleHierarchy;
@Before
public void setUp() {
tempFolderProvider = new AnalysisTempFolderProvider();
- projectReactor = mock(ProjectReactor.class);
- ProjectDefinition projectDefinition = mock(ProjectDefinition.class);
- when(projectReactor.getRoot()).thenReturn(projectDefinition);
- when(projectDefinition.getWorkDir()).thenReturn(temp.getRoot());
+ moduleHierarchy = mock(InputModuleHierarchy.class);
+ DefaultInputModule module = mock(DefaultInputModule.class);
+ when(moduleHierarchy.root()).thenReturn(module);
+ when(module.getWorkDir()).thenReturn(temp.getRoot());
}
@Test
public void createTempFolder() throws IOException {
File defaultDir = new File(temp.getRoot(), AnalysisTempFolderProvider.TMP_NAME);
- TempFolder tempFolder = tempFolderProvider.provide(projectReactor);
+ TempFolder tempFolder = tempFolderProvider.provide(moduleHierarchy);
tempFolder.newDir();
tempFolder.newFile();
assertThat(defaultDir).exists();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java
index e46702cb90e..33717366d07 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java
@@ -19,12 +19,17 @@
*/
package org.sonar.scanner.cpd;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -32,8 +37,8 @@ import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
@@ -50,10 +55,6 @@ import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class CpdExecutorTest {
@Rule
public LogTester logTester = new LogTester();
@@ -65,7 +66,7 @@ public class CpdExecutorTest {
public ExpectedException thrown = ExpectedException.none();
private CpdExecutor executor;
- private MapSettings settings;
+ private CpdSettings settings;
private SonarCpdBlockIndex index;
private ReportPublisher publisher;
private ScannerReportReader reader;
@@ -80,15 +81,15 @@ public class CpdExecutorTest {
File outputDir = temp.newFolder();
baseDir = temp.newFolder();
- settings = new MapSettings();
+ settings = mock(CpdSettings.class);
publisher = mock(ReportPublisher.class);
when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir));
- index = new SonarCpdBlockIndex(publisher, settings.asConfig());
- componentStore = new InputComponentStore(new PathResolver());
- executor = new CpdExecutor(settings.asConfig(), index, publisher, componentStore);
- reader = new ScannerReportReader(outputDir);
- componentStore.put(TestInputFileBuilder.newDefaultInputModule("foo", baseDir));
+ index = new SonarCpdBlockIndex(publisher, settings);
+ DefaultInputModule inputModule = TestInputFileBuilder.newDefaultInputModule("foo", baseDir);
+ componentStore = new InputComponentStore(new PathResolver(), inputModule);
+ executor = new CpdExecutor(settings, index, publisher, componentStore);
+ reader = new ScannerReportReader(outputDir);
batchComponent1 = createComponent("src/Foo.php", 5);
batchComponent2 = createComponent("src/Foo2.php", 5);
@@ -105,22 +106,6 @@ public class CpdExecutorTest {
}
@Test
- public void defaultMinimumTokens() {
- assertThat(executor.getMinimumTokens("java")).isEqualTo(100);
- }
-
- @Test
- public void minimumTokensByLanguage() {
- settings.setProperty("sonar.cpd.java.minimumTokens", "42");
- settings.setProperty("sonar.cpd.php.minimumTokens", "33");
- assertThat(executor.getMinimumTokens("java")).isEqualTo(42);
-
- settings.setProperty("sonar.cpd.java.minimumTokens", "42");
- settings.setProperty("sonar.cpd.php.minimumTokens", "33");
- assertThat(executor.getMinimumTokens("php")).isEqualTo(33);
- }
-
- @Test
public void testNothingToSave() {
executor.saveDuplications(batchComponent1, Collections.<CloneGroup>emptyList());
assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(0);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdSettingsTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdSettingsTest.java
new file mode 100644
index 00000000000..c7774c750e9
--- /dev/null
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdSettingsTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Optional;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.config.Configuration;
+
+public class CpdSettingsTest {
+ private CpdSettings cpdSettings;
+ private Configuration configuration;
+ private DefaultInputModule module;
+
+ @Before
+ public void setUp() {
+ module = mock(DefaultInputModule.class);
+ InputModuleHierarchy hierarchy = mock(InputModuleHierarchy.class);
+ when(hierarchy.root()).thenReturn(module);
+ configuration = mock(Configuration.class);
+ cpdSettings = new CpdSettings(configuration, hierarchy);
+ }
+
+ @Test
+ public void defaultMinimumTokens() {
+ when(configuration.getInt(anyString())).thenReturn(Optional.empty());
+ assertThat(cpdSettings.getMinimumTokens("java")).isEqualTo(100);
+ }
+
+ @Test
+ public void minimumTokensByLanguage() {
+ when(configuration.getInt("sonar.cpd.java.minimumTokens")).thenReturn(Optional.of(42));
+ when(configuration.getInt("sonar.cpd.php.minimumTokens")).thenReturn(Optional.of(33));
+
+ assertThat(cpdSettings.getMinimumTokens("java")).isEqualTo(42);
+ assertThat(cpdSettings.getMinimumTokens("php")).isEqualTo(33);
+ }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/DefaultIndexTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/DefaultIndexTest.java
index d82bb5d20b1..d7d16341d8f 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/DefaultIndexTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/DefaultIndexTest.java
@@ -19,6 +19,10 @@
*/
package org.sonar.scanner.index;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.io.IOException;
import java.util.Collections;
import org.junit.Before;
@@ -44,10 +48,6 @@ import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.scan.measure.MeasureCache;
import org.sonar.scanner.sensor.DefaultSensorStorage;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class DefaultIndexTest {
@org.junit.Rule
@@ -83,10 +83,10 @@ public class DefaultIndexTest {
rootDef.addSubProject(moduleBDef);
moduleBDef.addSubProject(moduleB1Def);
- project = new Project(rootDef);
- moduleA = new Project(moduleADef);
- moduleB = new Project(moduleBDef);
- moduleB1 = new Project(moduleB1Def);
+ project = new Project(new DefaultInputModule(rootDef));
+ moduleA = new Project(new DefaultInputModule(moduleADef));
+ moduleB = new Project(new DefaultInputModule(moduleBDef));
+ moduleB1 = new Project(new DefaultInputModule(moduleB1Def));
RulesProfile rulesProfile = RulesProfile.create();
rule = Rule.create("repoKey", "ruleKey", "Rule");
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java
index a0aae458ed9..718f16ceb62 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java
@@ -53,12 +53,11 @@ public class EnforceIssuesFilterTest {
issue = mock(FilterableIssue.class);
chain = mock(IssueFilterChain.class);
when(chain.accept(issue)).thenReturn(true);
-
- ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
}
@Test
public void shouldPassToChainIfNoConfiguredPatterns() {
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
verify(chain).accept(issue);
}
@@ -76,6 +75,7 @@ public class EnforceIssuesFilterTest {
when(rulePattern.match(rule)).thenReturn(false);
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
verify(chain).accept(issue);
}
@@ -100,6 +100,7 @@ public class EnforceIssuesFilterTest {
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
when(inputComponentStore.getByKey(componentKey)).thenReturn(createComponentWithPath(path));
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
assertThat(ignoreFilter.accept(issue, chain)).isTrue();
verifyZeroInteractions(chain);
}
@@ -128,6 +129,7 @@ public class EnforceIssuesFilterTest {
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
when(inputComponentStore.getByKey(componentKey)).thenReturn(createComponentWithPath(path));
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
assertThat(ignoreFilter.accept(issue, chain)).isFalse();
verifyZeroInteractions(chain);
}
@@ -152,6 +154,7 @@ public class EnforceIssuesFilterTest {
when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
when(inputComponentStore.getByKey(componentKey)).thenReturn(null);
+ ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
assertThat(ignoreFilter.accept(issue, chain)).isFalse();
verifyZeroInteractions(chain);
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/tracking/SourceHashHolderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/tracking/SourceHashHolderTest.java
index 0cf540f0b7a..dde76bf6722 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/tracking/SourceHashHolderTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/tracking/SourceHashHolderTest.java
@@ -19,9 +19,17 @@
*/
package org.sonar.scanner.issue.tracking;
+import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
+import java.util.Collections;
+
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -34,12 +42,6 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
public class SourceHashHolderTest {
@Rule
@@ -51,10 +53,11 @@ public class SourceHashHolderTest {
DefaultInputFile file;
private File ioFile;
- private ProjectDefinition def = ProjectDefinition.create();
+ private ProjectDefinition def;
@Before
public void setUp() throws Exception {
+ def = mock(ProjectDefinition.class);
lastSnapshots = mock(ServerLineHashesLoader.class);
file = mock(DefaultInputFile.class);
ioFile = temp.newFile();
@@ -83,7 +86,7 @@ public class SourceHashHolderTest {
public void should_lazy_load_reference_hashes_when_status_changed() throws Exception {
final String source = "source";
FileUtils.write(ioFile, source, StandardCharsets.UTF_8);
- def.setKey("foo");
+ when(def.getKeyWithBranch()).thenReturn("foo");
when(file.relativePath()).thenReturn("src/Foo.java");
String key = "foo:src/Foo.java";
when(file.status()).thenReturn(InputFile.Status.CHANGED);
@@ -100,8 +103,8 @@ public class SourceHashHolderTest {
public void should_lazy_load_reference_hashes_when_status_changed_on_branch() throws Exception {
final String source = "source";
FileUtils.write(ioFile, source, StandardCharsets.UTF_8);
- def.setKey("foo");
- def.properties().put(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch");
+ when(def.getKeyWithBranch()).thenReturn("foo:myBranch");
+ when(def.properties()).thenReturn(Collections.singletonMap(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch"));
when(file.relativePath()).thenReturn("src/Foo.java");
String key = "foo:myBranch:src/Foo.java";
when(file.status()).thenReturn(InputFile.Status.CHANGED);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java
index b2d4722cf1c..55a3234a522 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java
@@ -670,6 +670,7 @@ public class FileSystemMediumTest {
.newScanTask(new File(projectDir, "sonar-project.properties"))
.start();
+ System.out.println(logs.getAsString());
assertThat(result.inputFiles()).hasSize(4);
assertThat(result.inputDirs()).hasSize(4);
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/SensorsExecutorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/SensorsExecutorTest.java
index 5afcb9ee1f5..dcea19af285 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/SensorsExecutorTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/SensorsExecutorTest.java
@@ -19,27 +19,30 @@
*/
package org.sonar.scanner.phases;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.io.IOException;
import java.util.Collections;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
+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.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.resources.Project;
import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
import org.sonar.scanner.events.EventBus;
import org.sonar.scanner.sensor.SensorStrategy;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class SensorsExecutorTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@@ -83,12 +86,17 @@ public class SensorsExecutorTest {
when(selector.selectSensors(any(DefaultInputModule.class), eq(false))).thenReturn(Collections.singleton(perModuleSensor));
when(selector.selectSensors(any(DefaultInputModule.class), eq(true))).thenReturn(Collections.singleton(globalSensor));
- DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule("root", temp.newFolder());
- rootModuleExecutor = new SensorsExecutor(selector, rootModule, mock(EventBus.class), strategy);
+ ProjectDefinition childDef = ProjectDefinition.create().setKey("sub").setBaseDir(temp.newFolder());
+ ProjectDefinition rootDef = ProjectDefinition.create().setKey("root").setBaseDir(temp.newFolder());
+
+ DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule(rootDef);
+ DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(childDef);
+
+ InputModuleHierarchy hierarchy = mock(InputModuleHierarchy.class);
+ when(hierarchy.isRoot(rootModule)).thenReturn(true);
- DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule("sub", temp.newFolder());
- rootModule.definition().addSubProject(subModule.definition());
- subModuleExecutor = new SensorsExecutor(selector, subModule, mock(EventBus.class), strategy);
+ rootModuleExecutor = new SensorsExecutor(selector, rootModule, hierarchy, mock(EventBus.class), strategy);
+ subModuleExecutor = new SensorsExecutor(selector, subModule, hierarchy, mock(EventBus.class), strategy);
}
@Test
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java
index 47ceca94888..9f19852e6fd 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java
@@ -26,6 +26,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.AnalysisMode;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.postjob.issue.PostJobIssue;
import org.sonar.api.batch.rule.Severity;
@@ -51,9 +52,10 @@ public class DefaultPostJobContextTest {
private AnalysisMode analysisMode;
@Before
- public void prepare() {
+ public void setUp() throws IOException {
issueCache = mock(IssueCache.class);
- componentStore = new InputComponentStore(new PathResolver());
+ DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule("foo", temp.newFolder());
+ componentStore = new InputComponentStore(new PathResolver(), rootModule);
settings = new MapSettings();
analysisMode = mock(AnalysisMode.class);
context = new DefaultPostJobContext(settings.asConfig(), settings, issueCache, componentStore, analysisMode);
@@ -85,8 +87,6 @@ public class DefaultPostJobContextTest {
assertThat(issue.inputComponent()).isNull();
String moduleKey = "foo";
- componentStore.put(TestInputFileBuilder.newDefaultInputModule("foo", temp.newFolder()));
-
componentStore.put(new TestInputFileBuilder(moduleKey, "src/Foo.php").build());
assertThat(issue.inputComponent()).isNotNull();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/profiling/PhasesSumUpTimeProfilerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/profiling/PhasesSumUpTimeProfilerTest.java
index a3d55dfa855..b2853116007 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/profiling/PhasesSumUpTimeProfilerTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/profiling/PhasesSumUpTimeProfilerTest.java
@@ -42,6 +42,7 @@ import org.sonar.api.batch.events.SensorExecutionHandler;
import org.sonar.api.batch.events.SensorExecutionHandler.SensorExecutionEvent;
import org.sonar.api.batch.events.SensorsPhaseHandler;
import org.sonar.api.batch.events.SensorsPhaseHandler.SensorsPhaseEvent;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.System2;
import org.sonar.scanner.bootstrap.GlobalProperties;
@@ -132,7 +133,7 @@ public class PhasesSumUpTimeProfilerTest {
}
private Project mockProject(String name, boolean isRoot) {
- return new Project(ProjectDefinition.create().setName(name).setKey(name));
+ return new Project(new DefaultInputModule(ProjectDefinition.create().setName(name).setKey(name)));
}
private void fakeAnalysis(PhasesSumUpTimeProfiler profiler, final Project module) {
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/AnalysisContextReportPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/AnalysisContextReportPublisherTest.java
index 3c65a91b598..77fc6206b24 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/AnalysisContextReportPublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/AnalysisContextReportPublisherTest.java
@@ -31,6 +31,8 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.AnalysisMode;
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.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
@@ -65,6 +67,7 @@ public class AnalysisContextReportPublisherTest {
private System2 system2;
private ProjectRepositories projectRepos;
private GlobalConfiguration globalSettings;
+ private InputModuleHierarchy hierarchy;
@Before
public void prepare() throws Exception {
@@ -73,7 +76,8 @@ public class AnalysisContextReportPublisherTest {
when(system2.properties()).thenReturn(new Properties());
projectRepos = mock(ProjectRepositories.class);
globalSettings = mock(GlobalConfiguration.class);
- publisher = new AnalysisContextReportPublisher(analysisMode, pluginRepo, system2, projectRepos, globalSettings);
+ hierarchy = mock(InputModuleHierarchy.class);
+ publisher = new AnalysisContextReportPublisher(analysisMode, pluginRepo, system2, projectRepos, globalSettings, hierarchy);
}
@Test
@@ -95,7 +99,7 @@ public class AnalysisContextReportPublisherTest {
ScannerReportWriter writer = new ScannerReportWriter(temp.newFolder());
publisher.init(writer);
- publisher.dumpModuleSettings(ProjectDefinition.create().setProperty("sonar.projectKey", "foo"));
+ publisher.dumpModuleSettings(new DefaultInputModule("foo"));
assertThat(writer.getFileStructure().analysisLog()).doesNotExist();
}
@@ -122,8 +126,7 @@ public class AnalysisContextReportPublisherTest {
when(projectRepos.moduleExists("foo")).thenReturn(true);
when(projectRepos.settings("foo")).thenReturn(ImmutableMap.of(COM_FOO, "bar", SONAR_SKIP, "true"));
- publisher.dumpModuleSettings(ProjectDefinition.create()
- .setProperty("sonar.projectKey", "foo"));
+ publisher.dumpModuleSettings(new DefaultInputModule("foo"));
String content = FileUtils.readFileToString(writer.getFileStructure().analysisLog());
assertThat(content).doesNotContain(COM_FOO);
@@ -144,10 +147,10 @@ public class AnalysisContextReportPublisherTest {
assertThat(content).containsOnlyOnce(COM_FOO);
assertThat(content).doesNotContain(SONAR_SKIP);
- publisher.dumpModuleSettings(ProjectDefinition.create()
+ publisher.dumpModuleSettings(new DefaultInputModule(ProjectDefinition.create()
.setProperty("sonar.projectKey", "foo")
.setProperty(COM_FOO, "bar")
- .setProperty(SONAR_SKIP, "true"));
+ .setProperty(SONAR_SKIP, "true")));
content = FileUtils.readFileToString(writer.getFileStructure().analysisLog());
assertThat(content).containsOnlyOnce(COM_FOO);
@@ -170,9 +173,9 @@ public class AnalysisContextReportPublisherTest {
assertThat(content).containsOnlyOnce(BIZ);
assertThat(content).containsSequence(BIZ, FOO);
- publisher.dumpModuleSettings(ProjectDefinition.create()
+ publisher.dumpModuleSettings(new DefaultInputModule(ProjectDefinition.create()
.setProperty("sonar.projectKey", "foo")
- .setProperty("env." + FOO, "BAR"));
+ .setProperty("env." + FOO, "BAR")));
content = FileUtils.readFileToString(writer.getFileStructure().analysisLog());
assertThat(content).containsOnlyOnce(FOO);
@@ -187,12 +190,12 @@ public class AnalysisContextReportPublisherTest {
assertThat(writer.getFileStructure().analysisLog()).exists();
- publisher.dumpModuleSettings(ProjectDefinition.create()
+ publisher.dumpModuleSettings(new DefaultInputModule(ProjectDefinition.create()
.setProperty("sonar.projectKey", "foo")
.setProperty("sonar.projectKey", "foo")
.setProperty("sonar.login", "my_token")
.setProperty("sonar.password", "azerty")
- .setProperty("sonar.cpp.license.secured", "AZERTY"));
+ .setProperty("sonar.cpp.license.secured", "AZERTY")));
assertThat(FileUtils.readFileToString(writer.getFileStructure().analysisLog())).containsSequence(
"sonar.cpp.license.secured=******",
@@ -222,14 +225,15 @@ public class AnalysisContextReportPublisherTest {
ScannerReportWriter writer = new ScannerReportWriter(temp.newFolder());
publisher.init(writer);
- ProjectDefinition module = ProjectDefinition.create()
+ DefaultInputModule module = new DefaultInputModule(ProjectDefinition.create()
.setProperty("sonar.projectKey", "foo")
- .setProperty(SONAR_SKIP, "true");
+ .setProperty(SONAR_SKIP, "true"));
- ProjectDefinition.create()
+ DefaultInputModule parent = new DefaultInputModule(ProjectDefinition.create()
.setProperty("sonar.projectKey", "parent")
- .setProperty(SONAR_SKIP, "true")
- .addSubProject(module);
+ .setProperty(SONAR_SKIP, "true"));
+
+ when(hierarchy.parent(module)).thenReturn(parent);
publisher.dumpModuleSettings(module);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java
index 5551ca8f679..395d227be62 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java
@@ -26,6 +26,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.measures.CoreMetrics;
@@ -56,8 +57,8 @@ public class CoveragePublisherTest {
public void prepare() throws IOException {
String moduleKey = "foo";
inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setLines(5).build();
- InputComponentStore componentCache = new InputComponentStore(new PathResolver());
- componentCache.put(TestInputFileBuilder.newDefaultInputModule(moduleKey, temp.newFolder()));
+ DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule(moduleKey, temp.newFolder());
+ InputComponentStore componentCache = new InputComponentStore(new PathResolver(), rootModule);
componentCache.put(inputFile);
measureCache = mock(MeasureCache.class);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java
index d3dfe4cc3e9..6f513738f45 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java
@@ -69,8 +69,7 @@ public class MeasuresPublisherTest {
String moduleKey = "foo";
inputModule = TestInputFileBuilder.newDefaultInputModule(moduleKey, temp.newFolder());
inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setPublish(true).build();
- InputComponentStore componentCache = new InputComponentStore(new PathResolver());
- componentCache.put(inputModule);
+ InputComponentStore componentCache = new InputComponentStore(new PathResolver(), inputModule);
componentCache.put(inputFile);
measureCache = mock(MeasureCache.class);
when(measureCache.byComponentKey(anyString())).thenReturn(Collections.<DefaultMeasure<?>>emptyList());
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
index e59cbd47ee4..3d3dddfe821 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
@@ -19,8 +19,15 @@
*/
package org.sonar.scanner.report;
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.io.File;
import java.util.Date;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -32,53 +39,48 @@ import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.scanner.ProjectAnalysisInfo;
+import org.sonar.scanner.cpd.CpdSettings;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.rule.ModuleQProfiles;
import org.sonar.scanner.rule.QProfile;
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class MetadataPublisherTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- private ProjectDefinition projectDef;
private DefaultInputModule rootModule;
private MetadataPublisher underTest;
private MapSettings settings;
private ModuleQProfiles qProfiles;
private ProjectAnalysisInfo projectAnalysisInfo;
+ private CpdSettings cpdSettings;
private InputModuleHierarchy inputModuleHierarchy;
@Before
public void prepare() {
- projectDef = ProjectDefinition.create().setKey("foo");
- rootModule = new DefaultInputModule(projectDef, TestInputFileBuilder.nextBatchId());
projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
+ cpdSettings = mock(CpdSettings.class);
when(projectAnalysisInfo.analysisDate()).thenReturn(new Date(1234567L));
- inputModuleHierarchy = mock(InputModuleHierarchy.class);
- when(inputModuleHierarchy.root()).thenReturn(rootModule);
settings = new MapSettings();
qProfiles = mock(ModuleQProfiles.class);
- underTest = new MetadataPublisher(projectAnalysisInfo, inputModuleHierarchy, settings.asConfig(), qProfiles);
+ createPublisher(ProjectDefinition.create().setKey("foo"));
+ }
+
+ private void createPublisher(ProjectDefinition def) {
+ rootModule = new DefaultInputModule(def, TestInputFileBuilder.nextBatchId());
+ inputModuleHierarchy = mock(InputModuleHierarchy.class);
+ when(inputModuleHierarchy.root()).thenReturn(rootModule);
+ underTest = new MetadataPublisher(projectAnalysisInfo, inputModuleHierarchy, settings.asConfig(), qProfiles, cpdSettings);
}
@Test
public void write_metadata() throws Exception {
settings.setProperty(CoreProperties.CPD_CROSS_PROJECT, "true");
Date date = new Date();
- when(qProfiles.findAll()).thenReturn(asList(new QProfile()
- .setKey("q1")
- .setName("Q1")
- .setLanguage("java")
- .setRulesUpdatedAt(date)));
+ when(qProfiles.findAll()).thenReturn(asList(new QProfile("q1", "Q1", "java", date)));
File outputDir = temp.newFolder();
ScannerReportWriter writer = new ScannerReportWriter(outputDir);
@@ -89,7 +91,6 @@ public class MetadataPublisherTest {
assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
assertThat(metadata.getProjectKey()).isEqualTo("foo");
assertThat(metadata.getProjectKey()).isEqualTo("foo");
- assertThat(metadata.getCrossProjectDuplicationActivated()).isTrue();
assertThat(metadata.getQprofilesPerLanguage()).containsOnly(entry("java", org.sonar.scanner.protocol.output.ScannerReport.Metadata.QProfile.newBuilder()
.setKey("q1")
.setName("Q1")
@@ -100,10 +101,14 @@ public class MetadataPublisherTest {
@Test
public void write_project_branch() throws Exception {
+ when(cpdSettings.isCrossProjectDuplicationEnabled()).thenReturn(false);
settings.setProperty(CoreProperties.CPD_CROSS_PROJECT, "true");
settings.setProperty(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch");
- projectDef.properties().put(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch");
- projectDef.setKey("foo");
+
+ ProjectDefinition projectDef = ProjectDefinition.create()
+ .setKey("foo")
+ .setProperty(CoreProperties.PROJECT_BRANCH_PROPERTY, "myBranch");
+ createPublisher(projectDef);
File outputDir = temp.newFolder();
ScannerReportWriter writer = new ScannerReportWriter(outputDir);
@@ -115,7 +120,6 @@ public class MetadataPublisherTest {
assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
assertThat(metadata.getProjectKey()).isEqualTo("foo");
assertThat(metadata.getBranch()).isEqualTo("myBranch");
- // Cross project duplication disabled on branches
assertThat(metadata.getCrossProjectDuplicationActivated()).isFalse();
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java
index 7b93925349e..635f15e74f5 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java
@@ -19,12 +19,21 @@
*/
package org.sonar.scanner.report;
+import static org.apache.commons.io.FileUtils.readFileToString;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import java.io.File;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -34,6 +43,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.sonar.api.CoreProperties;
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.config.PropertyDefinitions;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.platform.Server;
@@ -44,20 +55,11 @@ import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.scanner.analysis.DefaultAnalysisMode;
import org.sonar.scanner.bootstrap.ScannerWsClient;
-import org.sonar.scanner.scan.ImmutableProjectReactor;
import org.sonarqube.ws.WsCe;
import org.sonarqube.ws.client.HttpException;
import org.sonarqube.ws.client.WsRequest;
import org.sonarqube.ws.client.WsResponse;
-import static org.apache.commons.io.FileUtils.readFileToString;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
public class ReportPublisherTest {
@Rule
@@ -73,22 +75,23 @@ public class ReportPublisherTest {
MapSettings settings = new MapSettings(new PropertyDefinitions(CorePropertyDefinitions.all()));
ScannerWsClient wsClient;
Server server = mock(Server.class);
- ImmutableProjectReactor reactor = mock(ImmutableProjectReactor.class);
- ProjectDefinition root;
+ InputModuleHierarchy moduleHierarchy = mock(InputModuleHierarchy.class);
+ DefaultInputModule root;
AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);
@Before
public void setUp() {
wsClient = mock(ScannerWsClient.class, Mockito.RETURNS_DEEP_STUBS);
- root = ProjectDefinition.create().setKey("struts").setWorkDir(temp.getRoot());
- when(reactor.getRoot()).thenReturn(root);
+ root = new DefaultInputModule(ProjectDefinition.create().setKey("struts").setWorkDir(temp.getRoot()));
+ when(moduleHierarchy.root()).thenReturn(root);
when(server.getPublicRootUrl()).thenReturn("https://localhost");
when(server.getVersion()).thenReturn("6.4");
}
@Test
public void log_and_dump_information_about_report_uploading() throws IOException {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ new ReportPublisherStep[0]);
settings.setProperty(CoreProperties.PROJECT_ORGANIZATION_PROPERTY, "MyOrg");
underTest.logSuccess("TASK-123");
@@ -111,7 +114,8 @@ public class ReportPublisherTest {
@Test
public void parse_upload_error_message() throws IOException {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ new ReportPublisherStep[0]);
HttpException ex = new HttpException("url", 404, "{\"errors\":[{\"msg\":\"Organization with key 'MyOrg' does not exist\"}]}");
WsResponse response = mock(WsResponse.class);
when(response.failIfNotSuccessful()).thenThrow(ex);
@@ -125,7 +129,8 @@ public class ReportPublisherTest {
@Test
public void log_public_url_if_defined() throws IOException {
when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ new ReportPublisherStep[0]);
underTest.logSuccess("TASK-123");
@@ -146,7 +151,8 @@ public class ReportPublisherTest {
@Test
public void fail_if_public_url_malformed() throws IOException {
when(server.getPublicRootUrl()).thenReturn("invalid");
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ new ReportPublisherStep[0]);
exception.expect(MessageException.class);
exception.expectMessage("Failed to parse public URL set in SonarQube server: invalid");
@@ -155,7 +161,8 @@ public class ReportPublisherTest {
@Test
public void log_but_not_dump_information_when_report_is_not_uploaded() {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ new ReportPublisherStep[0]);
underTest.logSuccess(/* report not uploaded, no server task */null);
@@ -172,7 +179,8 @@ public class ReportPublisherTest {
settings.setProperty("sonar.batch.keepReport", true);
Path reportDir = temp.getRoot().toPath().resolve("batch-report");
Files.createDirectory(reportDir);
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ new ReportPublisherStep[0]);
underTest.start();
underTest.stop();
@@ -183,7 +191,7 @@ public class ReportPublisherTest {
public void should_delete_report_by_default() throws IOException {
Path reportDir = temp.getRoot().toPath().resolve("batch-report");
Files.createDirectory(reportDir);
- ReportPublisher job = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher job = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
job.start();
job.stop();
@@ -192,7 +200,8 @@ public class ReportPublisherTest {
@Test
public void test_ws_parameters() throws Exception {
- ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
+ ReportPublisher underTest = new ReportPublisher(settings.asConfig(), wsClient, server, contextPublisher, moduleHierarchy, mode, mock(TempFolder.class),
+ new ReportPublisherStep[0]);
settings.setProperty(CoreProperties.PROJECT_ORGANIZATION_PROPERTY, "MyOrg");
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java
index 3624dcabf65..76f0dc7aee6 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java
@@ -28,6 +28,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
@@ -55,8 +56,8 @@ public class SourcePublisherTest {
.setCharset(StandardCharsets.ISO_8859_1)
.build();
- InputComponentStore componentStore = new InputComponentStore(new PathResolver());
- componentStore.put(TestInputFileBuilder.newDefaultInputModule(moduleKey, baseDir));
+ DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule(moduleKey, baseDir);
+ InputComponentStore componentStore = new InputComponentStore(new PathResolver(), rootModule);
componentStore.put(inputFile);
publisher = new SourcePublisher(componentStore);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileTest.java
index a21efc17c55..e5fda6b88c5 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileTest.java
@@ -26,18 +26,9 @@ import static org.assertj.core.api.Assertions.assertThat;
public class QProfileTest {
@Test
public void testEquals() {
- QProfile q1 = new QProfile();
- QProfile q2 = new QProfile();
- QProfile q3 = new QProfile();
-
- q1.setKey("k1");
- q1.setName("name1");
-
- q2.setKey("k1");
- q2.setName("name2");
-
- q3.setKey("k3");
- q3.setName("name3");
+ QProfile q1 = new QProfile("k1", "name1", null, null);
+ QProfile q2 = new QProfile("k1", "name2", null, null);
+ QProfile q3 = new QProfile("k3", "name3", null, null);
assertThat(q1).isEqualTo(q2);
assertThat(q1).isNotEqualTo(q3);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java
index f68303521a5..cd5b36636f4 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java
@@ -50,9 +50,9 @@ public class QProfileVerifierTest {
public void before() throws Exception {
fs = new DefaultFileSystem(temp.newFolder().toPath());
profiles = mock(ModuleQProfiles.class);
- QProfile javaProfile = new QProfile().setKey("p1").setName("My Java profile").setLanguage("java");
+ QProfile javaProfile = new QProfile("p1", "My Java profile", "java", null);
when(profiles.findByLanguage("java")).thenReturn(javaProfile);
- QProfile cobolProfile = new QProfile().setKey("p2").setName("My Cobol profile").setLanguage("cobol");
+ QProfile cobolProfile = new QProfile("p2", "My Cobol profile", "cobol", null);
when(profiles.findByLanguage("cobol")).thenReturn(cobolProfile);
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/RulesProfileProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/RulesProfileProviderTest.java
index 8dff3fadef3..2df62b25272 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/RulesProfileProviderTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/RulesProfileProviderTest.java
@@ -39,7 +39,7 @@ public class RulesProfileProviderTest {
@Test
public void merge_profiles() {
- QProfile qProfile = new QProfile().setKey("java-sw").setName("Sonar way").setLanguage("java");
+ QProfile qProfile = new QProfile("java-sw", "Sonar way", "java", null);
when(qProfiles.findAll()).thenReturn(Arrays.asList(qProfile));
RulesProfile profile = provider.provide(qProfiles, new ActiveRulesBuilder().build(), settings.asConfig());
@@ -61,7 +61,7 @@ public class RulesProfileProviderTest {
public void keep_compatibility_with_single_language_projects() {
settings.setProperty("sonar.language", "java");
- QProfile qProfile = new QProfile().setKey("java-sw").setName("Sonar way").setLanguage("java");
+ QProfile qProfile = new QProfile("java-sw", "Sonar way", "java", null);
when(qProfiles.findByLanguage("java")).thenReturn(qProfile);
RulesProfile profile = provider.provide(qProfiles, new ActiveRulesBuilder().build(), settings.asConfig());
@@ -74,7 +74,7 @@ public class RulesProfileProviderTest {
@Test
public void support_rule_templates() {
- QProfile qProfile = new QProfile().setKey("java-sw").setName("Sonar way").setLanguage("java");
+ QProfile qProfile = new QProfile("java-sw", "Sonar way", "java", null);
when(qProfiles.findAll()).thenReturn(Arrays.asList(qProfile));
ActiveRulesBuilder activeRulesBuilder = new ActiveRulesBuilder();
activeRulesBuilder.create(RuleKey.of("java", "S001")).setTemplateRuleKey("T001").setLanguage("java").activate();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/DefaultInputModuleHierarchyTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/DefaultInputModuleHierarchyTest.java
index be0f7773038..977fdc6a67c 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/DefaultInputModuleHierarchyTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/DefaultInputModuleHierarchyTest.java
@@ -19,20 +19,17 @@
*/
package org.sonar.scanner.scan;
-import org.junit.Before;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.HashMap;
+import java.util.Map;
+
import org.junit.Test;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import static org.assertj.core.api.Assertions.assertThat;
-
public class DefaultInputModuleHierarchyTest {
private DefaultInputModuleHierarchy moduleHierarchy;
- @Before
- public void setUp() {
- moduleHierarchy = new DefaultInputModuleHierarchy();
- }
-
@Test
public void test() {
DefaultInputModule root = new DefaultInputModule("root");
@@ -41,11 +38,14 @@ public class DefaultInputModuleHierarchyTest {
DefaultInputModule mod3 = new DefaultInputModule("mod3");
DefaultInputModule mod4 = new DefaultInputModule("mod4");
- moduleHierarchy.setRoot(root);
- moduleHierarchy.index(mod1, root);
- moduleHierarchy.index(mod2, mod1);
- moduleHierarchy.index(mod3, root);
- moduleHierarchy.index(mod4, root);
+ Map<DefaultInputModule, DefaultInputModule> parents = new HashMap<>();
+
+ parents.put(mod1, root);
+ parents.put(mod2, mod1);
+ parents.put(mod3, root);
+ parents.put(mod4, root);
+
+ moduleHierarchy = new DefaultInputModuleHierarchy(parents);
assertThat(moduleHierarchy.children(root)).containsOnly(mod1, mod3, mod4);
assertThat(moduleHierarchy.children(mod4)).isEmpty();
@@ -58,4 +58,28 @@ public class DefaultInputModuleHierarchyTest {
assertThat(moduleHierarchy.root()).isEqualTo(root);
}
+
+ @Test
+ public void testOnlyRoot() {
+ DefaultInputModule root = new DefaultInputModule("root");
+ moduleHierarchy = new DefaultInputModuleHierarchy(root);
+
+ assertThat(moduleHierarchy.children(root)).isEmpty();
+ assertThat(moduleHierarchy.parent(root)).isNull();
+ assertThat(moduleHierarchy.root()).isEqualTo(root);
+ }
+
+ @Test
+ public void testParentChild() {
+ DefaultInputModule root = new DefaultInputModule("root");
+ DefaultInputModule mod1 = new DefaultInputModule("mod1");
+ moduleHierarchy = new DefaultInputModuleHierarchy(root, mod1);
+
+ assertThat(moduleHierarchy.children(root)).containsOnly(mod1);
+ assertThat(moduleHierarchy.children(mod1)).isEmpty();
+
+ assertThat(moduleHierarchy.parent(mod1)).isEqualTo(root);
+ assertThat(moduleHierarchy.parent(root)).isNull();
+ assertThat(moduleHierarchy.root()).isEqualTo(root);
+ }
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java
index 74faa55f153..63bd38a6ada 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java
@@ -19,48 +19,63 @@
*/
package org.sonar.scanner.scan;
-import org.junit.Before;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
import org.junit.Test;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class ModuleIndexerTest {
private ModuleIndexer indexer;
private DefaultComponentTree tree;
private DefaultInputModuleHierarchy moduleHierarchy;
- private ImmutableProjectReactor reactor;
private InputComponentStore componentStore;
- @Before
- public void setUp() {
- reactor = mock(ImmutableProjectReactor.class);
- componentStore = new InputComponentStore(new PathResolver());
+ public void createIndexer(DefaultInputModule rootModule) {
+ componentStore = new InputComponentStore(new PathResolver(), rootModule);
tree = new DefaultComponentTree();
- moduleHierarchy = new DefaultInputModuleHierarchy();
- indexer = new ModuleIndexer(reactor, tree, componentStore, new BatchIdGenerator(), moduleHierarchy);
+ moduleHierarchy = mock(DefaultInputModuleHierarchy.class);
+ indexer = new ModuleIndexer(tree, componentStore, moduleHierarchy);
}
-
+
@Test
public void testIndex() {
- ProjectDefinition root = ProjectDefinition.create().setKey("root");
- ProjectDefinition mod1 = ProjectDefinition.create().setKey("mod1");
- ProjectDefinition mod2 = ProjectDefinition.create().setKey("mod2");
- ProjectDefinition mod3 = ProjectDefinition.create().setKey("mod3");
- ProjectDefinition mod4 = ProjectDefinition.create().setKey("mod4");
+ ProjectDefinition rootDef = mock(ProjectDefinition.class);
+ ProjectDefinition def = mock(ProjectDefinition.class);
+ when(rootDef.getParent()).thenReturn(null);
+ when(def.getParent()).thenReturn(rootDef);
+
+ DefaultInputModule root = mock(DefaultInputModule.class);
+ DefaultInputModule mod1 = mock(DefaultInputModule.class);
+ DefaultInputModule mod2 = mock(DefaultInputModule.class);
+ DefaultInputModule mod3 = mock(DefaultInputModule.class);
+
+ when(root.key()).thenReturn("root");
+ when(mod1.key()).thenReturn("mod1");
+ when(mod2.key()).thenReturn("mod2");
+ when(mod3.key()).thenReturn("mod3");
+
+ when(root.getKeyWithBranch()).thenReturn("root");
+ when(mod1.getKeyWithBranch()).thenReturn("mod1");
+ when(mod2.getKeyWithBranch()).thenReturn("mod2");
+ when(mod3.getKeyWithBranch()).thenReturn("mod3");
+
+ when(root.definition()).thenReturn(rootDef);
+ when(mod1.definition()).thenReturn(def);
+ when(mod2.definition()).thenReturn(def);
+ when(mod3.definition()).thenReturn(def);
- root.addSubProject(mod1);
- mod1.addSubProject(mod2);
- root.addSubProject(mod3);
- root.addSubProject(mod4);
+ createIndexer(root);
+ when(moduleHierarchy.root()).thenReturn(root);
+ when(moduleHierarchy.children(root)).thenReturn(Arrays.asList(mod1, mod2, mod3));
- when(reactor.getRoot()).thenReturn(root);
indexer.start();
InputModule rootModule = moduleHierarchy.root();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectLockTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectLockTest.java
index cd628bbe8f4..af46b5edd7b 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectLockTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectLockTest.java
@@ -19,22 +19,23 @@
*/
package org.sonar.scanner.scan;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-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.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.home.cache.DirectoryLock;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class ProjectLockTest {
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
@@ -49,12 +50,12 @@ public class ProjectLockTest {
}
private ProjectLock setUpTest(File file) {
- ProjectReactor projectReactor = mock(ProjectReactor.class);
- ProjectDefinition projectDefinition = mock(ProjectDefinition.class);
- when(projectReactor.getRoot()).thenReturn(projectDefinition);
- when(projectDefinition.getWorkDir()).thenReturn(file);
+ InputModuleHierarchy hierarchy = mock(InputModuleHierarchy.class);
+ DefaultInputModule root = mock(DefaultInputModule.class);
+ when(hierarchy.root()).thenReturn(root);
+ when(root.getWorkDir()).thenReturn(file);
- return new ProjectLock(projectReactor);
+ return new ProjectLock(hierarchy);
}
@Test
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java
index 9f7833fbc75..24fa9205c37 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java
@@ -19,6 +19,9 @@
*/
package org.sonar.scanner.scan;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -26,28 +29,21 @@ import org.junit.rules.ExpectedException;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
-import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.analysis.DefaultAnalysisMode;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class ProjectReactorValidatorTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
private ProjectReactorValidator validator;
- private Settings settings;
private DefaultAnalysisMode mode;
@Before
public void prepare() {
mode = mock(DefaultAnalysisMode.class);
- settings = new MapSettings();
- validator = new ProjectReactorValidator(settings, mode);
+ validator = new ProjectReactorValidator(mode);
}
@Test
@@ -62,12 +58,12 @@ public class ProjectReactorValidatorTest {
validator.validate(createProjectReactor("3-3"));
validator.validate(createProjectReactor("-:"));
}
-
+
@Test
public void allow_slash_issues_mode() {
when(mode.isIssues()).thenReturn(true);
validator.validate(createProjectReactor("project/key"));
-
+
when(mode.isIssues()).thenReturn(false);
thrown.expect(MessageException.class);
thrown.expectMessage("is not a valid project or module key");
@@ -157,16 +153,6 @@ public class ProjectReactorValidatorTest {
validator.validate(reactor);
}
- @Test
- public void fail_with_deprecated_sonar_phase() {
- ProjectReactor reactor = createProjectReactor("foo");
- settings.setProperty("sonar.phase", "phase");
-
- thrown.expect(MessageException.class);
- thrown.expectMessage("\"sonar.phase\" is deprecated");
- validator.validate(reactor);
- }
-
private ProjectReactor createProjectReactor(String projectKey) {
ProjectDefinition def = ProjectDefinition.create().setProperty(CoreProperties.PROJECT_KEY_PROPERTY, projectKey);
ProjectReactor reactor = new ProjectReactor(def);
@@ -177,9 +163,7 @@ public class ProjectReactorValidatorTest {
ProjectDefinition def = ProjectDefinition.create()
.setProperty(CoreProperties.PROJECT_KEY_PROPERTY, projectKey)
.setProperty(CoreProperties.PROJECT_BRANCH_PROPERTY, branch);
- ProjectReactor reactor = new ProjectReactor(def);
- settings.setProperty(CoreProperties.PROJECT_BRANCH_PROPERTY, branch);
- return reactor;
+ return new ProjectReactor(def);
}
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoryCleanerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoryCleanerTest.java
index 58b4acc2823..aa824ab9abc 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoryCleanerTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoryCleanerTest.java
@@ -19,20 +19,21 @@
*/
package org.sonar.scanner.scan;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.io.File;
import java.io.IOException;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-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.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.home.cache.DirectoryLock;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class WorkDirectoryCleanerTest {
private WorkDirectoryCleaner cleaner;
@Rule
@@ -50,21 +51,21 @@ public class WorkDirectoryCleanerTest {
lock.createNewFile();
// mock project
- ProjectReactor projectReactor = mock(ProjectReactor.class);
- ProjectDefinition projectDefinition = mock(ProjectDefinition.class);
- when(projectReactor.getRoot()).thenReturn(projectDefinition);
- when(projectDefinition.getWorkDir()).thenReturn(temp.getRoot());
+ InputModuleHierarchy hierarchy = mock(InputModuleHierarchy.class);
+ DefaultInputModule root = mock(DefaultInputModule.class);
+ when(hierarchy.root()).thenReturn(root);
+ when(root.getWorkDir()).thenReturn(temp.getRoot());
assertThat(temp.getRoot().list().length).isGreaterThan(1);
- cleaner = new WorkDirectoryCleaner(projectReactor);
+ cleaner = new WorkDirectoryCleaner(hierarchy);
}
-
+
@Test
public void testNonExisting() {
temp.delete();
cleaner.execute();
}
-
+
@Test
public void testClean() {
File lock = new File(temp.getRoot(), DirectoryLock.LOCK_FILE_NAME);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ExclusionFiltersTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ExclusionFiltersTest.java
index 9815f2de7f2..f64a6729750 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ExclusionFiltersTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ExclusionFiltersTest.java
@@ -19,9 +19,12 @@
*/
package org.sonar.scanner.scan.filesystem;
+import static org.assertj.core.api.Assertions.assertThat;
+
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -33,8 +36,6 @@ import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.scan.filesystem.FileExclusions;
-import static org.assertj.core.api.Assertions.assertThat;
-
public class ExclusionFiltersTest {
@Rule
@@ -53,7 +54,8 @@ public class ExclusionFiltersTest {
@Test
public void no_inclusions_nor_exclusions() throws IOException {
filter.prepare();
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java");
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isTrue();
assertThat(filter.accept(indexedFile, InputFile.Type.TEST)).isTrue();
}
@@ -63,10 +65,10 @@ public class ExclusionFiltersTest {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java");
filter.prepare();
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java");
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isTrue();
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java");
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isFalse();
}
@@ -75,10 +77,10 @@ public class ExclusionFiltersTest {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java,**/*Dto.java");
filter.prepare();
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java");
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isFalse();
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDto.java");
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDto.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isTrue();
}
@@ -89,14 +91,14 @@ public class ExclusionFiltersTest {
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.java");
filter.prepare();
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java");
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isFalse();
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java");
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isTrue();
// source exclusions do not apply to tests
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/test/java/com/mycompany/FooDao.java");
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/test/java/com/mycompany/FooDao.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.TEST)).isTrue();
}
@@ -108,10 +110,10 @@ public class ExclusionFiltersTest {
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getAbsolutePath());
filter.prepare();
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java");
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isTrue();
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Bar.java");
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Bar.java", null);
assertThat(filter.accept(indexedFile, InputFile.Type.MAIN)).isFalse();
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java
index 6bff097acf3..9a82a623f55 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java
@@ -27,6 +27,7 @@ import java.util.List;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Status;
import org.sonar.api.batch.fs.InputFile.Type;
@@ -44,16 +45,20 @@ public class InputComponentStoreTest {
@Test
public void should_add_input_file() throws Exception {
- InputComponentStore cache = new InputComponentStore(new PathResolver());
-
String rootModuleKey = "struts";
+ String subModuleKey = "struts-core";
+
File rootBaseDir = temp.newFolder();
- DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule(rootModuleKey, rootBaseDir);
- cache.put(rootModule);
- String subModuleKey = "struts-core";
- DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(subModuleKey, temp.newFolder());
- rootModule.definition().addSubProject(subModule.definition());
+ ProjectDefinition moduleDef = ProjectDefinition.create()
+ .setKey(subModuleKey).setBaseDir(rootBaseDir);
+ ProjectDefinition rootDef = ProjectDefinition.create()
+ .setKey(rootModuleKey).setBaseDir(rootBaseDir).addSubProject(moduleDef);
+
+ DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule(rootDef);
+ DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(moduleDef);
+
+ InputComponentStore cache = new InputComponentStore(new PathResolver(), rootModule);
cache.put(subModule);
DefaultInputFile fooFile = new TestInputFileBuilder(rootModuleKey, "src/main/java/Foo.java")
@@ -97,9 +102,7 @@ public class InputComponentStoreTest {
static class InputComponentStoreTester extends InputComponentStore {
InputComponentStoreTester() throws IOException {
- super(new PathResolver());
- DefaultInputModule root = TestInputFileBuilder.newDefaultInputModule("root", temp.newFolder());
- put(root);
+ super(new PathResolver(), TestInputFileBuilder.newDefaultInputModule("root", temp.newFolder()));
}
InputFile addFile(String moduleKey, String relpath, String language) {
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/LanguageDetectionTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/LanguageDetectionTest.java
index 86d33bb6660..1d8f553d1f5 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/LanguageDetectionTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/LanguageDetectionTest.java
@@ -19,15 +19,19 @@
*/
package org.sonar.scanner.scan.filesystem;
+import static junit.framework.Assert.fail;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
+
import java.io.File;
import java.io.IOException;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
@@ -35,10 +39,6 @@ import org.sonar.api.utils.MessageException;
import org.sonar.scanner.repository.language.DefaultLanguagesRepository;
import org.sonar.scanner.repository.language.LanguagesRepository;
-import static junit.framework.Assert.fail;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.spy;
-
public class LanguageDetectionTest {
@Rule
@@ -67,23 +67,23 @@ public class LanguageDetectionTest {
LanguagesRepository languages = new DefaultLanguagesRepository(new Languages(new MockLanguage("java", "java", "jav"), new MockLanguage("cobol", "cbl", "cob")));
LanguageDetection detection = new LanguageDetection(settings.asConfig(), languages);
- assertThat(detection.language(newIndexedFile("Foo.java"))).isEqualTo("java");
- assertThat(detection.language(newIndexedFile("src/Foo.java"))).isEqualTo("java");
- assertThat(detection.language(newIndexedFile("Foo.JAVA"))).isEqualTo("java");
- assertThat(detection.language(newIndexedFile("Foo.jav"))).isEqualTo("java");
- assertThat(detection.language(newIndexedFile("Foo.Jav"))).isEqualTo("java");
+ assertThat(detectLanguage(detection, "Foo.java")).isEqualTo("java");
+ assertThat(detectLanguage(detection, "src/Foo.java")).isEqualTo("java");
+ assertThat(detectLanguage(detection, "Foo.JAVA")).isEqualTo("java");
+ assertThat(detectLanguage(detection, "Foo.jav")).isEqualTo("java");
+ assertThat(detectLanguage(detection, "Foo.Jav")).isEqualTo("java");
- assertThat(detection.language(newIndexedFile("abc.cbl"))).isEqualTo("cobol");
- assertThat(detection.language(newIndexedFile("abc.CBL"))).isEqualTo("cobol");
+ assertThat(detectLanguage(detection, "abc.cbl")).isEqualTo("cobol");
+ assertThat(detectLanguage(detection, "abc.CBL")).isEqualTo("cobol");
- assertThat(detection.language(newIndexedFile("abc.php"))).isNull();
- assertThat(detection.language(newIndexedFile("abc"))).isNull();
+ assertThat(detectLanguage(detection, "abc.php")).isNull();
+ assertThat(detectLanguage(detection, "abc")).isNull();
}
@Test
public void should_not_fail_if_no_language() throws Exception {
LanguageDetection detection = spy(new LanguageDetection(settings.asConfig(), new DefaultLanguagesRepository(new Languages())));
- assertThat(detection.language(newIndexedFile("Foo.java"))).isNull();
+ assertThat(detectLanguage(detection, "Foo.java")).isNull();
}
@Test
@@ -91,7 +91,7 @@ public class LanguageDetectionTest {
LanguagesRepository languages = new DefaultLanguagesRepository(new Languages(new MockLanguage("abap", "abap", "ABAP")));
LanguageDetection detection = new LanguageDetection(settings.asConfig(), languages);
- assertThat(detection.language(newIndexedFile("abc.abap"))).isEqualTo("abap");
+ assertThat(detectLanguage(detection, "abc.abap")).isEqualTo("abap");
}
@Test
@@ -102,15 +102,15 @@ public class LanguageDetectionTest {
// No side-effect on non-ABAP projects
LanguageDetection detection = new LanguageDetection(settings.asConfig(), languages);
- assertThat(detection.language(newIndexedFile("abc"))).isNull();
- assertThat(detection.language(newIndexedFile("abc.abap"))).isNull();
- assertThat(detection.language(newIndexedFile("abc.java"))).isEqualTo("java");
+ assertThat(detectLanguage(detection, "abc")).isNull();
+ assertThat(detectLanguage(detection, "abc.abap")).isNull();
+ assertThat(detectLanguage(detection, "abc.java")).isEqualTo("java");
settings.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "abap");
detection = new LanguageDetection(settings.asConfig(), languages);
- assertThat(detection.language(newIndexedFile("abc"))).isEqualTo("abap");
- assertThat(detection.language(newIndexedFile("abc.txt"))).isEqualTo("abap");
- assertThat(detection.language(newIndexedFile("abc.java"))).isEqualTo("abap");
+ assertThat(detectLanguage(detection, "abc")).isEqualTo("abap");
+ assertThat(detectLanguage(detection, "abc.txt")).isEqualTo("abap");
+ assertThat(detectLanguage(detection, "abc.java")).isEqualTo("abap");
}
@Test
@@ -119,10 +119,10 @@ public class LanguageDetectionTest {
settings.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "java");
LanguageDetection detection = new LanguageDetection(settings.asConfig(), languages);
- assertThat(detection.language(newIndexedFile("abc"))).isNull();
- assertThat(detection.language(newIndexedFile("abc.php"))).isNull();
- assertThat(detection.language(newIndexedFile("abc.java"))).isEqualTo("java");
- assertThat(detection.language(newIndexedFile("src/abc.java"))).isEqualTo("java");
+ assertThat(detectLanguage(detection, "abc")).isNull();
+ assertThat(detectLanguage(detection, "abc.php")).isNull();
+ assertThat(detectLanguage(detection, "abc.java")).isEqualTo("java");
+ assertThat(detectLanguage(detection, "src/abc.java")).isEqualTo("java");
}
@Test
@@ -140,7 +140,7 @@ public class LanguageDetectionTest {
LanguagesRepository languages = new DefaultLanguagesRepository(new Languages(new MockLanguage("xml", "xhtml"), new MockLanguage("web", "xhtml")));
LanguageDetection detection = new LanguageDetection(settings.asConfig(), languages);
try {
- detection.language(newIndexedFile("abc.xhtml"));
+ detectLanguage(detection, "abc.xhtml");
fail();
} catch (MessageException e) {
assertThat(e.getMessage())
@@ -157,8 +157,8 @@ public class LanguageDetectionTest {
settings.setProperty("sonar.lang.patterns.xml", "xml/**");
settings.setProperty("sonar.lang.patterns.web", "web/**");
LanguageDetection detection = new LanguageDetection(settings.asConfig(), languages);
- assertThat(detection.language(newIndexedFile("xml/abc.xhtml"))).isEqualTo("xml");
- assertThat(detection.language(newIndexedFile("web/abc.xhtml"))).isEqualTo("web");
+ assertThat(detectLanguage(detection, "xml/abc.xhtml")).isEqualTo("xml");
+ assertThat(detectLanguage(detection, "web/abc.xhtml")).isEqualTo("web");
}
@Test
@@ -169,10 +169,10 @@ public class LanguageDetectionTest {
LanguageDetection detection = new LanguageDetection(settings.asConfig(), languages);
- assertThat(detection.language(newIndexedFile("abc.abap"))).isEqualTo("abap");
- assertThat(detection.language(newIndexedFile("abc.cobol"))).isEqualTo("cobol");
+ assertThat(detectLanguage(detection, "abc.abap")).isEqualTo("abap");
+ assertThat(detectLanguage(detection, "abc.cobol")).isEqualTo("cobol");
try {
- detection.language(newIndexedFile("abc.txt"));
+ detectLanguage(detection, "abc.txt");
fail();
} catch (MessageException e) {
assertThat(e.getMessage())
@@ -182,9 +182,8 @@ public class LanguageDetectionTest {
}
}
- private DefaultIndexedFile newIndexedFile(String path) throws IOException {
- File basedir = temp.newFolder();
- return new DefaultIndexedFile("foo", basedir.toPath(), path);
+ private String detectLanguage(LanguageDetection detection, String path) {
+ return detection.language(new File(temp.getRoot(), path).getAbsolutePath(), path);
}
static class MockLanguage implements Language {
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializerTest.java
index 4790f48ae6e..454223ad846 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializerTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleFileSystemInitializerTest.java
@@ -19,8 +19,12 @@
*/
package org.sonar.scanner.scan.filesystem;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
import java.io.File;
import java.io.IOException;
+
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.junit.Rule;
@@ -30,9 +34,6 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.api.utils.TempFolder;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
public class ModuleFileSystemInitializerTest {
@Rule
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java
index cb018de8258..8451685ee3c 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java
@@ -26,6 +26,7 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.scanner.sensor.SensorStrategy;
@@ -46,8 +47,8 @@ public class ModuleInputComponentStoreTest {
@Before
public void setUp() throws IOException {
- componentStore = new InputComponentStore(new PathResolver());
- componentStore.put(TestInputFileBuilder.newDefaultInputModule(moduleKey, temp.newFolder()));
+ DefaultInputModule root = TestInputFileBuilder.newDefaultInputModule(moduleKey, temp.newFolder());
+ componentStore = new InputComponentStore(new PathResolver(), root);
}
@Test
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java
index 926b149ef3e..42d4c443c72 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java
@@ -19,6 +19,12 @@
*/
package org.sonar.scanner.scan.report;
+import static net.javacrumbs.jsonunit.assertj.JsonAssert.assertThatJson;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
@@ -26,6 +32,7 @@ import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.TimeZone;
+
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -51,12 +58,6 @@ import org.sonar.scanner.issue.tracking.TrackedIssue;
import org.sonar.scanner.scan.DefaultComponentTree;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
-import static net.javacrumbs.jsonunit.assertj.JsonAssert.assertThatJson;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
public class JSONReportTest {
private SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
@@ -80,10 +81,11 @@ public class JSONReportTest {
SIMPLE_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+02:00"));
when(server.getVersion()).thenReturn("3.6");
- InputComponentStore inputComponentStore = new InputComponentStore(new PathResolver());
DefaultComponentTree inputComponentTree = new DefaultComponentTree();
- DefaultInputModule rootModule = new DefaultInputModule(ProjectDefinition.create().setBaseDir(projectBaseDir).setKey("struts"), 1);
- inputComponentStore.put(rootModule);
+ ProjectDefinition def = ProjectDefinition.create().setBaseDir(projectBaseDir).setKey("struts");
+ DefaultInputModule rootModule = new DefaultInputModule(def, 1);
+ InputComponentStore inputComponentStore = new InputComponentStore(new PathResolver(), rootModule);
+
DefaultInputModule moduleA = new DefaultInputModule("struts-core");
inputComponentTree.index(moduleA, rootModule);
DefaultInputModule moduleB = new DefaultInputModule("struts-ui");
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/coverage/CoverageExclusionsTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/coverage/CoverageExclusionsTest.java
index 7eafee529ef..e5d5d91a7a2 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/coverage/CoverageExclusionsTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/coverage/CoverageExclusionsTest.java
@@ -37,14 +37,13 @@ public class CoverageExclusionsTest {
@Before
public void prepare() {
settings = new MapSettings(new PropertyDefinitions(ExclusionProperties.all()));
- coverageExclusions = new CoverageExclusions(settings.asConfig());
}
@Test
public void shouldExcludeFileBasedOnPattern() {
InputFile file = new TestInputFileBuilder("foo", "src/org/polop/File.php").build();
settings.setProperty("sonar.coverage.exclusions", "src/org/polop/*");
- coverageExclusions.initPatterns();
+ coverageExclusions = new CoverageExclusions(settings.asConfig());
assertThat(coverageExclusions.isExcluded(file)).isTrue();
}
@@ -52,7 +51,7 @@ public class CoverageExclusionsTest {
public void shouldNotExcludeFileBasedOnPattern() {
InputFile file = new TestInputFileBuilder("foo", "src/org/polop/File.php").build();
settings.setProperty("sonar.coverage.exclusions", "src/org/other/*");
- coverageExclusions.initPatterns();
+ coverageExclusions = new CoverageExclusions(settings.asConfig());
assertThat(coverageExclusions.isExcluded(file)).isFalse();
}
}
diff --git a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java
index f61d225128d..e8468cc79d3 100644
--- a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java
+++ b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java
@@ -21,9 +21,12 @@ package org.sonar.scanner.protocol.output;
import java.io.File;
+import javax.annotation.concurrent.Immutable;
+
/**
* Structure of files in the zipped report
*/
+@Immutable
public class FileStructure {
public enum Domain {
diff --git a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java
index 9cca4f6d5ca..9ce6547ff52 100644
--- a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java
+++ b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java
@@ -23,9 +23,13 @@ import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
+
+import javax.annotation.concurrent.Immutable;
+
import org.sonar.core.util.ContextException;
import org.sonar.core.util.Protobuf;
+@Immutable
public class ScannerReportWriter {
private final FileStructure fileStructure;