ソースを参照

SONAR-5389 New Analyzer API

tags/4.4-RC1
Julien HENRY 10年前
コミット
d35dc73824
100個のファイルの変更2860行の追加456行の削除
  1. 19
    19
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/UserManagedMetrics.java
  2. 2
    2
      plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/FileHashSensor.java
  3. 5
    5
      plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/FileHashSensorTest.java
  4. 3
    3
      plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java
  5. 3
    3
      plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarEngine.java
  6. 4
    4
      plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarEngineTest.java
  7. 6
    0
      pom.xml
  8. 34
    0
      sonar-batch-plugin-api/pom.xml
  9. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/FilePredicate.java
  10. 2
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/FilePredicates.java
  11. 2
    1
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/FileSystem.java
  12. 1
    1
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java
  13. 1
    1
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFileFilter.java
  14. 2
    2
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbsolutePathPredicate.java
  15. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AndPredicate.java
  16. 10
    2
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFilePredicates.java
  17. 59
    62
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java
  18. 8
    87
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
  19. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FalsePredicate.java
  20. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/LanguagePredicate.java
  21. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/NotPredicate.java
  22. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/OrPredicate.java
  23. 3
    3
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPattern.java
  24. 0
    1
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPatternPredicate.java
  25. 6
    12
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/RelativePathPredicate.java
  26. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/StatusPredicate.java
  27. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TruePredicate.java
  28. 0
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TypePredicate.java
  29. 1
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/package-info.java
  30. 1
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/package-info.java
  31. 29
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/BatchComponent.java
  32. 6
    7
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/BatchExtension.java
  33. 46
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/InstantiationStrategy.java
  34. 51
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/Analyzer.java
  35. 80
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/AnalyzerContext.java
  36. 107
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/AnalyzerDescriptor.java
  37. 126
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/issue/AnalyzerIssue.java
  38. 21
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/issue/package-info.java
  39. 129
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/measure/AnalyzerMeasure.java
  40. 21
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/measure/package-info.java
  41. 21
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/package-info.java
  42. 244
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/FilenameUtils.java
  43. 413
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/Preconditions.java
  44. 140
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/StringUtils.java
  45. 205
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/WildcardPattern.java
  46. 21
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/package-info.java
  47. 57
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/languages/Language.java
  48. 21
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/languages/package-info.java
  49. 29
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/measures/Metric.java
  50. 21
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/measures/package-info.java
  51. 43
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/rules/QProfile.java
  52. 90
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/rules/RuleKey.java
  53. 21
    0
      sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/rules/package-info.java
  54. 12
    14
      sonar-batch-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultFilePredicatesTest.java
  55. 2
    3
      sonar-batch-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultFileSystemTest.java
  56. 1
    5
      sonar-batch-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java
  57. 0
    0
      sonar-batch-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/PathPatternTest.java
  58. 4
    0
      sonar-batch/pom.xml
  59. 8
    3
      sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java
  60. 9
    0
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalysisMode.java
  61. 2
    8
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
  62. 18
    4
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java
  63. 13
    4
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java
  64. 6
    7
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java
  65. 6
    1
      sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
  66. 2
    2
      sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java
  67. 1
    1
      sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
  68. 3
    3
      sonar-batch/src/main/java/org/sonar/batch/index/ResourceKeyMigration.java
  69. 21
    2
      sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java
  70. 13
    3
      sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
  71. 2
    2
      sonar-batch/src/main/java/org/sonar/batch/issue/ignore/scanner/IssueExclusionsLoader.java
  72. 2
    2
      sonar-batch/src/main/java/org/sonar/batch/language/LanguageDistributionDecorator.java
  73. 63
    0
      sonar-batch/src/main/java/org/sonar/batch/languages/DeprecatedLanguagesReferential.java
  74. 17
    10
      sonar-batch/src/main/java/org/sonar/batch/languages/LanguagesReferential.java
  75. 20
    0
      sonar-batch/src/main/java/org/sonar/batch/languages/package-info.java
  76. 4
    3
      sonar-batch/src/main/java/org/sonar/batch/phases/SensorMatcher.java
  77. 6
    3
      sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java
  78. 12
    52
      sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java
  79. 9
    10
      sonar-batch/src/main/java/org/sonar/batch/rule/QProfileEventsDecorator.java
  80. 4
    3
      sonar-batch/src/main/java/org/sonar/batch/rule/QProfileSensor.java
  81. 1
    1
      sonar-batch/src/main/java/org/sonar/batch/rule/QProfileVerifier.java
  82. 5
    4
      sonar-batch/src/main/java/org/sonar/batch/rule/RulesProfileProvider.java
  83. 12
    12
      sonar-batch/src/main/java/org/sonar/batch/rule/UsedQProfiles.java
  84. 46
    0
      sonar-batch/src/main/java/org/sonar/batch/rules/DefaultQProfileReferential.java
  85. 10
    13
      sonar-batch/src/main/java/org/sonar/batch/rules/QProfileWithId.java
  86. 39
    0
      sonar-batch/src/main/java/org/sonar/batch/rules/QProfilesReferential.java
  87. 21
    0
      sonar-batch/src/main/java/org/sonar/batch/rules/package-info.java
  88. 169
    0
      sonar-batch/src/main/java/org/sonar/batch/scan/AnalyzerContextAdaptor.java
  89. 4
    5
      sonar-batch/src/main/java/org/sonar/batch/scan/LanguageVerifier.java
  90. 11
    1
      sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
  91. 17
    25
      sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
  92. 8
    1
      sonar-batch/src/main/java/org/sonar/batch/scan/ScanTask.java
  93. 78
    0
      sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java
  94. 5
    5
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/AdditionalFilePredicates.java
  95. 2
    2
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java
  96. 22
    6
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java
  97. 3
    3
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileFilters.java
  98. 28
    13
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java
  99. 5
    5
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilder.java
  100. 0
    0
      sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilderFactory.java

+ 19
- 19
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/UserManagedMetrics.java ファイルの表示

@@ -29,24 +29,24 @@ public final class UserManagedMetrics implements Metrics {
private static final String DOMAIN = "Management";

public List<Metric> getMetrics() {
return ImmutableList.of(
new Metric.Builder("burned_budget", "Burned budget", Metric.ValueType.FLOAT)
.setDirection(Metric.DIRECTION_NONE)
.setQualitative(false)
.setDomain(DOMAIN)
.setUserManaged(true)
.create(),
new Metric.Builder("business_value", "Business value", Metric.ValueType.FLOAT)
.setDirection(Metric.DIRECTION_BETTER)
.setQualitative(true)
.setDomain(DOMAIN)
.setUserManaged(true)
.create(),
new Metric.Builder("team_size", "Team size", Metric.ValueType.INT)
.setDirection(Metric.DIRECTION_NONE)
.setQualitative(false)
.setDomain(DOMAIN)
.setUserManaged(true)
.create());
return ImmutableList.<Metric>of(
new Metric.Builder("burned_budget", "Burned budget", Metric.ValueType.FLOAT)
.setDirection(Metric.DIRECTION_NONE)
.setQualitative(false)
.setDomain(DOMAIN)
.setUserManaged(true)
.create(),
new Metric.Builder("business_value", "Business value", Metric.ValueType.FLOAT)
.setDirection(Metric.DIRECTION_BETTER)
.setQualitative(true)
.setDomain(DOMAIN)
.setUserManaged(true)
.create(),
new Metric.Builder("team_size", "Team size", Metric.ValueType.INT)
.setDirection(Metric.DIRECTION_NONE)
.setQualitative(false)
.setDomain(DOMAIN)
.setUserManaged(true)
.create());
}
}

+ 2
- 2
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/FileHashSensor.java ファイルの表示

@@ -23,7 +23,7 @@ import com.google.common.collect.Maps;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
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.api.resources.Project;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.batch.index.ComponentDataCache;
@@ -59,7 +59,7 @@ 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 hash = ((DefaultInputFile) inputFile).hash();
String hash = ((DeprecatedDefaultInputFile) inputFile).hash();
if (hash != null) {
map.put(inputFile.relativePath(), hash);
}

+ 5
- 5
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/FileHashSensorTest.java ファイルの表示

@@ -28,7 +28,7 @@ import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.SensorContext;
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.api.resources.Project;
import org.sonar.batch.index.ComponentDataCache;
import org.sonar.batch.scan.filesystem.InputFileCache;
@@ -58,8 +58,8 @@ public class FileHashSensorTest {
@Test
public void store_file_hashes() throws Exception {
when(fileCache.byModule("struts")).thenReturn(Lists.<InputFile>newArrayList(
new DefaultInputFile("src/Foo.java").setFile(temp.newFile()).setHash("ABC"),
new DefaultInputFile("src/Bar.java").setFile(temp.newFile()).setHash("DEF")));
new DeprecatedDefaultInputFile("src/Foo.java").setFile(temp.newFile()).setHash("ABC"),
new DeprecatedDefaultInputFile("src/Bar.java").setFile(temp.newFile()).setHash("DEF")));

SensorContext sensorContext = mock(SensorContext.class);
sensor.analyse(project, sensorContext);
@@ -72,8 +72,8 @@ public class FileHashSensorTest {
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(
new DefaultInputFile("src/Foo.java").setFile(temp.newFile()).setHash("ABC"),
new DefaultInputFile("src/Bar.java").setFile(temp.newFile()).setHash("DEF")));
new DeprecatedDefaultInputFile("src/Foo.java").setFile(temp.newFile()).setHash("ABC"),
new DeprecatedDefaultInputFile("src/Bar.java").setFile(temp.newFile()).setHash("DEF")));

SensorContext sensorContext = mock(SensorContext.class);
sensor.analyse(project, sensorContext);

+ 3
- 3
plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java ファイルの表示

