]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3677 enhanced file system
authorSimon Brandhof <simon.brandhof@gmail.com>
Wed, 9 Oct 2013 16:19:01 +0000 (18:19 +0200)
committerSimon Brandhof <simon.brandhof@gmail.com>
Wed, 9 Oct 2013 16:21:36 +0000 (18:21 +0200)
62 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/FileHashSensor.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/FileHashSensorTest.java
plugins/sonar-maven-batch-plugin/src/main/java/org/sonar/plugins/maven/MavenProjectConverter.java
sonar-batch/src/main/java/org/sonar/batch/ResourceFilters.java
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/UnsupportedProperties.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/AttributeFilter.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ChangedFileFilter.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapter.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ExclusionFilter.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ExclusionFilters.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterContext.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterWrapper.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashCache.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashDigest.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashes.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileQueryFilter.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileSystemLogger.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/HashBuilder.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InclusionFilter.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileCache.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageFilters.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProvider.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PathPattern.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ProjectFileSystemAdapter.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/RemoteFileHashes.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/WhiteListFileFilter.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/UnsupportedPropertiesTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/AttributeFilterTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystemTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapterTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFilterTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFiltersTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileFilterContextTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileFilterWrapperTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashCacheTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashDigestTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashesTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileSystemLoggerTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/HashBuilderTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InclusionFilterTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputFileCacheTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageFiltersTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProviderTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ProjectFileSystemAdapterTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/RemoteFileHashesTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/WhiteListFileFilterTest.java [deleted file]
sonar-core/src/main/java/org/sonar/core/source/SnapshotDataType.java
sonar-core/src/test/java/org/sonar/core/persistence/DryRunDatabaseFactoryTest.java
sonar-plugin-api/src/main/java/org/sonar/api/resources/InputFile.java
sonar-plugin-api/src/main/java/org/sonar/api/resources/InputFileUtils.java
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileQuery.java
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileSystemFilter.java
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileType.java
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFileFilter.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/ModuleFileSystem.java
sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/SimpleModuleFileSystem.java

index df5cd76ade53a19a4ea7910f53ebeafd41aef520..74af986d8141f2d1d44b021fc9806e6ea9e8294c 100644 (file)
  */
 package org.sonar.plugins.core.sensors;
 
+import com.google.common.collect.Maps;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.batch.Sensor;
 import org.sonar.api.batch.SensorContext;
 import org.sonar.api.resources.Project;
-import org.sonar.api.scan.filesystem.FileQuery;
-import org.sonar.api.scan.filesystem.FileType;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
-import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.utils.KeyValueFormat;
 import org.sonar.batch.index.ComponentDataCache;
-import org.sonar.batch.scan.filesystem.FileHashCache;
+import org.sonar.batch.scan.filesystem.InputFileCache;
 import org.sonar.core.source.SnapshotDataType;
 
