*/
package org.sonar.api.batch.bootstrap;
+/**
+ * Provides root project key with branch
+ */
@FunctionalInterface
public interface ProjectKey {
String get();
* <code>some/path/Foo.java</code> and <code>other/path/Foo.java</code>.
* The parameter must match exactly, no patterns are allowed,
* and it must not be <code>null</code>.
+ *
+ * @since 6.3
*/
FilePredicate hasFilename(String s);
* <code>some/path/Foo.java</code> and <code>other/path/Foo.JAVA</code>
* but not <code>some/path/Foo.js</code>.
* The parameter must not be <code>null</code>.
+ *
+ * @since 6.3
*/
FilePredicate hasExtension(String s);
@CheckForNull
InputDir inputDir(String relativePath);
-
- InputModule module();
+ /**
+ * @since 6.3
+ */
Iterable<InputFile> getFilesByName(String filename);
+ /**
+ * @since 6.3
+ */
Iterable<InputFile> getFilesByExtension(String extension);
}
}
import org.sonar.api.batch.fs.InputPath;
/**
+ * Represents the indexed view of an {@link InputFile}. Accessing any of data exposed here won't trigger the expensive generation of
+ * metadata for the {@link InputFile}.
+ *
* @since 6.3
*/
public interface IndexedFile extends InputPath {
public interface InputComponent {
/**
- * Component key shared by all part of SonarQube (batch, server, WS...)
+ * Component key shared by all part of SonarQube (batch, server, WS...).
+ * It doesn't include the branch.
*/
String key();
-
+
/**
* Is the component an {@link InputFile}
*/
boolean isFile();
-
}
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputModule;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.api.utils.PathUtils;
return this;
}
- public DefaultFileSystem add(InputModule inputModule) {
- cache.add(inputModule);
- return this;
- }
-
/**
* Adds a language to the list. To be used only for unit tests that need to use {@link #languages()} without
* using {@link #add(InputFile)}.
protected abstract void doAdd(InputDir inputDir);
- protected abstract void doAdd(InputModule inputModule);
-
final void add(InputFile inputFile) {
doAdd(inputFile);
}
public void add(InputDir inputDir) {
doAdd(inputDir);
}
-
- public void add(InputModule inputModule) {
- doAdd(inputModule);
- }
-
}
/**
private static class MapCache extends Cache {
private final Map<String, InputFile> fileMap = new HashMap<>();
private final Map<String, InputDir> dirMap = new HashMap<>();
- private InputModule module;
private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create();
private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
return dirMap.get(relativePath);
}
- @Override
- public InputModule module() {
- return module;
- }
-
@Override
public Iterable<InputFile> getFilesByName(String filename) {
return filesByNameCache.get(filename);
return filesByExtensionCache.get(extension);
}
- @Override
protected void doAdd(InputFile inputFile) {
fileMap.put(inputFile.relativePath(), inputFile);
filesByNameCache.put(FilenamePredicate.getFilename(inputFile), inputFile);
protected void doAdd(InputDir inputDir) {
dirMap.put(inputDir.relativePath(), inputDir);
}
-
- @Override
- protected void doAdd(InputModule inputModule) {
- module = inputModule;
- }
}
@Override
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.utils.PathUtils;
+/**
+ * @since 6.3
+ */
public class DefaultIndexedFile extends DefaultInputComponent implements IndexedFile {
private final String relativePath;
private final String moduleKey;
}
/**
- * Component key.
+ * Component key (without branch).
*/
@Override
public String key() {
private Status status;
private Charset charset;
private Metadata metadata;
- private boolean publish = false;
+ private boolean publish;
public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator) {
super(indexedFile.batchId());
this.indexedFile = indexedFile;
this.metadataGenerator = metadataGenerator;
this.metadata = null;
+ this.publish = false;
}
- private void checkMetadata() {
+ public void checkMetadata() {
if (metadata == null) {
metadataGenerator.accept(this);
}
}
- public void setPublish(boolean publish) {
+ /**
+ * @since 6.3
+ */
+ public DefaultInputFile setPublish(boolean publish) {
this.publish = publish;
+ return this;
}
+ /**
+ * @since 6.3
+ */
public boolean publish() {
return publish;
}
}
/**
- * Component key.
+ * Component key (without branch).
*/
@Override
public String key() {
* @since 6.1
*/
void addContextProperty(String key, String value);
-
+
+ /**
+ * Indicate that a file should be published in the report sent to SonarQube.
+ * Files are automatically marked if any data is created for it (issues, highlighting, coverage, etc.).
+ * @since 6.3
+ */
void markForPublishing(InputFile inputFile);
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.fs.internal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class MetadataTest {
+ @Test
+ public void testRoundtrip() {
+ Metadata metadata = new Metadata(10, 20, "hash", new int[] {1, 2}, 30);
+ assertThat(metadata.lastValidOffset()).isEqualTo(30);
+ assertThat(metadata.lines()).isEqualTo(10);
+ assertThat(metadata.nonBlankLines()).isEqualTo(20);
+ assertThat(metadata.originalLineOffsets()).isEqualTo(new int[] {1, 2});
+ assertThat(metadata.hash()).isEqualTo("hash");
+ }
+}
import org.sonar.api.utils.System2;
/**
- * Used by views !!
- *
+ * @since 6.3
*/
@ScannerSide
public class ProjectAnalysisInfo implements Startable {
private final PostJobOptimizer postJobOptimizer;
public ScannerExtensionDictionnary(ComponentContainer componentContainer, DefaultSensorContext sensorContext,
- SensorOptimizer sensorOptimizer, PostJobContext postJobContext,
- PostJobOptimizer postJobOptimizer) {
+ SensorOptimizer sensorOptimizer, PostJobContext postJobContext, PostJobOptimizer postJobOptimizer) {
this.componentContainer = componentContainer;
this.sensorContext = sensorContext;
this.sensorOptimizer = sensorOptimizer;
void runCpdAnalysis(ExecutorService executorService, String componentKey, final Collection<Block> fileBlocks, long timeout) {
DefaultInputComponent component = (DefaultInputComponent) componentStore.getByKey(componentKey);
if (component == null) {
- LOG.error("Resource not found in component cache: {}. Skipping CPD computation for it", componentKey);
+ LOG.error("Resource not found in component store: {}. Skipping CPD computation for it", componentKey);
return;
}
@Override
public Resource getParent(Resource reference) {
- return index.getParent(reference.getEffectiveKey());
+ return index.getParent(getComponentKey(reference));
}
@Override
public Collection<Resource> getChildren(Resource reference) {
- return index.getChildren(reference.getEffectiveKey());
+ return index.getChildren(getComponentKey(reference));
}
@Override
return index.getMeasure(module.key(), metric);
}
+ /**
+ * Returns effective key of a resource, without branch.
+ */
private String getComponentKey(Resource r) {
if (ResourceUtils.isProject(r) || /* For technical projects */ResourceUtils.isRootProject(r)) {
return r.getKey();
@Override
public <G extends Serializable> Measure<G> getMeasure(Resource resource, Metric<G> metric) {
- return index.getMeasure(resource.getEffectiveKey(), metric);
+ return index.getMeasure(getComponentKey(resource), metric);
}
@Override
this.metricFinder = metricFinder;
}
- public void setCurrentProject(DefaultSensorStorage sensorStorage) {
+ public void setCurrentStorage(DefaultSensorStorage sensorStorage) {
// the following components depend on the current module, so they need to be reloaded.
this.sensorStorage = sensorStorage;
}
return measure;
}
+ /**
+ * @param key Effective key, without branch
+ */
@CheckForNull
public Resource getParent(String key) {
InputComponent component = componentStore.getByKey(key);
return toResource(parent);
}
+ /**
+ * @param key Effective key, without branch
+ */
public Collection<Resource> getChildren(String key) {
InputComponent component = componentStore.getByKey(key);
Collection<InputComponent> children = tree.getChildren(component);
return r;
}
+ /**
+ * Gets a component from the store as a resource.
+ * @param key Effective key, without branch
+ */
@CheckForNull
public Resource getResource(String key) {
InputComponent component = componentStore.getByKey(key);
import java.util.List;
import java.util.Map;
-import org.sonar.api.batch.fs.InputModule;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.IssueComment;
private DefaultInputModule module;
private ProjectAnalysisInfo projectAnalysisInfo;
- DeprecatedIssueAdapterForFilter(InputModule module, ProjectAnalysisInfo projectAnalysisInfo, org.sonar.scanner.protocol.output.ScannerReport.Issue rawIssue,
+ DeprecatedIssueAdapterForFilter(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, org.sonar.scanner.protocol.output.ScannerReport.Issue rawIssue,
String componentKey) {
- this.module = (DefaultInputModule) module;
+ this.module = module;
this.projectAnalysisInfo = projectAnalysisInfo;
this.rawIssue = rawIssue;
this.componentKey = componentKey;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.issue.Issue;
import org.sonar.api.scan.issue.filter.IssueFilter;
public class IssueFilters {
private final IssueFilter[] filters;
private final org.sonar.api.issue.batch.IssueFilter[] deprecatedFilters;
- private final InputModule module;
+ private final DefaultInputModule module;
private final ProjectAnalysisInfo projectAnalysisInfo;
- public IssueFilters(InputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] exclusionFilters, org.sonar.api.issue.batch.IssueFilter[] filters) {
+ public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] exclusionFilters, org.sonar.api.issue.batch.IssueFilter[] filters) {
this.module = module;
this.filters = exclusionFilters;
this.deprecatedFilters = filters;
this.projectAnalysisInfo = projectAnalysisInfo;
}
- public IssueFilters(InputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] filters) {
+ public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] filters) {
this(module, projectAnalysisInfo, filters, new org.sonar.api.issue.batch.IssueFilter[0]);
}
- public IssueFilters(InputModule module, ProjectAnalysisInfo projectAnalysisInfo, org.sonar.api.issue.batch.IssueFilter[] deprecatedFilters) {
+ public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo, org.sonar.api.issue.batch.IssueFilter[] deprecatedFilters) {
this(module, projectAnalysisInfo, new IssueFilter[0], deprecatedFilters);
}
- public IssueFilters(InputModule module, ProjectAnalysisInfo projectAnalysisInfo) {
+ public IssueFilters(DefaultInputModule module, ProjectAnalysisInfo projectAnalysisInfo) {
this(module, projectAnalysisInfo, new IssueFilter[0], new org.sonar.api.issue.batch.IssueFilter[0]);
}
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.FileSystemLogger;
import org.sonar.scanner.scan.report.IssuesReports;
-import org.sonar.scanner.scm.ScmPublisher;
public final class IssuesPhaseExecutor extends AbstractPhaseExecutor {
import java.util.Map;
import javax.annotation.Nonnull;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.measures.CoreMetrics;
@Override
public void publish(ScannerReportWriter writer) {
- for (final InputFile file : componentCache.allFiles()) {
- DefaultInputFile inputFile = (DefaultInputFile) file;
+ for (final DefaultInputFile inputFile : componentCache.allFilesToPublish()) {
Map<Integer, LineCoverage.Builder> coveragePerLine = new LinkedHashMap<>();
int lineCount = inputFile.lines();
public class MeasuresPublisher implements ReportPublisherStep {
- private final InputComponentStore componentCache;
+ private final InputComponentStore componentStore;
private final MeasureCache measureCache;
private final TestPlanBuilder testPlanBuilder;
- public MeasuresPublisher(InputComponentStore componentCache, MeasureCache measureCache, TestPlanBuilder testPlanBuilder) {
- this.componentCache = componentCache;
+ public MeasuresPublisher(InputComponentStore componentStore, MeasureCache measureCache, TestPlanBuilder testPlanBuilder) {
+ this.componentStore = componentStore;
this.measureCache = measureCache;
this.testPlanBuilder = testPlanBuilder;
}
public void publish(ScannerReportWriter writer) {
final ScannerReport.Measure.Builder builder = ScannerReport.Measure.newBuilder();
- for (final InputComponent c : componentCache.all()) {
+ for (final InputComponent c : componentStore.all()) {
DefaultInputComponent component = (DefaultInputComponent) c;
// Recompute all coverage measures from line data to take into account the possible merge of several reports
updateCoverageFromLineData(component);
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.BOMInputStream;
-import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
private final InputComponentStore componentCache;
- public SourcePublisher(InputComponentStore componentCache) {
- this.componentCache = componentCache;
+ public SourcePublisher(InputComponentStore componentStore) {
+ this.componentCache = componentStore;
}
@Override
public void publish(ScannerReportWriter writer) {
- for (final InputFile file : componentCache.allFiles()) {
- DefaultInputFile inputFile = (DefaultInputFile) file;
+ for (final DefaultInputFile inputFile : componentCache.allFilesToPublish()) {
File iofile = writer.getSourceFile(inputFile.batchId());
- int line = 0;
+
try (FileOutputStream output = new FileOutputStream(iofile);
BOMInputStream bomIn = new BOMInputStream(new FileInputStream(inputFile.file()),
ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
BufferedReader reader = new BufferedReader(new InputStreamReader(bomIn, inputFile.charset()))) {
- String lineStr = reader.readLine();
- while (lineStr != null) {
- IOUtils.write(lineStr, output, StandardCharsets.UTF_8);
- line++;
- if (line < inputFile.lines()) {
- IOUtils.write("\n", output, StandardCharsets.UTF_8);
- }
- lineStr = reader.readLine();
- }
+ writeSource(reader, output, inputFile.lines());
} catch (IOException e) {
throw new IllegalStateException("Unable to store file source in the report", e);
}
}
}
+
+ private static void writeSource(BufferedReader reader, FileOutputStream output, int lines) throws IOException {
+ int line = 0;
+ String lineStr = reader.readLine();
+ while (lineStr != null) {
+ IOUtils.write(lineStr, output, StandardCharsets.UTF_8);
+ line++;
+ if (line < lines) {
+ IOUtils.write("\n", output, StandardCharsets.UTF_8);
+ }
+ lineStr = reader.readLine();
+ }
+ }
}
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
+/**
+ * Indexes all modules into {@link DefaultComponentTree}, {@link DefaultInputModuleHierarchy) and {@link InputComponentStore}, using the
+ * project definitions provided by the {@link ImmutableProjectReactor}.
+ */
public class ModuleIndexer implements Startable {
private final ImmutableProjectReactor projectReactor;
private final DefaultComponentTree componentTree;
private final DefaultInputModuleHierarchy moduleHierarchy;
private final BatchIdGenerator batchIdGenerator;
+ private final InputComponentStore componentStore;
public ModuleIndexer(ImmutableProjectReactor projectReactor, DefaultComponentTree componentTree,
- BatchIdGenerator batchIdGenerator, DefaultInputModuleHierarchy moduleHierarchy) {
+ InputComponentStore componentStore, BatchIdGenerator batchIdGenerator, DefaultInputModuleHierarchy moduleHierarchy) {
this.projectReactor = projectReactor;
this.componentTree = componentTree;
+ this.componentStore = componentStore;
this.moduleHierarchy = moduleHierarchy;
this.batchIdGenerator = batchIdGenerator;
}
public void start() {
DefaultInputModule root = new DefaultInputModule(projectReactor.getRoot(), batchIdGenerator.get());
moduleHierarchy.setRoot(root);
+ componentStore.put(root);
createChildren(root);
}
DefaultInputModule child = new DefaultInputModule(def, batchIdGenerator.get());
moduleHierarchy.index(child, parent);
componentTree.index(child, parent);
+ componentStore.put(child);
createChildren(child);
}
}
@Override
protected void doAfterStart() {
DefaultIndex index = getComponentByType(DefaultIndex.class);
- index.setCurrentProject(getComponentByType(DefaultSensorStorage.class));
+ index.setCurrentStorage(getComponentByType(DefaultSensorStorage.class));
getComponentByType(AbstractPhaseExecutor.class).execute(module);
}
ProjectAnalysisInfo.class,
DefaultIndex.class,
Storages.class,
- DefaultIssueCallback.class,
new RulesProvider(),
new ProjectRepositoriesProvider(),
new QualityProfileProvider(),
// issues
+ DefaultIssueCallback.class,
IssueCache.class,
DefaultProjectIssues.class,
IssueTransition.class,
*/
package org.sonar.scanner.scan.filesystem;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
+import org.sonar.api.batch.fs.InputComponent;
+
+/**
+ * Generates unique IDs for any {@link InputComponent}.
+ * The IDs must be unique among all types of components and for all modules in the project.
+ * The ID should never be 0, as it is sometimes used to indicate invalid components.
+ */
public class BatchIdGenerator implements Supplier<Integer> {
- private int nextBatchId = 1;
+ private AtomicInteger nextBatchId = new AtomicInteger(1);
@Override
public Integer get() {
- return nextBatchId++;
+ return nextBatchId.getAndIncrement();
}
}
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.ScannerSide;
import org.sonar.scanner.scan.DefaultComponentTree;
import org.sonar.scanner.util.ProgressReport;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
/**
* Index input files into {@link InputComponentStore}.
*/
private final DefaultInputModule module;
private final BatchIdGenerator batchIdGenerator;
private final InputComponentStore componentStore;
+ private ExecutorService executorService;
+ private final List<Future<Void>> tasks;
private ProgressReport progressReport;
this.inputFileBuilder = inputFileBuilder;
this.filters = filters;
this.exclusionFilters = exclusionFilters;
+ this.tasks = new ArrayList<>();
this.isAggregator = !def.getSubProjects().isEmpty();
}
}
void index(DefaultModuleFileSystem fileSystem) {
- fileSystem.add(module);
if (isAggregator) {
// No indexing for an aggregator module
return;
}
+
+ int threads = Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
+ this.executorService = Executors.newFixedThreadPool(threads, new ThreadFactoryBuilder().setNameFormat("FileIndexer-%d").build());
+
progressReport = new ProgressReport("Report about progress of file indexation", TimeUnit.SECONDS.toMillis(10));
progressReport.start("Index files");
exclusionFilters.prepare();
indexFiles(fileSystem, progress, fileSystem.sources(), InputFile.Type.MAIN);
indexFiles(fileSystem, progress, fileSystem.tests(), InputFile.Type.TEST);
- progressReport.stop(progress.count() + " files indexed");
+ waitForTasksToComplete();
+
+ progressReport.stop(progress.count() + " " + pluralizeFiles(progress.count()) + " indexed");
if (exclusionFilters.hasPattern()) {
- LOG.info("{} files ignored because of inclusion/exclusion patterns", progress.excludedByPatternsCount());
+ LOG.info("{} {} ignored because of inclusion/exclusion patterns", progress.excludedByPatternsCount(), pluralizeFiles(progress.excludedByPatternsCount()));
+ }
+ }
+
+ private void waitForTasksToComplete() {
+ executorService.shutdown();
+ for (Future<Void> task : tasks) {
+ try {
+ task.get();
+ } catch (ExecutionException e) {
+ // Unwrap ExecutionException
+ throw e.getCause() instanceof RuntimeException ? (RuntimeException) e.getCause() : new IllegalStateException(e.getCause());
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
}
}
+ private static String pluralizeFiles(int count) {
+ return count == 1 ? "file" : "files";
+ }
+
private void indexFiles(DefaultModuleFileSystem fileSystem, Progress progress, List<File> sources, InputFile.Type type) {
try {
for (File dirOrFile : sources) {
if (dirOrFile.isDirectory()) {
indexDirectory(fileSystem, progress, dirOrFile.toPath(), type);
} else {
- indexFile(fileSystem, progress, dirOrFile.toPath(), type);
+ tasks.add(executorService.submit(() -> indexFile(fileSystem, progress, dirOrFile.toPath(), type)));
}
}
} catch (IOException e) {
new IndexFileVisitor(fileSystem, status, type));
}
- private void indexFile(DefaultModuleFileSystem fileSystem, Progress progress, Path sourceFile, InputFile.Type type) throws IOException {
+ private Void indexFile(DefaultModuleFileSystem fileSystem, Progress progress, Path sourceFile, InputFile.Type type) throws IOException {
// get case of real file without resolving link
Path realFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS);
DefaultInputFile inputFile = inputFileBuilder.create(realFile, type, fileSystem.encoding());
if (inputFile != null) {
if (exclusionFilters.accept(inputFile, type) && accept(inputFile)) {
- fileSystem.add(inputFile);
- indexParentDir(fileSystem, inputFile);
- progress.markAsIndexed(inputFile);
+ synchronized (this) {
+ fileSystem.add(inputFile);
+ indexParentDir(fileSystem, inputFile);
+ progress.markAsIndexed(inputFile);
+ }
LOG.debug("'{}' indexed {} with language '{}'", inputFile.relativePath(), type == Type.TEST ? "as test " : "", inputFile.language());
+ inputFileBuilder.checkMetadata(inputFile);
} else {
progress.increaseExcludedByPatternsCount();
}
}
+ return null;
}
private void indexParentDir(DefaultModuleFileSystem fileSystem, InputFile inputFile) {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!Files.isHidden(file)) {
- indexFile(fileSystem, status, file, type);
+ tasks.add(executorService.submit(() -> indexFile(fileSystem, status, file, type)));
}
return FileVisitResult.CONTINUE;
}
private class Progress {
private final Set<Path> indexed = new HashSet<>();
- private int excludedByPatternsCount = 0;
+ private AtomicInteger excludedByPatternsCount = new AtomicInteger(0);
- synchronized void markAsIndexed(IndexedFile inputFile) {
+ void markAsIndexed(IndexedFile inputFile) {
if (indexed.contains(inputFile.path())) {
throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
+ "disjoint sets for main and test files");
}
indexed.add(inputFile.path());
- progressReport.message(indexed.size() + " files indexed... (last one was " + inputFile.relativePath() + ")");
+ progressReport.message(indexed.size() + " " + pluralizeFiles(indexed.size()) + " indexed... (last one was " + inputFile.relativePath() + ")");
}
void increaseExcludedByPatternsCount() {
- excludedByPatternsCount++;
+ excludedByPatternsCount.incrementAndGet();
}
public int excludedByPatternsCount() {
- return excludedByPatternsCount;
+ return excludedByPatternsCount.get();
}
int count() {
return inputComponents.values();
}
+ public Iterable<DefaultInputFile> allFilesToPublish() {
+ return inputFileCache.values().stream()
+ .map(f -> (DefaultInputFile) f)
+ .filter(DefaultInputFile::publish)::iterator;
+ }
+
public Iterable<InputFile> allFiles() {
return inputFileCache.values();
}
import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.config.Settings;
import org.sonar.api.scan.filesystem.PathResolver;
public class InputFileBuilder {
+ private static final String PRELOAD_FILE_METADATA_KEY = "sonar.preloadFileMetadata";
private static final Logger LOG = LoggerFactory.getLogger(InputFileBuilder.class);
private final String moduleKey;
private final Path moduleBaseDir;
private final LanguageDetection langDetection;
private final BatchIdGenerator idGenerator;
private final MetadataGenerator metadataGenerator;
+ private final boolean preloadMetadata;
public InputFileBuilder(DefaultInputModule module, PathResolver pathResolver, LanguageDetection langDetection, MetadataGenerator metadataGenerator,
- BatchIdGenerator idGenerator) {
+ BatchIdGenerator idGenerator, Settings settings) {
this.moduleKey = module.key();
this.moduleBaseDir = module.definition().getBaseDir().toPath();
this.pathResolver = pathResolver;
this.langDetection = langDetection;
this.metadataGenerator = metadataGenerator;
this.idGenerator = idGenerator;
+ this.preloadMetadata = settings.getBoolean(PRELOAD_FILE_METADATA_KEY);
}
@CheckForNull
return null;
}
indexedFile.setLanguage(language);
+
return new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(f, defaultEncoding));
}
+
+ void checkMetadata(DefaultInputFile inputFile) {
+ if (preloadMetadata) {
+ inputFile.checkMetadata();
+ }
+ }
}
import com.google.common.annotations.VisibleForTesting;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
this.fileMetadata = fileMetadata;
}
+ /**
+ * Sets all metadata in the file, including charset and status.
+ * It is an expensive computation, reading the entire file.
+ */
+ public void setMetadata(final DefaultInputFile inputFile, Charset defaultEncoding) {
+ try {
+ Charset charset = detectCharset(inputFile.path(), defaultEncoding);
+ inputFile.setCharset(charset);
+ Metadata metadata = fileMetadata.readMetadata(inputFile.file(), charset);
+ inputFile.setMetadata(metadata);
+ inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile.relativePath(), metadata.hash()));
+ LOG.debug("'{}' generated metadata {} with charset '{}'",
+ inputFile.relativePath(), inputFile.type() == Type.TEST ? "as test " : "", charset);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
/**
* @return charset detected from BOM in given file or given defaultCharset
* @throws IllegalStateException if an I/O error occurs
*/
- private static Charset detectCharset(File file, Charset defaultCharset) {
- try (FileInputStream inputStream = new FileInputStream(file)) {
+ private static Charset detectCharset(Path path, Charset defaultCharset) {
+ try (InputStream inputStream = Files.newInputStream(path)) {
byte[] bom = new byte[4];
int n = inputStream.read(bom, 0, bom.length);
if ((n >= 3) && (bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
return defaultCharset;
}
} catch (IOException e) {
- throw new IllegalStateException("Unable to read file " + file.getAbsolutePath(), e);
- }
- }
-
- public void setMetadata(final DefaultInputFile inputFile, Charset defaultEncoding) {
- try {
- Charset charset = detectCharset(inputFile.file(), defaultEncoding);
- inputFile.setCharset(charset);
- Metadata metadata = fileMetadata.readMetadata(inputFile.file(), charset);
- inputFile.setMetadata(metadata);
- inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile.relativePath(), metadata.hash()));
- LOG.debug("'{}' generated metadata {} with and charset '{}'",
- inputFile.relativePath(), inputFile.type() == Type.TEST ? "as test " : "", charset);
- } catch (Exception e) {
- throw new IllegalStateException(e);
+ throw new IllegalStateException("Unable to read file " + path.toAbsolutePath().toString(), e);
}
}
}
inputComponentStore.put(inputDir);
}
- @Override
- protected void doAdd(InputModule inputModule) {
- inputComponentStore.put(inputModule);
- }
-
- @Override
- public InputModule module() {
- return inputComponentStore.getModule(moduleKey);
- }
-
@Override
public Iterable<InputFile> getFilesByName(String filename) {
return inputComponentStore.getFilesByName(filename);
if (settings.getBoolean(CONSOLE_REPORT_ENABLED_KEY)) {
LOG.warn("Console report is deprecated. Use SonarLint CLI to have local reports of issues");
Report r = new Report();
- r.setNoFile(!inputPathCache.allFiles().iterator().hasNext());
+ r.setNoFile(!inputPathCache.allFilesToPublish().iterator().hasNext());
for (TrackedIssue issue : issueCache.all()) {
r.process(issue);
}
public IssuesReport buildReport() {
DefaultInputModule project = moduleHierarchy.root();
IssuesReport issuesReport = new IssuesReport();
- issuesReport.setNoFile(!inputComponentCache.allFiles().iterator().hasNext());
+ issuesReport.setNoFile(!inputComponentCache.allFilesToPublish().iterator().hasNext());
issuesReport.setTitle(project.definition().getName());
issuesReport.setDate(projectAnalysisInfo.analysisDate());
import org.sonar.api.PropertyType;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputDir;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
private final Server server;
private final Rules rules;
private final IssueCache issueCache;
- private final InputComponentStore fileCache;
+ private final InputComponentStore componentStore;
private final DefaultInputModule rootModule;
private final UserRepositoryLoader userRepository;
private final InputModuleHierarchy moduleHierarchy;
public JSONReport(InputModuleHierarchy moduleHierarchy, Settings settings, FileSystem fileSystem, Server server, Rules rules, IssueCache issueCache,
- DefaultInputModule rootModule, InputComponentStore fileCache, UserRepositoryLoader userRepository) {
+ DefaultInputModule rootModule, InputComponentStore componentStore, UserRepositoryLoader userRepository) {
this.moduleHierarchy = moduleHierarchy;
this.settings = settings;
this.fileSystem = fileSystem;
this.rules = rules;
this.issueCache = issueCache;
this.rootModule = rootModule;
- this.fileCache = fileCache;
+ this.componentStore = componentStore;
this.userRepository = userRepository;
}
json.name("components").beginArray();
// Dump modules
writeJsonModuleComponents(json, rootModule);
- for (InputFile inputFile : fileCache.allFiles()) {
- String key = ((DefaultInputFile) inputFile).key();
+ for (DefaultInputFile inputFile : componentStore.allFilesToPublish()) {
+ String key = inputFile.key();
json
.beginObject()
.prop("key", key)
.prop("path", inputFile.relativePath())
- .prop("moduleKey", StringUtils.substringBeforeLast(key, ":"))
+ .prop("moduleKey", inputFile.moduleKey())
.prop("status", inputFile.status().name())
.endObject();
}
- for (InputDir inputDir : fileCache.allDirs()) {
+ for (InputDir inputDir : componentStore.allDirs()) {
String key = ((DefaultInputDir) inputDir).key();
json
.beginObject()
*/
package org.sonar.scanner.scm;
-import java.io.File;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
+import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Builder;
import org.sonar.scanner.repository.FileData;
import org.sonar.scanner.repository.ProjectRepositories;
-import org.sonar.scanner.scan.ImmutableProjectReactor;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
private final ScmConfiguration configuration;
private final ProjectRepositories projectRepositories;
private final ModuleInputComponentStore componentStore;
-
- private DefaultModuleFileSystem fs;
- private ScannerReportWriter writer;
+ private final DefaultModuleFileSystem fs;
+ private final ScannerReportWriter writer;
public ScmPublisher(DefaultInputModule inputModule, ScmConfiguration configuration, ProjectRepositories projectRepositories,
- ModuleInputComponentStore componentStore, DefaultModuleFileSystem fs, ImmutableProjectReactor reactor) {
+ ModuleInputComponentStore componentStore, DefaultModuleFileSystem fs, ReportPublisher reportPublisher) {
this.inputModule = inputModule;
this.configuration = configuration;
this.projectRepositories = projectRepositories;
this.componentStore = componentStore;
this.fs = fs;
- File reportDir = new File(reactor.getRoot().getWorkDir(), "batch-report");
- writer = new ScannerReportWriter(reportDir);
+ this.writer = reportPublisher.getWriter();
}
public void publish() {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.scanner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Date;
+
+import org.junit.Test;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.MapSettings;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.System2;
+
+public class ProjectAnalysisInfoTest {
+ @Test
+ public void testSimpleDate() {
+ Settings settings = new MapSettings();
+ settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01");
+ settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version");
+ System2 system = mock(System2.class);
+ ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings, system);
+ info.start();
+ LocalDate date = LocalDate.of(2017, 1, 1);
+
+ assertThat(info.analysisDate()).isEqualTo(Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
+ assertThat(info.analysisVersion()).isEqualTo("version");
+ }
+}
public void failOnMissingComponent() {
executor.runCpdAnalysis(null, "unknown", Collections.emptyList(), 1);
readDuplications(0);
- assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Resource not found in component cache: unknown. Skipping CPD computation for it");
+ assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Resource not found in component store: unknown. Skipping CPD computation for it");
}
@Test
rule = Rule.create("repoKey", "ruleKey", "Rule");
rule.setId(1);
rulesProfile.activateRule(rule, null);
- index.setCurrentProject(mock(DefaultSensorStorage.class));
+ index.setCurrentStorage(mock(DefaultSensorStorage.class));
}
@Test
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.stream.Collectors;
+
import org.sonar.batch.bootstrapper.LogOutput;
import com.google.common.collect.Multimap;
import com.google.common.collect.HashMultimap;
public class LogOutputRecorder implements LogOutput {
- private Multimap<String, String> recordedByLevel = HashMultimap.create();
- private List<String> recorded = new LinkedList<>();
- private StringBuffer asString = new StringBuffer();
+ private final Multimap<String, String> recordedByLevel = HashMultimap.create();
+ private final List<String> recorded = new LinkedList<>();
+ private final StringBuffer asString = new StringBuffer();
@Override
- public void log(String formattedMessage, Level level) {
+ public synchronized void log(String formattedMessage, Level level) {
recordedByLevel.put(level.toString(), formattedMessage);
recorded.add(formattedMessage);
asString.append(formattedMessage).append("\n");
return recorded;
}
+ public String getAllAsString() {
+ return recorded.stream().collect(Collectors.joining("\n"));
+ }
+
public Collection<String> get(String level) {
return recordedByLevel.get(level);
}
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
+import org.sonar.scanner.mediumtest.LogOutputRecorder;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.TaskResult;
import org.sonar.xoo.XooPlugin;
+import org.sonar.xoo.rule.XooRulesDefinition;
import java.io.File;
import java.io.IOException;
@Rule
public ExpectedException thrown = ExpectedException.none();
+ private LogOutputRecorder logs = new LogOutputRecorder();
+
public ScannerMediumTester tester = ScannerMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
+ .setLogOutput(logs)
.build();
private File baseDir;
-
private ImmutableMap.Builder<String, String> builder;
@Before
@After
public void stop() {
tester.stop();
+ logs = new LogOutputRecorder();
}
@Test
assertThat(result.getReportReader().readComponent(ref).getName()).isEmpty();
assertThat(result.inputFiles()).hasSize(1);
assertThat(result.inputDirs()).hasSize(1);
- assertThat(result.inputFile("src/sample.xoo").type()).isEqualTo(InputFile.Type.MAIN);
- assertThat(result.inputFile("src/sample.xoo").relativePath()).isEqualTo("src/sample.xoo");
- assertThat(result.inputDir("src").relativePath()).isEqualTo("src");
+
+ DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
+ InputDir dir = result.inputDir("src");
+ assertThat(file.type()).isEqualTo(InputFile.Type.MAIN);
+ assertThat(file.relativePath()).isEqualTo("src/sample.xoo");
+ assertThat(dir.relativePath()).isEqualTo("src");
+
+ // file and dirs were not published
+ assertThat(file.publish()).isFalse();
+ assertThat(result.getReportComponent(dir.key())).isNull();
+ assertThat(result.getReportComponent(file.key())).isNull();
+ }
+
+ @Test
+ public void onlyGenerateMetadataIfNeeded() throws IOException {
+ builder = ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.verbose", "true")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project");
+
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+ File unknownFile = new File(srcDir, "sample.unknown");
+ FileUtils.write(unknownFile, "Sample xoo\ncontent");
+
+ tester.newTask()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .start();
+
+ assertThat(logs.getAllAsString()).contains("2 files indexed");
+ assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
+ assertThat(logs.getAllAsString()).doesNotContain("'src/sample.unknown' generated metadata");
+ }
+
+ @Test
+ public void preloadFileMetadata() throws IOException {
+ builder = ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.verbose", "true")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.preloadFileMetadata", "true")
+ .put("sonar.projectDescription", "Description of Foo Project");
+
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+ File unknownFile = new File(srcDir, "sample.unknown");
+ FileUtils.write(unknownFile, "Sample xoo\ncontent");
+
+ tester.newTask()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .start();
+
+ assertThat(logs.getAllAsString()).contains("2 files indexed");
+ assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
+ assertThat(logs.getAllAsString()).contains("'src/sample.unknown' generated metadata");
+ }
+
+ @Test
+ public void publishFilesWithIssues() throws IOException {
+ ScannerMediumTester tester2 = ScannerMediumTester.builder()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .addRules(new XooRulesDefinition())
+ .addActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo")
+ .build();
+ tester2.start();
+
+ builder = ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.verbose", "true")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project");
+
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent");
+
+ TaskResult result = tester2.newTask()
+ .properties(builder
+ .put("sonar.sources", "src")
+ .build())
+ .start();
+
+ DefaultInputFile file = (DefaultInputFile) result.inputFile("src/sample.xoo");
+ InputDir dir = result.inputDir("src");
+
+ assertThat(file.publish()).isTrue();
+ assertThat(result.getReportComponent(dir.key())).isNotNull();
+ assertThat(result.getReportComponent(file.key())).isNotNull();
+
+ tester2.stop();
}
@Test
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputModule;
import org.sonar.scanner.scan.filesystem.BatchIdGenerator;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
public class ModuleIndexerTest {
private ModuleIndexer indexer;
private DefaultComponentTree tree;
private DefaultInputModuleHierarchy moduleHierarchy;
private ImmutableProjectReactor reactor;
+ private InputComponentStore componentStore;
@Before
public void setUp() {
reactor = mock(ImmutableProjectReactor.class);
+ componentStore = new InputComponentStore();
tree = new DefaultComponentTree();
moduleHierarchy = new DefaultInputModuleHierarchy();
- indexer = new ModuleIndexer(reactor, tree, new BatchIdGenerator(), moduleHierarchy);
+ indexer = new ModuleIndexer(reactor, tree, componentStore, new BatchIdGenerator(), moduleHierarchy);
}
@Test
*/
package org.sonar.scanner.scan.filesystem;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedList;
+import java.util.List;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Status;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.scanner.scan.filesystem.InputComponentStore;
-import java.nio.charset.StandardCharsets;
-
-import static org.assertj.core.api.Assertions.assertThat;
public class InputComponentStoreTest {
@Rule
@Test
public void should_add_input_file() throws Exception {
InputComponentStore cache = new InputComponentStore();
- DefaultInputFile fooFile = new TestInputFileBuilder("struts", "src/main/java/Foo.java").setModuleBaseDir(temp.newFolder().toPath()).build();
+ DefaultInputFile fooFile = new TestInputFileBuilder("struts", "src/main/java/Foo.java")
+ .setModuleBaseDir(temp.newFolder().toPath())
+ .setPublish(true)
+ .build();
cache.put(fooFile);
cache.put(new TestInputFileBuilder("struts-core", "src/main/java/Bar.java")
.setLanguage("bla")
+ .setPublish(false)
.setType(Type.MAIN)
.setStatus(Status.ADDED)
.setLines(2)
assertThat(inputPath.relativePath()).startsWith("src/main/java/");
}
+ List<InputFile> toPublish = new LinkedList<>();
+ cache.allFilesToPublish().forEach(toPublish::add);
+ assertThat(toPublish).containsOnly(fooFile);
+
cache.remove(fooFile);
assertThat(cache.allFiles()).hasSize(1);
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.config.MapSettings;
+import org.sonar.api.config.Settings;
import org.sonar.api.scan.filesystem.PathResolver;
public class InputFileBuilderTest {
LanguageDetection langDetection = mock(LanguageDetection.class);
MetadataGenerator metadataGenerator = mock(MetadataGenerator.class);
BatchIdGenerator idGenerator = new BatchIdGenerator();
- builder = new InputFileBuilder(module, pathResolver, langDetection, metadataGenerator, idGenerator);
+ Settings settings = new MapSettings();
+ builder = new InputFileBuilder(module, pathResolver, langDetection, metadataGenerator, idGenerator, settings);
}
@Test
public void testBuild() {
Path filePath = baseDir.resolve("src/File1.xoo");
DefaultInputFile inputFile = builder.create(filePath, Type.MAIN, StandardCharsets.UTF_8);
-
+
assertThat(inputFile.moduleKey()).isEqualTo("module1");
assertThat(inputFile.absolutePath()).isEqualTo(filePath.toString());
assertThat(inputFile.key()).isEqualTo("module1:src/File1.xoo");
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.config.Settings;
import org.sonar.api.config.MapSettings;
@Test
public void testNoFile() {
settings.setProperty(ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, "true");
- when(inputPathCache.allFiles()).thenReturn(Collections.<InputFile>emptyList());
- when(issueCache.all()).thenReturn(Collections.<TrackedIssue>emptyList());
+ when(inputPathCache.allFilesToPublish()).thenReturn(Collections.emptyList());
+ when(issueCache.all()).thenReturn(Collections.emptyList());
report.execute();
assertDeprecated();
assertThat(getReportLog()).isEqualTo(
@Test
public void testNoNewIssue() {
settings.setProperty(ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, "true");
- when(inputPathCache.allFiles()).thenReturn(Arrays.<InputFile>asList(new TestInputFileBuilder("foo", "src/Foo.php").build()));
+ when(inputPathCache.allFilesToPublish()).thenReturn(Collections.singleton(new TestInputFileBuilder("foo", "src/Foo.php").build()));
when(issueCache.all()).thenReturn(Arrays.asList(createIssue(false, null)));
report.execute();
assertDeprecated();
@Test
public void testOneNewIssue() {
settings.setProperty(ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, "true");
- when(inputPathCache.allFiles()).thenReturn(Arrays.<InputFile>asList(new TestInputFileBuilder("foo", "src/Foo.php").build()));
+ when(inputPathCache.allFilesToPublish()).thenReturn(Collections.singleton(new TestInputFileBuilder("foo", "src/Foo.php").build()));
when(issueCache.all()).thenReturn(Arrays.asList(createIssue(true, Severity.BLOCKER)));
report.execute();
assertDeprecated();
@Test
public void testOneNewIssuePerSeverity() {
settings.setProperty(ConsoleReport.CONSOLE_REPORT_ENABLED_KEY, "true");
- when(inputPathCache.allFiles()).thenReturn(Arrays.<InputFile>asList(new TestInputFileBuilder("foo", "src/Foo.php").build()));
+ when(inputPathCache.allFilesToPublish()).thenReturn(Collections.singleton(new TestInputFileBuilder("foo", "src/Foo.php").build()));
when(issueCache.all()).thenReturn(Arrays.asList(
createIssue(true, Severity.BLOCKER),
createIssue(true, Severity.CRITICAL),
*/
package org.sonar.scanner.scan.report;
-import com.google.common.collect.Lists;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputDir;
DefaultInputFile inputFile = new TestInputFileBuilder("struts", "src/main/java/org/apache/struts/Action.java").build();
inputFile.setStatus(InputFile.Status.CHANGED);
InputComponentStore fileCache = mock(InputComponentStore.class);
- when(fileCache.allFiles()).thenReturn(Arrays.<InputFile>asList(inputFile));
- when(fileCache.allDirs()).thenReturn(Arrays.<InputDir>asList(inputDir));
+ when(fileCache.allFilesToPublish()).thenReturn(Collections.singleton(inputFile));
+ when(fileCache.allDirs()).thenReturn(Collections.singleton(inputDir));
DefaultInputModule rootModule = new DefaultInputModule("struts");
DefaultInputModule moduleA = new DefaultInputModule("struts-core");
issue.setAssignee("simon");
issue.setCreationDate(SIMPLE_DATE_FORMAT.parse("2013-04-24"));
issue.setNew(false);
- when(issueCache.all()).thenReturn(Lists.newArrayList(issue));
+ when(issueCache.all()).thenReturn(Collections.singleton(issue));
ScannerInput.User user = ScannerInput.User.newBuilder().setLogin("simon").setName("Simon").build();
when(userRepository.load("simon")).thenReturn(user);
issue.setResolution(Issue.RESOLUTION_FIXED);
issue.setCreationDate(SIMPLE_DATE_FORMAT.parse("2013-04-24"));
issue.setNew(false);
- when(issueCache.all()).thenReturn(Lists.newArrayList(issue));
+ when(issueCache.all()).thenReturn(Collections.singleton(issue));
StringWriter writer = new StringWriter();
jsonReport.writeJson(writer);
"sonar.projectVersion", "1.0",
"sonar.sources", "src",
"sonar.analysis.mode", "issues",
+ "sonar.preloadFileMetadata", "true",
"sonar.showProfiling", "true")
.setEnvironmentVariable("SONAR_RUNNER_OPTS", "-Xmx" + xmx + "m -server")
.setProjectDir(baseDir);
private void scanProject() {
MavenBuild build = MavenBuild.create(new File("projects/struts-1.3.9-diet/pom.xml"))
.setCleanSonarGoals()
+ // exclude pom.xml, otherwise it will be published in SQ 6.3+ and not in previous versions, resulting in a different number of components
+ .setProperty("sonar.exclusions", "**/pom.xml")
.setProperty("sonar.dynamicAnalysis", "false")
.setProperty("sonar.scm.disabled", "true")
.setProperty("sonar.cpd.cross_project", "true");