diff options
author | Dimitris Kavvathas <dimitris.kavvathas@sonarsource.com> | 2022-12-07 11:10:47 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-12-12 20:04:02 +0000 |
commit | 978818983042dcad1e997cc81c8a98c9724bfb80 (patch) | |
tree | c79e3792119850141e6c0f9c4326adbedab39410 /sonar-scanner-engine/src/main/java/org/sonar/scanner | |
parent | 133d15e977d3d2a71413578ac5b8c72d918b8b7d (diff) | |
download | sonarqube-978818983042dcad1e997cc81c8a98c9724bfb80.tar.gz sonarqube-978818983042dcad1e997cc81c8a98c9724bfb80.zip |
SONAR-17518 Ignore AccessDeniedException of directory, if it is excluded.
Diffstat (limited to 'sonar-scanner-engine/src/main/java/org/sonar/scanner')
2 files changed, 75 insertions, 6 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java index 2d808175dd0..545d653fbf1 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java @@ -45,7 +45,7 @@ public abstract class AbstractExclusionFilters { private PathPattern[] testInclusionsPattern; private PathPattern[] testExclusionsPattern; - public AbstractExclusionFilters(Function<String, String[]> configProvider) { + protected 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); @@ -138,10 +138,6 @@ public abstract class AbstractExclusionFilters { public boolean isExcluded(Path absolutePath, Path relativePath, InputFile.Type type) { PathPattern[] exclusionPatterns = InputFile.Type.MAIN == type ? mainExclusionsPattern : testExclusionsPattern; - if (exclusionPatterns.length == 0) { - return false; - } - for (PathPattern pattern : exclusionPatterns) { if (pattern.match(absolutePath, relativePath)) { return true; @@ -150,4 +146,25 @@ public abstract class AbstractExclusionFilters { return false; } + + /** + * <p>Checks if the file should be excluded as a parent directory of excluded files and subdirectories.</p> + * + * @param absolutePath The full path of the file. + * @param relativePath The relative path of the file. + * @param baseDir The base directory of the project. + * @param type The file type. + * @return True if the file should be excluded, false otherwise. + */ + public boolean isExcludedAsParentDirectoryOfExcludedChildren(Path absolutePath, Path relativePath, Path baseDir, InputFile.Type type) { + PathPattern[] exclusionPatterns = InputFile.Type.MAIN == type ? mainExclusionsPattern : testExclusionsPattern; + + return Stream.of(exclusionPatterns) + .map(PathPattern::toString) + .filter(ps -> ps.endsWith("/**/*")) + .map(ps -> ps.substring(0, ps.length() - 5)) + .map(baseDir::resolve) + .anyMatch(exclusionRootPath -> absolutePath.startsWith(exclusionRootPath) + || PathPattern.create(exclusionRootPath.toString()).match(absolutePath, relativePath)); + } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java index 1219428a305..0c7b24d235c 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java @@ -20,6 +20,7 @@ package org.sonar.scanner.scan.filesystem; import java.io.IOException; +import java.nio.file.AccessDeniedException; import java.nio.file.FileSystemLoopException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; @@ -38,6 +39,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; +import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile.Type; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.scm.IgnoreCommand; @@ -216,6 +218,27 @@ public class ProjectFileIndexer { new IndexFileVisitor(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, type, exclusionCounter)); } + + /** + * <p>Checks if the path is a directory that is excluded.</p> + * + * <p>Exclusions patterns are checked both at project and module level.</p> + * + * @param moduleExclusionFilters The exclusion filters. + * @param realAbsoluteFile The path to be checked. + * @param projectBaseDir The project base directory. + * @param moduleBaseDir The module base directory. + * @param type The input file type. + * @return True if path is an excluded directory, false otherwise. + */ + private static boolean isExcludedDirectory(ModuleExclusionFilters moduleExclusionFilters, Path realAbsoluteFile, Path projectBaseDir, Path moduleBaseDir, + InputFile.Type type) { + Path projectRelativePath = projectBaseDir.relativize(realAbsoluteFile); + Path moduleRelativePath = moduleBaseDir.relativize(realAbsoluteFile); + return moduleExclusionFilters.isExcludedAsParentDirectoryOfExcludedChildren(realAbsoluteFile, projectRelativePath, projectBaseDir, type) + || moduleExclusionFilters.isExcludedAsParentDirectoryOfExcludedChildren(realAbsoluteFile, moduleRelativePath, moduleBaseDir, type); + } + private class IndexFileVisitor implements FileVisitor<Path> { private final DefaultInputModule module; private final ModuleExclusionFilters moduleExclusionFilters; @@ -249,16 +272,45 @@ public class ProjectFileIndexer { return FileVisitResult.CONTINUE; } + /** + * <p>Overridden method to handle exceptions while visiting files in the analysis.</p> + * + * <p> + * <ul> + * <li>FileSystemLoopException - We show a warning that a symlink loop exists and we skip the file.</li> + * <li>AccessDeniedException for excluded files/directories - We skip the file, as files excluded from the analysis, shouldn't throw access exceptions.</li> + * </ul> + * </p> + * + * @param file a reference to the file + * @param exc the I/O exception that prevented the file from being visited + * + * @throws IOException + */ @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; + } else if (exc instanceof AccessDeniedException && isExcluded(file)) { + return FileVisitResult.CONTINUE; } - throw exc; } + /** + * <p>Checks if the directory is excluded in the analysis or not. Only the exclusions are checked.</p> + * + * <p>The inclusions cannot be checked for directories, since the current implementation of pattern matching is intended only for files.</p> + * + * @param path The file or directory. + * @return True if file/directory is excluded from the analysis, false otherwise. + */ + private boolean isExcluded(Path path) throws IOException { + Path realAbsoluteFile = path.toRealPath(LinkOption.NOFOLLOW_LINKS).toAbsolutePath().normalize(); + return isExcludedDirectory(moduleExclusionFilters, realAbsoluteFile, inputModuleHierarchy.root().getBaseDir(), module.getBaseDir(), type); + } + @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { return FileVisitResult.CONTINUE; |