]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5389 Add InputDir concept in batch API
authorJulien HENRY <julien.henry@sonarsource.com>
Tue, 22 Jul 2014 07:27:34 +0000 (09:27 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Tue, 22 Jul 2014 10:35:56 +0000 (12:35 +0200)
20 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
sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileCache.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleInputFileCache.java
sonar-batch/src/main/java/org/sonar/batch/scan/report/JsonReport.java
sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContextFactory.java
sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputFileCacheTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/scan/report/JsonReportTest.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/FileSystem.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputDir.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputPath.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputDir.java [new file with mode: 0644]

index b1c5dac5147bc5f0e5eaea4f72f20743201646e0..d18e146fe53f82e92b85e0f4faa0e4d8401a4f36 100644 (file)
@@ -27,7 +27,7 @@ import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
 import org.sonar.api.resources.Project;
 import org.sonar.api.utils.KeyValueFormat;
 import org.sonar.batch.index.ComponentDataCache;
-import org.sonar.batch.scan.filesystem.InputFileCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
 import org.sonar.core.DryRunIncompatible;
 import org.sonar.core.source.SnapshotDataTypes;
 
@@ -43,10 +43,10 @@ import java.util.Map;
 @DryRunIncompatible
 public final class FileHashSensor implements Sensor {
 
-  private final InputFileCache fileCache;
+  private final InputPathCache fileCache;
   private final ComponentDataCache componentDataCache;
 
-  public FileHashSensor(InputFileCache fileCache, ComponentDataCache componentDataCache) {
+  public FileHashSensor(InputPathCache fileCache, ComponentDataCache componentDataCache) {
     this.fileCache = fileCache;
     this.componentDataCache = componentDataCache;
   }
@@ -58,7 +58,7 @@ public final class FileHashSensor implements Sensor {
   @Override
   public void analyse(Project project, SensorContext context) {
     Map<String, String> map = Maps.newHashMap();
-    for (InputFile inputFile : fileCache.byModule(project.key())) {
+    for (InputFile inputFile : fileCache.filesByModule(project.key())) {
       String hash = ((DeprecatedDefaultInputFile) inputFile).hash();
       if (hash != null) {
         map.put(inputFile.relativePath(), hash);
index 29f5e64cce94750ce535ba6a4345918f3aa22dc3..4f851f39cae0454fb95e555ecdb36a2abbd06379 100644 (file)
@@ -31,7 +31,7 @@ import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
 import org.sonar.api.resources.Project;
 import org.sonar.batch.index.ComponentDataCache;
-import org.sonar.batch.scan.filesystem.InputFileCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
 import org.sonar.core.source.SnapshotDataTypes;
 
 import java.util.Collections;
@@ -51,13 +51,13 @@ public class FileHashSensorTest {
   public ExpectedException thrown = ExpectedException.none();
 
   Project project = new Project("struts");
-  InputFileCache fileCache = mock(InputFileCache.class);
+  InputPathCache fileCache = mock(InputPathCache.class);
   ComponentDataCache componentDataCache = mock(ComponentDataCache.class);
   FileHashSensor sensor = new FileHashSensor(fileCache, componentDataCache);
 
   @Test
   public void store_file_hashes() throws Exception {
-    when(fileCache.byModule("struts")).thenReturn(Lists.<InputFile>newArrayList(
+    when(fileCache.filesByModule("struts")).thenReturn(Lists.<InputFile>newArrayList(
       new DeprecatedDefaultInputFile("src/Foo.java").setFile(temp.newFile()).setHash("ABC"),
       new DeprecatedDefaultInputFile("src/Bar.java").setFile(temp.newFile()).setHash("DEF")));
 
@@ -71,7 +71,7 @@ public class FileHashSensorTest {
   @Test
   public void store_file_hashes_for_branches() throws Exception {
     project = new Project("struts", "branch-2.x", "Struts 2.x");
-    when(fileCache.byModule("struts:branch-2.x")).thenReturn(Lists.<InputFile>newArrayList(
+    when(fileCache.filesByModule("struts:branch-2.x")).thenReturn(Lists.<InputFile>newArrayList(
       new DeprecatedDefaultInputFile("src/Foo.java").setFile(temp.newFile()).setHash("ABC"),
       new DeprecatedDefaultInputFile("src/Bar.java").setFile(temp.newFile()).setHash("DEF")));
 
@@ -90,7 +90,7 @@ public class FileHashSensorTest {
 
   @Test
   public void dont_save_hashes_if_no_files() throws Exception {
-    when(fileCache.byModule("struts")).thenReturn(Collections.<InputFile>emptyList());
+    when(fileCache.filesByModule("struts")).thenReturn(Collections.<InputFile>emptyList());
 
     SensorContext sensorContext = mock(SensorContext.class);
     sensor.analyse(project, sensorContext);
index 5eaa1ee13a4be6ef999cda0e485335bc580ef033..394a2d2688a7e6278f8e77e6095e5bc91e34198a 100644 (file)
@@ -39,7 +39,7 @@ import org.sonar.batch.protocol.input.GlobalReferentials;
 import org.sonar.batch.protocol.input.ProjectReferentials;
 import org.sonar.batch.referential.GlobalReferentialsLoader;
 import org.sonar.batch.referential.ProjectReferentialsLoader;
-import org.sonar.batch.scan.filesystem.InputFileCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
 import org.sonar.batch.scan2.AnalyzerIssueCache;
 import org.sonar.batch.scan2.AnalyzerMeasureCache;
 import org.sonar.batch.scan2.ProjectScanContainer;
@@ -212,7 +212,7 @@ public class BatchMediumTester {
         measures.add(measure);
       }
 
-      InputFileCache inputFileCache = container.getComponentByType(InputFileCache.class);
+      InputPathCache inputFileCache = container.getComponentByType(InputPathCache.class);
       for (InputFile inputFile : inputFileCache.all()) {
         inputFiles.add(inputFile);
       }
index 9c2b46bf9b8f30ba37a6e1c88481c0c19071b03a..e3fde9a8c0f6686a3d522d8ce7b2e42d0c936888 100644 (file)
@@ -67,7 +67,7 @@ import org.sonar.batch.phases.GraphPersister;
 import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
 import org.sonar.batch.referential.ProjectReferentialsProvider;
 import org.sonar.batch.rule.RulesProvider;
-import org.sonar.batch.scan.filesystem.InputFileCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
 import org.sonar.batch.scan.maven.FakeMavenPluginExecutor;
 import org.sonar.batch.scan.maven.MavenPluginExecutor;
 import org.sonar.batch.scan.measure.MeasureCache;
@@ -153,7 +153,7 @@ public class ProjectScanContainer extends ComponentContainer {
       DefaultUserFinder.class,
 
       // file system
-      InputFileCache.class,
+      InputPathCache.class,
       PathResolver.class,
 
       // issues
index bdd0da25555f9e1af8b024abcd783b3663e5644c..a33bbc503589e1acf2c2fb8cc84cb27ae4e0fe8d 100644 (file)
@@ -46,7 +46,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 
 /**
- * Index input files into {@link InputFileCache}.
+ * Index input files into {@link InputPathCache}.
  */
 public class FileIndexer implements BatchComponent {
 
@@ -56,18 +56,18 @@ public class FileIndexer implements BatchComponent {
   private static final IOFileFilter FILE_FILTER = HiddenFileFilter.VISIBLE;
 
   private final List<InputFileFilter> filters;
-  private final InputFileCache fileCache;
+  private final InputPathCache fileCache;
   private final boolean isAggregator;
   private final ExclusionFilters exclusionFilters;
   private final InputFileBuilderFactory inputFileBuilderFactory;
 
   public FileIndexer(List<InputFileFilter> filters, ExclusionFilters exclusionFilters, InputFileBuilderFactory inputFileBuilderFactory,
-    InputFileCache cache, ProjectDefinition def) {
+    InputPathCache cache, ProjectDefinition def) {
     this(filters, exclusionFilters, inputFileBuilderFactory, cache, !def.getSubProjects().isEmpty());
   }
 
   private FileIndexer(List<InputFileFilter> filters, ExclusionFilters exclusionFilters, InputFileBuilderFactory inputFileBuilderFactory,
-    InputFileCache cache, boolean isAggregator) {
+    InputPathCache cache, boolean isAggregator) {
     this.filters = filters;
     this.exclusionFilters = exclusionFilters;
     this.inputFileBuilderFactory = inputFileBuilderFactory;
@@ -83,7 +83,7 @@ public class FileIndexer implements BatchComponent {
     LOG.info("Index files");
     exclusionFilters.prepare();
 
-    Progress progress = new Progress(fileCache.byModule(fileSystem.moduleKey()));
+    Progress progress = new Progress(fileCache.filesByModule(fileSystem.moduleKey()));
 
     InputFileBuilder inputFileBuilder = inputFileBuilderFactory.create(fileSystem);
     indexFiles(fileSystem, progress, inputFileBuilder, fileSystem.sources(), InputFile.Type.MAIN);
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
deleted file mode 100644 (file)
index 3b12d8b..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 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.batch.fs.InputFile;
-import org.sonar.batch.index.Cache;
-import org.sonar.batch.index.Caches;
-
-import javax.annotation.CheckForNull;
-
-/**
- * Cache of all files. This cache is shared amongst all project modules. Inclusion and
- * exclusion patterns are already applied.
- */
-public class InputFileCache implements BatchComponent {
-
-  // [path type | module key | path] -> InputFile
-  // For example:
-  // [rel | struts-core | src/main/java/Action.java] -> InputFile
-  // [rel | struts-core | src/main/java/Filter.java] -> InputFile
-  // [abs | struts-core | /absolute/path/to/src/main/java/Action.java] -> InputFile
-  // [abs | struts-core | /absolute/path/to/src/main/java/Filter.java] -> InputFile
-  private final Cache<InputFile> cache;
-
-  public InputFileCache(Caches caches) {
-    cache = caches.createCache("inputFiles");
-  }
-
-  public Iterable<InputFile> all() {
-    return cache.values();
-  }
-
-  public Iterable<InputFile> byModule(String moduleKey) {
-    return cache.values(moduleKey);
-  }
-
-  public InputFileCache removeModule(String moduleKey) {
-    cache.clear(moduleKey);
-    return this;
-  }
-
-  public InputFileCache remove(String moduleKey, InputFile inputFile) {
-    cache.remove(moduleKey, inputFile.relativePath());
-    return this;
-  }
-
-  public InputFileCache put(String moduleKey, InputFile inputFile) {
-    cache.put(moduleKey, inputFile.relativePath(), inputFile);
-    return this;
-  }
-
-  @CheckForNull
-  public InputFile get(String moduleKey, String relativePath) {
-    return cache.get(moduleKey, relativePath);
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java
new file mode 100644 (file)
index 0000000..842ecab
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputPath;
+import org.sonar.batch.index.Cache;
+import org.sonar.batch.index.Caches;
+
+import javax.annotation.CheckForNull;
+
+/**
+ * Cache of all files. This cache is shared amongst all project modules. Inclusion and
+ * exclusion patterns are already applied.
+ */
+public class InputPathCache implements BatchComponent {
+
+  private static final String DIR = "DIR";
+  private static final String FILE = "FILE";
+  // [module key | type | path] -> InputPath
+  // For example:
+  // [struts-core | FILE | src/main/java/Action.java] -> InputFile
+  // [struts-core | FILE | src/main/java/Filter.java] -> InputFile
+  // [struts-core | DIR | src/main/java] -> InputDir
+  private final Cache<InputPath> cache;
+
+  public InputPathCache(Caches caches) {
+    cache = caches.createCache("inputFiles");
+  }
+
+  public Iterable<InputPath> all() {
+    return cache.values();
+  }
+
+  public Iterable<InputFile> filesByModule(String moduleKey) {
+    return (Iterable) cache.values(moduleKey, FILE);
+  }
+
+  public InputPathCache removeModule(String moduleKey) {
+    cache.clear(moduleKey);
+    return this;
+  }
+
+  public InputPathCache remove(String moduleKey, InputFile inputFile) {
+    cache.remove(moduleKey, FILE, inputFile.relativePath());
+    return this;
+  }
+
+  public InputPathCache put(String moduleKey, InputFile inputFile) {
+    cache.put(moduleKey, FILE, inputFile.relativePath(), inputFile);
+    return this;
+  }
+
+  @CheckForNull
+  public InputFile getFile(String moduleKey, String relativePath) {
+    return (InputFile) cache.get(moduleKey, FILE, relativePath);
+  }
+
+  public InputDir getDir(String moduleKey, String relativePath) {
+    return (InputDir) cache.get(moduleKey, DIR, relativePath);
+  }
+}
index d555074db79187b0a268845f0aa8ebd8c1aa6610..c11d585a9c55a370ef036cb0030039b63370cf1f 100644 (file)
@@ -21,37 +21,34 @@ package org.sonar.batch.scan.filesystem;
 
 import org.sonar.api.BatchComponent;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.InputDir;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
 import org.sonar.api.batch.fs.internal.RelativePathPredicate;
-import org.sonar.api.resources.Project;
 
 public class ModuleInputFileCache extends DefaultFileSystem.Cache implements BatchComponent {
 
   private final String moduleKey;
-  private final InputFileCache projectCache;
+  private final InputPathCache projectCache;
 
-  public ModuleInputFileCache(Project module, ProjectDefinition projectDef, InputFileCache projectCache) {
-    this.moduleKey = module.getKey();
-    this.projectCache = projectCache;
-  }
-
-  /**
-   * Used by scan2
-   */
-  public ModuleInputFileCache(ProjectDefinition projectDef, InputFileCache projectCache) {
-    this.moduleKey = projectDef.getKey();
+  public ModuleInputFileCache(ProjectDefinition projectDef, InputPathCache projectCache) {
+    this.moduleKey = projectDef.getKeyWithBranch();
     this.projectCache = projectCache;
   }
 
   @Override
   protected Iterable<InputFile> inputFiles() {
-    return projectCache.byModule(moduleKey);
+    return projectCache.filesByModule(moduleKey);
   }
 
   @Override
   protected InputFile inputFile(RelativePathPredicate predicate) {
-    return projectCache.get(moduleKey, predicate.path());
+    return projectCache.getFile(moduleKey, predicate.path());
+  }
+
+  @Override
+  protected InputDir inputDir(String relativePath) {
+    return projectCache.getDir(moduleKey, relativePath);
   }
 
   @Override
index fe8ddc7826ded4eee00e74619412bd56a9f36d32..a5334ace9d643ea21b8850fbf24b11fb05ed5981 100644 (file)
@@ -26,8 +26,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.BatchComponent;
 import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputDir;
 import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
+import org.sonar.api.batch.fs.InputPath;
+import org.sonar.api.batch.fs.internal.DefaultInputDir;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.config.Settings;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.platform.Server;
@@ -43,9 +46,13 @@ import org.sonar.batch.bootstrap.AnalysisMode;
 import org.sonar.batch.events.BatchStepEvent;
 import org.sonar.batch.events.EventBus;
 import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.scan.filesystem.InputFileCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
 
-import java.io.*;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -67,11 +74,11 @@ public class JsonReport implements BatchComponent {
   private final EventBus eventBus;
   private final AnalysisMode analysisMode;
   private final UserFinder userFinder;
-  private final InputFileCache fileCache;
+  private final InputPathCache fileCache;
   private final Project rootModule;
 
   public JsonReport(Settings settings, FileSystem fileSystem, Server server, RuleFinder ruleFinder, IssueCache issueCache,
-                    EventBus eventBus, AnalysisMode analysisMode, UserFinder userFinder, Project rootModule, InputFileCache fileCache) {
+    EventBus eventBus, AnalysisMode analysisMode, UserFinder userFinder, Project rootModule, InputPathCache fileCache) {
     this.settings = settings;
     this.fileSystem = fileSystem;
     this.server = server;
@@ -167,16 +174,28 @@ public class JsonReport implements BatchComponent {
     json.name("components").beginArray();
     // Dump modules
     writeJsonModuleComponents(json, rootModule);
-    // TODO we need to dump directories
-    for (InputFile inputFile : fileCache.all()) {
-      String key = ((DeprecatedDefaultInputFile) inputFile).key();
-      json
-        .beginObject()
-        .prop("key", key)
-        .prop("path", inputFile.relativePath())
-        .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
-        .prop("status", inputFile.status().name())
-        .endObject();
+    for (InputPath inputPath : fileCache.all()) {
+      if (inputPath instanceof InputFile) {
+        InputFile inputFile = (InputFile) inputPath;
+        String key = ((DefaultInputFile) inputFile).key();
+        json
+          .beginObject()
+          .prop("key", key)
+          .prop("path", inputFile.relativePath())
+          .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
+          .prop("status", inputFile.status().name())
+          .endObject();
+      } else {
+        InputDir inputDir = (InputDir) inputPath;
+        String key = ((DefaultInputDir) inputDir).key();
+        json
+          .beginObject()
+          .prop("key", key)
+          .prop("path", inputDir.relativePath())
+          .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
+          .endObject();
+      }
+
     }
     json.endArray();
   }
index addc6e18e3cb6404c53072e04f0d19704c66620a..603cf47bb3fe6e5475c4a96a43a6ed620b9d12d7 100644 (file)
@@ -26,16 +26,16 @@ import org.sonar.api.batch.measure.MetricFinder;
 import org.sonar.api.measures.FileLinesContext;
 import org.sonar.api.measures.FileLinesContextFactory;
 import org.sonar.api.resources.Resource;
-import org.sonar.batch.scan.filesystem.InputFileCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
 
 public class DefaultFileLinesContextFactory implements FileLinesContextFactory {
 
   private final AnalyzerMeasureCache measureCache;
   private final MetricFinder metricFinder;
   private final ProjectDefinition def;
-  private InputFileCache fileCache;
+  private InputPathCache fileCache;
 
-  public DefaultFileLinesContextFactory(InputFileCache fileCache, FileSystem fs, MetricFinder metricFinder, AnalyzerMeasureCache measureCache,
+  public DefaultFileLinesContextFactory(InputPathCache fileCache, FileSystem fs, MetricFinder metricFinder, AnalyzerMeasureCache measureCache,
     ProjectDefinition def) {
     this.fileCache = fileCache;
     this.metricFinder = metricFinder;
@@ -50,7 +50,7 @@ public class DefaultFileLinesContextFactory implements FileLinesContextFactory {
 
   @Override
   public FileLinesContext createFor(InputFile inputFile) {
-    if (fileCache.get(def.getKey(), inputFile.relativePath()) == null) {
+    if (fileCache.getFile(def.getKey(), inputFile.relativePath()) == null) {
       throw new IllegalStateException("InputFile is not indexed: " + inputFile);
     }
     return new DefaultFileLinesContext(metricFinder, measureCache, def.getKey(), inputFile);
index 91b11ce80dac30f9f21e3238e2d63e355a653fd4..b0738e420e40a0b583851910a27817e06f7da936 100644 (file)
@@ -41,7 +41,7 @@ import org.sonar.batch.referential.ProjectReferentialsLoader;
 import org.sonar.batch.referential.ProjectReferentialsProvider;
 import org.sonar.batch.scan.ProjectReactorBuilder;
 import org.sonar.batch.scan.ProjectSettings;
-import org.sonar.batch.scan.filesystem.InputFileCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
 import org.sonar.batch.scan.maven.FakeMavenPluginExecutor;
 import org.sonar.batch.scan.maven.MavenPluginExecutor;
 
@@ -98,7 +98,7 @@ public class ProjectScanContainer extends ComponentContainer {
       AnalyzerMeasureCache.class,
 
       // file system
-      InputFileCache.class,
+      InputPathCache.class,
       PathResolver.class,
 
       // issues
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
deleted file mode 100644 (file)
index 3da4eeb..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 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.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
-import org.sonar.batch.index.Caches;
-import org.sonar.batch.index.CachesTest;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class InputFileCacheTest {
-
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  Caches caches;
-
-  @Before
-  public void start() throws Exception {
-    caches = CachesTest.createCacheOnTemp(temp);
-    caches.start();
-  }
-
-  @After
-  public void stop() {
-    caches.stop();
-  }
-
-  @Test
-  public void should_add_input_file() throws Exception {
-    InputFileCache cache = new InputFileCache(caches);
-    DefaultInputFile fooFile = new DefaultInputFile("src/main/java/Foo.java").setFile(temp.newFile("Foo.java"));
-    cache.put("struts", fooFile);
-    cache.put("struts-core", new DeprecatedDefaultInputFile("src/main/java/Bar.java").setFile(temp.newFile("Bar.java")));
-
-    assertThat(cache.get("struts", "src/main/java/Foo.java").relativePath())
-      .isEqualTo("src/main/java/Foo.java");
-
-    assertThat(cache.byModule("struts")).hasSize(1);
-    assertThat(cache.byModule("struts-core")).hasSize(1);
-    assertThat(cache.all()).hasSize(2);
-    for (InputFile inputFile : cache.all()) {
-      assertThat(inputFile.relativePath()).startsWith("src/main/java/");
-    }
-
-    cache.remove("struts", fooFile);
-    assertThat(cache.all()).hasSize(1);
-
-    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/InputPathCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java
new file mode 100644 (file)
index 0000000..6a81b66
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
+import org.sonar.batch.index.Caches;
+import org.sonar.batch.index.CachesTest;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class InputPathCacheTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  Caches caches;
+
+  @Before
+  public void start() throws Exception {
+    caches = CachesTest.createCacheOnTemp(temp);
+    caches.start();
+  }
+
+  @After
+  public void stop() {
+    caches.stop();
+  }
+
+  @Test
+  public void should_add_input_file() throws Exception {
+    InputPathCache cache = new InputPathCache(caches);
+    DefaultInputFile fooFile = new DefaultInputFile("src/main/java/Foo.java").setFile(temp.newFile("Foo.java"));
+    cache.put("struts", fooFile);
+    cache.put("struts-core", new DeprecatedDefaultInputFile("src/main/java/Bar.java").setFile(temp.newFile("Bar.java")));
+
+    assertThat(cache.getFile("struts", "src/main/java/Foo.java").relativePath())
+      .isEqualTo("src/main/java/Foo.java");
+
+    assertThat(cache.filesByModule("struts")).hasSize(1);
+    assertThat(cache.filesByModule("struts-core")).hasSize(1);
+    assertThat(cache.all()).hasSize(2);
+    for (InputFile inputFile : cache.all()) {
+      assertThat(inputFile.relativePath()).startsWith("src/main/java/");
+    }
+
+    cache.remove("struts", fooFile);
+    assertThat(cache.all()).hasSize(1);
+
+    cache.removeModule("struts");
+    assertThat(cache.filesByModule("struts")).hasSize(0);
+    assertThat(cache.filesByModule("struts-core")).hasSize(1);
+    assertThat(cache.all()).hasSize(1);
+  }
+
+}
index 6f4f306a0c5ee59ab38528a75c2a5c88a66547b1..5909265792725bd62c8d1e02925436c1fcd65f16 100644 (file)
@@ -44,7 +44,7 @@ import org.sonar.api.user.UserFinder;
 import org.sonar.batch.bootstrap.AnalysisMode;
 import org.sonar.batch.events.EventBus;
 import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.scan.filesystem.InputFileCache;
+import org.sonar.batch.scan.filesystem.InputPathCache;
 import org.sonar.core.user.DefaultUser;
 
 import java.io.File;
@@ -88,7 +88,7 @@ public class JsonReportTest {
     DeprecatedDefaultInputFile inputFile = new DeprecatedDefaultInputFile("src/main/java/org/apache/struts/Action.java");
     inputFile.setKey("struts:src/main/java/org/apache/struts/Action.java");
     inputFile.setStatus(InputFile.Status.CHANGED);
-    InputFileCache fileCache = mock(InputFileCache.class);
+    InputPathCache fileCache = mock(InputPathCache.class);
     when(fileCache.all()).thenReturn(Arrays.<InputFile>asList(inputFile));
     Project rootModule = new Project("struts");
     Project moduleA = new Project("struts-core");
index 56fdc0320f5496f21545cb900c37e90b905db682..0c285f686e2b4075cc89021a5bd9e9de74f3e523 100644 (file)
@@ -95,6 +95,16 @@ public interface FileSystem extends BatchComponent {
   @CheckForNull
   InputFile inputFile(FilePredicate predicate);
 
+  /**
+   * Returns {@link InputDir} matching the current {@link File}.
+   * @return null if directory is not indexed.
+   * @throw {@link IllegalArgumentException} is File is null or not a directory.
+   * 
+   * @since 4.5
+   */
+  @CheckForNull
+  InputDir inputDir(File dir);
+
   /**
    * Input files matching the given attributes. Return all the files if the parameter
    * <code>attributes</code> is empty.
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputDir.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputDir.java
new file mode 100644 (file)
index 0000000..d120c60
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.batch.fs;
+
+import java.io.File;
+
+/**
+ * Layer over {@link java.io.File} for directories.
+ *
+ * @since 4.5
+ */
+public interface InputDir extends InputPath {
+
+  /**
+   * Path relative to module base directory. Path is unique and identifies directory
+   * within given <code>{@link FileSystem}</code>. File separator is the forward
+   * slash ('/'), even on Microsoft Windows.
+   * <p/>
+   * Returns <code>src/main/java/com</code> if module base dir is
+   * <code>/path/to/module</code> and if directory is
+   * <code>/path/to/module/src/main/java/com</code>.
+   * <p/>
+   * Relative path is not null and is normalized ('foo/../foo' is replaced by 'foo').
+   */
+  @Override
+  String relativePath();
+
+  /**
+   * Normalized absolute path. File separator is forward slash ('/'), even on Microsoft Windows.
+   * <p/>
+   * This is not canonical path. Symbolic links are not resolved. For example if /project/src links
+   * to /tmp/src and basedir is /project, then this method returns /project/src. Use
+   * {@code file().getCanonicalPath()} to resolve symbolic link.
+   */
+  @Override
+  String absolutePath();
+
+  /**
+   * The underlying absolute {@link java.io.File}
+   */
+  @Override
+  File file();
+
+}
index 83e9697f15ff59eee01c9ff923457733de63fcb4..32ea0e3cf2e01f8b6fac9cad30e72f6a0db2e4dd 100644 (file)
 package org.sonar.api.batch.fs;
 
 import java.io.File;
-import java.io.Serializable;
 
 /**
  * This layer over {@link java.io.File} adds information for code analyzers.
  *
  * @since 4.2
  */
-public interface InputFile extends Serializable {
+public interface InputFile extends InputPath {
 
   enum Type {
     MAIN, TEST
@@ -51,6 +50,7 @@ public interface InputFile extends Serializable {
    * <p/>
    * Relative path is not null and is normalized ('foo/../foo' is replaced by 'foo').
    */
+  @Override
   String relativePath();
 
   /**
@@ -60,11 +60,13 @@ public interface InputFile extends Serializable {
    * to /tmp/src and basedir is /project, then this method returns /project/src/index.php. Use
    * {@code file().getCanonicalPath()} to resolve symbolic link.
    */
+  @Override
   String absolutePath();
 
   /**
    * The underlying absolute {@link java.io.File}
    */
+  @Override
   File file();
 
   /**
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputPath.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputPath.java
new file mode 100644 (file)
index 0000000..6a3ac3a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.batch.fs;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * Layer over {@link java.io.File} for files or directories.
+ *
+ * @since 4.5
+ */
+public interface InputPath extends Serializable {
+
+  /**
+   * @see InputFile#relativePath()
+   * @see InputDir#relativePath()
+   */
+  String relativePath();
+
+  /**
+   * @see InputFile#absolutePath()
+   * @see InputDir#absolutePath()
+   */
+  String absolutePath();
+
+  /**
+   * @see InputFile#file()
+   * @see InputDir#file()
+   */
+  File file();
+
+}
index 2002c6feb1f61732d96318c5ecd1f380b199091a..7b79d948d102554127ae1173eae0a69d1d189db8 100644 (file)
  */
 package org.sonar.api.batch.fs.internal;
 
+import org.sonar.api.utils.PathUtils;
+
 import com.google.common.base.Preconditions;
 import org.sonar.api.batch.fs.FilePredicate;
 import org.sonar.api.batch.fs.FilePredicates;
 import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputDir;
 import org.sonar.api.batch.fs.InputFile;
 
 import javax.annotation.CheckForNull;
@@ -155,6 +158,12 @@ public class DefaultFileSystem implements FileSystem {
     return result;
   }
 
+  @Override
+  public InputDir inputDir(File dir) {
+    doPreloadFiles();
+    return cache.inputDir(PathUtils.sanitize(new RelativeP));
+  }
+
   public static Collection<InputFile> filter(Iterable<InputFile> target, FilePredicate predicate) {
     Collection<InputFile> result = new ArrayList<InputFile>();
     for (InputFile element : target) {
@@ -210,6 +219,9 @@ public class DefaultFileSystem implements FileSystem {
     @CheckForNull
     protected abstract InputFile inputFile(RelativePathPredicate predicate);
 
+    @CheckForNull
+    protected abstract InputDir inputDir(String relativePath);
+
     protected abstract void doAdd(InputFile inputFile);
 
     final void add(InputFile inputFile) {
@@ -222,6 +234,7 @@ public class DefaultFileSystem implements FileSystem {
    */
   private static class MapCache extends Cache {
     private final Map<String, InputFile> fileMap = new HashMap<String, InputFile>();
+    private final Map<String, InputDir> dirMap = new HashMap<String, InputDir>();
 
     @Override
     public Iterable<InputFile> inputFiles() {
@@ -233,6 +246,11 @@ public class DefaultFileSystem implements FileSystem {
       return fileMap.get(predicate.path());
     }
 
+    @Override
+    protected InputDir inputDir(String relativePath) {
+      return dirMap.get(relativePath);
+    }
+
     @Override
     protected void doAdd(InputFile inputFile) {
       fileMap.put(inputFile.relativePath(), inputFile);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputDir.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputDir.java
new file mode 100644 (file)
index 0000000..26fc37a
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.batch.fs.internal;
+
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.utils.PathUtils;
+
+import javax.annotation.CheckForNull;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * @since 4.5
+ */
+public class DefaultInputDir implements InputDir, Serializable {
+
+  private final String relativePath;
+  private String absolutePath;
+  private String key;
+
+  public DefaultInputDir(String relativePath) {
+    this.relativePath = PathUtils.sanitize(relativePath);
+  }
+
+  @Override
+  public String relativePath() {
+    return relativePath;
+  }
+
+  /**
+   * Marked as nullable just for the unit tests that do not call {@link #setFile(java.io.File)}
+   * previously.
+   */
+  @Override
+  @CheckForNull
+  public String absolutePath() {
+    return absolutePath;
+  }
+
+  @Override
+  public File file() {
+    if (absolutePath == null) {
+      throw new IllegalStateException("Can not return the java.io.File because absolute path is not set (see method setFile(java.io.File))");
+    }
+    return new File(absolutePath);
+  }
+
+  /**
+   * Component key. It's marked as nullable just for the unit tests that
+   * do not previously call {@link #setKey(String)}.
+   */
+  @CheckForNull
+  public String key() {
+    return key;
+  }
+
+  public DefaultInputDir setAbsolutePath(String s) {
+    this.absolutePath = PathUtils.sanitize(s);
+    return this;
+  }
+
+  public DefaultInputDir setFile(File file) {
+    setAbsolutePath(file.getAbsolutePath());
+    return this;
+  }
+
+  public DefaultInputDir setKey(String s) {
+    this.key = s;
+    return this;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof DefaultInputDir)) {
+      return false;
+    }
+
+    DefaultInputDir that = (DefaultInputDir) o;
+    return relativePath.equals(that.relativePath);
+  }
+
+  @Override
+  public int hashCode() {
+    return relativePath.hashCode();
+  }
+
+  @Override
+  public String toString() {
+    return "[relative=" + relativePath + ", abs=" + absolutePath + "]";
+  }
+}