Browse Source

SONAR-3677 refactor API

tags/4.0
Simon Brandhof 10 years ago
parent
commit
7cdb8cbfb5
31 changed files with 807 additions and 274 deletions
  1. 5
    4
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/FileHashSensor.java
  2. 3
    2
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/FileHashSensorTest.java
  3. 11
    0
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/AttributeFilter.java
  4. 3
    3
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java
  5. 1
    1
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileFilters.java
  6. 4
    3
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java
  7. 6
    0
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileQueryFilter.java
  8. 25
    5
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java
  9. 1
    1
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PathPattern.java
  10. 6
    4
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/AttributeFilterTest.java
  11. 3
    2
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystemTest.java
  12. 4
    5
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DeprecatedFileFiltersTest.java
  13. 5
    6
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFilterTest.java
  14. 13
    14
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFiltersTest.java
  15. 101
    0
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileQueryFilterTest.java
  16. 5
    6
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InclusionFilterTest.java
  17. 3
    3
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputFileCacheTest.java
  18. 97
    0
      sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageRecognizerTest.java
  19. 2
    2
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileQuery.java
  20. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileType.java
  21. 68
    115
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java
  22. 1
    0
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFileFilter.java
  23. 42
    0
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFiles.java
  24. 5
    1
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/ModuleFileSystem.java
  25. 114
    0
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/internal/DefaultInputFile.java
  26. 87
    0
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/internal/InputFileBuilder.java
  27. 23
    0
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/internal/package-info.java
  28. 46
    0
      sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/InputFilesTest.java
  29. 0
    96
      sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/SimpleModuleFileSystem.java
  30. 92
    0
      sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/internal/DefaultInputFileTest.java
  31. 30
    0
      sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/internal/InputFileBuilderTest.java

+ 5
- 4
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/FileHashSensor.java View File

@@ -20,7 +20,6 @@
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;
@@ -28,6 +27,7 @@ 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.InputFileCache;
import org.sonar.core.DryRunIncompatible;
import org.sonar.core.source.SnapshotDataTypes;

import java.util.Map;
@@ -36,8 +36,10 @@ 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.
*
* @since 4.0
*/
@DryRunIncompatible
public final class FileHashSensor implements Sensor {

private final InputFileCache fileCache;
@@ -56,10 +58,9 @@ public final class FileHashSensor implements Sensor {
public void analyse(Project project, SensorContext context) {
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);
if (hash != null) {
map.put(inputFile.relativePath(), hash);
}
}
if (!map.isEmpty()) {

+ 3
- 2
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/FileHashSensorTest.java View File

@@ -28,6 +28,7 @@ import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Project;
import org.sonar.api.scan.filesystem.InputFile;
import org.sonar.api.scan.filesystem.internal.DefaultInputFile;
import org.sonar.batch.index.ComponentDataCache;
import org.sonar.batch.scan.filesystem.InputFileCache;
import org.sonar.core.source.SnapshotDataTypes;
@@ -53,8 +54,8 @@ public class FileHashSensorTest {
@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"))
DefaultInputFile.create(temp.newFile(), "src/Foo.java", ImmutableMap.of(InputFile.ATTRIBUTE_HASH, "ABC")),
DefaultInputFile.create(temp.newFile(), "src/Bar.java", ImmutableMap.of(InputFile.ATTRIBUTE_HASH, "DEF"))
));

SensorContext sensorContext = mock(SensorContext.class);

+ 11
- 0
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/AttributeFilter.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.batch.scan.filesystem;

import com.google.common.annotations.VisibleForTesting;
import org.sonar.api.scan.filesystem.InputFile;
import org.sonar.api.scan.filesystem.InputFileFilter;

@@ -38,4 +39,14 @@ class AttributeFilter implements InputFileFilter {
String value = inputFile.attribute(key);
return values.contains(value);
}

@VisibleForTesting
String key() {
return key;
}

@VisibleForTesting
Collection<String> values() {
return values;
}
}

+ 3
- 3
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java View File

@@ -27,8 +27,8 @@ 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.InputFiles;
import org.sonar.api.scan.filesystem.ModuleFileSystem;
import org.sonar.api.utils.SonarException;