-import java.io.File;
-import java.util.List;
+import java.util.Map;
 
 /**
  * This sensor will retrieve hash of each file of the current module and store it in DB
  * in order to compare it during next analysis and see if the file was modified.
  * This is used by the incremental preview mode.
- * @see org.sonar.plugins.core.batch.IncrementalPreviewFilter
  * @since 4.0
  */
 public final class FileHashSensor implements Sensor {
 
-  private ModuleFileSystem moduleFileSystem;
-  private PathResolver pathResolver;
-  private ComponentDataCache componentDataCache;
-  private FileHashCache fileHashCache;
+  private final InputFileCache fileCache;
+  private final ComponentDataCache componentDataCache;
 
-  public FileHashSensor(FileHashCache fileHashCache, ModuleFileSystem moduleFileSystem, PathResolver pathResolver, ComponentDataCache componentDataCache) {
-    this.fileHashCache = fileHashCache;
-    this.moduleFileSystem = moduleFileSystem;
-    this.pathResolver = pathResolver;
+  public FileHashSensor(InputFileCache fileCache, ComponentDataCache componentDataCache) {
+    this.fileCache = fileCache;
     this.componentDataCache = componentDataCache;
   }
 
@@ -61,20 +54,17 @@ public final class FileHashSensor implements Sensor {
 
   @Override
   public void analyse(Project project, SensorContext context) {
-    StringBuilder fileHashMap = new StringBuilder();
-    analyse(fileHashMap, project, FileType.SOURCE);
-    analyse(fileHashMap, project, FileType.TEST);
-    String fileHashes = fileHashMap.toString();
-    if (StringUtils.isNotBlank(fileHashes)) {
-      componentDataCache.setStringData(project.getKey(), SnapshotDataType.FILE_HASH.getValue(), fileHashes);
+    Map<String, String> map = Maps.newHashMap();
+    for (InputFile inputFile : fileCache.byModule(project.key())) {
+      String baseRelativePath = inputFile.attribute(InputFile.ATTRIBUTE_BASE_RELATIVE_PATH);
+      String hash = inputFile.attribute(InputFile.ATTRIBUTE_HASH);
+      if (StringUtils.isNotEmpty(baseRelativePath) && StringUtils.isNotEmpty(hash)) {
+        map.put(baseRelativePath, hash);
+      }
     }
-  }
-
-  private void analyse(StringBuilder fileHashMap, Project project, FileType fileType) {
-    List<File> files = moduleFileSystem.files(FileQuery.on(fileType).onLanguage(project.getLanguageKey()));
-    for (File file : files) {
-      String hash = fileHashCache.getCurrentHash(file, moduleFileSystem.sourceCharset());
-      fileHashMap.append(pathResolver.relativePath(moduleFileSystem.baseDir(), file)).append("=").append(hash).append("\n");
+    if (!map.isEmpty()) {
+      String data = KeyValueFormat.format(map);
+      componentDataCache.setStringData(project.getKey(), SnapshotDataType.FILE_HASH.getValue(), data);
     }
   }
 
index b46519c27d3f5004a910a2ebcca5a9268918166c..7e11a61698c35398fc56e3f5f80992983a2bd7b3 100644 (file)
  */
 package org.sonar.plugins.core.sensors;
 
-import com.google.common.base.Charsets;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.apache.commons.io.FileUtils;
-import org.junit.Before;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import edu.emory.mathcs.backport.java.util.Collections;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.SensorContext;
-import org.sonar.api.resources.Java;
 import org.sonar.api.resources.Project;
-import org.sonar.api.scan.filesystem.FileQuery;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
-import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.api.scan.filesystem.InputFile;
 import org.sonar.batch.index.ComponentDataCache;
-import org.sonar.batch.scan.filesystem.FileHashCache;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
+import org.sonar.batch.scan.filesystem.InputFileCache;
 
 import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 public class FileHashSensorTest {
 
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
-  private FileHashSensor sensor;
-
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
-  private ModuleFileSystem fileSystem;
+  Project project = new Project("struts");
+  InputFileCache fileCache = mock(InputFileCache.class);
+  ComponentDataCache componentDataCache = mock(ComponentDataCache.class);
+  FileHashSensor sensor = new FileHashSensor(fileCache, componentDataCache);
 
-  private ComponentDataCache componentDataCache;
-
-  private Project project;
+  @Test
+  public void store_file_hashes() throws Exception {
+    when(fileCache.byModule("struts")).thenReturn(Lists.<InputFile>newArrayList(
+      InputFile.create(temp.newFile(), "src/Foo.java", ImmutableMap.of(InputFile.ATTRIBUTE_HASH, "ABC")),
+      InputFile.create(temp.newFile(), "src/Bar.java", ImmutableMap.of(InputFile.ATTRIBUTE_HASH, "DEF"))
+    ));
 
-  private FileHashCache fileHashCache;
+    SensorContext sensorContext = mock(SensorContext.class);
+    sensor.analyse(project, sensorContext);
 
-  @Before
-  public void prepare() {
-    fileSystem = mock(ModuleFileSystem.class);
-    when(fileSystem.sourceCharset()).thenReturn(Charsets.UTF_8);
-    componentDataCache = mock(ComponentDataCache.class);
-    fileHashCache = mock(FileHashCache.class);
-    sensor = new FileHashSensor(fileHashCache, fileSystem, new PathResolver(), componentDataCache);
-    PropertiesConfiguration conf = new PropertiesConfiguration();
-    conf.setProperty("sonar.language", "java");
-    project = new Project("java_project").setConfiguration(conf).setLanguage(Java.INSTANCE);
+    verify(componentDataCache).setStringData("struts", "file_hash", "src/Foo.java=ABC;src/Bar.java=DEF");
+    verifyZeroInteractions(sensorContext);
   }
 
   @Test
-  public void improve_code_coverage() throws Exception {
+  public void various_tests() throws Exception {
     assertThat(sensor.shouldExecuteOnProject(project)).isTrue();
     assertThat(sensor.toString()).isEqualTo("FileHashSensor");
   }
 
   @Test
-  public void computeHashes() throws Exception {
-    File baseDir = temp.newFolder();
-    File file1 = new File(baseDir, "src/com/foo/Bar.java");
-    FileUtils.write(file1, "Bar", Charsets.UTF_8);
-    when(fileHashCache.getCurrentHash(file1, Charsets.UTF_8)).thenReturn("barhash");
-    File file2 = new File(baseDir, "src/com/foo/Foo.java");
-    FileUtils.write(file2, "Foo", Charsets.UTF_8);
-    when(fileHashCache.getCurrentHash(file2, Charsets.UTF_8)).thenReturn("foohash");
-    when(fileSystem.baseDir()).thenReturn(baseDir);
-    when(fileSystem.files(any(FileQuery.class))).thenReturn(Arrays.asList(file1, file2)).thenReturn(Collections.<File> emptyList());
-    sensor.analyse(project, mock(SensorContext.class));
+  public void dont_save_hashes_if_no_files() throws Exception {
+    when(fileCache.byModule("struts")).thenReturn(Collections.<InputFile>emptyList());
 
-    verify(componentDataCache).setStringData("java_project", "hash",
-      "src/com/foo/Bar.java=barhash\n"
-        + "src/com/foo/Foo.java=foohash\n");
-  }
-
-  @Test
-  public void dont_save_hashes_if_no_file() throws Exception {
-    File baseDir = temp.newFolder();
-    when(fileSystem.baseDir()).thenReturn(baseDir);
-    when(fileSystem.files(any(FileQuery.class))).thenReturn(Collections.<File> emptyList());
-    sensor.analyse(project, mock(SensorContext.class));
+    SensorContext sensorContext = mock(SensorContext.class);
+    sensor.analyse(project, sensorContext);
 
-    verify(componentDataCache, never()).setStringData(anyString(), anyString(), anyString());
+    verifyZeroInteractions(componentDataCache);
+    verifyZeroInteractions(sensorContext);
   }
 }
index 3b877f3d479d725a75efcdd907eb9dc3ed937b6f..6b8834393719fc371558b42c7c2976e155d3ca30 100644 (file)
@@ -226,11 +226,11 @@ public class MavenProjectConverter implements TaskExtension {
 
   public static void synchronizeFileSystem(MavenProject pom, DefaultModuleFileSystem into) {
     into.resetDirs(
-        pom.getBasedir(),
-        getBuildDir(pom),
-        resolvePaths(pom.getCompileSourceRoots(), pom.getBasedir()),
-        resolvePaths(pom.getTestCompileSourceRoots(), pom.getBasedir()),
-        Arrays.asList(resolvePath(pom.getBuild().getOutputDirectory(), pom.getBasedir())));
+      pom.getBasedir(),
+      getBuildDir(pom),
+      resolvePaths(pom.getCompileSourceRoots(), pom.getBasedir()),
+      resolvePaths(pom.getTestCompileSourceRoots(), pom.getBasedir()),
+      Arrays.asList(resolvePath(pom.getBuild().getOutputDirectory(), pom.getBasedir())));
   }
 
   static File resolvePath(@Nullable String path, File basedir) {
index 77f3f7dd31b560a4015f276a0ff57f271259fe7a..c32b0dbd68b5898596e16de0091713882f5a3a86 100644 (file)
@@ -35,7 +35,7 @@ public class ResourceFilters {
   private ResourceFilter[] filters;
 
   public ResourceFilters(ResourceFilter[] filters) {
-    this.filters = (filters == null ? new ResourceFilter[0] : filters);
+    this.filters = filters == null ? new ResourceFilter[0] : filters;
   }
 
   public ResourceFilters() {
index 37ef6fcedb404fa184bcdea678fb5b1a8ae38a38..d6ce991ec1053fe532d71ee59d4f47d34b438321 100644 (file)
@@ -28,7 +28,6 @@ import org.sonar.api.platform.ComponentContainer;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.Project;
 import org.sonar.api.scan.filesystem.FileExclusions;
-import org.sonar.api.scan.filesystem.PathResolver;
 import org.sonar.batch.DefaultProjectClasspath;
 import org.sonar.batch.DefaultSensorContext;
 import org.sonar.batch.DefaultTimeMachine;
@@ -49,12 +48,7 @@ import org.sonar.batch.issue.IssueFilters;
 import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.batch.phases.PhaseExecutor;
 import org.sonar.batch.phases.PhasesTimeProfiler;
-import org.sonar.batch.scan.filesystem.DeprecatedFileSystemAdapter;
-import org.sonar.batch.scan.filesystem.ExclusionFilters;
-import org.sonar.batch.scan.filesystem.FileHashCache;
-import org.sonar.batch.scan.filesystem.FileSystemLogger;
-import org.sonar.batch.scan.filesystem.LanguageFilters;
-import org.sonar.batch.scan.filesystem.ModuleFileSystemProvider;
+import org.sonar.batch.scan.filesystem.*;
 import org.sonar.core.component.ScanPerspectives;
 import org.sonar.core.measure.MeasurementFilters;
 
@@ -97,15 +91,16 @@ public class ModuleScanContainer extends ComponentContainer {
       Languages.class,
 
       // file system
-      PathResolver.class,
       FileExclusions.class,
-      LanguageFilters.class,
       ExclusionFilters.class,
+      FileHashes.class,
+      RemoteFileHashes.class,
+      FileIndexer.class,
+      LanguageRecognizer.class,
+      FileSystemLogger.class,
       DefaultProjectClasspath.class,
       new ModuleFileSystemProvider(),
-      DeprecatedFileSystemAdapter.class,
-      FileSystemLogger.class,
-      FileHashCache.class,
+      ProjectFileSystemAdapter.class,
 
       // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor)
       getComponentByType(ResourcePersister.class).getSnapshot(module),
index a425e6386da13e96a65960c2e862e087fb20d67b..4b8a82fbe4b6c66f501d32b177b2dee2eb457773 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.api.batch.bootstrap.ProjectReactor;
 import org.sonar.api.config.Settings;
 import org.sonar.api.platform.ComponentContainer;
 import org.sonar.api.resources.Project;
+import org.sonar.api.scan.filesystem.PathResolver;
 import org.sonar.api.utils.SonarException;
 import org.sonar.batch.DefaultFileLinesContextFactory;
 import org.sonar.batch.DefaultResourceCreationLock;
@@ -38,7 +39,7 @@ import org.sonar.batch.index.*;
 import org.sonar.batch.issue.*;
 import org.sonar.batch.phases.GraphPersister;
 import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
-import org.sonar.batch.scan.filesystem.HashBuilder;
+import org.sonar.batch.scan.filesystem.InputFileCache;
 import org.sonar.batch.scan.maven.FakeMavenPluginExecutor;
 import org.sonar.batch.scan.maven.MavenPluginExecutor;
 import org.sonar.batch.source.HighlightableBuilder;
@@ -117,7 +118,10 @@ public class ProjectScanContainer extends ComponentContainer {
       ResourceCache.class,
       ComponentDataCache.class,
       ComponentDataPersister.class,
-      HashBuilder.class,
+
+      // file system
+      InputFileCache.class,
+      PathResolver.class,
 
       // issues
       IssueUpdater.class,
index 5f83ff8654f55491804cde22b627dfb11e49d515..cce1d037c06ff23f84d5d97b0919e238eb4a0f8d 100644 (file)
@@ -20,7 +20,9 @@
 package org.sonar.batch.scan;
 
 import org.sonar.api.BatchComponent;
+import org.sonar.api.CoreProperties;
 import org.sonar.api.config.Settings;
+import org.sonar.api.utils.MessageException;
 
 public class UnsupportedProperties implements BatchComponent {
   private final Settings settings;
@@ -31,11 +33,18 @@ public class UnsupportedProperties implements BatchComponent {
 
   public void start() {
     verify("sonar.light", "The property 'sonar.light' is no longer supported. Please use 'sonar.dynamicAnalysis'");
+    verifyIncrementalPreviewMode();
   }
 
   private void verify(String key, String message) {
     if (settings.hasKey(key)) {
-      throw new IllegalArgumentException(message);
+      throw MessageException.of(message);
+    }
+  }
+
+  private void verifyIncrementalPreviewMode() {
+    if (settings.getBoolean(CoreProperties.INCREMENTAL_PREVIEW) && !settings.getBoolean(CoreProperties.DRY_RUN)) {
+      throw MessageException.of("Incremental mode is only supported with preview mode");
     }
   }
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/AttributeFilter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/AttributeFilter.java
new file mode 100644 (file)
index 0000000..f256548
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.scan.filesystem.InputFileFilter;
+
+import java.util.Collection;
+
+class AttributeFilter implements InputFileFilter {
+  private final String key;
+  private final Collection<String> values;
+
+  AttributeFilter(String key, Collection<String> values) {
+    this.key = key;
+    this.values = values;
+  }
+
+  @Override
+  public boolean accept(InputFile inputFile) {
+    String value = inputFile.attribute(key);
+    return values.contains(value);
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ChangedFileFilter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ChangedFileFilter.java
deleted file mode 100644 (file)
index 509fb2e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.sonar.api.scan.filesystem.FileSystemFilter;
-
-import java.io.File;
-
-/**
- * When enabled this filter will only allow modified files to be analyzed.
- * @since 4.0
- */
-class ChangedFileFilter implements FileSystemFilter {
-
-  private FileHashCache fileHashCache;
-
-  public ChangedFileFilter(FileHashCache fileHashCache) {
-    this.fileHashCache = fileHashCache;
-  }
-
-  @Override
-  public boolean accept(File file, Context context) {
-    String previousHash = fileHashCache.getPreviousHash(file);
-    if (previousHash == null) {
-      return true;
-    }
-    String currentHash = fileHashCache.getCurrentHash(file, context.fileSystem().sourceCharset());
-    return !currentHash.equals(previousHash);
-  }
-
-}
index 1d0c76a7bee9689f33e860af34f27dfe565ac797..327a5663106f176f0b45877b6ff75a6e7edddecd 100644 (file)
@@ -22,24 +22,17 @@ package org.sonar.batch.scan.filesystem;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.filefilter.FileFilterUtils;
-import org.apache.commons.io.filefilter.HiddenFileFilter;
-import org.apache.commons.io.filefilter.IOFileFilter;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.config.Settings;
 import org.sonar.api.scan.filesystem.FileQuery;
-import org.sonar.api.scan.filesystem.FileSystemFilter;
-import org.sonar.api.scan.filesystem.FileType;
+import org.sonar.api.scan.filesystem.InputFile;
 import org.sonar.api.scan.filesystem.ModuleFileSystem;
-import org.sonar.api.scan.filesystem.PathResolver;
 import org.sonar.api.utils.SonarException;
 
+import javax.annotation.CheckForNull;
 import java.io.File;
-import java.io.FileFilter;
 import java.nio.charset.Charset;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -49,42 +42,57 @@ import java.util.List;
  */
 public class DefaultModuleFileSystem implements ModuleFileSystem {
 
-  private static final IOFileFilter DIR_FILTER = FileFilterUtils.and(HiddenFileFilter.VISIBLE, FileFilterUtils.notFileFilter(FileFilterUtils.prefixFileFilter(".")));
+  private final String moduleKey;
+  private final InputFileCache cache;
+  private final FileIndexer indexer;
+  private final Settings settings;
 
-  private Settings settings;
   private File baseDir, workingDir, buildDir;
   private List<File> sourceDirs = Lists.newArrayList();
   private List<File> testDirs = Lists.newArrayList();
   private List<File> binaryDirs = Lists.newArrayList();
-  private PathResolver pathResolver = new PathResolver();
-  private List<FileSystemFilter> fsFilters = Lists.newArrayList();
-  private LanguageFilters languageFilters;
-  private FileHashCache fileHashCache;
+  private List<File> additionalSourceFiles = Lists.newArrayList();
+  private List<File> additionalTestFiles = Lists.newArrayList();
 
-  DefaultModuleFileSystem(FileHashCache fileHashCache) {
-    this.fileHashCache = fileHashCache;
+  public DefaultModuleFileSystem(String moduleKey, Settings settings, InputFileCache cache, FileIndexer indexer) {
+    this.moduleKey = moduleKey;
+    this.settings = settings;
+    this.cache = cache;
+    this.indexer = indexer;
   }
 
+  @Override
+  public String moduleKey() {
+    return moduleKey;
+  }
+
+  @Override
   public File baseDir() {
     return baseDir;
   }
 
+  @Override
+  @CheckForNull
   public File buildDir() {
     return buildDir;
   }
 
+  @Override
   public List<File> sourceDirs() {
     return sourceDirs;
   }
 
+  @Override
   public List<File> testDirs() {
     return testDirs;
   }
 
+  @Override
   public List<File> binaryDirs() {
     return binaryDirs;
   }
 
+  @Override
   public Charset sourceCharset() {
     final Charset charset;
     String encoding = settings.getString(CoreProperties.ENCODING_PROPERTY);
@@ -100,97 +108,69 @@ public class DefaultModuleFileSystem implements ModuleFileSystem {
     return !settings.hasKey(CoreProperties.ENCODING_PROPERTY);
   }
 
+  @Override
   public File workingDir() {
     return workingDir;
   }
 
-  List<FileSystemFilter> filters() {
-    return fsFilters;
+  List<File> additionalSourceFiles() {
+    return additionalSourceFiles;
   }
 
-  LanguageFilters languageFilters() {
-    return languageFilters;
+  List<File> additionalTestFiles() {
+    return additionalTestFiles;
   }
 
-  public List<File> files(FileQuery query) {
-    boolean changedFilesOnly = false;
-    if (settings.getBoolean(CoreProperties.INCREMENTAL_PREVIEW)) {
-      if (!settings.getBoolean(CoreProperties.DRY_RUN)) {
-        throw new SonarException("Incremental preview is only supported with preview mode");
-      }
-      changedFilesOnly = true;
-    }
-    return files(query, changedFilesOnly);
+  void setBaseDir(File baseDir) {
+    this.baseDir = baseDir;
   }
 
-  @Override
-  public List<File> changedFiles(FileQuery query) {
-    return files(query, true);
+  void setWorkingDir(File workingDir) {
+    this.workingDir = workingDir;
   }
 
-  private List<File> files(FileQuery query, boolean changedFilesOnly) {
-    List<FileSystemFilter> filters = Lists.newArrayList(fsFilters);
-    if (changedFilesOnly) {
-      filters.add(new ChangedFileFilter(fileHashCache));
-    }
-    for (FileFilter fileFilter : query.filters()) {
-      filters.add(new FileFilterWrapper(fileFilter));
-    }
-    for (String language : query.languages()) {
-      filters.add(new FileFilterWrapper(languageFilters.forLang(language)));
-    }
-    for (String inclusion : query.inclusions()) {
-      filters.add(new InclusionFilter(inclusion));
-    }
-    for (String exclusion : query.exclusions()) {
-      filters.add(new ExclusionFilter(exclusion));
-    }
-    List<File> result = Lists.newLinkedList();
-    FileFilterContext context = new FileFilterContext(this);
-    for (FileType type : query.types()) {
-      context.setType(type);
-      switch (type) {
-        case SOURCE:
-          applyFilters(result, context, filters, sourceDirs);
-          break;
-        case TEST:
-          applyFilters(result, context, filters, testDirs);
-          break;
-        default:
-          throw new IllegalArgumentException("Unknown file type: " + type);
-      }
-    }
-    return result;
+  void setBuildDir(File buildDir) {
+    this.buildDir = buildDir;
   }
 
-  private void applyFilters(List<File> result, FileFilterContext context,
-    Collection<FileSystemFilter> filters, Collection<File> dirs) {
-    for (File dir : dirs) {
-      if (dir.exists()) {
-        context.setRelativeDir(dir);
-        Collection<File> files = FileUtils.listFiles(dir, HiddenFileFilter.VISIBLE, DIR_FILTER);
-        for (File file : files) {
-          if (accept(file, context, filters)) {
-            result.add(file);
-          }
-        }
-      }
-    }
+  void addSourceDir(File d) {
+    this.sourceDirs.add(d);
   }
 
-  private boolean accept(File file, FileFilterContext context, Collection<FileSystemFilter> filters) {
-    context.setRelativePath(pathResolver.relativePath(context.relativeDir(), file));
-    try {
-      context.setCanonicalPath(file.getCanonicalPath());
-    } catch (Exception e) {
-      throw new IllegalStateException("Fail to get the canonical path of: " + file);
-    }
-    for (FileSystemFilter filter : filters) {
-      if (!filter.accept(file, context)) {
-        return false;
+  void addTestDir(File d) {
+    this.testDirs.add(d);
+  }
+
+  void addBinaryDir(File d) {
+    this.binaryDirs.add(d);
+  }
+
+  void setAdditionalSourceFiles(List<File> files) {
+    this.additionalSourceFiles = files;
+  }
+
+  void setAdditionalTestFiles(List<File> files) {
+    this.additionalTestFiles = files;
+  }
+
+  /**
+   * @since 4.0
+   */
+  public Iterable<InputFile> inputFiles(FileQuery query) {
+    List<InputFile> result = Lists.newArrayList();
+
+    FileQueryFilter filter = new FileQueryFilter(settings, query);
+    for (InputFile input : cache.byModule(moduleKey)) {
+      if (filter.accept(input)) {
+        result.add(input);
       }
     }
-    return true;
+    return result;
+  }
+
+  @Override
+  public List<File> files(FileQuery query) {
+    return InputFile.toFiles(inputFiles(query));
   }
 
   public void resetDirs(File basedir, File buildDir, List<File> sourceDirs, List<File> testDirs, List<File> binaryDirs) {
@@ -200,6 +180,11 @@ public class DefaultModuleFileSystem implements ModuleFileSystem {
     this.sourceDirs = existingDirs(sourceDirs);
     this.testDirs = existingDirs(testDirs);
     this.binaryDirs = existingDirs(binaryDirs);
+    indexer.index(this);
+  }
+
+  void index() {
+    indexer.index(this);
   }
 
   private List<File> existingDirs(List<File> dirs) {
@@ -212,50 +197,21 @@ public class DefaultModuleFileSystem implements ModuleFileSystem {
     return builder.build();
   }
 
-  DefaultModuleFileSystem setSettings(Settings settings) {
-    this.settings = settings;
-    return this;
-  }
-
-  DefaultModuleFileSystem setBaseDir(File baseDir) {
-    this.baseDir = baseDir;
-    return this;
-  }
-
-  DefaultModuleFileSystem setWorkingDir(File workingDir) {
-    this.workingDir = workingDir;
-    return this;
-  }
 
-  DefaultModuleFileSystem setBuildDir(File buildDir) {
-    this.buildDir = buildDir;
-    return this;
-  }
-
-  DefaultModuleFileSystem addFilters(FileSystemFilter... f) {
-    for (FileSystemFilter filter : f) {
-      this.fsFilters.add(filter);
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
     }
-    return this;
-  }
-
-  DefaultModuleFileSystem setLanguageFilters(LanguageFilters languageFilters) {
-    this.languageFilters = languageFilters;
-    return this;
-  }
-
-  DefaultModuleFileSystem addSourceDir(File d) {
-    this.sourceDirs.add(d);
-    return this;
-  }
-
-  DefaultModuleFileSystem addTestDir(File d) {
-    this.testDirs.add(d);
-    return this;
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    DefaultModuleFileSystem that = (DefaultModuleFileSystem) o;
+    return moduleKey.equals(that.moduleKey);
   }
 
-  DefaultModuleFileSystem addBinaryDir(File d) {
-    this.binaryDirs.add(d);
-    return this;
+  @Override
+  public int hashCode() {
+    return moduleKey.hashCode();
   }
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapter.java
deleted file mode 100644 (file)
index 4379089..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang.CharEncoding;
-import org.apache.maven.project.MavenProject;
-import org.sonar.api.resources.InputFile;
-import org.sonar.api.resources.InputFileUtils;
-import org.sonar.api.resources.Java;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.ProjectFileSystem;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.scan.filesystem.FileQuery;
-import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.api.utils.SonarException;
-
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.List;
-
-/**
- * Adapter for keeping the backward-compatibility of the deprecated component {@link org.sonar.api.resources.ProjectFileSystem}
- *
- * @since 3.5
- */
-public class DeprecatedFileSystemAdapter implements ProjectFileSystem {
-
-  private final DefaultModuleFileSystem target;
-  private final PathResolver pathResolver = new PathResolver();
-  private final MavenProject pom;
-
-
-  public DeprecatedFileSystemAdapter(DefaultModuleFileSystem target, Project project, @Nullable MavenProject pom) {
-    this.target = target;
-    this.pom = pom;
-
-    // TODO See http://jira.codehaus.org/browse/SONAR-2126
-    // previously MavenProjectBuilder was responsible for creation of ProjectFileSystem
-    project.setFileSystem(this);
-  }
-
-  public DeprecatedFileSystemAdapter(DefaultModuleFileSystem target, Project project) {
-    this(target, project, null);
-  }
-
-  public void start() {
-    // used to avoid NPE in Project#getFileSystem()
-  }
-
-  public Charset getSourceCharset() {
-    return target.sourceCharset();
-  }
-
-  public File getBasedir() {
-    return target.baseDir();
-  }
-
-  public File getBuildDir() {
-    File dir = target.buildDir();
-    if (dir == null) {
-      // emulate build dir to keep backward-compatibility
-      dir = new File(getSonarWorkingDirectory(), "build");
-    }
-    return dir;
-  }
-
-  public File getBuildOutputDir() {
-    File dir = Iterables.getFirst(target.binaryDirs(), null);
-    if (dir == null) {
-      // emulate binary dir
-      dir = new File(getBuildDir(), "classes");
-    }
-
-    return dir;
-  }
-
-  public List<File> getSourceDirs() {
-    return target.sourceDirs();
-  }
-
-  public ProjectFileSystem addSourceDir(File dir) {
-    target.addSourceDir(dir);
-    return this;
-  }
-
-  public List<File> getTestDirs() {
-    return target.testDirs();
-  }
-
-  public ProjectFileSystem addTestDir(File dir) {
-    target.addTestDir(dir);
-    return this;
-  }
-
-  public File getReportOutputDir() {
-    if (pom != null) {
-      return resolvePath(pom.getReporting().getOutputDirectory());
-    }
-    // emulate Maven report output dir
-    return new File(getBuildDir(), "site");
-  }
-
-  public File getSonarWorkingDirectory() {
-    return target.workingDir();
-  }
-
-  public File resolvePath(String path) {
-    File file = new File(path);
-    if (!file.isAbsolute()) {
-      try {
-        file = new File(getBasedir(), path).getCanonicalFile();
-      } catch (IOException e) {
-        throw new SonarException("Unable to resolve path '" + path + "'", e);
-      }
-    }
-    return file;
-  }
-
-  public List<File> getSourceFiles(Language... langs) {
-    List<File> result = Lists.newArrayList();
-    for (Language lang : langs) {
-      result.addAll(target.files(FileQuery.onSource().onLanguage(lang.getKey())));
-    }
-    return result;
-  }
-
-  public List<File> getJavaSourceFiles() {
-    return getSourceFiles(Java.INSTANCE);
-  }
-
-  public boolean hasJavaSourceFiles() {
-    return !getJavaSourceFiles().isEmpty();
-  }
-
-  public List<File> getTestFiles(Language... langs) {
-    List<File> result = Lists.newArrayList();
-    for (Language lang : langs) {
-      result.addAll(target.files(FileQuery.onTest().onLanguage(lang.getKey())));
-    }
-    return result;
-  }
-
-  public boolean hasTestFiles(Language lang) {
-    return !getTestFiles(lang).isEmpty();
-  }
-
-  public File writeToWorkingDirectory(String content, String fileName) throws IOException {
-    File file = new File(target.workingDir(), fileName);
-    FileUtils.writeStringToFile(file, content, CharEncoding.UTF_8);
-    return file;
-  }
-
-  public File getFileFromBuildDirectory(String filename) {
-    File file = new File(getBuildDir(), filename);
-    return file.exists() ? file : null;
-  }
-
-  public Resource toResource(File file) {
-    if (file == null || !file.exists()) {
-      return null;
-    }
-    PathResolver.RelativePath relativePath = pathResolver.relativePath(getSourceDirs(), file);
-    if (relativePath == null) {
-      return null;
-    }
-    return file.isFile() ? new org.sonar.api.resources.File(relativePath.path()) : new org.sonar.api.resources.Directory(relativePath.path());
-  }
-
-  public List<InputFile> mainFiles(String... langs) {
-    List<InputFile> result = Lists.newArrayList();
-    List<File> files = target.files(FileQuery.onSource().onLanguage(langs));
-    for (File file : files) {
-      PathResolver.RelativePath relativePath = pathResolver.relativePath(getSourceDirs(), file);
-      if (relativePath != null) {
-        result.add(InputFileUtils.create(relativePath.dir(), relativePath.path()));
-      }
-    }
-    return result;
-  }
-
-  public List<InputFile> testFiles(String... langs) {
-    List<InputFile> result = Lists.newArrayList();
-    List<File> files = target.files(FileQuery.onTest().onLanguage(langs));
-    for (File file : files) {
-      PathResolver.RelativePath relativePath = pathResolver.relativePath(getTestDirs(), file);
-      if (relativePath != null) {
-        result.add(InputFileUtils.create(relativePath.dir(), relativePath.path()));
-      }
-    }
-
-    return result;
-  }
-}
index 172b58b28fa04c6a5a0abfad2678c110b825ab6a..5cbe77975fb1b7ca97d68f57274d64206cc72a65 100644 (file)
  */
 package org.sonar.batch.scan.filesystem;
 
-import org.sonar.api.scan.filesystem.FileSystemFilter;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.scan.filesystem.InputFileFilter;
 
-import java.io.File;
-
-class ExclusionFilter implements FileSystemFilter {
+class ExclusionFilter implements InputFileFilter {
   private final PathPattern pattern;
 
   ExclusionFilter(String s) {
     this.pattern = PathPattern.create(s);
   }
 
-  public boolean accept(File file, FileSystemFilter.Context context) {
-    return !pattern.match(context);
+  @Override
+  public boolean accept(InputFile inputFile) {
+    return !pattern.match(inputFile);
   }
 
   @Override
index e8e3eab994338e28ba2558191a3bb491716e48ab..2e1130d55be7fc3ed95507cccb04ef9fd1304ab0 100644 (file)
@@ -26,12 +26,10 @@ import org.sonar.api.batch.ResourceFilter;
 import org.sonar.api.resources.Resource;
 import org.sonar.api.resources.ResourceUtils;
 import org.sonar.api.scan.filesystem.FileExclusions;
-import org.sonar.api.scan.filesystem.FileSystemFilter;
-import org.sonar.api.scan.filesystem.FileType;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.scan.filesystem.InputFileFilter;
 
-import java.io.File;
-
-public class ExclusionFilters implements FileSystemFilter, ResourceFilter, BatchComponent {
+public class ExclusionFilters implements InputFileFilter, ResourceFilter, BatchComponent {
   private final FileExclusions exclusionSettings;
 
   public ExclusionFilters(FileExclusions exclusions) {
@@ -45,7 +43,6 @@ public class ExclusionFilters implements FileSystemFilter, ResourceFilter, Batch
     log("Excluded tests: ", testExclusions());
   }
 
-
   private void log(String title, PathPattern[] patterns) {
     if (patterns.length > 0) {
       Logger log = LoggerFactory.getLogger(ExclusionFilters.class);
@@ -56,26 +53,38 @@ public class ExclusionFilters implements FileSystemFilter, ResourceFilter, Batch
     }
   }
 
-  public boolean accept(File file, Context context) {
-    PathPattern[] inclusionPatterns = context.type() == FileType.TEST ? testInclusions() : sourceInclusions();
-    if (inclusionPatterns.length > 0) {
+  @Override
+  public boolean accept(InputFile inputFile) {
+    String type = inputFile.attribute(InputFile.ATTRIBUTE_TYPE);
+    PathPattern[] inclusionPatterns = null;
+    PathPattern[] exclusionPatterns = null;
+    if (InputFile.TYPE_SOURCE.equals(type)) {
+      inclusionPatterns = sourceInclusions();
+      exclusionPatterns = sourceExclusions();
+    } else if (InputFile.TYPE_TEST.equals(type)) {
+      inclusionPatterns = testInclusions();
+      exclusionPatterns = testExclusions();
+    }
+    if (inclusionPatterns != null && inclusionPatterns.length > 0) {
       boolean matchInclusion = false;
       for (PathPattern pattern : inclusionPatterns) {
-        matchInclusion |= pattern.match(context);
+        matchInclusion |= pattern.match(inputFile);
       }
       if (!matchInclusion) {
         return false;
       }
     }
-    PathPattern[] exclusionPatterns = context.type() == FileType.TEST ? testExclusions() : sourceExclusions();
-    for (PathPattern pattern : exclusionPatterns) {
-      if (pattern.match(context)) {
-        return false;
+    if (exclusionPatterns != null && exclusionPatterns.length > 0) {
+      for (PathPattern pattern : exclusionPatterns) {
+        if (pattern.match(inputFile)) {
+          return false;
+        }
       }
     }
     return true;
   }
 
+
   public boolean isIgnored(Resource resource) {
     if (ResourceUtils.isFile(resource)) {
       PathPattern[] inclusionPatterns = ResourceUtils.isUnitTestClass(resource) ? testInclusions() : sourceInclusions();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterContext.java
deleted file mode 100644 (file)
index 7382917..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.apache.commons.io.FilenameUtils;
-import org.sonar.api.batch.FileFilter;
-import org.sonar.api.scan.filesystem.FileType;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
-
-import java.io.File;
-
-class FileFilterContext implements FileFilter.Context {
-  private final ModuleFileSystem fileSystem;
-  private FileType type;
-  private File sourceDir;
-  private String fileRelativePath;
-  private String fileCanonicalPath;
-
-  FileFilterContext(ModuleFileSystem fileSystem) {
-    this.fileSystem = fileSystem;
-  }
-
-  public ModuleFileSystem fileSystem() {
-    return fileSystem;
-  }
-
-  public FileType type() {
-    return type;
-  }
-
-  FileFilterContext setType(FileType t) {
-    this.type = t;
-    return this;
-  }
-
-  public File relativeDir() {
-    return sourceDir;
-  }
-
-  public String relativePath() {
-    return fileRelativePath;
-  }
-
-  public String canonicalPath() {
-    return fileCanonicalPath;
-  }
-
-  FileFilterContext setRelativeDir(File d) {
-    this.sourceDir = d;
-    return this;
-  }
-
-  FileFilterContext setRelativePath(String s) {
-    this.fileRelativePath = s;
-    return this;
-  }
-
-  FileFilterContext setCanonicalPath(String s) {
-    this.fileCanonicalPath = FilenameUtils.separatorsToUnix(s);
-    return this;
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterWrapper.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterWrapper.java
deleted file mode 100644 (file)
index 632aa68..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.sonar.api.scan.filesystem.FileSystemFilter;
-
-import java.io.File;
-import java.io.FileFilter;
-
-/**
- * @since 3.5
- */
-class FileFilterWrapper implements FileSystemFilter {
-  private final FileFilter filter;
-
-  FileFilterWrapper(FileFilter filter) {
-    this.filter = filter;
-  }
-
-  public boolean accept(File file, Context context) {
-    return filter.accept(file);
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashCache.java
deleted file mode 100644 (file)
index c17733c..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.collect.Maps;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.api.utils.SonarException;
-import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.PastSnapshotFinder;
-import org.sonar.core.source.SnapshotDataType;
-import org.sonar.core.source.jdbc.SnapshotDataDao;
-import org.sonar.core.source.jdbc.SnapshotDataDto;
-
-import javax.annotation.CheckForNull;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-public class FileHashCache implements BatchComponent, Startable {
-
-  private Map<String, String> currentHashCache = Maps.newHashMap();
-  private Map<String, String> previousHashCache = Maps.newHashMap();
-
-  private PathResolver pathResolver;
-  private HashBuilder hashBuilder;
-  private SnapshotDataDao snapshotDataDao;
-  private PastSnapshotFinder pastSnapshotFinder;
-  private Snapshot snapshot;
-  private ProjectDefinition module;
-
-  public FileHashCache(ProjectDefinition module, PathResolver pathResolver, HashBuilder hashBuilder,
-    Snapshot snapshot,
-    SnapshotDataDao snapshotDataDao,
-    PastSnapshotFinder pastSnapshotFinder) {
-    this.module = module;
-    this.pathResolver = pathResolver;
-    this.hashBuilder = hashBuilder;
-    this.snapshot = snapshot;
-    this.snapshotDataDao = snapshotDataDao;
-    this.pastSnapshotFinder = pastSnapshotFinder;
-  }
-
-  @Override
-  public void start() {
-    // Extract previous checksum of all files of this module and store them in a map
-    PastSnapshot pastSnapshot = pastSnapshotFinder.findPreviousAnalysis(snapshot);
-    if (pastSnapshot.isRelatedToSnapshot()) {
-      Collection<SnapshotDataDto> selectSnapshotData = snapshotDataDao.selectSnapshotData(pastSnapshot.getProjectSnapshot().getId().longValue(),
-        Arrays.asList(SnapshotDataType.FILE_HASH.getValue()));
-      if (!selectSnapshotData.isEmpty()) {
-        SnapshotDataDto snapshotDataDto = selectSnapshotData.iterator().next();
-        String data = snapshotDataDto.getData();
-        try {
-          List<String> lines = IOUtils.readLines(new StringReader(data));
-          for (String line : lines) {
-            String[] keyValue = StringUtils.split(line, "=");
-            if (keyValue.length == 2) {
-              previousHashCache.put(keyValue[0], keyValue[1]);
-            }
-          }
-        } catch (IOException e) {
-          throw new SonarException("Unable to read previous file hashes", e);
-        }
-      }
-    }
-  }
-
-  public String getCurrentHash(File file, Charset sourceCharset) {
-    String relativePath = pathResolver.relativePath(module.getBaseDir(), file);
-    if (!currentHashCache.containsKey(relativePath)) {
-      currentHashCache.put(relativePath, hashBuilder.computeHashNormalizeLineEnds(file, sourceCharset));
-    }
-    return currentHashCache.get(relativePath);
-  }
-
-  @CheckForNull
-  public String getPreviousHash(File file) {
-    String relativePath = pathResolver.relativePath(module.getBaseDir(), file);
-    return previousHashCache.get(relativePath);
-  }
-
-  @Override
-  public void stop() {
-    // Nothing to do
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashDigest.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashDigest.java
new file mode 100644 (file)
index 0000000..e7f5cb3
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+
+/**
+ * Computes hash of files. Ends of Lines are ignored, so files with
+ * same content but different EOL encoding have the same hash.
+ */
+class FileHashDigest {
+
+  // This singleton aims only to increase the coverage by allowing
+  // to test the private method !
+  static final FileHashDigest INSTANCE = new FileHashDigest();
+
+  private FileHashDigest() {
+  }
+
+  /**
+   * Compute hash of a file ignoring line ends differences.
+   * Maximum performance is needed.
+   */
+  String hash(File file, Charset charset) {
+    Reader reader = null;
+    try {
+      MessageDigest md5Digest = DigestUtils.getMd5Digest();
+      md5Digest.reset();
+      reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
+      int i = reader.read();
+      boolean afterCR = true;
+      while (i != -1) {
+        char c = (char) i;
+        if (afterCR) {
+          afterCR = false;
+          if (c == '\n') {
+            // Ignore
+            i = reader.read();
+            continue;
+          }
+        }
+        if (c == '\r') {
+          afterCR = true;
+          c = '\n';
+        }
+        md5Digest.update(charToBytesUTF(c));
+        i = reader.read();
+      }
+      return Hex.encodeHexString(md5Digest.digest());
+    } catch (IOException e) {
+      throw new IllegalStateException(String.format("Fail to compute hash of file %s with charset %s", file.getAbsolutePath(), charset), e);
+    } finally {
+      IOUtils.closeQuietly(reader);
+    }
+  }
+
+  private byte[] charToBytesUTF(char c) {
+    char[] buffer = new char[]{c};
+    byte[] b = new byte[buffer.length << 1];
+    for (int i = 0; i < buffer.length; i++) {
+      int bpos = i << 1;
+      b[bpos] = (byte) ((buffer[i] & 0xFF00) >> 8);
+      b[bpos + 1] = (byte) (buffer[i] & 0x00FF);
+    }
+    return b;
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashes.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileHashes.java
new file mode 100644 (file)
index 0000000..5ffcc11
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.sonar.api.BatchComponent;
+
+import javax.annotation.CheckForNull;
+import java.io.File;
+import java.nio.charset.Charset;
+
+/**
+ * Facade for local and remote file hashes
+ */
+public class FileHashes implements BatchComponent {
+
+  private final RemoteFileHashes remoteFileHashes;
+
+  public FileHashes(RemoteFileHashes remoteFileHashes) {
+    this.remoteFileHashes = remoteFileHashes;
+  }
+
+  @CheckForNull
+  public String hash(File file, Charset charset) {
+    return FileHashDigest.INSTANCE.hash(file, charset);
+  }
+
+  @CheckForNull
+  public String remoteHash(String baseRelativePath) {
+    return remoteFileHashes.remoteHash(baseRelativePath);
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java
new file mode 100644 (file)
index 0000000..4ffcb0e
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.filefilter.FileFilterUtils;
+import org.apache.commons.io.filefilter.HiddenFileFilter;
+import org.apache.commons.io.filefilter.IOFileFilter;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.scan.filesystem.InputFileFilter;
+import org.sonar.api.scan.filesystem.ModuleFileSystem;
+import org.sonar.api.scan.filesystem.PathResolver;
+
+import javax.annotation.Nullable;
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Index input files into {@link InputFileCache}.
+ */
+public class FileIndexer implements BatchComponent {
+
+  private static final IOFileFilter DIR_FILTER = FileFilterUtils.and(HiddenFileFilter.VISIBLE, FileFilterUtils.notFileFilter(FileFilterUtils.prefixFileFilter(".")));
+  private static final IOFileFilter FILE_FILTER = HiddenFileFilter.VISIBLE;
+
+  private final PathResolver pathResolver = new PathResolver();
+  private final List<InputFileFilter> filters;
+  private final LanguageRecognizer languageRecognizer;
+  private final InputFileCache cache;
+  private final FileHashes fileHashes;
+
+  // TODO support deprecated filters
+  public FileIndexer(List<InputFileFilter> filters, LanguageRecognizer languageRecognizer,
+                     InputFileCache cache, FileHashes fileHashes) {
+    this.filters = filters;
+    this.languageRecognizer = languageRecognizer;
+    this.cache = cache;
+    this.fileHashes = fileHashes;
+  }
+
+  public void index(ModuleFileSystem fileSystem) {
+    Logger logger = LoggerFactory.getLogger(FileIndexer.class);
+    logger.info("Index files");
+
+    cache.removeModule(fileSystem.moduleKey());
+    int count = 0;
+    for (File sourceDir : fileSystem.sourceDirs()) {
+      count += indexDirectory(fileSystem, sourceDir, InputFile.TYPE_SOURCE);
+    }
+    for (File testDir : fileSystem.testDirs()) {
+      count += indexDirectory(fileSystem, testDir, InputFile.TYPE_TEST);
+    }
+
+    // TODO index additional sources and test files
+
+    logger.info(String.format("%d files indexed", count));
+  }
+
+  private int indexDirectory(ModuleFileSystem fileSystem, File sourceDir, String type) {
+    int count = 0;
+    Collection<File> files = FileUtils.listFiles(sourceDir, FILE_FILTER, DIR_FILTER);
+    for (File file : files) {
+      InputFile input = newInputFile(fileSystem, sourceDir, type, file);
+      if (accept(input)) {
+        cache.put(fileSystem.moduleKey(), input);
+        count++;
+      }
+    }
+    return count;
+  }
+
+  private InputFile newInputFile(ModuleFileSystem fileSystem, File sourceDir, String type, File file) {
+    try {
+      Map<String, String> attributes = Maps.newHashMap();
+
+      // paths
+      String baseRelativePath = pathResolver.relativePath(fileSystem.baseDir(), file);
+      set(attributes, InputFile.ATTRIBUTE_SOURCEDIR_PATH, FilenameUtils.normalize(sourceDir.getCanonicalPath(), true));
+      set(attributes, InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, pathResolver.relativePath(sourceDir, file));
+      set(attributes, InputFile.ATTRIBUTE_CANONICAL_PATH, FilenameUtils.normalize(file.getCanonicalPath(), true));
+
+      // other metadata
+      set(attributes, InputFile.ATTRIBUTE_TYPE, type);
+      String extension = FilenameUtils.getExtension(file.getName());
+      set(attributes, InputFile.ATTRIBUTE_EXTENSION, extension);
+      set(attributes, InputFile.ATTRIBUTE_LANGUAGE, languageRecognizer.ofExtension(extension));
+      initStatus(file, fileSystem.sourceCharset(), baseRelativePath, attributes);
+
+      return InputFile.create(file, baseRelativePath, attributes);
+
+    } catch (Exception e) {
+      throw new IllegalStateException("Fail to read file: " + file.getAbsolutePath(), e);
+    }
+  }
+
+  private void initStatus(File file, Charset charset, String baseRelativePath, Map<String, String> attributes) {
+    String hash = fileHashes.hash(file, charset);
+    set(attributes, InputFile.ATTRIBUTE_HASH, hash);
+
+    String remoteHash = fileHashes.remoteHash(baseRelativePath);
+    // currently no need to store this remote hash in attributes
+    if (StringUtils.equals(hash, remoteHash)) {
+      set(attributes, InputFile.ATTRIBUTE_STATUS, InputFile.STATUS_SAME);
+    } else if (StringUtils.isEmpty(remoteHash)) {
+      set(attributes, InputFile.ATTRIBUTE_STATUS, InputFile.STATUS_ADDED);
+    } else {
+      set(attributes, InputFile.ATTRIBUTE_STATUS, InputFile.STATUS_CHANGED);
+    }
+  }
+
+  private void set(Map<String, String> attributes, String key, @Nullable String value) {
+    if (value != null) {
+      attributes.put(key, value);
+    }
+  }
+
+  private boolean accept(InputFile inputFile) {
+    for (InputFileFilter filter : filters) {
+      if (!filter.accept(inputFile)) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileQueryFilter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileQueryFilter.java
new file mode 100644 (file)
index 0000000..b62694c
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.Lists;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.scan.filesystem.FileQuery;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.scan.filesystem.InputFileFilter;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+class FileQueryFilter {
+
+  private final List<InputFileFilter> filters;
+
+  FileQueryFilter(Settings settings, FileQuery query) {
+    filters = Lists.newArrayList();
+    for (String pattern : query.inclusions()) {
+      filters.add(new InclusionFilter(pattern));
+    }
+    for (String pattern : query.exclusions()) {
+      filters.add(new ExclusionFilter(pattern));
+    }
+    for (Map.Entry<String, Collection<String>> entry : query.attributes().entrySet()) {
+      filters.add(new AttributeFilter(entry.getKey(), entry.getValue()));
+    }
+
+    // TODO speed-up the following algorithm. Cache ?
+    if (settings.getBoolean(CoreProperties.INCREMENTAL_PREVIEW)) {
+      Collection<String> status = query.attributes().get(InputFile.ATTRIBUTE_STATUS);
+      if (status == null || status.isEmpty()) {
+        // TODO should be not(SAME) instead of is(ADDED, CHANGED)
+        filters.add(new AttributeFilter(InputFile.ATTRIBUTE_STATUS, Lists.newArrayList(InputFile.STATUS_ADDED, InputFile.STATUS_CHANGED)));
+      }
+    }
+  }
+
+  boolean accept(InputFile inputFile) {
+    for (InputFileFilter filter : filters) {
+      if (!filter.accept(inputFile)) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
index c52b00c32df41466a236a85db56d1fdd0f516387..2d402d358b0d570146bccaf6f4dc27d10727022e 100644 (file)
@@ -23,13 +23,14 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.sonar.api.BatchComponent;
 
 import java.io.File;
 import java.nio.charset.Charset;
 import java.util.List;
 import java.util.Locale;
 
-public class FileSystemLogger {
+public class FileSystemLogger implements BatchComponent {
 
   private final DefaultModuleFileSystem fs;
 
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/HashBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/HashBuilder.java
deleted file mode 100644 (file)
index 2db7946..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.BatchExtension;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.utils.SonarException;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.Charset;
-import java.security.MessageDigest;
-
-/**
- * @since 4.0
- */
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-public final class HashBuilder implements BatchExtension {
-
-  /**
-   * Compute hash of a file ignoring line ends differences.
-   * Maximum performance is needed.
-   */
-  public String computeHashNormalizeLineEnds(File file, Charset charset) {
-    Reader reader = null;
-    try {
-      MessageDigest md5Digest = DigestUtils.getMd5Digest();
-      md5Digest.reset();
-      reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
-      int i = reader.read();
-      boolean afterCR = true;
-      while (i != -1) {
-        char c = (char) i;
-        if (afterCR) {
-          afterCR = false;
-          if (c == '\n') {
-            // Ignore
-            i = reader.read();
-            continue;
-          }
-        }
-        if (c == '\r') {
-          afterCR = true;
-          c = '\n';
-        }
-        md5Digest.update(charToBytesUTF(c));
-        i = reader.read();
-      }
-      return Hex.encodeHexString(md5Digest.digest());
-    } catch (IOException e) {
-      throw new SonarException("Unable to compute file hash", e);
-    } finally {
-      IOUtils.closeQuietly(reader);
-    }
-  }
-
-  public static byte[] charToBytesUTF(char c) {
-    char[] buffer = new char[] {c};
-    byte[] b = new byte[buffer.length << 1];
-    for (int i = 0; i < buffer.length; i++) {
-      int bpos = i << 1;
-      b[bpos] = (byte) ((buffer[i] & 0xFF00) >> 8);
-      b[bpos + 1] = (byte) (buffer[i] & 0x00FF);
-    }
-    return b;
-  }
-}
index 43c776121e89b3425da08a87d3f4e5c15ceef9e5..ef5d391e0cc1ae89845196cfb8d8fd75174699ef 100644 (file)
  */
 package org.sonar.batch.scan.filesystem;
 
-import org.sonar.api.scan.filesystem.FileSystemFilter;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.scan.filesystem.InputFileFilter;
 
-import java.io.File;
-
-class InclusionFilter implements FileSystemFilter {
+class InclusionFilter implements InputFileFilter {
   private final PathPattern pattern;
 
   InclusionFilter(String s) {
     this.pattern = PathPattern.create(s);
   }
 
-  public boolean accept(File file, FileSystemFilter.Context context) {
-    return pattern.match(context);
+  @Override
+  public boolean accept(InputFile inputFile) {
+    return pattern.match(inputFile);
   }
 
   @Override
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileCache.java
new file mode 100644 (file)
index 0000000..f45f808
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.batch.index.Cache;
+import org.sonar.batch.index.Caches;
+
+/**
+ * Cache of all files. This cache is shared amongst all project modules. Inclusion and
+ * exclusion patterns are already applied.
+ */
+public class InputFileCache implements BatchComponent {
+
+  // module key -> path -> InputFile
+  private final Cache<String, InputFile> cache;
+
+  public InputFileCache(Caches caches) {
+    cache = caches.createCache("inputFiles");
+  }
+
+  public Iterable<InputFile> byModule(String moduleKey) {
+    return cache.values(moduleKey);
+  }
+
+  public InputFileCache removeModule(String moduleKey) {
+    cache.clear(moduleKey);
+    return this;
+  }
+
+  public Iterable<InputFile> all() {
+    return cache.allValues();
+  }
+
+  public InputFileCache put(String moduleKey, InputFile file) {
+    cache.put(moduleKey, file.path(), file);
+    return this;
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageFilters.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageFilters.java
deleted file mode 100644 (file)
index fcc887b..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.apache.commons.io.IOCase;
-import org.apache.commons.io.filefilter.FalseFileFilter;
-import org.apache.commons.io.filefilter.IOFileFilter;
-import org.apache.commons.io.filefilter.SuffixFileFilter;
-import org.apache.commons.io.filefilter.TrueFileFilter;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-
-public class LanguageFilters implements BatchComponent {
-  private final Languages languages;
-
-  public LanguageFilters(Languages languages) {
-    this.languages = languages;
-  }
-
-  public IOFileFilter forLang(String lang) {
-    Language language = languages.get(lang);
-    if (language == null) {
-      return FalseFileFilter.FALSE;
-    }
-    String[] suffixes = language.getFileSuffixes();
-    if (suffixes != null && suffixes.length>0) {
-      return new SuffixFileFilter(suffixes, IOCase.SENSITIVE);
-    }
-    return TrueFileFilter.TRUE;
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java
new file mode 100644 (file)
index 0000000..6139683
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.resources.Language;
+
+import javax.annotation.CheckForNull;
+import java.util.Map;
+
+/**
+ * Based on file extensions.
+ */
+public class LanguageRecognizer implements BatchComponent {
+
+  private final Map<String, String> byExtensions = Maps.newHashMap();
+
+  public LanguageRecognizer(Language[] languages) {
+    for (Language language : languages) {
+      for (String suffix : language.getFileSuffixes()) {
+        String extension = StringUtils.removeStart(suffix, ".");
+
+        String s = byExtensions.get(extension);
+        if (s != null) {
+          throw new IllegalStateException(String.format(
+            "File extension '%s' is declared by two languages: %s and %s", extension, s, language.getKey()
+          ));
+        }
+        byExtensions.put(extension, language.getKey());
+      }
+    }
+  }
+
+  // TODO what about cobol files without extension ?
+  @CheckForNull
+  String ofExtension(String fileExtension) {
+    if (StringUtils.isNotBlank(fileExtension)) {
+      return byExtensions.get(fileExtension);
+    }
+    return null;
+  }
+}
index 3efae8a0ec0d2b5441e06db1448dc8c99f70180e..7bd84e87ef7233247971362871542d2780c399e9 100644 (file)
  */
 package org.sonar.batch.scan.filesystem;
 
-import com.google.common.collect.ImmutableSet;
 import org.apache.commons.io.FileUtils;
 import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.config.Settings;
 import org.sonar.api.scan.filesystem.FileSystemFilter;
-import org.sonar.api.scan.filesystem.FileType;
 import org.sonar.api.scan.filesystem.PathResolver;
 import org.sonar.batch.bootstrap.TempDirectories;
 
@@ -37,22 +35,21 @@ import java.util.List;
  */
 public class ModuleFileSystemProvider extends ProviderAdapter {
 
+  private PathResolver pathResolver = new PathResolver();
   private DefaultModuleFileSystem singleton;
 
-  public DefaultModuleFileSystem provide(ProjectDefinition module, PathResolver pathResolver, TempDirectories tempDirectories,
-    LanguageFilters languageFilters, Settings settings, FileSystemFilter[] pluginFileFilters,
-    FileHashCache fileHashCache) {
+  public DefaultModuleFileSystem provide(
+    ProjectDefinition module, TempDirectories tempDirectories,Settings settings, InputFileCache cache, FileIndexer indexer) {
+
     if (singleton == null) {
-      DefaultModuleFileSystem fs = new DefaultModuleFileSystem(fileHashCache);
-      fs.setLanguageFilters(languageFilters);
+      DefaultModuleFileSystem fs = new DefaultModuleFileSystem(module.getKey(), settings, cache, indexer);
       fs.setBaseDir(module.getBaseDir());
       fs.setBuildDir(module.getBuildDir());
-      fs.setSettings(settings);
       fs.setWorkingDir(guessWorkingDir(module, tempDirectories));
-      fs.addFilters(pluginFileFilters);
-      initBinaryDirs(module, pathResolver, fs);
-      initSources(module, pathResolver, fs);
-      initTests(module, pathResolver, fs);
+      initBinaryDirs(module, fs);
+      initSources(module, fs);
+      initTests(module, fs);
+      fs.index();
       singleton = fs;
     }
     return singleton;
@@ -72,7 +69,7 @@ public class ModuleFileSystemProvider extends ProviderAdapter {
     return workDir;
   }
 
-  private void initSources(ProjectDefinition module, PathResolver pathResolver, DefaultModuleFileSystem fs) {
+  private void initSources(ProjectDefinition module, DefaultModuleFileSystem fs) {
     for (String sourcePath : module.getSourceDirs()) {
       File dir = pathResolver.relativeFile(module.getBaseDir(), sourcePath);
       if (dir.isDirectory() && dir.exists()) {
@@ -80,12 +77,10 @@ public class ModuleFileSystemProvider extends ProviderAdapter {
       }
     }
     List<File> sourceFiles = pathResolver.relativeFiles(module.getBaseDir(), module.getSourceFiles());
-    if (!sourceFiles.isEmpty()) {
-      fs.addFilters(new WhiteListFileFilter(FileType.SOURCE, ImmutableSet.copyOf(sourceFiles)));
-    }
+    fs.setAdditionalSourceFiles(sourceFiles);
   }
 
-  private void initTests(ProjectDefinition module, PathResolver pathResolver, DefaultModuleFileSystem fs) {
+  private void initTests(ProjectDefinition module, DefaultModuleFileSystem fs) {
     for (String testPath : module.getTestDirs()) {
       File dir = pathResolver.relativeFile(module.getBaseDir(), testPath);
       if (dir.exists() && dir.isDirectory()) {
@@ -93,12 +88,10 @@ public class ModuleFileSystemProvider extends ProviderAdapter {
       }
     }
     List<File> testFiles = pathResolver.relativeFiles(module.getBaseDir(), module.getTestFiles());
-    if (!testFiles.isEmpty()) {
-      fs.addFilters(new WhiteListFileFilter(FileType.TEST, ImmutableSet.copyOf(testFiles)));
-    }
+    fs.setAdditionalTestFiles(testFiles);
   }
 
-  private void initBinaryDirs(ProjectDefinition module, PathResolver pathResolver, DefaultModuleFileSystem fs) {
+  private void initBinaryDirs(ProjectDefinition module, DefaultModuleFileSystem fs) {
     for (String path : module.getBinaries()) {
       File dir = pathResolver.relativeFile(module.getBaseDir(), path);
       fs.addBinaryDir(dir);
index bd6eb8479e07f670e1d641eb873a59d7a9f25b6e..2df7c53e4d652ed4cd20f961c8d04e743142e7a5 100644 (file)
@@ -21,20 +21,21 @@ package org.sonar.batch.scan.filesystem;
 
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.resources.Resource;
-import org.sonar.api.scan.filesystem.FileSystemFilter;
+import org.sonar.api.scan.filesystem.InputFile;
 import org.sonar.api.utils.WildcardPattern;
 
 abstract class PathPattern {
+
   final WildcardPattern pattern;
 
   PathPattern(String pattern) {
     this.pattern = WildcardPattern.create(pattern);
   }
 
-  abstract boolean match(FileSystemFilter.Context context);
-
   abstract boolean match(Resource resource);
 
+  abstract boolean match(InputFile inputFile);
+
   abstract boolean supportResource();
 
   static PathPattern create(String s) {
@@ -58,14 +59,17 @@ abstract class PathPattern {
       super(pattern);
     }
 
-    boolean match(FileSystemFilter.Context context) {
-      return pattern.match(context.canonicalPath());
+    @Override
+    boolean match(InputFile inputFile) {
+      return pattern.match(inputFile.attribute(InputFile.ATTRIBUTE_CANONICAL_PATH));
     }
 
+    @Override
     boolean match(Resource resource) {
       return false;
     }
 
+    @Override
     boolean supportResource() {
       return false;
     }
@@ -76,19 +80,26 @@ abstract class PathPattern {
     }
   }
 
+  /**
+   * Path relative to source directory
+   */
   private static class RelativePathPattern extends PathPattern {
     private RelativePathPattern(String pattern) {
       super(pattern);
     }
 
-    boolean match(FileSystemFilter.Context context) {
-      return pattern.match(context.relativePath());
+    @Override
+    boolean match(InputFile inputFile) {
+      String path = inputFile.attribute(InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH);
+      return path != null && pattern.match(path);
     }
 
+    @Override
     boolean match(Resource resource) {
       return resource.matchFilePattern(pattern.toString());
     }
 
+    @Override
     boolean supportResource() {
       return true;
     }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ProjectFileSystemAdapter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ProjectFileSystemAdapter.java
new file mode 100644 (file)
index 0000000..1f5ab33
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.CharEncoding;
+import org.apache.maven.project.MavenProject;
+import org.sonar.api.resources.*;
+import org.sonar.api.scan.filesystem.FileQuery;
+import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.api.utils.SonarException;
+
+import javax.annotation.Nullable;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * Adapter for keeping the backward-compatibility of the deprecated component {@link org.sonar.api.resources.ProjectFileSystem}
+ *
+ * @since 3.5
+ */
+public class ProjectFileSystemAdapter implements ProjectFileSystem {
+
+  private final DefaultModuleFileSystem target;
+  private final PathResolver pathResolver = new PathResolver();
+  private final MavenProject pom;
+
+
+  public ProjectFileSystemAdapter(DefaultModuleFileSystem target, Project project, @Nullable MavenProject pom) {
+    this.target = target;
+    this.pom = pom;
+
+    // TODO See http://jira.codehaus.org/browse/SONAR-2126
+    // previously MavenProjectBuilder was responsible for creation of ProjectFileSystem
+    project.setFileSystem(this);
+  }
+
+  public ProjectFileSystemAdapter(DefaultModuleFileSystem target, Project project) {
+    this(target, project, null);
+  }
+
+  public void start() {
+    // used to avoid NPE in Project#getFileSystem()
+  }
+
+  public Charset getSourceCharset() {
+    return target.sourceCharset();
+  }
+
+  public File getBasedir() {
+    return target.baseDir();
+  }
+
+  public File getBuildDir() {
+    File dir = target.buildDir();
+    if (dir == null) {
+      // emulate build dir to keep backward-compatibility
+      dir = new File(getSonarWorkingDirectory(), "build");
+    }
+    return dir;
+  }
+
+  public File getBuildOutputDir() {
+    File dir = Iterables.getFirst(target.binaryDirs(), null);
+    if (dir == null) {
+      // emulate binary dir
+      dir = new File(getBuildDir(), "classes");
+    }
+
+    return dir;
+  }
+
+  public List<File> getSourceDirs() {
+    return target.sourceDirs();
+  }
+
+  public ProjectFileSystem addSourceDir(File dir) {
+    target.addSourceDir(dir);
+    return this;
+  }
+
+  public List<File> getTestDirs() {
+    return target.testDirs();
+  }
+
+  public ProjectFileSystem addTestDir(File dir) {
+    target.addTestDir(dir);
+    return this;
+  }
+
+  public File getReportOutputDir() {
+    if (pom != null) {
+      return resolvePath(pom.getReporting().getOutputDirectory());
+    }
+    // emulate Maven report output dir
+    return new File(getBuildDir(), "site");
+  }
+
+  public File getSonarWorkingDirectory() {
+    return target.workingDir();
+  }
+
+  public File resolvePath(String path) {
+    File file = new File(path);
+    if (!file.isAbsolute()) {
+      try {
+        file = new File(getBasedir(), path).getCanonicalFile();
+      } catch (IOException e) {
+        throw new SonarException("Unable to resolve path '" + path + "'", e);
+      }
+    }
+    return file;
+  }
+
+  public List<File> getSourceFiles(Language... langs) {
+    List<File> result = Lists.newArrayList();
+    for (Language lang : langs) {
+      result.addAll(target.files(FileQuery.onSource().onLanguage(lang.getKey())));
+    }
+    return result;
+  }
+
+  public List<File> getJavaSourceFiles() {
+    return getSourceFiles(Java.INSTANCE);
+  }
+
+  public boolean hasJavaSourceFiles() {
+    return !getJavaSourceFiles().isEmpty();
+  }
+
+  public List<File> getTestFiles(Language... langs) {
+    List<File> result = Lists.newArrayList();
+    for (Language lang : langs) {
+      result.addAll(target.files(FileQuery.onTest().onLanguage(lang.getKey())));
+    }
+    return result;
+  }
+
+  public boolean hasTestFiles(Language lang) {
+    return !getTestFiles(lang).isEmpty();
+  }
+
+  public File writeToWorkingDirectory(String content, String fileName) throws IOException {
+    File file = new File(target.workingDir(), fileName);
+    FileUtils.writeStringToFile(file, content, CharEncoding.UTF_8);
+    return file;
+  }
+
+  public File getFileFromBuildDirectory(String filename) {
+    File file = new File(getBuildDir(), filename);
+    return file.exists() ? file : null;
+  }
+
+  public Resource toResource(File file) {
+    if (file == null || !file.exists()) {
+      return null;
+    }
+    PathResolver.RelativePath relativePath = pathResolver.relativePath(getSourceDirs(), file);
+    if (relativePath == null) {
+      return null;
+    }
+    return file.isFile() ? new org.sonar.api.resources.File(relativePath.path()) : new org.sonar.api.resources.Directory(relativePath.path());
+  }
+
+  public List<InputFile> mainFiles(String... langs) {
+    List<InputFile> result = Lists.newArrayList();
+    Iterable<org.sonar.api.scan.filesystem.InputFile> files = target.inputFiles(FileQuery.onSource().onLanguage(langs));
+    for (org.sonar.api.scan.filesystem.InputFile file : files) {
+      String sourceDir = file.attribute(org.sonar.api.scan.filesystem.InputFile.ATTRIBUTE_SOURCEDIR_PATH);
+      String sourceRelativePath = file.attribute(org.sonar.api.scan.filesystem.InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH);
+      if (sourceDir != null && sourceRelativePath != null) {
+        result.add(InputFileUtils.create(new File(sourceDir), sourceRelativePath));
+      }
+    }
+    return result;
+  }
+
+  public List<InputFile> testFiles(String... langs) {
+    List<InputFile> result = Lists.newArrayList();
+    Iterable<org.sonar.api.scan.filesystem.InputFile> files = target.inputFiles(FileQuery.onTest().onLanguage(langs));
+    for (org.sonar.api.scan.filesystem.InputFile file : files) {
+      String sourceDir = file.attribute(org.sonar.api.scan.filesystem.InputFile.ATTRIBUTE_SOURCEDIR_PATH);
+      String sourceRelativePath = file.attribute(org.sonar.api.scan.filesystem.InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH);
+      if (sourceDir != null && sourceRelativePath != null) {
+        result.add(InputFileUtils.create(new File(sourceDir), sourceRelativePath));
+      }
+    }
+    return result;
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/RemoteFileHashes.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/RemoteFileHashes.java
new file mode 100644 (file)
index 0000000..b2d8853
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.Maps;
+import org.picocontainer.Startable;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.batch.components.PastSnapshot;
+import org.sonar.batch.components.PastSnapshotFinder;
+import org.sonar.core.source.SnapshotDataType;
+import org.sonar.core.source.jdbc.SnapshotDataDao;
+import org.sonar.core.source.jdbc.SnapshotDataDto;
+
+import javax.annotation.CheckForNull;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+
+public class RemoteFileHashes implements BatchComponent, Startable {
+
+  private final SnapshotDataDao dao;
+  private final PastSnapshotFinder pastSnapshotFinder;
+  private final Snapshot snapshot;
+
+  private Map<String, String> pathToHash = Maps.newHashMap();
+
+  public RemoteFileHashes(Snapshot snapshot, SnapshotDataDao dao, PastSnapshotFinder pastSnapshotFinder) {
+    this.snapshot = snapshot;
+    this.dao = dao;
+    this.pastSnapshotFinder = pastSnapshotFinder;
+  }
+
+  @Override
+  public void start() {
+    // Extract previous checksum of all files of this module and store them in a map
+    PastSnapshot pastSnapshot = pastSnapshotFinder.findPreviousAnalysis(snapshot);
+    if (pastSnapshot.isRelatedToSnapshot()) {
+      Collection<SnapshotDataDto> selectSnapshotData = dao.selectSnapshotData(
+        pastSnapshot.getProjectSnapshot().getId().longValue(),
+        Arrays.asList(SnapshotDataType.FILE_HASH.getValue())
+      );
+      if (!selectSnapshotData.isEmpty()) {
+        SnapshotDataDto snapshotDataDto = selectSnapshotData.iterator().next();
+        String data = snapshotDataDto.getData();
+        pathToHash = KeyValueFormat.parse(data);
+      }
+    }
+  }
+
+  @CheckForNull
+  public String remoteHash(String baseRelativePath) {
+    return pathToHash.get(baseRelativePath);
+  }
+
+  @Override
+  public void stop() {
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/WhiteListFileFilter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/WhiteListFileFilter.java
deleted file mode 100644 (file)
index fb4cdb6..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.SystemUtils;
-import org.sonar.api.scan.filesystem.FileSystemFilter;
-import org.sonar.api.scan.filesystem.FileType;
-
-import java.io.File;
-import java.util.Set;
-
-/**
- * @since 3.5
- */
-class WhiteListFileFilter implements FileSystemFilter {
-  private final FileType fileType;
-  private final Set<File> files;
-
-  WhiteListFileFilter(FileType fileType, Set<File> files) {
-    Preconditions.checkNotNull(fileType);
-    Preconditions.checkNotNull(files);
-    this.fileType = fileType;
-    this.files = files;
-  }
-
-  public boolean accept(File file, Context context) {
-    return !context.type().equals(fileType) || files.contains(file);
-  }
-
-  @Override
-  public String toString() {
-    return StringUtils.capitalize(fileType.name().toLowerCase()) + " files: " + SystemUtils.LINE_SEPARATOR +
-      Joiner.on(SystemUtils.LINE_SEPARATOR).join(files);
-  }
-}
index 648bee96caac5105f31832f09d76966d74267cff..f5246e640996b9a94d6a649c4a2f5c3096b9c805 100644 (file)
@@ -22,8 +22,9 @@ package org.sonar.batch.scan;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.sonar.api.CoreProperties;
 import org.sonar.api.config.Settings;
-import org.sonar.batch.scan.UnsupportedProperties;
+import org.sonar.api.utils.MessageException;
 
 public class UnsupportedPropertiesTest {
 
@@ -32,10 +33,11 @@ public class UnsupportedPropertiesTest {
 
   @Test
   public void should_fail_if_sonar_light_is_set() {
+    thrown.expect(MessageException.class);
+    thrown.expectMessage("The property 'sonar.light' is no longer supported. Please use 'sonar.dynamicAnalysis'");
+
     Settings settings = new Settings();
     settings.setProperty("sonar.light", true);
-
-    thrown.expect(IllegalArgumentException.class);
     new UnsupportedProperties(settings).start();
   }
 
@@ -44,4 +46,23 @@ public class UnsupportedPropertiesTest {
     Settings settings = new Settings();
     new UnsupportedProperties(settings).start();
   }
+
+  @Test
+  public void should_fail_if_incremental_but_not_preview_mode() {
+    thrown.expect(MessageException.class);
+    thrown.expectMessage("Incremental mode is only supported with preview mode");
+
+    Settings settings = new Settings();
+    settings.setProperty(CoreProperties.INCREMENTAL_PREVIEW, true);
+    settings.setProperty(CoreProperties.DRY_RUN, false);
+    new UnsupportedProperties(settings).start();
+  }
+
+  @Test
+  public void should_not_fail_if_incremental_preview_mode() {
+    Settings settings = new Settings();
+    settings.setProperty(CoreProperties.INCREMENTAL_PREVIEW, true);
+    settings.setProperty(CoreProperties.DRY_RUN, true);
+    new UnsupportedProperties(settings).start();
+  }
 }
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/AttributeFilterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/AttributeFilterTest.java
new file mode 100644 (file)
index 0000000..1ce0a8a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.scan.filesystem.InputFile;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class AttributeFilterTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @Test
+  public void should_check_attribute_value() throws Exception {
+    AttributeFilter filter = new AttributeFilter("foo", Lists.newArrayList("one", "two"));
+
+    assertThat(filter.accept(InputFile.create(temp.newFile(), "Why.java", ImmutableMap.of("foo", "two")))).isTrue();
+    assertThat(filter.accept(InputFile.create(temp.newFile(), "Where.java", ImmutableMap.of("foo", "three")))).isFalse();
+    assertThat(filter.accept(InputFile.create(temp.newFile(), "What.java", ImmutableMap.of("bar", "one")))).isFalse();
+
+  }
+}
index 61f0ccbe5bd0930b548f43c6bceb43151ca66bce..c0dfddb5a7e0f48fe52661d049d527e70ddd756c 100644 (file)
  */
 package org.sonar.batch.scan.filesystem;
 
-import com.google.common.base.Charsets;
-import org.apache.commons.io.filefilter.FileFilterUtils;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.config.Settings;
-import org.sonar.api.resources.AbstractLanguage;
-import org.sonar.api.resources.Languages;
 import org.sonar.api.scan.filesystem.FileQuery;
-import org.sonar.api.scan.filesystem.FileSystemFilter;
-import org.sonar.api.utils.SonarException;
+import org.sonar.api.scan.filesystem.InputFile;
 
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
-import java.util.Arrays;
 import java.util.List;
 
 import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 public class DefaultModuleFileSystemTest {
+
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
+  InputFileCache fileCache = mock(InputFileCache.class);
+  Settings settings = new Settings();
+  FileIndexer fileIndexer = mock(FileIndexer.class);
+
   @Test
-  public void test_new_file_system() throws IOException {
-    File basedir = temp.newFolder("base");
-    File workingDir = temp.newFolder("work");
-    LanguageFilters languageFilters = mock(LanguageFilters.class);
-    FileSystemFilter fileFilter = mock(FileSystemFilter.class);
-
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setWorkingDir(workingDir)
-      .addBinaryDir(new File(basedir, "target/classes"))
-      .addSourceDir(new File(basedir, "src/main/java"))
-      .addSourceDir(new File(basedir, "src/main/groovy"))
-      .addTestDir(new File(basedir, "src/test/java"))
-      .addFilters(fileFilter)
-      .setLanguageFilters(languageFilters);
-
-    assertThat(fileSystem).isNotNull();
-    assertThat(fileSystem.baseDir().getCanonicalPath()).isEqualTo(basedir.getCanonicalPath());
-    assertThat(fileSystem.workingDir().getCanonicalPath()).isEqualTo(workingDir.getCanonicalPath());
-    assertThat(fileSystem.sourceDirs()).hasSize(2);
-    assertThat(fileSystem.testDirs()).hasSize(1);
-    assertThat(fileSystem.binaryDirs()).hasSize(1);
-    assertThat(fileSystem.filters()).containsOnly(fileFilter);
-    assertThat(fileSystem.languageFilters()).isSameAs(languageFilters);
+  public void test_equals_and_hashCode() throws Exception {
+    DefaultModuleFileSystem foo1 = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
+    DefaultModuleFileSystem foo2 = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
+    DefaultModuleFileSystem bar = new DefaultModuleFileSystem("bar", settings, fileCache, fileIndexer);
+
+    assertThat(foo1.moduleKey()).isEqualTo("foo");
+    assertThat(foo1.equals(foo1)).isTrue();
+    assertThat(foo1.equals(foo2)).isTrue();
+    assertThat(foo1.equals(bar)).isFalse();
+    assertThat(foo1.equals("foo")).isFalse();
+    assertThat(foo1.hashCode()).isEqualTo(foo1.hashCode());
+    assertThat(foo1.hashCode()).isEqualTo(foo2.hashCode());
   }
 
   @Test
   public void default_source_encoding() {
-    File basedir = temp.newFolder("base");
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setSettings(new Settings());
+    DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
 
-    assertThat(fileSystem.sourceCharset()).isEqualTo(Charset.defaultCharset());
-    assertThat(fileSystem.isDefaultSourceCharset()).isTrue();
+    assertThat(fs.sourceCharset()).isEqualTo(Charset.defaultCharset());
+    assertThat(fs.isDefaultSourceCharset()).isTrue();
   }
 
   @Test
   public void source_encoding_is_set() {
-    File basedir = temp.newFolder("base");
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCODING_PROPERTY, "UTF-8");
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setSettings(settings);
-
-    assertThat(fileSystem.sourceCharset()).isEqualTo(Charset.forName("UTF-8"));
-    assertThat(fileSystem.isDefaultSourceCharset()).isFalse();
-  }
+    settings.setProperty(CoreProperties.ENCODING_PROPERTY, "Cp1124");
+    DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
 
-  @Test
-  public void should_exclude_dirs_starting_with_dot() throws IOException {
-    File basedir = new File(resourcesDir(), "exclude_dir_starting_with_dot");
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setWorkingDir(temp.newFolder())
-      .addSourceDir(new File(basedir, "src"))
-      .setSettings(new Settings());
-
-    List<File> files = fileSystem.files(FileQuery.onSource());
-    assertThat(files).hasSize(1);
-    assertThat(files.get(0).getName()).isEqualTo("Included.java");
+    assertThat(fs.sourceCharset()).isEqualTo(Charset.forName("Cp1124"));
+
+    // This test fails when default Java encoding is "IBM AIX Ukraine". Sorry for that.
+    assertThat(fs.isDefaultSourceCharset()).isFalse();
   }
 
   @Test
-  public void should_load_source_files_by_language() throws IOException {
-    File basedir = new File(resourcesDir(), "main_and_test_files");
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setWorkingDir(temp.newFolder())
-      .addSourceDir(new File(basedir, "src/main/java"))
-      .addTestDir(new File(basedir, "src/test/java"))
-      .setLanguageFilters(new LanguageFilters(new Languages(new Java(), new Php())))
-      .setSettings(new Settings());
-
-    List<File> files = fileSystem.files(FileQuery.onSource().onLanguage("java"));
-    assertThat(files).hasSize(2);
-    for (File sourceFiles : files) {
-      assertThat(sourceFiles).exists().isFile();
-      assertThat(sourceFiles.getName()).isIn("Hello.java", "Foo.java");
-    }
-    assertThat(fileSystem.files(FileQuery.onSource().onLanguage("php"))).isEmpty();
+  public void test_dirs() throws IOException {
+    File basedir = temp.newFolder("base");
+    File buildDir = temp.newFolder("build");
+    File workingDir = temp.newFolder("work");
+
+    DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
+    fs.setBaseDir(basedir);
+    fs.setBuildDir(buildDir);
+    fs.setWorkingDir(workingDir);
+    fs.addBinaryDir(new File(basedir, "target/classes"));
+    fs.addSourceDir(new File(basedir, "src/main/java"));
+    fs.addSourceDir(new File(basedir, "src/main/groovy"));
+    fs.addTestDir(new File(basedir, "src/test/java"));
+
+    assertThat(fs.baseDir().getCanonicalPath()).isEqualTo(basedir.getCanonicalPath());
+    assertThat(fs.workingDir().getCanonicalPath()).isEqualTo(workingDir.getCanonicalPath());
+    assertThat(fs.buildDir().getCanonicalPath()).isEqualTo(buildDir.getCanonicalPath());
+    assertThat(fs.sourceDirs()).hasSize(2);
+    assertThat(fs.testDirs()).hasSize(1);
+    assertThat(fs.binaryDirs()).hasSize(1);
   }
 
   @Test
-  public void should_load_test_files() throws IOException {
-    File basedir = new File(resourcesDir(), "main_and_test_files");
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setWorkingDir(temp.newFolder())
-      .addSourceDir(new File(basedir, "src/main/java"))
-      .addTestDir(new File(basedir, "src/test/java"))
-      .setSettings(new Settings());
-
-    assertThat(fileSystem.testDirs()).hasSize(1);
-    List<File> testFiles = fileSystem.files(FileQuery.onTest());
-    assertThat(testFiles).hasSize(2);
-    for (File testFile : testFiles) {
-      assertThat(testFile).exists().isFile();
-      assertThat(testFile.getName()).endsWith("Test.java");
-    }
+  public void test_additional_source_files() throws IOException {
+    DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
+    assertThat(fs.additionalSourceFiles()).isEmpty();
+    assertThat(fs.additionalTestFiles()).isEmpty();
+
+    File main = temp.newFile("Main.java");
+    File test = temp.newFile("Test.java");
+    fs.setAdditionalSourceFiles(Lists.newArrayList(main));
+    fs.setAdditionalTestFiles(Lists.newArrayList(test));
+    assertThat(fs.additionalSourceFiles()).containsOnly(main);
+    assertThat(fs.additionalTestFiles()).containsOnly(test);
   }
 
   @Test
-  public void should_load_test_files_by_language() throws IOException {
-    File basedir = new File(resourcesDir(), "main_and_test_files");
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setWorkingDir(temp.newFolder())
-      .addSourceDir(new File(basedir, "src/main/java"))
-      .addTestDir(new File(basedir, "src/test/java"))
-      .setLanguageFilters(new LanguageFilters(new Languages(new Java(), new Php())))
-      .setSettings(new Settings());
-
-    List<File> testFiles = fileSystem.files(FileQuery.onTest().onLanguage("java"));
-    assertThat(testFiles).hasSize(2);
-    for (File testFile : testFiles) {
-      assertThat(testFile).exists().isFile();
-      assertThat(testFile.getName()).endsWith("Test.java");
-    }
-    assertThat(fileSystem.files(FileQuery.onTest().onLanguage("php"))).isEmpty();
-  }
+  public void should_reset_dirs() throws IOException {
+    File basedir = temp.newFolder();
+    DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
+    fs.setBaseDir(basedir);
+    fs.setWorkingDir(basedir);
+    fs.addSourceDir(new File(basedir, "src/main/java"));
 
-  private File resourcesDir() {
-    File dir = new File("test-resources/DefaultModuleFileSystemTest");
-    if (!dir.exists()) {
-      dir = new File("sonar-batch/test-resources/DefaultModuleFileSystemTest");
-    }
-    return dir;
+    File existingDir = temp.newFolder("new_folder");
+    File notExistingDir = new File(existingDir, "not_exist");
+
+    fs.resetDirs(existingDir, existingDir,
+      Lists.newArrayList(existingDir, notExistingDir), Lists.newArrayList(existingDir, notExistingDir), Lists.newArrayList(existingDir, notExistingDir));
+
+    assertThat(fs.baseDir().getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
+    assertThat(fs.buildDir().getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
+    assertThat(fs.sourceDirs()).hasSize(1);
+    assertThat(fs.sourceDirs().get(0).getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
+    assertThat(fs.testDirs()).hasSize(1);
+    assertThat(fs.testDirs().get(0).getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
+    assertThat(fs.binaryDirs()).hasSize(1);
+    assertThat(fs.binaryDirs().get(0).getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
+    verify(fileIndexer).index(fs);
   }
 
   @Test
-  public void should_apply_file_filters() throws IOException {
-    File basedir = new File(resourcesDir(), "main_and_test_files");
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setWorkingDir(temp.newFolder())
-      .addSourceDir(new File(basedir, "src/main/java"))
-      .addFilters(new FileFilterWrapper(FileFilterUtils.nameFileFilter("Foo.java")))
-      .setSettings(new Settings());
-
-    List<File> files = fileSystem.files(FileQuery.onSource());
-    assertThat(files).hasSize(1);
-    assertThat(files.get(0).getName()).isEqualTo("Foo.java");
-  }
+  public void should_search_input_files() throws Exception {
+    DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
 
-  static class Php extends AbstractLanguage {
-    public Php() {
-      super("php");
-    }
+    File mainFile = temp.newFile();
+    InputFile mainInput = InputFile.create(mainFile, "Main.java", ImmutableMap.of(InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE));
+    InputFile testInput = InputFile.create(temp.newFile(), "Test.java", ImmutableMap.of(InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_TEST));
 
-    public String[] getFileSuffixes() {
-      return new String[] {"php"};
-    }
-  }
+    when(fileCache.byModule("foo")).thenReturn(Lists.newArrayList(mainInput, testInput));
 
-  static class Java extends AbstractLanguage {
-    public Java() {
-      super("java");
-    }
+    Iterable<InputFile> inputFiles = fs.inputFiles(FileQuery.onSource());
+    assertThat(inputFiles).containsOnly(mainInput);
 
-    public String[] getFileSuffixes() {
-      return new String[] {"java", "jav"};
-    }
+    List<File> files = fs.files(FileQuery.onSource());
+    assertThat(files).containsOnly(mainFile);
   }
 
   @Test
-  public void test_reset_dirs() throws IOException {
-    File basedir = temp.newFolder();
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setWorkingDir(basedir)
-      .addSourceDir(new File(basedir, "src/main/java"))
-      .addFilters(new FileFilterWrapper(FileFilterUtils.nameFileFilter("Foo.java")));
-
-    File existingDir = temp.newFolder("new_folder");
-    File notExistingDir = new File(existingDir, "not_exist");
+  public void should_index() throws Exception {
+    DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);
 
-    fileSystem.resetDirs(existingDir, existingDir,
-      Arrays.asList(existingDir, notExistingDir), Arrays.asList(existingDir, notExistingDir), Arrays.asList(existingDir, notExistingDir));
-
-    assertThat(fileSystem.baseDir().getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
-    assertThat(fileSystem.buildDir().getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
-    assertThat(fileSystem.sourceDirs()).hasSize(1);
-    assertThat(fileSystem.sourceDirs().get(0).getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
-    assertThat(fileSystem.testDirs()).hasSize(1);
-    assertThat(fileSystem.testDirs().get(0).getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
-    assertThat(fileSystem.binaryDirs()).hasSize(1);
-    assertThat(fileSystem.binaryDirs().get(0).getCanonicalPath()).isEqualTo(existingDir.getCanonicalPath());
-  }
+    verifyZeroInteractions(fileIndexer);
 
-  @Test
-  public void should_throw_if_incremental_mode_and_not_in_dryrun() throws Exception {
-    File basedir = temp.newFolder();
-    Settings settings = new Settings();
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(FileHashCache.class))
-      .setBaseDir(basedir)
-      .setWorkingDir(temp.newFolder())
-      .addSourceDir(new File(basedir, "src/main/java"))
-      .setSettings(settings);
-
-    settings.setProperty(CoreProperties.INCREMENTAL_PREVIEW, true);
-
-    thrown.expect(SonarException.class);
-    thrown.expectMessage("Incremental preview is only supported with preview mode");
-    fileSystem.files(FileQuery.onSource());
+    fs.index();
+    verify(fileIndexer).index(fs);
   }
 
-  @Test
-  public void should_filter_changed_files() throws Exception {
-    File basedir = new File(resourcesDir(), "main_and_test_files");
-    Settings settings = new Settings();
-    settings.setProperty(CoreProperties.ENCODING_PROPERTY, "UTF-8");
-    File mainDir = new File(basedir, "src/main/java");
-    File testDir = new File(basedir, "src/test/java");
-    File foo = new File(mainDir, "Foo.java");
-    File hello = new File(mainDir, "Hello.java");
-    File fooTest = new File(testDir, "FooTest.java");
-    File helloTest = new File(testDir, "HelloTest.java");
-
-    FileHashCache fileHashCache = mock(FileHashCache.class);
-    when(fileHashCache.getPreviousHash(foo)).thenReturn("oldfoohash");
-    when(fileHashCache.getCurrentHash(foo, Charsets.UTF_8)).thenReturn("foohash");
-    when(fileHashCache.getPreviousHash(hello)).thenReturn("oldhellohash");
-    when(fileHashCache.getCurrentHash(hello, Charsets.UTF_8)).thenReturn("oldhellohash");
-    when(fileHashCache.getPreviousHash(fooTest)).thenReturn("oldfooTesthash");
-    when(fileHashCache.getCurrentHash(fooTest, Charsets.UTF_8)).thenReturn("fooTesthash");
-    when(fileHashCache.getPreviousHash(helloTest)).thenReturn("oldhelloTesthash");
-    when(fileHashCache.getCurrentHash(helloTest, Charsets.UTF_8)).thenReturn("oldhelloTesthash");
-
-    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(fileHashCache)
-      .setBaseDir(basedir)
-      .setWorkingDir(temp.newFolder())
-      .addSourceDir(mainDir)
-      .addTestDir(testDir)
-      .setSettings(settings);
-
-    assertThat(fileSystem.files(FileQuery.onSource())).containsOnly(foo, hello);
-    assertThat(fileSystem.files(FileQuery.onTest())).containsOnly(fooTest, helloTest);
-
-    assertThat(fileSystem.changedFiles(FileQuery.onSource())).containsExactly(foo);
-    assertThat(fileSystem.changedFiles(FileQuery.onTest())).containsExactly(fooTest);
-
-    settings.setProperty(CoreProperties.INCREMENTAL_PREVIEW, true);
-    settings.setProperty(CoreProperties.DRY_RUN, true);
-
-    assertThat(fileSystem.files(FileQuery.onSource())).containsExactly(foo);
-    assertThat(fileSystem.files(FileQuery.onTest())).containsExactly(fooTest);
-  }
+  //
+//
+//
+//  @Test
+//  public void should_exclude_dirs_starting_with_dot() throws IOException {
+//    File basedir = new File(resourcesDir(), "exclude_dir_starting_with_dot");
+//    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(RemoteFileHashes.class))
+//      .setBaseDir(basedir)
+//      .setWorkingDir(temp.newFolder())
+//      .addSourceDir(new File(basedir, "src"))
+//      .setSettings(new Settings());
+//
+//    List<File> files = fileSystem.files(FileQuery.onSource());
+//    assertThat(files).hasSize(1);
+//    assertThat(files.get(0).getName()).isEqualTo("Included.java");
+//  }
+//
+//  @Test
+//  public void should_load_source_files_by_language() throws IOException {
+//    File basedir = new File(resourcesDir(), "main_and_test_files");
+//    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(RemoteFileHashes.class))
+//      .setBaseDir(basedir)
+//      .setWorkingDir(temp.newFolder())
+//      .addSourceDir(new File(basedir, "src/main/java"))
+//      .addTestDir(new File(basedir, "src/test/java"))
+//      .setSettings(new Settings());
+//
+//    List<File> files = fileSystem.files(FileQuery.onSource().onLanguage("java"));
+//    assertThat(files).hasSize(2);
+//    for (File sourceFiles : files) {
+//      assertThat(sourceFiles).exists().isFile();
+//      assertThat(sourceFiles.getName()).isIn("Hello.java", "Foo.java");
+//    }
+//    assertThat(fileSystem.files(FileQuery.onSource().onLanguage("php"))).isEmpty();
+//  }
+//
+//  @Test
+//  public void should_load_test_files() throws IOException {
+//    File basedir = new File(resourcesDir(), "main_and_test_files");
+//    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(RemoteFileHashes.class))
+//      .setBaseDir(basedir)
+//      .setWorkingDir(temp.newFolder())
+//      .addSourceDir(new File(basedir, "src/main/java"))
+//      .addTestDir(new File(basedir, "src/test/java"))
+//      .setSettings(new Settings());
+//
+//    assertThat(fileSystem.testDirs()).hasSize(1);
+//    List<File> testFiles = fileSystem.files(FileQuery.onTest());
+//    assertThat(testFiles).hasSize(2);
+//    for (File testFile : testFiles) {
+//      assertThat(testFile).exists().isFile();
+//      assertThat(testFile.getName()).endsWith("Test.java");
+//    }
+//  }
+//
+//  @Test
+//  public void should_load_test_files_by_language() throws IOException {
+//    File basedir = new File(resourcesDir(), "main_and_test_files");
+//    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(RemoteFileHashes.class))
+//      .setBaseDir(basedir)
+//      .setWorkingDir(temp.newFolder())
+//      .addSourceDir(new File(basedir, "src/main/java"))
+//      .addTestDir(new File(basedir, "src/test/java"))
+//      .setSettings(new Settings());
+//
+//    List<File> testFiles = fileSystem.files(FileQuery.onTest().onLanguage("java"));
+//    assertThat(testFiles).hasSize(2);
+//    for (File testFile : testFiles) {
+//      assertThat(testFile).exists().isFile();
+//      assertThat(testFile.getName()).endsWith("Test.java");
+//    }
+//    assertThat(fileSystem.files(FileQuery.onTest().onLanguage("php"))).isEmpty();
+//  }
+//
+//  private File resourcesDir() {
+//    File dir = new File("test-resources/DefaultModuleFileSystemTest");
+//    if (!dir.exists()) {
+//      dir = new File("sonar-batch/test-resources/DefaultModuleFileSystemTest");
+//    }
+//    return dir;
+//  }
+//
+//  @Test
+//  public void should_apply_file_filters() throws IOException {
+//    File basedir = new File(resourcesDir(), "main_and_test_files");
+//    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(RemoteFileHashes.class))
+//      .setBaseDir(basedir)
+//      .setWorkingDir(temp.newFolder())
+//      .addSourceDir(new File(basedir, "src/main/java"))
+//      .addFilters(new FileFilterWrapper(FileFilterUtils.nameFileFilter("Foo.java")))
+//      .setSettings(new Settings());
+//
+//    List<File> files = fileSystem.files(FileQuery.onSource());
+//    assertThat(files).hasSize(1);
+//    assertThat(files.get(0).getName()).isEqualTo("Foo.java");
+//  }
+//
+//  static class Php extends AbstractLanguage {
+//    public Php() {
+//      super("php");
+//    }
+//
+//    public String[] getFileSuffixes() {
+//      return new String[] {"php"};
+//    }
+//  }
+//
+//  static class Java extends AbstractLanguage {
+//    public Java() {
+//      super("java");
+//    }
+//
+//    public String[] getFileSuffixes() {
+//      return new String[] {"java", "jav"};
+//    }
+//  }
+//
+//
+//
+//  @Test
+//  public void should_throw_if_incremental_mode_and_not_in_dryrun() throws Exception {
+//    File basedir = temp.newFolder();
+//    Settings settings = new Settings();
+//    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(mock(RemoteFileHashes.class))
+//      .setBaseDir(basedir)
+//      .setWorkingDir(temp.newFolder())
+//      .addSourceDir(new File(basedir, "src/main/java"))
+//      .setSettings(settings);
+//
+//    settings.setProperty(CoreProperties.INCREMENTAL_PREVIEW, true);
+//
+//    thrown.expect(SonarException.class);
+//    thrown.expectMessage("Incremental preview is only supported with preview mode");
+//    fileSystem.files(FileQuery.onSource());
+//  }
+//
+//  @Test
+//  public void should_filter_changed_files() throws Exception {
+//    File basedir = new File(resourcesDir(), "main_and_test_files");
+//    Settings settings = new Settings();
+//    settings.setProperty(CoreProperties.ENCODING_PROPERTY, "UTF-8");
+//    File mainDir = new File(basedir, "src/main/java");
+//    File testDir = new File(basedir, "src/test/java");
+//    File foo = new File(mainDir, "Foo.java");
+//    File hello = new File(mainDir, "Hello.java");
+//    File fooTest = new File(testDir, "FooTest.java");
+//    File helloTest = new File(testDir, "HelloTest.java");
+//
+//    RemoteFileHashes remoteFileHashes = mock(RemoteFileHashes.class);
+//    when(remoteFileHashes.getPreviousHash(foo)).thenReturn("oldfoohash");
+//    when(remoteFileHashes.getCurrentHash(foo, Charsets.UTF_8)).thenReturn("foohash");
+//    when(remoteFileHashes.getPreviousHash(hello)).thenReturn("oldhellohash");
+//    when(remoteFileHashes.getCurrentHash(hello, Charsets.UTF_8)).thenReturn("oldhellohash");
+//    when(remoteFileHashes.getPreviousHash(fooTest)).thenReturn("oldfooTesthash");
+//    when(remoteFileHashes.getCurrentHash(fooTest, Charsets.UTF_8)).thenReturn("fooTesthash");
+//    when(remoteFileHashes.getPreviousHash(helloTest)).thenReturn("oldhelloTesthash");
+//    when(remoteFileHashes.getCurrentHash(helloTest, Charsets.UTF_8)).thenReturn("oldhelloTesthash");
+//
+//    DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem(remoteFileHashes)
+//      .setBaseDir(basedir)
+//      .setWorkingDir(temp.newFolder())
+//      .addSourceDir(mainDir)
+//      .addTestDir(testDir)
+//      .setSettings(settings);
+//
+//    assertThat(fileSystem.files(FileQuery.onSource())).containsOnly(foo, hello);
+//    assertThat(fileSystem.files(FileQuery.onTest())).containsOnly(fooTest, helloTest);
+//
+//    assertThat(fileSystem.changedFiles(FileQuery.onSource())).containsExactly(foo);
+//    assertThat(fileSystem.changedFiles(FileQuery.onTest())).containsExactly(fooTest);
+//
+//    settings.setProperty(CoreProperties.INCREMENTAL_PREVIEW, true);
+//    settings.setProperty(CoreProperties.DRY_RUN, true);
+//
+//    assertThat(fileSystem.files(FileQuery.onSource())).containsExactly(foo);
+//    assertThat(fileSystem.files(FileQuery.onTest())).containsExactly(fooTest);
+//  }
 
 }
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapterTest.java
deleted file mode 100644 (file)
index 6207a13..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.mockito.Mockito;
-import org.sonar.api.resources.Project;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class DeprecatedFileSystemAdapterTest {
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Test
-  public void should_wrap_module_file_system() {
-    DefaultModuleFileSystem target = mock(DefaultModuleFileSystem.class, Mockito.RETURNS_SMART_NULLS);
-    DeprecatedFileSystemAdapter adapter = new DeprecatedFileSystemAdapter(target, new Project("my-project"));
-
-    assertThat(adapter.getBasedir()).isNotNull();
-    verify(target).baseDir();
-
-    assertThat(adapter.getSourceDirs()).isNotNull();
-    verify(target).sourceDirs();
-
-    assertThat(adapter.getTestDirs()).isNotNull();
-    verify(target).testDirs();
-
-    assertThat(adapter.getSourceCharset()).isNotNull();
-    verify(target).sourceCharset();
-
-    assertThat(adapter.getBuildDir()).isNotNull();
-    verify(target).buildDir();
-  }
-
-  @Test
-  public void should_create_default_build_dir() throws IOException {
-    File workingDir = temp.newFile("work");
-    DefaultModuleFileSystem target = mock(DefaultModuleFileSystem.class);
-    when(target.workingDir()).thenReturn(workingDir);
-    DeprecatedFileSystemAdapter adapter = new DeprecatedFileSystemAdapter(target, new Project("my-project"));
-
-    File buildDir = adapter.getBuildDir();
-    assertThat(buildDir.getParentFile().getCanonicalPath()).isEqualTo(workingDir.getCanonicalPath());
-  }
-}
index 269441d3ebb2c8d83d3649a763728b8f51e5a8b6..9272d2cf012d0423ee772b6bbeb931c7e53de53a 100644 (file)
  */
 package org.sonar.batch.scan.filesystem;
 
+import com.google.common.collect.ImmutableMap;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
+import org.sonar.api.scan.filesystem.InputFile;
 
 import java.io.File;
 import java.io.IOException;
 
 import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
 
 public class ExclusionFilterTest {
+
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
   @Test
-  public void accept() throws IOException {
-    ExclusionFilter filter = new ExclusionFilter("**/*Foo.java");
-    File file = temp.newFile();
-    FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class));
+  public void accept() throws Exception {
+    ExclusionFilter sourceRelativeFilter = new ExclusionFilter("**/*Foo.java");
+    ExclusionFilter absoluteFilter = new ExclusionFilter("file:**/src/main/**Foo.java");
 
-    context.setCanonicalPath("/absolute/path/to/MyFoo.java");
-    context.setRelativePath("relative/path/to/MyFoo.java");
-    assertThat(filter.accept(file, context)).isFalse();
+    File file = temp.newFile();
+    InputFile inputFile = InputFile.create(file, "src/main/java/org/MyFoo.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_CANONICAL_PATH, "/absolute/path/to/src/main/java/org/MyFoo.java",
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "org/MyFoo.java"
+    ));
 
-    context.setCanonicalPath("/absolute/path/to/Other.java");
-    context.setRelativePath("relative/path/to/Other.java");
+    assertThat(sourceRelativeFilter.accept(inputFile)).isFalse();
+    assertThat(absoluteFilter.accept(inputFile)).isFalse();
 
-    assertThat(filter.accept(file, context)).isTrue();
+    inputFile = InputFile.create(file, "src/main/java/org/Other.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_CANONICAL_PATH, "/absolute/path/to/src/main/java/org/Other.java",
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "org/Other.java"
+    ));
+    assertThat(sourceRelativeFilter.accept(inputFile)).isTrue();
+    assertThat(absoluteFilter.accept(inputFile)).isTrue();
   }
 
   @Test
index 0bea3c050403e1a194349139293949718e02a268..05c3d0654589dc652c9186ef43020b1a5b0ffd49 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.batch.scan.filesystem;
 
+import com.google.common.collect.ImmutableMap;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
@@ -28,15 +29,14 @@ import org.sonar.api.resources.File;
 import org.sonar.api.resources.JavaFile;
 import org.sonar.api.resources.Project;
 import org.sonar.api.scan.filesystem.FileExclusions;
-import org.sonar.api.scan.filesystem.FileType;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
+import org.sonar.api.scan.filesystem.InputFile;
 
 import java.io.IOException;
 
 import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
 
 public class ExclusionFiltersTest {
+
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
@@ -46,19 +46,26 @@ public class ExclusionFiltersTest {
     settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java");
     ExclusionFilters filter = new ExclusionFilters(new FileExclusions(settings));
 
-    FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setType(FileType.SOURCE);
-    context.setRelativePath("com/mycompany/Foo.java");
-    assertThat(filter.accept(temp.newFile(), context)).isFalse();
+    java.io.File file = temp.newFile();
+    InputFile inputFile = InputFile.create(file, "src/main/java/com/mycompany/Foo.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE,
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "com/mycompany/Foo.java"
+    ));
+
+    assertThat(filter.accept(inputFile)).isFalse();
 
-    context.setRelativePath("com/mycompany/FooDao.java");
-    assertThat(filter.accept(temp.newFile(), context)).isTrue();
+    inputFile = InputFile.create(file, "src/main/java/com/mycompany/FooDao.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE,
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "com/mycompany/FooDao.java"
+    ));
+    assertThat(filter.accept(inputFile)).isTrue();
 
     // source inclusions do not apply to tests
-    context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setType(FileType.TEST);
-    context.setRelativePath("com/mycompany/Foo.java");
-    assertThat(filter.accept(temp.newFile(), context)).isTrue();
+    inputFile = InputFile.create(file, "src/main/java/com/mycompany/Foo.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_TEST,
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "com/mycompany/Foo.java"
+    ));
+    assertThat(filter.accept(inputFile)).isTrue();
   }
 
   @Test
@@ -67,13 +74,19 @@ public class ExclusionFiltersTest {
     settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java,**/*Dto.java");
     ExclusionFilters filter = new ExclusionFilters(new FileExclusions(settings));
 
-    FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setType(FileType.SOURCE);
-    context.setRelativePath("com/mycompany/Foo.java");
-    assertThat(filter.accept(temp.newFile(), context)).isFalse();
+    java.io.File file = temp.newFile();
+    InputFile inputFile = InputFile.create(file, "src/main/java/com/mycompany/Foo.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE,
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "com/mycompany/Foo.java"
+    ));
 
-    context.setRelativePath("com/mycompany/FooDto.java");
-    assertThat(filter.accept(temp.newFile(), context)).isTrue();
+    assertThat(filter.accept(inputFile)).isFalse();
+
+    inputFile = InputFile.create(file, "src/main/java/com/mycompany/FooDto.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE,
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "com/mycompany/FooDto.java"
+    ));
+    assertThat(filter.accept(inputFile)).isTrue();
   }
 
   @Test
@@ -82,19 +95,25 @@ public class ExclusionFiltersTest {
     settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.java");
     ExclusionFilters filter = new ExclusionFilters(new FileExclusions(settings));
 
-    FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setType(FileType.SOURCE);
-    context.setRelativePath("com/mycompany/FooDao.java");
-    assertThat(filter.accept(temp.newFile(), context)).isFalse();
+    java.io.File file = temp.newFile();
+    InputFile inputFile = InputFile.create(file, "src/main/java/com/mycompany/FooDao.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE,
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "com/mycompany/FooDao.java"
+    ));
+    assertThat(filter.accept(inputFile)).isFalse();
 
-    context.setRelativePath("com/mycompany/Foo.java");
-    assertThat(filter.accept(temp.newFile(), context)).isTrue();
+    inputFile = InputFile.create(file, "src/main/java/com/mycompany/Foo.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE,
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "com/mycompany/Foo.java"
+    ));
+    assertThat(filter.accept(inputFile)).isTrue();
 
     // source exclusions do not apply to tests
-    context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setType(FileType.TEST);
-    context.setRelativePath("com/mycompany/FooDao.java");
-    assertThat(filter.accept(temp.newFile(), context)).isTrue();
+    inputFile = InputFile.create(file, "src/main/java/com/mycompany/FooDao.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_TEST,
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "com/mycompany/FooDao.java"
+    ));
+    assertThat(filter.accept(inputFile)).isTrue();
   }
 
   @Test
@@ -106,15 +125,17 @@ public class ExclusionFiltersTest {
     settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getCanonicalPath());
     ExclusionFilters filter = new ExclusionFilters(new FileExclusions(settings));
 
-    FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setType(FileType.SOURCE);
-    context.setRelativePath("org/bar/Foo.java");
-    context.setCanonicalPath(includedFile.getCanonicalPath());
-    assertThat(filter.accept(includedFile, context)).isTrue();
-
-    context.setRelativePath("org/bar/Bar.java");
-    context.setCanonicalPath(excludedFile.getCanonicalPath());
-    assertThat(filter.accept(excludedFile, context)).isFalse();
+    InputFile includedInput = InputFile.create(includedFile, "src/main/java/org/bar/Foo.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE,
+      InputFile.ATTRIBUTE_CANONICAL_PATH, includedFile.getCanonicalPath()
+    ));
+    assertThat(filter.accept(includedInput)).isTrue();
+
+    InputFile excludedInput = InputFile.create(excludedFile, "src/main/java/org/bar/Bar.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE,
+      InputFile.ATTRIBUTE_CANONICAL_PATH, excludedFile.getCanonicalPath()
+    ));
+    assertThat(filter.accept(excludedInput)).isFalse();
   }
 
   @Test
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileFilterContextTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileFilterContextTest.java
deleted file mode 100644 (file)
index aa74da4..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class FileFilterContextTest {
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Test
-  public void should_use_slash_for_canonical_path() throws IOException {
-    // even on windows
-    File file = temp.newFile("foo.txt");
-    FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setCanonicalPath(file.getCanonicalPath());
-    assertThat(context.canonicalPath()).doesNotContain("\\").contains("/");
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileFilterWrapperTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileFilterWrapperTest.java
deleted file mode 100644 (file)
index fbaeec9..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.apache.commons.io.filefilter.IOFileFilter;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.mockito.Mockito;
-import org.sonar.api.scan.filesystem.FileSystemFilter;
-
-import java.io.File;
-import java.io.IOException;
-
-public class FileFilterWrapperTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Test
-  public void should_wrap_java_io_filefilter() throws IOException {
-    IOFileFilter filter = Mockito.mock(IOFileFilter.class);
-    FileFilterWrapper wrapper = new FileFilterWrapper(filter);
-
-    File file = temp.newFile();
-    wrapper.accept(file, Mockito.mock(FileSystemFilter.Context.class));
-
-    Mockito.verify(filter).accept(file);
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashCacheTest.java
deleted file mode 100644 (file)
index 1c70890..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.base.Charsets;
-import org.apache.commons.io.FileUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
-import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.PastSnapshotFinder;
-import org.sonar.core.source.SnapshotDataType;
-import org.sonar.core.source.jdbc.SnapshotDataDao;
-import org.sonar.core.source.jdbc.SnapshotDataDto;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Date;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class FileHashCacheTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  private FileHashCache cache;
-
-  private PastSnapshotFinder pastSnapshotFinder;
-
-  private Snapshot snapshot;
-
-  private File baseDir;
-
-  private SnapshotDataDao snapshotDataDao;
-
-  private ModuleFileSystem moduleFileSystem;
-
-  @Before
-  public void prepare() throws Exception {
-    pastSnapshotFinder = mock(PastSnapshotFinder.class);
-    snapshot = mock(Snapshot.class);
-    baseDir = temp.newFolder();
-    snapshotDataDao = mock(SnapshotDataDao.class);
-    moduleFileSystem = mock(ModuleFileSystem.class);
-    cache = new FileHashCache(ProjectDefinition.create().setBaseDir(baseDir), new PathResolver(), new HashBuilder(), snapshot,
-      snapshotDataDao, pastSnapshotFinder);
-  }
-
-  @Test
-  public void should_return_null_if_no_previous_snapshot() throws Exception {
-    when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(new PastSnapshot("foo"));
-
-    cache.start();
-    assertThat(cache.getPreviousHash(new File(baseDir, "src/main/java/foo/Bar.java"))).isNull();
-  }
-
-  @Test
-  public void should_return_null_if_no_previous_snapshot_data() throws Exception {
-    Snapshot previousSnapshot = mock(Snapshot.class);
-    PastSnapshot pastSnapshot = new PastSnapshot("foo", new Date(), previousSnapshot);
-    when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(pastSnapshot);
-
-    cache.start();
-    assertThat(cache.getPreviousHash(new File(baseDir, "src/main/java/foo/Bar.java"))).isNull();
-  }
-
-  @Test
-  public void should_return_previous_hash() throws Exception {
-    Snapshot previousSnapshot = mock(Snapshot.class);
-    when(previousSnapshot.getId()).thenReturn(123);
-    PastSnapshot pastSnapshot = new PastSnapshot("foo", new Date(), previousSnapshot);
-    when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(pastSnapshot);
-
-    SnapshotDataDto snapshotDataDto = new SnapshotDataDto();
-    snapshotDataDto.setData("src/main/java/foo/Bar.java=abcd1234\n");
-    when(snapshotDataDao.selectSnapshotData(123, Arrays.asList(SnapshotDataType.FILE_HASH.getValue())))
-      .thenReturn(Arrays.asList(snapshotDataDto));
-
-    File file = new File(baseDir, "src/main/java/foo/Bar.java");
-    FileUtils.write(file, "foo", Charsets.UTF_8);
-    cache.start();
-    assertThat(cache.getPreviousHash(file)).isEqualTo("abcd1234");
-  }
-
-  @Test
-  public void should_compute_and_cache_current_hash() throws Exception {
-    when(moduleFileSystem.sourceCharset()).thenReturn(Charsets.UTF_8);
-
-    File file = new File(baseDir, "src/main/java/foo/Bar.java");
-    FileUtils.write(file, "foo", Charsets.UTF_8);
-    String hash = "9a8742076ef9ffa5591f633704c2286b";
-    assertThat(cache.getCurrentHash(file, Charsets.UTF_8)).isEqualTo(hash);
-
-    // Modify file
-    FileUtils.write(file, "bar", Charsets.UTF_8);
-    assertThat(cache.getCurrentHash(file, Charsets.UTF_8)).isEqualTo(hash);
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashDigestTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashDigestTest.java
new file mode 100644 (file)
index 0000000..c3345c2
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.base.Charsets;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class FileHashDigestTest {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @Test
+  public void should_compute_hash() throws Exception {
+    File tempFile = temp.newFile();
+    FileUtils.write(tempFile, "foo\r\nbar", Charsets.UTF_8, true);
+
+    assertThat(FileHashDigest.INSTANCE.hash(tempFile, Charsets.UTF_8)).isEqualTo("daef8a22a3f12580beadf086a9e11519");
+  }
+
+  @Test
+  public void should_normalize_line_ends() throws Exception {
+    File file1 = temp.newFile();
+    FileUtils.write(file1, "foobar\nfofo", Charsets.UTF_8);
+    String hash1 = FileHashDigest.INSTANCE.hash(file1, Charsets.UTF_8);
+
+    File file2 = temp.newFile();
+    FileUtils.write(file2, "foobar\r\nfofo", Charsets.UTF_8);
+    String hash2 = FileHashDigest.INSTANCE.hash(file2, Charsets.UTF_8);
+
+    File file3 = temp.newFile();
+    FileUtils.write(file3, "foobar\rfofo", Charsets.UTF_8);
+    String hash3 = FileHashDigest.INSTANCE.hash(file3, Charsets.UTF_8);
+
+    File file4 = temp.newFile();
+    FileUtils.write(file4, "foobar\nfofo\n", Charsets.UTF_8);
+    String hash4 = FileHashDigest.INSTANCE.hash(file4, Charsets.UTF_8);
+
+    assertThat(hash1).isEqualTo(hash2);
+    assertThat(hash1).isEqualTo(hash3);
+    assertThat(hash1).isNotEqualTo(hash4);
+  }
+
+  @Test
+  public void should_throw_if_file_does_not_exist() throws Exception {
+    File tempFolder = temp.newFolder();
+    File file = new File(tempFolder, "doesNotExist.txt");
+
+    thrown.expect(IllegalStateException.class);
+    thrown.expectMessage("Fail to compute hash of file " + file.getAbsolutePath() + " with charset UTF-8");
+
+    FileHashDigest.INSTANCE.hash(file, Charsets.UTF_8);
+  }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashesTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileHashesTest.java
new file mode 100644 (file)
index 0000000..98ae99d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.nio.charset.Charset;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+public class FileHashesTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  RemoteFileHashes remoteFileHashes = mock(RemoteFileHashes.class);
+
+  @Test
+  public void hash() throws Exception {
+    File file = temp.newFile();
+    FileUtils.write(file, "fooo");
+
+    FileHashes hashes = new FileHashes(remoteFileHashes);
+    assertThat(hashes.hash(file, Charset.forName("UTF-8"))).isEqualTo("efc4470c96a94b1ff400175ef8368444");
+    verifyZeroInteractions(remoteFileHashes);
+  }
+
+  @Test
+  public void remote_hash() throws Exception {
+    String path = "src/main/java/Foo.java";
+    when(remoteFileHashes.remoteHash(path)).thenReturn("ABCDE");
+
+    FileHashes hashes = new FileHashes(remoteFileHashes);
+    assertThat(hashes.remoteHash(path)).isEqualTo("ABCDE");
+  }
+}
index 19f2ae4c62dfaed50bd6b72f87f7ce64c9409a4d..f218d0bba4a6b1fd09c13b89e5f6eb04ce8bc163 100644 (file)
@@ -38,11 +38,10 @@ public class FileSystemLoggerTest {
 
   @Test
   public void log() {
-    DefaultModuleFileSystem fs = new DefaultModuleFileSystem(mock(FileHashCache.class));
+    DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", mock(Settings.class), mock(InputFileCache.class), mock(FileIndexer.class));
     File src = temp.newFolder("src");
     File test = temp.newFolder("test");
     File base = temp.newFolder("base");
-    fs.setSettings(new Settings());
     fs.setBaseDir(base);
     fs.addSourceDir(src);
     fs.addTestDir(test);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/HashBuilderTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/HashBuilderTest.java
deleted file mode 100644 (file)
index f15876f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.base.Charsets;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.utils.SonarException;
-
-import java.io.File;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class HashBuilderTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-  private HashBuilder hashBuilder = new HashBuilder();
-
-  @Test
-  public void should_compute_hash() throws Exception {
-    File tempFile = temp.newFile();
-    FileUtils.write(tempFile, "foo\r\nbar", Charsets.UTF_8, true);
-
-    assertThat(hashBuilder.computeHashNormalizeLineEnds(tempFile, Charsets.UTF_8)).isEqualTo("daef8a22a3f12580beadf086a9e11519");
-  }
-
-  @Test
-  public void should_normalize_line_ends() throws Exception {
-    File file1 = temp.newFile();
-    FileUtils.write(file1, "foobar\nfofo", Charsets.UTF_8);
-    String hash1 = hashBuilder.computeHashNormalizeLineEnds(file1, Charsets.UTF_8);
-
-    File file2 = temp.newFile();
-    FileUtils.write(file2, "foobar\r\nfofo", Charsets.UTF_8);
-    String hash2 = hashBuilder.computeHashNormalizeLineEnds(file2, Charsets.UTF_8);
-
-    File file3 = temp.newFile();
-    FileUtils.write(file3, "foobar\rfofo", Charsets.UTF_8);
-    String hash3 = hashBuilder.computeHashNormalizeLineEnds(file3, Charsets.UTF_8);
-
-    File file4 = temp.newFile();
-    FileUtils.write(file4, "foobar\nfofo\n", Charsets.UTF_8);
-    String hash4 = hashBuilder.computeHashNormalizeLineEnds(file4, Charsets.UTF_8);
-
-    assertThat(hash1).isEqualTo(hash2);
-    assertThat(hash1).isEqualTo(hash3);
-    assertThat(hash1).isNotEqualTo(hash4);
-  }
-
-  @Test(expected = SonarException.class)
-  public void should_throw_on_not_existing_file() throws Exception {
-    File tempFolder = temp.newFolder();
-    hashBuilder.computeHashNormalizeLineEnds(new File(tempFolder, "unknowFile.txt"), Charsets.UTF_8);
-  }
-}
index 8333c6c228606a433685e82602aad39f5705be69..38f391fa8cecac90e8fa935f6cc05e4c50ebb908 100644 (file)
  */
 package org.sonar.batch.scan.filesystem;
 
+import com.google.common.collect.ImmutableMap;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
+import org.sonar.api.scan.filesystem.InputFile;
 
 import java.io.File;
-import java.io.IOException;
 
 import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
 
 public class InclusionFilterTest {
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
   @Test
-  public void accept() throws IOException {
-    InclusionFilter filter = new InclusionFilter("**/*Foo.java");
-    File file = temp.newFile();
-    FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class));
+  public void accept() throws Exception {
+    InclusionFilter sourceRelativeFilter = new InclusionFilter("**/*Foo.java");
+    InclusionFilter absoluteFilter = new InclusionFilter("file:**/src/main/**Foo.java");
 
-    context.setCanonicalPath("/absolute/path/to/MyFoo.java");
-    context.setRelativePath("relative/path/to/MyFoo.java");
-    assertThat(filter.accept(file, context)).isTrue();
 
-    context.setCanonicalPath("/absolute/path/to/Other.java");
-    context.setRelativePath("relative/path/to/Other.java");
+    File file = temp.newFile();
+    InputFile inputFile = InputFile.create(file, "src/main/java/org/MyFoo.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_CANONICAL_PATH, "/absolute/path/to/src/main/java/org/MyFoo.java",
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "org/MyFoo.java"
+    ));
+
+    assertThat(sourceRelativeFilter.accept(inputFile)).isTrue();
+    assertThat(absoluteFilter.accept(inputFile)).isTrue();
 
-    assertThat(filter.accept(file, context)).isFalse();
+    inputFile = InputFile.create(file, "src/main/java/org/Other.java", ImmutableMap.of(
+      InputFile.ATTRIBUTE_CANONICAL_PATH, "/absolute/path/to/src/main/java/org/Other.java",
+      InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "org/Other.java"
+    ));
+    assertThat(sourceRelativeFilter.accept(inputFile)).isFalse();
+    assertThat(absoluteFilter.accept(inputFile)).isFalse();
   }
 
   @Test
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputFileCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputFileCacheTest.java
new file mode 100644 (file)
index 0000000..25b82b8
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.Maps;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.batch.index.Caches;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class InputFileCacheTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  Caches caches = new Caches();
+
+  @Before
+  public void start() {
+    caches.start();
+  }
+
+  @After
+  public void stop() {
+    caches.stop();
+  }
+
+  @Test
+  public void should_add_input_file() throws Exception {
+    InputFileCache cache = new InputFileCache(caches);
+    cache.put("struts", InputFile.create(temp.newFile(), "src/main/java/Foo.java", Maps.<String, String>newHashMap()));
+    cache.put("struts-core", InputFile.create(temp.newFile(), "src/main/java/Foo.java", Maps.<String, String>newHashMap()));
+
+    assertThat(cache.byModule("struts")).hasSize(1);
+    assertThat(cache.byModule("struts-core")).hasSize(1);
+    assertThat(cache.all()).hasSize(2);
+
+    cache.removeModule("struts");
+    assertThat(cache.byModule("struts")).hasSize(0);
+    assertThat(cache.byModule("struts-core")).hasSize(1);
+    assertThat(cache.all()).hasSize(1);
+  }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageFiltersTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageFiltersTest.java
deleted file mode 100644 (file)
index 7e09c3d..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.apache.commons.io.filefilter.FalseFileFilter;
-import org.apache.commons.io.filefilter.IOFileFilter;
-import org.apache.commons.io.filefilter.SuffixFileFilter;
-import org.apache.commons.io.filefilter.TrueFileFilter;
-import org.junit.Test;
-import org.sonar.api.resources.AbstractLanguage;
-import org.sonar.api.resources.Languages;
-
-import java.lang.reflect.Field;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class LanguageFiltersTest {
-  @Test
-  public void forLang() throws Exception {
-    LanguageFilters filters = new LanguageFilters(new Languages(new Java(), new Php()));
-
-    IOFileFilter filter = filters.forLang("php");
-    assertThat(filter).isInstanceOf(SuffixFileFilter.class);
-    assertThat(suffixes((SuffixFileFilter) filter)).containsOnly("php");
-
-    filter = filters.forLang("java");
-    assertThat(filter).isInstanceOf(SuffixFileFilter.class);
-    assertThat(suffixes((SuffixFileFilter) filter)).containsOnly("java", "jav");
-
-    assertThat(filters.forLang("unknown")).isSameAs(FalseFileFilter.FALSE);
-  }
-
-  private String[] suffixes(SuffixFileFilter filter) throws Exception {
-    Field privateField = SuffixFileFilter.class.getDeclaredField("suffixes");
-    privateField.setAccessible(true);
-
-    return (String[]) privateField.get(filter);
-  }
-
-  static class Php extends AbstractLanguage {
-    public Php() {
-      super("php");
-    }
-
-    public String[] getFileSuffixes() {
-      return new String[]{"php"};
-    }
-  }
-
-  static class Java extends AbstractLanguage {
-    public Java() {
-      super("java");
-    }
-
-    public String[] getFileSuffixes() {
-      return new String[]{"java", "jav"};
-    }
-  }
-}
index 600fa6a4aac19c182582c552c6328fbab163a39e..d2aa69e6dc1fadbb766109c4efe95e88e290f292 100644 (file)
@@ -25,13 +25,12 @@ import org.apache.commons.io.FilenameUtils;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.config.Settings;
 import org.sonar.api.scan.filesystem.FileQuery;
-import org.sonar.api.scan.filesystem.FileSystemFilter;
 import org.sonar.api.scan.filesystem.ModuleFileSystem;
-import org.sonar.api.scan.filesystem.PathResolver;
 import org.sonar.batch.bootstrap.TempDirectories;
 
 import java.io.File;
@@ -45,6 +44,10 @@ public class ModuleFileSystemProviderTest {
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
+  InputFileCache fileCache = mock(InputFileCache.class, Mockito.RETURNS_DEEP_STUBS);
+  Settings settings = new Settings();
+  FileIndexer fileIndexer = mock(FileIndexer.class, Mockito.RETURNS_DEEP_STUBS);
+
   @Test
   public void test_provide() throws IOException {
     ModuleFileSystemProvider provider = new ModuleFileSystemProvider();
@@ -53,8 +56,7 @@ public class ModuleFileSystemProviderTest {
     ProjectDefinition module = ProjectDefinition.create()
       .setBaseDir(baseDir)
       .setWorkDir(workDir);
-    ModuleFileSystem fs = provider.provide(module, new PathResolver(), new TempDirectories(), mock(LanguageFilters.class),
-      new Settings(), new FileSystemFilter[0], mock(FileHashCache.class));
+    ModuleFileSystem fs = provider.provide(module, new TempDirectories(), settings, fileCache, fileIndexer);
 
     assertThat(fs).isNotNull();
     assertThat(fs.baseDir().getCanonicalPath()).isEqualTo(baseDir.getCanonicalPath());
@@ -69,8 +71,8 @@ public class ModuleFileSystemProviderTest {
   public void default_charset_is_platform_dependent() throws IOException {
     ModuleFileSystemProvider provider = new ModuleFileSystemProvider();
 
-    ModuleFileSystem fs = provider.provide(newSimpleModule(), new PathResolver(), new TempDirectories(), mock(LanguageFilters.class),
-      new Settings(), new FileSystemFilter[0], mock(FileHashCache.class));
+    ModuleFileSystem fs = provider.provide(newSimpleModule(), new TempDirectories(),
+      new Settings(), mock(InputFileCache.class), mock(FileIndexer.class));
 
     assertThat(fs.sourceCharset()).isEqualTo(Charset.defaultCharset());
   }
@@ -82,8 +84,8 @@ public class ModuleFileSystemProviderTest {
     Settings settings = new Settings();
     settings.setProperty(CoreProperties.ENCODING_PROPERTY, Charsets.ISO_8859_1.name());
 
-    ModuleFileSystem fs = provider.provide(module, new PathResolver(), new TempDirectories(), mock(LanguageFilters.class),
-      settings, new FileSystemFilter[0], mock(FileHashCache.class));
+    ModuleFileSystem fs = provider.provide(module, new TempDirectories(),
+      settings, mock(InputFileCache.class), mock(FileIndexer.class));
 
     assertThat(fs.sourceCharset()).isEqualTo(Charsets.ISO_8859_1);
   }
@@ -108,8 +110,8 @@ public class ModuleFileSystemProviderTest {
       .addTestDirs("src/test/java", "src/test/unknown")
       .addBinaryDir("target/classes");
 
-    ModuleFileSystem fs = provider.provide(project, new PathResolver(), new TempDirectories(), mock(LanguageFilters.class),
-      new Settings(), new FileSystemFilter[0], mock(FileHashCache.class));
+    ModuleFileSystem fs = provider.provide(project, new TempDirectories(),
+      new Settings(), mock(InputFileCache.class), mock(FileIndexer.class));
 
     assertThat(fs.baseDir().getCanonicalPath()).isEqualTo(baseDir.getCanonicalPath());
     assertThat(fs.buildDir().getCanonicalPath()).isEqualTo(buildDir.getCanonicalPath());
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ProjectFileSystemAdapterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ProjectFileSystemAdapterTest.java
new file mode 100644 (file)
index 0000000..0bdb33e
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
+import org.sonar.api.resources.Project;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+public class ProjectFileSystemAdapterTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @Test
+  public void should_wrap_module_file_system() {
+    DefaultModuleFileSystem target = mock(DefaultModuleFileSystem.class, Mockito.RETURNS_SMART_NULLS);
+    ProjectFileSystemAdapter adapter = new ProjectFileSystemAdapter(target, new Project("my-project"));
+
+    assertThat(adapter.getBasedir()).isNotNull();
+    verify(target).baseDir();
+
+    assertThat(adapter.getSourceDirs()).isNotNull();
+    verify(target).sourceDirs();
+
+    assertThat(adapter.getTestDirs()).isNotNull();
+    verify(target).testDirs();
+
+    assertThat(adapter.getSourceCharset()).isNotNull();
+    verify(target).sourceCharset();
+
+    assertThat(adapter.getBuildDir()).isNotNull();
+    verify(target).buildDir();
+  }
+
+  @Test
+  public void should_create_default_build_dir() throws IOException {
+    File workingDir = temp.newFile("work");
+    DefaultModuleFileSystem target = mock(DefaultModuleFileSystem.class);
+    when(target.workingDir()).thenReturn(workingDir);
+    ProjectFileSystemAdapter adapter = new ProjectFileSystemAdapter(target, new Project("my-project"));
+
+    File buildDir = adapter.getBuildDir();
+    assertThat(buildDir.getParentFile().getCanonicalPath()).isEqualTo(workingDir.getCanonicalPath());
+  }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/RemoteFileHashesTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/RemoteFileHashesTest.java
new file mode 100644 (file)
index 0000000..91b2f5e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.batch.components.PastSnapshot;
+import org.sonar.batch.components.PastSnapshotFinder;
+import org.sonar.core.source.SnapshotDataType;
+import org.sonar.core.source.jdbc.SnapshotDataDao;
+import org.sonar.core.source.jdbc.SnapshotDataDto;
+
+import java.util.Arrays;
+import java.util.Date;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class RemoteFileHashesTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  PastSnapshotFinder pastSnapshotFinder = mock(PastSnapshotFinder.class);
+  Snapshot snapshot = mock(Snapshot.class);
+  SnapshotDataDao snapshotDataDao = mock(SnapshotDataDao.class);
+  RemoteFileHashes hashes = new RemoteFileHashes(snapshot, snapshotDataDao, pastSnapshotFinder);
+
+  @Test
+  public void should_return_null_if_no_remote_snapshot() throws Exception {
+    when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(new PastSnapshot("foo"));
+
+    hashes.start();
+    assertThat(hashes.remoteHash("src/main/java/foo/Bar.java")).isNull();
+    hashes.stop();
+  }
+
+  @Test
+  public void should_return_null_if_no_remote_hashes() throws Exception {
+    Snapshot previousSnapshot = mock(Snapshot.class);
+    PastSnapshot pastSnapshot = new PastSnapshot("foo", new Date(), previousSnapshot);
+    when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(pastSnapshot);
+
+    hashes.start();
+    assertThat(hashes.remoteHash("src/main/java/foo/Bar.java")).isNull();
+    hashes.stop();
+  }
+
+  @Test
+  public void should_return_remote_hash() throws Exception {
+    Snapshot previousSnapshot = mock(Snapshot.class);
+    when(previousSnapshot.getId()).thenReturn(123);
+    PastSnapshot pastSnapshot = new PastSnapshot("foo", new Date(), previousSnapshot);
+    when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(pastSnapshot);
+
+    SnapshotDataDto snapshotDataDto = new SnapshotDataDto();
+    snapshotDataDto.setData("src/main/java/foo/Bar.java=abcd1234");
+    when(snapshotDataDao.selectSnapshotData(123, Arrays.asList(SnapshotDataType.FILE_HASH.getValue())))
+      .thenReturn(Arrays.asList(snapshotDataDto));
+
+    hashes.start();
+    assertThat(hashes.remoteHash("src/main/java/foo/Bar.java")).isEqualTo("abcd1234");
+    hashes.stop();
+  }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/WhiteListFileFilterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/WhiteListFileFilterTest.java
deleted file mode 100644 (file)
index 7d337a6..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.collect.Sets;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.scan.filesystem.FileType;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class WhiteListFileFilterTest {
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Test
-  public void should_accept() throws IOException {
-    WhiteListFileFilter filter = new WhiteListFileFilter(FileType.SOURCE, Sets.newHashSet(
-      new File("Foo.java"),
-      new File("Bar.java")
-    ));
-
-    FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setType(FileType.SOURCE);
-    assertThat(filter.accept(new File("Foo.java"), context)).isTrue();
-    assertThat(filter.accept(new File("Other.java"), context)).isFalse();
-
-    context = new FileFilterContext(mock(ModuleFileSystem.class));
-    context.setType(FileType.TEST);
-    assertThat(filter.accept(new File("Foo.java"), context)).isTrue();
-    assertThat(filter.accept(new File("Other.java"), context)).isTrue();
-  }
-
-  @Test
-    public void test_toString() throws IOException {
-      WhiteListFileFilter filter = new WhiteListFileFilter(FileType.SOURCE, Sets.newHashSet(
-        new File("Foo.java"),
-        new File("Bar.java")
-      ));
-
-      assertThat(filter.toString())
-        .contains("Source files:")
-        .contains("Foo.java")
-        .contains("Bar.java");
-    }
-}
index b45eb9d32affdca4d58aeebd619532ed5a63c34e..52fddd558cd8c671d686a7634b5287db4c2ec967 100644 (file)
@@ -24,7 +24,7 @@ public enum SnapshotDataType {
 
   SYNTAX_HIGHLIGHTING("highlight_syntax"),
   SYMBOL_HIGHLIGHTING("symbol"),
-  FILE_HASH("hash");
+  FILE_HASH("file_hash");
 
   private SnapshotDataType(String value) {
     this.value = value;
index 79c5461b89264428d6dbfe165c6862c96ef851de..e5389e962774358f60bbc872ae9bbe21bbe129fb 100644 (file)
@@ -54,7 +54,7 @@ public class DryRunDatabaseFactoryTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void should_create_database_without_project() throws IOException, SQLException {
+  public void should_create_database_without_project() throws Exception {
     setupData("should_create_database");
 
     byte[] db = createDb(null);
@@ -71,7 +71,7 @@ public class DryRunDatabaseFactoryTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void should_create_database_with_project() throws IOException, SQLException {
+  public void should_create_database_with_project() throws Exception {
     setupData("should_create_database");
 
     byte[] database = createDb(123L);
@@ -85,7 +85,7 @@ public class DryRunDatabaseFactoryTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void should_create_database_with_issues() throws IOException, SQLException {
+  public void should_create_database_with_issues() throws Exception {
     setupData("should_create_database_with_issues");
 
     byte[] database = createDb(399L);
@@ -95,7 +95,7 @@ public class DryRunDatabaseFactoryTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void should_export_issues_of_project_tree() throws IOException, SQLException {
+  public void should_export_issues_of_project_tree() throws Exception {
     setupData("multi-modules-with-issues");
 
     // 300 : root module -> export issues of all modules
@@ -109,7 +109,7 @@ public class DryRunDatabaseFactoryTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void should_export_issues_of_sub_module() throws IOException, SQLException {
+  public void should_export_issues_of_sub_module() throws Exception {
     setupData("multi-modules-with-issues");
 
     // 301 : sub module with 1 closed issue and 1 open issue
@@ -122,7 +122,7 @@ public class DryRunDatabaseFactoryTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void should_export_issues_of_sub_module_2() throws IOException, SQLException {
+  public void should_export_issues_of_sub_module_2() throws Exception {
     setupData("multi-modules-with-issues");
 
     // 302 : sub module without any issues
index 8584e22b07be4fac9e4d2d725986460c95b74725..d33cd146ea4088a4c6257ba35f97aaf093afb354 100644 (file)
@@ -25,7 +25,9 @@ import java.io.InputStream;
 
 /**
  * @since 2.6
+ * @deprecated in 4.0. Replaced by {@link org.sonar.api.scan.filesystem.InputFile}
  */
+@Deprecated
 public interface InputFile {
   /**
    * The source base directory, different than the project basedir.
index 576d2c18ceceac85dcc8d7d8a7d3f012467cfe02..9e018844b19cb932518f304d8bcdeff1da99a5b5 100644 (file)
@@ -34,7 +34,9 @@ import java.util.List;
 
 /**
  * @since 2.8
+ * @deprecated in 4.0. Replaced by {@link org.sonar.api.scan.filesystem.InputFile}.
  */
+@Deprecated
 public final class InputFileUtils {
 
   private InputFileUtils() {
index e69b13e92fa0130073a583a34478002bfb9dd7e9..3135b7c27cf9bde3b865ce1a0f520641a3967852 100644 (file)
  */
 package org.sonar.api.scan.filesystem;
 
-import com.google.common.collect.Lists;
+import com.google.common.base.Function;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Sets;
 
+import javax.annotation.Nullable;
 import java.io.FileFilter;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -32,8 +37,14 @@ import java.util.Set;
  */
 public class FileQuery {
 
+  // TODO better builders, for example FileQuery.ALL
+
   public static FileQuery on(FileType... types) {
-    return new FileQuery(types);
+    FileQuery query = new FileQuery();
+    for (FileType type : types) {
+      query.on(InputFile.ATTRIBUTE_TYPE, type.name().toLowerCase());
+    }
+    return query;
   }
 
   public static FileQuery onSource() {
@@ -44,27 +55,40 @@ public class FileQuery {
     return on(FileType.TEST);
   }
 
-  private final Set<FileType> types;
-  private final Set<String> languages = Sets.newLinkedHashSet();
-  private final Set<String> inclusions = Sets.newLinkedHashSet();
-  private final Set<String> exclusions = Sets.newLinkedHashSet();
-  private final Collection<FileFilter> filters = Lists.newLinkedList();
+  private final ListMultimap<String, String> attributes = ArrayListMultimap.create();
+  private final Set<String> inclusions = Sets.newHashSet();
+  private final Set<String> exclusions = Sets.newHashSet();
+
+  private FileQuery() {
+  }
+
+  private FileQuery on(String attribute, String... values) {
+    for (String value : values) {
+      attributes.put(attribute, value);
+    }
+    return this;
+  }
 
-  private FileQuery(FileType... types) {
-    this.types = Sets.newHashSet(types);
+  public Map<String, Collection<String>> attributes() {
+    return attributes.asMap();
   }
 
+  @Deprecated
   public Collection<FileType> types() {
-    return types;
+    return Collections2.transform(attributes.get(InputFile.ATTRIBUTE_TYPE), new Function<String, FileType>() {
+      @Override
+      public FileType apply(@Nullable String input) {
+        return input != null ? FileType.valueOf(input) : null;
+      }
+    });
   }
 
   public Collection<String> languages() {
-    return languages;
+    return attributes.get(InputFile.ATTRIBUTE_LANGUAGE);
   }
 
   public FileQuery onLanguage(String... languages) {
-    this.languages.addAll(Arrays.asList(languages));
-    return this;
+    return on(InputFile.ATTRIBUTE_LANGUAGE, languages);
   }
 
   public Collection<String> inclusions() {
@@ -85,13 +109,14 @@ public class FileQuery {
     return this;
   }
 
+  // TODO deprecate
   public Collection<FileFilter> filters() {
-    return filters;
+    throw new UnsupportedOperationException("TODO");
   }
 
+  // TODO deprecate ?
   public FileQuery withFilters(FileFilter... filters) {
-    this.filters.addAll(Arrays.asList(filters));
-    return this;
+    throw new UnsupportedOperationException("TODO");
   }
 }
 
index 7d03441df56132ef3bd382c9ea0a802a33569fcd..3a215937d23c7b3a64e162443c5a887da7236535 100644 (file)
@@ -30,7 +30,9 @@ import java.io.File;
  *   <li>exclude the files which names start with Generated</li>
  * </ul>
  * @since 3.5
+ * @deprecated in 4.0. Replaced by {@link InputFileFilter}.
  */
+@Deprecated
 public interface FileSystemFilter extends BatchExtension {
 
   /**
index 6600ae2099a6b223df6b9541311eaee1b234cafb..31f3938da22a4535477486a7bc567bc915c53389 100644 (file)
@@ -21,7 +21,9 @@ package org.sonar.api.scan.filesystem;
 
 /**
  * @since 3.5
+ * @deprecated in 4.0. Replaced by more flexible {@link InputFile} attributes.
  */
+@Deprecated
 public enum FileType {
   SOURCE, TEST
 }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java
new file mode 100644 (file)
index 0000000..c28298e
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.api.scan.filesystem;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.lang.StringUtils;
+
+import javax.annotation.CheckForNull;
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @since 4.0
+ */
+public class InputFile implements Serializable {
+
+  // TODO refactor attribute constants as classes or enums ?
+
+  /**
+   * Path relative to module base directory.
+   */
+  public static final String ATTRIBUTE_BASE_RELATIVE_PATH = "baseRelPath";
+
+  // TODO ambiguity of term "source" with sourceDir versus testDir properties
+  // Here it does not depend on type.
+  public static final String ATTRIBUTE_SOURCEDIR_PATH = "srcDirPath";
+  public static final String ATTRIBUTE_SOURCE_RELATIVE_PATH = "srcRelPath";
+
+  public static final String ATTRIBUTE_CANONICAL_PATH = "canonicalPath";
+  public static final String ATTRIBUTE_LANGUAGE = "lang";
+  public static final String ATTRIBUTE_TYPE = "type";
+  public static final String ATTRIBUTE_STATUS = "status";
+  public static final String STATUS_SAME = "same";
+  public static final String STATUS_CHANGED = "changed";
+  public static final String STATUS_ADDED = "added";
+  public static final String ATTRIBUTE_HASH = "checksum";
+  public static final String ATTRIBUTE_EXTENSION = "extension";
+  public static final String TYPE_SOURCE = "source";
+  public static final String TYPE_TEST = "test";
+
+  // TODO limitation of persistit -> add unit test
+  private transient File transientFile;
+  private Map<String, String> attributes;
+
+  private InputFile(File file, Map<String, String> attributes) {
+    this.transientFile = file;
+    this.attributes = attributes;
+  }
+
+  /**
+   * Plugins should not build their own instances of {@link InputFile}. This method
+   * aims to be used by unit tests.
+   * // TODO provide builder ?
+   */
+  public static InputFile create(File file, String baseRelativePath, Map<String, String> attributes) {
+    Map<String,String> copy = Maps.newHashMap(attributes);
+    copy.put(InputFile.ATTRIBUTE_BASE_RELATIVE_PATH, baseRelativePath);
+    return new InputFile(file, copy);
+  }
+
+  /**
+   * Path from module base directory. Path is unique and identifies file within given
+   * <code>{@link ModuleFileSystem}</code>. File separator is the forward slash ('/'),
+   * even on MSWindows.
+   */
+  public String path() {
+    return attribute(ATTRIBUTE_BASE_RELATIVE_PATH);
+  }
+
+  public File file() {
+    if (transientFile == null) {
+      transientFile = new File(attribute(ATTRIBUTE_CANONICAL_PATH));
+    }
+    return transientFile;
+  }
+
+  public String name() {
+    return file().getName();
+  }
+
+  public boolean has(String attribute, String value) {
+    return StringUtils.equals(attributes.get(attribute), value);
+  }
+
+  @CheckForNull
+  public String attribute(String key) {
+    return attributes.get(key);
+  }
+
+  public Map<String, String> attributes() {
+    return attributes;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    InputFile inputFile = (InputFile) o;
+    return attribute(ATTRIBUTE_CANONICAL_PATH).equals(inputFile.attribute(ATTRIBUTE_CANONICAL_PATH));
+  }
+
+  @Override
+  public int hashCode() {
+    return path().hashCode();
+  }
+
+  public static List<File> toFiles(Iterable<InputFile> inputFiles) {
+    List<File> files = Lists.newArrayList();
+    for (InputFile inputFile : inputFiles) {
+      files.add(inputFile.file());
+    }
+    return files;
+  }
+
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFileFilter.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFileFilter.java
new file mode 100644 (file)
index 0000000..2b16682
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.api.scan.filesystem;
+
+import org.sonar.api.BatchExtension;
+
+/**
+ * TODO document lifecycle -> executed when initializing project
+ * @since 4.0
+ */
+public interface InputFileFilter extends BatchExtension {
+
+  boolean accept(InputFile inputFile);
+
+}
index 31882d0ac28e6df6e3eaecc6f665ff78a61f822b..f8c8257141f4e739590824e6226047103862973c 100644 (file)
@@ -20,9 +20,9 @@
 package org.sonar.api.scan.filesystem;
 
 import org.sonar.api.BatchComponent;
+import org.sonar.api.resources.InputFile;
 
 import javax.annotation.CheckForNull;
-
 import java.io.File;
 import java.nio.charset.Charset;
 import java.util.List;
@@ -31,6 +31,14 @@ import java.util.List;
  * @since 3.5
  */
 public interface ModuleFileSystem extends BatchComponent {
+
+  /**
+   * Unique module key
+   *
+   * @since 4.0
+   */
+  String moduleKey();
+
   /**
    * Base directory.
    */
@@ -47,12 +55,14 @@ public interface ModuleFileSystem extends BatchComponent {
    * Source directories. Non-existing directories are excluded.
    * Example in Maven : ${project.basedir}/src/main/java
    */
+  // TODO mark as dangerous to use
   List<File> sourceDirs();
 
   /**
    * Test directories. Non-existing directories are excluded.
    * Example in Maven : ${project.basedir}/src/test/java
    */
+  // TODO mark as dangerous to use
   List<File> testDirs();
 
   /**
@@ -71,12 +81,6 @@ public interface ModuleFileSystem extends BatchComponent {
    */
   List<File> files(FileQuery query);
 
-  /**
-   * Search for changed files. Never return null.
-   * @since 4.0
-   */
-  List<File> changedFiles(FileQuery query);
-
   /**
    * Charset of source and test files. If it's not defined, then return the platform default charset.
    */
index 48bb0a3fcb0e46fce4d2efdbe6ba56fbd3e15a7d..4d821c0bf8e866aeaa3627940825af408cfed3e7 100644 (file)
@@ -42,6 +42,11 @@ public class SimpleModuleFileSystem implements ModuleFileSystem {
     this.buildDir = new File(baseDir, "build");
   }
 
+  @Override
+  public String moduleKey() {
+    return null;
+  }
+
   public File baseDir() {
     return baseDir;
   }
@@ -81,11 +86,6 @@ public class SimpleModuleFileSystem implements ModuleFileSystem {
     return Collections.emptyList();
   }
 
-  @Override
-  public List<File> changedFiles(FileQuery query) {
-    return Collections.emptyList();
-  }
-
   public Charset sourceCharset() {
     return Charset.forName(CharEncoding.UTF_8);
   }