]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8622 Lazily generate metadata for input files 1576/head
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Tue, 24 Jan 2017 17:02:09 +0000 (18:02 +0100)
committerDuarte Meneses <duarte.meneses@sonarsource.com>
Fri, 27 Jan 2017 15:26:30 +0000 (16:26 +0100)
46 files changed:
sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectKey.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/FilePredicates.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/FileSystem.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/IndexedFile.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputComponent.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultIndexedFile.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/MetadataTest.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectAnalysisInfo.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerExtensionDictionnary.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/deprecated/DeprecatedSensorContext.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/index/DefaultIndex.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DeprecatedIssueAdapterForFilter.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CoveragePublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/SourcePublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.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/BatchIdGenerator.java
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
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStore.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/report/ConsoleReport.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/report/IssuesReportBuilder.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/report/JSONReport.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/ProjectAnalysisInfoTest.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/index/DefaultIndexTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/LogOutputRecorder.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java
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
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/ConsoleReportTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java
tests/perf/src/test/java/org/sonarsource/sonarqube/perf/scanner/suite/FileSystemTest.java
tests/upgrade/src/test/java/org/sonarsource/sonarqube/upgrade/UpgradeTest.java

index bcd9941d3872fe59dff7ffa074aa36b1e3a96126..a465da801c50affcefdf8d11522335a57be272f2 100644 (file)
@@ -19,6 +19,9 @@
  */
 package org.sonar.api.batch.bootstrap;
 
