package org.sonar.api.batch.fs;
import org.sonar.api.ExtensionPoint;
-import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.scanner.ScannerSide;
import org.sonarsource.api.sonarlint.SonarLintSide;
/**
* Extension point to exclude some files from inspection
* @since 4.2
+ * @since 7.6 evaluated at project level
*/
@ScannerSide
@SonarLintSide
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
-
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
-
-import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
import org.sonar.api.batch.fs.internal.charhandler.FileHashComputer;
* Computes hash of files. Ends of Lines are ignored, so files with
* same content but different EOL encoding have the same hash.
*/
-@ScannerSide
@Immutable
public class FileMetadata {
private static final char LINE_FEED = '\n';
@Deprecated
@ScannerSide
public class FileExclusions {
- private final Configuration settings;
- public FileExclusions(Configuration settings) {
- this.settings = settings;
+ private final Configuration config;
+
+ public FileExclusions(Configuration config) {
+ this.config = config;
}
public String[] sourceInclusions() {
}
private String[] inclusions(String propertyKey) {
- return Arrays.stream(settings.getStringArray(propertyKey))
+ return Arrays.stream(config.getStringArray(propertyKey))
.map(StringUtils::trim)
.filter(s -> !"**/*".equals(s))
.filter(s -> !"file:**/*".equals(s))
}
private String[] exclusions(String globalExclusionsProperty, String exclusionsProperty) {
- String[] globalExclusions = settings.getStringArray(globalExclusionsProperty);
- String[] exclusions = settings.getStringArray(exclusionsProperty);
+ String[] globalExclusions = config.getStringArray(globalExclusionsProperty);
+ String[] exclusions = config.getStringArray(exclusionsProperty);
return Stream.concat(Arrays.stream(globalExclusions), Arrays.stream(exclusions))
.map(StringUtils::trim)
.toArray(String[]::new);
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.pattern.LineRange;
import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
public class IssueExclusionsRegexpScanner extends CharHandler {
- private static final Logger LOG = LoggerFactory.getLogger(IssueExclusionsLoader.class);
+ private static final Logger LOG = Loggers.get(IssueExclusionsLoader.class);
private final StringBuilder sb = new StringBuilder();
private final List<Pattern> allFilePatterns;
import java.util.Arrays;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
public abstract class AbstractModulePhaseExecutor {
private final PostJobsExecutor postJobsExecutor;
private final SensorsExecutor sensorsExecutor;
private final DefaultModuleFileSystem fs;
- private final QProfileVerifier profileVerifier;
private final IssueExclusionsLoader issueExclusionsLoader;
private final InputModuleHierarchy hierarchy;
- private final FileIndexer fileIndexer;
private final ModuleCoverageExclusions moduleCoverageExclusions;
private final ProjectCoverageExclusions projectCoverageExclusions;
private final AnalysisWarnings analysisWarnings;
private boolean warnCoverageAlreadyLogged;
public AbstractModulePhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, InputModuleHierarchy hierarchy, DefaultModuleFileSystem fs,
- QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, FileIndexer fileIndexer,
+ IssueExclusionsLoader issueExclusionsLoader,
ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
AnalysisWarnings analysisWarnings) {
this.postJobsExecutor = postJobsExecutor;
this.sensorsExecutor = sensorsExecutor;
this.fs = fs;
- this.profileVerifier = profileVerifier;
this.issueExclusionsLoader = issueExclusionsLoader;
this.hierarchy = hierarchy;
- this.fileIndexer = fileIndexer;
this.moduleCoverageExclusions = moduleCoverageExclusions;
this.projectCoverageExclusions = projectCoverageExclusions;
this.analysisWarnings = analysisWarnings;
* Executed on each module
*/
public final void execute(DefaultInputModule module) {
- // Index the filesystem
- fileIndexer.index();
-
- // Log detected languages and their profiles after FS is indexed and languages detected
- profileVerifier.execute();
-
- // Initialize issue exclusions
- initIssueExclusions();
-
// Initialize coverage exclusions
evaluateCoverageExclusions(module);
protected abstract void executeOnRoot();
- private void initIssueExclusions() {
- if (issueExclusionsLoader.shouldExecute()) {
- for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
- issueExclusionsLoader.addMulticriteriaPatterns(((DefaultInputFile) inputFile).getModuleRelativePath(), inputFile.key());
- }
- }
- }
}
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.issue.tracking.IssueTransition;
-import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.report.IssuesReports;
public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor {
private final IssueTransition localIssueTracking;
public IssuesPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
- IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy, FileIndexer fileIndexer,
- ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
- AnalysisWarnings analysisWarnings) {
- super(postJobsExecutor, sensorsExecutor, moduleHierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer,
+ IssuesReports jsonReport, DefaultModuleFileSystem fs,
+ IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy,
+ ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
+ AnalysisWarnings analysisWarnings) {
+ super(postJobsExecutor, sensorsExecutor, moduleHierarchy, fs, issueExclusionsLoader,
moduleCoverageExclusions, projectCoverageExclusions, analysisWarnings);
this.issuesReport = jsonReport;
this.localIssueTracking = localIssueTracking;
import org.sonar.scanner.cpd.CpdExecutor;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.report.ReportPublisher;
-import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scm.ScmPublisher;
public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor {
private final ScmPublisher scm;
public PublishPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- ReportPublisher reportPublisher, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader,
- CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy, FileIndexer fileIndexer,
- ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
- AnalysisWarnings analysisWarnings) {
- super(postJobsExecutor, sensorsExecutor, hierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer, moduleCoverageExclusions,
+ ReportPublisher reportPublisher, DefaultModuleFileSystem fs, IssueExclusionsLoader issueExclusionsLoader,
+ CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy,
+ ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
+ AnalysisWarnings analysisWarnings) {
+ super(postJobsExecutor, sensorsExecutor, hierarchy, fs, issueExclusionsLoader, moduleCoverageExclusions,
projectCoverageExclusions, analysisWarnings);
this.reportPublisher = reportPublisher;
this.cpdExecutor = cpdExecutor;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.MessageException;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
-@ScannerSide
public class QProfileVerifier {
private static final Logger LOG = LoggerFactory.getLogger(QProfileVerifier.class);
- private final Configuration settings;
- private final FileSystem fs;
+ private final Configuration config;
+ private final InputComponentStore store;
private final QualityProfiles profiles;
- public QProfileVerifier(Configuration settings, FileSystem fs, QualityProfiles profiles) {
- this.settings = settings;
- this.fs = fs;
+ public QProfileVerifier(Configuration config, InputComponentStore store, QualityProfiles profiles) {
+ this.config = config;
+ this.store = store;
this.profiles = profiles;
}
@VisibleForTesting
void execute(Logger logger) {
- String defaultName = settings.get(QualityProfiles.SONAR_PROFILE_PROP).orElse(null);
+ String defaultName = config.get(QualityProfiles.SONAR_PROFILE_PROP).orElse(null);
boolean defaultNameUsed = StringUtils.isBlank(defaultName);
- for (String lang : fs.languages()) {
+ for (String lang : store.getLanguages()) {
QProfile profile = profiles.findByLanguage(lang);
if (profile == null) {
logger.warn("No Quality profile found for language {}", lang);
}
}
}
- if (!defaultNameUsed && !fs.languages().isEmpty()) {
+ if (!defaultNameUsed && !store.getLanguages().isEmpty()) {
throw MessageException.of("sonar.profile was set to '" + defaultName + "' but didn't match any profile for any language. Please check your configuration.");
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.scan.filesystem.FileExclusions;
import org.sonar.core.extension.CoreExtensionsInstaller;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.deprecated.perspectives.ScannerPerspectives;
import org.sonar.scanner.issue.ModuleIssueFilters;
import org.sonar.scanner.issue.ModuleIssues;
-import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
-import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
-import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.phases.AbstractModulePhaseExecutor;
import org.sonar.scanner.phases.IssuesPhaseExecutor;
import org.sonar.scanner.phases.ModuleCoverageExclusions;
import org.sonar.scanner.postjob.PostJobOptimizer;
import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.ExclusionFilters;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
-import org.sonar.scanner.scan.filesystem.InputFileBuilder;
-import org.sonar.scanner.scan.filesystem.MetadataGenerator;
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
import org.sonar.scanner.scan.report.IssuesReports;
import org.sonar.scanner.sensor.DefaultSensorContext;
// file system
ModuleInputComponentStore.class,
FileExclusions.class,
- ExclusionFilters.class,
- MetadataGenerator.class,
- FileMetadata.class,
- FileIndexer.class,
- InputFileBuilder.class,
DefaultModuleFileSystem.class,
- QProfileVerifier.class,
SensorOptimizer.class,
PostJobOptimizer.class,
// issues
ModuleIssues.class,
- // issue exclusions
- IssueInclusionPatternInitializer.class,
- IssueExclusionPatternInitializer.class,
- PatternMatcher.class,
- IssueExclusionsLoader.class,
- EnforceIssuesFilter.class,
- IgnoreIssuesFilter.class,
-
// Perspectives
ScannerPerspectives.class,
import com.google.common.annotations.VisibleForTesting;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.api.batch.rule.CheckFactory;
import org.sonar.scanner.deprecated.test.TestableBuilder;
import org.sonar.scanner.issue.DefaultProjectIssues;
import org.sonar.scanner.issue.IssueCache;
+import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
+import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
+import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.issue.tracking.DefaultServerLineHashesLoader;
import org.sonar.scanner.issue.tracking.IssueTransition;
import org.sonar.scanner.issue.tracking.LocalIssueTracking;
import org.sonar.scanner.rule.ActiveRulesProvider;
import org.sonar.scanner.rule.DefaultActiveRulesLoader;
import org.sonar.scanner.rule.DefaultRulesLoader;
+import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.rule.RulesLoader;
import org.sonar.scanner.rule.RulesProvider;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.branch.BranchType;
import org.sonar.scanner.scan.branch.ProjectBranchesProvider;
import org.sonar.scanner.scan.branch.ProjectPullRequestsProvider;
+import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.scan.filesystem.LanguageDetection;
+import org.sonar.scanner.scan.filesystem.MetadataGenerator;
+import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
+import org.sonar.scanner.scan.filesystem.ProjectFileIndexer;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
import org.sonar.scanner.scan.filesystem.StatusDetection;
import org.sonar.scanner.scan.measure.DefaultMetricFinder;
new ScmChangedFilesProvider(),
StatusDetection.class,
LanguageDetection.class,
+ MetadataGenerator.class,
+ FileMetadata.class,
+ FileIndexer.class,
+ ProjectFileIndexer.class,
+ ProjectExclusionFilters.class,
+
// rules
new ActiveRulesProvider(),
new QualityProfilesProvider(),
CheckFactory.class,
+ QProfileVerifier.class,
// issues
IssueCache.class,
// Measures
MeasureCache.class,
+ // issue exclusions
+ IssueInclusionPatternInitializer.class,
+ IssueExclusionPatternInitializer.class,
+ PatternMatcher.class,
+ IssueExclusionsLoader.class,
+ EnforceIssuesFilter.class,
+ IgnoreIssuesFilter.class,
+
// context
ContextPropertiesCache.class,
ContextPropertiesPublisher.class,
LOG.info("Branch name: {}, type: {}", branchConfig.branchName(), branchTypeToDisplayName(branchConfig.branchType()));
}
+ getComponentByType(ProjectFileIndexer.class).index();
+
+ // Log detected languages and their profiles after FS is indexed and languages detected
+ getComponentByType(QProfileVerifier.class).execute();
+
LOG.debug("Start recursive analysis of project modules");
scanRecursively(tree, tree.root(), analysisMode);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.scan.filesystem;
+
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.PathPattern;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+public abstract class AbstractExclusionFilters {
+
+ private static final Logger LOG = Loggers.get(AbstractExclusionFilters.class);
+ private final String[] sourceInclusions;
+ private final String[] testInclusions;
+ private final String[] sourceExclusions;
+ private final String[] testExclusions;
+
+ private PathPattern[] mainInclusionsPattern;
+ private PathPattern[] mainExclusionsPattern;
+ private PathPattern[] testInclusionsPattern;
+ private PathPattern[] testExclusionsPattern;
+
+ public AbstractExclusionFilters(Function<String, String[]> configProvider) {
+ this.sourceInclusions = inclusions(configProvider, CoreProperties.PROJECT_INCLUSIONS_PROPERTY);
+ this.testInclusions = inclusions(configProvider, CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY);
+ this.sourceExclusions = exclusions(configProvider, CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_EXCLUSIONS_PROPERTY);
+ this.testExclusions = exclusions(configProvider, CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY);
+ this.mainInclusionsPattern = prepareMainInclusions(sourceInclusions);
+ this.mainExclusionsPattern = prepareMainExclusions(sourceExclusions, testInclusions);
+ this.testInclusionsPattern = prepareTestInclusions(testInclusions);
+ this.testExclusionsPattern = prepareTestExclusions(testExclusions);
+ }
+
+ protected void log() {
+ log("Included sources: ", mainInclusionsPattern);
+ log("Excluded sources: ", mainExclusionsPattern);
+ log("Included tests: ", testInclusionsPattern);
+ log("Excluded tests: ", testExclusionsPattern);
+ }
+
+ private String[] inclusions(Function<String, String[]> configProvider, String propertyKey) {
+ return Arrays.stream(configProvider.apply(propertyKey))
+ .map(StringUtils::trim)
+ .filter(s -> !"**/*".equals(s))
+ .filter(s -> !"file:**/*".equals(s))
+ .toArray(String[]::new);
+ }
+
+ private String[] exclusions(Function<String, String[]> configProvider, String globalExclusionsProperty, String exclusionsProperty) {
+ String[] globalExclusions = configProvider.apply(globalExclusionsProperty);
+ String[] exclusions = configProvider.apply(exclusionsProperty);
+ return Stream.concat(Arrays.stream(globalExclusions), Arrays.stream(exclusions))
+ .map(StringUtils::trim)
+ .toArray(String[]::new);
+ }
+
+ public boolean hasPattern() {
+ return mainInclusionsPattern.length > 0 || mainExclusionsPattern.length > 0 || testInclusionsPattern.length > 0 || testExclusionsPattern.length > 0;
+ }
+
+ private static void log(String title, PathPattern[] patterns) {
+ if (patterns.length > 0) {
+ LOG.info(title);
+ for (PathPattern pattern : patterns) {
+ LOG.info(" {}", pattern);
+ }
+ }
+ }
+
+ public boolean accept(Path absolutePath, Path relativePath, InputFile.Type type) {
+ PathPattern[] inclusionPatterns;
+ PathPattern[] exclusionPatterns;
+ if (InputFile.Type.MAIN == type) {
+ inclusionPatterns = mainInclusionsPattern;
+ exclusionPatterns = mainExclusionsPattern;
+ } else if (InputFile.Type.TEST == type) {
+ inclusionPatterns = testInclusionsPattern;
+ exclusionPatterns = testExclusionsPattern;
+ } else {
+ throw new IllegalArgumentException("Unknown file type: " + type);
+ }
+
+ if (inclusionPatterns.length > 0) {
+ boolean matchInclusion = false;
+ for (PathPattern pattern : inclusionPatterns) {
+ matchInclusion |= pattern.match(absolutePath, relativePath);
+ }
+ if (!matchInclusion) {
+ return false;
+ }
+ }
+ if (exclusionPatterns.length > 0) {
+ for (PathPattern pattern : exclusionPatterns) {
+ if (pattern.match(absolutePath, relativePath)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private static PathPattern[] prepareMainInclusions(String[] sourceInclusions) {
+ if (sourceInclusions.length > 0) {
+ // User defined params
+ return PathPattern.create(sourceInclusions);
+ }
+ return new PathPattern[0];
+ }
+
+ private static PathPattern[] prepareTestInclusions(String[] testInclusions) {
+ return PathPattern.create(testInclusions);
+ }
+
+ static PathPattern[] prepareMainExclusions(String[] sourceExclusions, String[] testInclusions) {
+ String[] patterns = (String[]) ArrayUtils.addAll(
+ sourceExclusions, testInclusions);
+ return PathPattern.create(patterns);
+ }
+
+ private static PathPattern[] prepareTestExclusions(String[] testExclusions) {
+ return PathPattern.create(testExclusions);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof AbstractExclusionFilters)) {
+ return false;
+ }
+ AbstractExclusionFilters that = (AbstractExclusionFilters) o;
+ return Arrays.equals(sourceInclusions, that.sourceInclusions) &&
+ Arrays.equals(testInclusions, that.testInclusions) &&
+ Arrays.equals(sourceExclusions, that.sourceExclusions) &&
+ Arrays.equals(testExclusions, that.testExclusions);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Arrays.hashCode(sourceInclusions);
+ result = 31 * result + Arrays.hashCode(testInclusions);
+ result = 31 * result + Arrays.hashCode(sourceExclusions);
+ result = 31 * result + Arrays.hashCode(testExclusions);
+ return result;
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.scan.filesystem;
-
-import java.nio.file.Path;
-import org.apache.commons.lang.ArrayUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.PathPattern;
-import org.sonar.api.scan.filesystem.FileExclusions;
-
-@ScannerSide
-public class ExclusionFilters {
-
- private static final Logger LOG = LoggerFactory.getLogger(ExclusionFilters.class);
-
- private final FileExclusions exclusionSettings;
-
- private PathPattern[] mainInclusions;
- private PathPattern[] mainExclusions;
- private PathPattern[] testInclusions;
- private PathPattern[] testExclusions;
-
- public ExclusionFilters(FileExclusions exclusions) {
- this.exclusionSettings = exclusions;
- }
-
- public void prepare() {
- mainInclusions = prepareMainInclusions();
- mainExclusions = prepareMainExclusions();
- testInclusions = prepareTestInclusions();
- testExclusions = prepareTestExclusions();
- log("Included sources: ", mainInclusions);
- log("Excluded sources: ", mainExclusions);
- log("Included tests: ", testInclusions);
- log("Excluded tests: ", testExclusions);
- }
-
- public boolean hasPattern() {
- return mainInclusions.length > 0 || mainExclusions.length > 0 || testInclusions.length > 0 || testExclusions.length > 0;
- }
-
- private static void log(String title, PathPattern[] patterns) {
- if (patterns.length > 0) {
- LOG.info(title);
- for (PathPattern pattern : patterns) {
- LOG.info(" {}", pattern);
- }
- }
- }
-
- public boolean accept(Path absolutePath, Path relativePath, InputFile.Type type) {
- PathPattern[] inclusionPatterns;
- PathPattern[] exclusionPatterns;
- if (InputFile.Type.MAIN == type) {
- inclusionPatterns = mainInclusions;
- exclusionPatterns = mainExclusions;
- } else if (InputFile.Type.TEST == type) {
- inclusionPatterns = testInclusions;
- exclusionPatterns = testExclusions;
- } else {
- throw new IllegalArgumentException("Unknown file type: " + type);
- }
-
- if (inclusionPatterns.length > 0) {
- boolean matchInclusion = false;
- for (PathPattern pattern : inclusionPatterns) {
- matchInclusion |= pattern.match(absolutePath, relativePath);
- }
- if (!matchInclusion) {
- return false;
- }
- }
- if (exclusionPatterns.length > 0) {
- for (PathPattern pattern : exclusionPatterns) {
- if (pattern.match(absolutePath, relativePath)) {
- return false;
- }
- }
- }
- return true;
- }
-
- PathPattern[] prepareMainInclusions() {
- if (exclusionSettings.sourceInclusions().length > 0) {
- // User defined params
- return PathPattern.create(exclusionSettings.sourceInclusions());
- }
- return new PathPattern[0];
- }
-
- PathPattern[] prepareTestInclusions() {
- return PathPattern.create(computeTestInclusions());
- }
-
- private String[] computeTestInclusions() {
- if (exclusionSettings.testInclusions().length > 0) {
- // User defined params
- return exclusionSettings.testInclusions();
- }
- return ArrayUtils.EMPTY_STRING_ARRAY;
- }
-
- PathPattern[] prepareMainExclusions() {
- String[] patterns = (String[]) ArrayUtils.addAll(
- exclusionSettings.sourceExclusions(), computeTestInclusions());
- return PathPattern.create(patterns);
- }
-
- PathPattern[] prepareTestExclusions() {
- return PathPattern.create(exclusionSettings.testExclusions());
- }
-}
*/
package org.sonar.scanner.scan.filesystem;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.io.IOException;
-import java.nio.file.FileSystemLoopException;
-import java.nio.file.FileVisitOption;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
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.List;
-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.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.InputFileFilter;
+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.batch.fs.internal.DefaultInputProject;
+import org.sonar.api.batch.fs.internal.SensorStrategy;
+import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
+import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.util.ProgressReport;
/**
* Index input files into {@link InputComponentStore}.
*/
-@ScannerSide
public class FileIndexer {
- private static final Logger LOG = LoggerFactory.getLogger(FileIndexer.class);
+ private static final Logger LOG = Loggers.get(FileIndexer.class);
+ private final AnalysisWarnings analysisWarnings;
+ private final ScanProperties properties;
private final InputFileFilter[] filters;
- private final ExclusionFilters exclusionFilters;
- private final InputFileBuilder inputFileBuilder;
- private final DefaultInputModule module;
+ private final ProjectExclusionFilters projectExclusionFilters;
+ private final IssueExclusionsLoader issueExclusionsLoader;
+ private final MetadataGenerator metadataGenerator;
+ private final DefaultInputProject project;
private final ScannerComponentIdGenerator scannerComponentIdGenerator;
private final InputComponentStore componentStore;
- private ExecutorService executorService;
- private final List<Future<Void>> tasks;
- private final DefaultModuleFileSystem defaultModuleFileSystem;
+ private final SensorStrategy sensorStrategy;
private final LanguageDetection langDetection;
- private ProgressReport progressReport;
+ private boolean warnExclusionsAlreadyLogged;
- public FileIndexer(ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, DefaultInputModule module, ExclusionFilters exclusionFilters,
- InputFileBuilder inputFileBuilder, DefaultModuleFileSystem defaultModuleFileSystem,
- LanguageDetection languageDetection,
- InputFileFilter[] filters) {
+ public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters,
+ IssueExclusionsLoader issueExclusionsLoader,
+ MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy,
+ LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties,
+ InputFileFilter[] filters) {
+ this.project = project;
this.scannerComponentIdGenerator = scannerComponentIdGenerator;
this.componentStore = componentStore;
- this.module = module;
- this.inputFileBuilder = inputFileBuilder;
- this.defaultModuleFileSystem = defaultModuleFileSystem;
+ this.issueExclusionsLoader = issueExclusionsLoader;
+ this.metadataGenerator = metadataGenerator;
+ this.sensorStrategy = sensorStrategy;
this.langDetection = languageDetection;
+ this.analysisWarnings = analysisWarnings;
+ this.properties = properties;
this.filters = filters;
- this.exclusionFilters = exclusionFilters;
- this.tasks = new ArrayList<>();
+ this.projectExclusionFilters = projectExclusionFilters;
}
- public FileIndexer(ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, DefaultInputModule module, ExclusionFilters exclusionFilters,
- InputFileBuilder inputFileBuilder, DefaultModuleFileSystem defaultModuleFileSystem,
- LanguageDetection languageDetection) {
- this(scannerComponentIdGenerator, componentStore, module, exclusionFilters, inputFileBuilder, defaultModuleFileSystem, languageDetection,
- new InputFileFilter[0]);
+ public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters,
+ IssueExclusionsLoader issueExclusionsLoader,
+ MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
+ this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, issueExclusionsLoader, metadataGenerator, sensorStrategy, languageDetection, analysisWarnings,
+ properties, new InputFileFilter[0]);
}
- public void index() {
- int threads = Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
- this.executorService = Executors.newFixedThreadPool(threads, new ThreadFactoryBuilder()
- .setNameFormat("FileIndexer-%d")
- .setDaemon(true)
- .build());
-
- progressReport = new ProgressReport("Report about progress of file indexation", TimeUnit.SECONDS.toMillis(10));
- progressReport.start("Index files");
- exclusionFilters.prepare();
-
- Progress progress = new Progress();
-
- indexFiles(module.getSourceDirsOrFiles(), InputFile.Type.MAIN, progress);
- indexFiles(module.getTestDirsOrFiles(), InputFile.Type.TEST, progress);
-
- waitForTasksToComplete(progressReport);
-
- progressReport.stop(progress.count() + " " + pluralizeFiles(progress.count()) + " indexed");
-
- if (exclusionFilters.hasPattern()) {
- LOG.info("{} {} ignored because of inclusion/exclusion patterns", progress.excludedByPatternsCount(), pluralizeFiles(progress.excludedByPatternsCount()));
- }
- }
-
- private void waitForTasksToComplete(ProgressReport report) {
- executorService.shutdown();
- for (Future<Void> task : tasks) {
- try {
- task.get();
- } catch (ExecutionException e) {
- // Unwrap ExecutionException
- stopAsap(report);
- throw e.getCause() instanceof RuntimeException ? (RuntimeException) e.getCause() : new IllegalStateException(e.getCause());
- } catch (InterruptedException e) {
- stopAsap(report);
- throw new IllegalStateException(e);
- }
- }
- }
-
- private void stopAsap(ProgressReport report) {
- report.stop(null);
- executorService.shutdownNow();
- try {
- executorService.awaitTermination(5, TimeUnit.SECONDS);
- } catch (InterruptedException e1) {
- // ignore, what's important is the original exception
- }
- }
-
- private static String pluralizeFiles(int count) {
- return count == 1 ? "file" : "files";
- }
-
- private void indexFiles(List<Path> sources, InputFile.Type type, Progress progress) {
- try {
- for (Path dirOrFile : sources) {
- if (dirOrFile.toFile().isDirectory()) {
- indexDirectory(dirOrFile, type, progress);
- } else {
- tasks.add(executorService.submit(() -> indexFile(dirOrFile, type, progress)));
- }
- }
- } catch (IOException e) {
- throw new IllegalStateException("Failed to index files", e);
- }
- }
-
- private void indexDirectory(Path dirToIndex, InputFile.Type type, Progress progress) throws IOException {
- Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
- new IndexFileVisitor(type, progress));
- }
-
- private Void indexFile(Path sourceFile, InputFile.Type type, Progress progress) throws IOException {
+ public void indexFile(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Path sourceFile, InputFile.Type type, ProgressReport progressReport,
+ AtomicInteger excludedByPatternsCount)
+ throws IOException {
// get case of real file without resolving link
Path realAbsoluteFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS).toAbsolutePath().normalize();
- if (!realAbsoluteFile.startsWith(module.getBaseDir())) {
- LOG.warn("File '{}' is ignored. It is not located in module basedir '{}'.", realAbsoluteFile.toAbsolutePath(), module.getBaseDir());
- return null;
+ if (!realAbsoluteFile.startsWith(project.getBaseDir())) {
+ LOG.warn("File '{}' is ignored. It is not located in project basedir '{}'.", realAbsoluteFile.toAbsolutePath(), project.getBaseDir());
+ return;
}
- Path relativePath = module.getBaseDir().relativize(realAbsoluteFile);
- if (!exclusionFilters.accept(realAbsoluteFile, relativePath, type)) {
- progress.increaseExcludedByPatternsCount();
- return null;
+ Path projectRelativePath = project.getBaseDir().relativize(realAbsoluteFile);
+ Path moduleRelativePath = module.getBaseDir().relativize(realAbsoluteFile);
+ if (!projectExclusionFilters.accept(realAbsoluteFile, projectRelativePath, type)) {
+ excludedByPatternsCount.incrementAndGet();
+ return;
+ }
+ if (!moduleExclusionFilters.accept(realAbsoluteFile, moduleRelativePath, type)) {
+ if (projectExclusionFilters.equals(moduleExclusionFilters)) {
+ warnOnce("File '" + projectRelativePath + "' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
+ "Please update file inclusion/exclusion configuration so that patterns refer to project relative paths.");
+ } else {
+ warnOnce("Defining inclusion/exclusions at module level is deprecated. " +
+ "Move file inclusion/exclusion configuration from module '" + module.getName() + "' " +
+ "to the root project and update patterns to refer to project relative paths.");
+ }
+ excludedByPatternsCount.incrementAndGet();
+ return;
}
- String language = langDetection.language(realAbsoluteFile, relativePath);
+ String language = langDetection.language(realAbsoluteFile, projectRelativePath);
if (language == null && langDetection.getForcedLanguage() != null) {
LOG.warn("File '{}' is ignored because it doesn't belong to the forced language '{}'", realAbsoluteFile.toAbsolutePath(), langDetection.getForcedLanguage());
- return null;
+ return;
+ }
+ DefaultIndexedFile indexedFile = new DefaultIndexedFile(realAbsoluteFile, project.key(),
+ projectRelativePath.toString(),
+ moduleRelativePath.toString(),
+ type, language, scannerComponentIdGenerator.getAsInt(), sensorStrategy);
+ DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(module.getKeyWithBranch(), f, module.getEncoding()));
+ if (language != null) {
+ inputFile.setPublished(true);
}
- DefaultInputFile inputFile = inputFileBuilder.create(type, realAbsoluteFile, language);
if (!accept(inputFile)) {
- progress.increaseExcludedByPatternsCount();
- return null;
+ return;
+ }
+ if (componentStore.getFile(inputFile.getProjectRelativePath()) != null) {
+ throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
+ + "disjoint sets for main and test files");
}
- synchronized (this) {
- progress.markAsIndexed(inputFile);
- defaultModuleFileSystem.add(inputFile);
+ componentStore.put(module.key(), inputFile);
+ if (issueExclusionsLoader.shouldExecute()) {
+ issueExclusionsLoader.addMulticriteriaPatterns(inputFile.getProjectRelativePath(), inputFile.key());
+ }
+ LOG.debug("'{}' indexed {}with language '{}'", projectRelativePath, type == Type.TEST ? "as test " : "", inputFile.language());
+ if (properties.preloadFileMetadata()) {
+ inputFile.checkMetadata();
+ }
+ int count = componentStore.allFiles().size();
+ progressReport.message(count + " " + pluralizeFiles(count) + " indexed... (last one was " + inputFile.getProjectRelativePath() + ")");
+ }
+
+ private void warnOnce(String msg) {
+ if (!warnExclusionsAlreadyLogged) {
+ LOG.warn(msg);
+ analysisWarnings.addUnique(msg);
+ warnExclusionsAlreadyLogged = true;
}
- LOG.debug("'{}' indexed {}with language '{}'", relativePath, type == Type.TEST ? "as test " : "", inputFile.language());
- inputFileBuilder.checkMetadata(inputFile);
- return null;
}
private boolean accept(InputFile indexedFile) {
return true;
}
- private class IndexFileVisitor implements FileVisitor<Path> {
- private final Progress status;
- private final Type type;
-
- IndexFileVisitor(InputFile.Type type, Progress status) {
- this.status = status;
- this.type = type;
- }
-
- @Override
- public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
- Path fileName = dir.getFileName();
-
- if (fileName != null && fileName.toString().length() > 1 && fileName.toString().charAt(0) == '.') {
- return FileVisitResult.SKIP_SUBTREE;
- }
- if (Files.isHidden(dir)) {
- return FileVisitResult.SKIP_SUBTREE;
- }
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- if (!Files.isHidden(file)) {
- tasks.add(executorService.submit(() -> indexFile(file, type, status)));
- }
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
- if (exc instanceof FileSystemLoopException) {
- LOG.warn("Not indexing due to symlink loop: {}", file.toFile());
- return FileVisitResult.CONTINUE;
- }
-
- throw exc;
- }
-
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
- return FileVisitResult.CONTINUE;
- }
- }
-
- private class Progress {
- private AtomicInteger indexedCount = new AtomicInteger(0);
- private AtomicInteger excludedByPatternsCount = new AtomicInteger(0);
-
- void markAsIndexed(DefaultInputFile inputFile) {
- if (componentStore.getFile(inputFile.getProjectRelativePath()) != null) {
- throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
- + "disjoint sets for main and test files");
- }
- int count = indexedCount.incrementAndGet();
- progressReport.message(count + " " + pluralizeFiles(count) + " indexed... (last one was " + inputFile.getProjectRelativePath() + ")");
- }
-
- void increaseExcludedByPatternsCount() {
- excludedByPatternsCount.incrementAndGet();
- }
-
- public int excludedByPatternsCount() {
- return excludedByPatternsCount.get();
- }
-
- int count() {
- return indexedCount.get();
- }
+ private static String pluralizeFiles(int count) {
+ return count == 1 ? "file" : "files";
}
}
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileExtensionPredicate;
-import org.sonar.api.scanner.fs.InputProject;
import org.sonar.scanner.scan.branch.BranchConfiguration;
/**
private final Map<String, InputComponent> inputComponents = new HashMap<>();
private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create();
private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
- private final InputProject project;
private final BranchConfiguration branchConfiguration;
- public InputComponentStore(InputProject project, BranchConfiguration branchConfiguration) {
- this.project = project;
+ public InputComponentStore(BranchConfiguration branchConfiguration) {
this.branchConfiguration = branchConfiguration;
}
::iterator;
}
- public Iterable<InputFile> allFiles() {
+ public Collection<InputFile> allFiles() {
return globalInputFileCache.values();
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.scan.filesystem;
-
-import java.nio.file.Path;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.InputFile;
-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.batch.fs.internal.DefaultInputProject;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.scanner.scan.ScanProperties;
-
-public class InputFileBuilder {
- private final DefaultInputProject project;
- private final DefaultInputModule module;
- private final ScannerComponentIdGenerator idGenerator;
- private final MetadataGenerator metadataGenerator;
- private final boolean preloadMetadata;
- private final Path projectBaseDir;
- private final SensorStrategy sensorStrategy;
-
- public InputFileBuilder(DefaultInputProject project, DefaultInputModule module, MetadataGenerator metadataGenerator,
- ScannerComponentIdGenerator idGenerator, ScanProperties properties,
- SensorStrategy sensorStrategy) {
- this.sensorStrategy = sensorStrategy;
- this.projectBaseDir = project.getBaseDir();
- this.project = project;
- this.module = module;
- this.metadataGenerator = metadataGenerator;
- this.idGenerator = idGenerator;
- this.preloadMetadata = properties.preloadFileMetadata();
- }
-
- DefaultInputFile create(InputFile.Type type, Path absolutePath, @Nullable String language) {
- DefaultIndexedFile indexedFile = new DefaultIndexedFile(absolutePath, project.key(),
- projectBaseDir.relativize(absolutePath).toString(),
- module.getBaseDir().relativize(absolutePath).toString(),
- type, language, idGenerator.getAsInt(), sensorStrategy);
- DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(f, module.getEncoding()));
- if (language != null) {
- inputFile.setPublished(true);
- }
-
- return inputFile;
- }
-
- void checkMetadata(DefaultInputFile inputFile) {
- if (preloadMetadata) {
- inputFile.checkMetadata();
- }
- }
-}
import com.google.common.annotations.VisibleForTesting;
import java.io.InputStream;
import java.nio.charset.Charset;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
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.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.fs.internal.Metadata;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
public class MetadataGenerator {
- private static final Logger LOG = LoggerFactory.getLogger(MetadataGenerator.class);
+ private static final Logger LOG = Loggers.get(MetadataGenerator.class);
@VisibleForTesting
static final Charset UTF_32BE = Charset.forName("UTF-32BE");
private final StatusDetection statusDetection;
private final FileMetadata fileMetadata;
- private final DefaultInputModule inputModule;
private final IssueExclusionsLoader exclusionsScanner;
- public MetadataGenerator(DefaultInputModule inputModule, StatusDetection statusDetection, FileMetadata fileMetadata, IssueExclusionsLoader exclusionsScanner) {
- this.inputModule = inputModule;
+ public MetadataGenerator(StatusDetection statusDetection, FileMetadata fileMetadata, IssueExclusionsLoader exclusionsScanner) {
this.statusDetection = statusDetection;
this.fileMetadata = fileMetadata;
this.exclusionsScanner = exclusionsScanner;
* 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) {
+ public void setMetadata(String moduleKeyWithBranch, final DefaultInputFile inputFile, Charset defaultEncoding) {
CharsetDetector charsetDetector = new CharsetDetector(inputFile.path(), defaultEncoding);
try {
Charset charset;
inputFile.setCharset(charset);
Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile.key()));
inputFile.setMetadata(metadata);
- inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile, metadata.hash()));
- LOG.debug("'{}' generated metadata {} with charset '{}'", inputFile, inputFile.type() == Type.TEST ? "as test " : "", charset);
+ inputFile.setStatus(statusDetection.status(moduleKeyWithBranch, inputFile, metadata.hash()));
+ LOG.debug("'{}' generated metadata{} with charset '{}'", inputFile, inputFile.type() == Type.TEST ? " as test " : "", charset);
} catch (Exception e) {
throw new IllegalStateException(e);
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.scan.filesystem;
+
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+
+import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
+
+public class ModuleExclusionFilters extends AbstractExclusionFilters {
+
+ public ModuleExclusionFilters(DefaultInputModule module) {
+ super(k -> {
+ String value = module.properties().get(k);
+ return value != null ? parseAsCsv(k, value) : new String[0];
+ });
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.scan.filesystem;
+
+import org.sonar.api.config.Configuration;
+
+public class ProjectExclusionFilters extends AbstractExclusionFilters {
+
+ public ProjectExclusionFilters(Configuration projectConfig) {
+ super(projectConfig::getStringArray);
+ log();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.scan.filesystem;
+
+import java.io.IOException;
+import java.nio.file.FileSystemLoopException;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.scanner.util.ProgressReport;
+
+/**
+ * Index project input files into {@link InputComponentStore}.
+ */
+public class ProjectFileIndexer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ProjectFileIndexer.class);
+ private final AbstractExclusionFilters projectExclusionFilters;
+ private final DefaultInputProject project;
+ private final InputComponentStore componentStore;
+ private final InputModuleHierarchy inputModuleHierarchy;
+ private final FileIndexer fileIndexer;
+
+ private ProgressReport progressReport;
+
+ public ProjectFileIndexer(DefaultInputProject project, InputComponentStore componentStore, AbstractExclusionFilters exclusionFilters,
+ InputModuleHierarchy inputModuleHierarchy,
+ FileIndexer fileIndexer) {
+ this.project = project;
+ this.componentStore = componentStore;
+ this.inputModuleHierarchy = inputModuleHierarchy;
+ this.fileIndexer = fileIndexer;
+ this.projectExclusionFilters = exclusionFilters;
+ }
+
+ public void index() {
+ progressReport = new ProgressReport("Report about progress of file indexation", TimeUnit.SECONDS.toMillis(10));
+ progressReport.start("Index files");
+
+ AtomicInteger excludedByPatternsCount = new AtomicInteger(0);
+
+ indexModulesRecursively(inputModuleHierarchy.root(), excludedByPatternsCount);
+
+ int totalIndexed = componentStore.allFiles().size();
+ progressReport.stop(totalIndexed + " " + pluralizeFiles(totalIndexed) + " indexed");
+
+ if (projectExclusionFilters.hasPattern()) {
+ int excludedFileCount = excludedByPatternsCount.get();
+ LOG.info("{} {} ignored because of inclusion/exclusion patterns", excludedFileCount, pluralizeFiles(excludedFileCount));
+ }
+ }
+
+ private void indexModulesRecursively(DefaultInputModule module, AtomicInteger excludedByPatternsCount) {
+ inputModuleHierarchy.children(module).forEach(m -> indexModulesRecursively(m, excludedByPatternsCount));
+ index(module, excludedByPatternsCount);
+ }
+
+ private void index(DefaultInputModule module, AtomicInteger excludedByPatternsCount) {
+ ModuleExclusionFilters moduleExclusionFilters = new ModuleExclusionFilters(module);
+ indexFiles(module, moduleExclusionFilters, module.getSourceDirsOrFiles(), Type.MAIN, excludedByPatternsCount);
+ indexFiles(module, moduleExclusionFilters, module.getTestDirsOrFiles(), Type.TEST, excludedByPatternsCount);
+ }
+
+ private static String pluralizeFiles(int count) {
+ return count == 1 ? "file" : "files";
+ }
+
+ private void indexFiles(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, List<Path> sources, Type type, AtomicInteger excludedByPatternsCount) {
+ try {
+ for (Path dirOrFile : sources) {
+ if (dirOrFile.toFile().isDirectory()) {
+ indexDirectory(module, moduleExclusionFilters, dirOrFile, type, excludedByPatternsCount);
+ } else {
+ fileIndexer.indexFile(module, moduleExclusionFilters, dirOrFile, type, progressReport, excludedByPatternsCount);
+ }
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to index files", e);
+ }
+ }
+
+ private void indexDirectory(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Path dirToIndex, Type type, AtomicInteger excludedByPatternsCount)
+ throws IOException {
+ Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
+ new IndexFileVisitor(module, moduleExclusionFilters, type, excludedByPatternsCount));
+ }
+
+ private class IndexFileVisitor implements FileVisitor<Path> {
+ private final DefaultInputModule module;
+ private final AbstractExclusionFilters moduleExclusionFilters;
+ private final Type type;
+ private final AtomicInteger excludedByPatternsCount;
+
+ IndexFileVisitor(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Type type, AtomicInteger excludedByPatternsCount) {
+ this.module = module;
+ this.moduleExclusionFilters = moduleExclusionFilters;
+ this.type = type;
+ this.excludedByPatternsCount = excludedByPatternsCount;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ Path fileName = dir.getFileName();
+
+ if (fileName != null && fileName.toString().length() > 1 && fileName.toString().charAt(0) == '.') {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ if (Files.isHidden(dir)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ if (!Files.isHidden(file)) {
+ fileIndexer.indexFile(module, moduleExclusionFilters, file, type, progressReport, excludedByPatternsCount);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+ if (exc instanceof FileSystemLoopException) {
+ LOG.warn("Not indexing due to symlink loop: {}", file.toFile());
+ return FileVisitResult.CONTINUE;
+ }
+
+ throw exc;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+ }
+
+}
when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir));
DefaultInputProject project = TestInputFileBuilder.newDefaultInputProject("foo", baseDir);
- componentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
+ componentStore = new InputComponentStore(mock(BranchConfiguration.class));
executor = new CpdExecutor(settings, index, publisher, componentStore, executorService);
reader = new ScannerReportReader(outputDir);
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.scanner.mediumtest.AnalysisResult;
-import org.sonar.scanner.mediumtest.LogOutputRecorder;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.xoo.XooPlugin;
import org.sonar.xoo.global.GlobalSensor;
import org.sonar.xoo.rule.XooRulesDefinition;
+import static java.util.stream.Collectors.joining;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeTrue;
@Rule
public ExpectedException thrown = ExpectedException.none();
- private LogOutputRecorder logs = new LogOutputRecorder();
+ @Rule
+ public LogTester logTester = new LogTester();
@Rule
public ScannerMediumTester tester = new ScannerMediumTester()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
- .addDefaultQProfile("xoo2", "Sonar Way")
- .setLogOutput(logs);
+ .addDefaultQProfile("xoo2", "Sonar Way");
private File baseDir;
private ImmutableMap.Builder<String, String> builder;
.build())
.execute();
- assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
- assertThat(logs.getAllAsString()).contains("Organization key: my org");
- assertThat(logs.getAllAsString()).doesNotContain("Branch key");
+ assertThat(logTester.logs()).contains("Project key: com.foo.project");
+ assertThat(logTester.logs()).contains("Organization key: my org");
+ assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Branch key");
}
@Test
.build())
.execute();
- assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
- assertThat(logs.getAllAsString()).contains("Branch key: my-branch");
- assertThat(logs.getAllAsString()).contains("The use of \"sonar.branch\" is deprecated and replaced by \"sonar.branch.name\".");
+ assertThat(logTester.logs()).contains("Project key: com.foo.project");
+ assertThat(logTester.logs()).contains("Branch key: my-branch");
+ assertThat(logTester.logs()).contains("The use of \"sonar.branch\" is deprecated and replaced by \"sonar.branch.name\". See https://redirect.sonarsource.com/doc/branches.html.");
}
@Test
.build())
.execute();
- assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
- assertThat(logs.getAllAsString()).doesNotContain("Organization key");
- assertThat(logs.getAllAsString()).doesNotContain("Branch key");
+ assertThat(logTester.logs()).contains("Project key: com.foo.project");
+ assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Organization key");
+ assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Branch key");
}
@Test
File javaFile = new File(srcDir, "sample.java");
FileUtils.write(javaFile, "Sample xoo\ncontent");
+ logTester.setLevel(LoggerLevel.DEBUG);
+
tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();
- assertThat(logs.getAllAsString()).contains("2 files indexed");
- assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
- assertThat(logs.getAllAsString()).doesNotContain("'src/sample.java' generated metadata");
+ assertThat(logTester.logs()).contains("2 files indexed");
+ assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
+ assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/sample.java' generated metadata");
}
File javaFile = new File(srcDir, "sample.java");
FileUtils.write(javaFile, "Sample xoo\ncontent");
+ logTester.setLevel(LoggerLevel.DEBUG);
+
tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();
- assertThat(logs.getAllAsString()).contains("2 files indexed");
- assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
- assertThat(logs.getAllAsString()).contains("'src/sample.java' generated metadata");
+ assertThat(logTester.logs()).contains("2 files indexed");
+ assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
+ assertThat(logTester.logs()).contains("'src/sample.java' generated metadata with charset 'UTF-8'");
}
@Test
Path javaFile = mainDir.resolve("sample.java");
Files.write(javaFile, "Sample xoo\ncontent".getBytes(StandardCharsets.UTF_8));
+ logTester.setLevel(LoggerLevel.DEBUG);
+
AnalysisResult result = tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src/main")
.build())
.execute();
- assertThat(logs.getAllAsString()).contains("3 files indexed");
- assertThat(logs.getAllAsString()).contains("'src/main/sample.xoo' generated metadata");
- assertThat(logs.getAllAsString()).doesNotContain("'src/main/sample.java' generated metadata");
- assertThat(logs.getAllAsString()).doesNotContain("'src/test/sample.java' generated metadata");
+ assertThat(logTester.logs()).contains("3 files indexed");
+ assertThat(logTester.logs()).contains("'src/main/sample.xoo' generated metadata with charset 'UTF-8'");
+ assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/main/sample.java' generated metadata");
+ assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/test/sample.java' generated metadata");
DefaultInputFile javaInputFile = (DefaultInputFile) result.inputFile("src/main/sample.java");
thrown.expect(IllegalStateException.class);
File xooFile = new File(srcDir, "sample.unknown");
FileUtils.write(xooFile, "Sample xoo\ncontent");
+ logTester.setLevel(LoggerLevel.DEBUG);
+
AnalysisResult result = tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();
- assertThat(logs.getAllAsString()).contains("1 file indexed");
- assertThat(logs.getAllAsString()).contains("'src" + File.separator + "sample.unknown' indexed with language 'null'");
- assertThat(logs.getAllAsString()).contains("'src/sample.unknown' generated metadata");
+ assertThat(logTester.logs()).contains("1 file indexed");
+ assertThat(logTester.logs()).contains("'src" + File.separator + "sample.unknown' indexed with language 'null'");
+ assertThat(logTester.logs()).contains("'src/sample.unknown' generated metadata with charset 'UTF-8'");
DefaultInputFile inputFile = (DefaultInputFile) result.inputFile("src/sample.unknown");
assertThat(result.getReportComponent(inputFile)).isNotNull();
}
new Random().nextBytes(b);
FileUtils.writeByteArrayToFile(unknownFile, b);
+ logTester.setLevel(LoggerLevel.DEBUG);
+
tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();
- assertThat(logs.getAllAsString()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with language 'null'");
- assertThat(logs.getAllAsString()).doesNotContain("'src/myfile.binary' generating issue exclusions");
- assertThat(logs.getAllAsString()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
+ assertThat(logTester.logs()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with language 'null'");
+ assertThat(logTester.logs()).doesNotContain("'src/myfile.binary' generating issue exclusions");
+ assertThat(logTester.logs()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
}
@Test
File unknownFile = new File(srcDir, "myfile.binary");
FileUtils.write(unknownFile, "some text");
+ logTester.setLevel(LoggerLevel.DEBUG);
+
tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();
- assertThat(logs.getAllAsString()).containsOnlyOnce("- Exclusion pattern 'pattern'");
- assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
+ assertThat(logTester.logs()).containsOnlyOnce("- Exclusion pattern 'pattern': every issue in this file will be ignored.");
+ assertThat(logTester.logs()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
}
@Test
assertThat(result.inputFiles()).hasSize(2);
}
+ @Test
+ public void warn_user_for_outdated_inherited_exclusions_for_multi_module_project() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sample.xoo");
+ FileUtils.write(xooFileA, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sample.xoo");
+ FileUtils.write(xooFileB, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("sonar.exclusions", "src/sample.xoo")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(fileA).isNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(fileB).isNull();
+
+ assertThat(logTester.logs(LoggerLevel.WARN))
+ .contains("File 'moduleB/src/sample.xoo' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
+ "Please update file inclusion/exclusion configuration so that patterns refer to project relative paths.");
+ }
+
+ @Test
+ public void warn_user_for_outdated_module_exclusions_for_multi_module_project() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File baseDirModuleA = new File(baseDir, "moduleA");
+ File baseDirModuleB = new File(baseDir, "moduleB");
+ File srcDirA = new File(baseDirModuleA, "src");
+ srcDirA.mkdirs();
+ File srcDirB = new File(baseDirModuleB, "src");
+ srcDirB.mkdirs();
+
+ File xooFileA = new File(srcDirA, "sample.xoo");
+ FileUtils.write(xooFileA, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+ File xooFileB = new File(srcDirB, "sample.xoo");
+ FileUtils.write(xooFileB, "Sample xoo\ncontent", StandardCharsets.UTF_8);
+
+ AnalysisResult result = tester.newAnalysis()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.sources", "src")
+ .put("sonar.modules", "moduleA,moduleB")
+ .put("moduleB.sonar.exclusions", "src/sample.xoo")
+ .build())
+ .execute();
+
+ InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
+ assertThat(fileA).isNotNull();
+
+ InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
+ assertThat(fileB).isNull();
+
+ assertThat(logTester.logs(LoggerLevel.WARN))
+ .contains("Defining inclusion/exclusions at module level is deprecated. " +
+ "Move file inclusion/exclusion configuration from module 'moduleB' to the root project and update patterns to refer to project relative paths.");
+ }
+
@Test
public void failForDuplicateInputFile() throws IOException {
File srcDir = new File(baseDir, "src");
.execute();
assertThat(result.inputFiles()).hasSize(4);
- assertThat(logs.get("INFO")).contains(
+ assertThat(logTester.logs(LoggerLevel.INFO)).contains(
"Global Sensor: module_a/module_a1/src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo",
"Global Sensor: module_a/module_a2/src/main/xoo/com/sonar/it/samples/modules/a2/HelloA2.xoo",
"Global Sensor: module_b/module_b1/src/main/xoo/com/sonar/it/samples/modules/b1/HelloB1.xoo",
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.AnalysisMode;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.postjob.issue.PostJobIssue;
import org.sonar.api.batch.rule.Severity;
@Before
public void setUp() throws IOException {
issueCache = mock(IssueCache.class);
- DefaultInputProject project = TestInputFileBuilder.newDefaultInputProject("foo", temp.newFolder());
- componentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
+ componentStore = new InputComponentStore(mock(BranchConfiguration.class));
settings = new MapSettings();
analysisMode = mock(AnalysisMode.class);
context = new DefaultPostJobContext(settings.asConfig(), settings, issueCache, componentStore, analysisMode);
.setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1);
- InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+ InputComponentStore store = new InputComponentStore(branchConfiguration);
Path moduleBaseDir = temp.newFolder().toPath();
ProjectDefinition module1Def = ProjectDefinition.create()
DefaultInputProject project = new DefaultInputProject(rootDef, 1);
- InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+ InputComponentStore store = new InputComponentStore(branchConfiguration);
ComponentsPublisher publisher = new ComponentsPublisher(project, store);
publisher.publish(writer);
.setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1);
- InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+ InputComponentStore store = new InputComponentStore(branchConfiguration);
DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.java", 5)
.setLines(2)
.setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1);
- InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+ InputComponentStore store = new InputComponentStore(branchConfiguration);
ComponentsPublisher publisher = new ComponentsPublisher(project, store);
publisher.publish(writer);
.setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1);
- InputComponentStore store = new InputComponentStore(project, branchConfiguration);
+ InputComponentStore store = new InputComponentStore(branchConfiguration);
ComponentsPublisher publisher = new ComponentsPublisher(project, store);
publisher.publish(writer);
String moduleKey = "foo";
inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setLines(5).build();
DefaultInputProject rootModule = TestInputFileBuilder.newDefaultInputProject(moduleKey, temp.newFolder());
- InputComponentStore componentCache = new InputComponentStore(rootModule, mock(BranchConfiguration.class));
+ InputComponentStore componentCache = new InputComponentStore(mock(BranchConfiguration.class));
componentCache.put(moduleKey, inputFile);
measureCache = mock(MeasureCache.class);
String projectKey = "foo";
project = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder());
inputFile = new TestInputFileBuilder(projectKey, "src/Foo.php").setPublish(true).build();
- InputComponentStore componentCache = new InputComponentStore(project, mock(BranchConfiguration.class));
+ InputComponentStore componentCache = new InputComponentStore(mock(BranchConfiguration.class));
componentCache.put(projectKey, inputFile);
measureCache = mock(MeasureCache.class);
when(measureCache.byComponentKey(anyString())).thenReturn(Collections.<DefaultMeasure<?>>emptyList());
.build();
DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(moduleKey, baseDir);
- InputComponentStore componentStore = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
+ InputComponentStore componentStore = new InputComponentStore(mock(BranchConfiguration.class));
componentStore.put(moduleKey, inputFile);
publisher = new SourcePublisher(componentStore);
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
-import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.MessageException;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@Rule
public ExpectedException thrown = ExpectedException.none();
- private DefaultFileSystem fs;
+ private InputComponentStore store;
private QualityProfiles profiles;
private MapSettings settings = new MapSettings();
@Before
public void before() throws Exception {
- fs = new DefaultFileSystem(temp.newFolder().toPath());
+ store = new InputComponentStore(mock(BranchConfiguration.class));
profiles = mock(QualityProfiles.class);
QProfile javaProfile = new QProfile("p1", "My Java profile", "java", null);
when(profiles.findByLanguage("java")).thenReturn(javaProfile);
@Test
public void should_log_all_used_profiles() {
- fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
- fs.add(new TestInputFileBuilder("foo", "src/Baz.cbl").setLanguage("cobol").build());
+ store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+ store.put("foo", new TestInputFileBuilder("foo", "src/Baz.cbl").setLanguage("cobol").build());
- QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
+ QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
Logger logger = mock(Logger.class);
profileLogger.execute(logger);
@Test
public void should_fail_if_default_profile_not_used() {
- fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+ store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
settings.setProperty("sonar.profile", "Unknown");
- QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
+ QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
thrown.expect(MessageException.class);
thrown.expectMessage("sonar.profile was set to 'Unknown' but didn't match any profile for any language. Please check your configuration.");
public void should_not_fail_if_no_language_on_project() {
settings.setProperty("sonar.profile", "Unknown");
- QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
+ QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
profileLogger.execute();
@Test
public void should_not_fail_if_default_profile_used_at_least_once() {
- fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+ store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
settings.setProperty("sonar.profile", "My Java profile");
- QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
+ QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
profileLogger.execute();
}
private InputComponentStore componentStore;
public void createIndexer(DefaultInputProject rootProject) {
- componentStore = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
+ componentStore = new InputComponentStore(mock(BranchConfiguration.class));
moduleHierarchy = mock(DefaultInputModuleHierarchy.class);
indexer = new ModuleIndexer(componentStore, moduleHierarchy);
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.scan.filesystem;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.fs.IndexedFile;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.scan.filesystem.FileExclusions;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ExclusionFiltersTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
- private Path moduleBaseDir;
- private MapSettings settings;
- private ExclusionFilters filter;
-
- @Before
- public void setUp() throws IOException {
- settings = new MapSettings();
- moduleBaseDir = temp.newFolder().toPath();
- filter = new ExclusionFilters(new FileExclusions(settings.asConfig()));
- }
-
- @Test
- public void no_inclusions_nor_exclusions() throws IOException {
- filter.prepare();
-
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
- }
-
- @Test
- public void match_inclusion() throws IOException {
- settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java");
- filter.prepare();
-
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
-
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
- }
-
- @Test
- public void match_at_least_one_inclusion() throws IOException {
- settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java,**/*Dto.java");
- filter.prepare();
-
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
-
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDto.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
- }
-
- @Test
- public void match_exclusions() throws IOException {
- settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
- settings.setProperty(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, "src/test/java/**/*");
- settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.java");
- filter.prepare();
-
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
-
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
-
- // source exclusions do not apply to tests
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/test/java/com/mycompany/FooDao.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
- }
-
- @Test
- public void match_exclusion_by_absolute_path() throws IOException {
- File excludedFile = new File(moduleBaseDir.toString(), "src/main/java/org/bar/Bar.java");
-
- settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
- settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getAbsolutePath());
- filter.prepare();
-
- IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
-
- indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Bar.java", null);
- assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
- }
-
- @Test
- public void trim_pattern() {
- settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, " **/*Dao.java ");
-
- assertThat(filter.prepareMainExclusions()[0].toString()).isEqualTo("**/*Dao.java");
- }
-
-}
DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(rootDef);
DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(moduleDef);
- InputComponentStore store = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
+ InputComponentStore store = new InputComponentStore(mock(BranchConfiguration.class));
store.put(subModule);
DefaultInputFile fooFile = new TestInputFileBuilder(rootModuleKey, "src/main/java/Foo.java")
static class InputComponentStoreTester extends InputComponentStore {
InputComponentStoreTester() throws IOException {
- super(TestInputFileBuilder.newDefaultInputProject("root", temp.newFolder()), mock(BranchConfiguration.class));
+ super(mock(BranchConfiguration.class));
}
InputFile addFile(String moduleKey, String relpath, String language) {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.scan.filesystem;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-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.batch.fs.internal.DefaultInputProject;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.scanner.scan.ScanProperties;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class InputFileBuilderTest {
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private Path baseDir;
- private Path workDir;
- private InputFileBuilder builder;
-
- private SensorStrategy sensorStrategy;
-
- @Before
- public void setUp() throws IOException {
- baseDir = temp.newFolder().toPath();
- workDir = temp.newFolder().toPath();
- DefaultInputProject project = new DefaultInputProject(ProjectDefinition.create()
- .setBaseDir(baseDir.toFile())
- .setWorkDir(workDir.toFile())
- .setProperty(CoreProperties.ENCODING_PROPERTY, StandardCharsets.UTF_8.name())
- .setKey("root"), 0);
- Path moduleBaseDir = baseDir.resolve("module1");
- Files.createDirectories(moduleBaseDir);
- DefaultInputModule module = new DefaultInputModule(ProjectDefinition.create()
- .setBaseDir(moduleBaseDir.toFile())
- .setWorkDir(workDir.toFile())
- .setKey("module1"), 1);
-
- MetadataGenerator metadataGenerator = mock(MetadataGenerator.class);
- ScannerComponentIdGenerator idGenerator = new ScannerComponentIdGenerator();
- ScanProperties properties = mock(ScanProperties.class);
- sensorStrategy = new SensorStrategy();
- builder = new InputFileBuilder(project, module, metadataGenerator, idGenerator, properties,
- sensorStrategy);
- }
-
- @Test
- public void testBuild() {
- Path filePath = baseDir.resolve("module1/src/File1.xoo");
- DefaultInputFile inputFile = builder.create(Type.MAIN, filePath, null);
-
- assertThat(inputFile.absolutePath()).isEqualTo(filePath.toString().replaceAll("\\\\", "/"));
- assertThat(inputFile.relativePath()).isEqualTo("src/File1.xoo");
- assertThat(inputFile.path()).isEqualTo(filePath);
- assertThat(inputFile.key()).isEqualTo("root:module1/src/File1.xoo");
- assertThat(inputFile.isPublished()).isFalse();
-
- sensorStrategy.setGlobal(true);
-
- assertThat(inputFile.relativePath()).isEqualTo("module1/src/File1.xoo");
- }
-}
import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.utils.PathUtils;
MockitoAnnotations.initMocks(this);
metadata = new FileMetadata();
IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class));
- generator = new MetadataGenerator(new DefaultInputModule(ProjectDefinition.create().setKey("module").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())),
- statusDetection, metadata, issueExclusionsLoader);
+ generator = new MetadataGenerator(statusDetection, metadata, issueExclusionsLoader);
}
@Test
DefaultInputFile inputFile = new TestInputFileBuilder("struts", relativePath)
.setModuleBaseDir(baseDir)
.build();
- generator.setMetadata(inputFile, StandardCharsets.US_ASCII);
+ generator.setMetadata("module", inputFile, StandardCharsets.US_ASCII);
return inputFile;
}
@Before
public void setUp() throws IOException {
DefaultInputProject root = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder());
- componentStore = new InputComponentStore(root, mock(BranchConfiguration.class));
+ componentStore = new InputComponentStore(mock(BranchConfiguration.class));
}
@Test
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.scan.filesystem;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.fs.IndexedFile;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
+import org.sonar.api.config.internal.MapSettings;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProjectExclusionFiltersTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+ private Path moduleBaseDir;
+ private MapSettings settings;
+
+ @Before
+ public void setUp() throws IOException {
+ settings = new MapSettings();
+ moduleBaseDir = temp.newFolder().toPath();
+ }
+
+ @Test
+ public void no_inclusions_nor_exclusions() throws IOException {
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
+ }
+
+ @Test
+ public void match_inclusion() throws IOException {
+ settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java");
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
+ }
+
+ @Test
+ public void match_at_least_one_inclusion() throws IOException {
+ settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java,**/*Dto.java");
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
+
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDto.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+ }
+
+ @Test
+ public void match_exclusions() throws IOException {
+ settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
+ settings.setProperty(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, "src/test/java/**/*");
+ settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.java");
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
+
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+
+ // source exclusions do not apply to tests
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/test/java/com/mycompany/FooDao.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.TEST)).isTrue();
+ }
+
+ @Test
+ public void match_exclusion_by_absolute_path() throws IOException {
+ File excludedFile = new File(moduleBaseDir.toString(), "src/main/java/org/bar/Bar.java");
+
+ settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
+ settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getAbsolutePath());
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+ IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
+
+ indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Bar.java", null);
+ assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
+ }
+
+ @Test
+ public void trim_pattern() {
+ ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());
+
+ assertThat(filter.prepareMainExclusions(new String[] {" **/*Dao.java "}, new String[0])[0].toString()).isEqualTo("**/*Dao.java");
+ }
+
+}
ProjectDefinition def = ProjectDefinition.create().setBaseDir(projectBaseDir).setWorkDir(temp.newFolder()).setKey("struts");
DefaultInputProject project = new DefaultInputProject(def, 1);
- InputComponentStore inputComponentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
+ InputComponentStore inputComponentStore = new InputComponentStore(mock(BranchConfiguration.class));
DefaultInputFile inputFile = new TestInputFileBuilder("struts", "src/main/java/org/apache/struts/Action.java")
.setModuleBaseDir(projectBaseDir.toPath()).build();