import javax.annotation.CheckForNull;
import java.io.File;
@@ -155,8 +155,8 @@ public class DefaultModuleFileSystem implements ModuleFileSystem {

/**
* @since 4.0
* TODO move into API
*/
@Override
public Iterable<InputFile> inputFiles(FileQuery query) {
List<InputFile> result = Lists.newArrayList();

@@ -172,7 +172,7 @@ public class DefaultModuleFileSystem implements ModuleFileSystem {
@Override
// TODO deprecate
public List<File> files(FileQuery query) {
return InputFile.toFiles(inputFiles(query));
return InputFiles.toFiles(inputFiles(query));
}

public void resetDirs(File basedir, File buildDir, List<File> sourceDirs, List<File> testDirs, List<File> binaryDirs) {

+ 1
- 1
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileFilters.java View File

@@ -78,7 +78,7 @@ public class DeprecatedFileFilters implements InputFileFilter {

@Override
public String canonicalPath() {
return inputFile.attribute(InputFile.ATTRIBUTE_CANONICAL_PATH);
return inputFile.path();
}
}
}

+ 4
- 3
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java View File

@@ -33,6 +33,7 @@ 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 org.sonar.api.scan.filesystem.internal.DefaultInputFile;

import javax.annotation.Nullable;
import java.io.File;
@@ -63,9 +64,10 @@ public class FileIndexer implements BatchComponent {
this.fileHashes = fileHashes;
}

public void index(ModuleFileSystem fileSystem) {
public void index(DefaultModuleFileSystem fileSystem) {
Logger logger = LoggerFactory.getLogger(FileIndexer.class);
logger.info("Index files");
// TODO log configuration too (replace FileSystemLogger)

cache.removeModule(fileSystem.moduleKey());
int count = 0;
@@ -102,7 +104,6 @@ public class FileIndexer implements BatchComponent {
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);
@@ -111,7 +112,7 @@ public class FileIndexer implements BatchComponent {
set(attributes, InputFile.ATTRIBUTE_LANGUAGE, languageRecognizer.ofExtension(extension));
initStatus(file, fileSystem.sourceCharset(), baseRelativePath, attributes);

return InputFile.create(file, baseRelativePath, attributes);
return DefaultInputFile.create(file, baseRelativePath, attributes);

} catch (Exception e) {
throw new IllegalStateException("Fail to read file: " + file.getAbsolutePath(), e);

+ 6
- 0
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileQueryFilter.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.batch.scan.filesystem;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
@@ -56,6 +57,11 @@ class FileQueryFilter {
}
}

@VisibleForTesting
List<InputFileFilter> filters() {
return filters;
}

boolean accept(InputFile inputFile) {
for (InputFileFilter filter : filters) {
if (!filter.accept(inputFile)) {

+ 25
- 5
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java View File

@@ -21,6 +21,7 @@ package org.sonar.batch.scan.filesystem;

import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.BatchComponent;
import org.sonar.api.resources.Language;

@@ -28,16 +29,26 @@ import javax.annotation.CheckForNull;
import java.util.Map;

/**
* Based on file extensions.
* Detect language of source files. Simplistic, based on file extensions.
*/
public class LanguageRecognizer implements BatchComponent {
public class LanguageRecognizer implements BatchComponent, Startable {

private final Map<String, String> byExtensions = Maps.newHashMap();
/**
* Lower-case extension -> language
*/
private Map<String, String> byExtensions = Maps.newHashMap();

private final Language[] languages;

public LanguageRecognizer(Language[] languages) {
this.languages = languages;
}

@Override
public void start() {
for (Language language : languages) {
for (String suffix : language.getFileSuffixes()) {
String extension = StringUtils.removeStart(suffix, ".");
String extension = sanitizeExtension(suffix);

String s = byExtensions.get(extension);
if (s != null) {
@@ -50,12 +61,21 @@ public class LanguageRecognizer implements BatchComponent {
}
}

@Override
public void stop() {
// do nothing
}

// TODO what about cobol files without extension ?
@CheckForNull
String ofExtension(String fileExtension) {
if (StringUtils.isNotBlank(fileExtension)) {
return byExtensions.get(fileExtension);
return byExtensions.get(StringUtils.lowerCase(fileExtension));
}
return null;
}

static String sanitizeExtension(String suffix) {
return StringUtils.lowerCase(StringUtils.removeStart(suffix, "."));
}
}

+ 1
- 1
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PathPattern.java View File

@@ -61,7 +61,7 @@ abstract class PathPattern {

@Override
boolean match(InputFile inputFile) {
return pattern.match(inputFile.attribute(InputFile.ATTRIBUTE_CANONICAL_PATH));
return pattern.match(inputFile.path());
}

@Override

+ 6
- 4
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/AttributeFilterTest.java View File

@@ -24,7 +24,7 @@ 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 org.sonar.api.scan.filesystem.internal.DefaultInputFile;

import static org.fest.assertions.Assertions.assertThat;

@@ -37,9 +37,11 @@ public class AttributeFilterTest {
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();
assertThat(filter.key()).isEqualTo("foo");
assertThat(filter.values()).containsOnly("one", "two");
assertThat(filter.accept(DefaultInputFile.create(temp.newFile(), "Why.java", ImmutableMap.of("foo", "two")))).isTrue();
assertThat(filter.accept(DefaultInputFile.create(temp.newFile(), "Where.java", ImmutableMap.of("foo", "three")))).isFalse();
assertThat(filter.accept(DefaultInputFile.create(temp.newFile(), "What.java", ImmutableMap.of("bar", "one")))).isFalse();

}
}

+ 3
- 2
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystemTest.java View File

@@ -29,6 +29,7 @@ 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.internal.DefaultInputFile;

import java.io.File;
import java.io.IOException;
@@ -151,8 +152,8 @@ public class DefaultModuleFileSystemTest {
DefaultModuleFileSystem fs = new DefaultModuleFileSystem("foo", settings, fileCache, fileIndexer);

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));
InputFile mainInput = DefaultInputFile.create(mainFile, "Main.java", ImmutableMap.of(InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE));
InputFile testInput = DefaultInputFile.create(temp.newFile(), "Test.java", ImmutableMap.of(InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_TEST));

when(fileCache.byModule("foo")).thenReturn(Lists.newArrayList(mainInput, testInput));


+ 4
- 5
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DeprecatedFileFiltersTest.java View File

@@ -28,7 +28,7 @@ import org.mockito.ArgumentCaptor;
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.internal.DefaultInputFile;

import java.io.File;

@@ -48,7 +48,7 @@ public class DeprecatedFileFiltersTest {
public void no_filters() throws Exception {
DeprecatedFileFilters filters = new DeprecatedFileFilters();

InputFile inputFile = InputFile.create(temp.newFile(), "src/main/java/Foo.java", Maps.<String, String>newHashMap());
InputFile inputFile = DefaultInputFile.create(temp.newFile(), "src/main/java/Foo.java", Maps.<String, String>newHashMap());
assertThat(filters.accept(inputFile)).isTrue();
}

@@ -58,8 +58,7 @@ public class DeprecatedFileFiltersTest {

File basedir = temp.newFolder();
File file = temp.newFile();
InputFile inputFile = InputFile.create(file, "src/main/java/Foo.java", ImmutableMap.of(
InputFile.ATTRIBUTE_CANONICAL_PATH, new File(basedir, "src/main/java/Foo.java").getAbsolutePath(),
InputFile inputFile = DefaultInputFile.create(file, "src/main/java/Foo.java", ImmutableMap.of(
InputFile.ATTRIBUTE_SOURCEDIR_PATH, new File(basedir, "src/main/java").getAbsolutePath(),
InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "Foo.java",
InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_TEST
@@ -73,7 +72,7 @@ public class DeprecatedFileFiltersTest {
verify(filter).accept(eq(file), argument.capture());

DeprecatedFileFilters.DeprecatedContext context = argument.getValue();
assertThat(context.canonicalPath()).isEqualTo(new File(basedir, "src/main/java/Foo.java").getAbsolutePath());
assertThat(context.canonicalPath()).isEqualTo(file.getAbsolutePath());
assertThat(context.relativeDir()).isEqualTo(new File(basedir, "src/main/java"));
assertThat(context.relativePath()).isEqualTo("Foo.java");
assertThat(context.type()).isEqualTo(FileType.TEST);

+ 5
- 6
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFilterTest.java View File

@@ -24,9 +24,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.scan.filesystem.InputFile;
import org.sonar.api.scan.filesystem.internal.DefaultInputFile;

import java.io.File;
import java.io.IOException;

import static org.fest.assertions.Assertions.assertThat;

@@ -40,17 +40,16 @@ public class ExclusionFilterTest {
ExclusionFilter sourceRelativeFilter = new ExclusionFilter("**/*Foo.java");
ExclusionFilter absoluteFilter = new ExclusionFilter("file:**/src/main/**Foo.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",
File file = new File(temp.newFolder(), "src/main/java/org/MyFoo.java");
InputFile inputFile = DefaultInputFile.create(file, "src/main/java/org/MyFoo.java", ImmutableMap.of(
InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "org/MyFoo.java"
));

assertThat(sourceRelativeFilter.accept(inputFile)).isFalse();
assertThat(absoluteFilter.accept(inputFile)).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",
file = new File(temp.newFolder(), "src/main/java/org/Other.java");
inputFile = DefaultInputFile.create(file, "src/main/java/org/Other.java", ImmutableMap.of(
InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "org/Other.java"
));
assertThat(sourceRelativeFilter.accept(inputFile)).isTrue();

+ 13
- 14
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFiltersTest.java View File

@@ -30,6 +30,7 @@ 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.InputFile;
import org.sonar.api.scan.filesystem.internal.DefaultInputFile;

import java.io.IOException;

@@ -47,21 +48,21 @@ public class ExclusionFiltersTest {
ExclusionFilters filter = new ExclusionFilters(new FileExclusions(settings));

java.io.File file = temp.newFile();
InputFile inputFile = InputFile.create(file, "src/main/java/com/mycompany/Foo.java", ImmutableMap.of(
InputFile inputFile = DefaultInputFile.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();

inputFile = InputFile.create(file, "src/main/java/com/mycompany/FooDao.java", ImmutableMap.of(
inputFile = DefaultInputFile.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
inputFile = InputFile.create(file, "src/main/java/com/mycompany/Foo.java", ImmutableMap.of(
inputFile = DefaultInputFile.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"
));
@@ -75,14 +76,14 @@ public class ExclusionFiltersTest {
ExclusionFilters filter = new ExclusionFilters(new FileExclusions(settings));

java.io.File file = temp.newFile();
InputFile inputFile = InputFile.create(file, "src/main/java/com/mycompany/Foo.java", ImmutableMap.of(
InputFile inputFile = DefaultInputFile.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();

inputFile = InputFile.create(file, "src/main/java/com/mycompany/FooDto.java", ImmutableMap.of(
inputFile = DefaultInputFile.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"
));
@@ -96,20 +97,20 @@ public class ExclusionFiltersTest {
ExclusionFilters filter = new ExclusionFilters(new FileExclusions(settings));

java.io.File file = temp.newFile();
InputFile inputFile = InputFile.create(file, "src/main/java/com/mycompany/FooDao.java", ImmutableMap.of(
InputFile inputFile = DefaultInputFile.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();

inputFile = InputFile.create(file, "src/main/java/com/mycompany/Foo.java", ImmutableMap.of(
inputFile = DefaultInputFile.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
inputFile = InputFile.create(file, "src/main/java/com/mycompany/FooDao.java", ImmutableMap.of(
inputFile = DefaultInputFile.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"
));
@@ -125,15 +126,13 @@ public class ExclusionFiltersTest {
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getCanonicalPath());
ExclusionFilters filter = new ExclusionFilters(new FileExclusions(settings));

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()
InputFile includedInput = DefaultInputFile.create(includedFile, "src/main/java/org/bar/Foo.java", ImmutableMap.of(
InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE
));
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()
InputFile excludedInput = DefaultInputFile.create(excludedFile, "src/main/java/org/bar/Bar.java", ImmutableMap.of(
InputFile.ATTRIBUTE_TYPE, InputFile.TYPE_SOURCE
));
assertThat(filter.accept(excludedInput)).isFalse();
}

+ 101
- 0
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileQueryFilterTest.java View File

@@ -0,0 +1,101 @@
/*
* 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.Test;
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 static org.fest.assertions.Assertions.assertThat;

public class FileQueryFilterTest {

Settings settings = new Settings();

@Test
public void wrap_query_on_attributes() throws Exception {
FileQuery query = FileQuery.onSource();
FileQueryFilter filter = new FileQueryFilter(settings, query);

assertThat(filter.filters()).hasSize(1);
InputFileFilter typeFilter = filter.filters().get(0);
assertThat(typeFilter).isInstanceOf(AttributeFilter.class);
assertThat(((AttributeFilter) typeFilter).key()).isEqualTo(InputFile.ATTRIBUTE_TYPE);
assertThat(((AttributeFilter) typeFilter).values()).containsOnly(InputFile.TYPE_SOURCE);
}

@Test
public void wrap_query_on_inclusions() throws Exception {
FileQuery query = FileQuery.on().withInclusions("Foo*.java");
FileQueryFilter filter = new FileQueryFilter(settings, query);

assertThat(filter.filters()).hasSize(1);
InputFileFilter inclusionFilter = filter.filters().get(0);
assertThat(inclusionFilter).isInstanceOf(InclusionFilter.class);
assertThat(inclusionFilter.toString()).isEqualTo("Includes: Foo*.java");
}

@Test
public void wrap_query_on_exclusions() throws Exception {
FileQuery query = FileQuery.on().withExclusions("Foo*.java");
FileQueryFilter filter = new FileQueryFilter(settings, query);

assertThat(filter.filters()).hasSize(1);
InputFileFilter exclusionFilter = filter.filters().get(0);
assertThat(exclusionFilter).isInstanceOf(ExclusionFilter.class);
assertThat(exclusionFilter.toString()).isEqualTo("Excludes: Foo*.java");
}

@Test
public void all_files_by_default() throws Exception {
FileQuery query = FileQuery.on();
FileQueryFilter filter = new FileQueryFilter(settings, query);
assertThat(filter.filters()).isEmpty();
}

@Test
public void only_changed_files_by_default_if_incremental_mode() throws Exception {
settings.setProperty(CoreProperties.INCREMENTAL_PREVIEW, true);

FileQuery query = FileQuery.on();
FileQueryFilter filter = new FileQueryFilter(settings, query);

assertThat(filter.filters()).hasSize(1);
AttributeFilter statusFilter = (AttributeFilter) filter.filters().get(0);
assertThat(statusFilter.key()).isEqualTo(InputFile.ATTRIBUTE_STATUS);
assertThat(statusFilter.values()).containsOnly(InputFile.STATUS_ADDED, InputFile.STATUS_CHANGED);
}

@Test
public void get_all_files_even_if_incremental_mode() throws Exception {
settings.setProperty(CoreProperties.INCREMENTAL_PREVIEW, true);

FileQuery query = FileQuery.on().on(InputFile.ATTRIBUTE_STATUS, InputFile.STATUS_SAME);
FileQueryFilter filter = new FileQueryFilter(settings, query);

assertThat(filter.filters()).hasSize(1);
AttributeFilter statusFilter = (AttributeFilter) filter.filters().get(0);
assertThat(statusFilter.key()).isEqualTo(InputFile.ATTRIBUTE_STATUS);
assertThat(statusFilter.values()).containsOnly(InputFile.STATUS_SAME);
}
}

+ 5
- 6
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InclusionFilterTest.java View File

@@ -24,6 +24,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.scan.filesystem.InputFile;
import org.sonar.api.scan.filesystem.internal.DefaultInputFile;

import java.io.File;

@@ -38,18 +39,16 @@ public class InclusionFilterTest {
InclusionFilter sourceRelativeFilter = new InclusionFilter("**/*Foo.java");
InclusionFilter absoluteFilter = new InclusionFilter("file:**/src/main/**Foo.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",
File file = new File(temp.newFolder(), "src/main/java/org/MyFoo.java");
InputFile inputFile = DefaultInputFile.create(file, "src/main/java/org/MyFoo.java", ImmutableMap.of(
InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "org/MyFoo.java"
));

assertThat(sourceRelativeFilter.accept(inputFile)).isTrue();
assertThat(absoluteFilter.accept(inputFile)).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",
file = new File(temp.newFolder(), "src/main/java/org/Other.java");
inputFile = DefaultInputFile.create(file, "src/main/java/org/Other.java", ImmutableMap.of(
InputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "org/Other.java"
));
assertThat(sourceRelativeFilter.accept(inputFile)).isFalse();

+ 3
- 3
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputFileCacheTest.java View File

@@ -25,7 +25,7 @@ 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.api.scan.filesystem.internal.DefaultInputFile;
import org.sonar.batch.index.Caches;

import static org.fest.assertions.Assertions.assertThat;
@@ -50,8 +50,8 @@ public class InputFileCacheTest {
@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()));
cache.put("struts", DefaultInputFile.create(temp.newFile(), "src/main/java/Foo.java", Maps.<String, String>newHashMap()));
cache.put("struts-core", DefaultInputFile.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);

+ 97
- 0
sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageRecognizerTest.java View File

@@ -0,0 +1,97 @@
/*
* 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.Test;
import org.sonar.api.resources.Java;
import org.sonar.api.resources.Language;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;

public class LanguageRecognizerTest {

@Test
public void test_sanitizeExtension() throws Exception {
assertThat(LanguageRecognizer.sanitizeExtension(".cbl")).isEqualTo("cbl");
assertThat(LanguageRecognizer.sanitizeExtension(".CBL")).isEqualTo("cbl");
assertThat(LanguageRecognizer.sanitizeExtension("CBL")).isEqualTo("cbl");
assertThat(LanguageRecognizer.sanitizeExtension("cbl")).isEqualTo("cbl");
}

@Test
public void search_by_file_extension() throws Exception {
Language[] languages = new Language[]{Java.INSTANCE, new Cobol()};
LanguageRecognizer recognizer = new LanguageRecognizer(languages);

recognizer.start();
assertThat(recognizer.ofExtension("java")).isEqualTo(Java.KEY);
assertThat(recognizer.ofExtension("cbl")).isEqualTo("cobol");
assertThat(recognizer.ofExtension("CBL")).isEqualTo("cobol");
assertThat(recognizer.ofExtension("php")).isNull();
assertThat(recognizer.ofExtension("")).isNull();
assertThat(recognizer.ofExtension(null)).isNull();
recognizer.stop();
}

@Test
public void fail_if_conflict_of_file_extensions() throws Exception {
Language[] languages = new Language[]{Java.INSTANCE, new Language() {
@Override
public String getKey() {
return "java2";
}

@Override
public String getName() {
return "Java2";
}

@Override
public String[] getFileSuffixes() {
return new String[]{"java2", "java"};
}
}};

try {
new LanguageRecognizer(languages).start();
fail();
} catch (IllegalStateException e) {
assertThat(e.getMessage()).isEqualTo("File extension 'java' is declared by two languages: java and java2");
}
}

static class Cobol implements Language {
@Override
public String getKey() {
return "cobol";
}

@Override
public String getName() {
return "Cobol";
}

@Override
public String[] getFileSuffixes() {
return new String[]{"cbl", "cob"};
}
}
}

+ 2
- 2
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileQuery.java View File

@@ -37,7 +37,7 @@ import java.util.Set;
*/
public class FileQuery {

// TODO better builders, for example FileQuery.ALL
// TODO REFACTOR - better builders, for example FileQuery.ALL

public static FileQuery on(FileType... types) {
FileQuery query = new FileQuery();
@@ -62,7 +62,7 @@ public class FileQuery {
private FileQuery() {
}

private FileQuery on(String attribute, String... values) {
public FileQuery on(String attribute, String... values) {
for (String value : values) {
attributes.put(attribute, value);
}

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileType.java View File

@@ -21,7 +21,7 @@ package org.sonar.api.scan.filesystem;

/**
* @since 3.5
* @deprecated in 4.0. Replaced by more flexible {@link InputFile} attributes.
* @deprecated in 4.0. Replaced by more flexible {@link org.sonar.api.scan.filesystem.InputFile} attributes.
*/
@Deprecated
public enum FileType {

+ 68
- 115
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java View File

@@ -1,141 +1,94 @@
/*
* 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.HashMap;
import java.util.List;
import java.util.Map;

/**
* @since 4.0
*/
public class InputFile implements Serializable {
public interface InputFile extends Serializable {

/**
* Canonical path of source directory.
* Example: <code>/path/to/module/src/main/java</code> or <code>C:\path\to\module\src\main\java</code>
*/
String ATTRIBUTE_SOURCEDIR_PATH = "srcDirPath";

// TODO refactor attribute constants as classes or enums ?
/**
* Relative path from source directory. File separator is the forward slash ('/'),
* even on MSWindows.
*/
String ATTRIBUTE_SOURCE_RELATIVE_PATH = "srcRelPath";

/**
* Path relative to module base directory.
* Detected language
*/
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;
}
String ATTRIBUTE_LANGUAGE = "lang";

/**
* 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 = new HashMap<String, String>(attributes);
copy.put(InputFile.ATTRIBUTE_BASE_RELATIVE_PATH, baseRelativePath);
return new InputFile(file, copy);
}
String ATTRIBUTE_TYPE = "type";
String TYPE_SOURCE = "source";
String TYPE_TEST = "test";

String ATTRIBUTE_STATUS = "status";
String STATUS_SAME = "same";
String STATUS_CHANGED = "changed";
String STATUS_ADDED = "added";

String ATTRIBUTE_HASH = "hash";
String ATTRIBUTE_EXTENSION = "extension";


/**
* Path from module base directory. Path is unique and identifies file within given
* <code>{@link ModuleFileSystem}</code>. File separator is the forward slash ('/'),
* <code>{@link org.sonar.api.scan.filesystem.ModuleFileSystem}</code>. File separator is the forward slash ('/'),
* even on MSWindows.
* <p/>
* If:
* <ul>
* <li>Module base dir is <code>/absolute/path/to/module</code></li>
* <li>File is <code>/absolute/path/to/module/src/main/java/com/Foo.java</code></li>
* </ul>
* then the path is <code>src/main/java/com/Foo.java</code>
* <p/>
* On MSWindows, if:
* <ul>
* <li>Module base dir is <code>C:\absolute\path\to\module</code></li>
* <li>File is <code>C:\absolute\path\to\module\src\main\java\com\Foo.java</code></li>
* </ul>
* then the path is <code>src/main/java/com/Foo.java</code>.
* <p/>
* Returned relative path is never null.
*/
public String path() {
return attribute(ATTRIBUTE_BASE_RELATIVE_PATH);
}
String relativePath();

public File file() {
if (transientFile == null) {
transientFile = new File(attribute(ATTRIBUTE_CANONICAL_PATH));
}
return transientFile;
}
/**
* Canonical path.
*/
String path();

public String name() {
return file().getName();
}
/**
* Not-null related {@link java.io.File}
*/
File file();

public boolean has(String attribute, String value) {
return StringUtils.equals(attributes.get(attribute), value);
}
/**
* Not-null filename, including extension
*/

@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;
}
String name();

/**
* Does the given attribute have the given value ?
*/
boolean has(String attribute, String value);

/**
* See list of attribute keys in constants starting with ATTRIBUTE_.
*/
@CheckForNull
String attribute(String key);

Map<String, String> attributes();
}

+ 1
- 0
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFileFilter.java View File

@@ -23,6 +23,7 @@ import org.sonar.api.BatchExtension;

/**
* TODO document lifecycle -> executed when initializing project
*
* @since 4.0
*/
public interface InputFileFilter extends BatchExtension {

+ 42
- 0
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFiles.java View File

@@ -0,0 +1,42 @@
/*
* 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 java.io.File;
import java.util.List;

/**
* @since 4.0
*/
public class InputFiles {
InputFiles() {
// static methods only
}

public static List<File> toFiles(Iterable<InputFile> inputFiles) {
List<File> files = Lists.newArrayList();
for (InputFile inputFile : inputFiles) {
files.add(inputFile.file());
}
return files;
}
}

+ 5
- 1
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/ModuleFileSystem.java View File

@@ -20,7 +20,6 @@
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;
@@ -81,6 +80,11 @@ public interface ModuleFileSystem extends BatchComponent {
*/
List<File> files(FileQuery query);

/**
* @since 4.0
*/
Iterable<InputFile> inputFiles(FileQuery query);

/**
* Charset of source and test files. If it's not defined, then return the platform default charset.
*/

+ 114
- 0
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/internal/DefaultInputFile.java View File

@@ -0,0 +1,114 @@
/*
* 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.internal;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.scan.filesystem.InputFile;

import javax.annotation.CheckForNull;
import java.io.File;
import java.io.IOException;
import java.util.Map;

/**
* PLUGINS MUST NOT USE THIS CLASS.
*
* @since 4.0
*/
public class DefaultInputFile implements InputFile {

private final String path;
private final String relativePath;
private final Map<String, String> attributes;

private DefaultInputFile(File file, String relativePath, Map<String, String> attributes) {
try {
this.path = file.getCanonicalPath();
this.relativePath = FilenameUtils.separatorsToUnix(relativePath);
this.attributes = attributes;
} catch (IOException e) {
throw new IllegalStateException("Fail to get canonical path of: " + file, e);
}
}

/**
* Plugins must not build their own instances of {@link InputFile}.
* {@link org.sonar.api.scan.filesystem.ModuleFileSystem} must be used to search for files to scan.
* <p/>
* Usage: <code>InputFile.create(file, "src/main/java/com/Foo.java", attributes)</code>
*/
public static DefaultInputFile create(File file, String relativePath, Map<String, String> attributes) {
return new DefaultInputFile(file, relativePath, attributes);
}

@Override
public String relativePath() {
return relativePath;
}

@Override
public String path() {
return path;
}

@Override
public File file() {
return new File(path);
}

@Override
public String name() {
return file().getName();
}

@Override
public boolean has(String attribute, String value) {
return StringUtils.equals(attributes.get(attribute), value);
}

@Override
@CheckForNull
public String attribute(String key) {
return attributes.get(key);
}

@Override
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;
}
DefaultInputFile other = (DefaultInputFile) o;
return path.equals(other.path);
}

@Override
public int hashCode() {
return path.hashCode();
}
}

+ 87
- 0
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/internal/InputFileBuilder.java View File

@@ -0,0 +1,87 @@
/*
* 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.internal;

import org.sonar.api.scan.filesystem.InputFile;

import javax.annotation.Nullable;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
* FOR UNIT-TESTING ONLY
*
* @since 4.0
*/
public class InputFileBuilder {

private final Map<String, String> attributes = new HashMap<String, String>();
private final File file;
private final String relativePath;

public static void _FOR_UNIT_TESTING_ONLY_() {
// For those who don't read javadoc
}

public InputFileBuilder(File file, String relativePath) {
this.file = file;
this.relativePath = relativePath;
}

public InputFileBuilder attribute(String key, @Nullable String value) {
if (value != null) {
attributes.put(key, value);
}
return this;
}

public InputFileBuilder type(@Nullable String type) {
return attribute(InputFile.ATTRIBUTE_TYPE, type);
}

public InputFileBuilder extension(@Nullable String extension) {
return attribute(InputFile.ATTRIBUTE_EXTENSION, extension);
}

public InputFileBuilder language(@Nullable String language) {
return attribute(InputFile.ATTRIBUTE_LANGUAGE, language);
}

public InputFileBuilder hash(@Nullable String hash) {
return attribute(InputFile.ATTRIBUTE_HASH, hash);
}

public InputFileBuilder status(@Nullable String status) {
return attribute(InputFile.ATTRIBUTE_STATUS, status);
}

public InputFileBuilder sourceDir(File dir) {
return sourceDir(dir.getAbsolutePath());
}

public InputFileBuilder sourceDir(@Nullable String path) {
return attribute(InputFile.ATTRIBUTE_SOURCEDIR_PATH, path);
}

public DefaultInputFile build() {
return DefaultInputFile.create(file, relativePath, attributes);
}
}

+ 23
- 0
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/internal/package-info.java View File

@@ -0,0 +1,23 @@
/*
* 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.
*/
@ParametersAreNonnullByDefault
package org.sonar.api.scan.filesystem.internal;

import javax.annotation.ParametersAreNonnullByDefault;

+ 46
- 0
sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/InputFilesTest.java View File

@@ -0,0 +1,46 @@
/*
* 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 org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.scan.filesystem.internal.InputFileBuilder;

import java.io.File;

import static org.fest.assertions.Assertions.assertThat;

public class InputFilesTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void test_toFiles() throws Exception {
File file1 = temp.newFile();
File file2 = temp.newFile();
InputFile input1 = new InputFileBuilder(file1, "src/main/java/Foo.java").build();
InputFile input2 = new InputFileBuilder(file2, "src/main/java/Bar.java").build();

assertThat(InputFiles.toFiles(Lists.newArrayList(input1, input2))).containsOnly(file1, file2);
}
}

+ 0
- 96
sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/SimpleModuleFileSystem.java View File

@@ -1,96 +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.api.scan.filesystem;

import com.google.common.collect.Lists;
import org.apache.commons.lang.CharEncoding;

import java.io.File;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;

/**
* @since 3.5
*/
public class SimpleModuleFileSystem implements ModuleFileSystem {
private File baseDir;
private File buildDir;
private List<File> sourceDirs = Lists.newArrayList();
private List<File> testDirs = Lists.newArrayList();
private List<File> binaryDirs = Lists.newArrayList();

public SimpleModuleFileSystem(File baseDir) {
this.baseDir = baseDir;
this.buildDir = new File(baseDir, "build");
}

@Override
public String moduleKey() {
return null;
}

public File baseDir() {
return baseDir;
}

public File buildDir() {
return buildDir;
}

public List<File> sourceDirs() {
return sourceDirs;
}

public List<File> testDirs() {
return testDirs;
}

public List<File> binaryDirs() {
return binaryDirs;
}

public SimpleModuleFileSystem addSourceDir(File d) {
sourceDirs.add(d);
return this;
}

public SimpleModuleFileSystem addTestDir(File d) {
testDirs.add(d);
return this;
}

public SimpleModuleFileSystem addBinaryDir(File d) {
binaryDirs.add(d);
return this;
}

public List<File> files(FileQuery query) {
return Collections.emptyList();
}

public Charset sourceCharset() {
return Charset.forName(CharEncoding.UTF_8);
}

public File workingDir() {
return new File(baseDir, "work");
}
}

+ 92
- 0
sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/internal/DefaultInputFileTest.java View File

@@ -0,0 +1,92 @@
/*
* 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.internal;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.scan.filesystem.InputFile;

import java.io.File;
import java.io.IOException;

import static org.fest.assertions.Assertions.assertThat;

public class DefaultInputFileTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void test_attributes() throws IOException {
File file = temp.newFile();
InputFile input = new InputFileBuilder(file, "src/main/java/Foo.java")
.attribute("foo", "bar")
.type(InputFile.TYPE_TEST)
.extension("jav")
.hash("ABC")
.status(InputFile.STATUS_ADDED)
.language("java")
.build();

assertThat(input.attributes()).hasSize(6);
assertThat(input.attribute("unknown")).isNull();
assertThat(input.attribute("foo")).isEqualTo("bar");
assertThat(input.attribute(InputFile.ATTRIBUTE_TYPE)).isEqualTo(InputFile.TYPE_TEST);
assertThat(input.attribute(InputFile.ATTRIBUTE_EXTENSION)).isEqualTo("jav");
assertThat(input.attribute(InputFile.ATTRIBUTE_HASH)).isEqualTo("ABC");
assertThat(input.attribute(InputFile.ATTRIBUTE_LANGUAGE)).isEqualTo("java");
assertThat(input.attribute(InputFile.ATTRIBUTE_STATUS)).isEqualTo(InputFile.STATUS_ADDED);

assertThat(input.has(InputFile.ATTRIBUTE_LANGUAGE, "java")).isTrue();
assertThat(input.has(InputFile.ATTRIBUTE_LANGUAGE, "php")).isFalse();
assertThat(input.has("unknown", "xxx")).isFalse();
}

@Test
public void test_file() throws Exception {
File sourceDir = temp.newFolder();
File file = temp.newFile("Foo.java");
InputFile input = new InputFileBuilder(file, "src/main/java/Foo.java")
.sourceDir(sourceDir)
.build();

assertThat(input.name()).isEqualTo("Foo.java");
assertThat(input.file()).isEqualTo(file);
assertThat(input.attribute(InputFile.ATTRIBUTE_SOURCEDIR_PATH)).isEqualTo(sourceDir.getAbsolutePath());
assertThat(input.relativePath()).isEqualTo("src/main/java/Foo.java");
assertThat(input.path()).isEqualTo(file.getCanonicalPath());
}

@Test
public void test_equals_and_hashCode() throws Exception {
File file1 = temp.newFile();
InputFile input1 = new InputFileBuilder(file1, "src/main/java/Foo.java").build();
InputFile input1a = new InputFileBuilder(file1, "src/main/java/Foo.java").build();
InputFile input2 = new InputFileBuilder(temp.newFile(), "src/main/java/Bar.java").build();

assertThat(input1.equals(input1)).isTrue();
assertThat(input1.equals(input1a)).isTrue();
assertThat(input1.equals(input2)).isFalse();
assertThat(input1.hashCode()).isEqualTo(input1.hashCode());
assertThat(input1.hashCode()).isEqualTo(input1a.hashCode());

}
}

+ 30
- 0
sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/internal/InputFileBuilderTest.java View File

@@ -0,0 +1,30 @@
/*
* 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.internal;

import org.junit.Test;

public class InputFileBuilderTest {
@Test
public void just_for_coverage() throws Exception {
InputFileBuilder._FOR_UNIT_TESTING_ONLY_();
// do not fail
}
}

Loading…
Cancel
Save