@@ -31,7 +31,7 @@ import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;
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.api.config.Settings;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.SonarException;
@@ -106,7 +106,7 @@ public class SonarBridgeEngine extends CpdEngine {
TokenizerBridge bridge = new TokenizerBridge(mapping.getTokenizer(), fs.encoding().name(), getBlockSize(project, languageKey));
for (InputFile inputFile : sourceFiles) {
LOG.debug("Populating index from {}", inputFile);
String resourceEffectiveKey = ((DefaultInputFile) inputFile).key();
String resourceEffectiveKey = ((DeprecatedDefaultInputFile) inputFile).key();
List<Block> blocks = bridge.chunk(resourceEffectiveKey, inputFile.file());
index.insert(inputFile, blocks);
}
@@ -118,7 +118,7 @@ public class SonarBridgeEngine extends CpdEngine {
try {
for (InputFile inputFile : sourceFiles) {
LOG.debug("Detection of duplications for {}", inputFile);
String resourceEffectiveKey = ((DefaultInputFile) inputFile).key();
String resourceEffectiveKey = ((DeprecatedDefaultInputFile) inputFile).key();
Collection<Block> fileBlocks = index.getByInputFile(inputFile, resourceEffectiveKey);

Iterable<CloneGroup> filtered;

+ 3
- 3
plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarEngine.java ファイルの表示

@@ -31,7 +31,7 @@ import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;
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.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
@@ -115,7 +115,7 @@ public class SonarEngine extends CpdEngine {

for (InputFile inputFile : sourceFiles) {
LOG.debug("Populating index from {}", inputFile);
String resourceEffectiveKey = ((DefaultInputFile) inputFile).key();
String resourceEffectiveKey = ((DeprecatedDefaultInputFile) inputFile).key();

List<Statement> statements;

@@ -141,7 +141,7 @@ public class SonarEngine extends CpdEngine {
try {
for (InputFile inputFile : sourceFiles) {
LOG.debug("Detection of duplications for {}", inputFile);
String resourceEffectiveKey = ((DefaultInputFile) inputFile).key();
String resourceEffectiveKey = ((DeprecatedDefaultInputFile) inputFile).key();

Collection<Block> fileBlocks = index.getByInputFile(inputFile, resourceEffectiveKey);


+ 4
- 4
plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarEngineTest.java ファイルの表示

@@ -25,7 +25,7 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.SensorContext;
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.api.measures.CoreMetrics;
import org.sonar.api.test.IsMeasure;
import org.sonar.duplications.index.CloneGroup;
@@ -46,11 +46,11 @@ public class SonarEngineTest {
public TemporaryFolder temp = new TemporaryFolder();

SensorContext context = mock(SensorContext.class);
DefaultInputFile inputFile;
DeprecatedDefaultInputFile inputFile;

@Before
public void before() throws IOException {
inputFile = new DefaultInputFile("src/main/java/Foo.java");
inputFile = new DeprecatedDefaultInputFile("src/main/java/Foo.java");
inputFile.setFile(temp.newFile("Foo.java"));
}

@@ -138,7 +138,7 @@ public class SonarEngineTest {

@Test
public void shouldEscapeXmlEntities() throws IOException {
InputFile csharpFile = new DefaultInputFile("Loads/File Loads/Subs & Reds/SubsRedsDelivery.cs")
InputFile csharpFile = new DeprecatedDefaultInputFile("Loads/File Loads/Subs & Reds/SubsRedsDelivery.cs")
.setFile(temp.newFile("SubsRedsDelivery.cs"));
List<CloneGroup> groups = Arrays.asList(newCloneGroup(
new ClonePart("Loads/File Loads/Subs & Reds/SubsRedsDelivery.cs", 0, 5, 204),

+ 6
- 0
pom.xml ファイルの表示

@@ -14,6 +14,7 @@
<modules>
<module>sonar-application</module>
<module>sonar-batch</module>
<module>sonar-batch-plugin-api</module>
<module>sonar-batch-maven-compat</module>
<module>sonar-check-api</module>
<module>sonar-colorizer</module>
@@ -574,6 +575,11 @@
<artifactId>sonar-plugin-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-batch-plugin-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-update-center-common</artifactId>

+ 34
- 0
sonar-batch-plugin-api/pom.xml ファイルの表示

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar</artifactId>
<version>4.4-SNAPSHOT</version>
</parent>

<artifactId>sonar-batch-plugin-api</artifactId>
<packaging>jar</packaging>

<name>SonarQube :: Batch Plugin API</name>
<dependencies>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
</dependency>
</dependencies>


</project>

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/FilePredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/FilePredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/FilePredicates.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/FilePredicates.java ファイルの表示

@@ -64,6 +64,8 @@ public interface FilePredicates {

FilePredicate hasLanguages(Collection<String> languages);

FilePredicate hasLanguages(String... languages);

FilePredicate hasStatus(InputFile.Status status);

FilePredicate hasType(InputFile.Type type);

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/FileSystem.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/FileSystem.java ファイルの表示

@@ -19,9 +19,10 @@
*/
package org.sonar.api.batch.fs;

import org.sonar.api.BatchComponent;
import org.sonar.batch.api.BatchComponent;

import javax.annotation.CheckForNull;

import java.io.File;
import java.nio.charset.Charset;
import java.util.SortedSet;

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFile.java ファイルの表示

@@ -33,7 +33,7 @@ public interface InputFile extends Serializable {
MAIN, TEST
}

/**
/**
* Status regarding previous analysis
*/
enum Status {

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFileFilter.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFileFilter.java ファイルの表示

@@ -19,7 +19,7 @@
*/
package org.sonar.api.batch.fs;

import org.sonar.api.BatchExtension;
import org.sonar.batch.api.BatchExtension;

/**
* Extension point to exclude some files from inspection

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbsolutePathPredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbsolutePathPredicate.java ファイルの表示

@@ -19,9 +19,9 @@
*/
package org.sonar.api.batch.fs.internal;

import org.apache.commons.io.FilenameUtils;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.batch.api.internal.FilenameUtils;

/**
* @since 4.2
@@ -31,7 +31,7 @@ class AbsolutePathPredicate implements FilePredicate {
private final String path;

AbsolutePathPredicate(String path) {
this.path = FilenameUtils.normalize(path, true);
this.path = FilenameUtils.normalize(path);
}

@Override

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AndPredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AndPredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFilePredicates.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFilePredicates.java ファイルの表示

@@ -19,12 +19,12 @@
*/
package org.sonar.api.batch.fs.internal;

import com.google.common.collect.Lists;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.InputFile;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -115,7 +115,15 @@ public class DefaultFilePredicates implements FilePredicates {
}

public FilePredicate hasLanguages(Collection<String> languages) {
List<FilePredicate> list = Lists.newArrayList();
List<FilePredicate> list = new ArrayList<FilePredicate>();
for (String language : languages) {
list.add(hasLanguage(language));
}
return or(list);
}

public FilePredicate hasLanguages(String... languages) {
List<FilePredicate> list = new ArrayList<FilePredicate>();
for (String language : languages) {
list.add(hasLanguage(language));
}

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java ファイルの表示

@@ -19,27 +19,25 @@
*/
package org.sonar.api.batch.fs.internal;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
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.InputFile;
import org.sonar.batch.api.internal.Preconditions;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.TreeSet;

/**
* @since 4.2
@@ -47,7 +45,7 @@ import java.util.SortedSet;
public class DefaultFileSystem implements FileSystem {

private final Cache cache;
private final SortedSet<String> languages = Sets.newTreeSet();
private final SortedSet<String> languages = new TreeSet<String>();
private File baseDir, workDir;
private Charset encoding;
private final FilePredicates predicates = new DefaultFilePredicates();
@@ -101,39 +99,70 @@ public class DefaultFileSystem implements FileSystem {
@Override
public InputFile inputFile(FilePredicate predicate) {
doPreloadFiles();
if (predicate instanceof UniqueIndexPredicate) {
return cache.inputFile((UniqueIndexPredicate) predicate);
if (predicate instanceof RelativePathPredicate) {
return cache.inputFile((RelativePathPredicate) predicate);
}
try {
Iterable<InputFile> files = inputFiles(predicate);
return Iterables.getOnlyElement(files);
} catch (NoSuchElementException e) {
// contrary to guava, return null if iterable is empty
Iterable<InputFile> files = inputFiles(predicate);
Iterator<InputFile> iterator = files.iterator();
if (!iterator.hasNext()) {
return null;
}
InputFile first = iterator.next();
if (!iterator.hasNext()) {
return first;
}

StringBuilder sb = new StringBuilder();
sb.append("expected one element but was: <" + first);
for (int i = 0; i < 4 && iterator.hasNext(); i++) {
sb.append(", " + iterator.next());
}
if (iterator.hasNext()) {
sb.append(", ...");
}
sb.append('>');

throw new IllegalArgumentException(sb.toString());

}

@Override
public Iterable<InputFile> inputFiles(FilePredicate predicate) {
doPreloadFiles();
return Iterables.filter(cache.inputFiles(), new GuavaPredicate(predicate));
return filter(cache.inputFiles(), predicate);
}

@Override
public boolean hasFiles(FilePredicate predicate) {
doPreloadFiles();
return Iterables.indexOf(cache.inputFiles(), new GuavaPredicate(predicate)) >= 0;
for (InputFile element : cache.inputFiles()) {
if (predicate.apply(element)) {
return true;
}
}
return false;
}

@Override
public Iterable<File> files(FilePredicate predicate) {
doPreloadFiles();
return Iterables.transform(inputFiles(predicate), new Function<InputFile, File>() {
@Override
public File apply(@Nullable InputFile input) {
return input == null ? null : input.file();
Collection<File> result = new ArrayList<File>();
for (InputFile element : inputFiles(predicate)) {
if (predicate.apply(element)) {
result.add(element.file());
}
});
}
return result;
}

public static Collection<InputFile> filter(Iterable<InputFile> target, FilePredicate predicate) {
Collection<InputFile> result = new ArrayList<InputFile>();
for (InputFile element : target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}

/**
@@ -179,17 +208,12 @@ public class DefaultFileSystem implements FileSystem {
protected abstract Iterable<InputFile> inputFiles();

@CheckForNull
protected abstract InputFile inputFile(UniqueIndexPredicate predicate);
protected abstract InputFile inputFile(RelativePathPredicate predicate);

protected abstract void doAdd(InputFile inputFile);

protected abstract void doIndex(String indexId, Object value, InputFile inputFile);

final void add(InputFile inputFile) {
doAdd(inputFile);
for (FileIndex index : FileIndex.ALL) {
doIndex(index.id(), index.valueOf(inputFile), inputFile);
}
}
}

@@ -197,49 +221,22 @@ public class DefaultFileSystem implements FileSystem {
* Used only for testing
*/
private static class MapCache extends Cache {
private final List<InputFile> files = Lists.newArrayList();
private final Map<String, Map<Object, InputFile>> fileMap = Maps.newHashMap();
private final Map<String, InputFile> fileMap = new HashMap<String, InputFile>();

@Override
public Iterable<InputFile> inputFiles() {
return Lists.newArrayList(files);
return new ArrayList<InputFile>(fileMap.values());
}

@Override
public InputFile inputFile(UniqueIndexPredicate predicate) {
Map<Object, InputFile> byAttr = fileMap.get(predicate.indexId());
if (byAttr != null) {
return byAttr.get(predicate.value());
}
return null;
public InputFile inputFile(RelativePathPredicate predicate) {
return fileMap.get(predicate.path());
}

@Override
protected void doAdd(InputFile inputFile) {
files.add(inputFile);
}

@Override
protected void doIndex(String indexId, Object value, InputFile inputFile) {
Map<Object, InputFile> attrValues = fileMap.get(indexId);
if (attrValues == null) {
attrValues = Maps.newHashMap();
fileMap.put(indexId, attrValues);
}
attrValues.put(value, inputFile);
fileMap.put(inputFile.relativePath(), inputFile);
}
}

private static class GuavaPredicate implements Predicate<InputFile> {
private final FilePredicate predicate;

private GuavaPredicate(FilePredicate predicate) {
this.predicate = predicate;
}

@Override
public boolean apply(@Nullable InputFile input) {
return input != null && predicate.apply(input);
}
}
}

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java ファイルの表示

@@ -19,17 +19,18 @@
*/
package org.sonar.api.batch.fs.internal;

import org.apache.commons.io.FilenameUtils;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.utils.PathUtils;
import org.sonar.batch.api.internal.FilenameUtils;

import javax.annotation.CheckForNull;
import java.io.*;

import java.io.File;
import java.io.Serializable;

/**
* @since 4.2
*/
public class DefaultInputFile implements InputFile, org.sonar.api.resources.InputFile, Serializable {
public class DefaultInputFile implements InputFile, Serializable {

private final String relativePath;
private String absolutePath;
@@ -39,13 +40,9 @@ public class DefaultInputFile implements InputFile, org.sonar.api.resources.Inpu
private String hash;
private int lines;
private String key;
private String deprecatedKey;
private String sourceDirAbsolutePath;
private String pathRelativeToSourceDir;
private String basedir;

public DefaultInputFile(String relativePath) {
this.relativePath = FilenameUtils.normalize(relativePath, true);
this.relativePath = FilenameUtils.normalize(relativePath);
}

@Override
@@ -120,7 +117,7 @@ public class DefaultInputFile implements InputFile, org.sonar.api.resources.Inpu
}

public DefaultInputFile setAbsolutePath(String s) {
this.absolutePath = FilenameUtils.normalize(s, true);
this.absolutePath = FilenameUtils.normalize(s);
return this;
}

@@ -159,85 +156,12 @@ public class DefaultInputFile implements InputFile, org.sonar.api.resources.Inpu
return this;
}

/**
* Key used before version 4.2. It can be different than {@link #key} on Java files.
*/
public String deprecatedKey() {
return deprecatedKey;
}

public DefaultInputFile setDeprecatedKey(String s) {
this.deprecatedKey = s;
return this;
}

/**
* Used only for backward-compatibility. Meaningless since version 4.2.
*/
public String sourceDirAbsolutePath() {
return sourceDirAbsolutePath;
}

public DefaultInputFile setSourceDirAbsolutePath(String s) {
this.sourceDirAbsolutePath = FilenameUtils.normalize(s, true);
return this;
}

/**
* Used only for backward-compatibility. Meaningless since version 4.2.
*/

public String pathRelativeToSourceDir() {
return pathRelativeToSourceDir;
}

public DefaultInputFile setPathRelativeToSourceDir(String s) {
this.pathRelativeToSourceDir = FilenameUtils.normalize(s, true);
return this;
}

/**
* @deprecated in 4.2. Replaced by {@link org.sonar.api.batch.fs.FileSystem#baseDir()}
*/
@Deprecated
@Override
public File getFileBaseDir() {
return new File(basedir);
}

public void setBasedir(File basedir) {
this.basedir = PathUtils.sanitize(basedir.getAbsolutePath());
}

/**
* @deprecated in 4.2. Use {@link #file()}
*/
@Deprecated
@Override
public File getFile() {
return file();
}

/**
* @deprecated in 4.2. Use {@link #relativePath()}
*/
@Deprecated
@Override
public String getRelativePath() {
return pathRelativeToSourceDir;
}

@Override
public InputStream getInputStream() throws FileNotFoundException {
return new BufferedInputStream(new FileInputStream(file()));
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if (!(o instanceof DefaultInputFile)) {
return false;
}

@@ -255,6 +179,3 @@ public class DefaultInputFile implements InputFile, org.sonar.api.resources.Inpu
return "[relative=" + relativePath + ", abs=" + absolutePath + "]";
}
}




sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FalsePredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FalsePredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/LanguagePredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/LanguagePredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/NotPredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/NotPredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/OrPredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/OrPredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPattern.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPattern.java ファイルの表示

@@ -19,10 +19,10 @@
*/
package org.sonar.api.batch.fs.internal;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.utils.WildcardPattern;
import org.sonar.batch.api.internal.FilenameUtils;
import org.sonar.batch.api.internal.StringUtils;
import org.sonar.batch.api.internal.WildcardPattern;

public abstract class PathPattern {


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPatternPredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/PathPatternPredicate.java ファイルの表示

@@ -21,7 +21,6 @@ package org.sonar.api.batch.fs.internal;

import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.PathPattern;

/**
* @since 4.2

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/RelativePathPredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/RelativePathPredicate.java ファイルの表示

@@ -19,34 +19,28 @@
*/
package org.sonar.api.batch.fs.internal;

import org.apache.commons.io.FilenameUtils;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.batch.api.internal.FilenameUtils;

/**
* @since 4.2
*/
class RelativePathPredicate implements FilePredicate, UniqueIndexPredicate {
public class RelativePathPredicate implements FilePredicate {

private final String path;

RelativePathPredicate(String path) {
this.path = FilenameUtils.normalize(path, true);
this.path = FilenameUtils.normalize(path);
}

@Override
public boolean apply(InputFile f) {
return path.equals(f.relativePath());
}

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

@Override
public String indexId() {
return RelativePathIndex.ID;
public boolean apply(InputFile f) {
return path.equals(f.relativePath());
}

}

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/StatusPredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/StatusPredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TruePredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TruePredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TypePredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/TypePredicate.java ファイルの表示


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/package-info.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/package-info.java ファイルの表示

@@ -21,3 +21,4 @@
package org.sonar.api.batch.fs.internal;

import javax.annotation.ParametersAreNonnullByDefault;


sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/package-info.java → sonar-batch-plugin-api/src/main/java/org/sonar/api/batch/fs/package-info.java ファイルの表示

@@ -21,3 +21,4 @@
package org.sonar.api.batch.fs;

import javax.annotation.ParametersAreNonnullByDefault;


+ 29
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/BatchComponent.java ファイルの表示

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

/**
* Dependency Injection : all the classes implementing this interface are available in the batch IoC container.
* Just add a parameter to the constructor of your component.
*
* @since 4.4
*/
public interface BatchComponent {
}

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/UniqueIndexPredicate.java → sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/BatchExtension.java ファイルの表示

@@ -17,15 +17,14 @@
* 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;
package org.sonar.batch.api;


/**
* @since 4.2
* Batch extension point.
*
* @since 4.4
*/
public interface UniqueIndexPredicate {

String indexId();

Object value();
public interface BatchExtension extends BatchComponent {

}

+ 46
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/InstantiationStrategy.java ファイルの表示

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

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Define instantiation strategy of batch extensions. If an extension is not annotated, then default value
* is {@link #PER_PROJECT}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface InstantiationStrategy {

/**
* Shared extension. Lifecycle is the full analysis.
*/
String PER_BATCH = "PER_BATCH";

/**
* Created and initialized for each project and sub-project (a project is a module in Maven terminology).
*/
String PER_PROJECT = "PER_PROJECT";

String value();
}

+ 51
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/Analyzer.java ファイルの表示

@@ -0,0 +1,51 @@
/*
* 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.api.analyzer;

import org.sonar.batch.api.BatchExtension;

/**
* <p>
* An Analyzer is invoked once during the analysis of a project. The analyzer can parse a flat file, connect to a web server... Analyzers are
* used to add measure and issues at file level.
* </p>
*
* <p>
* For example the Cobertura Analyzer parses Cobertura report and saves the first-level of measures on files.
* </p>
*
* @since 4.4
*/
public interface Analyzer extends BatchExtension {

/**
* Describe what this analyzer is doing.
* @return
*/
AnalyzerDescriptor describe();

/**
* The method that is going to be run when the analyzer is called
*
* @param context the context
*/
void analyse(AnalyzerContext context);

}

+ 80
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/AnalyzerContext.java ファイルの表示

@@ -0,0 +1,80 @@
/*
* 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.api.analyzer;

import org.sonar.api.batch.fs.InputFile;
import org.sonar.batch.api.analyzer.issue.AnalyzerIssue;
import org.sonar.batch.api.analyzer.measure.AnalyzerMeasure;
import org.sonar.batch.api.measures.Metric;

import javax.annotation.CheckForNull;

import java.io.Serializable;
import java.util.Collection;

/**
* @since 4.4
*/
public interface AnalyzerContext {

// ----------- MEASURES --------------

/**
* Find a project measure.
*/
@CheckForNull
AnalyzerMeasure<?> getMeasure(String metricKey);

/**
* Find a project measure.
*/
@CheckForNull
<G extends Serializable> AnalyzerMeasure<G> getMeasure(Metric<G> metric);

/**
* Find a file measure.
*/
@CheckForNull
AnalyzerMeasure<?> getMeasure(InputFile file, String metricKey);

/**
* Find a file measure.
*/
@CheckForNull
<G extends Serializable> AnalyzerMeasure<G> getMeasure(InputFile file, Metric<G> metric);

/**
* Add a measure.
*/
void addMeasure(AnalyzerMeasure<?> measure);

// ----------- ISSUES --------------

/**
* Add an issue.
*/
void addIssue(AnalyzerIssue issue);

/**
* Add a list of issues.
*/
void addIssues(Collection<AnalyzerIssue> issues);

}

+ 107
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/AnalyzerDescriptor.java ファイルの表示

@@ -0,0 +1,107 @@
/*
* 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.api.analyzer;

import org.sonar.api.batch.fs.InputFile;
import org.sonar.batch.api.measures.Metric;

import java.util.Arrays;
import java.util.Collection;

public class AnalyzerDescriptor {

private final String name;
private final Metric<?>[] dependsOn;
private final Metric<?>[] provides;
private final String[] languages;
private final InputFile.Type[] types;

private AnalyzerDescriptor(Builder builder) {
this.name = builder.name;
this.dependsOn = builder.dependsOn != null ? builder.dependsOn : new Metric<?>[0];
this.provides = builder.provides != null ? builder.provides : new Metric<?>[0];
this.languages = builder.languages != null ? builder.languages : new String[0];
this.types = builder.types;
}

public String name() {
return name;
}

public Metric<?>[] dependsOn() {
return dependsOn;
}

public Metric<?>[] provides() {
return provides;
}

public Collection<String> languages() {
return Arrays.asList(languages);
}

public InputFile.Type[] types() {
return types;
}

public static Builder builder() {
return new Builder();
}

public static class Builder {

private String name;
private Metric<?>[] dependsOn;
private Metric<?>[] provides;
private String[] languages;
private InputFile.Type[] types;

public Builder name(String name) {
this.name = name;
return this;
}

public Builder dependsOn(Metric<?>... metrics) {
this.dependsOn = metrics;
return this;
}

public Builder provides(Metric<?>... metrics) {
this.provides = metrics;
return this;
}

public Builder runOnLanguages(String... languageKeys) {
this.languages = languageKeys;
return this;
}

public Builder runOnTypes(InputFile.Type... types) {
this.types = types;
return this;
}

public AnalyzerDescriptor build() {
return new AnalyzerDescriptor(this);
}

}

}

+ 126
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/issue/AnalyzerIssue.java ファイルの表示

@@ -0,0 +1,126 @@
/*
* 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.api.analyzer.issue;

import org.sonar.api.batch.fs.InputFile;
import org.sonar.batch.api.analyzer.Analyzer;
import org.sonar.batch.api.internal.Preconditions;
import org.sonar.batch.api.rules.RuleKey;

import javax.annotation.Nullable;

/**
* Issue reported by an {@link Analyzer}
*
* @since 4.4
*/
public class AnalyzerIssue {

private final InputFile inputFile;
private final RuleKey ruleKey;
private final String message;
private final Integer line;
private final Double effortToFix;

private AnalyzerIssue(Builder builder) {
this.inputFile = builder.file;
this.ruleKey = builder.ruleKey;
this.message = builder.message;
this.line = builder.line;
this.effortToFix = builder.effortToFix;
}

public static Builder builder() {
return new Builder();
}

@Nullable
public InputFile inputFile() {
return inputFile;
}

public RuleKey ruleKey() {
return ruleKey;
}

public String message() {
return message;
}

public Integer line() {
return line;
}

@Nullable
public Double effortToFix() {
return effortToFix;
}

public static class Builder {

private Boolean onProject = null;
private InputFile file;
private RuleKey ruleKey;
private String message;
private Integer line;
private Double effortToFix;

public AnalyzerIssue build() {
return new AnalyzerIssue(this);
}

public Builder ruleKey(RuleKey ruleKey) {
this.ruleKey = ruleKey;
return this;
}

public Builder onFile(InputFile file) {
Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
Preconditions.checkNotNull(file, "InputFile should be non null");
this.file = file;
this.onProject = false;
return this;
}

public Builder onProject() {
Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
this.file = null;
this.onProject = true;
return this;
}

public Builder atLine(int line) {
this.line = line;
return this;
}

public Builder effortToFix(@Nullable Double effortToFix) {
this.effortToFix = effortToFix;
return this;
}

public Builder message(String message) {
this.message = message;
return this;
}

}

}

+ 21
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/issue/package-info.java ファイルの表示

@@ -0,0 +1,21 @@
/*
* 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.
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.batch.api.analyzer.issue;

+ 129
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/measure/AnalyzerMeasure.java ファイルの表示

@@ -0,0 +1,129 @@
/*
* 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.api.analyzer.measure;

import org.sonar.api.batch.fs.InputFile;
import org.sonar.batch.api.internal.Preconditions;
import org.sonar.batch.api.measures.Metric;

import javax.annotation.Nullable;

import java.io.Serializable;

public class AnalyzerMeasure<G extends Serializable> implements Serializable {

private final InputFile inputFile;
private final String metricKey;
private final G value;

private AnalyzerMeasure(Builder<G> builder) {
Preconditions.checkNotNull(builder.value, "Measure value can't be null");
Preconditions.checkNotNull(builder.metricKey, "Measure metricKey can't be null");
this.inputFile = builder.file;
this.metricKey = builder.metricKey;
this.value = builder.value;
}

@Nullable
public InputFile inputFile() {
return inputFile;
}

public String metricKey() {
return metricKey;
}

public Serializable value() {
return value;
}

public static <G extends Serializable> Builder<G> builder() {
return new Builder<G>();
}

public static class Builder<G extends Serializable> {

private Boolean onProject = null;
private InputFile file;
private String metricKey;
private G value;

public Builder<G> onFile(InputFile file) {
Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
Preconditions.checkNotNull(file, "InputFile should be non null");
this.file = file;
this.onProject = false;
return this;
}

public Builder<G> onProject() {
Preconditions.checkState(onProject == null, "onFile or onProject can be called only once");
this.file = null;
this.onProject = true;
return this;
}

private Builder<G> metricKey(String metricKey) {
Preconditions.checkState(metricKey != null, "Metric already defined");
this.metricKey = metricKey;
return this;
}

public Builder<G> forMetric(Metric<G> metric) {
return metricKey(metric.key());
}

public Builder<G> withValue(G value) {
Preconditions.checkState(value != null, "Measure value already defined");
Preconditions.checkNotNull(value, "Measure value can't be null");
this.value = value;
return this;
}

public AnalyzerMeasure<G> build() {
return new AnalyzerMeasure<G>(this);
}
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof AnalyzerMeasure)) {
return false;
}
AnalyzerMeasure<?> other = (AnalyzerMeasure<?>) obj;
return metricKey.equals(other.metricKey)
&& value.equals(other.value)
&& (inputFile == null ? other.inputFile == null : inputFile.equals(other.inputFile));
}

@Override
public int hashCode() {
return metricKey.hashCode()
+ value.hashCode()
+ (inputFile != null ? inputFile.hashCode() : 0);
}

@Override
public String toString() {
return "AnalyzerMeasure[" + (inputFile != null ? "inputFile=" + inputFile.toString() : "onProject")
+ ",metricKey=" + metricKey + ",value=" + value + "]";
}

}

+ 21
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/measure/package-info.java ファイルの表示

@@ -0,0 +1,21 @@
/*
* 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.
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.batch.api.analyzer.measure;

+ 21
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/analyzer/package-info.java ファイルの表示

@@ -0,0 +1,21 @@
/*
* 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.
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.batch.api.analyzer;

+ 244
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/FilenameUtils.java ファイルの表示

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

import java.io.File;

/**
* Copied from commons io
*
*/
public class FilenameUtils {

public static final char EXTENSION_SEPARATOR = '.';

private static final char UNIX_SEPARATOR = '/';

/**
* The Windows separator character.
*/
private static final char WINDOWS_SEPARATOR = '\\';

/**
* The system separator character.
*/
private static final char SYSTEM_SEPARATOR = File.separatorChar;

/**
* The separator character that is the opposite of the system separator.
*/
private static final char OTHER_SEPARATOR;
static {
if (isSystemWindows()) {
OTHER_SEPARATOR = UNIX_SEPARATOR;
} else {
OTHER_SEPARATOR = WINDOWS_SEPARATOR;
}
}

static boolean isSystemWindows() {
return SYSTEM_SEPARATOR == WINDOWS_SEPARATOR;
}

public static String normalize(String filename) {
return doNormalize(filename, UNIX_SEPARATOR, true);
}

private static String doNormalize(String filename, char separator, boolean keepSeparator) {
if (filename == null) {
return null;
}
int size = filename.length();
if (size == 0) {
return filename;
}
int prefix = getPrefixLength(filename);
if (prefix < 0) {
return null;
}

char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy
filename.getChars(0, filename.length(), array, 0);

// fix separators throughout
char otherSeparator = separator == SYSTEM_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_SEPARATOR;
for (int i = 0; i < array.length; i++) {
if (array[i] == otherSeparator) {
array[i] = separator;
}
}

// add extra separator on the end to simplify code below
boolean lastIsDirectory = true;
if (array[size - 1] != separator) {
array[size++] = separator;
lastIsDirectory = false;
}

// adjoining slashes
for (int i = prefix + 1; i < size; i++) {
if (array[i] == separator && array[i - 1] == separator) {
System.arraycopy(array, i, array, i - 1, size - i);
size--;
i--;
}
}

// dot slash
for (int i = prefix + 1; i < size; i++) {
if (array[i] == separator && array[i - 1] == '.' &&
(i == prefix + 1 || array[i - 2] == separator)) {
if (i == size - 1) {
lastIsDirectory = true;
}
System.arraycopy(array, i + 1, array, i - 1, size - i);
size -= 2;
i--;
}
}

// double dot slash
outer: for (int i = prefix + 2; i < size; i++) {
if (array[i] == separator && array[i - 1] == '.' && array[i - 2] == '.' &&
(i == prefix + 2 || array[i - 3] == separator)) {
if (i == prefix + 2) {
return null;
}
if (i == size - 1) {
lastIsDirectory = true;
}
int j;
for (j = i - 4; j >= prefix; j--) {
if (array[j] == separator) {
// remove b/../ from a/b/../c
System.arraycopy(array, i + 1, array, j + 1, size - i);
size -= i - j;
i = j + 1;
continue outer;
}
}
// remove a/../ from a/../c
System.arraycopy(array, i + 1, array, prefix, size - i);
size -= i + 1 - prefix;
i = prefix + 1;
}
}

if (size <= 0) { // should never be less than 0
return "";
}
if (size <= prefix) { // should never be less than prefix
return new String(array, 0, size);
}
if (lastIsDirectory && keepSeparator) {
return new String(array, 0, size); // keep trailing separator
}
return new String(array, 0, size - 1); // lose trailing separator
}

public static int getPrefixLength(String filename) {
if (filename == null) {
return -1;
}
int len = filename.length();
if (len == 0) {
return 0;
}
char ch0 = filename.charAt(0);
if (ch0 == ':') {
return -1;
}
if (len == 1) {
if (ch0 == '~') {
return 2; // return a length greater than the input
}
return isSeparator(ch0) ? 1 : 0;
} else {
if (ch0 == '~') {
int posUnix = filename.indexOf(UNIX_SEPARATOR, 1);
int posWin = filename.indexOf(WINDOWS_SEPARATOR, 1);
if (posUnix == -1 && posWin == -1) {
return len + 1; // return a length greater than the input
}
posUnix = posUnix == -1 ? posWin : posUnix;
posWin = posWin == -1 ? posUnix : posWin;
return Math.min(posUnix, posWin) + 1;
}
char ch1 = filename.charAt(1);
if (ch1 == ':') {
ch0 = Character.toUpperCase(ch0);
if (ch0 >= 'A' && ch0 <= 'Z') {
if (len == 2 || isSeparator(filename.charAt(2)) == false) {
return 2;
}
return 3;
}
return -1;

} else if (isSeparator(ch0) && isSeparator(ch1)) {
int posUnix = filename.indexOf(UNIX_SEPARATOR, 2);
int posWin = filename.indexOf(WINDOWS_SEPARATOR, 2);
if (posUnix == -1 && posWin == -1 || posUnix == 2 || posWin == 2) {
return -1;
}
posUnix = posUnix == -1 ? posWin : posUnix;
posWin = posWin == -1 ? posUnix : posWin;
return Math.min(posUnix, posWin) + 1;
} else {
return isSeparator(ch0) ? 1 : 0;
}
}
}

private static boolean isSeparator(char ch) {
return ch == UNIX_SEPARATOR || ch == WINDOWS_SEPARATOR;
}

public static String getExtension(String filename) {
if (filename == null) {
return null;
}
int index = indexOfExtension(filename);
if (index == -1) {
return "";
} else {
return filename.substring(index + 1);
}
}

public static int indexOfExtension(String filename) {
if (filename == null) {
return -1;
}
int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
int lastSeparator = indexOfLastSeparator(filename);
return lastSeparator > extensionPos ? -1 : extensionPos;
}

public static int indexOfLastSeparator(String filename) {
if (filename == null) {
return -1;
}
int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
return Math.max(lastUnixPos, lastWindowsPos);
}

}

+ 413
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/Preconditions.java ファイルの表示

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

import javax.annotation.Nullable;

/**
* Copied from Guava
*/
public final class Preconditions {
private Preconditions() {
}

/**
* Ensures the truth of an expression involving one or more parameters to the
* calling method.
*
* @param expression a boolean expression
* @throws IllegalArgumentException if {@code expression} is false
*/
public static void checkArgument(boolean expression) {
if (!expression) {
throw new IllegalArgumentException();
}
}

/**
* Ensures the truth of an expression involving one or more parameters to the
* calling method.
*
* @param expression a boolean expression
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @throws IllegalArgumentException if {@code expression} is false
*/
public static void checkArgument(
boolean expression, @Nullable Object errorMessage) {
if (!expression) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
}
}

/**
* Ensures the truth of an expression involving one or more parameters to the
* calling method.
*
* @param expression a boolean expression
* @param errorMessageTemplate a template for the exception message should the
* check fail. The message is formed by replacing each {@code %s}
* placeholder in the template with an argument. These are matched by
* position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
* Unmatched arguments will be appended to the formatted message in square
* braces. Unmatched placeholders will be left as-is.
* @param errorMessageArgs the arguments to be substituted into the message
* template. Arguments are converted to strings using
* {@link String#valueOf(Object)}.
* @throws IllegalArgumentException if {@code expression} is false
* @throws NullPointerException if the check fails and either {@code
* errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
* this happen)
*/
public static void checkArgument(boolean expression,
@Nullable String errorMessageTemplate,
@Nullable Object... errorMessageArgs) {
if (!expression) {
throw new IllegalArgumentException(
format(errorMessageTemplate, errorMessageArgs));
}
}

/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
* @throws IllegalStateException if {@code expression} is false
*/
public static void checkState(boolean expression) {
if (!expression) {
throw new IllegalStateException();
}
}

/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @throws IllegalStateException if {@code expression} is false
*/
public static void checkState(
boolean expression, @Nullable Object errorMessage) {
if (!expression) {
throw new IllegalStateException(String.valueOf(errorMessage));
}
}

/**
* Ensures the truth of an expression involving the state of the calling
* instance, but not involving any parameters to the calling method.
*
* @param expression a boolean expression
* @param errorMessageTemplate a template for the exception message should the
* check fail. The message is formed by replacing each {@code %s}
* placeholder in the template with an argument. These are matched by
* position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
* Unmatched arguments will be appended to the formatted message in square
* braces. Unmatched placeholders will be left as-is.
* @param errorMessageArgs the arguments to be substituted into the message
* template. Arguments are converted to strings using
* {@link String#valueOf(Object)}.
* @throws IllegalStateException if {@code expression} is false
* @throws NullPointerException if the check fails and either {@code
* errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
* this happen)
*/
public static void checkState(boolean expression,
@Nullable String errorMessageTemplate,
@Nullable Object... errorMessageArgs) {
if (!expression) {
throw new IllegalStateException(
format(errorMessageTemplate, errorMessageArgs));
}
}

/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static <T> T checkNotNull(T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}

/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @param errorMessage the exception message to use if the check fails; will
* be converted to a string using {@link String#valueOf(Object)}
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
}
return reference;
}

/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference an object reference
* @param errorMessageTemplate a template for the exception message should the
* check fail. The message is formed by replacing each {@code %s}
* placeholder in the template with an argument. These are matched by
* position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
* Unmatched arguments will be appended to the formatted message in square
* braces. Unmatched placeholders will be left as-is.
* @param errorMessageArgs the arguments to be substituted into the message
* template. Arguments are converted to strings using
* {@link String#valueOf(Object)}.
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static <T> T checkNotNull(T reference,
@Nullable String errorMessageTemplate,
@Nullable Object... errorMessageArgs) {
if (reference == null) {
// If either of these parameters is null, the right thing happens anyway
throw new NullPointerException(
format(errorMessageTemplate, errorMessageArgs));
}
return reference;
}

/*
* All recent hotspots (as of 2009) *really* like to have the natural code
*
* if (guardExpression) {
* throw new BadException(messageExpression);
* }
*
* refactored so that messageExpression is moved to a separate
* String-returning method.
*
* if (guardExpression) {
* throw new BadException(badMsg(...));
* }
*
* The alternative natural refactorings into void or Exception-returning
* methods are much slower. This is a big deal - we're talking factors of
* 2-8 in microbenchmarks, not just 10-20%. (This is a hotspot optimizer
* bug, which should be fixed, but that's a separate, big project).
*
* The coding pattern above is heavily used in java.util, e.g. in ArrayList.
* There is a RangeCheckMicroBenchmark in the JDK that was used to test this.
*
* But the methods in this class want to throw different exceptions,
* depending on the args, so it appears that this pattern is not directly
* applicable. But we can use the ridiculous, devious trick of throwing an
* exception in the middle of the construction of another exception.
* Hotspot is fine with that.
*/

/**
* Ensures that {@code index} specifies a valid <i>element</i> in an array,
* list or string of size {@code size}. An element index may range from zero,
* inclusive, to {@code size}, exclusive.
*
* @param index a user-supplied index identifying an element of an array, list
* or string
* @param size the size of that array, list or string
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is not
* less than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkElementIndex(int index, int size) {
return checkElementIndex(index, size, "index");
}

/**
* Ensures that {@code index} specifies a valid <i>element</i> in an array,
* list or string of size {@code size}. An element index may range from zero,
* inclusive, to {@code size}, exclusive.
*
* @param index a user-supplied index identifying an element of an array, list
* or string
* @param size the size of that array, list or string
* @param desc the text to use to describe this index in an error message
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is not
* less than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkElementIndex(
int index, int size, @Nullable String desc) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
}
return index;
}

private static String badElementIndex(int index, int size, String desc) {
if (index < 0) {
return format("%s (%s) must not be negative", desc, index);
} else if (size < 0) {
throw new IllegalArgumentException("negative size: " + size);
} else { // index >= size
return format("%s (%s) must be less than size (%s)", desc, index, size);
}
}

/**
* Ensures that {@code index} specifies a valid <i>position</i> in an array,
* list or string of size {@code size}. A position index may range from zero
* to {@code size}, inclusive.
*
* @param index a user-supplied index identifying a position in an array, list
* or string
* @param size the size of that array, list or string
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is
* greater than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkPositionIndex(int index, int size) {
return checkPositionIndex(index, size, "index");
}

/**
* Ensures that {@code index} specifies a valid <i>position</i> in an array,
* list or string of size {@code size}. A position index may range from zero
* to {@code size}, inclusive.
*
* @param index a user-supplied index identifying a position in an array, list
* or string
* @param size the size of that array, list or string
* @param desc the text to use to describe this index in an error message
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is
* greater than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkPositionIndex(
int index, int size, @Nullable String desc) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
}
return index;
}

private static String badPositionIndex(int index, int size, String desc) {
if (index < 0) {
return format("%s (%s) must not be negative", desc, index);
} else if (size < 0) {
throw new IllegalArgumentException("negative size: " + size);
} else { // index > size
return format("%s (%s) must not be greater than size (%s)",
desc, index, size);
}
}

/**
* Ensures that {@code start} and {@code end} specify a valid <i>positions</i>
* in an array, list or string of size {@code size}, and are in order. A
* position index may range from zero to {@code size}, inclusive.
*
* @param start a user-supplied index identifying a starting position in an
* array, list or string
* @param end a user-supplied index identifying a ending position in an array,
* list or string
* @param size the size of that array, list or string
* @throws IndexOutOfBoundsException if either index is negative or is
* greater than {@code size}, or if {@code end} is less than {@code start}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static void checkPositionIndexes(int start, int end, int size) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (start < 0 || end < start || end > size) {
throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
}
}

private static String badPositionIndexes(int start, int end, int size) {
if (start < 0 || start > size) {
return badPositionIndex(start, size, "start index");
}
if (end < 0 || end > size) {
return badPositionIndex(end, size, "end index");
}
// end < start
return format("end index (%s) must not be less than start index (%s)",
end, start);
}

/**
* Substitutes each {@code %s} in {@code template} with an argument. These
* are matched by position - the first {@code %s} gets {@code args[0]}, etc.
* If there are more arguments than placeholders, the unmatched arguments will
* be appended to the end of the formatted message in square braces.
*
* @param template a non-null string containing 0 or more {@code %s}
* placeholders.
* @param args the arguments to be substituted into the message
* template. Arguments are converted to strings using
* {@link String#valueOf(Object)}. Arguments can be null.
*/
static String format(String template,
@Nullable Object... args) {
template = String.valueOf(template); // null -> "null"

// start substituting the arguments into the '%s' placeholders
StringBuilder builder = new StringBuilder(
template.length() + 16 * args.length);
int templateStart = 0;
int i = 0;
while (i < args.length) {
int placeholderStart = template.indexOf("%s", templateStart);
if (placeholderStart == -1) {
break;
}
builder.append(template.substring(templateStart, placeholderStart));
builder.append(args[i++]);
templateStart = placeholderStart + 2;
}
builder.append(template.substring(templateStart));

// if we run out of placeholders, append the extra args in square braces
if (i < args.length) {
builder.append(" [");
builder.append(args[i++]);
while (i < args.length) {
builder.append(", ");
builder.append(args[i++]);
}
builder.append(']');
}

return builder.toString();
}
}

+ 140
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/StringUtils.java ファイルの表示

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

/**
* Copied from commons lang
*/
public class StringUtils {

public static final String EMPTY = "";

public static String trim(String str) {
return str == null ? null : str.trim();
}

public static String removeStart(String str, String remove) {
if (isEmpty(str) || isEmpty(remove)) {
return str;
}
if (str.startsWith(remove)) {
return str.substring(remove.length());
}
return str;
}

public static String removeEnd(String str, String remove) {
if (isEmpty(str) || isEmpty(remove)) {
return str;
}
if (str.endsWith(remove)) {
return str.substring(0, str.length() - remove.length());
}
return str;
}

public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}

public static boolean startsWithIgnoreCase(String str, String prefix) {
return startsWith(str, prefix, true);
}

private static boolean startsWith(String str, String prefix, boolean ignoreCase) {
if (str == null || prefix == null) {
return (str == null && prefix == null);
}
if (prefix.length() > str.length()) {
return false;
}
return str.regionMatches(ignoreCase, 0, prefix, 0, prefix.length());
}

public static String substring(String str, int start) {
if (str == null) {
return null;
}

// handle negatives, which means last n characters
if (start < 0) {
start = str.length() + start; // remember start is negative
}

if (start < 0) {
start = 0;
}
if (start > str.length()) {
return EMPTY;
}

return str.substring(start);
}

public static boolean isBlank(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(str.charAt(i)) == false)) {
return false;
}
}
return true;
}

public static boolean isNotBlank(String str) {
return !StringUtils.isBlank(str);
}

public static String removeEndIgnoreCase(String str, String remove) {
if (isEmpty(str) || isEmpty(remove)) {
return str;
}
if (endsWithIgnoreCase(str, remove)) {
return str.substring(0, str.length() - remove.length());
}
return str;
}

public static boolean endsWithIgnoreCase(String str, String suffix) {
return endsWith(str, suffix, true);
}

private static boolean endsWith(String str, String suffix, boolean ignoreCase) {
if (str == null || suffix == null) {
return (str == null && suffix == null);
}
if (suffix.length() > str.length()) {
return false;
}
int strOffset = str.length() - suffix.length();
return str.regionMatches(ignoreCase, strOffset, suffix, 0, suffix.length());
}

public static String lowerCase(String str) {
if (str == null) {
return null;
}
return str.toLowerCase();
}

}

+ 205
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/WildcardPattern.java ファイルの表示

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

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
* Implementation of Ant-style matching patterns.
* Contrary to other implementations (like AntPathMatcher from Spring Framework) it is based on {@link Pattern Java Regular Expressions}.
* To increase performance it holds an internal cache of all processed patterns.
* <p>
* Following rules are applied:
* <ul>
* <li>? matches single character</li>
* <li>* matches zero or more characters</li>
* <li>** matches zero or more 'directories'</li>
* </ul>
* </p>
* <p>
* Some examples of patterns:
* <ul>
* <li><code>org/T?st.java</code> - matches <code>org/Test.java</code> and also <code>org/Tost.java</code></li>
* <li><code>org/*.java</code> - matches all <code>.java</code> files in the <code>org</code> directory,
* e.g. <code>org/Foo.java</code> or <code>org/Bar.java</code></li>
* <li><code>org/**</code> - matches all files underneath the <code>org</code> directory,
* e.g. <code>org/Foo.java</code> or <code>org/foo/bar.jsp</code></li>
* <li><code>org/&#42;&#42;/Test.java</code> - matches all <code>Test.java</code> files underneath the <code>org</code> directory,
* e.g. <code>org/Test.java</code> or <code>org/foo/Test.java</code> or <code>org/foo/bar/Test.java</code></li>
* <li><code>org/&#42;&#42;/*.java</code> - matches all <code>.java</code> files underneath the <code>org</code> directory,
* e.g. <code>org/Foo.java</code> or <code>org/foo/Bar.java</code> or <code>org/foo/bar/Baz.java</code></li>
* </ul>
* </p>
* <p>
* Another implementation, which is also based on Java Regular Expressions, can be found in
* <a href="https://github.com/JetBrains/intellij-community/blob/idea/107.743/platform/util/src/com/intellij/openapi/util/io/FileUtil.java#L847">FileUtil</a>
* from IntelliJ OpenAPI.
* </p>
*
*/
public class WildcardPattern {

private static final Map<String, WildcardPattern> CACHE = new HashMap<String, WildcardPattern>();
private static final String SPECIAL_CHARS = "()[]^$.{}+|";

private Pattern pattern;
private String stringRepresentation;

protected WildcardPattern(String pattern, String directorySeparator) {
this.stringRepresentation = pattern;
this.pattern = Pattern.compile(toRegexp(pattern, directorySeparator));
}

private static String toRegexp(String antPattern, String directorySeparator) {
final String escapedDirectorySeparator = '\\' + directorySeparator;

final StringBuilder sb = new StringBuilder(antPattern.length());

sb.append('^');

int i = antPattern.startsWith("/") || antPattern.startsWith("\\") ? 1 : 0;
while (i < antPattern.length()) {
final char ch = antPattern.charAt(i);

if (SPECIAL_CHARS.indexOf(ch) != -1) {
// Escape regexp-specific characters
sb.append('\\').append(ch);
} else if (ch == '*') {
if (i + 1 < antPattern.length() && antPattern.charAt(i + 1) == '*') {
// Double asterisk
// Zero or more directories
if (i + 2 < antPattern.length() && isSlash(antPattern.charAt(i + 2))) {
sb.append("(?:.*").append(escapedDirectorySeparator).append("|)");
i += 2;
} else {
sb.append(".*");
i += 1;
}
} else {
// Single asterisk
// Zero or more characters excluding directory separator
sb.append("[^").append(escapedDirectorySeparator).append("]*?");
}
} else if (ch == '?') {
// Any single character excluding directory separator
sb.append("[^").append(escapedDirectorySeparator).append("]");
} else if (isSlash(ch)) {
// Directory separator
sb.append(escapedDirectorySeparator);
} else {
// Single character
sb.append(ch);
}

i++;
}

sb.append('$');

return sb.toString();
}

private static boolean isSlash(char ch) {
return ch == '/' || ch == '\\';
}

/**
* Returns string representation of this pattern.
*
* @since 2.5
*/
@Override
public String toString() {
return stringRepresentation;
}

/**
* Returns true if specified value matches this pattern.
*/
public boolean match(String value) {
value = StringUtils.removeStart(value, "/");
value = StringUtils.removeEnd(value, "/");
return pattern.matcher(value).matches();
}

/**
* Returns true if specified value matches one of specified patterns.
*
* @since 2.4
*/
public static boolean match(WildcardPattern[] patterns, String value) {
for (WildcardPattern pattern : patterns) {
if (pattern.match(value)) {
return true;
}
}
return false;
}

/**
* Creates pattern with "/" as a directory separator.
*
* @see #create(String, String)
*/
public static WildcardPattern create(String pattern) {
return create(pattern, "/");
}

/**
* Creates array of patterns with "/" as a directory separator.
*
* @see #create(String, String)
*/
public static WildcardPattern[] create(String[] patterns) {
if (patterns == null) {
return new WildcardPattern[0];
}
WildcardPattern[] exclusionPAtterns = new WildcardPattern[patterns.length];
for (int i = 0; i < patterns.length; i++) {
exclusionPAtterns[i] = create(patterns[i]);
}
return exclusionPAtterns;
}

/**
* Creates pattern with specified separator for directories.
* <p>
* This is used to match Java-classes, i.e. <code>org.foo.Bar</code> against <code>org/**</code>.
* <b>However usage of character other than "/" as a directory separator is misleading and should be avoided,
* so method {@link #create(String)} is preferred over this one.</b>
* </p>
* <p>
* Also note that no matter whether forward or backward slashes were used in the <code>antPattern</code>
* the returned pattern will use <code>directorySeparator</code>.
* Thus to match Windows-style path "dir\file.ext" against pattern "dir/file.ext" normalization should be performed.
* </p>
*/
public static WildcardPattern create(String pattern, String directorySeparator) {
String key = pattern + directorySeparator;
WildcardPattern wildcardPattern = CACHE.get(key);
if (wildcardPattern == null) {
wildcardPattern = new WildcardPattern(pattern, directorySeparator);
CACHE.put(key, wildcardPattern);
}
return wildcardPattern;
}
}

+ 21
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/internal/package-info.java ファイルの表示

@@ -0,0 +1,21 @@
/*
* 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.
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.batch.api.internal;

+ 57
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/languages/Language.java ファイルの表示

@@ -0,0 +1,57 @@
/*
* 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.api.languages;

import java.util.Arrays;
import java.util.Collection;

public final class Language {

private final String key, name;
private final String[] fileSuffixes;

public Language(String key, String name, String... fileSuffixes) {
this.key = key;
this.name = name;
this.fileSuffixes = fileSuffixes;
}

/**
* For example "java".
*/
public String key() {
return key;
}

/**
* For example "Java"
*/
public String name() {
return name;
}

/**
* For example ["jav", "java"].
*/
public Collection<String> fileSuffixes() {
return Arrays.asList(fileSuffixes);
}

}

+ 21
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/languages/package-info.java ファイルの表示

@@ -0,0 +1,21 @@
/*
* 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.
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.batch.api.languages;

+ 29
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/measures/Metric.java ファイルの表示

@@ -0,0 +1,29 @@
/*
* 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.api.measures;

import java.io.Serializable;

public interface Metric<G extends Serializable> {

Class<G> type();

String key();
}

+ 21
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/measures/package-info.java ファイルの表示

@@ -0,0 +1,21 @@
/*
* 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.
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.batch.api.measures;

+ 43
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/rules/QProfile.java ファイルの表示

@@ -0,0 +1,43 @@
/*
* 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.api.rules;

public class QProfile {
private final String name, language;
private final Integer version;

public QProfile(String name, String language, Integer version) {
this.name = name;
this.language = language;
this.version = version;
}

public String name() {
return name;
}

public String language() {
return language;
}

public Integer version() {
return version;
}
}

+ 90
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/rules/RuleKey.java ファイルの表示

@@ -0,0 +1,90 @@
/*
* 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.api.rules;

import java.io.Serializable;

/**
* Key of a rule. Unique among all the rule repositories.
*
* @since 3.6
*/
public class RuleKey implements Serializable {
private final String repository, rule;

protected RuleKey(String repositoryKey, String ruleKey) {
this.repository = repositoryKey;
this.rule = ruleKey;
}

/**
* Create a key. Parameters are NOT null.
*/
public static RuleKey of(String repository, String rule) {
return new RuleKey(repository, rule);
}

/**
* Never null
*/
public String repository() {
return repository;
}

/**
* Never null
*/
public String rule() {
return rule;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RuleKey ruleKey = (RuleKey) o;
if (!repository.equals(ruleKey.repository)) {
return false;
}
if (!rule.equals(ruleKey.rule)) {
return false;
}
return true;
}

@Override
public int hashCode() {
int result = repository.hashCode();
result = 31 * result + rule.hashCode();
return result;
}

/**
* Format is "repository:rule", for example "squid:AvoidCycle"
*/
@Override
public String toString() {
return String.format("%s:%s", repository, rule);
}
}

+ 21
- 0
sonar-batch-plugin-api/src/main/java/org/sonar/batch/api/rules/package-info.java ファイルの表示

@@ -0,0 +1,21 @@
/*
* 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.
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.batch.api.rules;

sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultFilePredicatesTest.java → sonar-batch-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultFilePredicatesTest.java ファイルの表示

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.fs.internal;

import org.apache.commons.io.FilenameUtils;
import org.fest.assertions.Assertions;
import org.junit.Before;
import org.junit.Rule;
@@ -71,9 +70,9 @@ public class DefaultFilePredicatesTest {

@Test
public void matches_inclusion_patterns() throws Exception {
assertThat(predicates.matchesPathPatterns(new String[]{"src/other/**.java", "src/main/**/Action.java"}).apply(javaFile)).isTrue();
assertThat(predicates.matchesPathPatterns(new String[]{}).apply(javaFile)).isTrue();
assertThat(predicates.matchesPathPatterns(new String[]{"src/other/**.java", "src/**/*.php"}).apply(javaFile)).isFalse();
assertThat(predicates.matchesPathPatterns(new String[] {"src/other/**.java", "src/main/**/Action.java"}).apply(javaFile)).isTrue();
assertThat(predicates.matchesPathPatterns(new String[] {}).apply(javaFile)).isTrue();
assertThat(predicates.matchesPathPatterns(new String[] {"src/other/**.java", "src/**/*.php"}).apply(javaFile)).isFalse();
}

@Test
@@ -85,9 +84,9 @@ public class DefaultFilePredicatesTest {

@Test
public void does_not_match_exclusion_patterns() throws Exception {
assertThat(predicates.doesNotMatchPathPatterns(new String[]{}).apply(javaFile)).isTrue();
assertThat(predicates.doesNotMatchPathPatterns(new String[]{"src/other/**.java", "src/**/*.php"}).apply(javaFile)).isTrue();
assertThat(predicates.doesNotMatchPathPatterns(new String[]{"src/other/**.java", "src/main/**/Action.java"}).apply(javaFile)).isFalse();
assertThat(predicates.doesNotMatchPathPatterns(new String[] {}).apply(javaFile)).isTrue();
assertThat(predicates.doesNotMatchPathPatterns(new String[] {"src/other/**.java", "src/**/*.php"}).apply(javaFile)).isTrue();
assertThat(predicates.doesNotMatchPathPatterns(new String[] {"src/other/**.java", "src/main/**/Action.java"}).apply(javaFile)).isFalse();
}

@Test
@@ -107,7 +106,7 @@ public class DefaultFilePredicatesTest {
public void has_absolute_path() throws Exception {
String path = javaFile.file().getAbsolutePath();
assertThat(predicates.hasAbsolutePath(path).apply(javaFile)).isTrue();
assertThat(predicates.hasAbsolutePath(FilenameUtils.separatorsToWindows(path)).apply(javaFile)).isTrue();
assertThat(predicates.hasAbsolutePath(path.replaceAll("/", "\\\\")).apply(javaFile)).isTrue();

assertThat(predicates.hasAbsolutePath(temp.newFile().getAbsolutePath()).apply(javaFile)).isFalse();
assertThat(predicates.hasAbsolutePath("src/main/java/struts/Action.java").apply(javaFile)).isFalse();
@@ -130,7 +129,6 @@ public class DefaultFilePredicatesTest {
// relative file
assertThat(predicates.is(new File(javaFile.relativePath())).apply(javaFile)).isTrue();


// absolute file
assertThat(predicates.is(javaFile.file()).apply(javaFile)).isTrue();
assertThat(predicates.is(javaFile.file().getAbsoluteFile()).apply(javaFile)).isTrue();
@@ -187,8 +185,8 @@ public class DefaultFilePredicatesTest {
assertThat(predicates.and(Arrays.asList(predicates.all(), predicates.none())).apply(javaFile)).isFalse();

// array
assertThat(predicates.and(new FilePredicate[]{predicates.all(), predicates.all()}).apply(javaFile)).isTrue();
assertThat(predicates.and(new FilePredicate[]{predicates.all(), predicates.none()}).apply(javaFile)).isFalse();
assertThat(predicates.and(new FilePredicate[] {predicates.all(), predicates.all()}).apply(javaFile)).isTrue();
assertThat(predicates.and(new FilePredicate[] {predicates.all(), predicates.none()}).apply(javaFile)).isFalse();
}

@Test
@@ -210,8 +208,8 @@ public class DefaultFilePredicatesTest {
assertThat(predicates.or(Arrays.asList(predicates.none(), predicates.none())).apply(javaFile)).isFalse();

// array
assertThat(predicates.or(new FilePredicate[]{predicates.all(), predicates.all()}).apply(javaFile)).isTrue();
assertThat(predicates.or(new FilePredicate[]{predicates.all(), predicates.none()}).apply(javaFile)).isTrue();
assertThat(predicates.or(new FilePredicate[]{predicates.none(), predicates.none()}).apply(javaFile)).isFalse();
assertThat(predicates.or(new FilePredicate[] {predicates.all(), predicates.all()}).apply(javaFile)).isTrue();
assertThat(predicates.or(new FilePredicate[] {predicates.all(), predicates.none()}).apply(javaFile)).isTrue();
assertThat(predicates.or(new FilePredicate[] {predicates.none(), predicates.none()}).apply(javaFile)).isFalse();
}
}

sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultFileSystemTest.java → sonar-batch-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultFileSystemTest.java ファイルの表示

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.fs.internal;

import com.google.common.base.Charsets;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -60,8 +59,8 @@ public class DefaultFileSystemTest {
assertThat(fs.isDefaultJvmEncoding()).isTrue();
assertThat(fs.encoding()).isEqualTo(Charset.defaultCharset());

fs.setEncoding(Charsets.ISO_8859_1);
assertThat(fs.encoding()).isEqualTo(Charsets.ISO_8859_1);
fs.setEncoding(Charset.forName("ISO-8859-1"));
assertThat(fs.encoding()).isEqualTo(Charset.forName("ISO-8859-1"));
assertThat(fs.isDefaultJvmEncoding()).isFalse();
}


sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java → sonar-batch-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputFileTest.java ファイルの表示

@@ -37,18 +37,14 @@ public class DefaultInputFileTest {
public void test() throws Exception {
DefaultInputFile inputFile = new DefaultInputFile("src/Foo.php")
.setFile(temp.newFile("Foo.php"))
.setDeprecatedKey("deprecated")
.setKey("ABCDE")
.setHash("1234")
.setLines(42)
.setLanguage("php")
.setStatus(InputFile.Status.ADDED)
.setType(InputFile.Type.TEST)
.setPathRelativeToSourceDir("Foo.php");
.setType(InputFile.Type.TEST);

assertThat(inputFile.relativePath()).isEqualTo("src/Foo.php");
// deprecated method is different -> path relative to source dir
assertThat(inputFile.getRelativePath()).isEqualTo("Foo.php");
assertThat(new File(inputFile.relativePath())).isRelative();
assertThat(inputFile.absolutePath()).endsWith("Foo.php");
assertThat(new File(inputFile.absolutePath())).isAbsolute();

sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/PathPatternTest.java → sonar-batch-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/PathPatternTest.java ファイルの表示


+ 4
- 0
sonar-batch/pom.xml ファイルの表示

@@ -40,6 +40,10 @@
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-java-api</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-batch-plugin-api</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-plugin-api</artifactId>

+ 8
- 3
sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java ファイルの表示

@@ -30,11 +30,16 @@ import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilter;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.*;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.ProjectLink;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Violation;
import org.sonar.api.utils.SonarException;
import org.sonar.core.measure.MeasurementFilters;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -110,7 +115,7 @@ public class DefaultSensorContext implements SensorContext {
}

@Override
public Measure getMeasure(Metric metric) {
public <G extends Serializable> Measure<G> getMeasure(Metric<G> metric) {
return index.getMeasure(project, metric);
}

@@ -130,7 +135,7 @@ public class DefaultSensorContext implements SensorContext {
}

@Override
public Measure getMeasure(Resource resource, Metric metric) {
public <G extends Serializable> Measure<G> getMeasure(Resource resource, Metric<G> metric) {
return index.getMeasure(resource, metric);
}


+ 9
- 0
sonar-batch/src/main/java/org/sonar/batch/bootstrap/AnalysisMode.java ファイルの表示

@@ -38,6 +38,7 @@ public class AnalysisMode implements BatchComponent {
private boolean preview;
private boolean incremental;
private int previewReadTimeoutSec;
private boolean sensorMode;

public AnalysisMode(BootstrapProperties bootstrapProps) {
init(bootstrapProps);
@@ -51,20 +52,28 @@ public class AnalysisMode implements BatchComponent {
return incremental;
}

public boolean isSensorMode() {
return sensorMode;
}

private void init(BootstrapProperties bootstrapProps) {
if (bootstrapProps.properties().containsKey(CoreProperties.DRY_RUN)) {
LOG.warn(MessageFormat.format("Property {0} is deprecated. Please use {1} instead.", CoreProperties.DRY_RUN, CoreProperties.ANALYSIS_MODE));
preview = "true".equals(bootstrapProps.property(CoreProperties.DRY_RUN));
incremental = false;
sensorMode = false;
} else {
String mode = bootstrapProps.property(CoreProperties.ANALYSIS_MODE);
preview = CoreProperties.ANALYSIS_MODE_PREVIEW.equals(mode);
incremental = CoreProperties.ANALYSIS_MODE_INCREMENTAL.equals(mode);
sensorMode = CoreProperties.ANALYSIS_MODE_SENSOR.equals(mode);
}
if (incremental) {
LOG.info("Incremental mode");
} else if (preview) {
LOG.info("Preview mode");
} else if (sensorMode) {
LOG.info("Sensor mode");
}
// To stay compatible with plugins that use the old property to check mode
if (incremental || preview) {

+ 2
- 8
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java ファイルの表示

@@ -20,9 +20,6 @@
package org.sonar.batch.bootstrap;

import com.google.common.collect.Lists;
import org.sonar.batch.debt.DebtDecorator;
import org.sonar.batch.debt.IssueChangelogDebtCalculator;
import org.sonar.batch.debt.NewDebtDecorator;
import org.sonar.batch.maven.DefaultMavenPluginExecutor;
import org.sonar.batch.maven.MavenProjectBootstrapper;
import org.sonar.batch.maven.MavenProjectBuilder;
@@ -36,11 +33,8 @@ public class BatchComponents {
public static Collection all() {
List components = Lists.newArrayList(
// Maven
MavenProjectBootstrapper.class, DefaultMavenPluginExecutor.class, MavenProjectConverter.class, MavenProjectBuilder.class,

// Debt
IssueChangelogDebtCalculator.class, DebtDecorator.class, NewDebtDecorator.class
);
MavenProjectBootstrapper.class, DefaultMavenPluginExecutor.class, MavenProjectConverter.class, MavenProjectBuilder.class
);
components.addAll(CorePropertyDefinitions.all());
return components;
}

+ 18
- 4
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java ファイルの表示

@@ -21,10 +21,14 @@ package org.sonar.batch.bootstrap;

import com.google.common.collect.Lists;
import org.apache.commons.lang.ClassUtils;
import org.sonar.api.BatchExtension;
import org.sonar.api.batch.CheckProject;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.batch.api.analyzer.Analyzer;
import org.sonar.batch.api.analyzer.AnalyzerContext;
import org.sonar.batch.scan.SensorWrapper;

import java.util.Collection;
import java.util.List;
@@ -34,8 +38,13 @@ import java.util.List;
*/
public class BatchExtensionDictionnary extends org.sonar.api.batch.BatchExtensionDictionnary {

public BatchExtensionDictionnary(ComponentContainer componentContainer) {
private FileSystem fs;
private AnalyzerContext context;

public BatchExtensionDictionnary(ComponentContainer componentContainer, FileSystem fs, AnalyzerContext context) {
super(componentContainer);
this.fs = fs;
this.context = context;
}

public <T> Collection<T> select(Class<T> type, Project project, boolean sort, ExtensionMatcher matcher) {
@@ -48,7 +57,10 @@ public class BatchExtensionDictionnary extends org.sonar.api.batch.BatchExtensio

private <T> List<T> getFilteredExtensions(Class<T> type, Project project, ExtensionMatcher matcher) {
List<T> result = Lists.newArrayList();
for (BatchExtension extension : getExtensions()) {
for (Object extension : getExtensions()) {
if (type == Sensor.class && extension instanceof Analyzer) {
extension = new SensorWrapper((Analyzer) extension, context, fs);
}
if (shouldKeep(type, extension, project, matcher)) {
result.add((T) extension);
}
@@ -57,7 +69,9 @@ public class BatchExtensionDictionnary extends org.sonar.api.batch.BatchExtensio
}

private boolean shouldKeep(Class type, Object extension, Project project, ExtensionMatcher matcher) {
boolean keep = ClassUtils.isAssignable(extension.getClass(), type) && (matcher == null || matcher.accept(extension));
boolean keep = (ClassUtils.isAssignable(extension.getClass(), type)
|| (type == Sensor.class && ClassUtils.isAssignable(extension.getClass(), Analyzer.class)))
&& (matcher == null || matcher.accept(extension));
if (keep && project != null && ClassUtils.isAssignable(extension.getClass(), CheckProject.class)) {
keep = ((CheckProject) extension).shouldExecuteOnProject(project);
}

+ 13
- 4
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java ファイルの表示

@@ -39,6 +39,10 @@ import org.sonar.batch.components.PastSnapshotFinderByDays;
import org.sonar.batch.components.PastSnapshotFinderByPreviousAnalysis;
import org.sonar.batch.components.PastSnapshotFinderByPreviousVersion;
import org.sonar.batch.components.PastSnapshotFinderByVersion;
import org.sonar.batch.debt.DebtModelProvider;
import org.sonar.batch.rule.RulesProvider;
import org.sonar.batch.rules.DefaultQProfileReferential;
import org.sonar.batch.rules.QProfilesReferential;
import org.sonar.batch.settings.DefaultSettingsReferential;
import org.sonar.batch.settings.SettingsReferential;
import org.sonar.core.cluster.NullQueue;
@@ -83,8 +87,8 @@ public class BootstrapContainer extends ComponentContainer {
addBootstrapComponents();
if (!sensorMode) {
addDatabaseComponents();
addCoreComponents();
}
addCoreComponents();
}

private void addBootstrapComponents() {
@@ -118,6 +122,9 @@ public class BootstrapContainer extends ComponentContainer {
if (getComponentByType(MetricFinder.class) == null) {
add(CacheMetricFinder.class);
}
if (getComponentByType(QProfilesReferential.class) == null) {
add(DefaultQProfileReferential.class);
}
}

private void addDatabaseComponents() {
@@ -156,7 +163,9 @@ public class BootstrapContainer extends ComponentContainer {
PastSnapshotFinderByPreviousVersion.class,
PastMeasuresLoader.class,
PastSnapshotFinder.class,
Durations.class);
Durations.class,
new DebtModelProvider(),
new RulesProvider());
}

@Override
@@ -172,8 +181,8 @@ public class BootstrapContainer extends ComponentContainer {
}
}

public void executeTask(Map<String, String> taskProperties) {
new TaskContainer(this, taskProperties).execute();
public void executeTask(Map<String, String> taskProperties, Object... components) {
new TaskContainer(this, taskProperties, components).execute();
}

}

+ 6
- 7
sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java ファイルの表示

@@ -43,11 +43,10 @@ public class ExtensionInstaller {
}

public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) {
boolean preview = analysisMode.isPreview();

// core components
for (Object o : BatchComponents.all()) {
doInstall(container, matcher, null, preview, o);
doInstall(container, matcher, null, o);
}

// plugin extensions
@@ -55,7 +54,7 @@ public class ExtensionInstaller {
PluginMetadata metadata = entry.getKey();
Plugin plugin = entry.getValue();
for (Object extension : plugin.getExtensions()) {
doInstall(container, matcher, metadata, preview, extension);
doInstall(container, matcher, metadata, extension);
}
}
List<ExtensionProvider> providers = container.getComponentsByType(ExtensionProvider.class);
@@ -63,18 +62,18 @@ public class ExtensionInstaller {
Object object = provider.provide();
if (object instanceof Iterable) {
for (Object extension : (Iterable) object) {
doInstall(container, matcher, null, preview, extension);
doInstall(container, matcher, null, extension);
}
} else {
doInstall(container, matcher, null, preview, object);
doInstall(container, matcher, null, object);
}
}
return this;
}

private void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginMetadata metadata, boolean dryRun, Object extension) {
private void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginMetadata metadata, Object extension) {
if (ExtensionUtils.supportsEnvironment(extension, env)
&& (!dryRun || ExtensionUtils.supportsPreview(extension))
&& (!analysisMode.isPreview() || ExtensionUtils.supportsPreview(extension))
&& matcher.accept(extension)) {
container.addExtension(metadata, extension);
} else {

+ 6
- 1
sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java ファイルの表示

@@ -41,10 +41,12 @@ import java.util.Map;
public class TaskContainer extends ComponentContainer {

private final Map<String, String> taskProperties;
private final Object[] components;

public TaskContainer(ComponentContainer parent, Map<String, String> taskProperties) {
public TaskContainer(ComponentContainer parent, Map<String, String> taskProperties, Object... components) {
super(parent);
this.taskProperties = taskProperties;
this.components = components;
}

@Override
@@ -52,6 +54,9 @@ public class TaskContainer extends ComponentContainer {
installCoreTasks();
installTaskExtensions();
installComponentsUsingTaskExtensions();
for (Object component : components) {
add(component);
}
}

void installCoreTasks() {

+ 2
- 2
sonar-batch/src/main/java/org/sonar/batch/bootstrapper/Batch.java ファイルの表示

@@ -87,12 +87,12 @@ public final class Batch {
/**
* @since 4.4
*/
public Batch executeTask(Map<String, String> taskProperties) {
public Batch executeTask(Map<String, String> taskProperties, Object... components) {
if (!started) {
throw new IllegalStateException("Batch is not started. Unable to execute task.");
}

bootstrapContainer.executeTask(taskProperties);
bootstrapContainer.executeTask(taskProperties, components);
return this;
}


+ 1
- 1
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java ファイルの表示

@@ -178,7 +178,7 @@ public class DefaultIndex extends SonarIndex {
}

@Override
public Measure getMeasure(Resource resource, Metric metric) {
public Measure getMeasure(Resource resource, org.sonar.batch.api.measures.Metric<?> metric) {
return getMeasures(resource, MeasuresFilters.metric(metric));
}


+ 3
- 3
sonar-batch/src/main/java/org/sonar/batch/index/ResourceKeyMigration.java ファイルの表示

@@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.batch.fs.FileSystem;
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.api.database.DatabaseSession;
import org.sonar.api.database.model.ResourceModel;
import org.sonar.api.resources.Directory;
@@ -80,7 +80,7 @@ public class ResourceKeyMigration implements BatchComponent {
Map<String, InputFile> deprecatedTestKeyMapper = new HashMap<String, InputFile>();
Map<String, String> deprecatedDirectoryKeyMapper = new HashMap<String, String>();
for (InputFile inputFile : inputFiles) {
String deprecatedKey = ((DefaultInputFile) inputFile).deprecatedKey();
String deprecatedKey = ((DeprecatedDefaultInputFile) inputFile).deprecatedKey();
if (deprecatedKey != null) {
if (InputFile.Type.TEST == inputFile.type() && !deprecatedTestKeyMapper.containsKey(deprecatedKey)) {
deprecatedTestKeyMapper.put(deprecatedKey, inputFile);
@@ -109,7 +109,7 @@ public class ResourceKeyMigration implements BatchComponent {
boolean isTest = Qualifiers.UNIT_TEST_FILE.equals(resourceModel.getQualifier());
InputFile matchedFile = findInputFile(deprecatedFileKeyMapper, deprecatedTestKeyMapper, oldEffectiveKey, isTest);
if (matchedFile != null) {
String newEffectiveKey = ((DefaultInputFile) matchedFile).key();
String newEffectiveKey = ((DeprecatedDefaultInputFile) matchedFile).key();
// Now compute migration of the parent dir
String oldKey = StringUtils.substringAfterLast(oldEffectiveKey, ":");
Resource sonarFile;

+ 21
- 2
sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java ファイルの表示

@@ -53,15 +53,34 @@ public class IssueFilters implements BatchExtension {
this(deprecatedFilters, deprecatedViolations, new org.sonar.api.issue.IssueFilter[0]);
}

/**
* Used by scan2
*/
public IssueFilters(org.sonar.api.issue.IssueFilter[] exclusionFilters, IssueFilter[] filters) {
this(null, null, exclusionFilters, filters);
}

public IssueFilters(org.sonar.api.issue.IssueFilter[] exclusionFilters) {
this(null, null, exclusionFilters, new IssueFilter[0]);
}

public IssueFilters(IssueFilter[] filters) {
this(null, null, new org.sonar.api.issue.IssueFilter[0], filters);
}

public IssueFilters() {
this(null, null, new org.sonar.api.issue.IssueFilter[0], new IssueFilter[0]);
}

public boolean accept(DefaultIssue issue, @Nullable Violation violation) {
if(new DefaultIssueFilterChain(filters).accept(issue)) {
if (new DefaultIssueFilterChain(filters).accept(issue)) {
// Apply deprecated rules only if filter chain accepts the current issue
for (org.sonar.api.issue.IssueFilter filter : exclusionFilters) {
if (!filter.accept(issue)) {
return false;
}
}
if (!deprecatedFilters.isEmpty()) {
if (deprecatedFilters != null && !deprecatedFilters.isEmpty()) {
Violation v = violation != null ? violation : deprecatedViolations.toViolation(issue);
return !deprecatedFilters.isIgnored(v);
}

+ 13
- 3
sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java ファイルの表示

@@ -47,7 +47,7 @@ public class ModuleIssues {
private final Project project;
private final IssueFilters filters;

public ModuleIssues(ActiveRules activeRules, Rules rules, IssueCache cache, Project project, IssueFilters filters) {
public ModuleIssues(ActiveRules activeRules, Rules rules, IssueCache cache, @Nullable Project project, IssueFilters filters) {
this.activeRules = activeRules;
this.rules = rules;
this.cache = cache;
@@ -55,6 +55,13 @@ public class ModuleIssues {
this.filters = filters;
}

/**
* Used by scan2
*/
public ModuleIssues(ActiveRules activeRules, Rules rules, IssueCache cache, IssueFilters filters) {
this(activeRules, rules, cache, null, filters);
}

public boolean initAndAddIssue(DefaultIssue issue) {
return initAndAddIssue(issue, null);
}
@@ -67,6 +74,7 @@ public class ModuleIssues {
private DefaultIssue newIssue(Violation violation) {
return (DefaultIssue) new DefaultIssueBuilder()
.componentKey(violation.getResource().getEffectiveKey())
// Project can be null but Violation not used by scan2
.projectKey(project.getRoot().getEffectiveKey())
.ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey()))
.effortToFix(violation.getCost())
@@ -107,8 +115,10 @@ public class ModuleIssues {
if (Strings.isNullOrEmpty(issue.message())) {
issue.setMessage(rule.name());
}
issue.setCreationDate(project.getAnalysisDate());
issue.setUpdateDate(project.getAnalysisDate());
if (project != null) {
issue.setCreationDate(project.getAnalysisDate());
issue.setUpdateDate(project.getAnalysisDate());
}
if (issue.severity() == null) {
issue.setSeverity(activeRule.severity());
}

+ 2
- 2
sonar-batch/src/main/java/org/sonar/batch/issue/ignore/scanner/IssueExclusionsLoader.java ファイルの表示

@@ -22,7 +22,7 @@ package org.sonar.batch.issue.ignore.scanner;

import org.sonar.api.batch.fs.FileSystem;
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.api.resources.Project;
import org.sonar.api.utils.SonarException;
import org.sonar.batch.issue.ignore.pattern.IssueExclusionPatternInitializer;
@@ -59,7 +59,7 @@ public final class IssueExclusionsLoader {

for (InputFile inputFile : fileSystem.inputFiles(fileSystem.predicates().all())) {
try {
String componentEffectiveKey = ((DefaultInputFile) inputFile).key();
String componentEffectiveKey = ((DeprecatedDefaultInputFile) inputFile).key();
if (componentEffectiveKey != null) {
String path = inputFile.relativePath();
inclusionPatternInitializer.initializePatternsForPath(path, componentEffectiveKey);

+ 2
- 2
sonar-batch/src/main/java/org/sonar/batch/language/LanguageDistributionDecorator.java ファイルの表示

@@ -44,14 +44,14 @@ public class LanguageDistributionDecorator implements Decorator {

@DependsUpon
public List<Metric> dependsUponMetrics() {
return ImmutableList.of(CoreMetrics.LINES);
return ImmutableList.<Metric>of(CoreMetrics.LINES);
}

@DependedUpon
public List<Metric> generatesMetrics() {
return ImmutableList.of(
CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION
);
);
}

public void decorate(Resource resource, DecoratorContext context) {

+ 63
- 0
sonar-batch/src/main/java/org/sonar/batch/languages/DeprecatedLanguagesReferential.java ファイルの表示

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

import org.sonar.api.resources.Languages;
import org.sonar.batch.api.languages.Language;

import javax.annotation.CheckForNull;

import java.util.ArrayList;
import java.util.Collection;

/**
* Languages referential using {@link Languages}
* @since 4.4
*/
public class DeprecatedLanguagesReferential implements LanguagesReferential {

private Languages languages;

public DeprecatedLanguagesReferential(Languages languages) {
this.languages = languages;
}

/**
* Get language.
*/
@CheckForNull
public Language get(String languageKey) {
org.sonar.api.resources.Language language = languages.get(languageKey);
return language != null ? new Language(language.getKey(), language.getName(), language.getFileSuffixes()) : null;
}

/**
* Get list of all supported languages.
*/
public Collection<Language> all() {
org.sonar.api.resources.Language[] all = languages.all();
Collection<Language> result = new ArrayList<Language>(all.length);
for (org.sonar.api.resources.Language language : all) {
result.add(new Language(language.getKey(), language.getName(), language.getFileSuffixes()));
}
return result;
}

}

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileIndex.java → sonar-batch/src/main/java/org/sonar/batch/languages/LanguagesReferential.java ファイルの表示

@@ -17,23 +17,30 @@
* 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;
package org.sonar.batch.languages;

import com.google.common.collect.ImmutableList;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.BatchComponent;
import org.sonar.batch.api.languages.Language;

import javax.annotation.CheckForNull;
import java.util.List;

// Accepted to support both InputFile and InputDir as long as indexes are on the same attributes
public interface FileIndex {
import java.util.Collection;

// Currently only a single index is supported
List<FileIndex> ALL = ImmutableList.<FileIndex>of(new RelativePathIndex());
/**
* Languages referential
* @since 4.4
*/
public interface LanguagesReferential extends BatchComponent {

/**
* Get language.
*/
@CheckForNull
Object valueOf(InputFile f);
Language get(String languageKey);

String id();
/**
* Get list of all supported languages.
*/
Collection<Language> all();

}

+ 20
- 0
sonar-batch/src/main/java/org/sonar/batch/languages/package-info.java ファイルの表示

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

+ 4
- 3
sonar-batch/src/main/java/org/sonar/batch/phases/SensorMatcher.java ファイルの表示

@@ -19,12 +19,12 @@
*/
package org.sonar.batch.phases;

import org.sonar.batch.bootstrap.ExtensionMatcher;

import org.apache.commons.lang.ClassUtils;
import org.sonar.api.BatchExtension;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.Sensor;
import org.sonar.batch.api.analyzer.Analyzer;
import org.sonar.batch.bootstrap.ExtensionMatcher;

/**
* Allow to filter sensors that will be executed.
@@ -36,7 +36,8 @@ public abstract class SensorMatcher implements BatchExtension, ExtensionMatcher

@Override
public final boolean accept(Object extension) {
return ClassUtils.isAssignable(extension.getClass(), Sensor.class) && acceptSensor((Sensor) extension);
return ClassUtils.isAssignable(extension.getClass(), Sensor.class)
&& acceptSensor((Sensor) extension) || ClassUtils.isAssignable(extension.getClass(), Analyzer.class);
}

public abstract boolean acceptSensor(Sensor sensor);

+ 6
- 3
sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java ファイルの表示

@@ -28,6 +28,8 @@ import org.sonar.api.batch.rule.internal.NewActiveRule;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RuleParam;
import org.sonar.batch.api.rules.QProfile;
import org.sonar.batch.rules.QProfileWithId;
import org.sonar.core.qualityprofile.db.ActiveRuleDao;
import org.sonar.core.qualityprofile.db.ActiveRuleDto;
import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
@@ -49,13 +51,14 @@ public class ActiveRulesProvider extends ProviderAdapter {

private ActiveRules load(ModuleQProfiles qProfiles, ActiveRuleDao dao, RuleFinder ruleFinder) {
ActiveRulesBuilder builder = new ActiveRulesBuilder();
for (ModuleQProfiles.QProfile qProfile : qProfiles.findAll()) {
for (QProfile qProfile : qProfiles.findAll()) {
QProfileWithId qProfileWithId = (QProfileWithId) qProfile;
ListMultimap<Integer, ActiveRuleParamDto> paramDtosByActiveRuleId = ArrayListMultimap.create();
for (ActiveRuleParamDto dto : dao.selectParamsByProfileId(qProfile.id())) {
for (ActiveRuleParamDto dto : dao.selectParamsByProfileId(qProfileWithId.id())) {
paramDtosByActiveRuleId.put(dto.getActiveRuleId(), dto);
}

for (ActiveRuleDto activeDto : dao.selectByProfileId(qProfile.id())) {
for (ActiveRuleDto activeDto : dao.selectByProfileId(qProfileWithId.id())) {
Rule rule = ruleFinder.findById(activeDto.getRulId());
if (rule != null) {
NewActiveRule newActiveRule = builder.activate(rule.ruleKey());

+ 12
- 52
sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java ファイルの表示

@@ -23,11 +23,11 @@ import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.BatchComponent;
import org.sonar.api.config.Settings;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.utils.MessageException;
import org.sonar.core.qualityprofile.db.QualityProfileDao;
import org.sonar.core.qualityprofile.db.QualityProfileDto;
import org.sonar.batch.api.languages.Language;
import org.sonar.batch.api.rules.QProfile;
import org.sonar.batch.languages.LanguagesReferential;
import org.sonar.batch.rules.QProfilesReferential;

import javax.annotation.CheckForNull;

@@ -41,55 +41,19 @@ public class ModuleQProfiles implements BatchComponent {

public static final String SONAR_PROFILE_PROP = "sonar.profile";

public static class QProfile {
private final String name, language;
private final Integer version;
private final int id;

public QProfile(QualityProfileDto dto) {
this.id = dto.getId();
this.name = dto.getName();
this.language = dto.getLanguage();
this.version = dto.getVersion();
}

QProfile(int id, String name, String language, Integer version) {
this.id = id;
this.name = name;
this.language = language;
this.version = version;
}

public int id() {
return id;
}

public String name() {
return name;
}

public String language() {
return language;
}

public Integer version() {
return version;
}
}

private final Map<String, QProfile> byLanguage;

public ModuleQProfiles(Settings settings, Languages languages, QualityProfileDao dao) {
public ModuleQProfiles(Settings settings, LanguagesReferential languages, QProfilesReferential qProfileRef) {
ImmutableMap.Builder<String, QProfile> builder = ImmutableMap.builder();
String defaultName = settings.getString(SONAR_PROFILE_PROP);

for (Language language : languages.all()) {
QProfile profile = null;
if (StringUtils.isNotBlank(defaultName)) {
profile = loadDefaultQProfile(dao, defaultName, language.getKey());
profile = loadDefaultQProfile(qProfileRef, defaultName, language.key());
}
if (profile == null) {
profile = loadQProfile(dao, settings, language.getKey());
profile = loadQProfile(qProfileRef, settings, language.key());
}
if (profile != null) {
builder.put(profile.language(), profile);
@@ -99,25 +63,21 @@ public class ModuleQProfiles implements BatchComponent {
}

@CheckForNull
private QProfile loadQProfile(QualityProfileDao dao, Settings settings, String language) {
private QProfile loadQProfile(QProfilesReferential qProfileRef, Settings settings, String language) {
String profileName = settings.getString("sonar.profile." + language);
if (profileName != null) {
QualityProfileDto dto = dao.selectByNameAndLanguage(profileName, language);
QProfile dto = qProfileRef.get(language, profileName);
if (dto == null) {
throw MessageException.of(String.format("Quality profile not found : '%s' on language '%s'", profileName, language));
}
return new QProfile(dto);
return dto;
}
return null;
}

@CheckForNull
private QProfile loadDefaultQProfile(QualityProfileDao dao, String profileName, String language) {
QualityProfileDto dto = dao.selectByNameAndLanguage(profileName, language);
if (dto != null) {
return new QProfile(dto);
}
return null;
private QProfile loadDefaultQProfile(QProfilesReferential qProfileRef, String profileName, String language) {
return qProfileRef.get(language, profileName);
}

public Collection<QProfile> findAll() {

+ 9
- 10
sonar-batch/src/main/java/org/sonar/batch/rule/QProfileEventsDecorator.java ファイルの表示

@@ -34,8 +34,7 @@ import org.sonar.api.resources.Languages;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.batch.rule.ModuleQProfiles.QProfile;
import org.sonar.batch.rules.QProfileWithId;
import org.sonar.core.qualityprofile.db.QualityProfileDao;
import org.sonar.core.qualityprofile.db.QualityProfileDto;

@@ -101,14 +100,14 @@ public class QProfileEventsDecorator implements Decorator {
} else {
pastProfileVersion = pastProfileVersionMeasure.getIntValue();
}
pastProfiles = UsedQProfiles.fromProfiles(new ModuleQProfiles.QProfile(pastProfileId, pastProfileName, pastProfileLanguage, pastProfileVersion));
pastProfiles = UsedQProfiles.fromProfiles(new QProfileWithId(pastProfileId, pastProfileName, pastProfileLanguage, pastProfileVersion));
}

// Now create appropriate events
Map<Integer, QProfile> pastProfilesById = Maps.newHashMap(pastProfiles.profilesById());
for (QProfile profile : currentProfiles.profilesById().values()) {
Map<Integer, QProfileWithId> pastProfilesById = Maps.newHashMap(pastProfiles.profilesById());
for (QProfileWithId profile : currentProfiles.profilesById().values()) {
if (pastProfilesById.containsKey(profile.id())) {
QProfile pastProfile = pastProfilesById.get(profile.id());
QProfileWithId pastProfile = pastProfilesById.get(profile.id());
if (pastProfile.version() < profile.version()) {
// New version of the same QP
usedProfile(context, profile);
@@ -118,25 +117,25 @@ public class QProfileEventsDecorator implements Decorator {
usedProfile(context, profile);
}
}
for (QProfile profile : pastProfilesById.values()) {
for (QProfileWithId profile : pastProfilesById.values()) {
// Following profiles are no more used
stopUsedProfile(context, profile);
}
}

private void stopUsedProfile(DecoratorContext context, QProfile profile) {
private void stopUsedProfile(DecoratorContext context, QProfileWithId profile) {
Language language = languages.get(profile.language());
String languageName = language != null ? language.getName() : profile.language();
context.createEvent("Stop using " + format(profile) + " (" + languageName + ")", format(profile) + " no more used for " + languageName, Event.CATEGORY_PROFILE, null);
}

private void usedProfile(DecoratorContext context, QProfile profile) {
private void usedProfile(DecoratorContext context, QProfileWithId profile) {
Language language = languages.get(profile.language());
String languageName = language != null ? language.getName() : profile.language();
context.createEvent("Use " + format(profile) + " (" + languageName + ")", format(profile) + " used for " + languageName, Event.CATEGORY_PROFILE, null);
}

private String format(QProfile profile) {
private String format(QProfileWithId profile) {
return profile.name() + " version " + profile.version();
}


+ 4
- 3
sonar-batch/src/main/java/org/sonar/batch/rule/QProfileSensor.java ファイルの表示

@@ -26,6 +26,7 @@ import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.resources.Project;
import org.sonar.batch.rules.QProfileWithId;
import org.sonar.core.qualityprofile.db.QualityProfileDao;

import java.util.List;
@@ -51,9 +52,9 @@ public class QProfileSensor implements Sensor {
}

public void analyse(Project project, SensorContext context) {
List<ModuleQProfiles.QProfile> profiles = Lists.newArrayList();
List<QProfileWithId> profiles = Lists.newArrayList();
for (String language : fs.languages()) {
ModuleQProfiles.QProfile qProfile = moduleQProfiles.findByLanguage(language);
QProfileWithId qProfile = (QProfileWithId) moduleQProfiles.findByLanguage(language);
if (qProfile != null) {
dao.updateUsedColumn(qProfile.id(), true);
profiles.add(qProfile);
@@ -65,7 +66,7 @@ public class QProfileSensor implements Sensor {

// For backward compatibility
if (profiles.size() == 1) {
ModuleQProfiles.QProfile qProfile = profiles.get(0);
QProfileWithId qProfile = profiles.get(0);
Measure measure = new Measure(CoreMetrics.PROFILE, qProfile.name()).setValue((double) qProfile.id());
Measure measureVersion = new Measure(CoreMetrics.PROFILE_VERSION, qProfile.version().doubleValue());
context.saveMeasure(measure);

+ 1
- 1
sonar-batch/src/main/java/org/sonar/batch/rule/QProfileVerifier.java ファイルの表示

@@ -27,7 +27,7 @@ import org.sonar.api.BatchComponent;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.config.Settings;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.rule.ModuleQProfiles.QProfile;
import org.sonar.batch.api.rules.QProfile;

public class QProfileVerifier implements BatchComponent {


+ 5
- 4
sonar-batch/src/main/java/org/sonar/batch/rule/RulesProfileProvider.java ファイルの表示

@@ -30,6 +30,7 @@ import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
import org.sonar.batch.api.rules.QProfile;

import java.util.Collection;
import java.util.Map;
@@ -55,8 +56,8 @@ public class RulesProfileProvider extends ProviderAdapter {
}

private RulesProfile loadSingleLanguageProfile(ModuleQProfiles qProfiles, ActiveRules activeRules,
RuleFinder ruleFinder, String language) {
ModuleQProfiles.QProfile qProfile = qProfiles.findByLanguage(language);
RuleFinder ruleFinder, String language) {
QProfile qProfile = qProfiles.findByLanguage(language);
if (qProfile != null) {
return new RulesProfileWrapper(select(qProfile, activeRules, ruleFinder));
}
@@ -65,13 +66,13 @@ public class RulesProfileProvider extends ProviderAdapter {

private RulesProfile loadProfiles(ModuleQProfiles qProfiles, ActiveRules activeRules, RuleFinder ruleFinder) {
Collection<RulesProfile> dtos = Lists.newArrayList();
for (ModuleQProfiles.QProfile qProfile : qProfiles.findAll()) {
for (QProfile qProfile : qProfiles.findAll()) {
dtos.add(select(qProfile, activeRules, ruleFinder));
}
return new RulesProfileWrapper(dtos);
}

private RulesProfile select(ModuleQProfiles.QProfile qProfile, ActiveRules activeRules, RuleFinder ruleFinder) {
private RulesProfile select(QProfile qProfile, ActiveRules activeRules, RuleFinder ruleFinder) {
RulesProfile deprecatedProfile = new RulesProfile();
deprecatedProfile.setVersion(qProfile.version());
deprecatedProfile.setName(qProfile.name());

+ 12
- 12
sonar-batch/src/main/java/org/sonar/batch/rule/UsedQProfiles.java ファイルの表示

@@ -26,7 +26,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.batch.rule.ModuleQProfiles.QProfile;
import org.sonar.batch.rules.QProfileWithId;

import javax.annotation.concurrent.Immutable;

@@ -37,14 +37,14 @@ import java.util.Map;
@Immutable
public class UsedQProfiles {

private Map<Integer, ModuleQProfiles.QProfile> profilesById = Maps.newLinkedHashMap();
private Map<Integer, QProfileWithId> profilesById = Maps.newLinkedHashMap();

private UsedQProfiles() {
}

public static final UsedQProfiles fromProfiles(Iterable<QProfile> profiles) {
public static final UsedQProfiles fromProfiles(Iterable<QProfileWithId> profiles) {
UsedQProfiles result = new UsedQProfiles();
for (QProfile qProfile : profiles) {
for (QProfileWithId qProfile : profiles) {
result.add(qProfile);
}
return result;
@@ -54,7 +54,7 @@ public class UsedQProfiles {
return new UsedQProfiles();
}

public static final UsedQProfiles fromProfiles(QProfile... profiles) {
public static final UsedQProfiles fromProfiles(QProfileWithId... profiles) {
return fromProfiles(Arrays.asList(profiles));
}

@@ -63,7 +63,7 @@ public class UsedQProfiles {
JsonArray root = new JsonParser().parse(json).getAsJsonArray();
for (JsonElement elt : root) {
JsonObject profile = elt.getAsJsonObject();
result.add(new QProfile(profile.get("id").getAsInt(), profile.get("name").getAsString(), profile.get("language").getAsString(), profile.get("version").getAsInt()));
result.add(new QProfileWithId(profile.get("id").getAsInt(), profile.get("name").getAsString(), profile.get("language").getAsString(), profile.get("version").getAsInt()));
}
return result;
}
@@ -72,7 +72,7 @@ public class UsedQProfiles {
StringWriter json = new StringWriter();
JsonWriter writer = JsonWriter.of(json);
writer.beginArray();
for (ModuleQProfiles.QProfile qProfile : profilesById.values()) {
for (QProfileWithId qProfile : profilesById.values()) {
writer.beginObject()
.prop("id", qProfile.id())
.prop("name", qProfile.name())
@@ -89,8 +89,8 @@ public class UsedQProfiles {
return empty().mergeInPlace(this).mergeInPlace(other);
}

private void add(ModuleQProfiles.QProfile profile) {
QProfile alreadyAdded = profilesById.get(profile.id());
private void add(QProfileWithId profile) {
QProfileWithId alreadyAdded = profilesById.get(profile.id());
if (alreadyAdded == null
// Keep only latest version
|| profile.version() > alreadyAdded.version()) {
@@ -98,8 +98,8 @@ public class UsedQProfiles {
}
}

private UsedQProfiles addAll(Iterable<QProfile> profiles) {
for (QProfile profile : profiles) {
private UsedQProfiles addAll(Iterable<QProfileWithId> profiles) {
for (QProfileWithId profile : profiles) {
this.add(profile);
}
return this;
@@ -110,7 +110,7 @@ public class UsedQProfiles {
return this;
}

public Map<Integer, ModuleQProfiles.QProfile> profilesById() {
public Map<Integer, QProfileWithId> profilesById() {
return ImmutableMap.copyOf(profilesById);
}


+ 46
- 0
sonar-batch/src/main/java/org/sonar/batch/rules/DefaultQProfileReferential.java ファイルの表示

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

import org.sonar.batch.api.rules.QProfile;
import org.sonar.core.qualityprofile.db.QualityProfileDao;
import org.sonar.core.qualityprofile.db.QualityProfileDto;

/**
* @since 4.4
*/
public class DefaultQProfileReferential implements QProfilesReferential {

private QualityProfileDao qualityProfileDao;

public DefaultQProfileReferential(QualityProfileDao qualityProfileDao) {
this.qualityProfileDao = qualityProfileDao;
}

@Override
public QProfile get(String language, String name) {
QualityProfileDto dto = qualityProfileDao.selectByNameAndLanguage(name, language);
if (dto == null) {
return null;
}
return new QProfileWithId(dto.getId(), dto.getName(), dto.getLanguage(), dto.getVersion());
}

}

sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/RelativePathIndex.java → sonar-batch/src/main/java/org/sonar/batch/rules/QProfileWithId.java ファイルの表示

@@ -17,23 +17,20 @@
* 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;
package org.sonar.batch.rules;

import org.sonar.api.batch.fs.InputFile;
import org.sonar.batch.api.rules.QProfile;

/**
* @since 4.2
*/
public class RelativePathIndex implements FileIndex {
public static final String ID = "rel";
public class QProfileWithId extends QProfile {
private final int id;

@Override
public Object valueOf(InputFile f) {
return f.relativePath();
public QProfileWithId(int id, String name, String language, Integer version) {
super(name, language, version);
this.id = id;
}

@Override
public String id() {
return ID;
public int id() {
return id;
}

}

+ 39
- 0
sonar-batch/src/main/java/org/sonar/batch/rules/QProfilesReferential.java ファイルの表示

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

import org.sonar.api.BatchComponent;
import org.sonar.batch.api.rules.QProfile;

import javax.annotation.CheckForNull;

/**
* Quality profiles referential
* @since 4.4
*/
public interface QProfilesReferential extends BatchComponent {

/**
* Get quality profile
*/
@CheckForNull
QProfile get(String language, String name);

}

+ 21
- 0
sonar-batch/src/main/java/org/sonar/batch/rules/package-info.java ファイルの表示

@@ -0,0 +1,21 @@
/*
* 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.
*/
@javax.annotation.ParametersAreNonnullByDefault
package org.sonar.batch.rules;

+ 169
- 0
sonar-batch/src/main/java/org/sonar/batch/scan/AnalyzerContextAdaptor.java ファイルの表示

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

import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.issue.Issuable;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.rule.RuleKey;
import org.sonar.batch.api.analyzer.AnalyzerContext;
import org.sonar.batch.api.analyzer.issue.AnalyzerIssue;
import org.sonar.batch.api.analyzer.measure.AnalyzerMeasure;
import org.sonar.batch.api.measures.Metric;

import java.io.Serializable;
import java.util.Collection;

public class AnalyzerContextAdaptor implements AnalyzerContext {

private SensorContext sensorContext;
private MetricFinder metricFinder;
private Project project;
private ResourcePerspectives perspectives;

public AnalyzerContextAdaptor(SensorContext sensorContext, MetricFinder metricFinder, Project project, ResourcePerspectives perspectives) {
this.sensorContext = sensorContext;
this.metricFinder = metricFinder;
this.project = project;
this.perspectives = perspectives;
}

@Override
public AnalyzerMeasure<?> getMeasure(String metricKey) {
Metric<?> m = metricFinder.findByKey(metricKey);
if (m == null) {
throw new IllegalStateException("Unknow metric with key: " + metricKey);
}
return getMeasure(m);
}

@Override
public <G extends Serializable> AnalyzerMeasure<G> getMeasure(Metric<G> metric) {
org.sonar.api.measures.Metric<G> m = metricFinder.findByKey(metric.key());
Measure<G> measure = sensorContext.getMeasure(m);
if (measure == null) {
return null;
}
return AnalyzerMeasure.<G>builder()
.onProject()
.forMetric(metric)
.withValue(measure.value())
.build();
}

@Override
public AnalyzerMeasure<?> getMeasure(InputFile file, String metricKey) {
Metric<?> m = metricFinder.findByKey(metricKey);
if (m == null) {
throw new IllegalStateException("Unknow metric with key: " + metricKey);
}
return getMeasure(file, m);
}

@Override
public <G extends Serializable> AnalyzerMeasure<G> getMeasure(InputFile file, Metric<G> metric) {
File fileRes = File.fromIOFile(file.file(), project);
org.sonar.api.measures.Metric<G> m = metricFinder.findByKey(metric.key());
Measure<G> measure = sensorContext.getMeasure(fileRes, m);
if (measure == null) {
return null;
}
return AnalyzerMeasure.<G>builder()
.onFile(file)
.forMetric(metric)
.withValue(measure.value())
.build();
}

@Override
public void addMeasure(AnalyzerMeasure<?> measure) {
org.sonar.api.measures.Metric<?> m = metricFinder.findByKey(measure.metricKey());

Measure measureToSave = new Measure(m);
switch (m.getType()) {
case BOOL:
measureToSave.setValue(Boolean.TRUE.equals(measure.value()) ? 1.0 : 0.0);
break;
case INT:
case MILLISEC:
measureToSave.setValue(Double.valueOf(((Integer) measure.value())));
break;
case FLOAT:
case PERCENT:
case RATING:
measureToSave.setValue(((Double) measure.value()));
break;
case STRING:
case LEVEL:
case DATA:
case DISTRIB:
measureToSave.setData(((String) measure.value()));
break;
case WORK_DUR:
measureToSave.setValue(Double.valueOf(((Long) measure.value())));
break;
default:
if (m.isNumericType()) {
measureToSave.setValue(((Double) measure.value()));
} else if (m.isDataType()) {
measureToSave.setData(((String) measure.value()));
} else {
throw new UnsupportedOperationException("Unsupported type :" + m.getType());
}
}
if (measure.inputFile() != null) {
File fileRes = File.fromIOFile(measure.inputFile().file(), project);
sensorContext.saveMeasure(fileRes, measureToSave);
} else {
sensorContext.saveMeasure(measureToSave);
}
}

@Override
public void addIssue(AnalyzerIssue issue) {
Resource r;
if (issue.inputFile() != null) {
r = File.fromIOFile(issue.inputFile().file(), project);
} else {
r = project;
}
Issuable issuable = perspectives.as(Issuable.class, r);
issuable.addIssue(issuable.newIssueBuilder()
.ruleKey(RuleKey.of(issue.ruleKey().repository(), issue.ruleKey().rule()))
.effortToFix(issue.effortToFix())
.line(issue.line())
.message(issue.message())
.build());
}

@Override
public void addIssues(Collection<AnalyzerIssue> issues) {
for (AnalyzerIssue analyzerIssue : issues) {
addIssue(analyzerIssue);
}
}

}

+ 4
- 5
sonar-batch/src/main/java/org/sonar/batch/scan/LanguageVerifier.java ファイルの表示

@@ -25,9 +25,9 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.config.Settings;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.api.languages.Language;
import org.sonar.batch.languages.LanguagesReferential;

/**
* Verifies that the property sonar.language is valid
@@ -37,16 +37,15 @@ public class LanguageVerifier implements Startable {
private static final Logger LOG = LoggerFactory.getLogger(LanguageVerifier.class);

private final Settings settings;
private final Languages languages;
private final LanguagesReferential languages;
private final DefaultFileSystem fs;

public LanguageVerifier(Settings settings, Languages languages, DefaultFileSystem fs) {
public LanguageVerifier(Settings settings, LanguagesReferential languages, DefaultFileSystem fs) {
this.settings = settings;
this.languages = languages;
this.fs = fs;
}


@Override
public void start() {
if (settings.hasKey(CoreProperties.PROJECT_LANGUAGE_PROPERTY)) {

+ 11
- 1
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java ファイルの表示

@@ -39,6 +39,9 @@ import org.sonar.batch.bootstrap.ExtensionInstaller;
import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.bootstrap.ExtensionUtils;
import org.sonar.batch.components.TimeMachineConfiguration;
import org.sonar.batch.debt.DebtDecorator;
import org.sonar.batch.debt.IssueChangelogDebtCalculator;
import org.sonar.batch.debt.NewDebtDecorator;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.DefaultIndex;
import org.sonar.batch.index.ResourcePersister;
@@ -139,6 +142,7 @@ public class ModuleScanContainer extends ComponentContainer {

TimeMachineConfiguration.class,
DefaultSensorContext.class,
AnalyzerContextAdaptor.class,
BatchExtensionDictionnary.class,
DefaultTimeMachine.class,
ViolationFilters.class,
@@ -178,6 +182,11 @@ public class ModuleScanContainer extends ComponentContainer {
// language
LanguageDistributionDecorator.class,

// Debt
IssueChangelogDebtCalculator.class,
DebtDecorator.class,
NewDebtDecorator.class,

ScanPerspectives.class);
}

@@ -191,7 +200,8 @@ public class ModuleScanContainer extends ComponentContainer {
// Example : C# plugin adds sub-projects at runtime, even if they are not defined in root pom.
return !ExtensionUtils.isMavenExtensionOnly(extension) || module.getPom() != null;
}
return false;
return ExtensionUtils.isType(extension, org.sonar.batch.api.BatchComponent.class)
&& ExtensionUtils.isInstantiationStrategy(extension, org.sonar.batch.api.InstantiationStrategy.PER_PROJECT);
}
});
}

+ 17
- 25
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java ファイルの表示

@@ -40,7 +40,6 @@ import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.bootstrap.ExtensionUtils;
import org.sonar.batch.bootstrap.MetricProvider;
import org.sonar.batch.components.PeriodsDefinition;
import org.sonar.batch.debt.DebtModelProvider;
import org.sonar.batch.debt.IssueChangelogDebtCalculator;
import org.sonar.batch.index.Caches;
import org.sonar.batch.index.ComponentDataCache;
@@ -61,9 +60,9 @@ import org.sonar.batch.issue.DeprecatedViolations;
import org.sonar.batch.issue.IssueCache;
import org.sonar.batch.issue.IssuePersister;
import org.sonar.batch.issue.ScanIssueStorage;
import org.sonar.batch.languages.DeprecatedLanguagesReferential;
import org.sonar.batch.phases.GraphPersister;
import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
import org.sonar.batch.rule.RulesProvider;
import org.sonar.batch.scan.filesystem.InputFileCache;
import org.sonar.batch.scan.maven.FakeMavenPluginExecutor;
import org.sonar.batch.scan.maven.MavenPluginExecutor;
@@ -101,27 +100,23 @@ public class ProjectScanContainer extends ComponentContainer {
}

private void projectBootstrap() {
// Old versions of bootstrappers used to pass project reactor as an extension
// so check if it is already present in parent container
ProjectReactor reactor = getComponentByType(ProjectReactor.class);
ProjectReactor reactor;
// OK, not present, so look for a custom ProjectBootstrapper
ProjectBootstrapper bootstrapper = getComponentByType(ProjectBootstrapper.class);
Settings settings = getComponentByType(Settings.class);
if (bootstrapper == null
// Starting from Maven plugin 2.3 then only DefaultProjectBootstrapper should be used.
|| "true".equals(settings.getString("sonar.mojoUseRunner"))) {
// Use default SonarRunner project bootstrapper
ProjectReactorBuilder builder = getComponentByType(ProjectReactorBuilder.class);
reactor = builder.execute();
} else {
reactor = bootstrapper.bootstrap();
}
if (reactor == null) {
// OK, not present, so look for a custom ProjectBootstrapper
ProjectBootstrapper bootstrapper = getComponentByType(ProjectBootstrapper.class);
Settings settings = getComponentByType(Settings.class);
if (bootstrapper == null
// Starting from Maven plugin 2.3 then only DefaultProjectBootstrapper should be used.
|| "true".equals(settings.getString("sonar.mojoUseRunner"))) {
// Use default SonarRunner project bootstrapper
ProjectReactorBuilder builder = getComponentByType(ProjectReactorBuilder.class);
reactor = builder.execute();
} else {
reactor = bootstrapper.bootstrap();
}
if (reactor == null) {
throw new SonarException(bootstrapper + " has returned null as ProjectReactor");
}
add(reactor);
throw new SonarException(bootstrapper + " has returned null as ProjectReactor");
}
add(reactor);
}

private void addBatchComponents() {
@@ -175,15 +170,12 @@ public class ProjectScanContainer extends ComponentContainer {

// lang
Languages.class,
DeprecatedLanguagesReferential.class,
HighlightableBuilder.class,
SymbolizableBuilder.class,

// technical debt
DefaultTechnicalDebtModel.class,
new DebtModelProvider(),

// rules
new RulesProvider(),

// Differential periods
PeriodsDefinition.class,

+ 8
- 1
sonar-batch/src/main/java/org/sonar/batch/scan/ScanTask.java ファイルの表示

@@ -24,8 +24,10 @@ import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.task.Task;
import org.sonar.api.task.TaskDefinition;
import org.sonar.batch.DefaultProjectTree;
import org.sonar.batch.bootstrap.BootstrapProperties;
import org.sonar.batch.bootstrap.TaskContainer;
import org.sonar.batch.phases.Phases;
import org.sonar.batch.scan2.ProjectScanContainer;

public class ScanTask implements Task {
public static final TaskDefinition DEFINITION = TaskDefinition.builder()
@@ -41,7 +43,12 @@ public class ScanTask implements Task {
}

public void execute() {
scan(new ProjectScanContainer(taskContainer));
boolean sensorMode = CoreProperties.ANALYSIS_MODE_SENSOR.equals(taskContainer.getComponentByType(BootstrapProperties.class).property(CoreProperties.ANALYSIS_MODE));
if (sensorMode) {
new ProjectScanContainer(taskContainer).execute();
} else {
scan(new org.sonar.batch.scan.ProjectScanContainer(taskContainer));
}
}

// Add components specific to project scan (views will use different ones)

+ 78
- 0
sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java ファイルの表示

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

import org.sonar.api.batch.DependedUpon;
import org.sonar.api.batch.DependsUpon;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.resources.Project;
import org.sonar.batch.api.analyzer.Analyzer;
import org.sonar.batch.api.analyzer.AnalyzerContext;
import org.sonar.batch.api.measures.Metric;

import java.util.Arrays;
import java.util.List;

public class SensorWrapper implements Sensor {

private Analyzer analyzer;
private AnalyzerContext adaptor;
private FileSystem fs;

public SensorWrapper(Analyzer analyzer, AnalyzerContext adaptor, FileSystem fs) {
this.analyzer = analyzer;
this.adaptor = adaptor;
this.fs = fs;
}

@DependedUpon
public List<Metric<?>> provides() {
return Arrays.asList(analyzer.describe().provides());
}

@DependsUpon
public List<Metric<?>> depends() {
return Arrays.asList(analyzer.describe().dependsOn());
}

@Override
public boolean shouldExecuteOnProject(Project project) {
if (!analyzer.describe().languages().isEmpty()) {
if (project.getLanguageKey() != null && !analyzer.describe().languages().contains(project.getLanguageKey())) {
return false;
}
boolean hasFile = false;
for (String languageKey : analyzer.describe().languages()) {
hasFile |= fs.hasFiles(fs.predicates().hasLanguage(languageKey));
}
if (!hasFile) {
return false;
}
}
return true;
}

@Override
public void analyse(Project module, SensorContext context) {
analyzer.analyse(adaptor);
}
}

+ 5
- 5
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/AdditionalFilePredicates.java ファイルの表示

@@ -22,7 +22,7 @@ package org.sonar.batch.scan.filesystem;
import org.apache.commons.io.FilenameUtils;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;

/**
* Additional {@link org.sonar.api.batch.fs.FilePredicate}s that are
@@ -43,7 +43,7 @@ class AdditionalFilePredicates {

@Override
public boolean apply(InputFile f) {
return key.equals(((DefaultInputFile) f).key());
return key.equals(((DeprecatedDefaultInputFile) f).key());
}
}

@@ -56,7 +56,7 @@ class AdditionalFilePredicates {

@Override
public boolean apply(InputFile f) {
return key.equals(((DefaultInputFile) f).deprecatedKey());
return key.equals(((DeprecatedDefaultInputFile) f).deprecatedKey());
}
}

@@ -69,7 +69,7 @@ class AdditionalFilePredicates {

@Override
public boolean apply(InputFile f) {
return path.equals(((DefaultInputFile) f).pathRelativeToSourceDir());
return path.equals(((DeprecatedDefaultInputFile) f).pathRelativeToSourceDir());
}
}

@@ -82,7 +82,7 @@ class AdditionalFilePredicates {

@Override
public boolean apply(InputFile f) {
return path.equals(((DefaultInputFile) f).sourceDirAbsolutePath());
return path.equals(((DeprecatedDefaultInputFile) f).sourceDirAbsolutePath());
}
}
}

+ 2
- 2
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java ファイルの表示

@@ -27,7 +27,7 @@ import org.sonar.api.CoreProperties;
import org.sonar.api.batch.SonarIndex;
import org.sonar.api.batch.fs.FileSystem;
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.api.config.Settings;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Languages;
@@ -65,7 +65,7 @@ public class ComponentIndexer implements BatchComponent {
for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
String languageKey = inputFile.language();
boolean unitTest = InputFile.Type.TEST == inputFile.type();
String pathFromSourceDir = ((DefaultInputFile) inputFile).pathRelativeToSourceDir();
String pathFromSourceDir = ((DeprecatedDefaultInputFile) inputFile).pathRelativeToSourceDir();
if (pathFromSourceDir == null) {
pathFromSourceDir = inputFile.relativePath();
}

+ 22
- 6
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java ファイルの表示

@@ -27,13 +27,14 @@ import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.config.Settings;
import org.sonar.api.resources.Project;
import org.sonar.api.scan.filesystem.FileQuery;
import org.sonar.api.scan.filesystem.ModuleFileSystem;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.MessageException;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -66,11 +67,24 @@ public class DefaultModuleFileSystem extends DefaultFileSystem implements Module
private ComponentIndexer componentIndexer;
private boolean initialized;

public DefaultModuleFileSystem(ModuleInputFileCache moduleInputFileCache, Project module, Settings settings, FileIndexer indexer, ModuleFileSystemInitializer initializer,
/**
* Used by scan2
*/
public DefaultModuleFileSystem(ModuleInputFileCache moduleInputFileCache, ProjectDefinition def, Settings settings, FileIndexer indexer, ModuleFileSystemInitializer initializer) {
this(moduleInputFileCache, def.getKey(), settings, indexer, initializer, null);
}

public DefaultModuleFileSystem(ModuleInputFileCache moduleInputFileCache, ProjectDefinition def, Project project, Settings settings, FileIndexer indexer,
ModuleFileSystemInitializer initializer,
ComponentIndexer componentIndexer) {
this(moduleInputFileCache, project.getKey(), settings, indexer, initializer, componentIndexer);
}

private DefaultModuleFileSystem(ModuleInputFileCache moduleInputFileCache, String moduleKey, Settings settings, FileIndexer indexer, ModuleFileSystemInitializer initializer,
@Nullable ComponentIndexer componentIndexer) {
super(moduleInputFileCache);
this.componentIndexer = componentIndexer;
this.moduleKey = module.getKey();
this.moduleKey = moduleKey;
this.settings = settings;
this.indexer = indexer;
if (initializer.baseDir() != null) {
@@ -202,7 +216,7 @@ public class DefaultModuleFileSystem extends DefaultFileSystem implements Module

public void resetDirs(File basedir, File buildDir, List<File> sourceDirs, List<File> testDirs, List<File> binaryDirs) {
if (initialized) {
throw new SonarException("Module filesystem is already initialized. Modifications of filesystem are only allowed during Initializer phase.");
throw MessageException.of("Module filesystem is already initialized. Modifications of filesystem are only allowed during Initializer phase.");
}
setBaseDir(basedir);
this.buildDir = buildDir;
@@ -213,11 +227,13 @@ public class DefaultModuleFileSystem extends DefaultFileSystem implements Module

public void index() {
if (initialized) {
throw new SonarException("Module filesystem can only be indexed once");
throw MessageException.of("Module filesystem can only be indexed once");
}
initialized = true;
indexer.index(this);
componentIndexer.execute(this);
if (componentIndexer != null) {
componentIndexer.execute(this);
}
}

private List<File> existingDirs(List<File> dirs) {

+ 3
- 3
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileFilters.java ファイルの表示

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

import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFileFilter;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
import org.sonar.api.scan.filesystem.FileSystemFilter;
import org.sonar.api.scan.filesystem.FileType;
import org.sonar.api.scan.filesystem.ModuleFileSystem;
@@ -72,12 +72,12 @@ public class DeprecatedFileFilters implements InputFileFilter {

@Override
public File relativeDir() {
return new File(((DefaultInputFile)inputFile).sourceDirAbsolutePath());
return new File(((DeprecatedDefaultInputFile)inputFile).sourceDirAbsolutePath());
}

@Override
public String relativePath() {
return ((DefaultInputFile)inputFile).pathRelativeToSourceDir();
return ((DeprecatedDefaultInputFile)inputFile).pathRelativeToSourceDir();
}

@Override

+ 28
- 13
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndexer.java ファイルの表示

@@ -27,11 +27,12 @@ import org.apache.commons.io.filefilter.IOFileFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFileFilter;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.MessageException;

import java.io.File;
import java.util.Collection;
@@ -44,31 +45,45 @@ import java.util.Set;
*/
public class FileIndexer implements BatchComponent {

private static final Logger LOG = LoggerFactory.getLogger(FileIndexer.class);

private static final IOFileFilter DIR_FILTER = FileFilterUtils.and(HiddenFileFilter.VISIBLE, FileFilterUtils.notFileFilter(FileFilterUtils.prefixFileFilter(".")));
private static final IOFileFilter FILE_FILTER = HiddenFileFilter.VISIBLE;

private final List<InputFileFilter> filters;
private final InputFileCache fileCache;
private final Project module;
private final boolean isAggregator;
private final ExclusionFilters exclusionFilters;
private final InputFileBuilderFactory inputFileBuilderFactory;

public FileIndexer(List<InputFileFilter> filters, ExclusionFilters exclusionFilters, InputFileBuilderFactory inputFileBuilderFactory,
InputFileCache cache, Project module) {
InputFileCache cache, Project module, ProjectDefinition def) {
this(filters, exclusionFilters, inputFileBuilderFactory, cache, !module.getModules().isEmpty());
}

/**
* Used by scan2
*/
public FileIndexer(List<InputFileFilter> filters, ExclusionFilters exclusionFilters, InputFileBuilderFactory inputFileBuilderFactory,
InputFileCache cache, ProjectDefinition def) {
this(filters, exclusionFilters, inputFileBuilderFactory, cache, !def.getSubProjects().isEmpty());
}

private FileIndexer(List<InputFileFilter> filters, ExclusionFilters exclusionFilters, InputFileBuilderFactory inputFileBuilderFactory,
InputFileCache cache, boolean isAggregator) {
this.filters = filters;
this.exclusionFilters = exclusionFilters;
this.inputFileBuilderFactory = inputFileBuilderFactory;
this.fileCache = cache;
this.module = module;
this.isAggregator = isAggregator;
}

void index(DefaultModuleFileSystem fileSystem) {
Logger logger = LoggerFactory.getLogger(FileIndexer.class);
if (!module.getModules().isEmpty()) {
if (isAggregator) {
// No indexing for an aggregator module
return;
}
logger.info("Index files");
LOG.info("Index files");
exclusionFilters.prepare();

Progress progress = new Progress(fileCache.byModule(fileSystem.moduleKey()));
@@ -93,13 +108,13 @@ public class FileIndexer implements BatchComponent {
fileCache.remove(fileSystem.moduleKey(), removed);
}

logger.info(String.format("%d files indexed", progress.count()));
LOG.info(String.format("%d files indexed", progress.count()));

}

private void indexFiles(InputFileBuilder inputFileBuilder, DefaultModuleFileSystem fileSystem, Progress progress, List<File> sourceFiles, InputFile.Type type) {
for (File sourceFile : sourceFiles) {
DefaultInputFile inputFile = inputFileBuilder.create(sourceFile);
DeprecatedDefaultInputFile inputFile = inputFileBuilder.create(sourceFile);
if (inputFile != null && exclusionFilters.accept(inputFile, type)) {
indexFile(inputFileBuilder, fileSystem, progress, inputFile, type);
}
@@ -109,7 +124,7 @@ public class FileIndexer implements BatchComponent {
private void indexDirectory(InputFileBuilder inputFileBuilder, DefaultModuleFileSystem fileSystem, Progress status, File dirToIndex, InputFile.Type type) {
Collection<File> files = FileUtils.listFiles(dirToIndex, FILE_FILTER, DIR_FILTER);
for (File file : files) {
DefaultInputFile inputFile = inputFileBuilder.create(file);
DeprecatedDefaultInputFile inputFile = inputFileBuilder.create(file);
if (inputFile != null && exclusionFilters.accept(inputFile, type)) {
indexFile(inputFileBuilder, fileSystem, status, inputFile, type);
}
@@ -117,7 +132,7 @@ public class FileIndexer implements BatchComponent {
}

private void indexFile(InputFileBuilder inputFileBuilder, DefaultModuleFileSystem fs,
Progress status, DefaultInputFile inputFile, InputFile.Type type) {
Progress status, DeprecatedDefaultInputFile inputFile, InputFile.Type type) {
InputFile completedFile = inputFileBuilder.complete(inputFile, type);
if (completedFile != null && accept(completedFile)) {
fs.add(completedFile);
@@ -146,7 +161,7 @@ public class FileIndexer implements BatchComponent {

void markAsIndexed(InputFile inputFile) {
if (indexed.contains(inputFile)) {
throw new SonarException("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
+ "disjoint sets for main and test files");
}
removed.remove(inputFile);

+ 5
- 5
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilder.java ファイルの表示

@@ -24,7 +24,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.FileSystem;
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.api.scan.filesystem.PathResolver;
import org.sonar.batch.bootstrap.AnalysisMode;
import org.sonar.batch.util.DeprecatedKeyUtils;
@@ -76,13 +76,13 @@ class InputFileBuilder {
}

@CheckForNull
DefaultInputFile create(File file) {
DeprecatedDefaultInputFile create(File file) {
String relativePath = pathResolver.relativePath(fs.baseDir(), file);
if (relativePath == null) {
LOG.warn("File '{}' is ignored. It is not located in module basedir '{}'.", file.getAbsolutePath(), fs.baseDir());
return null;
}
DefaultInputFile inputFile = new DefaultInputFile(relativePath);
DeprecatedDefaultInputFile inputFile = new DeprecatedDefaultInputFile(relativePath);
inputFile.setBasedir(fs.baseDir());
inputFile.setFile(file);
return inputFile;
@@ -92,7 +92,7 @@ class InputFileBuilder {
* Optimization to not set all InputFile data if the file is excluded from analysis.
*/
@CheckForNull
DefaultInputFile complete(DefaultInputFile inputFile, InputFile.Type type) {
DeprecatedDefaultInputFile complete(DeprecatedDefaultInputFile inputFile, InputFile.Type type) {
inputFile.setType(type);
inputFile.setKey(new StringBuilder().append(moduleKey).append(":").append(inputFile.relativePath()).toString());
inputFile.setBasedir(fs.baseDir());
@@ -112,7 +112,7 @@ class InputFileBuilder {
return inputFile;
}

private void fillDeprecatedData(DefaultInputFile inputFile) {
private void fillDeprecatedData(DeprecatedDefaultInputFile inputFile) {
List<File> sourceDirs = InputFile.Type.MAIN == inputFile.type() ? fs.sourceDirs() : fs.testDirs();
for (File sourceDir : sourceDirs) {
String sourceRelativePath = pathResolver.relativePath(sourceDir, inputFile.file());

+ 0
- 0
sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilderFactory.java ファイルの表示


変更されたファイルが多すぎるため、一部のファイルは表示されません

読み込み中…
キャンセル
保存