]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11508, SONAR-11484 Index files at project level
authorJulien HENRY <julien.henry@sonarsource.com>
Mon, 26 Nov 2018 15:36:06 +0000 (16:36 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 16 Jan 2019 08:43:03 +0000 (09:43 +0100)
35 files changed:
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFileFilter.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileExclusions.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractModulePhaseExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfileVerifier.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ExclusionFilters.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleExclusionFilters.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFilters.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ExclusionFiltersTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputFileBuilderTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java

index 49d6ceee2dc186b75ddd786905c000ebc73421cb..4535e4652476768de2e6127781648e433fbd137d 100644 (file)
 package org.sonar.api.batch.fs;
 
 import org.sonar.api.ExtensionPoint;
-import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.scanner.ScannerSide;
 import org.sonarsource.api.sonarlint.SonarLintSide;
 
 /**
  * Extension point to exclude some files from inspection
  * @since 4.2
+ * @since 7.6 evaluated at project level
  */
 @ScannerSide
 @SonarLintSide
index 3b52498ceafeeab26618d6bddffd7a3e5d30286c..bda14d89d4bfc2eb61084e55df238d56534f889d 100644 (file)
@@ -26,11 +26,8 @@ import java.io.InputStreamReader;
 import java.io.Reader;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
-
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
-
-import org.sonar.api.batch.ScannerSide;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
 import org.sonar.api.batch.fs.internal.charhandler.FileHashComputer;
@@ -42,7 +39,6 @@ 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 char LINE_FEED = '\n';
index e98b77161d41cd5f741d4372591834fa6b2bc8e6..35753e14fceb840fec23c5a97025c4b29b26dd57 100644 (file)
@@ -37,10 +37,11 @@ import org.sonar.api.config.Configuration;
 @Deprecated
 @ScannerSide
 public class FileExclusions {
-  private final Configuration settings;
 
-  public FileExclusions(Configuration settings) {
-    this.settings = settings;
+  private final Configuration config;
+
+  public FileExclusions(Configuration config) {
+    this.config = config;
   }
 
   public String[] sourceInclusions() {
@@ -52,7 +53,7 @@ public class FileExclusions {
   }
 
   private String[] inclusions(String propertyKey) {
-    return Arrays.stream(settings.getStringArray(propertyKey))
+    return Arrays.stream(config.getStringArray(propertyKey))
       .map(StringUtils::trim)
       .filter(s -> !"**/*".equals(s))
       .filter(s -> !"file:**/*".equals(s))
@@ -68,8 +69,8 @@ public class FileExclusions {
   }
 
   private String[] exclusions(String globalExclusionsProperty, String exclusionsProperty) {
-    String[] globalExclusions = settings.getStringArray(globalExclusionsProperty);
-    String[] exclusions = settings.getStringArray(exclusionsProperty);
+    String[] globalExclusions = config.getStringArray(globalExclusionsProperty);
+    String[] exclusions = config.getStringArray(exclusionsProperty);
     return Stream.concat(Arrays.stream(globalExclusions), Arrays.stream(exclusions))
       .map(StringUtils::trim)
       .toArray(String[]::new);
index db9b8f25f6e2c4bfec0f5b452838e9c206806f95..5daf24c6075cc9798ace1a6b8857a8be619041e1 100644 (file)
@@ -25,15 +25,15 @@ import java.util.List;
 import java.util.Set;
 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.charhandler.CharHandler;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
 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;
 
 public class IssueExclusionsRegexpScanner extends CharHandler {
-  private static final Logger LOG = LoggerFactory.getLogger(IssueExclusionsLoader.class);
+  private static final Logger LOG = Loggers.get(IssueExclusionsLoader.class);
 
   private final StringBuilder sb = new StringBuilder();
   private final List<Pattern> allFilePatterns;
index 7e3b1c3841440484c0f8bacaaf9b6284da419635..0737c2e594f77c5c93363ee660e5c95263509dbf 100644 (file)
@@ -22,17 +22,15 @@ package org.sonar.scanner.phases;
 import java.util.Arrays;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
 import org.sonar.api.notifications.AnalysisWarnings;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.rule.QProfileVerifier;
 import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
 
 public abstract class AbstractModulePhaseExecutor {
 
@@ -41,26 +39,22 @@ public abstract class AbstractModulePhaseExecutor {
   private final PostJobsExecutor postJobsExecutor;
   private final SensorsExecutor sensorsExecutor;
   private final DefaultModuleFileSystem fs;
-  private final QProfileVerifier profileVerifier;
   private final IssueExclusionsLoader issueExclusionsLoader;
   private final InputModuleHierarchy hierarchy;
-  private final FileIndexer fileIndexer;
   private final ModuleCoverageExclusions moduleCoverageExclusions;
   private final ProjectCoverageExclusions projectCoverageExclusions;
   private final AnalysisWarnings analysisWarnings;
   private boolean warnCoverageAlreadyLogged;
 
   public AbstractModulePhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, InputModuleHierarchy hierarchy, DefaultModuleFileSystem fs,
-                                     QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, FileIndexer fileIndexer,
+                                     IssueExclusionsLoader issueExclusionsLoader,
                                      ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
                                      AnalysisWarnings analysisWarnings) {
     this.postJobsExecutor = postJobsExecutor;
     this.sensorsExecutor = sensorsExecutor;
     this.fs = fs;
-    this.profileVerifier = profileVerifier;
     this.issueExclusionsLoader = issueExclusionsLoader;
     this.hierarchy = hierarchy;
-    this.fileIndexer = fileIndexer;
     this.moduleCoverageExclusions = moduleCoverageExclusions;
     this.projectCoverageExclusions = projectCoverageExclusions;
     this.analysisWarnings = analysisWarnings;
@@ -70,15 +64,6 @@ public abstract class AbstractModulePhaseExecutor {
    * Executed on each module
    */
   public final void execute(DefaultInputModule module) {
-    // Index the filesystem
-    fileIndexer.index();
-
-    // Log detected languages and their profiles after FS is indexed and languages detected
-    profileVerifier.execute();
-
-    // Initialize issue exclusions
-    initIssueExclusions();
-
     // Initialize coverage exclusions
     evaluateCoverageExclusions(module);
 
@@ -133,11 +118,4 @@ public abstract class AbstractModulePhaseExecutor {
 
   protected abstract void executeOnRoot();
 
-  private void initIssueExclusions() {
-    if (issueExclusionsLoader.shouldExecute()) {
-      for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
-        issueExclusionsLoader.addMulticriteriaPatterns(((DefaultInputFile) inputFile).getModuleRelativePath(), inputFile.key());
-      }
-    }
-  }
 }
index 5f1058bd92058f1537c331380323c1205a75008c..9c7e956364c88976179a3aa141051c36daf49246 100644 (file)
@@ -25,9 +25,7 @@ import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
 import org.sonar.api.notifications.AnalysisWarnings;
 import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 import org.sonar.scanner.issue.tracking.IssueTransition;
-import org.sonar.scanner.rule.QProfileVerifier;
 import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
 import org.sonar.scanner.scan.report.IssuesReports;
 
 public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor {
@@ -38,11 +36,11 @@ public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor {
   private final IssueTransition localIssueTracking;
 
   public IssuesPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
-                             IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
-                             IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy, FileIndexer fileIndexer,
-                             ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
-                             AnalysisWarnings analysisWarnings) {
-    super(postJobsExecutor, sensorsExecutor, moduleHierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer,
+    IssuesReports jsonReport, DefaultModuleFileSystem fs,
+    IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy,
+    ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
+    AnalysisWarnings analysisWarnings) {
+    super(postJobsExecutor, sensorsExecutor, moduleHierarchy, fs, issueExclusionsLoader,
       moduleCoverageExclusions, projectCoverageExclusions, analysisWarnings);
     this.issuesReport = jsonReport;
     this.localIssueTracking = localIssueTracking;
index 50e1c75b66607fe606eaf07fb76e339da58c0e87..6411b5b2309793f925e1f1ec013eca2f657f98c0 100644 (file)
@@ -24,9 +24,7 @@ import org.sonar.api.notifications.AnalysisWarnings;
 import org.sonar.scanner.cpd.CpdExecutor;
 import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 import org.sonar.scanner.report.ReportPublisher;
-import org.sonar.scanner.rule.QProfileVerifier;
 import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
 import org.sonar.scanner.scm.ScmPublisher;
 
 public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor {
@@ -36,11 +34,11 @@ public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor {
   private final ScmPublisher scm;
 
   public PublishPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
-                              ReportPublisher reportPublisher, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader,
-                              CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy, FileIndexer fileIndexer,
-                              ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
-                              AnalysisWarnings analysisWarnings) {
-    super(postJobsExecutor, sensorsExecutor, hierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer, moduleCoverageExclusions,
+    ReportPublisher reportPublisher, DefaultModuleFileSystem fs, IssueExclusionsLoader issueExclusionsLoader,
+    CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy,
+    ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
+    AnalysisWarnings analysisWarnings) {
+    super(postJobsExecutor, sensorsExecutor, hierarchy, fs, issueExclusionsLoader, moduleCoverageExclusions,
       projectCoverageExclusions, analysisWarnings);
     this.reportPublisher = reportPublisher;
     this.cpdExecutor = cpdExecutor;
index 21f44b0cfa523b5d2c5c564a8560d19816fe3d8f..b7ca12593964d0c28af222b9b836fae051a2738c 100644 (file)
@@ -23,25 +23,23 @@ import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.MessageException;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
 
 import static org.apache.commons.lang.StringUtils.isNotEmpty;
 
-@ScannerSide
 public class QProfileVerifier {
 
   private static final Logger LOG = LoggerFactory.getLogger(QProfileVerifier.class);
 
-  private final Configuration settings;
-  private final FileSystem fs;
+  private final Configuration config;
+  private final InputComponentStore store;
   private final QualityProfiles profiles;
 
-  public QProfileVerifier(Configuration settings, FileSystem fs, QualityProfiles profiles) {
-    this.settings = settings;
-    this.fs = fs;
+  public QProfileVerifier(Configuration config, InputComponentStore store, QualityProfiles profiles) {
+    this.config = config;
+    this.store = store;
     this.profiles = profiles;
   }
 
@@ -51,9 +49,9 @@ public class QProfileVerifier {
 
   @VisibleForTesting
   void execute(Logger logger) {
-    String defaultName = settings.get(QualityProfiles.SONAR_PROFILE_PROP).orElse(null);
+    String defaultName = config.get(QualityProfiles.SONAR_PROFILE_PROP).orElse(null);
     boolean defaultNameUsed = StringUtils.isBlank(defaultName);
-    for (String lang : fs.languages()) {
+    for (String lang : store.getLanguages()) {
       QProfile profile = profiles.findByLanguage(lang);
       if (profile == null) {
         logger.warn("No Quality profile found for language {}", lang);
@@ -64,7 +62,7 @@ public class QProfileVerifier {
         }
       }
     }
-    if (!defaultNameUsed && !fs.languages().isEmpty()) {
+    if (!defaultNameUsed && !store.getLanguages().isEmpty()) {
       throw MessageException.of("sonar.profile was set to '" + defaultName + "' but didn't match any profile for any language. Please check your configuration.");
     }
   }
index bf101a42de04615443d837d9c5ae951571c9efe4..1530412636a90744d24d5b4a004f42b59b73a3b1 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.scanner.scan;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.scan.filesystem.FileExclusions;
 import org.sonar.core.extension.CoreExtensionsInstaller;
 import org.sonar.core.platform.ComponentContainer;
@@ -33,12 +32,6 @@ import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
 import org.sonar.scanner.deprecated.perspectives.ScannerPerspectives;
 import org.sonar.scanner.issue.ModuleIssueFilters;
 import org.sonar.scanner.issue.ModuleIssues;
-import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
-import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
-import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 import org.sonar.scanner.phases.AbstractModulePhaseExecutor;
 import org.sonar.scanner.phases.IssuesPhaseExecutor;
 import org.sonar.scanner.phases.ModuleCoverageExclusions;
@@ -49,10 +42,6 @@ import org.sonar.scanner.postjob.DefaultPostJobContext;
 import org.sonar.scanner.postjob.PostJobOptimizer;
 import org.sonar.scanner.rule.QProfileVerifier;
 import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.ExclusionFilters;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
-import org.sonar.scanner.scan.filesystem.InputFileBuilder;
-import org.sonar.scanner.scan.filesystem.MetadataGenerator;
 import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
 import org.sonar.scanner.scan.report.IssuesReports;
 import org.sonar.scanner.sensor.DefaultSensorContext;
@@ -105,13 +94,7 @@ public class ModuleScanContainer extends ComponentContainer {
       // file system
       ModuleInputComponentStore.class,
       FileExclusions.class,
-      ExclusionFilters.class,
-      MetadataGenerator.class,
-      FileMetadata.class,
-      FileIndexer.class,
-      InputFileBuilder.class,
       DefaultModuleFileSystem.class,
-      QProfileVerifier.class,
 
       SensorOptimizer.class,
       PostJobOptimizer.class,
@@ -126,14 +109,6 @@ public class ModuleScanContainer extends ComponentContainer {
       // issues
       ModuleIssues.class,
 
-      // issue exclusions
-      IssueInclusionPatternInitializer.class,
-      IssueExclusionPatternInitializer.class,
-      PatternMatcher.class,
-      IssueExclusionsLoader.class,
-      EnforceIssuesFilter.class,
-      IgnoreIssuesFilter.class,
-
       // Perspectives
       ScannerPerspectives.class,
 
index 0079aedb0775411daf9aaf45c8807a2255ee86d3..baef9c2cac480aecd489ec77c247467aa25eba46 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.scanner.scan;
 import com.google.common.annotations.VisibleForTesting;
 import javax.annotation.Nullable;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
 import org.sonar.api.batch.fs.internal.SensorStrategy;
 import org.sonar.api.batch.rule.CheckFactory;
@@ -50,6 +51,12 @@ import org.sonar.scanner.deprecated.test.TestPlanBuilder;
 import org.sonar.scanner.deprecated.test.TestableBuilder;
 import org.sonar.scanner.issue.DefaultProjectIssues;
 import org.sonar.scanner.issue.IssueCache;
+import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
+import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
+import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 import org.sonar.scanner.issue.tracking.DefaultServerLineHashesLoader;
 import org.sonar.scanner.issue.tracking.IssueTransition;
 import org.sonar.scanner.issue.tracking.LocalIssueTracking;
@@ -85,6 +92,7 @@ import org.sonar.scanner.rule.ActiveRulesLoader;
 import org.sonar.scanner.rule.ActiveRulesProvider;
 import org.sonar.scanner.rule.DefaultActiveRulesLoader;
 import org.sonar.scanner.rule.DefaultRulesLoader;
+import org.sonar.scanner.rule.QProfileVerifier;
 import org.sonar.scanner.rule.RulesLoader;
 import org.sonar.scanner.rule.RulesProvider;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
@@ -92,8 +100,12 @@ import org.sonar.scanner.scan.branch.BranchConfigurationProvider;
 import org.sonar.scanner.scan.branch.BranchType;
 import org.sonar.scanner.scan.branch.ProjectBranchesProvider;
 import org.sonar.scanner.scan.branch.ProjectPullRequestsProvider;
+import org.sonar.scanner.scan.filesystem.FileIndexer;
 import org.sonar.scanner.scan.filesystem.InputComponentStore;
 import org.sonar.scanner.scan.filesystem.LanguageDetection;
+import org.sonar.scanner.scan.filesystem.MetadataGenerator;
+import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
+import org.sonar.scanner.scan.filesystem.ProjectFileIndexer;
 import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
 import org.sonar.scanner.scan.filesystem.StatusDetection;
 import org.sonar.scanner.scan.measure.DefaultMetricFinder;
@@ -165,11 +177,18 @@ public class ProjectScanContainer extends ComponentContainer {
       new ScmChangedFilesProvider(),
       StatusDetection.class,
       LanguageDetection.class,
+      MetadataGenerator.class,
+      FileMetadata.class,
+      FileIndexer.class,
+      ProjectFileIndexer.class,
+      ProjectExclusionFilters.class,
+
 
       // rules
       new ActiveRulesProvider(),
       new QualityProfilesProvider(),
       CheckFactory.class,
+      QProfileVerifier.class,
 
       // issues
       IssueCache.class,
@@ -191,6 +210,14 @@ public class ProjectScanContainer extends ComponentContainer {
       // Measures
       MeasureCache.class,
 
+      // issue exclusions
+      IssueInclusionPatternInitializer.class,
+      IssueExclusionPatternInitializer.class,
+      PatternMatcher.class,
+      IssueExclusionsLoader.class,
+      EnforceIssuesFilter.class,
+      IgnoreIssuesFilter.class,
+
       // context
       ContextPropertiesCache.class,
       ContextPropertiesPublisher.class,
@@ -290,6 +317,11 @@ public class ProjectScanContainer extends ComponentContainer {
       LOG.info("Branch name: {}, type: {}", branchConfig.branchName(), branchTypeToDisplayName(branchConfig.branchType()));
     }
 
+    getComponentByType(ProjectFileIndexer.class).index();
+
+    // Log detected languages and their profiles after FS is indexed and languages detected
+    getComponentByType(QProfileVerifier.class).execute();
+
     LOG.debug("Start recursive analysis of project modules");
     scanRecursively(tree, tree.root(), analysisMode);
 
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java
new file mode 100644 (file)
index 0000000..ed29b49
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.filesystem;
+
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.PathPattern;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+public abstract class AbstractExclusionFilters {
+
+  private static final Logger LOG = Loggers.get(AbstractExclusionFilters.class);
+  private final String[] sourceInclusions;
+  private final String[] testInclusions;
+  private final String[] sourceExclusions;
+  private final String[] testExclusions;
+
+  private PathPattern[] mainInclusionsPattern;
+  private PathPattern[] mainExclusionsPattern;
+  private PathPattern[] testInclusionsPattern;
+  private PathPattern[] testExclusionsPattern;
+
+  public AbstractExclusionFilters(Function<String, String[]> configProvider) {
+    this.sourceInclusions = inclusions(configProvider, CoreProperties.PROJECT_INCLUSIONS_PROPERTY);
+    this.testInclusions = inclusions(configProvider, CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY);
+    this.sourceExclusions = exclusions(configProvider, CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_EXCLUSIONS_PROPERTY);
+    this.testExclusions = exclusions(configProvider, CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY);
+    this.mainInclusionsPattern = prepareMainInclusions(sourceInclusions);
+    this.mainExclusionsPattern = prepareMainExclusions(sourceExclusions, testInclusions);
+    this.testInclusionsPattern = prepareTestInclusions(testInclusions);
+    this.testExclusionsPattern = prepareTestExclusions(testExclusions);
+  }
+
+  protected void log() {
+    log("Included sources: ", mainInclusionsPattern);
+    log("Excluded sources: ", mainExclusionsPattern);
+    log("Included tests: ", testInclusionsPattern);
+    log("Excluded tests: ", testExclusionsPattern);
+  }
+
+  private String[] inclusions(Function<String, String[]> configProvider, String propertyKey) {
+    return Arrays.stream(configProvider.apply(propertyKey))
+      .map(StringUtils::trim)
+      .filter(s -> !"**/*".equals(s))
+      .filter(s -> !"file:**/*".equals(s))
+      .toArray(String[]::new);
+  }
+
+  private String[] exclusions(Function<String, String[]> configProvider, String globalExclusionsProperty, String exclusionsProperty) {
+    String[] globalExclusions = configProvider.apply(globalExclusionsProperty);
+    String[] exclusions = configProvider.apply(exclusionsProperty);
+    return Stream.concat(Arrays.stream(globalExclusions), Arrays.stream(exclusions))
+      .map(StringUtils::trim)
+      .toArray(String[]::new);
+  }
+
+  public boolean hasPattern() {
+    return mainInclusionsPattern.length > 0 || mainExclusionsPattern.length > 0 || testInclusionsPattern.length > 0 || testExclusionsPattern.length > 0;
+  }
+
+  private static void log(String title, PathPattern[] patterns) {
+    if (patterns.length > 0) {
+      LOG.info(title);
+      for (PathPattern pattern : patterns) {
+        LOG.info("  {}", pattern);
+      }
+    }
+  }
+
+  public boolean accept(Path absolutePath, Path relativePath, InputFile.Type type) {
+    PathPattern[] inclusionPatterns;
+    PathPattern[] exclusionPatterns;
+    if (InputFile.Type.MAIN == type) {
+      inclusionPatterns = mainInclusionsPattern;
+      exclusionPatterns = mainExclusionsPattern;
+    } else if (InputFile.Type.TEST == type) {
+      inclusionPatterns = testInclusionsPattern;
+      exclusionPatterns = testExclusionsPattern;
+    } else {
+      throw new IllegalArgumentException("Unknown file type: " + type);
+    }
+
+    if (inclusionPatterns.length > 0) {
+      boolean matchInclusion = false;
+      for (PathPattern pattern : inclusionPatterns) {
+        matchInclusion |= pattern.match(absolutePath, relativePath);
+      }
+      if (!matchInclusion) {
+        return false;
+      }
+    }
+    if (exclusionPatterns.length > 0) {
+      for (PathPattern pattern : exclusionPatterns) {
+        if (pattern.match(absolutePath, relativePath)) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  private static PathPattern[] prepareMainInclusions(String[] sourceInclusions) {
+    if (sourceInclusions.length > 0) {
+      // User defined params
+      return PathPattern.create(sourceInclusions);
+    }
+    return new PathPattern[0];
+  }
+
+  private static PathPattern[] prepareTestInclusions(String[] testInclusions) {
+    return PathPattern.create(testInclusions);
+  }
+
+  static PathPattern[] prepareMainExclusions(String[] sourceExclusions, String[] testInclusions) {
+    String[] patterns = (String[]) ArrayUtils.addAll(
+      sourceExclusions, testInclusions);
+    return PathPattern.create(patterns);
+  }
+
+  private static PathPattern[] prepareTestExclusions(String[] testExclusions) {
+    return PathPattern.create(testExclusions);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof AbstractExclusionFilters)) {
+      return false;
+    }
+    AbstractExclusionFilters that = (AbstractExclusionFilters) o;
+    return Arrays.equals(sourceInclusions, that.sourceInclusions) &&
+      Arrays.equals(testInclusions, that.testInclusions) &&
+      Arrays.equals(sourceExclusions, that.sourceExclusions) &&
+      Arrays.equals(testExclusions, that.testExclusions);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = Arrays.hashCode(sourceInclusions);
+    result = 31 * result + Arrays.hashCode(testInclusions);
+    result = 31 * result + Arrays.hashCode(sourceExclusions);
+    result = 31 * result + Arrays.hashCode(testExclusions);
+    return result;
+  }
+}
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
deleted file mode 100644 (file)
index 530b2a7..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.filesystem;
-
-import java.nio.file.Path;
-import org.apache.commons.lang.ArrayUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.PathPattern;
-import org.sonar.api.scan.filesystem.FileExclusions;
-
-@ScannerSide
-public class ExclusionFilters {
-
-  private static final Logger LOG = LoggerFactory.getLogger(ExclusionFilters.class);
-
-  private final FileExclusions exclusionSettings;
-
-  private PathPattern[] mainInclusions;
-  private PathPattern[] mainExclusions;
-  private PathPattern[] testInclusions;
-  private PathPattern[] testExclusions;
-
-  public ExclusionFilters(FileExclusions exclusions) {
-    this.exclusionSettings = exclusions;
-  }
-
-  public void prepare() {
-    mainInclusions = prepareMainInclusions();
-    mainExclusions = prepareMainExclusions();
-    testInclusions = prepareTestInclusions();
-    testExclusions = prepareTestExclusions();
-    log("Included sources: ", mainInclusions);
-    log("Excluded sources: ", mainExclusions);
-    log("Included tests: ", testInclusions);
-    log("Excluded tests: ", testExclusions);
-  }
-
-  public boolean hasPattern() {
-    return mainInclusions.length > 0 || mainExclusions.length > 0 || testInclusions.length > 0 || testExclusions.length > 0;
-  }
-
-  private static void log(String title, PathPattern[] patterns) {
-    if (patterns.length > 0) {
-      LOG.info(title);
-      for (PathPattern pattern : patterns) {
-        LOG.info("  {}", pattern);
-      }
-    }
-  }
-
-  public boolean accept(Path absolutePath, Path relativePath, InputFile.Type type) {
-    PathPattern[] inclusionPatterns;
-    PathPattern[] exclusionPatterns;
-    if (InputFile.Type.MAIN == type) {
-      inclusionPatterns = mainInclusions;
-      exclusionPatterns = mainExclusions;
-    } else if (InputFile.Type.TEST == type) {
-      inclusionPatterns = testInclusions;
-      exclusionPatterns = testExclusions;
-    } else {
-      throw new IllegalArgumentException("Unknown file type: " + type);
-    }
-
-    if (inclusionPatterns.length > 0) {
-      boolean matchInclusion = false;
-      for (PathPattern pattern : inclusionPatterns) {
-        matchInclusion |= pattern.match(absolutePath, relativePath);
-      }
-      if (!matchInclusion) {
-        return false;
-      }
-    }
-    if (exclusionPatterns.length > 0) {
-      for (PathPattern pattern : exclusionPatterns) {
-        if (pattern.match(absolutePath, relativePath)) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
-  PathPattern[] prepareMainInclusions() {
-    if (exclusionSettings.sourceInclusions().length > 0) {
-      // User defined params
-      return PathPattern.create(exclusionSettings.sourceInclusions());
-    }
-    return new PathPattern[0];
-  }
-
-  PathPattern[] prepareTestInclusions() {
-    return PathPattern.create(computeTestInclusions());
-  }
-
-  private String[] computeTestInclusions() {
-    if (exclusionSettings.testInclusions().length > 0) {
-      // User defined params
-      return exclusionSettings.testInclusions();
-    }
-    return ArrayUtils.EMPTY_STRING_ARRAY;
-  }
-
-  PathPattern[] prepareMainExclusions() {
-    String[] patterns = (String[]) ArrayUtils.addAll(
-      exclusionSettings.sourceExclusions(), computeTestInclusions());
-    return PathPattern.create(patterns);
-  }
-
-  PathPattern[] prepareTestExclusions() {
-    return PathPattern.create(exclusionSettings.testExclusions());
-  }
-}
index 20a1d8036884a7757aa2431fd66cb9426db3c4be..86c11738f1bf90427893bbe95bc5031580736960 100644 (file)
  */
 package org.sonar.scanner.scan.filesystem;
 
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import java.io.IOException;
-import java.nio.file.FileSystemLoopException;
-import java.nio.file.FileVisitOption;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
 import java.nio.file.LinkOption;
 import java.nio.file.Path;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.ScannerSide;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputFile.Type;
 import org.sonar.api.batch.fs.InputFileFilter;
+import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.api.batch.fs.internal.SensorStrategy;
+import org.sonar.api.notifications.AnalysisWarnings;
 import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
+import org.sonar.scanner.scan.ScanProperties;
 import org.sonar.scanner.util.ProgressReport;
 
 /**
  * Index input files into {@link InputComponentStore}.
  */
-@ScannerSide
 public class FileIndexer {
 
-  private static final Logger LOG = LoggerFactory.getLogger(FileIndexer.class);
+  private static final Logger LOG = Loggers.get(FileIndexer.class);
+  private final AnalysisWarnings analysisWarnings;
+  private final ScanProperties properties;
   private final InputFileFilter[] filters;
-  private final ExclusionFilters exclusionFilters;
-  private final InputFileBuilder inputFileBuilder;
-  private final DefaultInputModule module;
+  private final ProjectExclusionFilters projectExclusionFilters;
+  private final IssueExclusionsLoader issueExclusionsLoader;
+  private final MetadataGenerator metadataGenerator;
+  private final DefaultInputProject project;
   private final ScannerComponentIdGenerator scannerComponentIdGenerator;
   private final InputComponentStore componentStore;
-  private ExecutorService executorService;
-  private final List<Future<Void>> tasks;
-  private final DefaultModuleFileSystem defaultModuleFileSystem;
+  private final SensorStrategy sensorStrategy;
   private final LanguageDetection langDetection;
 
-  private ProgressReport progressReport;
+  private boolean warnExclusionsAlreadyLogged;
 
-  public FileIndexer(ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, DefaultInputModule module, ExclusionFilters exclusionFilters,
-                     InputFileBuilder inputFileBuilder, DefaultModuleFileSystem defaultModuleFileSystem,
-                     LanguageDetection languageDetection,
-                     InputFileFilter[] filters) {
+  public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters,
+    IssueExclusionsLoader issueExclusionsLoader,
+    MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy,
+    LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties,
+    InputFileFilter[] filters) {
+    this.project = project;
     this.scannerComponentIdGenerator = scannerComponentIdGenerator;
     this.componentStore = componentStore;
-    this.module = module;
-    this.inputFileBuilder = inputFileBuilder;
-    this.defaultModuleFileSystem = defaultModuleFileSystem;
+    this.issueExclusionsLoader = issueExclusionsLoader;
+    this.metadataGenerator = metadataGenerator;
+    this.sensorStrategy = sensorStrategy;
     this.langDetection = languageDetection;
+    this.analysisWarnings = analysisWarnings;
+    this.properties = properties;
     this.filters = filters;
-    this.exclusionFilters = exclusionFilters;
-    this.tasks = new ArrayList<>();
+    this.projectExclusionFilters = projectExclusionFilters;
   }
 
-  public FileIndexer(ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, DefaultInputModule module, ExclusionFilters exclusionFilters,
-                     InputFileBuilder inputFileBuilder, DefaultModuleFileSystem defaultModuleFileSystem,
-                     LanguageDetection languageDetection) {
-    this(scannerComponentIdGenerator, componentStore, module, exclusionFilters, inputFileBuilder, defaultModuleFileSystem, languageDetection,
-      new InputFileFilter[0]);
+  public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters,
+    IssueExclusionsLoader issueExclusionsLoader,
+    MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
+    this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, issueExclusionsLoader, metadataGenerator, sensorStrategy, languageDetection, analysisWarnings,
+      properties, new InputFileFilter[0]);
   }
 
-  public void index() {
-    int threads = Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
-    this.executorService = Executors.newFixedThreadPool(threads, new ThreadFactoryBuilder()
-      .setNameFormat("FileIndexer-%d")
-      .setDaemon(true)
-      .build());
-
-    progressReport = new ProgressReport("Report about progress of file indexation", TimeUnit.SECONDS.toMillis(10));
-    progressReport.start("Index files");
-    exclusionFilters.prepare();
-
-    Progress progress = new Progress();
-
-    indexFiles(module.getSourceDirsOrFiles(), InputFile.Type.MAIN, progress);
-    indexFiles(module.getTestDirsOrFiles(), InputFile.Type.TEST, progress);
-
-    waitForTasksToComplete(progressReport);
-
-    progressReport.stop(progress.count() + " " + pluralizeFiles(progress.count()) + " indexed");
-
-    if (exclusionFilters.hasPattern()) {
-      LOG.info("{} {} ignored because of inclusion/exclusion patterns", progress.excludedByPatternsCount(), pluralizeFiles(progress.excludedByPatternsCount()));
-    }
-  }
-
-  private void waitForTasksToComplete(ProgressReport report) {
-    executorService.shutdown();
-    for (Future<Void> task : tasks) {
-      try {
-        task.get();
-      } catch (ExecutionException e) {
-        // Unwrap ExecutionException
-        stopAsap(report);
-        throw e.getCause() instanceof RuntimeException ? (RuntimeException) e.getCause() : new IllegalStateException(e.getCause());
-      } catch (InterruptedException e) {
-        stopAsap(report);
-        throw new IllegalStateException(e);
-      }
-    }
-  }
-
-  private void stopAsap(ProgressReport report) {
-    report.stop(null);
-    executorService.shutdownNow();
-    try {
-      executorService.awaitTermination(5, TimeUnit.SECONDS);
-    } catch (InterruptedException e1) {
-      // ignore, what's important is the original exception
-    }
-  }
-
-  private static String pluralizeFiles(int count) {
-    return count == 1 ? "file" : "files";
-  }
-
-  private void indexFiles(List<Path> sources, InputFile.Type type, Progress progress) {
-    try {
-      for (Path dirOrFile : sources) {
-        if (dirOrFile.toFile().isDirectory()) {
-          indexDirectory(dirOrFile, type, progress);
-        } else {
-          tasks.add(executorService.submit(() -> indexFile(dirOrFile, type, progress)));
-        }
-      }
-    } catch (IOException e) {
-      throw new IllegalStateException("Failed to index files", e);
-    }
-  }
-
-  private void indexDirectory(Path dirToIndex, InputFile.Type type, Progress progress) throws IOException {
-    Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
-      new IndexFileVisitor(type, progress));
-  }
-
-  private Void indexFile(Path sourceFile, InputFile.Type type, Progress progress) throws IOException {
+  public void indexFile(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Path sourceFile, InputFile.Type type, ProgressReport progressReport,
+                        AtomicInteger excludedByPatternsCount)
+    throws IOException {
     // get case of real file without resolving link
     Path realAbsoluteFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS).toAbsolutePath().normalize();
-    if (!realAbsoluteFile.startsWith(module.getBaseDir())) {
-      LOG.warn("File '{}' is ignored. It is not located in module basedir '{}'.", realAbsoluteFile.toAbsolutePath(), module.getBaseDir());
-      return null;
+    if (!realAbsoluteFile.startsWith(project.getBaseDir())) {
+      LOG.warn("File '{}' is ignored. It is not located in project basedir '{}'.", realAbsoluteFile.toAbsolutePath(), project.getBaseDir());
+      return;
     }
-    Path relativePath = module.getBaseDir().relativize(realAbsoluteFile);
-    if (!exclusionFilters.accept(realAbsoluteFile, relativePath, type)) {
-      progress.increaseExcludedByPatternsCount();
-      return null;
+    Path projectRelativePath = project.getBaseDir().relativize(realAbsoluteFile);
+    Path moduleRelativePath = module.getBaseDir().relativize(realAbsoluteFile);
+    if (!projectExclusionFilters.accept(realAbsoluteFile, projectRelativePath, type)) {
+      excludedByPatternsCount.incrementAndGet();
+      return;
+    }
+    if (!moduleExclusionFilters.accept(realAbsoluteFile, moduleRelativePath, type)) {
+      if (projectExclusionFilters.equals(moduleExclusionFilters)) {
+        warnOnce("File '" + projectRelativePath + "' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
+          "Please update file inclusion/exclusion configuration so that patterns refer to project relative paths.");
+      } else {
+        warnOnce("Defining inclusion/exclusions at module level is deprecated. " +
+          "Move file inclusion/exclusion configuration from module '" + module.getName() + "' " +
+          "to the root project and update patterns to refer to project relative paths.");
+      }
+      excludedByPatternsCount.incrementAndGet();
+      return;
     }
-    String language = langDetection.language(realAbsoluteFile, relativePath);
+    String language = langDetection.language(realAbsoluteFile, projectRelativePath);
     if (language == null && langDetection.getForcedLanguage() != null) {
       LOG.warn("File '{}' is ignored because it doesn't belong to the forced language '{}'", realAbsoluteFile.toAbsolutePath(), langDetection.getForcedLanguage());
-      return null;
+      return;
+    }
+    DefaultIndexedFile indexedFile = new DefaultIndexedFile(realAbsoluteFile, project.key(),
+      projectRelativePath.toString(),
+      moduleRelativePath.toString(),
+      type, language, scannerComponentIdGenerator.getAsInt(), sensorStrategy);
+    DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(module.getKeyWithBranch(), f, module.getEncoding()));
+    if (language != null) {
+      inputFile.setPublished(true);
     }
-    DefaultInputFile inputFile = inputFileBuilder.create(type, realAbsoluteFile, language);
     if (!accept(inputFile)) {
-      progress.increaseExcludedByPatternsCount();
-      return null;
+      return;
+    }
+    if (componentStore.getFile(inputFile.getProjectRelativePath()) != null) {
+      throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
+        + "disjoint sets for main and test files");
     }
-    synchronized (this) {
-      progress.markAsIndexed(inputFile);
-      defaultModuleFileSystem.add(inputFile);
+    componentStore.put(module.key(), inputFile);
+    if (issueExclusionsLoader.shouldExecute()) {
+      issueExclusionsLoader.addMulticriteriaPatterns(inputFile.getProjectRelativePath(), inputFile.key());
+    }
+    LOG.debug("'{}' indexed {}with language '{}'", projectRelativePath, type == Type.TEST ? "as test " : "", inputFile.language());
+    if (properties.preloadFileMetadata()) {
+      inputFile.checkMetadata();
+    }
+    int count = componentStore.allFiles().size();
+    progressReport.message(count + " " + pluralizeFiles(count) + " indexed...  (last one was " + inputFile.getProjectRelativePath() + ")");
+  }
+
+  private void warnOnce(String msg) {
+    if (!warnExclusionsAlreadyLogged) {
+      LOG.warn(msg);
+      analysisWarnings.addUnique(msg);
+      warnExclusionsAlreadyLogged = true;
     }
-    LOG.debug("'{}' indexed {}with language '{}'", relativePath, type == Type.TEST ? "as test " : "", inputFile.language());
-    inputFileBuilder.checkMetadata(inputFile);
-    return null;
   }
 
   private boolean accept(InputFile indexedFile) {
@@ -207,76 +162,8 @@ public class FileIndexer {
     return true;
   }
 
-  private class IndexFileVisitor implements FileVisitor<Path> {
-    private final Progress status;
-    private final Type type;
-
-    IndexFileVisitor(InputFile.Type type, Progress status) {
-      this.status = status;
-      this.type = type;
-    }
-
-    @Override
-    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
-      Path fileName = dir.getFileName();
-
-      if (fileName != null && fileName.toString().length() > 1 && fileName.toString().charAt(0) == '.') {
-        return FileVisitResult.SKIP_SUBTREE;
-      }
-      if (Files.isHidden(dir)) {
-        return FileVisitResult.SKIP_SUBTREE;
-      }
-      return FileVisitResult.CONTINUE;
-    }
-
-    @Override
-    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-      if (!Files.isHidden(file)) {
-        tasks.add(executorService.submit(() -> indexFile(file, type, status)));
-      }
-      return FileVisitResult.CONTINUE;
-    }
-
-    @Override
-    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
-      if (exc instanceof FileSystemLoopException) {
-        LOG.warn("Not indexing due to symlink loop: {}", file.toFile());
-        return FileVisitResult.CONTINUE;
-      }
-
-      throw exc;
-    }
-
-    @Override
-    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
-      return FileVisitResult.CONTINUE;
-    }
-  }
-
-  private class Progress {
-    private AtomicInteger indexedCount = new AtomicInteger(0);
-    private AtomicInteger excludedByPatternsCount = new AtomicInteger(0);
-
-    void markAsIndexed(DefaultInputFile inputFile) {
-      if (componentStore.getFile(inputFile.getProjectRelativePath()) != null) {
-        throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
-          + "disjoint sets for main and test files");
-      }
-      int count = indexedCount.incrementAndGet();
-      progressReport.message(count + " " + pluralizeFiles(count) + " indexed...  (last one was " + inputFile.getProjectRelativePath() + ")");
-    }
-
-    void increaseExcludedByPatternsCount() {
-      excludedByPatternsCount.incrementAndGet();
-    }
-
-    public int excludedByPatternsCount() {
-      return excludedByPatternsCount.get();
-    }
-
-    int count() {
-      return indexedCount.get();
-    }
+  private static String pluralizeFiles(int count) {
+    return count == 1 ? "file" : "files";
   }
 
 }
index a0f7e952db97be566d8d40c00e81966dc55e053a..6cc08a44ad45db6f5f1748061c5a7477b1e1960f 100644 (file)
@@ -37,7 +37,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 org.sonar.api.batch.fs.internal.FileExtensionPredicate;
-import org.sonar.api.scanner.fs.InputProject;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 
 /**
@@ -55,11 +54,9 @@ public class InputComponentStore {
   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 final InputProject project;
   private final BranchConfiguration branchConfiguration;
 
-  public InputComponentStore(InputProject project, BranchConfiguration branchConfiguration) {
-    this.project = project;
+  public InputComponentStore(BranchConfiguration branchConfiguration) {
     this.branchConfiguration = branchConfiguration;
   }
 
@@ -83,7 +80,7 @@ public class InputComponentStore {
       ::iterator;
   }
 
-  public Iterable<InputFile> allFiles() {
+  public Collection<InputFile> allFiles() {
     return globalInputFileCache.values();
   }
 
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
deleted file mode 100644 (file)
index 438a0ed..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.filesystem;
-
-import java.nio.file.Path;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.scanner.scan.ScanProperties;
-
-public class InputFileBuilder {
-  private final DefaultInputProject project;
-  private final DefaultInputModule module;
-  private final ScannerComponentIdGenerator idGenerator;
-  private final MetadataGenerator metadataGenerator;
-  private final boolean preloadMetadata;
-  private final Path projectBaseDir;
-  private final SensorStrategy sensorStrategy;
-
-  public InputFileBuilder(DefaultInputProject project, DefaultInputModule module, MetadataGenerator metadataGenerator,
-                          ScannerComponentIdGenerator idGenerator, ScanProperties properties,
-                          SensorStrategy sensorStrategy) {
-    this.sensorStrategy = sensorStrategy;
-    this.projectBaseDir = project.getBaseDir();
-    this.project = project;
-    this.module = module;
-    this.metadataGenerator = metadataGenerator;
-    this.idGenerator = idGenerator;
-    this.preloadMetadata = properties.preloadFileMetadata();
-  }
-
-  DefaultInputFile create(InputFile.Type type, Path absolutePath, @Nullable String language) {
-    DefaultIndexedFile indexedFile = new DefaultIndexedFile(absolutePath, project.key(),
-      projectBaseDir.relativize(absolutePath).toString(),
-      module.getBaseDir().relativize(absolutePath).toString(),
-      type, language, idGenerator.getAsInt(), sensorStrategy);
-    DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(f, module.getEncoding()));
-    if (language != null) {
-      inputFile.setPublished(true);
-    }
-
-    return inputFile;
-  }
-
-  void checkMetadata(DefaultInputFile inputFile) {
-    if (preloadMetadata) {
-      inputFile.checkMetadata();
-    }
-  }
-}
index 0590ae973d3a61dc08e9b3e718175f9878e926ca..a603edbe6dedc47f2bb1d82b125ef3fe9fa6f08c 100644 (file)
@@ -22,17 +22,16 @@ package org.sonar.scanner.scan.filesystem;
 import com.google.common.annotations.VisibleForTesting;
 import java.io.InputStream;
 import java.nio.charset.Charset;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.fs.InputFile.Type;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.batch.fs.internal.Metadata;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
 import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 
 public class MetadataGenerator {
-  private static final Logger LOG = LoggerFactory.getLogger(MetadataGenerator.class);
+  private static final Logger LOG = Loggers.get(MetadataGenerator.class);
   @VisibleForTesting
   static final Charset UTF_32BE = Charset.forName("UTF-32BE");
 
@@ -41,11 +40,9 @@ public class MetadataGenerator {
 
   private final StatusDetection statusDetection;
   private final FileMetadata fileMetadata;
-  private final DefaultInputModule inputModule;
   private final IssueExclusionsLoader exclusionsScanner;
 
-  public MetadataGenerator(DefaultInputModule inputModule, StatusDetection statusDetection, FileMetadata fileMetadata, IssueExclusionsLoader exclusionsScanner) {
-    this.inputModule = inputModule;
+  public MetadataGenerator(StatusDetection statusDetection, FileMetadata fileMetadata, IssueExclusionsLoader exclusionsScanner) {
     this.statusDetection = statusDetection;
     this.fileMetadata = fileMetadata;
     this.exclusionsScanner = exclusionsScanner;
@@ -55,7 +52,7 @@ public class MetadataGenerator {
    * Sets all metadata in the file, including charset and status.
    * It is an expensive computation, reading the entire file.
    */
-  public void setMetadata(final DefaultInputFile inputFile, Charset defaultEncoding) {
+  public void setMetadata(String moduleKeyWithBranch, final DefaultInputFile inputFile, Charset defaultEncoding) {
     CharsetDetector charsetDetector = new CharsetDetector(inputFile.path(), defaultEncoding);
     try {
       Charset charset;
@@ -69,8 +66,8 @@ public class MetadataGenerator {
       inputFile.setCharset(charset);
       Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile.key()));
       inputFile.setMetadata(metadata);
-      inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile, metadata.hash()));
-      LOG.debug("'{}' generated metadata {} with charset '{}'", inputFile, inputFile.type() == Type.TEST ? "as test " : "", charset);
+      inputFile.setStatus(statusDetection.status(moduleKeyWithBranch, inputFile, metadata.hash()));
+      LOG.debug("'{}' generated metadata{} with charset '{}'", inputFile, inputFile.type() == Type.TEST ? " as test " : "", charset);
     } catch (Exception e) {
       throw new IllegalStateException(e);
     }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleExclusionFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleExclusionFilters.java
new file mode 100644 (file)
index 0000000..fe67378
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.filesystem;
+
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+
+import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
+
+public class ModuleExclusionFilters extends AbstractExclusionFilters {
+
+  public ModuleExclusionFilters(DefaultInputModule module) {
+    super(k -> {
+      String value = module.properties().get(k);
+      return value != null ? parseAsCsv(k, value) : new String[0];
+    });
+  }
+
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFilters.java
new file mode 100644 (file)
index 0000000..dad3e3b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.filesystem;
+
+import org.sonar.api.config.Configuration;
+
+public class ProjectExclusionFilters extends AbstractExclusionFilters {
+
+  public ProjectExclusionFilters(Configuration projectConfig) {
+    super(projectConfig::getStringArray);
+    log();
+  }
+
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java
new file mode 100644 (file)
index 0000000..4d51181
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.filesystem;
+
+import java.io.IOException;
+import java.nio.file.FileSystemLoopException;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.scanner.util.ProgressReport;
+
+/**
+ * Index project input files into {@link InputComponentStore}.
+ */
+public class ProjectFileIndexer {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ProjectFileIndexer.class);
+  private final AbstractExclusionFilters projectExclusionFilters;
+  private final DefaultInputProject project;
+  private final InputComponentStore componentStore;
+  private final InputModuleHierarchy inputModuleHierarchy;
+  private final FileIndexer fileIndexer;
+
+  private ProgressReport progressReport;
+
+  public ProjectFileIndexer(DefaultInputProject project, InputComponentStore componentStore, AbstractExclusionFilters exclusionFilters,
+    InputModuleHierarchy inputModuleHierarchy,
+    FileIndexer fileIndexer) {
+    this.project = project;
+    this.componentStore = componentStore;
+    this.inputModuleHierarchy = inputModuleHierarchy;
+    this.fileIndexer = fileIndexer;
+    this.projectExclusionFilters = exclusionFilters;
+  }
+
+  public void index() {
+    progressReport = new ProgressReport("Report about progress of file indexation", TimeUnit.SECONDS.toMillis(10));
+    progressReport.start("Index files");
+
+    AtomicInteger excludedByPatternsCount = new AtomicInteger(0);
+
+    indexModulesRecursively(inputModuleHierarchy.root(), excludedByPatternsCount);
+
+    int totalIndexed = componentStore.allFiles().size();
+    progressReport.stop(totalIndexed + " " + pluralizeFiles(totalIndexed) + " indexed");
+
+    if (projectExclusionFilters.hasPattern()) {
+      int excludedFileCount = excludedByPatternsCount.get();
+      LOG.info("{} {} ignored because of inclusion/exclusion patterns", excludedFileCount, pluralizeFiles(excludedFileCount));
+    }
+  }
+
+  private void indexModulesRecursively(DefaultInputModule module, AtomicInteger excludedByPatternsCount) {
+    inputModuleHierarchy.children(module).forEach(m -> indexModulesRecursively(m, excludedByPatternsCount));
+    index(module, excludedByPatternsCount);
+  }
+
+  private void index(DefaultInputModule module, AtomicInteger excludedByPatternsCount) {
+    ModuleExclusionFilters moduleExclusionFilters = new ModuleExclusionFilters(module);
+    indexFiles(module, moduleExclusionFilters, module.getSourceDirsOrFiles(), Type.MAIN, excludedByPatternsCount);
+    indexFiles(module, moduleExclusionFilters, module.getTestDirsOrFiles(), Type.TEST, excludedByPatternsCount);
+  }
+
+  private static String pluralizeFiles(int count) {
+    return count == 1 ? "file" : "files";
+  }
+
+  private void indexFiles(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, List<Path> sources, Type type, AtomicInteger excludedByPatternsCount) {
+    try {
+      for (Path dirOrFile : sources) {
+        if (dirOrFile.toFile().isDirectory()) {
+          indexDirectory(module, moduleExclusionFilters, dirOrFile, type, excludedByPatternsCount);
+        } else {
+          fileIndexer.indexFile(module, moduleExclusionFilters, dirOrFile, type, progressReport, excludedByPatternsCount);
+        }
+      }
+    } catch (IOException e) {
+      throw new IllegalStateException("Failed to index files", e);
+    }
+  }
+
+  private void indexDirectory(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Path dirToIndex, Type type, AtomicInteger excludedByPatternsCount)
+    throws IOException {
+    Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
+      new IndexFileVisitor(module, moduleExclusionFilters, type, excludedByPatternsCount));
+  }
+
+  private class IndexFileVisitor implements FileVisitor<Path> {
+    private final DefaultInputModule module;
+    private final AbstractExclusionFilters moduleExclusionFilters;
+    private final Type type;
+    private final AtomicInteger excludedByPatternsCount;
+
+    IndexFileVisitor(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Type type, AtomicInteger excludedByPatternsCount) {
+      this.module = module;
+      this.moduleExclusionFilters = moduleExclusionFilters;
+      this.type = type;
+      this.excludedByPatternsCount = excludedByPatternsCount;
+    }
+
+    @Override
+    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+      Path fileName = dir.getFileName();
+
+      if (fileName != null && fileName.toString().length() > 1 && fileName.toString().charAt(0) == '.') {
+        return FileVisitResult.SKIP_SUBTREE;
+      }
+      if (Files.isHidden(dir)) {
+        return FileVisitResult.SKIP_SUBTREE;
+      }
+      return FileVisitResult.CONTINUE;
+    }
+
+    @Override
+    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+      if (!Files.isHidden(file)) {
+        fileIndexer.indexFile(module, moduleExclusionFilters, file, type, progressReport, excludedByPatternsCount);
+      }
+      return FileVisitResult.CONTINUE;
+    }
+
+    @Override
+    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+      if (exc instanceof FileSystemLoopException) {
+        LOG.warn("Not indexing due to symlink loop: {}", file.toFile());
+        return FileVisitResult.CONTINUE;
+      }
+
+      throw exc;
+    }
+
+    @Override
+    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+      return FileVisitResult.CONTINUE;
+    }
+  }
+
+}
index 6588f2e3c0aadaf4802747c80208dab62c213d4a..b56822cfbb072d2c757c5abe3014e60b4ff7ec5e 100644 (file)
@@ -90,7 +90,7 @@ public class CpdExecutorTest {
     when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir));
 
     DefaultInputProject project = TestInputFileBuilder.newDefaultInputProject("foo", baseDir);
-    componentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
+    componentStore = new InputComponentStore(mock(BranchConfiguration.class));
     executor = new CpdExecutor(settings, index, publisher, componentStore, executorService);
     reader = new ScannerReportReader(outputDir);
 
index 705692a6777fc34ad90afbf1fbd8bb5c5504e095..bcc778dc7242fcd18c37dc4910a763711d7b377c 100644 (file)
@@ -37,13 +37,15 @@ import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
 import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.LogOutputRecorder;
 import org.sonar.scanner.mediumtest.ScannerMediumTester;
 import org.sonar.xoo.XooPlugin;
 import org.sonar.xoo.global.GlobalSensor;
 import org.sonar.xoo.rule.XooRulesDefinition;
 
+import static java.util.stream.Collectors.joining;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assume.assumeTrue;
 
@@ -55,14 +57,14 @@ public class FileSystemMediumTest {
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
-  private LogOutputRecorder logs = new LogOutputRecorder();
+  @Rule
+  public LogTester logTester = new LogTester();
 
   @Rule
   public ScannerMediumTester tester = new ScannerMediumTester()
     .registerPlugin("xoo", new XooPlugin())
     .addDefaultQProfile("xoo", "Sonar Way")
-    .addDefaultQProfile("xoo2", "Sonar Way")
-    .setLogOutput(logs);
+    .addDefaultQProfile("xoo2", "Sonar Way");
 
   private File baseDir;
   private ImmutableMap.Builder<String, String> builder;
@@ -137,9 +139,9 @@ public class FileSystemMediumTest {
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
-    assertThat(logs.getAllAsString()).contains("Organization key: my org");
-    assertThat(logs.getAllAsString()).doesNotContain("Branch key");
+    assertThat(logTester.logs()).contains("Project key: com.foo.project");
+    assertThat(logTester.logs()).contains("Organization key: my org");
+    assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Branch key");
   }
 
   @Test
@@ -158,9 +160,9 @@ public class FileSystemMediumTest {
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
-    assertThat(logs.getAllAsString()).contains("Branch key: my-branch");
-    assertThat(logs.getAllAsString()).contains("The use of \"sonar.branch\" is deprecated and replaced by \"sonar.branch.name\".");
+    assertThat(logTester.logs()).contains("Project key: com.foo.project");
+    assertThat(logTester.logs()).contains("Branch key: my-branch");
+    assertThat(logTester.logs()).contains("The use of \"sonar.branch\" is deprecated and replaced by \"sonar.branch.name\". See https://redirect.sonarsource.com/doc/branches.html.");
   }
 
   @Test
@@ -197,9 +199,9 @@ public class FileSystemMediumTest {
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
-    assertThat(logs.getAllAsString()).doesNotContain("Organization key");
-    assertThat(logs.getAllAsString()).doesNotContain("Branch key");
+    assertThat(logTester.logs()).contains("Project key: com.foo.project");
+    assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Organization key");
+    assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Branch key");
   }
 
   @Test
@@ -215,15 +217,17 @@ public class FileSystemMediumTest {
     File javaFile = new File(srcDir, "sample.java");
     FileUtils.write(javaFile, "Sample xoo\ncontent");
 
+    logTester.setLevel(LoggerLevel.DEBUG);
+
     tester.newAnalysis()
       .properties(builder
         .put("sonar.sources", "src")
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).contains("2 files indexed");
-    assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
-    assertThat(logs.getAllAsString()).doesNotContain("'src/sample.java' generated metadata");
+    assertThat(logTester.logs()).contains("2 files indexed");
+    assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
+    assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/sample.java' generated metadata");
 
   }
 
@@ -241,15 +245,17 @@ public class FileSystemMediumTest {
     File javaFile = new File(srcDir, "sample.java");
     FileUtils.write(javaFile, "Sample xoo\ncontent");
 
+    logTester.setLevel(LoggerLevel.DEBUG);
+
     tester.newAnalysis()
       .properties(builder
         .put("sonar.sources", "src")
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).contains("2 files indexed");
-    assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
-    assertThat(logs.getAllAsString()).contains("'src/sample.java' generated metadata");
+    assertThat(logTester.logs()).contains("2 files indexed");
+    assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
+    assertThat(logTester.logs()).contains("'src/sample.java' generated metadata with charset 'UTF-8'");
   }
 
   @Test
@@ -271,6 +277,8 @@ public class FileSystemMediumTest {
     Path javaFile = mainDir.resolve("sample.java");
     Files.write(javaFile, "Sample xoo\ncontent".getBytes(StandardCharsets.UTF_8));
 
+    logTester.setLevel(LoggerLevel.DEBUG);
+
     AnalysisResult result = tester.newAnalysis()
       .properties(builder
         .put("sonar.sources", "src/main")
@@ -278,10 +286,10 @@ public class FileSystemMediumTest {
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).contains("3 files indexed");
-    assertThat(logs.getAllAsString()).contains("'src/main/sample.xoo' generated metadata");
-    assertThat(logs.getAllAsString()).doesNotContain("'src/main/sample.java' generated metadata");
-    assertThat(logs.getAllAsString()).doesNotContain("'src/test/sample.java' generated metadata");
+    assertThat(logTester.logs()).contains("3 files indexed");
+    assertThat(logTester.logs()).contains("'src/main/sample.xoo' generated metadata with charset 'UTF-8'");
+    assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/main/sample.java' generated metadata");
+    assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/test/sample.java' generated metadata");
     DefaultInputFile javaInputFile = (DefaultInputFile) result.inputFile("src/main/sample.java");
 
     thrown.expect(IllegalStateException.class);
@@ -304,15 +312,17 @@ public class FileSystemMediumTest {
     File xooFile = new File(srcDir, "sample.unknown");
     FileUtils.write(xooFile, "Sample xoo\ncontent");
 
+    logTester.setLevel(LoggerLevel.DEBUG);
+
     AnalysisResult result = tester.newAnalysis()
       .properties(builder
         .put("sonar.sources", "src")
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).contains("1 file indexed");
-    assertThat(logs.getAllAsString()).contains("'src" + File.separator + "sample.unknown' indexed with language 'null'");
-    assertThat(logs.getAllAsString()).contains("'src/sample.unknown' generated metadata");
+    assertThat(logTester.logs()).contains("1 file indexed");
+    assertThat(logTester.logs()).contains("'src" + File.separator + "sample.unknown' indexed with language 'null'");
+    assertThat(logTester.logs()).contains("'src/sample.unknown' generated metadata with charset 'UTF-8'");
     DefaultInputFile inputFile = (DefaultInputFile) result.inputFile("src/sample.unknown");
     assertThat(result.getReportComponent(inputFile)).isNotNull();
   }
@@ -337,15 +347,17 @@ public class FileSystemMediumTest {
     new Random().nextBytes(b);
     FileUtils.writeByteArrayToFile(unknownFile, b);
 
+    logTester.setLevel(LoggerLevel.DEBUG);
+
     tester.newAnalysis()
       .properties(builder
         .put("sonar.sources", "src")
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with language 'null'");
-    assertThat(logs.getAllAsString()).doesNotContain("'src/myfile.binary' generating issue exclusions");
-    assertThat(logs.getAllAsString()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
+    assertThat(logTester.logs()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with language 'null'");
+    assertThat(logTester.logs()).doesNotContain("'src/myfile.binary' generating issue exclusions");
+    assertThat(logTester.logs()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
   }
 
   @Test
@@ -363,14 +375,16 @@ public class FileSystemMediumTest {
     File unknownFile = new File(srcDir, "myfile.binary");
     FileUtils.write(unknownFile, "some text");
 
+    logTester.setLevel(LoggerLevel.DEBUG);
+
     tester.newAnalysis()
       .properties(builder
         .put("sonar.sources", "src")
         .build())
       .execute();
 
-    assertThat(logs.getAllAsString()).containsOnlyOnce("- Exclusion pattern 'pattern'");
-    assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
+    assertThat(logTester.logs()).containsOnlyOnce("- Exclusion pattern 'pattern': every issue in this file will be ignored.");
+    assertThat(logTester.logs()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
   }
 
   @Test
@@ -525,6 +539,84 @@ public class FileSystemMediumTest {
     assertThat(result.inputFiles()).hasSize(2);
   }
 
+  @Test
+  public void warn_user_for_outdated_inherited_exclusions_for_multi_module_project() throws IOException {
+
+    File baseDir = temp.getRoot();
+    File baseDirModuleA = new File(baseDir, "moduleA");
+    File baseDirModuleB = new File(baseDir, "moduleB");
+    File srcDirA = new File(baseDirModuleA, "src");
+    srcDirA.mkdirs();
+    File srcDirB = new File(baseDirModuleB, "src");
+    srcDirB.mkdirs();
+
+    File xooFileA = new File(srcDirA, "sample.xoo");
+    FileUtils.write(xooFileA, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+    File xooFileB = new File(srcDirB, "sample.xoo");
+    FileUtils.write(xooFileB, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+    AnalysisResult result = tester.newAnalysis()
+      .properties(ImmutableMap.<String, String>builder()
+        .put("sonar.task", "scan")
+        .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+        .put("sonar.projectKey", "com.foo.project")
+        .put("sonar.sources", "src")
+        .put("sonar.modules", "moduleA,moduleB")
+        .put("sonar.exclusions", "src/sample.xoo")
+        .build())
+      .execute();
+
+    InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+    assertThat(fileA).isNull();
+
+    InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+    assertThat(fileB).isNull();
+
+    assertThat(logTester.logs(LoggerLevel.WARN))
+      .contains("File 'moduleB/src/sample.xoo' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
+      "Please update file inclusion/exclusion configuration so that patterns refer to project relative paths.");
+  }
+
+  @Test
+  public void warn_user_for_outdated_module_exclusions_for_multi_module_project() throws IOException {
+
+    File baseDir = temp.getRoot();
+    File baseDirModuleA = new File(baseDir, "moduleA");
+    File baseDirModuleB = new File(baseDir, "moduleB");
+    File srcDirA = new File(baseDirModuleA, "src");
+    srcDirA.mkdirs();
+    File srcDirB = new File(baseDirModuleB, "src");
+    srcDirB.mkdirs();
+
+    File xooFileA = new File(srcDirA, "sample.xoo");
+    FileUtils.write(xooFileA, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+    File xooFileB = new File(srcDirB, "sample.xoo");
+    FileUtils.write(xooFileB, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+    AnalysisResult result = tester.newAnalysis()
+      .properties(ImmutableMap.<String, String>builder()
+        .put("sonar.task", "scan")
+        .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+        .put("sonar.projectKey", "com.foo.project")
+        .put("sonar.sources", "src")
+        .put("sonar.modules", "moduleA,moduleB")
+        .put("moduleB.sonar.exclusions", "src/sample.xoo")
+        .build())
+      .execute();
+
+    InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+    assertThat(fileA).isNotNull();
+
+    InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+    assertThat(fileB).isNull();
+
+    assertThat(logTester.logs(LoggerLevel.WARN))
+      .contains("Defining inclusion/exclusions at module level is deprecated. " +
+        "Move file inclusion/exclusion configuration from module 'moduleB' to the root project and update patterns to refer to project relative paths.");
+  }
+
   @Test
   public void failForDuplicateInputFile() throws IOException {
     File srcDir = new File(baseDir, "src");
@@ -639,7 +731,7 @@ public class FileSystemMediumTest {
       .execute();
 
     assertThat(result.inputFiles()).hasSize(4);
-    assertThat(logs.get("INFO")).contains(
+    assertThat(logTester.logs(LoggerLevel.INFO)).contains(
       "Global Sensor: module_a/module_a1/src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo",
       "Global Sensor: module_a/module_a2/src/main/xoo/com/sonar/it/samples/modules/a2/HelloA2.xoo",
       "Global Sensor: module_b/module_b1/src/main/xoo/com/sonar/it/samples/modules/b1/HelloB1.xoo",
index 3d45aa214d83cdb0ca852848b7a825ecd16b6a32..f9381879df1797f7c595208be64b755b24bcc3c7 100644 (file)
@@ -26,7 +26,6 @@ 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.DefaultInputProject;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.api.batch.postjob.issue.PostJobIssue;
 import org.sonar.api.batch.rule.Severity;
@@ -54,8 +53,7 @@ public class DefaultPostJobContextTest {
   @Before
   public void setUp() throws IOException {
     issueCache = mock(IssueCache.class);
-    DefaultInputProject project = TestInputFileBuilder.newDefaultInputProject("foo", temp.newFolder());
-    componentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
+    componentStore = new InputComponentStore(mock(BranchConfiguration.class));
     settings = new MapSettings();
     analysisMode = mock(AnalysisMode.class);
     context = new DefaultPostJobContext(settings.asConfig(), settings, issueCache, componentStore, analysisMode);
index e13bc24a9d076489f1b86f837b5fa469118b9947..5f026d2b8eb636c87ca3ca8be6a64076425298c4 100644 (file)
@@ -85,7 +85,7 @@ public class ComponentsPublisherTest {
       .setWorkDir(temp.newFolder());
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration);
 
     Path moduleBaseDir = temp.newFolder().toPath();
     ProjectDefinition module1Def = ProjectDefinition.create()
@@ -150,7 +150,7 @@ public class ComponentsPublisherTest {
 
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration);
 
     ComponentsPublisher publisher = new ComponentsPublisher(project, store);
     publisher.publish(writer);
@@ -175,7 +175,7 @@ public class ComponentsPublisherTest {
       .setWorkDir(temp.newFolder());
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration);
 
     DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.java", 5)
       .setLines(2)
@@ -212,7 +212,7 @@ public class ComponentsPublisherTest {
       .setWorkDir(temp.newFolder());
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration);
     ComponentsPublisher publisher = new ComponentsPublisher(project, store);
     publisher.publish(writer);
 
@@ -244,7 +244,7 @@ public class ComponentsPublisherTest {
       .setWorkDir(temp.newFolder());
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration);
     ComponentsPublisher publisher = new ComponentsPublisher(project, store);
     publisher.publish(writer);
 
index 93663f7f57bd5044ec9a99292eb41d8038c31630..f1c75d6a3e3c15cc8a08f485735e9fa0690385b4 100644 (file)
@@ -58,7 +58,7 @@ public class CoveragePublisherTest {
     String moduleKey = "foo";
     inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setLines(5).build();
     DefaultInputProject rootModule = TestInputFileBuilder.newDefaultInputProject(moduleKey, temp.newFolder());
-    InputComponentStore componentCache = new InputComponentStore(rootModule, mock(BranchConfiguration.class));
+    InputComponentStore componentCache = new InputComponentStore(mock(BranchConfiguration.class));
     componentCache.put(moduleKey, inputFile);
 
     measureCache = mock(MeasureCache.class);
index 7583eac09714cff61bcdc5f7aeac705891bf43dd..6af538c600bb847a6a21f77021326ec761538564 100644 (file)
@@ -69,7 +69,7 @@ public class MeasuresPublisherTest {
     String projectKey = "foo";
     project = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder());
     inputFile = new TestInputFileBuilder(projectKey, "src/Foo.php").setPublish(true).build();
-    InputComponentStore componentCache = new InputComponentStore(project, mock(BranchConfiguration.class));
+    InputComponentStore componentCache = new InputComponentStore(mock(BranchConfiguration.class));
     componentCache.put(projectKey, inputFile);
     measureCache = mock(MeasureCache.class);
     when(measureCache.byComponentKey(anyString())).thenReturn(Collections.<DefaultMeasure<?>>emptyList());
index da37398e387df4d51ce6b28763c0913fb52f0ddd..4028bdae0afb253056edc2b43264c43c1557114c 100644 (file)
@@ -58,7 +58,7 @@ public class SourcePublisherTest {
       .build();
 
     DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(moduleKey, baseDir);
-    InputComponentStore componentStore = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
+    InputComponentStore componentStore = new InputComponentStore(mock(BranchConfiguration.class));
     componentStore.put(moduleKey, inputFile);
 
     publisher = new SourcePublisher(componentStore);
index fb432157a58f57d572d9ecb0f9a30e0db3b17bad..18facbe6391b70a372cd368a383511fe4780abba 100644 (file)
@@ -25,10 +25,11 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 import org.slf4j.Logger;
-import org.sonar.api.batch.fs.internal.DefaultFileSystem;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.utils.MessageException;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -42,13 +43,13 @@ public class QProfileVerifierTest {
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
-  private DefaultFileSystem fs;
+  private InputComponentStore store;
   private QualityProfiles profiles;
   private MapSettings settings = new MapSettings();
 
   @Before
   public void before() throws Exception {
-    fs = new DefaultFileSystem(temp.newFolder().toPath());
+    store = new InputComponentStore(mock(BranchConfiguration.class));
     profiles = mock(QualityProfiles.class);
     QProfile javaProfile = new QProfile("p1", "My Java profile", "java", null);
     when(profiles.findByLanguage("java")).thenReturn(javaProfile);
@@ -58,10 +59,10 @@ public class QProfileVerifierTest {
 
   @Test
   public void should_log_all_used_profiles() {
-    fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
-    fs.add(new TestInputFileBuilder("foo", "src/Baz.cbl").setLanguage("cobol").build());
+    store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+    store.put("foo", new TestInputFileBuilder("foo", "src/Baz.cbl").setLanguage("cobol").build());
 
-    QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
+    QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
     Logger logger = mock(Logger.class);
     profileLogger.execute(logger);
 
@@ -71,11 +72,11 @@ public class QProfileVerifierTest {
 
   @Test
   public void should_fail_if_default_profile_not_used() {
-    fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+    store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
 
     settings.setProperty("sonar.profile", "Unknown");
 
-    QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
+    QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
 
     thrown.expect(MessageException.class);
     thrown.expectMessage("sonar.profile was set to 'Unknown' but didn't match any profile for any language. Please check your configuration.");
@@ -87,7 +88,7 @@ public class QProfileVerifierTest {
   public void should_not_fail_if_no_language_on_project() {
     settings.setProperty("sonar.profile", "Unknown");
 
-    QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
+    QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
 
     profileLogger.execute();
 
@@ -95,11 +96,11 @@ public class QProfileVerifierTest {
 
   @Test
   public void should_not_fail_if_default_profile_used_at_least_once() {
-    fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+    store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
 
     settings.setProperty("sonar.profile", "My Java profile");
 
-    QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
+    QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
 
     profileLogger.execute();
   }
index 2c2b51fd0ca08121d3e1b6d78afec190585be5fa..8c09090dff4a242df46e7edcdcbc2b036d7b959c 100644 (file)
@@ -37,7 +37,7 @@ public class ModuleIndexerTest {
   private InputComponentStore componentStore;
 
   public void createIndexer(DefaultInputProject rootProject) {
-    componentStore = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
+    componentStore = new InputComponentStore(mock(BranchConfiguration.class));
     moduleHierarchy = mock(DefaultInputModuleHierarchy.class);
     indexer = new ModuleIndexer(componentStore, moduleHierarchy);
   }
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
deleted file mode 100644 (file)
index a01aa69..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.filesystem;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.fs.IndexedFile;
-import org.sonar.api.batch.fs.InputFile;
-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
-  public TemporaryFolder temp = new TemporaryFolder();
-  private Path moduleBaseDir;
-  private MapSettings settings;
-  private ExclusionFilters filter;
-
-  @Before
-  public void setUp() throws IOException {
-    settings = new MapSettings();
-    moduleBaseDir = temp.newFolder().toPath();
-    filter = new ExclusionFilters(new FileExclusions(settings.asConfig()));
-  }
-
-  @Test
-  public void no_inclusions_nor_exclusions() throws IOException {
-    filter.prepare();
-
-    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
-  }
-
-  @Test
-  public void match_inclusion() throws IOException {
-    settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java");
-    filter.prepare();
-
-    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
-
-    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
-  }
-
-  @Test
-  public void match_at_least_one_inclusion() throws IOException {
-    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", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
-
-    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDto.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
-  }
-
-  @Test
-  public void match_exclusions() throws IOException {
-    settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
-    settings.setProperty(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, "src/test/java/**/*");
-    settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.java");
-    filter.prepare();
-
-    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
-
-    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
-
-    // source exclusions do not apply to tests
-    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/test/java/com/mycompany/FooDao.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
-  }
-
-  @Test
-  public void match_exclusion_by_absolute_path() throws IOException {
-    File excludedFile = new File(moduleBaseDir.toString(), "src/main/java/org/bar/Bar.java");
-
-    settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
-    settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getAbsolutePath());
-    filter.prepare();
-
-    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
-
-    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Bar.java", null);
-    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
-  }
-
-  @Test
-  public void trim_pattern() {
-    settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "   **/*Dao.java   ");
-
-    assertThat(filter.prepareMainExclusions()[0].toString()).isEqualTo("**/*Dao.java");
-  }
-
-}
index a9d30ff3bedad13f011e70b1156493d45b3beea8..ee736b0578f8178a2e603c6ee618465dd359d42f 100644 (file)
@@ -60,7 +60,7 @@ public class InputComponentStoreTest {
     DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(rootDef);
     DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(moduleDef);
 
-    InputComponentStore store = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
+    InputComponentStore store = new InputComponentStore(mock(BranchConfiguration.class));
     store.put(subModule);
 
     DefaultInputFile fooFile = new TestInputFileBuilder(rootModuleKey, "src/main/java/Foo.java")
@@ -96,7 +96,7 @@ public class InputComponentStoreTest {
 
   static class InputComponentStoreTester extends InputComponentStore {
     InputComponentStoreTester() throws IOException {
-      super(TestInputFileBuilder.newDefaultInputProject("root", temp.newFolder()), mock(BranchConfiguration.class));
+      super(mock(BranchConfiguration.class));
     }
 
     InputFile addFile(String moduleKey, String relpath, String language) {
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputFileBuilderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputFileBuilderTest.java
deleted file mode 100644 (file)
index 840cd7d..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.filesystem;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-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.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.fs.InputFile.Type;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.scanner.scan.ScanProperties;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class InputFileBuilderTest {
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  private Path baseDir;
-  private Path workDir;
-  private InputFileBuilder builder;
-
-  private SensorStrategy sensorStrategy;
-
-  @Before
-  public void setUp() throws IOException {
-    baseDir = temp.newFolder().toPath();
-    workDir = temp.newFolder().toPath();
-    DefaultInputProject project = new DefaultInputProject(ProjectDefinition.create()
-      .setBaseDir(baseDir.toFile())
-      .setWorkDir(workDir.toFile())
-      .setProperty(CoreProperties.ENCODING_PROPERTY, StandardCharsets.UTF_8.name())
-      .setKey("root"), 0);
-    Path moduleBaseDir = baseDir.resolve("module1");
-    Files.createDirectories(moduleBaseDir);
-    DefaultInputModule module = new DefaultInputModule(ProjectDefinition.create()
-      .setBaseDir(moduleBaseDir.toFile())
-      .setWorkDir(workDir.toFile())
-      .setKey("module1"), 1);
-
-    MetadataGenerator metadataGenerator = mock(MetadataGenerator.class);
-    ScannerComponentIdGenerator idGenerator = new ScannerComponentIdGenerator();
-    ScanProperties properties = mock(ScanProperties.class);
-    sensorStrategy = new SensorStrategy();
-    builder = new InputFileBuilder(project, module, metadataGenerator, idGenerator, properties,
-      sensorStrategy);
-  }
-
-  @Test
-  public void testBuild() {
-    Path filePath = baseDir.resolve("module1/src/File1.xoo");
-    DefaultInputFile inputFile = builder.create(Type.MAIN, filePath, null);
-
-    assertThat(inputFile.absolutePath()).isEqualTo(filePath.toString().replaceAll("\\\\", "/"));
-    assertThat(inputFile.relativePath()).isEqualTo("src/File1.xoo");
-    assertThat(inputFile.path()).isEqualTo(filePath);
-    assertThat(inputFile.key()).isEqualTo("root:module1/src/File1.xoo");
-    assertThat(inputFile.isPublished()).isFalse();
-
-    sensorStrategy.setGlobal(true);
-
-    assertThat(inputFile.relativePath()).isEqualTo("module1/src/File1.xoo");
-  }
-}
index da570b48e27b1ac943b247161d95bf55ea8894ae..b46d174783bcd4dff288264fc9a9ec138051a49d 100644 (file)
@@ -31,10 +31,8 @@ import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
 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.FileMetadata;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.api.utils.PathUtils;
@@ -64,8 +62,7 @@ public class MetadataGeneratorTest {
     MockitoAnnotations.initMocks(this);
     metadata = new FileMetadata();
     IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class));
-    generator = new MetadataGenerator(new DefaultInputModule(ProjectDefinition.create().setKey("module").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())),
-      statusDetection, metadata, issueExclusionsLoader);
+    generator = new MetadataGenerator(statusDetection, metadata, issueExclusionsLoader);
   }
 
   @Test
@@ -94,7 +91,7 @@ public class MetadataGeneratorTest {
     DefaultInputFile inputFile = new TestInputFileBuilder("struts", relativePath)
       .setModuleBaseDir(baseDir)
       .build();
-    generator.setMetadata(inputFile, StandardCharsets.US_ASCII);
+    generator.setMetadata("module", inputFile, StandardCharsets.US_ASCII);
     return inputFile;
   }
 
index 523d875470d1f7571ac7a6c8cfcedf1f7699f583..cb1b4793940743a55ed02ebe6c643564e118e352 100644 (file)
@@ -49,7 +49,7 @@ public class ModuleInputComponentStoreTest {
   @Before
   public void setUp() throws IOException {
     DefaultInputProject root = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder());
-    componentStore = new InputComponentStore(root, mock(BranchConfiguration.class));
+    componentStore = new InputComponentStore(mock(BranchConfiguration.class));
   }
 
   @Test
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java
new file mode 100644 (file)
index 0000000..a4f0a30
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.filesystem;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.fs.IndexedFile;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
+import org.sonar.api.config.internal.MapSettings;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProjectExclusionFiltersTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+  private Path moduleBaseDir;
+  private MapSettings settings;
+
+  @Before
+  public void setUp() throws IOException {
+    settings = new MapSettings();
+    moduleBaseDir = temp.newFolder().toPath();
+  }
+
+  @Test
+  public void no_inclusions_nor_exclusions() throws IOException {
+    ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
+  }
+
+  @Test
+  public void match_inclusion() throws IOException {
+    settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java");
+    ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+
+    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
+  }
+
+  @Test
+  public void match_at_least_one_inclusion() throws IOException {
+    settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java,**/*Dto.java");
+    ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
+
+    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDto.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+  }
+
+  @Test
+  public void match_exclusions() throws IOException {
+    settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
+    settings.setProperty(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, "src/test/java/**/*");
+    settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.java");
+    ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
+
+    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+
+    // source exclusions do not apply to tests
+    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/test/java/com/mycompany/FooDao.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
+  }
+
+  @Test
+  public void match_exclusion_by_absolute_path() throws IOException {
+    File excludedFile = new File(moduleBaseDir.toString(), "src/main/java/org/bar/Bar.java");
+
+    settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
+    settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getAbsolutePath());
+    ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+    IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+
+    indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Bar.java", null);
+    assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
+  }
+
+  @Test
+  public void trim_pattern() {
+    ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+    assertThat(filter.prepareMainExclusions(new String[] {"   **/*Dao.java   "}, new String[0])[0].toString()).isEqualTo("**/*Dao.java");
+  }
+
+}
index 36f422d95bf730a1344a85db2de891d0d4c9fad7..d018ad2c300d59f49041f3edacdc1366a6a79eb4 100644 (file)
@@ -79,7 +79,7 @@ public class JSONReportTest {
 
     ProjectDefinition def = ProjectDefinition.create().setBaseDir(projectBaseDir).setWorkDir(temp.newFolder()).setKey("struts");
     DefaultInputProject project = new DefaultInputProject(def, 1);
-    InputComponentStore inputComponentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
+    InputComponentStore inputComponentStore = new InputComponentStore(mock(BranchConfiguration.class));
 
     DefaultInputFile inputFile = new TestInputFileBuilder("struts", "src/main/java/org/apache/struts/Action.java")
       .setModuleBaseDir(projectBaseDir.toPath()).build();