import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.api.scan.filesystem.FileExclusions;
-import org.sonar.batch.DefaultProjectClasspath;
-import org.sonar.batch.DefaultSensorContext;
-import org.sonar.batch.DefaultTimeMachine;
-import org.sonar.batch.ProjectTree;
-import org.sonar.batch.ResourceFilters;
-import org.sonar.batch.ViolationFilters;
+import org.sonar.batch.*;
import org.sonar.batch.bootstrap.BatchExtensionDictionnary;
import org.sonar.batch.bootstrap.ExtensionInstaller;
import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.rule.ModuleRulesProvider;
import org.sonar.batch.rule.QProfileSensor;
import org.sonar.batch.rule.RulesProfileProvider;
-import org.sonar.batch.scan.filesystem.ComponentIndexer;
-import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.batch.scan.filesystem.DeprecatedFileFilters;
-import org.sonar.batch.scan.filesystem.ExclusionFilters;
-import org.sonar.batch.scan.filesystem.FileHashes;
-import org.sonar.batch.scan.filesystem.FileIndex;
-import org.sonar.batch.scan.filesystem.FileSystemLogger;
-import org.sonar.batch.scan.filesystem.LanguageRecognizer;
-import org.sonar.batch.scan.filesystem.ModuleFileSystemInitializer;
-import org.sonar.batch.scan.filesystem.ProjectFileSystemAdapter;
-import org.sonar.batch.scan.filesystem.RemoteFileHashes;
+import org.sonar.batch.scan.filesystem.*;
import org.sonar.batch.scan.language.DefaultModuleLanguages;
import org.sonar.batch.scan.report.ComponentSelectorFactory;
import org.sonar.batch.scan.report.JsonReport;
FileExclusions.class,
ExclusionFilters.class,
DeprecatedFileFilters.class,
- FileHashes.class,
- RemoteFileHashes.class,
+ InputFileBuilderFactory.class,
+ StatusDetectionFactory.class,
+ LanguageDetectionFactory.class,
+ PreviousFileHashLoader.class,
FileIndex.class,
ComponentIndexer.class,
DefaultModuleLanguages.class,
- LanguageRecognizer.class,
FileSystemLogger.class,
DefaultProjectClasspath.class,
DefaultModuleFileSystem.class,
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.IOUtils;
-
-import java.io.*;
-import java.nio.charset.Charset;
-import java.security.MessageDigest;
-
-/**
- * Computes hash of files. Ends of Lines are ignored, so files with
- * same content but different EOL encoding have the same hash.
- */
-class FileHashDigest {
-
- // This singleton aims only to increase the coverage by allowing
- // to test the private method !
- static final FileHashDigest INSTANCE = new FileHashDigest();
-
- private FileHashDigest() {
- }
-
- /**
- * Compute hash of a file ignoring line ends differences.
- * Maximum performance is needed.
- */
- String hash(File file, Charset charset) {
- Reader reader = null;
- try {
- MessageDigest md5Digest = DigestUtils.getMd5Digest();
- md5Digest.reset();
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
- int i = reader.read();
- boolean afterCR = true;
- while (i != -1) {
- char c = (char) i;
- if (afterCR) {
- afterCR = false;
- if (c == '\n') {
- // Ignore
- i = reader.read();
- continue;
- }
- }
- if (c == '\r') {
- afterCR = true;
- c = '\n';
- }
- md5Digest.update(charToBytesUTF(c));
- i = reader.read();
- }
- return Hex.encodeHexString(md5Digest.digest());
- } catch (IOException e) {
- throw new IllegalStateException(String.format("Fail to compute hash of file %s with charset %s", file.getAbsolutePath(), charset), e);
- } finally {
- IOUtils.closeQuietly(reader);
- }
- }
-
- private byte[] charToBytesUTF(char c) {
- char[] buffer = new char[]{c};
- byte[] b = new byte[buffer.length << 1];
- for (int i = 0; i < buffer.length; i++) {
- int bpos = i << 1;
- b[bpos] = (byte) ((buffer[i] & 0xFF00) >> 8);
- b[bpos + 1] = (byte) (buffer[i] & 0x00FF);
- }
- return b;
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.sonar.api.BatchComponent;
-
-import javax.annotation.CheckForNull;
-import java.io.File;
-import java.nio.charset.Charset;
-
-/**
- * Facade for local and remote file hashes
- */
-public class FileHashes implements BatchComponent {
-
- private final RemoteFileHashes remoteFileHashes;
-
- public FileHashes(RemoteFileHashes remoteFileHashes) {
- this.remoteFileHashes = remoteFileHashes;
- }
-
- @CheckForNull
- public String hash(File file, Charset charset) {
- return FileHashDigest.INSTANCE.hash(file, charset);
- }
-
- @CheckForNull
- public String remoteHash(String baseRelativePath) {
- return remoteFileHashes.remoteHash(baseRelativePath);
- }
-}
*/
package org.sonar.batch.scan.filesystem;
-import com.google.common.collect.Maps;
import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.HiddenFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
-import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
-import org.sonar.api.resources.Java;
-import org.sonar.api.resources.JavaFile;
import org.sonar.api.resources.Project;
import org.sonar.api.scan.filesystem.InputDir;
import org.sonar.api.scan.filesystem.InputFile;
-import org.sonar.api.scan.filesystem.InputFileFilter;
-import org.sonar.api.scan.filesystem.ModuleFileSystem;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.api.scan.filesystem.internal.DefaultInputDir;
-import org.sonar.api.scan.filesystem.internal.DefaultInputFile;
+import org.sonar.api.scan.filesystem.InputFileFilter;
import org.sonar.api.utils.PathUtils;
import org.sonar.api.utils.SonarException;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
import java.io.File;
-import java.nio.charset.Charset;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
private final PathResolver pathResolver;
private final List<InputFileFilter> filters;
- private final LanguageRecognizer languageRecognizer;
private final InputFileCache fileCache;
- private final FileHashes fileHashes;
private final Project module;
private final ExclusionFilters exclusionFilters;
+ private final InputFileBuilderFactory inputFileBuilderFactory;
- public FileIndex(List<InputFileFilter> filters, ExclusionFilters exclusionFilters, LanguageRecognizer languageRecognizer,
- InputFileCache cache, FileHashes fileHashes, PathResolver pathResolver, Project project) {
+ public FileIndex(List<InputFileFilter> filters, ExclusionFilters exclusionFilters, InputFileBuilderFactory inputFileBuilderFactory,
+ InputFileCache cache, PathResolver pathResolver, Project project) {
this.filters = filters;
this.exclusionFilters = exclusionFilters;
- this.languageRecognizer = languageRecognizer;
+ this.inputFileBuilderFactory = inputFileBuilderFactory;
this.fileCache = cache;
- this.fileHashes = fileHashes;
this.pathResolver = pathResolver;
this.module = project;
}
Progress progress = new Progress(fileCache.fileRelativePaths(fileSystem.moduleKey()));
+ InputFileBuilder inputFileBuilder = inputFileBuilderFactory.create(fileSystem);
if (!fileSystem.sourceFiles().isEmpty() || !fileSystem.testFiles().isEmpty()) {
// Index only provided files
- indexFiles(fileSystem, progress, fileSystem.sourceFiles(), InputFile.TYPE_MAIN);
- indexFiles(fileSystem, progress, fileSystem.testFiles(), InputFile.TYPE_TEST);
+ indexFiles(inputFileBuilder, fileSystem, progress, fileSystem.sourceFiles(), InputFile.TYPE_MAIN);
+ indexFiles(inputFileBuilder, fileSystem, progress, fileSystem.testFiles(), InputFile.TYPE_TEST);
} else if (fileSystem.baseDir() != null) {
// index from basedir
- indexDirectory(fileSystem, progress, fileSystem.baseDir());
+ indexDirectory(inputFileBuilder, fileSystem, progress, fileSystem.baseDir());
}
// Remove files that have been removed since previous indexation
}
- private void indexFiles(DefaultModuleFileSystem fileSystem, Progress progress, List<File> sourceFiles, String type) {
+ private void indexFiles(InputFileBuilder inputFileBuilder, DefaultModuleFileSystem fileSystem, Progress progress, List<File> sourceFiles, String type) {
for (File sourceFile : sourceFiles) {
String path = pathResolver.relativePath(fileSystem.baseDir(), sourceFile);
if (path == null) {
LoggerFactory.getLogger(getClass()).warn(String.format(
"File '%s' is not declared in module basedir %s", sourceFile.getAbsoluteFile(), fileSystem.baseDir()
- ));
+ ));
} else {
if (exclusionFilters.accept(sourceFile, path, type)) {
- indexFile(fileSystem, progress, sourceFile, path, type);
+ indexFile(inputFileBuilder, fileSystem, progress, sourceFile, path, type);
}
}
}
InputDir inputDir(DefaultModuleFileSystem fileSystem, File ioFile) {
String path = computeFilePath(fileSystem, ioFile);
- // TODO no cache for InputDir
- Map<String, String> attributes = Maps.newHashMap();
- // paths
+ DefaultInputDir inputDir = new DefaultInputDir(FilenameUtils.normalize(ioFile.getAbsolutePath(), true), path);
String resourceKey = PathUtils.sanitize(path);
- set(attributes, DefaultInputFile.ATTRIBUTE_COMPONENT_KEY, module.getEffectiveKey() + ":" + resourceKey);
- return DefaultInputDir.create(ioFile, path, attributes);
+ inputDir.setKey(module.getEffectiveKey() + ":" + resourceKey);
+ return inputDir;
}
- private void indexDirectory(DefaultModuleFileSystem fileSystem, Progress status, File dirToIndex) {
+ private void indexDirectory(InputFileBuilder inputFileBuilder, DefaultModuleFileSystem fileSystem, Progress status, File dirToIndex) {
Collection<File> files = FileUtils.listFiles(dirToIndex, FILE_FILTER, DIR_FILTER);
for (File sourceFile : files) {
String path = pathResolver.relativePath(fileSystem.baseDir(), sourceFile);
if (path == null) {
LoggerFactory.getLogger(getClass()).warn(String.format(
"File '%s' is not declared in module basedir %s", sourceFile.getAbsoluteFile(), fileSystem.baseDir()
- ));
+ ));
} else {
if (exclusionFilters.accept(sourceFile, path, InputFile.TYPE_MAIN)) {
- indexFile(fileSystem, status, sourceFile, path, InputFile.TYPE_MAIN);
+ indexFile(inputFileBuilder, fileSystem, status, sourceFile, path, InputFile.TYPE_MAIN);
}
if (exclusionFilters.accept(sourceFile, path, InputFile.TYPE_TEST)) {
- indexFile(fileSystem, status, sourceFile, path, InputFile.TYPE_TEST);
+ indexFile(inputFileBuilder, fileSystem, status, sourceFile, path, InputFile.TYPE_TEST);
}
}
}
}
- private void indexFile(DefaultModuleFileSystem fileSystem, Progress status, File file, String path, String type) {
- InputFile input = newInputFile(fileSystem, type, file, path);
- if (input != null && accept(input)) {
- fileCache.put(fileSystem.moduleKey(), input);
+ private void indexFile(InputFileBuilder inputFileBuilder, DefaultModuleFileSystem fs, Progress status, File file, String path, String type) {
+ InputFile inputFile = inputFileBuilder.create(file, type);
+ if (inputFile != null && accept(inputFile)) {
+ fileCache.put(fs.moduleKey(), inputFile);
status.markAsIndexed(path);
}
}
return pathResolver.relativePath(fileSystem.baseDir(), file);
}
- @CheckForNull
- private InputFile newInputFile(ModuleFileSystem fileSystem, String type, File file, String path) {
-
- Map<String, String> attributes = Maps.newHashMap();
- set(attributes, InputFile.ATTRIBUTE_TYPE, type);
-
- String resourceKey = PathUtils.sanitize(path);
- set(attributes, DefaultInputFile.ATTRIBUTE_COMPONENT_KEY, module.getEffectiveKey() + ":" + resourceKey);
- // hash + status
- initStatus(file, fileSystem.sourceCharset(), path, attributes);
-
- DefaultInputFile inputFile = DefaultInputFile.create(file, fileSystem.sourceCharset(), path, attributes);
- String lang = languageRecognizer.of(inputFile);
- if (lang == null) {
- return null;
- }
- set(inputFile.attributes(), InputFile.ATTRIBUTE_LANGUAGE, lang);
-
- setDeprecatedAttributes(fileSystem, type, file, attributes, inputFile, lang);
-
- return inputFile;
- }
-
- private void setDeprecatedAttributes(ModuleFileSystem fileSystem, String type, File file, Map<String, String> attributes, DefaultInputFile inputFile, String lang) {
- List<File> sourceDirs = InputFile.TYPE_MAIN.equals(type) ? fileSystem.sourceDirs() : fileSystem.testDirs();
- for (File src : sourceDirs) {
- String sourceRelativePath = pathResolver.relativePath(src, file);
- if (sourceRelativePath != null) {
- set(attributes, DefaultInputFile.ATTRIBUTE_SOURCEDIR_PATH, PathUtils.canonicalPath(src));
- set(attributes, DefaultInputFile.ATTRIBUTE_SOURCE_RELATIVE_PATH, sourceRelativePath);
- if (Java.KEY.equals(lang)) {
- set(inputFile.attributes(), DefaultInputFile.ATTRIBUTE_COMPONENT_DEPRECATED_KEY, module.getEffectiveKey() + ":"
- + JavaFile.fromRelativePath(sourceRelativePath, false).getDeprecatedKey());
- } else {
- set(inputFile.attributes(), DefaultInputFile.ATTRIBUTE_COMPONENT_DEPRECATED_KEY, module.getEffectiveKey() + ":" + sourceRelativePath);
- }
- return;
- }
- }
- }
-
- private void initStatus(File file, Charset charset, String baseRelativePath, Map<String, String> attributes) {
- String hash = fileHashes.hash(file, charset);
- set(attributes, DefaultInputFile.ATTRIBUTE_HASH, hash);
-
- String remoteHash = fileHashes.remoteHash(baseRelativePath);
- // currently no need to store this remote hash in attributes
- if (StringUtils.equals(hash, remoteHash)) {
- set(attributes, InputFile.ATTRIBUTE_STATUS, InputFile.STATUS_SAME);
- } else if (StringUtils.isEmpty(remoteHash)) {
- set(attributes, InputFile.ATTRIBUTE_STATUS, InputFile.STATUS_ADDED);
- } else {
- set(attributes, InputFile.ATTRIBUTE_STATUS, InputFile.STATUS_CHANGED);
- }
- }
-
- private void set(Map<String, String> attributes, String key, @Nullable String value) {
- if (value != null) {
- attributes.put(key, value);
- }
- }
private boolean accept(InputFile inputFile) {
// InputFileFilter extensions
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+
+/**
+ * Computes hash of files. Ends of Lines are ignored, so files with
+ * same content but different EOL encoding have the same hash.
+ */
+class FileMetadata {
+
+ private static final char LINE_FEED = '\n';
+ private static final char CARRIAGE_RETURN = '\r';
+
+ // This singleton aims only to increase the coverage by allowing
+ // to test the private method !
+ static final FileMetadata INSTANCE = new FileMetadata();
+
+ private FileMetadata() {
+ }
+
+ /**
+ * Compute hash of a file ignoring line ends differences.
+ * Maximum performance is needed.
+ */
+ Metadata read(File file, Charset encoding) {
+ Reader reader = null;
+ long lines = 0L;
+ char c = (char)-1;
+ try {
+ MessageDigest md5Digest = DigestUtils.getMd5Digest();
+ md5Digest.reset();
+ reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding));
+ int i = reader.read();
+ boolean afterCR = true;
+ while (i != -1) {
+ c = (char) i;
+ if (afterCR) {
+ afterCR = false;
+ if (c == LINE_FEED) {
+ // Ignore
+ i = reader.read();
+ lines++;
+ continue;
+ }
+ }
+ if (c == CARRIAGE_RETURN) {
+ afterCR = true;
+ c = LINE_FEED;
+ } else if (c == LINE_FEED) {
+ lines++;
+ }
+ md5Digest.update(charToBytesUTF(c));
+ i = reader.read();
+ }
+ if (c != LINE_FEED) {
+ lines++;
+ }
+ String hash = Hex.encodeHexString(md5Digest.digest());
+ return new Metadata(lines, hash);
+
+ } catch (IOException e) {
+ throw new IllegalStateException(String.format("Fail to read file '%s' with encoding '%s'", file.getAbsolutePath(), encoding), e);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+
+ private byte[] charToBytesUTF(char c) {
+ char[] buffer = new char[]{c};
+ byte[] b = new byte[buffer.length << 1];
+ for (int i = 0; i < buffer.length; i++) {
+ int bpos = i << 1;
+ b[bpos] = (byte) ((buffer[i] & 0xFF00) >> 8);
+ b[bpos + 1] = (byte) (buffer[i] & 0x00FF);
+ }
+ return b;
+ }
+
+ static class Metadata {
+ long lines;
+ String hash;
+
+ private Metadata(long lines, String hash) {
+ this.lines = lines;
+ this.hash = hash;
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.io.FilenameUtils;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.api.scan.filesystem.internal.DefaultInputFile;
+import org.sonar.api.utils.MessageException;
+
+import javax.annotation.CheckForNull;
+import java.io.File;
+import java.util.List;
+
+class InputFileBuilder {
+
+ private final String moduleKey;
+ private final PathResolver pathResolver;
+ private final LanguageDetection langDetection;
+ private final StatusDetection statusDetection;
+ private final DefaultModuleFileSystem fs;
+
+ InputFileBuilder(String moduleKey, PathResolver pathResolver, LanguageDetection langDetection,
+ StatusDetection statusDetection, DefaultModuleFileSystem fs) {
+ this.moduleKey = moduleKey;
+ this.pathResolver = pathResolver;
+ this.langDetection = langDetection;
+ this.statusDetection = statusDetection;
+ this.fs = fs;
+ }
+
+ @CheckForNull
+ DefaultInputFile create(File file, String type) {
+ String relativePath = pathResolver.relativePath(fs.baseDir(), file);
+ if (relativePath == null) {
+ throw MessageException.of(String.format("File '%s' is ignored. It is not in module basedir '%s'.", file.getAbsolutePath(), fs.baseDir()));
+ }
+ DefaultInputFile inputFile = DefaultInputFile.create(file, fs.sourceCharset(), relativePath, Maps.<String, String>newHashMap());
+ inputFile.setType(type);
+ inputFile.setKey(moduleKey + ":" + inputFile.path());
+ String lang = langDetection.language(inputFile);
+ if (lang == null) {
+ // TODO use a default plain-text language ?
+ return null;
+ }
+ inputFile.setLanguage(lang);
+ FileMetadata.Metadata metadata = FileMetadata.INSTANCE.read(inputFile.file(), fs.sourceCharset());
+ inputFile.setLines(metadata.lines);
+ inputFile.setHash(metadata.hash);
+ inputFile.setStatus(statusDetection.status(inputFile.path(), metadata.hash));
+ fillDeprecatedData(inputFile);
+ return inputFile;
+ }
+
+ private void fillDeprecatedData(DefaultInputFile inputFile) {
+ List<File> sourceDirs = InputFile.TYPE_MAIN.equals(inputFile.type()) ? fs.sourceDirs() : fs.testDirs();
+ for (File sourceDir : sourceDirs) {
+ String sourceRelativePath = pathResolver.relativePath(sourceDir, inputFile.file());
+ if (sourceRelativePath != null) {
+ inputFile.setPathRelativeToSourceDir(sourceRelativePath);
+ inputFile.setSourceDirAbsolutePath(FilenameUtils.normalize(sourceDir.getAbsolutePath(), true));
+
+ if (Java.KEY.equals(inputFile.language())) {
+ inputFile.setDeprecatedKey(moduleKey + ":" + JavaFile.fromRelativePath(sourceRelativePath, false).getDeprecatedKey());
+ } else {
+ inputFile.setDeprecatedKey(moduleKey + ":" + sourceRelativePath);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.api.resources.Project;
+import org.sonar.api.scan.filesystem.PathResolver;
+
+public class InputFileBuilderFactory implements BatchComponent {
+
+ private final String moduleKey;
+ private final PathResolver pathResolver;
+ private final LanguageDetectionFactory langDetectionFactory;
+ private final StatusDetectionFactory statusDetectionFactory;
+
+ public InputFileBuilderFactory(Project moduleDef, PathResolver pathResolver, LanguageDetectionFactory langDetectionFactory,
+ StatusDetectionFactory statusDetectionFactory) {
+ this.moduleKey = moduleDef.getEffectiveKey();
+ this.pathResolver = pathResolver;
+ this.langDetectionFactory = langDetectionFactory;
+ this.statusDetectionFactory = statusDetectionFactory;
+ }
+
+ InputFileBuilder create(DefaultModuleFileSystem fs) {
+ return new InputFileBuilder(moduleKey, pathResolver, langDetectionFactory.create(), statusDetectionFactory.create(), fs);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.utils.MessageException;
+
+import javax.annotation.CheckForNull;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Detect language of a source file based on its suffix and configured patterns.
+ */
+class LanguageDetection {
+
+ private static final Logger LOG = LoggerFactory.getLogger(LanguageDetection.class);
+
+ /**
+ * Lower-case extension -> languages
+ */
+ private final Map<String, PathPattern[]> patternByLanguage = Maps.newLinkedHashMap();
+ private final List<String> languagesToConsider = Lists.newArrayList();
+ private final String forcedLanguage;
+
+ LanguageDetection(Settings settings, Languages languages) {
+ for (Language language : languages.all()) {
+ String[] filePatterns = settings.getStringArray(getFileLangPatternPropKey(language.getKey()));
+ PathPattern[] pathPatterns = PathPattern.create(filePatterns);
+ if (pathPatterns.length > 0) {
+ patternByLanguage.put(language.getKey(), pathPatterns);
+ } else {
+ // If no custom language pattern is defined then fallback to suffixes declared by language
+ String[] patterns = Arrays.copyOf(language.getFileSuffixes(), language.getFileSuffixes().length);
+ for (int i = 0; i < patterns.length; i++) {
+ String suffix = patterns[i];
+ String extension = sanitizeExtension(suffix);
+ patterns[i] = "**/*." + extension;
+ }
+ PathPattern[] defaultLanguagePatterns = PathPattern.create(patterns);
+ patternByLanguage.put(language.getKey(), defaultLanguagePatterns);
+ LOG.debug("Declared extensions of language " + language + " were converted to " + getDetails(language.getKey()));
+ }
+ }
+
+ forcedLanguage = StringUtils.defaultIfBlank(settings.getString(CoreProperties.PROJECT_LANGUAGE_PROPERTY), null);
+ // First try with lang patterns
+ if (forcedLanguage != null) {
+ if (!patternByLanguage.containsKey(forcedLanguage)) {
+ throw MessageException.of("No language is installed with key '" + forcedLanguage + "'. Please update property '" + CoreProperties.PROJECT_LANGUAGE_PROPERTY + "'");
+ }
+ languagesToConsider.add(forcedLanguage);
+ } else {
+ languagesToConsider.addAll(patternByLanguage.keySet());
+ }
+ }
+
+ @CheckForNull
+ String language(InputFile inputFile) {
+ String detectedLanguage = null;
+ for (String languageKey : languagesToConsider) {
+ PathPattern[] patterns = patternByLanguage.get(languageKey);
+ if (patterns != null) {
+ for (PathPattern pathPattern : patterns) {
+ if (pathPattern.match(inputFile, false)) {
+ if (detectedLanguage == null) {
+ detectedLanguage = languageKey;
+ break;
+ } else {
+ // Language was already forced by another pattern
+ throw MessageException.of("Language of file '" + inputFile.path() + "' can not be decided as the file matches patterns of both " + getDetails(detectedLanguage)
+ + " and " + getDetails(languageKey));
+ }
+ }
+ }
+ }
+ }
+ if (detectedLanguage != null) {
+ LOG.debug("Language of file '" + inputFile.path() + "' was detected to be '" + detectedLanguage + "'");
+ return detectedLanguage;
+ }
+
+ // Check if deprecated sonar.language is used and we are on a language without declared extensions
+ if (forcedLanguage != null) {
+ // Languages without declared suffixes match everything
+ if (patternByLanguage.get(forcedLanguage).length == 0) {
+ return forcedLanguage;
+ }
+ }
+ return null;
+ }
+
+ private String getFileLangPatternPropKey(String languageKey) {
+ return "sonar.lang.patterns." + languageKey;
+ }
+
+ private String getDetails(String detectedLanguage) {
+ return getFileLangPatternPropKey(detectedLanguage) + " : " + Joiner.on(",").join(patternByLanguage.get(detectedLanguage));
+ }
+
+ static String sanitizeExtension(String suffix) {
+ return StringUtils.lowerCase(StringUtils.removeStart(suffix, "."));
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Languages;
+
+public class LanguageDetectionFactory implements BatchComponent {
+ private final Settings settings;
+ private final Languages languages;
+
+ public LanguageDetectionFactory(Settings settings, Languages languages) {
+ this.settings = settings;
+ this.languages = languages;
+ }
+
+ public LanguageDetection create() {
+ return new LanguageDetection(settings, languages);
+ }
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.Maps;
-import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.scan.filesystem.InputFile;
-import org.sonar.api.utils.SonarException;
-
-import javax.annotation.CheckForNull;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Detect language of source files.
- */
-public class LanguageRecognizer implements BatchComponent, Startable {
-
- private static final Logger LOG = LoggerFactory.getLogger(LanguageRecognizer.class);
-
- private final Languages languages;
-
- /**
- * Lower-case extension -> languages
- */
- private Map<String, PathPattern[]> patternByLanguage = Maps.newLinkedHashMap();
-
- private Settings settings;
-
- public LanguageRecognizer(Settings settings, Languages languages) {
- this.settings = settings;
- this.languages = languages;
- }
-
- @Override
- public void start() {
- for (Language language : languages.all()) {
- String[] filePatterns = settings.getStringArray(getFileLangPatternPropKey(language.getKey()));
- PathPattern[] pathPatterns = PathPattern.create(filePatterns);
- if (pathPatterns.length > 0) {
- patternByLanguage.put(language.getKey(), pathPatterns);
- } else if (language.getFileSuffixes().length > 0) {
- // If no custom language pattern is defined then fallback to suffixes declared by language
- String[] patterns = Arrays.copyOf(language.getFileSuffixes(), language.getFileSuffixes().length);
- for (int i = 0; i < patterns.length; i++) {
- String suffix = patterns[i];
- String extension = sanitizeExtension(suffix);
- patterns[i] = "**/*." + extension;
- }
- PathPattern[] defaultLanguagePatterns = PathPattern.create(patterns);
- patternByLanguage.put(language.getKey(), defaultLanguagePatterns);
- LOG.debug("Declared extensions of language " + language + " were converted to " + getDetails(language.getKey()));
- }
- }
- }
-
- private String getFileLangPatternPropKey(String languageKey) {
- return "sonar.lang.patterns." + languageKey;
- }
-
- @Override
- public void stop() {
- // do nothing
- }
-
- @CheckForNull
- String of(InputFile inputFile) {
- String deprecatedLanguageParam = settings.getString(CoreProperties.PROJECT_LANGUAGE_PROPERTY);
-
- // First try with lang patterns
- List<String> languagesToConsider = new ArrayList<String>();
- if (!StringUtils.isBlank(deprecatedLanguageParam)) {
- languagesToConsider.add(deprecatedLanguageParam);
- } else {
- languagesToConsider.addAll(patternByLanguage.keySet());
- }
- String detectedLanguage = null;
- for (String languageKey : languagesToConsider) {
- PathPattern[] patterns = patternByLanguage.get(languageKey);
- if (patterns != null) {
- for (PathPattern pathPattern : patterns) {
- if (pathPattern.match(inputFile, false)) {
- if (detectedLanguage == null) {
- detectedLanguage = languageKey;
- break;
- } else {
- // Language was already forced by another pattern
- throw new SonarException("Language of file '" + inputFile.path() + "' can not be decided as the file matches patterns of both " + getDetails(detectedLanguage)
- + " and " + getDetails(languageKey));
- }
- }
- }
- }
- }
- if (detectedLanguage != null) {
- LOG.debug("Language of file '" + inputFile.path() + "' was detected to be '" + detectedLanguage + "'");
- return detectedLanguage;
- }
-
- // Check if deprecated sonar.language is used and we are on a language without declared extensions
- if (StringUtils.isNotBlank(deprecatedLanguageParam)) {
- Language language = languages.get(deprecatedLanguageParam);
- if (language == null) {
- throw new SonarException("No language is installed with key '" + deprecatedLanguageParam + "'. Please update property '" + CoreProperties.PROJECT_LANGUAGE_PROPERTY + "'");
- }
- // Languages without declared suffixes match everything
- String[] fileSuffixes = language.getFileSuffixes();
- if (fileSuffixes.length == 0) {
- return deprecatedLanguageParam;
- }
- return null;
- }
-
- return null;
- }
-
- private String getDetails(String detectedLanguage) {
- return getFileLangPatternPropKey(detectedLanguage) + " : " + Joiner.on(",").join(patternByLanguage.get(detectedLanguage));
- }
-
- static String sanitizeExtension(String suffix) {
- return StringUtils.lowerCase(StringUtils.removeStart(suffix, "."));
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.collect.Maps;
+import org.picocontainer.Startable;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.batch.components.PastSnapshot;
+import org.sonar.batch.components.PastSnapshotFinder;
+import org.sonar.core.source.SnapshotDataTypes;
+import org.sonar.core.source.db.SnapshotDataDao;
+import org.sonar.core.source.db.SnapshotDataDto;
+
+import javax.annotation.CheckForNull;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+
+public class PreviousFileHashLoader implements BatchComponent {
+
+ private final SnapshotDataDao dao;
+ private final PastSnapshotFinder pastSnapshotFinder;
+ private final Snapshot snapshot;
+
+ public PreviousFileHashLoader(Snapshot snapshot, SnapshotDataDao dao, PastSnapshotFinder pastSnapshotFinder) {
+ this.snapshot = snapshot;
+ this.dao = dao;
+ this.pastSnapshotFinder = pastSnapshotFinder;
+ }
+
+ /**
+ * Extract hash of the files parsed during the previous analysis
+ */
+ Map<String, String> hashByRelativePath() {
+ Map<String, String> map = Maps.newHashMap();
+ PastSnapshot pastSnapshot = pastSnapshotFinder.findPreviousAnalysis(snapshot);
+ if (pastSnapshot.isRelatedToSnapshot()) {
+ Collection<SnapshotDataDto> selectSnapshotData = dao.selectSnapshotData(
+ pastSnapshot.getProjectSnapshot().getId().longValue(),
+ Arrays.asList(SnapshotDataTypes.FILE_HASHES)
+ );
+ if (!selectSnapshotData.isEmpty()) {
+ SnapshotDataDto snapshotDataDto = selectSnapshotData.iterator().next();
+ String data = snapshotDataDto.getData();
+ map = KeyValueFormat.parse(data);
+ }
+ }
+ return map;
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.collect.Maps;
-import org.picocontainer.Startable;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.PastSnapshotFinder;
-import org.sonar.core.source.SnapshotDataTypes;
-import org.sonar.core.source.db.SnapshotDataDao;
-import org.sonar.core.source.db.SnapshotDataDto;
-
-import javax.annotation.CheckForNull;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Map;
-
-public class RemoteFileHashes implements BatchComponent, Startable {
-
- private final SnapshotDataDao dao;
- private final PastSnapshotFinder pastSnapshotFinder;
- private final Snapshot snapshot;
-
- private Map<String, String> pathToHash = Maps.newHashMap();
-
- public RemoteFileHashes(Snapshot snapshot, SnapshotDataDao dao, PastSnapshotFinder pastSnapshotFinder) {
- this.snapshot = snapshot;
- this.dao = dao;
- this.pastSnapshotFinder = pastSnapshotFinder;
- }
-
- @Override
- public void start() {
- // Extract previous checksum of all files of this module and store them in a map
- PastSnapshot pastSnapshot = pastSnapshotFinder.findPreviousAnalysis(snapshot);
- if (pastSnapshot.isRelatedToSnapshot()) {
- Collection<SnapshotDataDto> selectSnapshotData = dao.selectSnapshotData(
- pastSnapshot.getProjectSnapshot().getId().longValue(),
- Arrays.asList(SnapshotDataTypes.FILE_HASHES)
- );
- if (!selectSnapshotData.isEmpty()) {
- SnapshotDataDto snapshotDataDto = selectSnapshotData.iterator().next();
- String data = snapshotDataDto.getData();
- pathToHash = KeyValueFormat.parse(data);
- }
- }
- }
-
- @CheckForNull
- public String remoteHash(String baseRelativePath) {
- return pathToHash.get(baseRelativePath);
- }
-
- @Override
- public void stop() {
- // nothing to do
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.scan.filesystem.InputFile;
+
+import java.util.Map;
+
+class StatusDetection {
+
+ private final Map<String, String> previousHashByRelativePath;
+
+ StatusDetection(Map<String, String> previousHashByRelativePath) {
+ this.previousHashByRelativePath = previousHashByRelativePath;
+ }
+
+ String status(String relativePath, String hash) {
+ String previousHash = previousHashByRelativePath.get(relativePath);
+
+ if (StringUtils.equals(hash, previousHash)) {
+ return InputFile.STATUS_SAME;
+ }
+ if (StringUtils.isEmpty(previousHash)) {
+ return InputFile.STATUS_ADDED;
+ }
+ return InputFile.STATUS_CHANGED;
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.sonar.api.BatchComponent;
+
+public class StatusDetectionFactory implements BatchComponent {
+
+ private final PreviousFileHashLoader previousFileHashLoader;
+
+ public StatusDetectionFactory(PreviousFileHashLoader l) {
+ this.previousFileHashLoader = l;
+ }
+
+ StatusDetection create() {
+ return new StatusDetection(previousFileHashLoader.hashByRelativePath());
+ }
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.base.Charsets;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class FileHashDigestTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void should_compute_hash() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\r\nbar", Charsets.UTF_8, true);
-
- assertThat(FileHashDigest.INSTANCE.hash(tempFile, Charsets.UTF_8)).isEqualTo("daef8a22a3f12580beadf086a9e11519");
- }
-
- @Test
- public void should_normalize_line_ends() throws Exception {
- File file1 = temp.newFile();
- FileUtils.write(file1, "foobar\nfofo", Charsets.UTF_8);
- String hash1 = FileHashDigest.INSTANCE.hash(file1, Charsets.UTF_8);
-
- File file2 = temp.newFile();
- FileUtils.write(file2, "foobar\r\nfofo", Charsets.UTF_8);
- String hash2 = FileHashDigest.INSTANCE.hash(file2, Charsets.UTF_8);
-
- File file3 = temp.newFile();
- FileUtils.write(file3, "foobar\rfofo", Charsets.UTF_8);
- String hash3 = FileHashDigest.INSTANCE.hash(file3, Charsets.UTF_8);
-
- File file4 = temp.newFile();
- FileUtils.write(file4, "foobar\nfofo\n", Charsets.UTF_8);
- String hash4 = FileHashDigest.INSTANCE.hash(file4, Charsets.UTF_8);
-
- assertThat(hash1).isEqualTo(hash2);
- assertThat(hash1).isEqualTo(hash3);
- assertThat(hash1).isNotEqualTo(hash4);
- }
-
- @Test
- public void should_throw_if_file_does_not_exist() throws Exception {
- File tempFolder = temp.newFolder();
- File file = new File(tempFolder, "doesNotExist.txt");
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("Fail to compute hash of file " + file.getAbsolutePath() + " with charset UTF-8");
-
- FileHashDigest.INSTANCE.hash(file, Charsets.UTF_8);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-import java.nio.charset.Charset;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.*;
-
-public class FileHashesTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- RemoteFileHashes remoteFileHashes = mock(RemoteFileHashes.class);
-
- @Test
- public void hash() throws Exception {
- File file = temp.newFile();
- FileUtils.write(file, "fooo");
-
- FileHashes hashes = new FileHashes(remoteFileHashes);
- assertThat(hashes.hash(file, Charset.forName("UTF-8"))).isEqualTo("efc4470c96a94b1ff400175ef8368444");
- verifyZeroInteractions(remoteFileHashes);
- }
-
- @Test
- public void remote_hash() throws Exception {
- String path = "src/main/java/Foo.java";
- when(remoteFileHashes.remoteHash(path)).thenReturn("ABCDE");
-
- FileHashes hashes = new FileHashes(remoteFileHashes);
- assertThat(hashes.remoteHash(path)).isEqualTo("ABCDE");
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.resources.Project;
-import org.sonar.api.scan.filesystem.InputDir;
-import org.sonar.api.scan.filesystem.InputFile;
-import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.api.scan.filesystem.internal.DefaultInputDir;
-
-import java.io.File;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class FileIndexTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void should_return_inputDir() throws Exception {
- FileIndex index = new FileIndex(null, null, null, null, null, new PathResolver(), new Project("myProject"));
- File baseDir = temp.newFolder();
- DefaultModuleFileSystem fileSystem = mock(DefaultModuleFileSystem.class);
- when(fileSystem.baseDir()).thenReturn(baseDir);
- File ioFile = new File(baseDir, "src/main/java/com/foo");
- InputDir inputDir = index.inputDir(fileSystem, ioFile);
-
- assertThat(inputDir.name()).isEqualTo("src/main/java/com/foo");
- assertThat(inputDir.file()).isEqualTo(ioFile);
- assertThat(inputDir.attribute(DefaultInputDir.ATTRIBUTE_COMPONENT_KEY)).isEqualTo("myProject:src/main/java/com/foo");
- }
-
- @Test
- public void should_not_index_aggregator() throws Exception {
- Project project = new Project("myProject");
- new Project("moduleA").setParent(project);
- InputFileCache fileCache = mock(InputFileCache.class);
- FileIndex index = new FileIndex(null, null, null, fileCache, null, new PathResolver(), project);
-
- index.index(null);
-
- verify(fileCache, never()).put(anyString(), any(InputFile.class));
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.base.Charsets;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class FileMetadataTest {
+
+ private static final String EXPECTED_HASH_WITHOUT_LATEST_EOL = "c80cc50d65ace6c4eb63f189d274dbeb";
+ private static final String EXPECTED_HASH_WITH_LATEST_EOL = "bf77e51d219e7d7d643faac86f1b5d15";
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void windows_without_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\r\nbar\r\nbaz", Charsets.UTF_8, true);
+
+ FileMetadata.Metadata metadata = FileMetadata.INSTANCE.read(tempFile, Charsets.UTF_8);
+ assertThat(metadata.lines).isEqualTo(3L);
+ assertThat(metadata.hash).isEqualTo(EXPECTED_HASH_WITHOUT_LATEST_EOL);
+ }
+
+ @Test
+ public void windows_with_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\r\nbar\r\nbaz\r\n", Charsets.UTF_8, true);
+
+ FileMetadata.Metadata metadata = FileMetadata.INSTANCE.read(tempFile, Charsets.UTF_8);
+ assertThat(metadata.lines).isEqualTo(3L);
+ assertThat(metadata.hash).isEqualTo(EXPECTED_HASH_WITH_LATEST_EOL);
+ }
+
+ @Test
+ public void unix_without_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\nbar\nbaz", Charsets.UTF_8, true);
+
+ FileMetadata.Metadata metadata = FileMetadata.INSTANCE.read(tempFile, Charsets.UTF_8);
+ assertThat(metadata.lines).isEqualTo(3L);
+ assertThat(metadata.hash).isEqualTo(EXPECTED_HASH_WITHOUT_LATEST_EOL);
+ }
+
+ @Test
+ public void unix_with_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\nbar\nbaz\n", Charsets.UTF_8, true);
+
+ FileMetadata.Metadata metadata = FileMetadata.INSTANCE.read(tempFile, Charsets.UTF_8);
+ assertThat(metadata.lines).isEqualTo(3L);
+ assertThat(metadata.hash).isEqualTo(EXPECTED_HASH_WITH_LATEST_EOL);
+ }
+
+ @Test
+ public void mix_of_newlines_with_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\nbar\r\nbaz\n", Charsets.UTF_8, true);
+
+ FileMetadata.Metadata metadata = FileMetadata.INSTANCE.read(tempFile, Charsets.UTF_8);
+ assertThat(metadata.lines).isEqualTo(3L);
+ assertThat(metadata.hash).isEqualTo(EXPECTED_HASH_WITH_LATEST_EOL);
+ }
+
+ @Test
+ public void mix_of_newlines_without_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\nbar\r\nbaz", Charsets.UTF_8, true);
+
+ FileMetadata.Metadata metadata = FileMetadata.INSTANCE.read(tempFile, Charsets.UTF_8);
+ assertThat(metadata.lines).isEqualTo(3L);
+ assertThat(metadata.hash).isEqualTo(EXPECTED_HASH_WITHOUT_LATEST_EOL);
+ }
+
+ @Test
+ public void should_throw_if_file_does_not_exist() throws Exception {
+ File tempFolder = temp.newFolder();
+ File file = new File(tempFolder, "doesNotExist.txt");
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Fail to read file '" + file.getAbsolutePath() + "' with encoding 'UTF-8'");
+
+ FileMetadata.INSTANCE.read(file, Charsets.UTF_8);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import com.google.common.base.Charsets;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.scan.filesystem.InputFile;
+import org.sonar.api.scan.filesystem.internal.InputFileBuilder;
+import org.sonar.api.utils.MessageException;
+
+import java.io.File;
+import java.io.IOException;
+
+import static junit.framework.Assert.fail;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
+
+public class LanguageDetectionTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void test_sanitizeExtension() throws Exception {
+ assertThat(LanguageDetection.sanitizeExtension(".cbl")).isEqualTo("cbl");
+ assertThat(LanguageDetection.sanitizeExtension(".CBL")).isEqualTo("cbl");
+ assertThat(LanguageDetection.sanitizeExtension("CBL")).isEqualTo("cbl");
+ assertThat(LanguageDetection.sanitizeExtension("cbl")).isEqualTo("cbl");
+ }
+
+ @Test
+ public void search_by_file_extension() throws Exception {
+ Languages languages = new Languages(new MockLanguage("java", "java", "jav"), new MockLanguage("cobol", "cbl", "cob"));
+ LanguageDetection detection = new LanguageDetection(new Settings(), languages);
+
+ assertThat(detection.language(newInputFile("Foo.java"))).isEqualTo("java");
+ assertThat(detection.language(newInputFile("src/Foo.java"))).isEqualTo("java");
+ assertThat(detection.language(newInputFile("Foo.JAVA"))).isEqualTo("java");
+ assertThat(detection.language(newInputFile("Foo.jav"))).isEqualTo("java");
+ assertThat(detection.language(newInputFile("Foo.Jav"))).isEqualTo("java");
+
+ assertThat(detection.language(newInputFile("abc.cbl"))).isEqualTo("cobol");
+ assertThat(detection.language(newInputFile("abc.CBL"))).isEqualTo("cobol");
+
+ assertThat(detection.language(newInputFile("abc.php"))).isNull();
+ assertThat(detection.language(newInputFile("abc"))).isNull();
+ }
+
+ @Test
+ public void should_not_fail_if_no_language() throws Exception {
+ LanguageDetection detection = spy(new LanguageDetection(new Settings(), new Languages()));
+ assertThat(detection.language(newInputFile("Foo.java"))).isNull();
+ }
+
+ @Test
+ public void plugin_can_declare_a_file_extension_twice_for_case_sensitivity() throws Exception {
+ Languages languages = new Languages(new MockLanguage("abap", "abap", "ABAP"));
+
+ LanguageDetection detection = new LanguageDetection(new Settings(), languages);
+ assertThat(detection.language(newInputFile("abc.abap"))).isEqualTo("abap");
+ }
+
+ @Test
+ public void language_with_no_extension() throws Exception {
+ // abap does not declare any file extensions.
+ // When analyzing an ABAP project, then all source files must be parsed.
+ Languages languages = new Languages(new MockLanguage("java", "java"), new MockLanguage("abap"));
+
+ // No side-effect on non-ABAP projects
+ LanguageDetection detection = new LanguageDetection(new Settings(), languages);
+ assertThat(detection.language(newInputFile("abc"))).isNull();
+ assertThat(detection.language(newInputFile("abc.abap"))).isNull();
+ assertThat(detection.language(newInputFile("abc.java"))).isEqualTo("java");
+
+ Settings settings = new Settings();
+ settings.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "abap");
+ detection = new LanguageDetection(settings, languages);
+ assertThat(detection.language(newInputFile("abc"))).isEqualTo("abap");
+ assertThat(detection.language(newInputFile("abc.txt"))).isEqualTo("abap");
+ assertThat(detection.language(newInputFile("abc.java"))).isEqualTo("abap");
+ }
+
+ @Test
+ public void force_language_using_deprecated_property() throws Exception {
+ Languages languages = new Languages(new MockLanguage("java", "java"), new MockLanguage("php", "php"));
+
+ Settings settings = new Settings();
+ settings.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "java");
+ LanguageDetection detection = new LanguageDetection(settings, languages);
+ assertThat(detection.language(newInputFile("abc"))).isNull();
+ assertThat(detection.language(newInputFile("abc.php"))).isNull();
+ assertThat(detection.language(newInputFile("abc.java"))).isEqualTo("java");
+ assertThat(detection.language(newInputFile("src/abc.java"))).isEqualTo("java");
+ }
+
+ @Test
+ public void fail_if_invalid_language() throws Exception {
+ thrown.expect(MessageException.class);
+ thrown.expectMessage("No language is installed with key 'unknown'. Please update property 'sonar.language'");
+
+ Languages languages = new Languages(new MockLanguage("java", "java"), new MockLanguage("php", "php"));
+ Settings settings = new Settings();
+ settings.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "unknown");
+ new LanguageDetection(settings, languages);
+ }
+
+ @Test
+ public void fail_if_conflicting_language_suffix() throws Exception {
+ Languages languages = new Languages(new MockLanguage("xml", "xhtml"), new MockLanguage("web", "xhtml"));
+ LanguageDetection detection = new LanguageDetection(new Settings(), languages);
+ try {
+ detection.language(newInputFile("abc.xhtml"));
+ fail();
+ } catch (MessageException e) {
+ assertThat(e.getMessage())
+ .contains("Language of file 'abc.xhtml' can not be decided as the file matches patterns of both ")
+ .contains("sonar.lang.patterns.web : **/*.xhtml")
+ .contains("sonar.lang.patterns.xml : **/*.xhtml");
+ }
+ }
+
+ @Test
+ public void solve_conflict_using_filepattern() throws Exception {
+ Languages languages = new Languages(new MockLanguage("xml", "xhtml"), new MockLanguage("web", "xhtml"));
+
+ Settings settings = new Settings();
+ settings.setProperty("sonar.lang.patterns.xml", "xml/**");
+ settings.setProperty("sonar.lang.patterns.web", "web/**");
+ LanguageDetection detection = new LanguageDetection(settings, languages);
+ assertThat(detection.language(newInputFile("xml/abc.xhtml"))).isEqualTo("xml");
+ assertThat(detection.language(newInputFile("web/abc.xhtml"))).isEqualTo("web");
+ }
+
+ @Test
+ public void fail_if_conflicting_filepattern() throws Exception {
+ Languages languages = new Languages(new MockLanguage("abap", "abap"), new MockLanguage("cobol", "cobol"));
+ Settings settings = new Settings();
+ settings.setProperty("sonar.lang.patterns.abap", "*.abap,*.txt");
+ settings.setProperty("sonar.lang.patterns.cobol", "*.cobol,*.txt");
+
+ LanguageDetection detection = new LanguageDetection(settings, languages);
+
+ assertThat(detection.language(newInputFile("abc.abap"))).isEqualTo("abap");
+ assertThat(detection.language(newInputFile("abc.cobol"))).isEqualTo("cobol");
+ try {
+ detection.language(newInputFile("abc.txt"));
+ fail();
+ } catch (MessageException e) {
+ assertThat(e.getMessage())
+ .contains("Language of file 'abc.txt' can not be decided as the file matches patterns of both ")
+ .contains("sonar.lang.patterns.abap : *.abap,*.txt")
+ .contains("sonar.lang.patterns.cobol : *.cobol,*.txt");
+ }
+ }
+
+ private InputFile newInputFile(String path) throws IOException {
+ File basedir = temp.newFolder();
+ return new InputFileBuilder(new File(basedir, path), Charsets.UTF_8, path).build();
+ }
+
+ 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 key;
+ }
+
+ @Override
+ public String getName() {
+ return key;
+ }
+
+ @Override
+ public String[] getFileSuffixes() {
+ return extensions;
+ }
+ }
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import com.google.common.base.Charsets;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.scan.filesystem.InputFile;
-import org.sonar.api.scan.filesystem.internal.InputFileBuilder;
-import org.sonar.api.utils.SonarException;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.spy;
-
-public class LanguageRecognizerTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void test_sanitizeExtension() throws Exception {
- assertThat(LanguageRecognizer.sanitizeExtension(".cbl")).isEqualTo("cbl");
- assertThat(LanguageRecognizer.sanitizeExtension(".CBL")).isEqualTo("cbl");
- assertThat(LanguageRecognizer.sanitizeExtension("CBL")).isEqualTo("cbl");
- assertThat(LanguageRecognizer.sanitizeExtension("cbl")).isEqualTo("cbl");
- }
-
- @Test
- public void search_by_file_extension() throws Exception {
- Languages languages = new Languages(new MockLanguage("java", "java", "jav"), new MockLanguage("cobol", "cbl", "cob"));
- LanguageRecognizer recognizer = new LanguageRecognizer(new Settings(), languages);
-
- recognizer.start();
- assertThat(recognizer.of(newInputFile("Foo.java"))).isEqualTo("java");
- assertThat(recognizer.of(newInputFile("src/Foo.java"))).isEqualTo("java");
- assertThat(recognizer.of(newInputFile("Foo.JAVA"))).isEqualTo("java");
- assertThat(recognizer.of(newInputFile("Foo.jav"))).isEqualTo("java");
- assertThat(recognizer.of(newInputFile("Foo.Jav"))).isEqualTo("java");
-
- assertThat(recognizer.of(newInputFile("abc.cbl"))).isEqualTo("cobol");
- assertThat(recognizer.of(newInputFile("abc.CBL"))).isEqualTo("cobol");
-
- assertThat(recognizer.of(newInputFile("abc.php"))).isNull();
- assertThat(recognizer.of(newInputFile("abc"))).isNull();
- recognizer.stop();
- }
-
- @Test
- public void should_not_fail_if_no_language() throws Exception {
- LanguageRecognizer recognizer = spy(new LanguageRecognizer(new Settings(), new Languages()));
- recognizer.start();
- assertThat(recognizer.of(newInputFile("Foo.java"))).isNull();
- }
-
- @Test
- public void plugin_can_declare_a_file_extension_twice_for_case_sensitivity() throws Exception {
- Languages languages = new Languages(new MockLanguage("abap", "abap", "ABAP"));
-
- LanguageRecognizer recognizer = new LanguageRecognizer(new Settings(), languages);
- recognizer.start();
- assertThat(recognizer.of(newInputFile("abc.abap"))).isEqualTo("abap");
- }
-
- @Test
- public void language_with_no_extension() throws Exception {
- // abap does not declare any file extensions.
- // When analyzing an ABAP project, then all source files must be parsed.
- Languages languages = new Languages(new MockLanguage("java", "java"), new MockLanguage("abap"));
-
- // No side-effect on non-ABAP projects
- LanguageRecognizer recognizer = new LanguageRecognizer(new Settings(), languages);
- recognizer.start();
- assertThat(recognizer.of(newInputFile("abc"))).isNull();
- assertThat(recognizer.of(newInputFile("abc.abap"))).isNull();
- assertThat(recognizer.of(newInputFile("abc.java"))).isEqualTo("java");
- recognizer.stop();
-
- Settings settings = new Settings();
- settings.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "abap");
- recognizer = new LanguageRecognizer(settings, languages);
- recognizer.start();
- assertThat(recognizer.of(newInputFile("abc"))).isEqualTo("abap");
- assertThat(recognizer.of(newInputFile("abc.txt"))).isEqualTo("abap");
- assertThat(recognizer.of(newInputFile("abc.java"))).isEqualTo("abap");
- recognizer.stop();
- }
-
- @Test
- public void force_language_using_deprecated_property() throws Exception {
- Languages languages = new Languages(new MockLanguage("java", "java"), new MockLanguage("php", "php"));
-
- Settings settings = new Settings();
- settings.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "java");
- LanguageRecognizer recognizer = new LanguageRecognizer(settings, languages);
- recognizer.start();
- assertThat(recognizer.of(newInputFile("abc"))).isNull();
- assertThat(recognizer.of(newInputFile("abc.php"))).isNull();
- assertThat(recognizer.of(newInputFile("abc.java"))).isEqualTo("java");
- assertThat(recognizer.of(newInputFile("src/abc.java"))).isEqualTo("java");
- recognizer.stop();
- }
-
- @Test
- public void fail_if_invalid_language() throws Exception {
- Languages languages = new Languages(new MockLanguage("java", "java"), new MockLanguage("php", "php"));
-
- Settings settings = new Settings();
- settings.setProperty(CoreProperties.PROJECT_LANGUAGE_PROPERTY, "unknow");
- LanguageRecognizer recognizer = new LanguageRecognizer(settings, languages);
- recognizer.start();
- thrown.expect(SonarException.class);
- thrown.expectMessage("No language is installed with key 'unknow'. Please update property 'sonar.language'");
- recognizer.of(newInputFile("abc"));
- recognizer.stop();
- }
-
- @Test
- public void fail_if_conflicting_language_suffix() throws Exception {
- Languages languages = new Languages(new MockLanguage("xml", "xhtml"), new MockLanguage("web", "xhtml"));
-
- Settings settings = new Settings();
- LanguageRecognizer recognizer = new LanguageRecognizer(settings, languages);
- recognizer.start();
- thrown.expect(SonarException.class);
- thrown.expectMessage(new BaseMatcher<String>() {
- @Override
- public void describeTo(Description arg0) {
- }
-
- @Override
- public boolean matches(Object arg0) {
- // Need custom matcher because order of language in the exception is not deterministic (hashmap)
- return arg0.toString().contains("Language of file 'abc.xhtml' can not be decided as the file matches patterns of both ")
- && arg0.toString().contains("sonar.lang.patterns.web : **/*.xhtml")
- && arg0.toString().contains("sonar.lang.patterns.xml : **/*.xhtml");
- }
- });
- recognizer.of(newInputFile("abc.xhtml"));
- recognizer.stop();
- }
-
- @Test
- public void solve_conflict_using_filepattern() throws Exception {
- Languages languages = new Languages(new MockLanguage("xml", "xhtml"), new MockLanguage("web", "xhtml"));
-
- Settings settings = new Settings();
- settings.setProperty("sonar.lang.patterns.xml", "xml/**");
- settings.setProperty("sonar.lang.patterns.web", "web/**");
- LanguageRecognizer recognizer = new LanguageRecognizer(settings, languages);
- recognizer.start();
- assertThat(recognizer.of(newInputFile("xml/abc.xhtml"))).isEqualTo("xml");
- assertThat(recognizer.of(newInputFile("web/abc.xhtml"))).isEqualTo("web");
- recognizer.stop();
- }
-
- @Test
- public void fail_if_conflicting_filepattern() throws Exception {
- Languages languages = new Languages(new MockLanguage("abap", "abap"), new MockLanguage("cobol", "cobol"));
-
- Settings settings = new Settings();
- settings.setProperty("sonar.lang.patterns.abap", "*.abap,*.txt");
- settings.setProperty("sonar.lang.patterns.cobol", "*.cobol,*.txt");
- LanguageRecognizer recognizer = new LanguageRecognizer(settings, languages);
- recognizer.start();
- assertThat(recognizer.of(newInputFile("abc.abap"))).isEqualTo("abap");
- assertThat(recognizer.of(newInputFile("abc.cobol"))).isEqualTo("cobol");
- thrown.expect(SonarException.class);
- thrown.expectMessage(new BaseMatcher<String>() {
- @Override
- public void describeTo(Description arg0) {
- }
-
- @Override
- public boolean matches(Object arg0) {
- // Need custom matcher because order of language in the exception is not deterministic (hashmap)
- return arg0.toString().contains("Language of file 'abc.txt' can not be decided as the file matches patterns of both ")
- && arg0.toString().contains("sonar.lang.patterns.abap : *.abap,*.txt")
- && arg0.toString().contains("sonar.lang.patterns.cobol : *.cobol,*.txt");
- }
- });
- recognizer.of(newInputFile("abc.txt"));
- recognizer.stop();
- }
-
- private InputFile newInputFile(String path) throws IOException {
- File basedir = temp.newFolder();
- return new InputFileBuilder(new File(basedir, path), Charsets.UTF_8, path).build();
- }
-
- 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 key;
- }
-
- @Override
- public String getName() {
- return key;
- }
-
- @Override
- public String[] getFileSuffixes() {
- return extensions;
- }
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.scan.filesystem;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.batch.components.PastSnapshot;
+import org.sonar.batch.components.PastSnapshotFinder;
+import org.sonar.core.source.SnapshotDataTypes;
+import org.sonar.core.source.db.SnapshotDataDao;
+import org.sonar.core.source.db.SnapshotDataDto;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class PreviousFileHashesLoaderTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ PastSnapshotFinder pastSnapshotFinder = mock(PastSnapshotFinder.class);
+ Snapshot snapshot = mock(Snapshot.class);
+ SnapshotDataDao snapshotDataDao = mock(SnapshotDataDao.class);
+ PreviousFileHashLoader loader = new PreviousFileHashLoader(snapshot, snapshotDataDao, pastSnapshotFinder);
+
+ @Test
+ public void should_return_null_if_no_previous_snapshot() throws Exception {
+ when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(new PastSnapshot("foo"));
+
+ Map<String, String> hashByRelativePath = loader.hashByRelativePath();
+ assertThat(hashByRelativePath.get("src/main/java/foo/Bar.java")).isNull();
+ }
+
+ @Test
+ public void should_return_null_if_no_remote_hashes() throws Exception {
+ Snapshot previousSnapshot = mock(Snapshot.class);
+ PastSnapshot pastSnapshot = new PastSnapshot("foo", new Date(), previousSnapshot);
+ when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(pastSnapshot);
+
+ Map<String, String> hashByRelativePath = loader.hashByRelativePath();
+ assertThat(hashByRelativePath.get("src/main/java/foo/Bar.java")).isNull();
+ }
+
+ @Test
+ public void should_return_remote_hash() throws Exception {
+ Snapshot previousSnapshot = mock(Snapshot.class);
+ when(previousSnapshot.getId()).thenReturn(123);
+ PastSnapshot pastSnapshot = new PastSnapshot("foo", new Date(), previousSnapshot);
+ when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(pastSnapshot);
+
+ SnapshotDataDto snapshotDataDto = new SnapshotDataDto();
+ snapshotDataDto.setData("src/main/java/foo/Bar.java=abcd1234");
+ when(snapshotDataDao.selectSnapshotData(123, Arrays.asList(SnapshotDataTypes.FILE_HASHES)))
+ .thenReturn(Arrays.asList(snapshotDataDto));
+
+ Map<String, String> hashByRelativePath = loader.hashByRelativePath();
+ assertThat(hashByRelativePath.get("src/main/java/foo/Bar.java")).isEqualTo("abcd1234");
+ }
+}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.scan.filesystem;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.PastSnapshotFinder;
-import org.sonar.core.source.SnapshotDataTypes;
-import org.sonar.core.source.db.SnapshotDataDao;
-import org.sonar.core.source.db.SnapshotDataDto;
-
-import java.util.Arrays;
-import java.util.Date;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class RemoteFileHashesTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- PastSnapshotFinder pastSnapshotFinder = mock(PastSnapshotFinder.class);
- Snapshot snapshot = mock(Snapshot.class);
- SnapshotDataDao snapshotDataDao = mock(SnapshotDataDao.class);
- RemoteFileHashes hashes = new RemoteFileHashes(snapshot, snapshotDataDao, pastSnapshotFinder);
-
- @Test
- public void should_return_null_if_no_remote_snapshot() throws Exception {
- when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(new PastSnapshot("foo"));
-
- hashes.start();
- assertThat(hashes.remoteHash("src/main/java/foo/Bar.java")).isNull();
- hashes.stop();
- }
-
- @Test
- public void should_return_null_if_no_remote_hashes() throws Exception {
- Snapshot previousSnapshot = mock(Snapshot.class);
- PastSnapshot pastSnapshot = new PastSnapshot("foo", new Date(), previousSnapshot);
- when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(pastSnapshot);
-
- hashes.start();
- assertThat(hashes.remoteHash("src/main/java/foo/Bar.java")).isNull();
- hashes.stop();
- }
-
- @Test
- public void should_return_remote_hash() throws Exception {
- Snapshot previousSnapshot = mock(Snapshot.class);
- when(previousSnapshot.getId()).thenReturn(123);
- PastSnapshot pastSnapshot = new PastSnapshot("foo", new Date(), previousSnapshot);
- when(pastSnapshotFinder.findPreviousAnalysis(snapshot)).thenReturn(pastSnapshot);
-
- SnapshotDataDto snapshotDataDto = new SnapshotDataDto();
- snapshotDataDto.setData("src/main/java/foo/Bar.java=abcd1234");
- when(snapshotDataDao.selectSnapshotData(123, Arrays.asList(SnapshotDataTypes.FILE_HASHES)))
- .thenReturn(Arrays.asList(snapshotDataDto));
-
- hashes.start();
- assertThat(hashes.remoteHash("src/main/java/foo/Bar.java")).isEqualTo("abcd1234");
- hashes.stop();
- }
-}
*/
package org.sonar.api.scan.filesystem.internal;
+import com.google.common.collect.Maps;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.scan.filesystem.InputDir;
this.attributes = attributes;
}
+ public DefaultInputDir(String absolutePath, String path) {
+ this.absolutePath = absolutePath;
+ this.path = path;
+ this.attributes = Maps.newHashMap();
+ }
+
/**
* Plugins must not build their own instances of {@link InputDir}.
* {@link org.sonar.api.scan.filesystem.ModuleFileSystem} must be used to search for inputDir.
public String toString() {
return String.format("[%s]", path);
}
+
+ public DefaultInputDir setKey(String s) {
+ attributes.put(ATTRIBUTE_COMPONENT_KEY, s);
+ return this;
+ }
}
import org.sonar.api.utils.PathUtils;
import javax.annotation.CheckForNull;
-
import java.io.File;
import java.nio.charset.Charset;
import java.util.Map;
private final String path;
private final Map<String, String> attributes;
private final String encoding;
+ private long lines = 0L;
private DefaultInputFile(File file, Charset encoding, String path, Map<String, String> attributes) {
this.encoding = encoding.name();
return absolutePath.hashCode();
}
+ public DefaultInputFile setLines(long l) {
+ this.lines = l;
+ return this;
+ }
+
+ public String language() {
+ return attributes.get(ATTRIBUTE_LANGUAGE);
+ }
+
+ public DefaultInputFile setLanguage(String s) {
+ attributes.put(ATTRIBUTE_LANGUAGE, s);
+ return this;
+ }
+
+ public DefaultInputFile setHash(String s) {
+ attributes.put(ATTRIBUTE_HASH, s);
+ return this;
+ }
+
+ public DefaultInputFile setStatus(String s) {
+ attributes.put(ATTRIBUTE_STATUS, s);
+ return this;
+ }
+
+ public DefaultInputFile setKey(String s) {
+ attributes.put(ATTRIBUTE_COMPONENT_KEY, s);
+ return this;
+ }
+
+ public DefaultInputFile setDeprecatedKey(String s) {
+ attributes.put(ATTRIBUTE_COMPONENT_DEPRECATED_KEY, s);
+ return this;
+ }
+
+ public DefaultInputFile setType(String s) {
+ attributes.put(ATTRIBUTE_TYPE, s);
+ return this;
+ }
+
+ /**
+ * Used only for backward-compatibility. Meaningless since version 4.2.
+ */
+ public String sourceDirAbsolutePath() {
+ return attributes.get(ATTRIBUTE_SOURCEDIR_PATH);
+ }
+
+ public DefaultInputFile setSourceDirAbsolutePath(String s) {
+ attributes.put(ATTRIBUTE_SOURCEDIR_PATH, FilenameUtils.normalize(s, true));
+ return this;
+ }
+
+ /**
+ * Used only for backward-compatibility. Meaningless since version 4.2.
+ */
+ public String pathRelativeToSourceDir() {
+ return attributes.get(ATTRIBUTE_SOURCE_RELATIVE_PATH);
+ }
+
+ public DefaultInputFile setPathRelativeToSourceDir(String s) {
+ attributes.put(ATTRIBUTE_SOURCE_RELATIVE_PATH, FilenameUtils.normalize(s, true));
+ return this;
+ }
+
@Override
public String toString() {
return String.format("[%s,%s]", path, type());