aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2013-10-11 12:13:24 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2013-10-11 12:13:32 +0200
commitf71a3cec9d925fb94d06d735c62c51e66109322f (patch)
tree430cb04495dc4d6a47dbebfb58347edde987f47b /sonar-batch
parent23506cffec508d01da926795860813e66f36d366 (diff)
downloadsonarqube-f71a3cec9d925fb94d06d735c62c51e66109322f.tar.gz
sonarqube-f71a3cec9d925fb94d06d735c62c51e66109322f.zip
SONAR-4751 do not fail but warn if a file extension is declared in multiple plugins
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndex.java3
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java61
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageRecognizerTest.java109
3 files changed, 102 insertions, 71 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndex.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndex.java
index c625b4a4ae2..2efaae29c67 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndex.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileIndex.java
@@ -151,9 +151,8 @@ public class FileIndex implements BatchComponent {
@CheckForNull
private InputFile newInputFile(ModuleFileSystem fileSystem, File sourceDir, String type, File file, String path) {
- // File extension must be kept case-sensitive
String lang = languageRecognizer.of(file);
- if (lang == null) {
+ if (lang==null) {
return null;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java
index 2214f24df1e..6357ee744ea 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageRecognizer.java
@@ -19,63 +19,82 @@
*/
package org.sonar.batch.scan.filesystem;
-import com.google.common.collect.Maps;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
+import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Project;
import javax.annotation.CheckForNull;
import java.io.File;
-import java.util.Map;
+import java.util.Set;
/**
* Detect language of source files. Simplistic, based on file extensions.
*/
public class LanguageRecognizer implements BatchComponent, Startable {
- /**
- * Lower-case extension -> language
- */
- private Map<String, String> byExtensions = Maps.newHashMap();
+ static final String NO_EXTENSION = "<UNSET>";
+ private final Project project;
private final Language[] languages;
- public LanguageRecognizer(Language[] languages) {
+ /**
+ * Lower-case extension -> languages
+ */
+ private SetMultimap<String, String> langsByExtension = HashMultimap.create();
+
+ public LanguageRecognizer(Project project, Language[] languages) {
+ this.project = project;
this.languages = languages;
}
@Override
public void start() {
for (Language language : languages) {
- for (String suffix : language.getFileSuffixes()) {
- String extension = sanitizeExtension(suffix);
+ if (language.getFileSuffixes().length == 0) {
+ langsByExtension.put(NO_EXTENSION, language.getKey());
- String s = byExtensions.get(extension);
- if (s != null && !StringUtils.equals(s, language.getKey())) {
- throw new IllegalStateException(String.format(
- "File extension '%s' is declared by two languages: %s and %s", extension, s, language.getKey()
- ));
+ } else {
+ for (String suffix : language.getFileSuffixes()) {
+ String extension = sanitizeExtension(suffix);
+ langsByExtension.put(extension, language.getKey());
}
- byExtensions.put(extension, language.getKey());
+ }
+ }
+
+ for (String extension : langsByExtension.keySet()) {
+ Set<String> langs = langsByExtension.get(extension);
+ if (langs.size() > 1) {
+ warnConflict(extension, langs);
}
}
}
+ @VisibleForTesting
+ void warnConflict(String extension, Set<String> langs) {
+ LoggerFactory.getLogger(LanguageRecognizer.class).warn(String.format(
+ "File extension '%s' is declared by several plugins: %s", extension, StringUtils.join(langs, ", ")
+ ));
+ }
+
@Override
public void stop() {
// do nothing
}
- // TODO what about cobol files without extension ?
@CheckForNull
String of(File file) {
- String extension = FilenameUtils.getExtension(file.getName());
- if (StringUtils.isNotBlank(extension)) {
- return byExtensions.get(StringUtils.lowerCase(extension));
- }
- return null;
+ // multi-language is not supported yet. Filter on project language
+ String extension = sanitizeExtension(FilenameUtils.getExtension(file.getName()));
+ extension = StringUtils.defaultIfBlank(extension, NO_EXTENSION);
+ Set<String> langs = langsByExtension.get(extension);
+ return langs.contains(project.getLanguageKey()) ? project.getLanguageKey() : null;
}
static String sanitizeExtension(String suffix) {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageRecognizerTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageRecognizerTest.java
index dbba4e17311..b329f3bfbb6 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageRecognizerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageRecognizerTest.java
@@ -22,11 +22,14 @@ package org.sonar.batch.scan.filesystem;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.resources.Java;
+import org.mockito.ArgumentMatcher;
import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Project;
+
+import java.util.Set;
import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
+import static org.mockito.Mockito.*;
public class LanguageRecognizerTest {
@@ -43,13 +46,18 @@ public class LanguageRecognizerTest {
@Test
public void search_by_file_extension() throws Exception {
- Language[] languages = new Language[]{Java.INSTANCE, new Cobol()};
- LanguageRecognizer recognizer = new LanguageRecognizer(languages);
+ Language[] languages = new Language[]{new MockLanguage("java", "java", "jav"), new MockLanguage("cobol", "cbl", "cob")};
+ LanguageRecognizer recognizer = new LanguageRecognizer(newProject("java"), languages);
recognizer.start();
- assertThat(recognizer.of(temp.newFile("Foo.java"))).isEqualTo(Java.KEY);
- assertThat(recognizer.of(temp.newFile("abc.cbl"))).isEqualTo("cobol");
- assertThat(recognizer.of(temp.newFile("abc.CBL"))).isEqualTo("cobol");
+ assertThat(recognizer.of(temp.newFile("Foo.java"))).isEqualTo("java");
+ assertThat(recognizer.of(temp.newFile("Foo.JAVA"))).isEqualTo("java");
+ assertThat(recognizer.of(temp.newFile("Foo.jav"))).isEqualTo("java");
+ assertThat(recognizer.of(temp.newFile("Foo.Jav"))).isEqualTo("java");
+
+ // multi-language is not supported yet -> filter on project language
+ assertThat(recognizer.of(temp.newFile("abc.cbl"))).isNull();
+ assertThat(recognizer.of(temp.newFile("abc.CBL"))).isNull();
assertThat(recognizer.of(temp.newFile("abc.php"))).isNull();
assertThat(recognizer.of(temp.newFile("abc"))).isNull();
recognizer.stop();
@@ -57,72 +65,77 @@ public class LanguageRecognizerTest {
@Test
public void fail_if_conflict_of_file_extensions() throws Exception {
- Language[] languages = new Language[]{Java.INSTANCE, new Language() {
- @Override
- public String getKey() {
- return "java2";
- }
+ Language[] languages = new Language[]{new MockLanguage("java", "java"), new MockLanguage("java2", "java", "java2")};
- @Override
- public String getName() {
- return "Java2";
- }
+ LanguageRecognizer recognizer = spy(new LanguageRecognizer(newProject("java"), languages));
+ recognizer.start();
+ verify(recognizer).warnConflict(eq("java"), argThat(new ArgumentMatcher<Set<String>>() {
@Override
- public String[] getFileSuffixes() {
- return new String[]{"java2", "java"};
+ public boolean matches(Object o) {
+ Set<String> set = (Set<String>) o;
+ return set.contains("java") && set.contains("java2") && set.size() == 2;
}
- }};
-
- try {
- new LanguageRecognizer(languages).start();
- fail();
- } catch (IllegalStateException e) {
- assertThat(e.getMessage()).isEqualTo("File extension 'java' is declared by two languages: java and java2");
- }
+ }));
}
+
@Test
public void plugin_can_declare_a_file_extension_twice_for_case_sensitivity() throws Exception {
- Language[] languages = new Language[]{new Language() {
- @Override
- public String getKey() {
- return "abap";
- }
+ Language[] languages = new Language[]{new MockLanguage("abap", "abap", "ABAP")};
- @Override
- public String getName() {
- return "ABAP";
- }
+ LanguageRecognizer recognizer = new LanguageRecognizer(newProject("abap"), languages);
+ recognizer.start();
+ assertThat(recognizer.of(temp.newFile("abc.abap"))).isEqualTo("abap");
+ }
- @Override
- public String[] getFileSuffixes() {
- return new String[]{"abap", "ABAP"};
- }
- }};
+ @Test
+ public void language_with_no_extension() throws Exception {
+ // abap here is associated to files without extension
+ Language[] languages = new Language[]{new MockLanguage("java", "java"), new MockLanguage("abap")};
- LanguageRecognizer recognizer = new LanguageRecognizer(languages);
+ // files without extension are detected only on abap projects
+ LanguageRecognizer recognizer = new LanguageRecognizer(newProject("java"), languages);
recognizer.start();
- assertThat(recognizer.of(temp.newFile("abc.abap"))).isEqualTo("abap");
+ assertThat(recognizer.of(temp.newFile("abc"))).isNull();
+ recognizer.stop();
+
+ recognizer = new LanguageRecognizer(newProject("abap"), languages);
+ recognizer.start();
+ assertThat(recognizer.of(temp.newFile("abc"))).isEqualTo("abap");
+ recognizer.stop();
}
- static class Cobol implements Language {
+ private Project newProject(String language) {
+ Project project = mock(Project.class);
+ when(project.getLanguageKey()).thenReturn(language);
+ return project;
+ }
+
+
+ static class MockLanguage implements Language {
+ private final String key;
+ private final String[] extensions;
+
+ MockLanguage(String key, String... extensions) {
+ this.key = key;
+ this.extensions = extensions;
+ }
+
@Override
public String getKey() {
- return "cobol";
+ return key;
}
@Override
public String getName() {
- return "Cobol";
+ return key;
}
@Override
public String[] getFileSuffixes() {
- return new String[]{"cbl", "cob"};
+ return extensions;
}
}
-
-
}