diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2014-01-29 23:22:42 +0100 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2014-01-29 23:31:56 +0100 |
commit | 0058d50600159ab128bb3c45d0b7438d20954109 (patch) | |
tree | 0de2f8fe6d0aa15bf6f0c88676274f8e475b16f1 | |
parent | 7e627194938dfcba2c5ff60beb92a26e4a92ea7c (diff) | |
download | sonarqube-0058d50600159ab128bb3c45d0b7438d20954109.tar.gz sonarqube-0058d50600159ab128bb3c45d0b7438d20954109.zip |
SONAR-5031 Provide line count as attribute of InputFile
3 files changed, 53 insertions, 32 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java index ad0064f565c..45224104444 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ComponentIndexer.java @@ -19,9 +19,7 @@ */ package org.sonar.batch.scan.filesystem; -import org.sonar.api.scan.filesystem.internal.DefaultInputFile; - -import org.sonar.api.scan.filesystem.InputFile; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.CharMatcher; import com.google.common.io.Files; import org.apache.commons.lang.StringUtils; @@ -37,6 +35,8 @@ import org.sonar.api.resources.Languages; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.scan.filesystem.FileQuery; +import org.sonar.api.scan.filesystem.InputFile; +import org.sonar.api.scan.filesystem.internal.DefaultInputFile; import org.sonar.api.utils.SonarException; import org.sonar.batch.index.ResourceKeyMigration; import org.sonar.batch.scan.language.DefaultModuleLanguages; @@ -57,9 +57,10 @@ public class ComponentIndexer implements BatchComponent { private final Project module; private final DefaultModuleLanguages moduleLanguages; private final ResourceDao resourceDao; + private InputFileCache fileCache; public ComponentIndexer(Project module, Languages languages, SonarIndex sonarIndex, Settings settings, ResourceKeyMigration migration, - DefaultModuleLanguages moduleLanguages, ResourceDao resourceDao) { + DefaultModuleLanguages moduleLanguages, ResourceDao resourceDao, InputFileCache fileCache) { this.module = module; this.languages = languages; this.sonarIndex = sonarIndex; @@ -67,10 +68,11 @@ public class ComponentIndexer implements BatchComponent { this.migration = migration; this.moduleLanguages = moduleLanguages; this.resourceDao = resourceDao; + this.fileCache = fileCache; } public void execute(DefaultModuleFileSystem fs) { - boolean importSource = settings.getBoolean(CoreProperties.CORE_IMPORT_SOURCES_PROPERTY); + boolean shouldImportSource = settings.getBoolean(CoreProperties.CORE_IMPORT_SOURCES_PROPERTY); Iterable<InputFile> inputFiles = fs.inputFiles(FileQuery.all()); migration.migrateIfNeeded(module, inputFiles); for (InputFile inputFile : inputFiles) { @@ -85,21 +87,28 @@ public class ComponentIndexer implements BatchComponent { if (sonarFile != null) { moduleLanguages.addLanguage(languageKey); sonarIndex.index(sonarFile); - if (importSource) { - importSources(inputFile, sonarFile); - } + importSources(shouldImportSource, inputFile, sonarFile); } } updateModuleLanguage(); } - private void importSources(InputFile inputFile, Resource sonarFile) { + @VisibleForTesting + void importSources(boolean shouldImportSource, InputFile inputFile, Resource sonarFile) { try { + // TODO this part deserve optimization. + // No need to read full content in memory when shouldImportSource=false + // We should try to remove BOM and count lines in a single pass String source = Files.toString(inputFile.file(), inputFile.encoding()); // SONAR-3860 Remove BOM character from source source = CharMatcher.anyOf("\uFEFF").removeFrom(source); - sonarIndex.setSource(sonarFile, source); + String[] lines = source.split("(\r)?\n|\r", -1); + inputFile.attributes().put(InputFile.ATTRIBUTE_LINE_COUNT, String.valueOf(lines.length)); + fileCache.put(module.getKey(), inputFile); + if (shouldImportSource) { + sonarIndex.setSource(sonarFile, source); + } } catch (Exception e) { throw new SonarException("Unable to read and import the source file : '" + inputFile.absolutePath() + "' with the charset : '" + inputFile.encoding() + "'.", e); diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java index c0945f0f570..69c01e7ffab 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ComponentIndexerTest.java @@ -19,8 +19,6 @@ */ package org.sonar.batch.scan.filesystem; -import org.sonar.api.scan.filesystem.InputFile; - import com.google.common.base.Charsets; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.CharEncoding; @@ -41,6 +39,7 @@ import org.sonar.api.resources.Project; import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Resource; import org.sonar.api.scan.filesystem.FileQuery; +import org.sonar.api.scan.filesystem.InputFile; import org.sonar.api.scan.filesystem.internal.DefaultInputFile; import org.sonar.api.scan.filesystem.internal.InputFileBuilder; import org.sonar.batch.index.ResourceKeyMigration; @@ -52,6 +51,7 @@ import java.io.IOException; import java.nio.charset.Charset; import java.util.Arrays; +import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -96,10 +96,9 @@ public class ComponentIndexerTest { newInputFile("src/main/java/foo/bar/Foo.java", "", "foo/bar/Foo.java", "java", false), newInputFile("src/main/java2/foo/bar/Foo.java", "", "foo/bar/Foo.java", "java", false), newInputFile("src/test/java/foo/bar/FooTest.java", "", "foo/bar/FooTest.java", "java", true))); - when(project.getLanguageKey()).thenReturn(Java.KEY); Languages languages = new Languages(Java.INSTANCE); ComponentIndexer indexer = new ComponentIndexer(project, languages, sonarIndex, settings, mock(ResourceKeyMigration.class), new DefaultModuleLanguages(settings, languages), - mock(ResourceDao.class)); + mock(ResourceDao.class), mock(InputFileCache.class)); indexer.execute(fs); verify(sonarIndex).index(JavaFile.create("src/main/java/foo/bar/Foo.java", "foo/bar/Foo.java", false)); @@ -121,11 +120,10 @@ public class ComponentIndexerTest { newInputFile("src/foo/bar/Foo.cbl", "", "foo/bar/Foo.cbl", "cobol", false), newInputFile("src2/foo/bar/Foo.cbl", "", "foo/bar/Foo.cbl", "cobol", false), newInputFile("src/test/foo/bar/FooTest.cbl", "", "foo/bar/FooTest.cbl", "cobol", true))); - when(project.getLanguageKey()).thenReturn("cobol"); Languages languages = new Languages(cobolLanguage); ComponentIndexer indexer = new ComponentIndexer(project, languages, sonarIndex, settings, mock(ResourceKeyMigration.class), new DefaultModuleLanguages(settings, languages), - mock(ResourceDao.class)); + mock(ResourceDao.class), mock(InputFileCache.class)); indexer.execute(fs); verify(sonarIndex).index(org.sonar.api.resources.File.create("/src/foo/bar/Foo.cbl", "foo/bar/Foo.cbl", cobolLanguage, false)); @@ -139,10 +137,9 @@ public class ComponentIndexerTest { when(fs.inputFiles(FileQuery.all())).thenReturn((Iterable) Arrays.asList( newInputFile("src/main/java/foo/bar/Foo.java", "sample code", "foo/bar/Foo.java", "java", false))); - when(project.getLanguageKey()).thenReturn(Java.KEY); Languages languages = new Languages(Java.INSTANCE); ComponentIndexer indexer = new ComponentIndexer(project, languages, sonarIndex, settings, mock(ResourceKeyMigration.class), new DefaultModuleLanguages(settings, languages), - mock(ResourceDao.class)); + mock(ResourceDao.class), mock(InputFileCache.class)); indexer.execute(fs); Resource sonarFile = JavaFile.create("src/main/java/foo/bar/Foo.java", "foo/bar/Foo.java", false); @@ -150,16 +147,6 @@ public class ComponentIndexerTest { verify(sonarIndex).setSource(sonarFile, "sample code"); } - private DefaultInputFile newInputFile(String path, String content, String sourceRelativePath, String languageKey, boolean unitTest) throws IOException { - File file = new File(baseDir, path); - FileUtils.write(file, content); - return new InputFileBuilder(file, Charsets.UTF_8, path) - .attribute(DefaultInputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, sourceRelativePath) - .attribute(InputFile.ATTRIBUTE_LANGUAGE, languageKey) - .attribute(InputFile.ATTRIBUTE_TYPE, unitTest ? InputFile.TYPE_TEST : InputFile.TYPE_MAIN) - .build(); - } - @Test public void should_use_mac_roman_charset_for_reading_source_files() throws Exception { String encoding = "MacRoman"; @@ -192,10 +179,9 @@ public class ComponentIndexerTest { .attribute(DefaultInputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "foo/bar/Foo.java") .attribute(InputFile.ATTRIBUTE_LANGUAGE, "java") .build())); - when(project.getLanguageKey()).thenReturn(Java.KEY); Languages languages = new Languages(Java.INSTANCE); ComponentIndexer indexer = new ComponentIndexer(project, languages, sonarIndex, settings, mock(ResourceKeyMigration.class), new DefaultModuleLanguages(settings, languages), - mock(ResourceDao.class)); + mock(ResourceDao.class), mock(InputFileCache.class)); indexer.execute(fs); Resource sonarFile = JavaFile.create("src/main/java/foo/bar/Foo.java", "foo/bar/Foo.java", false); @@ -221,10 +207,9 @@ public class ComponentIndexerTest { .attribute(DefaultInputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, "foo/bar/Foo.java") .attribute(InputFile.ATTRIBUTE_LANGUAGE, "java") .build())); - when(project.getLanguageKey()).thenReturn(Java.KEY); Languages languages = new Languages(Java.INSTANCE); ComponentIndexer indexer = new ComponentIndexer(project, languages, sonarIndex, settings, mock(ResourceKeyMigration.class), new DefaultModuleLanguages(settings, languages), - mock(ResourceDao.class)); + mock(ResourceDao.class), mock(InputFileCache.class)); indexer.execute(fs); Resource sonarFile = JavaFile.create("/src/main/java/foo/bar/Foo.java", "foo/bar/Foo.java", false); @@ -238,8 +223,30 @@ public class ComponentIndexerTest { })); } + @Test + public void should_compute_line_count() throws IOException { + DefaultInputFile inputFile = newInputFile("src/main/java/foo/bar/Foo.java", "line1\nline2\nline3", "foo/bar/Foo.java", "java", false); + when(fs.inputFiles(FileQuery.all())).thenReturn((Iterable) Arrays.asList(inputFile)); + Languages languages = new Languages(Java.INSTANCE); + ComponentIndexer indexer = new ComponentIndexer(project, languages, sonarIndex, settings, mock(ResourceKeyMigration.class), new DefaultModuleLanguages(settings, languages), + mock(ResourceDao.class), mock(InputFileCache.class)); + indexer.execute(fs); + + assertThat(inputFile.attribute(InputFile.ATTRIBUTE_LINE_COUNT)).isEqualTo("3"); + } + private File getFile(String testFile) { return new File("test-resources/org/sonar/batch/phases/FileIndexerTest/encoding/" + testFile); } + private DefaultInputFile newInputFile(String path, String content, String sourceRelativePath, String languageKey, boolean unitTest) throws IOException { + File file = new File(baseDir, path); + FileUtils.write(file, content); + return new InputFileBuilder(file, Charsets.UTF_8, path) + .attribute(DefaultInputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, sourceRelativePath) + .attribute(InputFile.ATTRIBUTE_LANGUAGE, languageKey) + .attribute(InputFile.ATTRIBUTE_TYPE, unitTest ? InputFile.TYPE_TEST : InputFile.TYPE_MAIN) + .build(); + } + } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java index 91ed1c144c1..e811576ec2e 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/InputFile.java @@ -34,6 +34,11 @@ public interface InputFile extends Serializable { String ATTRIBUTE_LANGUAGE = "LANG"; /** + * Number of lines in the file. + */ + String ATTRIBUTE_LINE_COUNT = "LINE_COUNT"; + + /** * Type of source file. For now only possible values are {@link #TYPE_MAIN} or {@link #TYPE_TEST} */ String ATTRIBUTE_TYPE = "TYPE"; |