+/**
+ * Provides root project key with branch
+ */
 @FunctionalInterface
 public interface ProjectKey {
   String get();
index 1aa792889232be2f4c8e5f9c82152ddbc58ae9c9..9c6d07fd33fb08f45e1562726bfe7588b98c1d24 100644 (file)
@@ -61,6 +61,8 @@ public interface FilePredicates {
    * <code>some/path/Foo.java</code> and <code>other/path/Foo.java</code>.
    * The parameter must match exactly, no patterns are allowed,
    * and it must not be <code>null</code>.
+   * 
+   * @since 6.3
    */
   FilePredicate hasFilename(String s);
 
@@ -70,6 +72,8 @@ public interface FilePredicates {
    * <code>some/path/Foo.java</code> and <code>other/path/Foo.JAVA</code>
    * but not <code>some/path/Foo.js</code>.
    * The parameter must not be <code>null</code>.
+   * 
+   * @since 6.3
    */
   FilePredicate hasExtension(String s);
 
index 2c9adee3092cec43cedaee7b18b3ee0ec395add1..695e64b93448be0385eced32fc5abd30dae9ad9b 100644 (file)
@@ -163,11 +163,15 @@ public interface FileSystem {
 
     @CheckForNull
     InputDir inputDir(String relativePath);
-    
-    InputModule module();
 
+    /**
+     * @since 6.3
+     */
     Iterable<InputFile> getFilesByName(String filename);
 
+    /**
+     * @since 6.3
+     */
     Iterable<InputFile> getFilesByExtension(String extension);
   }
 }
index 89381593298668b227ce688b229adc06bf3436a3..492ce417ed67969f5255c64cd7cf82de750e7c63 100644 (file)
@@ -32,6 +32,9 @@ import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputPath;
 
 /**
+ * Represents the indexed view of an {@link InputFile}. Accessing any of data exposed here won't trigger the expensive generation of 
+ * metadata for the {@link InputFile}.
+ * 
  * @since 6.3 
  */
 public interface IndexedFile extends InputPath {
index c6272fb8aee81133a3dcdc4c3a481ac716c25319..645b7f86d20b71469036943047b5c73b37861130 100644 (file)
@@ -30,14 +30,14 @@ package org.sonar.api.batch.fs;
 public interface InputComponent {
 
   /**
-   * Component key shared by all part of SonarQube (batch, server, WS...)
+   * Component key shared by all part of SonarQube (batch, server, WS...). 
+   * It doesn't include the branch.
    */
   String key();
-  
+
   /**
    * Is the component an {@link InputFile}
    */
   boolean isFile();
-  
 
 }
index de2c28766de86b4d7fc4d12cd0baf527a69f66c1..bdac6453b75aaeab682284d084f6c21ab0336425 100644 (file)
@@ -43,7 +43,6 @@ import org.sonar.api.batch.fs.FilePredicates;
 import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.InputDir;
 import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputModule;
 import org.sonar.api.scan.filesystem.PathResolver;
 import org.sonar.api.utils.PathUtils;
 
@@ -204,11 +203,6 @@ public class DefaultFileSystem implements FileSystem {
     return this;
   }
   
-  public DefaultFileSystem add(InputModule inputModule) {
-    cache.add(inputModule);
-    return this;
-  }
-
   /**
    * Adds a language to the list. To be used only for unit tests that need to use {@link #languages()} without
    * using {@link #add(InputFile)}.
@@ -243,8 +237,6 @@ public class DefaultFileSystem implements FileSystem {
 
     protected abstract void doAdd(InputDir inputDir);
 
-    protected abstract void doAdd(InputModule inputModule);
-
     final void add(InputFile inputFile) {
       doAdd(inputFile);
     }
@@ -252,11 +244,6 @@ public class DefaultFileSystem implements FileSystem {
     public void add(InputDir inputDir) {
       doAdd(inputDir);
     }
-
-    public void add(InputModule inputModule) {
-      doAdd(inputModule);
-    }
-
   }
 
   /**
@@ -265,7 +252,6 @@ public class DefaultFileSystem implements FileSystem {
   private static class MapCache extends Cache {
     private final Map<String, InputFile> fileMap = new HashMap<>();
     private final Map<String, InputDir> dirMap = new HashMap<>();
-    private InputModule module;
     private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create();
     private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
 
@@ -284,11 +270,6 @@ public class DefaultFileSystem implements FileSystem {
       return dirMap.get(relativePath);
     }
 
-    @Override
-    public InputModule module() {
-      return module;
-    }
-
     @Override
     public Iterable<InputFile> getFilesByName(String filename) {
       return filesByNameCache.get(filename);
@@ -298,7 +279,6 @@ public class DefaultFileSystem implements FileSystem {
       return filesByExtensionCache.get(extension);
     }
 
-    @Override
     protected void doAdd(InputFile inputFile) {
       fileMap.put(inputFile.relativePath(), inputFile);
       filesByNameCache.put(FilenamePredicate.getFilename(inputFile), inputFile);
@@ -309,11 +289,6 @@ public class DefaultFileSystem implements FileSystem {
     protected void doAdd(InputDir inputDir) {
       dirMap.put(inputDir.relativePath(), inputDir);
     }
-
-    @Override
-    protected void doAdd(InputModule inputModule) {
-      module = inputModule;
-    }
   }
 
   @Override
index d29b42c8b591577be19b643f33314b36a630bb19..ff653561dfc51f4dbe8a7a7fae0c880240a4dc9b 100644 (file)
@@ -29,6 +29,9 @@ import org.sonar.api.batch.fs.IndexedFile;
 import org.sonar.api.batch.fs.InputFile.Type;
 import org.sonar.api.utils.PathUtils;
 
+/**
+ * @since 6.3
+ */
 public class DefaultIndexedFile extends DefaultInputComponent implements IndexedFile {
   private final String relativePath;
   private final String moduleKey;
@@ -92,7 +95,7 @@ public class DefaultIndexedFile extends DefaultInputComponent implements Indexed
   }
 
   /**
-   * Component key.
+   * Component key (without branch).
    */
   @Override
   public String key() {
index cecc2e410d73b8328c38302a70fce6b874f9e0eb..192ac05be54c83acb416f3e69ea42957f30fdd4f 100644 (file)
@@ -40,25 +40,33 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
   private Status status;
   private Charset charset;
   private Metadata metadata;
-  private boolean publish = false;
+  private boolean publish;
 
   public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator) {
     super(indexedFile.batchId());
     this.indexedFile = indexedFile;
     this.metadataGenerator = metadataGenerator;
     this.metadata = null;
+    this.publish = false;
   }
 
-  private void checkMetadata() {
+  public void checkMetadata() {
     if (metadata == null) {
       metadataGenerator.accept(this);
     }
   }
 
-  public void setPublish(boolean publish) {
+  /**
+   * @since 6.3
+   */
+  public DefaultInputFile setPublish(boolean publish) {
     this.publish = publish;
+    return this;
   }
 
+  /**
+   * @since 6.3
+   */
   public boolean publish() {
     return publish;
   }
@@ -95,7 +103,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
   }
 
   /**
-   * Component key.
+   * Component key (without branch).
    */
   @Override
   public String key() {
index 9e7ebd82422ce90853c95a80fdc4600682ffd6c9..1aa685e79c33f9afe3c497d5f5be850e94be2065 100644 (file)
@@ -157,7 +157,12 @@ public interface SensorContext {
    * @since 6.1
    */
   void addContextProperty(String key, String value);
-  
+
+  /**
+   * Indicate that a file should be published in the report sent to SonarQube.
+   * Files are automatically marked if any data is created for it (issues, highlighting, coverage, etc.).
+   * @since 6.3
+   */
   void markForPublishing(InputFile inputFile);
 
 }
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/MetadataTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/MetadataTest.java
new file mode 100644 (file)
index 0000000..df0ce52
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.api.batch.fs.internal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class MetadataTest {
+  @Test
+  public void testRoundtrip() {
+    Metadata metadata = new Metadata(10, 20, "hash", new int[] {1, 2}, 30);
+    assertThat(metadata.lastValidOffset()).isEqualTo(30);
+    assertThat(metadata.lines()).isEqualTo(10);
+    assertThat(metadata.nonBlankLines()).isEqualTo(20);
+    assertThat(metadata.originalLineOffsets()).isEqualTo(new int[] {1, 2});
+    assertThat(metadata.hash()).isEqualTo("hash");
+  }
+}
index 3441db14cefa3a485e1fecb8e49884dd3731787c..98013b4881cac85af553dd0c3f031a259553ee02 100644 (file)
@@ -28,8 +28,7 @@ import org.sonar.api.utils.SonarException;
 import org.sonar.api.utils.System2;
 
 /**
- * Used by views !!
- *
+ * @since 6.3
  */
 @ScannerSide
 public class ProjectAnalysisInfo implements Startable {
index 446edb161ef39f556f299b99c6fd23c9262ac4cc..fa9189c0d6178ac5ef915b5e9a709140730e0caa 100644 (file)
@@ -63,8 +63,7 @@ public class ScannerExtensionDictionnary {
   private final PostJobOptimizer postJobOptimizer;
 
   public ScannerExtensionDictionnary(ComponentContainer componentContainer, DefaultSensorContext sensorContext,
-    SensorOptimizer sensorOptimizer, PostJobContext postJobContext,
-    PostJobOptimizer postJobOptimizer) {
+    SensorOptimizer sensorOptimizer, PostJobContext postJobContext, PostJobOptimizer postJobOptimizer) {
     this.componentContainer = componentContainer;
     this.sensorContext = sensorContext;
     this.sensorOptimizer = sensorOptimizer;
index 451d0a926421953516e0d0266cbd5f73154445f8..ac76cc2221215a0189c27647ec3c6b2dcf2d28e1 100644 (file)
@@ -110,7 +110,7 @@ public class CpdExecutor {
   void runCpdAnalysis(ExecutorService executorService, String componentKey, final Collection<Block> fileBlocks, long timeout) {
     DefaultInputComponent component = (DefaultInputComponent) componentStore.getByKey(componentKey);
     if (component == null) {
-      LOG.error("Resource not found in component cache: {}. Skipping CPD computation for it", componentKey);
+      LOG.error("Resource not found in component store: {}. Skipping CPD computation for it", componentKey);
       return;
     }
 
index cfc2d8cf89e24013f6e93d4c639a176c0dfdf019..1c7b788edce25f5f0072d93ddaad30534225954d 100644 (file)
@@ -55,12 +55,12 @@ public class DeprecatedSensorContext extends DefaultSensorContext implements Sen
 
   @Override
   public Resource getParent(Resource reference) {
-    return index.getParent(reference.getEffectiveKey());
+    return index.getParent(getComponentKey(reference));
   }
 
   @Override
   public Collection<Resource> getChildren(Resource reference) {
-    return index.getChildren(reference.getEffectiveKey());
+    return index.getChildren(getComponentKey(reference));
   }
 
   @Override
@@ -68,6 +68,9 @@ public class DeprecatedSensorContext extends DefaultSensorContext implements Sen
     return index.getMeasure(module.key(), metric);
   }
 
+  /**
+   * Returns effective key of a resource, without branch.
+   */
   private String getComponentKey(Resource r) {
     if (ResourceUtils.isProject(r) || /* For technical projects */ResourceUtils.isRootProject(r)) {
       return r.getKey();
@@ -93,7 +96,7 @@ public class DeprecatedSensorContext extends DefaultSensorContext implements Sen
 
   @Override
   public <G extends Serializable> Measure<G> getMeasure(Resource resource, Metric<G> metric) {
-    return index.getMeasure(resource.getEffectiveKey(), metric);
+    return index.getMeasure(getComponentKey(resource), metric);
   }
 
   @Override
index 32019e1f0bdbc5279e64d4697412b24bc18e472d..9a4e49a4eb842681c430f98bf1160a930ea8714b 100644 (file)
@@ -62,7 +62,7 @@ public class DefaultIndex {
     this.metricFinder = metricFinder;
   }
 
-  public void setCurrentProject(DefaultSensorStorage sensorStorage) {
+  public void setCurrentStorage(DefaultSensorStorage sensorStorage) {
     // the following components depend on the current module, so they need to be reloaded.
     this.sensorStorage = sensorStorage;
   }
@@ -156,6 +156,9 @@ public class DefaultIndex {
     return measure;
   }
 
+  /**
+   * @param key Effective key, without branch
+   */
   @CheckForNull
   public Resource getParent(String key) {
     InputComponent component = componentStore.getByKey(key);
@@ -170,6 +173,9 @@ public class DefaultIndex {
     return toResource(parent);
   }
 
+  /**
+   * @param key Effective key, without branch
+   */
   public Collection<Resource> getChildren(String key) {
     InputComponent component = componentStore.getByKey(key);
     Collection<InputComponent> children = tree.getChildren(component);
@@ -191,6 +197,10 @@ public class DefaultIndex {
     return r;
   }
 
+  /**
+   * Gets a component from the store as a resource.
+   * @param key Effective key, without branch
+   */
   @CheckForNull
   public Resource getResource(String key) {
     InputComponent component = componentStore.getByKey(key);
index 00cf22d19b2b8884c4ba9d27d47fa3109fdea0aa..83ef4634dcbcba724cb6ea1b0dcf32b1ed0c4223 100644 (file)
@@ -25,7 +25,6 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
-import org.sonar.api.batch.fs.InputModule;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueComment;
@@ -43,9 +42,9 @@ class DeprecatedIssueAdapterForFilter implements Issue {
   private DefaultInputModule module;
   private ProjectAnalysisInfo projectAnalysisInfo;
 
-  DeprecatedIssueAdapterForFilter(InputModule module, ProjectAnalysisInfo projectAnalysisInfo, org.sonar.scanner.protocol.output.ScannerReport.Issue rawIssue,
+  DeprecatedIssueAdapterForFilter(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, org.sonar.scanner.protocol.output.ScannerReport.Issue rawIssue,
     String componentKey) {
-    this.module = (DefaultInputModule) module;
+    this.module = module;
     this.projectAnalysisInfo = projectAnalysisInfo;
     this.rawIssue = rawIssue;
     this.componentKey = componentKey;
index f485dec405c3adf3f0b31197f80c02e9ef15e66e..7d961244f24e41c5a6e748125268aa400cc4000f 100644 (file)
@@ -25,7 +25,7 @@ import org.sonar.api.scan.issue.filter.IssueFilterChain;
 import org.sonar.scanner.ProjectAnalysisInfo;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.scan.issue.filter.IssueFilter;
 
@@ -33,25 +33,25 @@ import org.sonar.api.scan.issue.filter.IssueFilter;
 public class IssueFilters {
   private final IssueFilter[] filters;
   private final org.sonar.api.issue.batch.IssueFilter[] deprecatedFilters;
-  private final InputModule module;
+  private final DefaultInputModule module;
   private final ProjectAnalysisInfo projectAnalysisInfo;
 
-  public IssueFilters(InputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] exclusionFilters, org.sonar.api.issue.batch.IssueFilter[] filters) {
+  public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] exclusionFilters, org.sonar.api.issue.batch.IssueFilter[] filters) {
     this.module = module;
     this.filters = exclusionFilters;
     this.deprecatedFilters = filters;
     this.projectAnalysisInfo = projectAnalysisInfo;
   }
 
-  public IssueFilters(InputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] filters) {
+  public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] filters) {
     this(module, projectAnalysisInfo, filters, new org.sonar.api.issue.batch.IssueFilter[0]);
   }
 
-  public IssueFilters(InputModule module, ProjectAnalysisInfo projectAnalysisInfo, org.sonar.api.issue.batch.IssueFilter[] deprecatedFilters) {
+  public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, org.sonar.api.issue.batch.IssueFilter[] deprecatedFilters) {
     this(module, projectAnalysisInfo, new IssueFilter[0], deprecatedFilters);
   }
 
-  public IssueFilters(InputModule module, ProjectAnalysisInfo projectAnalysisInfo) {
+  public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo) {
     this(module, projectAnalysisInfo, new IssueFilter[0], new org.sonar.api.issue.batch.IssueFilter[0]);
   }
 
index 478b29bc5d6e0b3b96813497ec03f193610e5a4c..c68bf066b49f114dbdfed89e49cbecfe00d04e1d 100644 (file)
@@ -31,7 +31,6 @@ import org.sonar.scanner.rule.QProfileVerifier;
 import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
 import org.sonar.scanner.scan.filesystem.FileSystemLogger;
 import org.sonar.scanner.scan.report.IssuesReports;
-import org.sonar.scanner.scm.ScmPublisher;
 
 public final class IssuesPhaseExecutor extends AbstractPhaseExecutor {
 
index 2060505fca814ea9fe4161bc206a39b8da2e7fd0..c59e26f21f68c25405025c4a46d6db07f7be5a68 100644 (file)
@@ -25,7 +25,6 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import javax.annotation.Nonnull;
 import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.measures.CoreMetrics;
@@ -48,8 +47,7 @@ public class CoveragePublisher implements ReportPublisherStep {
 
   @Override
   public void publish(ScannerReportWriter writer) {
-    for (final InputFile file : componentCache.allFiles()) {
-      DefaultInputFile inputFile = (DefaultInputFile) file;
+    for (final DefaultInputFile inputFile : componentCache.allFilesToPublish()) {
       Map<Integer, LineCoverage.Builder> coveragePerLine = new LinkedHashMap<>();
 
       int lineCount = inputFile.lines();
index ed54d5261cb8b8751f10f86339a69e6e33f095be..ba283458e1439db6346db56c9573ca6762f72935 100644 (file)
@@ -68,12 +68,12 @@ import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES_KEY;
 
 public class MeasuresPublisher implements ReportPublisherStep {
 
-  private final InputComponentStore componentCache;
+  private final InputComponentStore componentStore;
   private final MeasureCache measureCache;
   private final TestPlanBuilder testPlanBuilder;
 
-  public MeasuresPublisher(InputComponentStore componentCache, MeasureCache measureCache, TestPlanBuilder testPlanBuilder) {
-    this.componentCache = componentCache;
+  public MeasuresPublisher(InputComponentStore componentStore, MeasureCache measureCache, TestPlanBuilder testPlanBuilder) {
+    this.componentStore = componentStore;
     this.measureCache = measureCache;
     this.testPlanBuilder = testPlanBuilder;
   }
@@ -82,7 +82,7 @@ public class MeasuresPublisher implements ReportPublisherStep {
   public void publish(ScannerReportWriter writer) {
     final ScannerReport.Measure.Builder builder = ScannerReport.Measure.newBuilder();
 
-    for (final InputComponent c : componentCache.all()) {
+    for (final InputComponent c : componentStore.all()) {
       DefaultInputComponent component = (DefaultInputComponent) c;
       // Recompute all coverage measures from line data to take into account the possible merge of several reports
       updateCoverageFromLineData(component);
index b270567f86f25d23c8ec1a555a08763615956f39..17ef8bf7ffcc16c2c1b064f0ade40bd5d67af029 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.scanner.report;
 import org.apache.commons.io.ByteOrderMark;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.input.BOMInputStream;
-import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.scanner.protocol.output.ScannerReportWriter;
 import org.sonar.scanner.scan.filesystem.InputComponentStore;
@@ -39,32 +38,36 @@ public class SourcePublisher implements ReportPublisherStep {
 
   private final InputComponentStore componentCache;
 
-  public SourcePublisher(InputComponentStore componentCache) {
-    this.componentCache = componentCache;
+  public SourcePublisher(InputComponentStore componentStore) {
+    this.componentCache = componentStore;
   }
 
   @Override
   public void publish(ScannerReportWriter writer) {
-    for (final InputFile file : componentCache.allFiles()) {
-      DefaultInputFile inputFile = (DefaultInputFile) file;
+    for (final DefaultInputFile inputFile : componentCache.allFilesToPublish()) {
       File iofile = writer.getSourceFile(inputFile.batchId());
-      int line = 0;
+
       try (FileOutputStream output = new FileOutputStream(iofile);
         BOMInputStream bomIn = new BOMInputStream(new FileInputStream(inputFile.file()),
           ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
         BufferedReader reader = new BufferedReader(new InputStreamReader(bomIn, inputFile.charset()))) {
-        String lineStr = reader.readLine();
-        while (lineStr != null) {
-          IOUtils.write(lineStr, output, StandardCharsets.UTF_8);
-          line++;
-          if (line < inputFile.lines()) {
-            IOUtils.write("\n", output, StandardCharsets.UTF_8);
-          }
-          lineStr = reader.readLine();
-        }
+        writeSource(reader, output, inputFile.lines());
       } catch (IOException e) {
         throw new IllegalStateException("Unable to store file source in the report", e);
       }
     }
   }
+
+  private static void writeSource(BufferedReader reader, FileOutputStream output, int lines) throws IOException {
+    int line = 0;
+    String lineStr = reader.readLine();
+    while (lineStr != null) {
+      IOUtils.write(lineStr, output, StandardCharsets.UTF_8);
+      line++;
+      if (line < lines) {
+        IOUtils.write("\n", output, StandardCharsets.UTF_8);
+      }
+      lineStr = reader.readLine();
+    }
+  }
 }
index 24c1557246a4cd0d2375ab806cff078f2c725d75..31f75f3ef403d44dd06b5021a74e6f4204c73fd2 100644 (file)
@@ -23,17 +23,24 @@ import org.picocontainer.Startable;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
 
+/**
+ * Indexes all modules into {@link DefaultComponentTree}, {@link DefaultInputModuleHierarchy) and {@link InputComponentStore}, using the 
+ * project definitions provided by the {@link ImmutableProjectReactor}.
+ */
 public class ModuleIndexer implements Startable {
   private final ImmutableProjectReactor projectReactor;
   private final DefaultComponentTree componentTree;
   private final DefaultInputModuleHierarchy moduleHierarchy;
   private final BatchIdGenerator batchIdGenerator;
+  private final InputComponentStore componentStore;
 
   public ModuleIndexer(ImmutableProjectReactor projectReactor, DefaultComponentTree componentTree,
-    BatchIdGenerator batchIdGenerator, DefaultInputModuleHierarchy moduleHierarchy) {
+    InputComponentStore componentStore, BatchIdGenerator batchIdGenerator, DefaultInputModuleHierarchy moduleHierarchy) {
     this.projectReactor = projectReactor;
     this.componentTree = componentTree;
+    this.componentStore = componentStore;
     this.moduleHierarchy = moduleHierarchy;
     this.batchIdGenerator = batchIdGenerator;
   }
@@ -42,6 +49,7 @@ public class ModuleIndexer implements Startable {
   public void start() {
     DefaultInputModule root = new DefaultInputModule(projectReactor.getRoot(), batchIdGenerator.get());
     moduleHierarchy.setRoot(root);
+    componentStore.put(root);
     createChildren(root);
   }
 
@@ -50,6 +58,7 @@ public class ModuleIndexer implements Startable {
       DefaultInputModule child = new DefaultInputModule(def, batchIdGenerator.get());
       moduleHierarchy.index(child, parent);
       componentTree.index(child, parent);
+      componentStore.put(child);
       createChildren(child);
     }
   }
index 9c087e1b1d7e15df559c2785c71d66bab06f6dbe..b62ad60e1a866c568212a6be1191d96f2fd51972 100644 (file)
@@ -167,7 +167,7 @@ public class ModuleScanContainer extends ComponentContainer {
   @Override
   protected void doAfterStart() {
     DefaultIndex index = getComponentByType(DefaultIndex.class);
-    index.setCurrentProject(getComponentByType(DefaultSensorStorage.class));
+    index.setCurrentStorage(getComponentByType(DefaultSensorStorage.class));
 
     getComponentByType(AbstractPhaseExecutor.class).execute(module);
   }
index 0144b2e7a4b90a68c347120a63fd5b943e278cbe..d9ddca72dbf5c360bee6cced7d408fa0188cbc02 100644 (file)
@@ -139,7 +139,6 @@ public class ProjectScanContainer extends ComponentContainer {
       ProjectAnalysisInfo.class,
       DefaultIndex.class,
       Storages.class,
-      DefaultIssueCallback.class,
       new RulesProvider(),
       new ProjectRepositoriesProvider(),
 
@@ -159,6 +158,7 @@ public class ProjectScanContainer extends ComponentContainer {
       new QualityProfileProvider(),
 
       // issues
+      DefaultIssueCallback.class,
       IssueCache.class,
       DefaultProjectIssues.class,
       IssueTransition.class,
index 48d90078bae3e5069374366e76f88e4e2c09c638..6443c15dc506c143190e905e26bca45ab50eed1b 100644 (file)
  */
 package org.sonar.scanner.scan.filesystem;
 
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Supplier;
 
+import org.sonar.api.batch.fs.InputComponent;
+
+/**
+ * Generates unique IDs for any {@link InputComponent}. 
+ * The IDs must be unique among all types of components and for all modules in the project.
+ * The ID should never be 0, as it is sometimes used to indicate invalid components. 
+ */
 public class BatchIdGenerator implements Supplier<Integer> {
-  private int nextBatchId = 1;
+  private AtomicInteger nextBatchId = new AtomicInteger(1);
 
   @Override
   public Integer get() {
-    return nextBatchId++;
+    return nextBatchId.getAndIncrement();
   }
 }
index 61ef1d38d27d6b30c155ed9b5f4a1703b028b109..c72c6ed09c08c3530990b224fb26b960e93cc9a5 100644 (file)
@@ -29,11 +29,18 @@ 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.HashSet;
 import java.util.List;
 import java.util.Set;
+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;
@@ -50,6 +57,8 @@ import org.sonar.api.utils.MessageException;
 import org.sonar.scanner.scan.DefaultComponentTree;
 import org.sonar.scanner.util.ProgressReport;
 
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
 /**
  * Index input files into {@link InputComponentStore}.
  */
@@ -65,6 +74,8 @@ public class FileIndexer {
   private final DefaultInputModule module;
   private final BatchIdGenerator batchIdGenerator;
   private final InputComponentStore componentStore;
+  private ExecutorService executorService;
+  private final List<Future<Void>> tasks;
 
   private ProgressReport progressReport;
 
@@ -77,6 +88,7 @@ public class FileIndexer {
     this.inputFileBuilder = inputFileBuilder;
     this.filters = filters;
     this.exclusionFilters = exclusionFilters;
+    this.tasks = new ArrayList<>();
     this.isAggregator = !def.getSubProjects().isEmpty();
   }
 
@@ -86,11 +98,14 @@ public class FileIndexer {
   }
 
   void index(DefaultModuleFileSystem fileSystem) {
-    fileSystem.add(module);
     if (isAggregator) {
       // No indexing for an aggregator module
       return;
     }
+
+    int threads = Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
+    this.executorService = Executors.newFixedThreadPool(threads, new ThreadFactoryBuilder().setNameFormat("FileIndexer-%d").build());
+
     progressReport = new ProgressReport("Report about progress of file indexation", TimeUnit.SECONDS.toMillis(10));
     progressReport.start("Index files");
     exclusionFilters.prepare();
@@ -100,20 +115,40 @@ public class FileIndexer {
     indexFiles(fileSystem, progress, fileSystem.sources(), InputFile.Type.MAIN);
     indexFiles(fileSystem, progress, fileSystem.tests(), InputFile.Type.TEST);
 
-    progressReport.stop(progress.count() + " files indexed");
+    waitForTasksToComplete();
+
+    progressReport.stop(progress.count() + " " + pluralizeFiles(progress.count()) + " indexed");
 
     if (exclusionFilters.hasPattern()) {
-      LOG.info("{} files ignored because of inclusion/exclusion patterns", progress.excludedByPatternsCount());
+      LOG.info("{} {} ignored because of inclusion/exclusion patterns", progress.excludedByPatternsCount(), pluralizeFiles(progress.excludedByPatternsCount()));
+    }
+  }
+
+  private void waitForTasksToComplete() {
+    executorService.shutdown();
+    for (Future<Void> task : tasks) {
+      try {
+        task.get();
+      } catch (ExecutionException e) {
+        // Unwrap ExecutionException
+        throw e.getCause() instanceof RuntimeException ? (RuntimeException) e.getCause() : new IllegalStateException(e.getCause());
+      } catch (InterruptedException e) {
+        throw new IllegalStateException(e);
+      }
     }
   }
 
+  private static String pluralizeFiles(int count) {
+    return count == 1 ? "file" : "files";
+  }
+
   private void indexFiles(DefaultModuleFileSystem fileSystem, Progress progress, List<File> sources, InputFile.Type type) {
     try {
       for (File dirOrFile : sources) {
         if (dirOrFile.isDirectory()) {
           indexDirectory(fileSystem, progress, dirOrFile.toPath(), type);
         } else {
-          indexFile(fileSystem, progress, dirOrFile.toPath(), type);
+          tasks.add(executorService.submit(() -> indexFile(fileSystem, progress, dirOrFile.toPath(), type)));
         }
       }
     } catch (IOException e) {
@@ -126,20 +161,24 @@ public class FileIndexer {
       new IndexFileVisitor(fileSystem, status, type));
   }
 
-  private void indexFile(DefaultModuleFileSystem fileSystem, Progress progress, Path sourceFile, InputFile.Type type) throws IOException {
+  private Void indexFile(DefaultModuleFileSystem fileSystem, Progress progress, Path sourceFile, InputFile.Type type) throws IOException {
     // get case of real file without resolving link
     Path realFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS);
     DefaultInputFile inputFile = inputFileBuilder.create(realFile, type, fileSystem.encoding());
     if (inputFile != null) {
       if (exclusionFilters.accept(inputFile, type) && accept(inputFile)) {
-        fileSystem.add(inputFile);
-        indexParentDir(fileSystem, inputFile);
-        progress.markAsIndexed(inputFile);
+        synchronized (this) {
+          fileSystem.add(inputFile);
+          indexParentDir(fileSystem, inputFile);
+          progress.markAsIndexed(inputFile);
+        }
         LOG.debug("'{}' indexed {} with language '{}'", inputFile.relativePath(), type == Type.TEST ? "as test " : "", inputFile.language());
+        inputFileBuilder.checkMetadata(inputFile);
       } else {
         progress.increaseExcludedByPatternsCount();
       }
     }
+    return null;
   }
 
   private void indexParentDir(DefaultModuleFileSystem fileSystem, InputFile inputFile) {
@@ -197,7 +236,7 @@ public class FileIndexer {
     @Override
     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
       if (!Files.isHidden(file)) {
-        indexFile(fileSystem, status, file, type);
+        tasks.add(executorService.submit(() -> indexFile(fileSystem, status, file, type)));
       }
       return FileVisitResult.CONTINUE;
     }
@@ -220,23 +259,23 @@ public class FileIndexer {
 
   private class Progress {
     private final Set<Path> indexed = new HashSet<>();
-    private int excludedByPatternsCount = 0;
+    private AtomicInteger excludedByPatternsCount = new AtomicInteger(0);
 
-    synchronized void markAsIndexed(IndexedFile inputFile) {
+    void markAsIndexed(IndexedFile inputFile) {
       if (indexed.contains(inputFile.path())) {
         throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
           + "disjoint sets for main and test files");
       }
       indexed.add(inputFile.path());
-      progressReport.message(indexed.size() + " files indexed...  (last one was " + inputFile.relativePath() + ")");
+      progressReport.message(indexed.size() + " " + pluralizeFiles(indexed.size()) + " indexed...  (last one was " + inputFile.relativePath() + ")");
     }
 
     void increaseExcludedByPatternsCount() {
-      excludedByPatternsCount++;
+      excludedByPatternsCount.incrementAndGet();
     }
 
     public int excludedByPatternsCount() {
-      return excludedByPatternsCount;
+      return excludedByPatternsCount.get();
     }
 
     int count() {
index ae6c52d38c54a129caa4850d1b94bdfcc4c8106e..54bf5b9e3e6ed4cd83aeaf2da9da4b10057d6d52 100644 (file)
@@ -59,6 +59,12 @@ public class InputComponentStore {
     return inputComponents.values();
   }
 
+  public Iterable<DefaultInputFile> allFilesToPublish() {
+    return inputFileCache.values().stream()
+      .map(f -> (DefaultInputFile) f)
+      .filter(DefaultInputFile::publish)::iterator;
+  }
+
   public Iterable<InputFile> allFiles() {
     return inputFileCache.values();
   }
index c3826963bb6a85fb3efb802bb7cf58faffc44cbb..4a41149f65b8bc0b9f78c14c8c7e8ab4708f3be0 100644 (file)
@@ -30,9 +30,11 @@ 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.config.Settings;
 import org.sonar.api.scan.filesystem.PathResolver;
 
 public class InputFileBuilder {
+  private static final String PRELOAD_FILE_METADATA_KEY = "sonar.preloadFileMetadata";
   private static final Logger LOG = LoggerFactory.getLogger(InputFileBuilder.class);
   private final String moduleKey;
   private final Path moduleBaseDir;
@@ -40,15 +42,17 @@ public class InputFileBuilder {
   private final LanguageDetection langDetection;
   private final BatchIdGenerator idGenerator;
   private final MetadataGenerator metadataGenerator;
+  private final boolean preloadMetadata;
 
   public InputFileBuilder(DefaultInputModule module, PathResolver pathResolver, LanguageDetection langDetection, MetadataGenerator metadataGenerator,
-    BatchIdGenerator idGenerator) {
+    BatchIdGenerator idGenerator, Settings settings) {
     this.moduleKey = module.key();
     this.moduleBaseDir = module.definition().getBaseDir().toPath();
     this.pathResolver = pathResolver;
     this.langDetection = langDetection;
     this.metadataGenerator = metadataGenerator;
     this.idGenerator = idGenerator;
+    this.preloadMetadata = settings.getBoolean(PRELOAD_FILE_METADATA_KEY);
   }
 
   @CheckForNull
@@ -65,6 +69,13 @@ public class InputFileBuilder {
       return null;
     }
     indexedFile.setLanguage(language);
+
     return new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(f, defaultEncoding));
   }
+
+  void checkMetadata(DefaultInputFile inputFile) {
+    if (preloadMetadata) {
+      inputFile.checkMetadata();
+    }
+  }
 }
index ace650416747bd22b50f4503e7907230749c3c73..8d1f6d69c27e171b675a8aea6bec353a7b345ac9 100644 (file)
@@ -21,11 +21,12 @@ package org.sonar.scanner.scan.filesystem;
 
 import com.google.common.annotations.VisibleForTesting;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -53,12 +54,30 @@ class MetadataGenerator {
     this.fileMetadata = fileMetadata;
   }
 
+  /**
+   * 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) {
+    try {
+      Charset charset = detectCharset(inputFile.path(), defaultEncoding);
+      inputFile.setCharset(charset);
+      Metadata metadata = fileMetadata.readMetadata(inputFile.file(), charset);
+      inputFile.setMetadata(metadata);
+      inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile.relativePath(), metadata.hash()));
+      LOG.debug("'{}' generated metadata {} with charset '{}'",
+        inputFile.relativePath(), inputFile.type() == Type.TEST ? "as test " : "", charset);
+    } catch (Exception e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
   /**
    * @return charset detected from BOM in given file or given defaultCharset
    * @throws IllegalStateException if an I/O error occurs
    */
-  private static Charset detectCharset(File file, Charset defaultCharset) {
-    try (FileInputStream inputStream = new FileInputStream(file)) {
+  private static Charset detectCharset(Path path, Charset defaultCharset) {
+    try (InputStream inputStream = Files.newInputStream(path)) {
       byte[] bom = new byte[4];
       int n = inputStream.read(bom, 0, bom.length);
       if ((n >= 3) && (bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
@@ -75,21 +94,7 @@ class MetadataGenerator {
         return defaultCharset;
       }
     } catch (IOException e) {
-      throw new IllegalStateException("Unable to read file " + file.getAbsolutePath(), e);
-    }
-  }
-
-  public void setMetadata(final DefaultInputFile inputFile, Charset defaultEncoding) {
-    try {
-      Charset charset = detectCharset(inputFile.file(), defaultEncoding);
-      inputFile.setCharset(charset);
-      Metadata metadata = fileMetadata.readMetadata(inputFile.file(), charset);
-      inputFile.setMetadata(metadata);
-      inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile.relativePath(), metadata.hash()));
-      LOG.debug("'{}' generated metadata {} with and charset '{}'",
-        inputFile.relativePath(), inputFile.type() == Type.TEST ? "as test " : "", charset);
-    } catch (Exception e) {
-      throw new IllegalStateException(e);
+      throw new IllegalStateException("Unable to read file " + path.toAbsolutePath().toString(), e);
     }
   }
 }
index dd518d9d152c5720680cfdada68db7c184be366a..d276b852cdd88ce6e27ae2dda472fdebe1e8ac7e 100644 (file)
@@ -61,16 +61,6 @@ public class ModuleInputComponentStore extends DefaultFileSystem.Cache {
     inputComponentStore.put(inputDir);
   }
 
-  @Override
-  protected void doAdd(InputModule inputModule) {
-    inputComponentStore.put(inputModule);
-  }
-
-  @Override
-  public InputModule module() {
-    return inputComponentStore.getModule(moduleKey);
-  }
-
   @Override
   public Iterable<InputFile> getFilesByName(String filename) {
     return inputComponentStore.getFilesByName(filename);
index 94f7054a128c6e75baf1f06372bb3467e388ad58..5dc8df428088aa97c22c9a41652fa97095d66b9a 100644 (file)
@@ -100,7 +100,7 @@ public class ConsoleReport implements Reporter {
     if (settings.getBoolean(CONSOLE_REPORT_ENABLED_KEY)) {
       LOG.warn("Console report is deprecated. Use SonarLint CLI to have local reports of issues");
       Report r = new Report();
-      r.setNoFile(!inputPathCache.allFiles().iterator().hasNext());
+      r.setNoFile(!inputPathCache.allFilesToPublish().iterator().hasNext());
       for (TrackedIssue issue : issueCache.all()) {
         r.process(issue);
       }
index 7d5e82a2f8f61d10b74245f6dcebba206cd0d54f..a711166fe7e643bab8b908e5d9ffa8b5f33db5cc 100644 (file)
@@ -58,7 +58,7 @@ public class IssuesReportBuilder {
   public IssuesReport buildReport() {
     DefaultInputModule project = moduleHierarchy.root();
     IssuesReport issuesReport = new IssuesReport();
-    issuesReport.setNoFile(!inputComponentCache.allFiles().iterator().hasNext());
+    issuesReport.setNoFile(!inputComponentCache.allFilesToPublish().iterator().hasNext());
     issuesReport.setTitle(project.definition().getName());
     issuesReport.setDate(projectAnalysisInfo.analysisDate());
 
index f1ce201314733a76c298afb7c70ec1579388c047..6551ddb2dc77ed620b7e23a5bd45bd884290488e 100644 (file)
@@ -40,7 +40,6 @@ import org.sonar.api.Property;
 import org.sonar.api.PropertyType;
 import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputDir;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
@@ -73,13 +72,13 @@ public class JSONReport implements Reporter {
   private final Server server;
   private final Rules rules;
   private final IssueCache issueCache;
-  private final InputComponentStore fileCache;
+  private final InputComponentStore componentStore;
   private final DefaultInputModule rootModule;
   private final UserRepositoryLoader userRepository;
   private final InputModuleHierarchy moduleHierarchy;
 
   public JSONReport(InputModuleHierarchy moduleHierarchy, Settings settings, FileSystem fileSystem, Server server, Rules rules, IssueCache issueCache,
-    DefaultInputModule rootModule, InputComponentStore fileCache, UserRepositoryLoader userRepository) {
+    DefaultInputModule rootModule, InputComponentStore componentStore, UserRepositoryLoader userRepository) {
     this.moduleHierarchy = moduleHierarchy;
     this.settings = settings;
     this.fileSystem = fileSystem;
@@ -87,7 +86,7 @@ public class JSONReport implements Reporter {
     this.rules = rules;
     this.issueCache = issueCache;
     this.rootModule = rootModule;
-    this.fileCache = fileCache;
+    this.componentStore = componentStore;
     this.userRepository = userRepository;
   }
 
@@ -166,17 +165,17 @@ public class JSONReport implements Reporter {
     json.name("components").beginArray();
     // Dump modules
     writeJsonModuleComponents(json, rootModule);
-    for (InputFile inputFile : fileCache.allFiles()) {
-      String key = ((DefaultInputFile) inputFile).key();
+    for (DefaultInputFile inputFile : componentStore.allFilesToPublish()) {
+      String key = inputFile.key();
       json
         .beginObject()
         .prop("key", key)
         .prop("path", inputFile.relativePath())
-        .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
+        .prop("moduleKey", inputFile.moduleKey())
         .prop("status", inputFile.status().name())
         .endObject();
     }
-    for (InputDir inputDir : fileCache.allDirs()) {
+    for (InputDir inputDir : componentStore.allDirs()) {
       String key = ((DefaultInputDir) inputDir).key();
       json
         .beginObject()
index 8c8f8ff5e955d0273a6b38f25e64e584abbfc2e3..2159e09ad4fef750ee2f7233e884c6279c8d38bb 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.scanner.scm;
 
-import java.io.File;
 import java.util.LinkedList;
 import java.util.List;
 import org.apache.commons.lang.StringUtils;
@@ -34,10 +33,10 @@ import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.scanner.protocol.output.ScannerReportWriter;
+import org.sonar.scanner.report.ReportPublisher;
 import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Builder;
 import org.sonar.scanner.repository.FileData;
 import org.sonar.scanner.repository.ProjectRepositories;
-import org.sonar.scanner.scan.ImmutableProjectReactor;
 import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
 import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
 
@@ -51,19 +50,17 @@ public final class ScmPublisher {
   private final ScmConfiguration configuration;
   private final ProjectRepositories projectRepositories;
   private final ModuleInputComponentStore componentStore;
-
-  private DefaultModuleFileSystem fs;
-  private ScannerReportWriter writer;
+  private final DefaultModuleFileSystem fs;
+  private final ScannerReportWriter writer;
 
   public ScmPublisher(DefaultInputModule inputModule, ScmConfiguration configuration, ProjectRepositories projectRepositories,
-    ModuleInputComponentStore componentStore, DefaultModuleFileSystem fs, ImmutableProjectReactor reactor) {
+    ModuleInputComponentStore componentStore, DefaultModuleFileSystem fs, ReportPublisher reportPublisher) {
     this.inputModule = inputModule;
     this.configuration = configuration;
     this.projectRepositories = projectRepositories;
     this.componentStore = componentStore;
     this.fs = fs;
-    File reportDir = new File(reactor.getRoot().getWorkDir(), "batch-report");
-    writer = new ScannerReportWriter(reportDir);
+    this.writer = reportPublisher.getWriter();
   }
 
   public void publish() {
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/ProjectAnalysisInfoTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/ProjectAnalysisInfoTest.java
new file mode 100644 (file)
index 0000000..8c0ff8b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Date;
+
+import org.junit.Test;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.MapSettings;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.System2;
+
+public class ProjectAnalysisInfoTest {
+  @Test
+  public void testSimpleDate() {
+    Settings settings = new MapSettings();
+    settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01");
+    settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version");
+    System2 system = mock(System2.class);
+    ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings, system);
+    info.start();
+    LocalDate date = LocalDate.of(2017, 1, 1);
+
+    assertThat(info.analysisDate()).isEqualTo(Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
+    assertThat(info.analysisVersion()).isEqualTo("version");
+  }
+}
index 33a74f0662e9b2959f0b0c9fbe94158b5c5f9c81..9a70906f1068e82759a6fe97a258324fc7c35297 100644 (file)
@@ -210,7 +210,7 @@ public class CpdExecutorTest {
   public void failOnMissingComponent() {
     executor.runCpdAnalysis(null, "unknown", Collections.emptyList(), 1);
     readDuplications(0);
-    assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Resource not found in component cache: unknown. Skipping CPD computation for it");
+    assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Resource not found in component store: unknown. Skipping CPD computation for it");
   }
 
   @Test
index 2eadd1f51708e173a608bf794cd909ca6953d1cd..b796c4f322c7fd9c36867cf2889f08cdb4cd717b 100644 (file)
@@ -93,7 +93,7 @@ public class DefaultIndexTest {
     rule = Rule.create("repoKey", "ruleKey", "Rule");
     rule.setId(1);
     rulesProfile.activateRule(rule, null);
-    index.setCurrentProject(mock(DefaultSensorStorage.class));
+    index.setCurrentStorage(mock(DefaultSensorStorage.class));
   }
 
   @Test
index e720681e671594f812f3cad47fb70fcb4aa4fb65..1ef8e3835d12b13c89671a331a2f2480e714651c 100644 (file)
@@ -22,17 +22,19 @@ package org.sonar.scanner.mediumtest;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+
 import org.sonar.batch.bootstrapper.LogOutput;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.HashMultimap;
 
 public class LogOutputRecorder implements LogOutput {
-  private Multimap<String, String> recordedByLevel = HashMultimap.create();
-  private List<String> recorded = new LinkedList<>();
-  private StringBuffer asString = new StringBuffer();
+  private final Multimap<String, String> recordedByLevel = HashMultimap.create();
+  private final List<String> recorded = new LinkedList<>();
+  private final StringBuffer asString = new StringBuffer();
 
   @Override
-  public void log(String formattedMessage, Level level) {
+  public synchronized void log(String formattedMessage, Level level) {
     recordedByLevel.put(level.toString(), formattedMessage);
     recorded.add(formattedMessage);
     asString.append(formattedMessage).append("\n");
@@ -42,6 +44,10 @@ public class LogOutputRecorder implements LogOutput {
     return recorded;
   }
 
+  public String getAllAsString() {
+    return recorded.stream().collect(Collectors.joining("\n"));
+  }
+
   public Collection<String> get(String level) {
     return recordedByLevel.get(level);
   }
index 6c83a42f0455424e099dbcc7652a0abab1ffc515..7cfe509172547586a369f3a23f4e2270da3e8cf3 100644 (file)
@@ -28,12 +28,16 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputDir;
 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.scanner.mediumtest.LogOutputRecorder;
 import org.sonar.scanner.mediumtest.ScannerMediumTester;
 import org.sonar.scanner.mediumtest.TaskResult;
 import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
 
 import java.io.File;
 import java.io.IOException;
@@ -48,13 +52,15 @@ public class FileSystemMediumTest {
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
+  private LogOutputRecorder logs = new LogOutputRecorder();
+
   public ScannerMediumTester tester = ScannerMediumTester.builder()
     .registerPlugin("xoo", new XooPlugin())
     .addDefaultQProfile("xoo", "Sonar Way")
+    .setLogOutput(logs)
     .build();
 
   private File baseDir;
-
   private ImmutableMap.Builder<String, String> builder;
 
   @Before
@@ -75,6 +81,7 @@ public class FileSystemMediumTest {
   @After
   public void stop() {
     tester.stop();
+    logs = new LogOutputRecorder();
   }
 
   @Test
@@ -103,9 +110,118 @@ public class FileSystemMediumTest {
     assertThat(result.getReportReader().readComponent(ref).getName()).isEmpty();
     assertThat(result.inputFiles()).hasSize(1);
     assertThat(result.inputDirs()).hasSize(1);
-    assertThat(result.inputFile("src/sample.xoo").type()).isEqualTo(InputFile.Type.MAIN);
-    assertThat(result.inputFile("src/sample.xoo").relativePath()).isEqualTo("src/sample.xoo");
-    assertThat(result.inputDir("src").relativePath()).isEqualTo("src");
+
+    DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
+    InputDir dir = result.inputDir("src");
+    assertThat(file.type()).isEqualTo(InputFile.Type.MAIN);
+    assertThat(file.relativePath()).isEqualTo("src/sample.xoo");
+    assertThat(dir.relativePath()).isEqualTo("src");
+
+    // file and dirs were not published
+    assertThat(file.publish()).isFalse();
+    assertThat(result.getReportComponent(dir.key())).isNull();
+    assertThat(result.getReportComponent(file.key())).isNull();
+  }
+
+  @Test
+  public void onlyGenerateMetadataIfNeeded() throws IOException {
+    builder = ImmutableMap.<String, String>builder()
+      .put("sonar.task", "scan")
+      .put("sonar.verbose", "true")
+      .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+      .put("sonar.projectKey", "com.foo.project")
+      .put("sonar.projectVersion", "1.0-SNAPSHOT")
+      .put("sonar.projectDescription", "Description of Foo Project");
+
+    File srcDir = new File(baseDir, "src");
+    srcDir.mkdir();
+
+    File xooFile = new File(srcDir, "sample.xoo");
+    FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+    File unknownFile = new File(srcDir, "sample.unknown");
+    FileUtils.write(unknownFile, "Sample xoo\ncontent");
+
+    tester.newTask()
+      .properties(builder
+        .put("sonar.sources", "src")
+        .build())
+      .start();
+
+    assertThat(logs.getAllAsString()).contains("2 files indexed");
+    assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
+    assertThat(logs.getAllAsString()).doesNotContain("'src/sample.unknown' generated metadata");
+  }
+
+  @Test
+  public void preloadFileMetadata() throws IOException {
+    builder = ImmutableMap.<String, String>builder()
+      .put("sonar.task", "scan")
+      .put("sonar.verbose", "true")
+      .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+      .put("sonar.projectKey", "com.foo.project")
+      .put("sonar.projectVersion", "1.0-SNAPSHOT")
+      .put("sonar.preloadFileMetadata", "true")
+      .put("sonar.projectDescription", "Description of Foo Project");
+
+    File srcDir = new File(baseDir, "src");
+    srcDir.mkdir();
+
+    File xooFile = new File(srcDir, "sample.xoo");
+    FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+    File unknownFile = new File(srcDir, "sample.unknown");
+    FileUtils.write(unknownFile, "Sample xoo\ncontent");
+
+    tester.newTask()
+      .properties(builder
+        .put("sonar.sources", "src")
+        .build())
+      .start();
+
+    assertThat(logs.getAllAsString()).contains("2 files indexed");
+    assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
+    assertThat(logs.getAllAsString()).contains("'src/sample.unknown' generated metadata");
+  }
+
+  @Test
+  public void publishFilesWithIssues() throws IOException {
+    ScannerMediumTester tester2 = ScannerMediumTester.builder()
+      .registerPlugin("xoo", new XooPlugin())
+      .addDefaultQProfile("xoo", "Sonar Way")
+      .addRules(new XooRulesDefinition())
+      .addActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo")
+      .build();
+    tester2.start();
+
+    builder = ImmutableMap.<String, String>builder()
+      .put("sonar.task", "scan")
+      .put("sonar.verbose", "true")
+      .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+      .put("sonar.projectKey", "com.foo.project")
+      .put("sonar.projectVersion", "1.0-SNAPSHOT")
+      .put("sonar.projectDescription", "Description of Foo Project");
+
+    File srcDir = new File(baseDir, "src");
+    srcDir.mkdir();
+
+    File xooFile = new File(srcDir, "sample.xoo");
+    FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+    TaskResult result = tester2.newTask()
+      .properties(builder
+        .put("sonar.sources", "src")
+        .build())
+      .start();
+
+    DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
+    InputDir dir = result.inputDir("src");
+
+    assertThat(file.publish()).isTrue();
+    assertThat(result.getReportComponent(dir.key())).isNotNull();
+    assertThat(result.getReportComponent(file.key())).isNotNull();
+
+    tester2.stop();
   }
 
   @Test
index 00d7c123bf7e4ec878d5a7777311cb2d38f86614..06f83958a4a65e817748a3a157fc750cd9072680 100644 (file)
@@ -28,19 +28,22 @@ import org.junit.Test;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.batch.fs.InputModule;
 import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
 
 public class ModuleIndexerTest {
   private ModuleIndexer indexer;
   private DefaultComponentTree tree;
   private DefaultInputModuleHierarchy moduleHierarchy;
   private ImmutableProjectReactor reactor;
+  private InputComponentStore componentStore;
 
   @Before
   public void setUp() {
     reactor = mock(ImmutableProjectReactor.class);
+    componentStore = new InputComponentStore();
     tree = new DefaultComponentTree();
     moduleHierarchy = new DefaultInputModuleHierarchy();
-    indexer = new ModuleIndexer(reactor, tree, new BatchIdGenerator(), moduleHierarchy);
+    indexer = new ModuleIndexer(reactor, tree, componentStore, new BatchIdGenerator(), moduleHierarchy);
   }
 
   @Test
index 131eb7d6c6e5116de750e49bfa527d0d6fbf7d43..4fbb83c58041ee9586a9bb6252a8a4274e91c02f 100644 (file)
  */
 package org.sonar.scanner.scan.filesystem;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedList;
+import java.util.List;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputFile.Status;
 import org.sonar.api.batch.fs.InputFile.Type;
 import org.sonar.api.batch.fs.InputPath;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.scanner.scan.filesystem.InputComponentStore;
-import java.nio.charset.StandardCharsets;
-
-import static org.assertj.core.api.Assertions.assertThat;
 
 public class InputComponentStoreTest {
   @Rule
@@ -39,10 +42,14 @@ public class InputComponentStoreTest {
   @Test
   public void should_add_input_file() throws Exception {
     InputComponentStore cache = new InputComponentStore();
-    DefaultInputFile fooFile = new TestInputFileBuilder("struts", "src/main/java/Foo.java").setModuleBaseDir(temp.newFolder().toPath()).build();
+    DefaultInputFile fooFile = new TestInputFileBuilder("struts", "src/main/java/Foo.java")
+      .setModuleBaseDir(temp.newFolder().toPath())
+      .setPublish(true)
+      .build();
     cache.put(fooFile);
     cache.put(new TestInputFileBuilder("struts-core", "src/main/java/Bar.java")
       .setLanguage("bla")
+      .setPublish(false)
       .setType(Type.MAIN)
       .setStatus(Status.ADDED)
       .setLines(2)
@@ -61,6 +68,10 @@ public class InputComponentStoreTest {
       assertThat(inputPath.relativePath()).startsWith("src/main/java/");
     }
 
+    List<InputFile> toPublish = new LinkedList<>();
+    cache.allFilesToPublish().forEach(toPublish::add);
+    assertThat(toPublish).containsOnly(fooFile);
+
     cache.remove(fooFile);
     assertThat(cache.allFiles()).hasSize(1);
 
index b1c514fd1a2e9cd17a139728cb66d4e8cd66529b..9856d8fabde517c2d4cb2732759f36e728f4ba65 100644 (file)
@@ -34,6 +34,8 @@ 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.config.MapSettings;
+import org.sonar.api.config.Settings;
 import org.sonar.api.scan.filesystem.PathResolver;
 
 public class InputFileBuilderTest {
@@ -54,14 +56,15 @@ public class InputFileBuilderTest {
     LanguageDetection langDetection = mock(LanguageDetection.class);
     MetadataGenerator metadataGenerator = mock(MetadataGenerator.class);
     BatchIdGenerator idGenerator = new BatchIdGenerator();
-    builder = new InputFileBuilder(module, pathResolver, langDetection, metadataGenerator, idGenerator);
+    Settings settings = new MapSettings();
+    builder = new InputFileBuilder(module, pathResolver, langDetection, metadataGenerator, idGenerator, settings);
   }
 
   @Test
   public void testBuild() {
     Path filePath = baseDir.resolve("src/File1.xoo");
     DefaultInputFile inputFile = builder.create(filePath, Type.MAIN, StandardCharsets.UTF_8);
-    
+
     assertThat(inputFile.moduleKey()).isEqualTo("module1");
     assertThat(inputFile.absolutePath()).isEqualTo(filePath.toString());
     assertThat(inputFile.key()).isEqualTo("module1:src/File1.xoo");
index a176c3098308ba3adaf05c08a9d22eb3c247c911..b0ae6550d4e85889aaca486da0a661642c3ba3d7 100644 (file)
@@ -25,7 +25,6 @@ import javax.annotation.Nullable;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.api.config.Settings;
 import org.sonar.api.config.MapSettings;
@@ -69,8 +68,8 @@ public class ConsoleReportTest {
   @Test
   public void testNoFile() {
     settings.setProperty(ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, "true");
-    when(inputPathCache.allFiles()).thenReturn(Collections.<InputFile>emptyList());
-    when(issueCache.all()).thenReturn(Collections.<TrackedIssue>emptyList());
+    when(inputPathCache.allFilesToPublish()).thenReturn(Collections.emptyList());
+    when(issueCache.all()).thenReturn(Collections.emptyList());
     report.execute();
     assertDeprecated();
     assertThat(getReportLog()).isEqualTo(
@@ -82,7 +81,7 @@ public class ConsoleReportTest {
   @Test
   public void testNoNewIssue() {
     settings.setProperty(ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, "true");
-    when(inputPathCache.allFiles()).thenReturn(Arrays.<InputFile>asList(new TestInputFileBuilder("foo", "src/Foo.php").build()));
+    when(inputPathCache.allFilesToPublish()).thenReturn(Collections.singleton(new TestInputFileBuilder("foo", "src/Foo.php").build()));
     when(issueCache.all()).thenReturn(Arrays.asList(createIssue(false, null)));
     report.execute();
     assertDeprecated();
@@ -95,7 +94,7 @@ public class ConsoleReportTest {
   @Test
   public void testOneNewIssue() {
     settings.setProperty(ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, "true");
-    when(inputPathCache.allFiles()).thenReturn(Arrays.<InputFile>asList(new TestInputFileBuilder("foo", "src/Foo.php").build()));
+    when(inputPathCache.allFilesToPublish()).thenReturn(Collections.singleton(new TestInputFileBuilder("foo", "src/Foo.php").build()));
     when(issueCache.all()).thenReturn(Arrays.asList(createIssue(true, Severity.BLOCKER)));
     report.execute();
     assertDeprecated();
@@ -109,7 +108,7 @@ public class ConsoleReportTest {
   @Test
   public void testOneNewIssuePerSeverity() {
     settings.setProperty(ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, "true");
-    when(inputPathCache.allFiles()).thenReturn(Arrays.<InputFile>asList(new TestInputFileBuilder("foo", "src/Foo.php").build()));
+    when(inputPathCache.allFilesToPublish()).thenReturn(Collections.singleton(new TestInputFileBuilder("foo", "src/Foo.php").build()));
     when(issueCache.all()).thenReturn(Arrays.asList(
       createIssue(true, Severity.BLOCKER),
       createIssue(true, Severity.CRITICAL),
index 01cce65f39530be390638a1ffd43095ea045150b..e464770bb66a834580e88b7910ccee4faa5c804c 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.scanner.scan.report;
 
-import com.google.common.collect.Lists;
 import java.io.File;
 import java.io.IOException;
 import java.io.StringWriter;
@@ -31,7 +30,6 @@ import org.apache.commons.io.IOUtils;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.InputDir;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
 import org.sonar.api.batch.fs.internal.DefaultInputDir;
@@ -86,8 +84,8 @@ public class JSONReportTest {
     DefaultInputFile inputFile = new TestInputFileBuilder("struts", "src/main/java/org/apache/struts/Action.java").build();
     inputFile.setStatus(InputFile.Status.CHANGED);
     InputComponentStore fileCache = mock(InputComponentStore.class);
-    when(fileCache.allFiles()).thenReturn(Arrays.<InputFile>asList(inputFile));
-    when(fileCache.allDirs()).thenReturn(Arrays.<InputDir>asList(inputDir));
+    when(fileCache.allFilesToPublish()).thenReturn(Collections.singleton(inputFile));
+    when(fileCache.allDirs()).thenReturn(Collections.singleton(inputDir));
 
     DefaultInputModule rootModule = new DefaultInputModule("struts");
     DefaultInputModule moduleA = new DefaultInputModule("struts-core");
@@ -123,7 +121,7 @@ public class JSONReportTest {
     issue.setAssignee("simon");
     issue.setCreationDate(SIMPLE_DATE_FORMAT.parse("2013-04-24"));
     issue.setNew(false);
-    when(issueCache.all()).thenReturn(Lists.newArrayList(issue));
+    when(issueCache.all()).thenReturn(Collections.singleton(issue));
     ScannerInput.User user = ScannerInput.User.newBuilder().setLogin("simon").setName("Simon").build();
     when(userRepository.load("simon")).thenReturn(user);
 
@@ -144,7 +142,7 @@ public class JSONReportTest {
     issue.setResolution(Issue.RESOLUTION_FIXED);
     issue.setCreationDate(SIMPLE_DATE_FORMAT.parse("2013-04-24"));
     issue.setNew(false);
-    when(issueCache.all()).thenReturn(Lists.newArrayList(issue));
+    when(issueCache.all()).thenReturn(Collections.singleton(issue));
 
     StringWriter writer = new StringWriter();
     jsonReport.writeJson(writer);
index d9987051f3d846b405a09678133508b8748ddb8d..1a86a088f4e57d09d307715b9fd984d720249bda 100644 (file)
@@ -78,6 +78,7 @@ public class FileSystemTest extends PerfTestCase {
         "sonar.projectVersion", "1.0",
         "sonar.sources", "src",
         "sonar.analysis.mode", "issues",
+        "sonar.preloadFileMetadata", "true",
         "sonar.showProfiling", "true")
       .setEnvironmentVariable("SONAR_RUNNER_OPTS", "-Xmx" + xmx + "m -server")
       .setProjectDir(baseDir);
index f1f7027bd1a07dbd5169853f168187cc2951e324..eed9250425ad78bde3686acfc90840a042bfbe9b 100644 (file)
@@ -209,6 +209,8 @@ public class UpgradeTest {
   private void scanProject() {
     MavenBuild build = MavenBuild.create(new File("projects/struts-1.3.9-diet/pom.xml"))
       .setCleanSonarGoals()
+      // exclude pom.xml, otherwise it will be published in SQ 6.3+ and not in previous versions, resulting in a different number of components
+      .setProperty("sonar.exclusions", "**/pom.xml")
       .setProperty("sonar.dynamicAnalysis", "false")
       .setProperty("sonar.scm.disabled", "true")
       .setProperty("sonar.cpd.cross_project", "true");