From 83d32715552731f58b44d4ef2195bc3493e15bfb Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Mon, 11 Feb 2013 17:00:07 +0100 Subject: [PATCH] SONAR-1896 refactor file system components used during project analysis --- .../org/sonar/plugins/core/CorePlugin.java | 242 ++++++++++-------- .../filesystem/DefaultModuleFileSystem.java | 228 +++++++++++++++++ .../DeprecatedFileSystemAdapter.java | 148 +++++++++++ .../scan/filesystem/ExclusionFileFilter.java | 47 ++++ .../scan/filesystem/FileFilterContext.java | 63 +++++ .../scan/filesystem/InclusionFileFilter.java | 58 +++++ .../scan/filesystem/LanguageFileFilters.java | 42 +++ .../filesystem/ModuleFileSystemProvider.java | 166 ++++++++++++ .../batch/scan/filesystem/PathResolver.java | 74 ++++++ .../scan/filesystem/WhiteListFileFilter.java | 42 +++ .../batch/scan/filesystem/package-info.java | 27 ++ .../DefaultModuleFileSystemTest.java | 187 ++++++++++++++ .../filesystem/ExclusionFileFilterTest.java | 71 +++++ .../filesystem/InclusionFileFilterTest.java | 76 ++++++ .../filesystem/LanguageFileFiltersTest.java | 75 ++++++ .../ModuleFileSystemProviderTest.java | 51 ++++ .../scan/filesystem/PathResolverTest.java | 88 +++++++ .../filesystem/WhiteListFileFilterTest.java | 54 ++++ .../src/org/.dirPrefixedWithDot/Excluded.java | 1 + .../src/org/.sonar/Excluded2.java | 1 + .../src/org/sonar/Included.java | 3 + .../src/main/java/Foo.java | 1 + .../src/main/java/Hello.java | 1 + .../src/test/java/FooTest.java | 1 + .../src/test/java/HelloTest.java | 1 + .../java/org/sonar/api/CoreProperties.java | 2 + .../java/org/sonar/api/batch/FileFilter.java | 8 +- .../resources/DefaultProjectFileSystem.java | 2 +- .../filesystem/FailToCreateFileException.java | 32 +++ .../sonar/api/scan/filesystem/FileFilter.java | 44 ++++ .../scan/filesystem/FileSystemException.java | 36 +++ .../scan/filesystem/IllegalPathException.java | 37 +++ .../api/scan/filesystem/JavaIoFileFilter.java | 44 ++++ .../api/scan/filesystem/ModuleFileSystem.java | 44 ++++ .../api/scan/filesystem/package-info.java | 27 ++ 35 files changed, 1907 insertions(+), 117 deletions(-) create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapter.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ExclusionFileFilter.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterContext.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InclusionFileFilter.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageFileFilters.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProvider.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PathResolver.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/WhiteListFileFilter.java create mode 100644 sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/package-info.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystemTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFileFilterTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InclusionFileFilterTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageFileFiltersTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProviderTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PathResolverTest.java create mode 100644 sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/WhiteListFileFilterTest.java create mode 100644 sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/.dirPrefixedWithDot/Excluded.java create mode 100644 sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/.sonar/Excluded2.java create mode 100644 sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/sonar/Included.java create mode 100644 sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/main/java/Foo.java create mode 100644 sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/main/java/Hello.java create mode 100644 sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/test/java/FooTest.java create mode 100644 sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/test/java/HelloTest.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FailToCreateFileException.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileFilter.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileSystemException.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/IllegalPathException.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/JavaIoFileFilter.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/ModuleFileSystem.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/package-info.java diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 62a8807c33b..44dea680560 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -189,6 +189,22 @@ import java.util.List; multiValues = true, category = CoreProperties.CATEGORY_EXCLUSIONS, defaultValue = CoreProperties.GLOBAL_TEST_EXCLUSIONS_DEFAULT), + @Property( + key = CoreProperties.PROJECT_INCLUSIONS_PROPERTY, + name = "Inclusions", + description = "Define the file sources to analyze. Changes will be applied during next code analysis.", + project = true, + global = true, + multiValues = true, + category = CoreProperties.CATEGORY_EXCLUSIONS), + @Property( + key = CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, + name = "Test Inclusions", + description = "Define the test files to analyze. Changes will be applied during next code analysis.", + project = true, + global = true, + multiValues = true, + category = CoreProperties.CATEGORY_EXCLUSIONS), @Property( key = CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, name = "Exclusions", @@ -395,129 +411,129 @@ public final class CorePlugin extends SonarPlugin { @SuppressWarnings("unchecked") public List getExtensions() { return ImmutableList.of( - DefaultResourceTypes.class, - UserManagedMetrics.class, - ProjectFileSystemLogger.class, - Periods.class, + DefaultResourceTypes.class, + UserManagedMetrics.class, + ProjectFileSystemLogger.class, + Periods.class, - // maven - MavenInitializer.class, + // maven + MavenInitializer.class, - // languages - Java.class, + // languages + Java.class, - // pages - Lcom4Viewer.class, - TestsViewer.class, + // pages + Lcom4Viewer.class, + TestsViewer.class, - // measure filters - ProjectFilter.class, - MyFavouritesFilter.class, + // measure filters + ProjectFilter.class, + MyFavouritesFilter.class, - // widgets - AlertsWidget.class, - CoverageWidget.class, - ItCoverageWidget.class, - CommentsDuplicationsWidget.class, - DescriptionWidget.class, - ComplexityWidget.class, - RulesWidget.class, - SizeWidget.class, - EventsWidget.class, - CustomMeasuresWidget.class, - TimelineWidget.class, - TimeMachineWidget.class, - HotspotMetricWidget.class, - HotspotMostViolatedResourcesWidget.class, - HotspotMostViolatedRulesWidget.class, - MyReviewsWidget.class, - ProjectReviewsWidget.class, - FalsePositiveReviewsWidget.class, - ReviewsPerDeveloperWidget.class, - PlannedReviewsWidget.class, - UnplannedReviewsWidget.class, - ActionPlansWidget.class, - ReviewsMetricsWidget.class, - TreemapWidget.class, - MeasureFilterListWidget.class, - MeasureFilterTreemapWidget.class, - WelcomeWidget.class, + // widgets + AlertsWidget.class, + CoverageWidget.class, + ItCoverageWidget.class, + CommentsDuplicationsWidget.class, + DescriptionWidget.class, + ComplexityWidget.class, + RulesWidget.class, + SizeWidget.class, + EventsWidget.class, + CustomMeasuresWidget.class, + TimelineWidget.class, + TimeMachineWidget.class, + HotspotMetricWidget.class, + HotspotMostViolatedResourcesWidget.class, + HotspotMostViolatedRulesWidget.class, + MyReviewsWidget.class, + ProjectReviewsWidget.class, + FalsePositiveReviewsWidget.class, + ReviewsPerDeveloperWidget.class, + PlannedReviewsWidget.class, + UnplannedReviewsWidget.class, + ActionPlansWidget.class, + ReviewsMetricsWidget.class, + TreemapWidget.class, + MeasureFilterListWidget.class, + MeasureFilterTreemapWidget.class, + WelcomeWidget.class, - // dashboards - ProjectDefaultDashboard.class, - ProjectHotspotDashboard.class, - ProjectReviewsDashboard.class, - ProjectTimeMachineDashboard.class, - GlobalDefaultDashboard.class, + // dashboards + ProjectDefaultDashboard.class, + ProjectHotspotDashboard.class, + ProjectReviewsDashboard.class, + ProjectTimeMachineDashboard.class, + GlobalDefaultDashboard.class, - // chart - XradarChart.class, - DistributionBarChart.class, - DistributionAreaChart.class, + // chart + XradarChart.class, + DistributionBarChart.class, + DistributionAreaChart.class, - // colorizers - JavaColorizerFormat.class, + // colorizers + JavaColorizerFormat.class, - // batch - ProfileSensor.class, - ProfileEventsSensor.class, - ProjectLinksSensor.class, - UnitTestDecorator.class, - VersionEventsSensor.class, - CheckAlertThresholds.class, - GenerateAlertEvents.class, - ViolationsDecorator.class, - WeightedViolationsDecorator.class, - ViolationsDensityDecorator.class, - LineCoverageDecorator.class, - CoverageDecorator.class, - BranchCoverageDecorator.class, - ItLineCoverageDecorator.class, - ItCoverageDecorator.class, - ItBranchCoverageDecorator.class, - OverallLineCoverageDecorator.class, - OverallCoverageDecorator.class, - OverallBranchCoverageDecorator.class, - ApplyProjectRolesDecorator.class, - ExcludedResourceFilter.class, - CommentDensityDecorator.class, - NoSonarFilter.class, - DirectoriesDecorator.class, - FilesDecorator.class, - ReviewNotifications.class, - ReviewWorkflowDecorator.class, - ReferenceAnalysis.class, - ManualMeasureDecorator.class, - ManualViolationInjector.class, - ViolationSeverityUpdater.class, - IndexProjectPostJob.class, - ReviewsMeasuresDecorator.class, + // batch + ProfileSensor.class, + ProfileEventsSensor.class, + ProjectLinksSensor.class, + UnitTestDecorator.class, + VersionEventsSensor.class, + CheckAlertThresholds.class, + GenerateAlertEvents.class, + ViolationsDecorator.class, + WeightedViolationsDecorator.class, + ViolationsDensityDecorator.class, + LineCoverageDecorator.class, + CoverageDecorator.class, + BranchCoverageDecorator.class, + ItLineCoverageDecorator.class, + ItCoverageDecorator.class, + ItBranchCoverageDecorator.class, + OverallLineCoverageDecorator.class, + OverallCoverageDecorator.class, + OverallBranchCoverageDecorator.class, + ApplyProjectRolesDecorator.class, + ExcludedResourceFilter.class, + CommentDensityDecorator.class, + NoSonarFilter.class, + DirectoriesDecorator.class, + FilesDecorator.class, + ReviewNotifications.class, + ReviewWorkflowDecorator.class, + ReferenceAnalysis.class, + ManualMeasureDecorator.class, + ManualViolationInjector.class, + ViolationSeverityUpdater.class, + IndexProjectPostJob.class, + ReviewsMeasuresDecorator.class, - // time machine - TendencyDecorator.class, - VariationDecorator.class, - ViolationTrackingDecorator.class, - ViolationPersisterDecorator.class, - NewViolationsDecorator.class, - TimeMachineConfigurationPersister.class, - NewCoverageFileAnalyzer.class, - NewItCoverageFileAnalyzer.class, - NewOverallCoverageFileAnalyzer.class, - NewCoverageAggregator.class, + // time machine + TendencyDecorator.class, + VariationDecorator.class, + ViolationTrackingDecorator.class, + ViolationPersisterDecorator.class, + NewViolationsDecorator.class, + TimeMachineConfigurationPersister.class, + NewCoverageFileAnalyzer.class, + NewItCoverageFileAnalyzer.class, + NewOverallCoverageFileAnalyzer.class, + NewCoverageAggregator.class, - // notifications - // Notify incoming violations on my favourite projects - NewViolationsOnMyFavouriteProject.class, - NotificationDispatcherMetadata.create("NewViolationsOnMyFavouriteProject") - .setProperty(NotificationDispatcherMetadata.GLOBAL_NOTIFICATION, "true"), - // Notify alerts on my favourite projects - AlertsOnMyFavouriteProject.class, - NotificationDispatcherMetadata.create("AlertsOnMyFavouriteProject") - .setProperty(NotificationDispatcherMetadata.GLOBAL_NOTIFICATION, "true"), - // Notify reviews changes - ChangesInReviewAssignedToMeOrCreatedByMe.class, - NotificationDispatcherMetadata.create("ChangesInReviewAssignedToMeOrCreatedByMe") - .setProperty(NotificationDispatcherMetadata.GLOBAL_NOTIFICATION, "true") - .setProperty(NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION, "true")); + // notifications + // Notify incoming violations on my favourite projects + NewViolationsOnMyFavouriteProject.class, + NotificationDispatcherMetadata.create("NewViolationsOnMyFavouriteProject") + .setProperty(NotificationDispatcherMetadata.GLOBAL_NOTIFICATION, "true"), + // Notify alerts on my favourite projects + AlertsOnMyFavouriteProject.class, + NotificationDispatcherMetadata.create("AlertsOnMyFavouriteProject") + .setProperty(NotificationDispatcherMetadata.GLOBAL_NOTIFICATION, "true"), + // Notify reviews changes + ChangesInReviewAssignedToMeOrCreatedByMe.class, + NotificationDispatcherMetadata.create("ChangesInReviewAssignedToMeOrCreatedByMe") + .setProperty(NotificationDispatcherMetadata.GLOBAL_NOTIFICATION, "true") + .setProperty(NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION, "true")); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java new file mode 100644 index 00000000000..10733249b6a --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystem.java @@ -0,0 +1,228 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.HiddenFileFilter; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.io.filefilter.TrueFileFilter; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.scan.filesystem.ModuleFileSystem; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * This class can't be immutable because of execution of maven plugins that can change the project structure (see MavenPluginHandler and sonar.phase) + * + * @since 3.5 + */ +public class DefaultModuleFileSystem implements ModuleFileSystem { + + private static final IOFileFilter DIR_FILTER = FileFilterUtils.and(HiddenFileFilter.VISIBLE, FileFilterUtils.notFileFilter(FileFilterUtils.prefixFileFilter("."))); + + private final Charset sourceCharset; + private File baseDir, workingDir; + private List sourceDirs, testDirs, binaryDirs; + private final PathResolver pathResolver; + private final List fileFilters; + private final LanguageFileFilters languageFileFilters; + + private DefaultModuleFileSystem(Builder builder) { + sourceCharset = builder.sourceCharset; + baseDir = builder.baseDir; + workingDir = builder.workingDir; + sourceDirs = ImmutableList.copyOf(builder.sourceDirs); + testDirs = ImmutableList.copyOf(builder.testDirs); + binaryDirs = ImmutableList.copyOf(builder.binaryDirs); + fileFilters = ImmutableList.copyOf(builder.fileFilters); + pathResolver = builder.pathResolver; + languageFileFilters = builder.languageFileFilters; + } + + public File baseDir() { + return baseDir; + } + + public List sourceDirs() { + return sourceDirs; + } + + public List sourceFiles() { + return files(sourceDirs, FileFilter.FileType.SOURCE, TrueFileFilter.TRUE); + } + + public List sourceFilesOfLang(String language) { + return files(sourceDirs, FileFilter.FileType.SOURCE, languageFileFilters.forLang(language)); + } + + public List testDirs() { + return testDirs; + } + + public List testFiles() { + return files(testDirs, FileFilter.FileType.TEST, TrueFileFilter.TRUE); + } + + public List testFilesOfLang(String language) { + return files(testDirs, FileFilter.FileType.TEST, languageFileFilters.forLang(language)); + } + + public List binaryDirs() { + return binaryDirs; + } + + public Charset sourceCharset() { + return sourceCharset; + } + + public File workingDir() { + return workingDir; + } + + PathResolver pathResolver() { + return pathResolver; + } + + List fileFilters() { + return fileFilters; + } + + LanguageFileFilters languageFileFilters() { + return languageFileFilters; + } + + /** + * Breaks immutability but it's required to allow Maven Plugins to be executed and to change project structure. + */ + public void resetDirs(File basedir, File workDir, List sourceDirs, List testDirs, List binaryDirs) { + this.baseDir = basedir; + this.workingDir = workDir; + this.sourceDirs = ImmutableList.copyOf(sourceDirs); + this.testDirs = ImmutableList.copyOf(testDirs); + this.binaryDirs = ImmutableList.copyOf(binaryDirs); + } + + private List files(List dirs, FileFilter.FileType fileType, IOFileFilter languageFilter) { + List result = Lists.newLinkedList(); + if (dirs != null && !dirs.isEmpty()) { + FileFilterContext context = new FileFilterContext(this, fileType); + for (File dir : dirs) { + if (dir.exists()) { + context.setSourceDir(dir); + Collection files = FileUtils.listFiles(dir, FileFilterUtils.and(HiddenFileFilter.VISIBLE, languageFilter), DIR_FILTER); + applyFilters(files, context); + result.addAll(files); + } + } + } + return result; + } + + private void applyFilters(Collection files, FileFilterContext context) { + if (!fileFilters.isEmpty()) { + Iterator it = files.iterator(); + while (it.hasNext()) { + File file = it.next(); + if (!accept(file, context)) { + it.remove(); + } + } + } + } + + private boolean accept(File file, FileFilterContext context) { + context.setFileRelativePath(pathResolver.relativePath(context.sourceDir(), file)); + for (FileFilter fileFilter : fileFilters) { + if (!fileFilter.accept(file, context)) { + return false; + } + } + return true; + } + + static final class Builder { + private Charset sourceCharset; + private File baseDir, workingDir; + private List sourceDirs = Lists.newArrayList(), testDirs = Lists.newArrayList(), binaryDirs = Lists.newArrayList(); + private List fileFilters = Lists.newArrayList(); + private PathResolver pathResolver; + LanguageFileFilters languageFileFilters; + + Builder sourceCharset(Charset c) { + this.sourceCharset = c; + return this; + } + + Builder baseDir(File f) { + this.baseDir = f; + return this; + } + + Builder workingDir(File f) { + this.workingDir = f; + return this; + } + + Builder addSourceDir(File d) { + sourceDirs.add(d); + return this; + } + + Builder addTestDir(File d) { + testDirs.add(d); + return this; + } + + Builder addBinaryDir(File d) { + binaryDirs.add(d); + return this; + } + + Builder addFileFilter(FileFilter f) { + fileFilters.add(f); + return this; + } + + Builder pathResolver(PathResolver r) { + pathResolver = r; + return this; + } + + Builder languageFileFilters(LanguageFileFilters l) { + languageFileFilters = l; + return this; + } + + DefaultModuleFileSystem build() { + Preconditions.checkNotNull(baseDir, "Module base directory is not set"); + Preconditions.checkNotNull(workingDir, "Module working directory is not set"); + Preconditions.checkNotNull(sourceCharset, "Module source charset is not set"); + return new DefaultModuleFileSystem(this); + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapter.java new file mode 100644 index 00000000000..a0a8120951b --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DeprecatedFileSystemAdapter.java @@ -0,0 +1,148 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.CharEncoding; +import org.sonar.api.resources.InputFile; +import org.sonar.api.resources.Java; +import org.sonar.api.resources.Language; +import org.sonar.api.resources.ProjectFileSystem; +import org.sonar.api.resources.Resource; +import org.sonar.api.scan.filesystem.ModuleFileSystem; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; + +public class DeprecatedFileSystemAdapter implements ProjectFileSystem { + + private final ModuleFileSystem target; + private final PathResolver pathResolver; + + public DeprecatedFileSystemAdapter(ModuleFileSystem target, PathResolver pathResolver) { + this.target = target; + this.pathResolver = pathResolver; + } + + public Charset getSourceCharset() { + return target.sourceCharset(); + } + + public File getBasedir() { + return target.baseDir(); + } + + public File getBuildDir() { + // TODO + return null; + } + + public File getBuildOutputDir() { + return Iterables.getFirst(target.binaryDirs(), null); + } + + public List getSourceDirs() { + return target.sourceDirs(); + } + + public ProjectFileSystem addSourceDir(File dir) { + throw new UnsupportedOperationException("File system is immutable"); + } + + public List getTestDirs() { + return target.testDirs(); + } + + public ProjectFileSystem addTestDir(File dir) { + throw new UnsupportedOperationException("File system is immutable"); + } + + public File getReportOutputDir() { + // TODO + return null; + } + + public File getSonarWorkingDirectory() { + return target.workingDir(); + } + + public File resolvePath(String path) { + // TODO + return null; + } + + public List getSourceFiles(Language... langs) { + List result = Lists.newArrayList(); + for (Language lang : langs) { + result.addAll(target.sourceFilesOfLang(lang.getKey())); + } + return result; + } + + public List getJavaSourceFiles() { + return getSourceFiles(Java.INSTANCE); + } + + public boolean hasJavaSourceFiles() { + return !getJavaSourceFiles().isEmpty(); + } + + public List getTestFiles(Language... langs) { + List result = Lists.newArrayList(); + for (Language lang : langs) { + result.addAll(target.testFilesOfLang(lang.getKey())); + } + return result; + } + + public boolean hasTestFiles(Language lang) { + return !getTestFiles(lang).isEmpty(); + } + + public File writeToWorkingDirectory(String content, String fileName) throws IOException { + File file = new File(target.workingDir(), fileName); + FileUtils.writeStringToFile(file, content, CharEncoding.UTF_8); + return file; + } + + public File getFileFromBuildDirectory(String filename) { + File file = new File(getBuildDir(), filename); + return (file.exists() ? file : null); + } + + public Resource toResource(File file) { + // TODO + return null; + } + + public List mainFiles(String... langs) { + // TODO + return null; + } + + public List testFiles(String... langs) { + // TODO + return null; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ExclusionFileFilter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ExclusionFileFilter.java new file mode 100644 index 00000000000..8f1847e7af1 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ExclusionFileFilter.java @@ -0,0 +1,47 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.utils.WildcardPattern; + +import java.io.File; + +/** + * @since 3.5 + */ +class ExclusionFileFilter implements FileFilter { + private final FileType fileType; + private final WildcardPattern pattern; + + ExclusionFileFilter(FileType fileType, String pattern) { + this.fileType = fileType; + this.pattern = WildcardPattern.create(StringUtils.trim(pattern)); + } + + public boolean accept(File file, Context context) { + return !fileType.equals(context.fileType()) || !pattern.match(context.fileRelativePath()); + } + + WildcardPattern pattern() { + return pattern; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterContext.java new file mode 100644 index 00000000000..937eb6e0421 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileFilterContext.java @@ -0,0 +1,63 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.sonar.api.batch.FileFilter; +import org.sonar.api.scan.filesystem.ModuleFileSystem; + +import java.io.File; + +class FileFilterContext implements FileFilter.Context { + private final ModuleFileSystem fileSystem; + private final FileFilter.FileType fileType; + private File sourceDir; + private String fileRelativePath; + + FileFilterContext(ModuleFileSystem fileSystem, FileFilter.FileType fileType) { + this.fileSystem = fileSystem; + this.fileType = fileType; + } + + public ModuleFileSystem fileSystem() { + return fileSystem; + } + + public FileFilter.FileType fileType() { + return fileType; + } + + public File sourceDir() { + return sourceDir; + } + + public String fileRelativePath() { + return fileRelativePath; + } + + FileFilterContext setSourceDir(File sourceDir) { + this.sourceDir = sourceDir; + return this; + } + + FileFilterContext setFileRelativePath(String fileRelativePath) { + this.fileRelativePath = fileRelativePath; + return this; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InclusionFileFilter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InclusionFileFilter.java new file mode 100644 index 00000000000..6220b6451d8 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InclusionFileFilter.java @@ -0,0 +1,58 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.utils.WildcardPattern; + +import javax.annotation.CheckForNull; + +import java.io.File; + +/** + * @since 3.5 + */ +class InclusionFileFilter implements FileFilter { + private final FileType fileType; + private final WildcardPattern pattern; + + private InclusionFileFilter(FileType fileType, String pattern) { + this.fileType = fileType; + this.pattern = WildcardPattern.create(pattern); + } + + public boolean accept(File file, Context context) { + return !fileType.equals(context.fileType()) || pattern.match(context.fileRelativePath()); + } + + @CheckForNull + static InclusionFileFilter create(FileType fileType, String pattern) { + String trimmedPattern = StringUtils.trim(pattern); + if (!"".equals(trimmedPattern) && !"**/*".equals(trimmedPattern)) { + return new InclusionFileFilter(fileType, trimmedPattern); + } + return null; + } + + WildcardPattern pattern() { + return pattern; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageFileFilters.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageFileFilters.java new file mode 100644 index 00000000000..f5cc8aacfa7 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/LanguageFileFilters.java @@ -0,0 +1,42 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.apache.commons.io.IOCase; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.io.filefilter.SuffixFileFilter; +import org.apache.commons.io.filefilter.TrueFileFilter; +import org.sonar.api.resources.Languages; + +public class LanguageFileFilters { + private final Languages languages; + + public LanguageFileFilters(Languages languages) { + this.languages = languages; + } + + public IOFileFilter forLang(String lang) { + String[] suffixes = languages.getSuffixes(lang); + if (suffixes != null && suffixes.length>0) { + return new SuffixFileFilter(suffixes, IOCase.SENSITIVE); + } + return TrueFileFilter.TRUE; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProvider.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProvider.java new file mode 100644 index 00000000000..4af31fc29be --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProvider.java @@ -0,0 +1,166 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import com.google.common.collect.ImmutableSet; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import org.picocontainer.injectors.ProviderAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.CoreProperties; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.config.Settings; +import org.sonar.api.scan.filesystem.FailToCreateFileException; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.scan.filesystem.ModuleFileSystem; +import org.sonar.batch.bootstrap.TempDirectories; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Locale; + +/** + * @since 3.5 + */ +public class ModuleFileSystemProvider extends ProviderAdapter { + private static final Logger LOG = LoggerFactory.getLogger(ModuleFileSystemProvider.class); + + private ModuleFileSystem singleton; + + public ModuleFileSystem provide(ProjectDefinition module, PathResolver pathResolver, TempDirectories tempDirectories, + LanguageFileFilters languageFileFilters, Settings settings, FileFilter[] pluginFileFilters) { + if (singleton == null) { + DefaultModuleFileSystem.Builder builder = new DefaultModuleFileSystem.Builder(); + + // dependencies + builder.pathResolver(pathResolver); + builder.languageFileFilters(languageFileFilters); + + // files and directories + // TODO should the basedir always exist ? If yes, then we check also check that it's a dir but not a file + builder.baseDir(module.getBaseDir()); + builder.sourceCharset(guessCharset(settings)); + builder.workingDir(guessWorkingDir(module, tempDirectories)); + initBinaryDirs(module, pathResolver, builder); + initSources(module, pathResolver, builder); + initTests(module, pathResolver, builder); + + // file filters + initPluginFilters(builder, pluginFileFilters); + initSourceInclusions(builder, settings); + initTestInclusions(builder, settings); + + singleton = builder.build(); + } + return singleton; + } + + private File guessWorkingDir(ProjectDefinition module, TempDirectories tempDirectories) { + File workDir = module.getWorkDir(); + if (workDir == null) { + workDir = tempDirectories.getDir("work"); + LOG.warn("Working dir is not set. Using: " + workDir.getAbsolutePath()); + } else { + LOG.warn("Working dir: " + workDir.getAbsolutePath()); + try { + FileUtils.forceMkdir(workDir); + } catch (Exception e) { + throw new FailToCreateFileException("Fail to create working dir: " + workDir.getAbsolutePath(), e); + } + } + return workDir; + } + + private Charset guessCharset(Settings settings) { + final Charset charset; + String encoding = settings.getString(CoreProperties.ENCODING_PROPERTY); + if (StringUtils.isNotEmpty(encoding)) { + charset = Charset.forName(StringUtils.trim(encoding)); + LOG.info("Source encoding: " + charset.displayName() + ", default locale: " + Locale.getDefault()); + } else { + charset = Charset.defaultCharset(); + LOG.warn("Source encoding is platform dependent (" + charset.displayName() + "), default locale: " + Locale.getDefault()); + } + return charset; + } + + private void initSources(ProjectDefinition module, PathResolver pathResolver, DefaultModuleFileSystem.Builder builder) { + for (String sourcePath : module.getSourceDirs()) { + builder.addSourceDir(pathResolver.relativeFile(module.getBaseDir(), sourcePath)); + } + List sourceFiles = pathResolver.relativeFiles(module.getBaseDir(), module.getSourceFiles()); + if (!sourceFiles.isEmpty()) { + builder.addFileFilter(new WhiteListFileFilter(FileFilter.FileType.SOURCE, ImmutableSet.copyOf(sourceFiles))); + } + } + + private void initTests(ProjectDefinition module, PathResolver pathResolver, DefaultModuleFileSystem.Builder builder) { + for (String testPath : module.getTestDirs()) { + builder.addTestDir(pathResolver.relativeFile(module.getBaseDir(), testPath)); + } + List testFiles = pathResolver.relativeFiles(module.getBaseDir(), module.getTestFiles()); + if (!testFiles.isEmpty()) { + builder.addFileFilter(new WhiteListFileFilter(FileFilter.FileType.TEST, ImmutableSet.copyOf(testFiles))); + } + } + + private void initPluginFilters(DefaultModuleFileSystem.Builder builder, FileFilter[] pluginFileFilters) { + for (FileFilter pluginFileFilter : pluginFileFilters) { + builder.addFileFilter(pluginFileFilter); + } + } + + private void initSourceInclusions(DefaultModuleFileSystem.Builder builder, Settings settings) { + initInclusions(builder, settings, FileFilter.FileType.SOURCE, + CoreProperties.PROJECT_INCLUSIONS_PROPERTY, CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_EXCLUSIONS_PROPERTY); + } + + private void initTestInclusions(DefaultModuleFileSystem.Builder builder, Settings settings) { + initInclusions(builder, settings, FileFilter.FileType.TEST, + CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY); + } + + private static void initInclusions(DefaultModuleFileSystem.Builder builder, Settings settings, FileFilter.FileType fileType, + String inclusionsProperty, String globalExclusionsProperty, String exclusionsProperty) { + String[] inclusions = settings.getStringArray(inclusionsProperty); + for (String inclusion : inclusions) { + InclusionFileFilter filter = InclusionFileFilter.create(fileType, inclusion); + if (filter != null) { + builder.addFileFilter(filter); + } + } + String[] globalExclusions = settings.getStringArray(globalExclusionsProperty); + for (String globalExclusion : globalExclusions) { + builder.addFileFilter(new ExclusionFileFilter(fileType, globalExclusion)); + } + String[] exclusions = settings.getStringArray(exclusionsProperty); + for (String exclusion : exclusions) { + builder.addFileFilter(new ExclusionFileFilter(fileType, exclusion)); + } + } + + private void initBinaryDirs(ProjectDefinition module, PathResolver pathResolver, DefaultModuleFileSystem.Builder builder) { + for (String path : module.getBinaries()) { + builder.addBinaryDir(pathResolver.relativeFile(module.getBaseDir(), path)); + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PathResolver.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PathResolver.java new file mode 100644 index 00000000000..357e5845f11 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/PathResolver.java @@ -0,0 +1,74 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import org.apache.commons.io.FilenameUtils; +import org.sonar.api.scan.filesystem.IllegalPathException; + +import java.io.File; +import java.util.List; + +/** + * @since 3.5 + */ +public class PathResolver { + + File relativeFile(File dir, String path) { + Preconditions.checkArgument(dir.isDirectory(), "Not a directory: " + dir.getAbsolutePath()); + File file = new File(path); + if (!file.isAbsolute()) { + try { + file = new File(dir, path).getCanonicalFile(); + } catch (Exception e) { + throw new IllegalPathException("Fail to resolve path '" + path + "' relative to: " + dir.getAbsolutePath()); + } + } + return file; + } + + List relativeFiles(File dir, List paths) { + List result = Lists.newArrayList(); + for (String path : paths) { + result.add(relativeFile(dir, path)); + } + return result; + } + + String relativePath(File dir, File file) { + List stack = Lists.newArrayList(); + String path = FilenameUtils.normalize(file.getAbsolutePath()); + File cursor = new File(path); + while (cursor != null) { + if (containsFile(dir, cursor)) { + return Joiner.on("/").join(stack); + } + stack.add(0, cursor.getName()); + cursor = cursor.getParentFile(); + } + return null; + } + + private boolean containsFile(File dir, File cursor) { + return FilenameUtils.equalsNormalizedOnSystem(dir.getAbsolutePath(), cursor.getAbsolutePath()); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/WhiteListFileFilter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/WhiteListFileFilter.java new file mode 100644 index 00000000000..1c8ffb3ca25 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/WhiteListFileFilter.java @@ -0,0 +1,42 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.sonar.api.scan.filesystem.FileFilter; + +import java.io.File; +import java.util.Set; + +/** + * @since 3.5 + */ +class WhiteListFileFilter implements FileFilter { + private final FileFilter.FileType fileType; + private final Set files; + + WhiteListFileFilter(FileType fileType, Set files) { + this.fileType = fileType; + this.files = files; + } + + public boolean accept(File file, Context context) { + return !context.fileType().equals(fileType) || files.contains(file); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/package-info.java new file mode 100644 index 00000000000..c1e6578d28f --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/package-info.java @@ -0,0 +1,27 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ + +/** + * This package is a part of bootstrap process, so we should take care about backward compatibility. + */ +@ParametersAreNonnullByDefault +package org.sonar.batch.scan.filesystem; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystemTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystemTest.java new file mode 100644 index 00000000000..605d6932ff4 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/DefaultModuleFileSystemTest.java @@ -0,0 +1,187 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.resources.AbstractLanguage; +import org.sonar.api.resources.Languages; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.scan.filesystem.JavaIoFileFilter; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class DefaultModuleFileSystemTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void test_builder() throws IOException { + File basedir = temp.newFolder("base"); + File workingDir = temp.newFolder("work"); + PathResolver pathResolver = mock(PathResolver.class); + LanguageFileFilters languageFileFilters = mock(LanguageFileFilters.class); + FileFilter fileFilter = mock(FileFilter.class); + + DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem.Builder() + .baseDir(basedir) + .workingDir(workingDir) + .addBinaryDir(new File(basedir, "target/classes")) + .addSourceDir(new File(basedir, "src/main/java")) + .addSourceDir(new File(basedir, "src/main/groovy")) + .addTestDir(new File(basedir, "src/test/java")) + .addFileFilter(fileFilter) + .sourceCharset(StandardCharsets.UTF_8) + .pathResolver(pathResolver) + .languageFileFilters(languageFileFilters) + .build(); + + assertThat(fileSystem).isNotNull(); + assertThat(fileSystem.baseDir().getCanonicalPath()).isEqualTo(basedir.getCanonicalPath()); + assertThat(fileSystem.workingDir().getCanonicalPath()).isEqualTo(workingDir.getCanonicalPath()); + assertThat(fileSystem.sourceDirs()).hasSize(2); + assertThat(fileSystem.testDirs()).hasSize(1); + assertThat(fileSystem.binaryDirs()).hasSize(1); + assertThat(fileSystem.sourceCharset().name()).isEqualTo("UTF-8"); + assertThat(fileSystem.pathResolver()).isSameAs(pathResolver); + assertThat(fileSystem.fileFilters()).containsOnly(fileFilter); + assertThat(fileSystem.languageFileFilters()).isSameAs(languageFileFilters); + } + + @Test + public void should_exclude_dirs_starting_with_dot() throws IOException { + File basedir = new File("test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot"); + DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem.Builder() + .baseDir(basedir) + .sourceCharset(StandardCharsets.UTF_8) + .workingDir(temp.newFolder()) + .addSourceDir(new File(basedir, "src")) + .build(); + + assertThat(fileSystem.sourceFiles()).hasSize(1); + assertThat(fileSystem.sourceFiles().get(0).getName()).isEqualTo("Included.java"); + } + + @Test + public void should_load_source_files_by_language() throws IOException { + File basedir = new File("test-resources/DefaultModuleFileSystemTest/main_and_test_files"); + DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem.Builder() + .baseDir(basedir) + .sourceCharset(StandardCharsets.UTF_8) + .workingDir(temp.newFolder()) + .addSourceDir(new File(basedir, "src/main/java")) + .addTestDir(new File(basedir, "src/test/java")) + .languageFileFilters(new LanguageFileFilters(new Languages(new Java(), new Php()))) + .build(); + + List files = fileSystem.sourceFilesOfLang("java"); + assertThat(files).hasSize(2); + for (File sourceFiles : files) { + assertThat(sourceFiles).exists().isFile(); + assertThat(sourceFiles.getName()).isIn("Hello.java", "Foo.java"); + } + assertThat(fileSystem.sourceFilesOfLang("php")).isEmpty(); + } + + @Test + public void should_load_test_files() throws IOException { + File basedir = new File("test-resources/DefaultModuleFileSystemTest/main_and_test_files"); + DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem.Builder() + .baseDir(basedir) + .sourceCharset(StandardCharsets.UTF_8) + .workingDir(temp.newFolder()) + .addSourceDir(new File(basedir, "src/main/java")) + .addTestDir(new File(basedir, "src/test/java")) + .build(); + + assertThat(fileSystem.testDirs()).hasSize(1); + assertThat(fileSystem.testFiles()).hasSize(2); + for (File testFile : fileSystem.testFiles()) { + assertThat(testFile).exists().isFile(); + assertThat(testFile.getName()).endsWith("Test.java"); + } + } + + @Test + public void should_load_test_files_by_language() throws IOException { + File basedir = new File("test-resources/DefaultModuleFileSystemTest/main_and_test_files"); + DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem.Builder() + .baseDir(basedir) + .sourceCharset(StandardCharsets.UTF_8) + .workingDir(temp.newFolder()) + .addSourceDir(new File(basedir, "src/main/java")) + .addTestDir(new File(basedir, "src/test/java")) + .languageFileFilters(new LanguageFileFilters(new Languages(new Java(), new Php()))) + .build(); + + List testFiles = fileSystem.testFilesOfLang("java"); + assertThat(testFiles).hasSize(2); + for (File testFile : testFiles) { + assertThat(testFile).exists().isFile(); + assertThat(testFile.getName()).endsWith("Test.java"); + } + assertThat(fileSystem.testFilesOfLang("php")).isEmpty(); + } + + @Test + public void should_apply_file_filters() throws IOException { + File basedir = new File("test-resources/DefaultModuleFileSystemTest/main_and_test_files"); + DefaultModuleFileSystem fileSystem = new DefaultModuleFileSystem.Builder() + .baseDir(basedir) + .sourceCharset(StandardCharsets.UTF_8) + .workingDir(temp.newFolder()) + .addSourceDir(new File(basedir, "src/main/java")) + .addFileFilter(JavaIoFileFilter.create(FileFilterUtils.nameFileFilter("Foo.java"))) + .pathResolver(new PathResolver()) + .build(); + + List files = fileSystem.sourceFiles(); + assertThat(files).hasSize(1); + assertThat(files.get(0).getName()).isEqualTo("Foo.java"); + } + + static class Php extends AbstractLanguage { + public Php() { + super("php"); + } + + public String[] getFileSuffixes() { + return new String[]{"php"}; + } + } + + static class Java extends AbstractLanguage { + public Java() { + super("java"); + } + + public String[] getFileSuffixes() { + return new String[]{"java", "jav"}; + } + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFileFilterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFileFilterTest.java new file mode 100644 index 00000000000..def69f5182b --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ExclusionFileFilterTest.java @@ -0,0 +1,71 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.scan.filesystem.ModuleFileSystem; + +import java.io.File; +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class ExclusionFileFilterTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void should_accept() throws IOException { + ExclusionFileFilter filter = new ExclusionFileFilter(FileFilter.FileType.SOURCE, "**/*Dao.java"); + File acceptedFile = temp.newFile("Foo.java"); + + FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.SOURCE); + context.setFileRelativePath("com/mycompany/Foo.java"); + assertThat(filter.accept(acceptedFile, context)).isTrue(); + + context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.TEST); + context.setFileRelativePath("com/mycompany/Foo.java"); + assertThat(filter.accept(acceptedFile, context)).isTrue(); + } + + @Test + public void should_exclude() throws IOException { + ExclusionFileFilter filter = new ExclusionFileFilter(FileFilter.FileType.SOURCE, "**/*Dao.java"); + File excludedFile = temp.newFile("FooDao.java"); + + FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.SOURCE); + context.setFileRelativePath("com/mycompany/FooDao.java"); + assertThat(filter.accept(excludedFile, context)).isFalse(); + + context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.TEST); + context.setFileRelativePath("com/mycompany/FooDao.java"); + assertThat(filter.accept(excludedFile, context)).isTrue(); + } + + @Test + public void should_trim_pattern() throws IOException { + ExclusionFileFilter filter = new ExclusionFileFilter(FileFilter.FileType.SOURCE, " **/*Dao.java "); + assertThat(filter.pattern().toString()).isEqualTo("**/*Dao.java"); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InclusionFileFilterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InclusionFileFilterTest.java new file mode 100644 index 00000000000..9bc1e729fbd --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InclusionFileFilterTest.java @@ -0,0 +1,76 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.scan.filesystem.ModuleFileSystem; + +import java.io.File; +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class InclusionFileFilterTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void should_accept() throws IOException { + InclusionFileFilter filter = InclusionFileFilter.create(FileFilter.FileType.SOURCE, "**/*Dao.java"); + File acceptedFile = temp.newFile("FooDao.java"); + + FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.SOURCE); + context.setFileRelativePath("com/mycompany/FooDao.java"); + assertThat(filter.accept(acceptedFile, context)).isTrue(); + + context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.TEST); + context.setFileRelativePath("com/mycompany/Foo.java"); + assertThat(filter.accept(acceptedFile, context)).isTrue(); + } + + @Test + public void should_exclude() throws IOException { + InclusionFileFilter filter = InclusionFileFilter.create(FileFilter.FileType.SOURCE, "**/*Dao.java"); + File excludedFile = temp.newFile("Foo.java"); + + FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.SOURCE); + context.setFileRelativePath("com/mycompany/Foo.java"); + assertThat(filter.accept(excludedFile, context)).isFalse(); + + context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.TEST); + context.setFileRelativePath("com/mycompany/Foo.java"); + assertThat(filter.accept(excludedFile, context)).isTrue(); + } + + @Test + public void should_trim_pattern() throws IOException { + InclusionFileFilter filter = InclusionFileFilter.create(FileFilter.FileType.SOURCE, " **/*Dao.java "); + assertThat(filter.pattern().toString()).isEqualTo("**/*Dao.java"); + } + + @Test + public void ignore_if_include_world() throws IOException { + assertThat(InclusionFileFilter.create(FileFilter.FileType.SOURCE, " **/* ")).isNull(); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageFileFiltersTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageFileFiltersTest.java new file mode 100644 index 00000000000..6cb5185b404 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/LanguageFileFiltersTest.java @@ -0,0 +1,75 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.io.filefilter.SuffixFileFilter; +import org.apache.commons.io.filefilter.TrueFileFilter; +import org.junit.Test; +import org.sonar.api.resources.AbstractLanguage; +import org.sonar.api.resources.Languages; + +import java.lang.reflect.Field; + +import static org.fest.assertions.Assertions.assertThat; + +public class LanguageFileFiltersTest { + @Test + public void forLang() throws Exception { + LanguageFileFilters filters = new LanguageFileFilters(new Languages(new Java(), new Php())); + + IOFileFilter filter = filters.forLang("php"); + assertThat(filter).isInstanceOf(SuffixFileFilter.class); + assertThat(suffixes((SuffixFileFilter) filter)).containsOnly("php"); + + filter = filters.forLang("java"); + assertThat(filter).isInstanceOf(SuffixFileFilter.class); + assertThat(suffixes((SuffixFileFilter) filter)).containsOnly("java", "jav"); + + assertThat(filters.forLang("unknown")).isSameAs(TrueFileFilter.TRUE); + } + + private String[] suffixes(SuffixFileFilter filter) throws Exception { + Field privateField = SuffixFileFilter.class.getDeclaredField("suffixes"); + privateField.setAccessible(true); + + return (String[]) privateField.get(filter); + } + + static class Php extends AbstractLanguage { + public Php() { + super("php"); + } + + public String[] getFileSuffixes() { + return new String[]{"php"}; + } + } + + static class Java extends AbstractLanguage { + public Java() { + super("java"); + } + + public String[] getFileSuffixes() { + return new String[]{"java", "jav"}; + } + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProviderTest.java new file mode 100644 index 00000000000..de91575bac2 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/ModuleFileSystemProviderTest.java @@ -0,0 +1,51 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.config.Settings; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.scan.filesystem.ModuleFileSystem; +import org.sonar.batch.bootstrap.TempDirectories; + +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class ModuleFileSystemProviderTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void test_provide() throws IOException { + ModuleFileSystemProvider provider = new ModuleFileSystemProvider(); + ProjectDefinition module = ProjectDefinition.create() + .setBaseDir(temp.newFolder()) + .setWorkDir(temp.newFolder()); + ModuleFileSystem fs = provider.provide(module, new PathResolver(), new TempDirectories(), mock(LanguageFileFilters.class), + new Settings(), new FileFilter[0]); + + assertThat(fs).isNotNull(); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PathResolverTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PathResolverTest.java new file mode 100644 index 00000000000..8515aa7a9f7 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/PathResolverTest.java @@ -0,0 +1,88 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import org.apache.commons.io.FilenameUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; + +public class PathResolverTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void get_file_by_relative_path() throws IOException { + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + File file = resolver.relativeFile(rootDir, "org/foo/Bar.java"); + assertThat(file.getName()).isEqualTo("Bar.java"); + assertThat(FilenameUtils.separatorsToUnix(file.getCanonicalPath())).endsWith("org/foo/Bar.java"); + assertThat(file.getParentFile().getParentFile().getParentFile().getCanonicalPath()).isEqualTo(rootDir.getCanonicalPath()); + } + + @Test + public void get_file_by_absolute_path() throws IOException { + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + File file = resolver.relativeFile(rootDir, new File(rootDir, "org/foo/Bar.java").getAbsolutePath()); + assertThat(file.getName()).isEqualTo("Bar.java"); + assertThat(FilenameUtils.separatorsToUnix(file.getCanonicalPath())).endsWith("org/foo/Bar.java"); + assertThat(file.getParentFile().getParentFile().getParentFile().getCanonicalPath()).isEqualTo(rootDir.getCanonicalPath()); + } + + @Test + public void get_files_by_relative_paths() throws IOException { + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + List files = resolver.relativeFiles(rootDir, Arrays.asList("org/foo/Bar.java", "org/hello/World.java")); + assertThat(files).hasSize(2); + for (File file : files) { + assertThat(file.getName()).endsWith(".java"); + assertThat(file.getParentFile().getParentFile().getParentFile().getCanonicalPath()).isEqualTo(rootDir.getCanonicalPath()); + } + } + + @Test + public void get_relative_path() throws IOException { + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + File org = new File(rootDir, "org"); + File hello = new File(org, "hello"); + File world = new File(hello, "World.java"); + + assertThat(resolver.relativePath(rootDir, world)).isEqualTo("org/hello/World.java"); + } + + @Test + public void null_relative_path_when_file_is_not_in_dir() throws IOException { + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + + assertThat(resolver.relativePath(rootDir, new File("Elsewhere.java"))).isNull(); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/WhiteListFileFilterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/WhiteListFileFilterTest.java new file mode 100644 index 00000000000..38c9e8215ab --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/WhiteListFileFilterTest.java @@ -0,0 +1,54 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.scan.filesystem; + +import com.google.common.collect.Sets; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.scan.filesystem.FileFilter; +import org.sonar.api.scan.filesystem.ModuleFileSystem; + +import java.io.File; +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class WhiteListFileFilterTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void should_accept() throws IOException { + WhiteListFileFilter filter = new WhiteListFileFilter(FileFilter.FileType.SOURCE, Sets.newHashSet( + new File("Foo.java"), + new File("Bar.java") + )); + + FileFilterContext context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.SOURCE); + assertThat(filter.accept(new File("Foo.java"), context)).isTrue(); + assertThat(filter.accept(new File("Other.java"), context)).isFalse(); + + context = new FileFilterContext(mock(ModuleFileSystem.class), FileFilter.FileType.TEST); + assertThat(filter.accept(new File("Foo.java"), context)).isTrue(); + assertThat(filter.accept(new File("Other.java"), context)).isTrue(); + } +} diff --git a/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/.dirPrefixedWithDot/Excluded.java b/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/.dirPrefixedWithDot/Excluded.java new file mode 100644 index 00000000000..9578920820c --- /dev/null +++ b/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/.dirPrefixedWithDot/Excluded.java @@ -0,0 +1 @@ +public class Excluded2 {} \ No newline at end of file diff --git a/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/.sonar/Excluded2.java b/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/.sonar/Excluded2.java new file mode 100644 index 00000000000..9578920820c --- /dev/null +++ b/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/.sonar/Excluded2.java @@ -0,0 +1 @@ +public class Excluded2 {} \ No newline at end of file diff --git a/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/sonar/Included.java b/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/sonar/Included.java new file mode 100644 index 00000000000..78e1aabbba7 --- /dev/null +++ b/sonar-batch/test-resources/DefaultModuleFileSystemTest/exclude_dir_starting_with_dot/src/org/sonar/Included.java @@ -0,0 +1,3 @@ +package org.sonar; + +public class Included {} \ No newline at end of file diff --git a/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/main/java/Foo.java b/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/main/java/Foo.java new file mode 100644 index 00000000000..f72abf33fa2 --- /dev/null +++ b/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/main/java/Foo.java @@ -0,0 +1 @@ +class Foo {} \ No newline at end of file diff --git a/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/main/java/Hello.java b/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/main/java/Hello.java new file mode 100644 index 00000000000..449be99af71 --- /dev/null +++ b/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/main/java/Hello.java @@ -0,0 +1 @@ +public class Hello {} \ No newline at end of file diff --git a/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/test/java/FooTest.java b/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/test/java/FooTest.java new file mode 100644 index 00000000000..31eebff6972 --- /dev/null +++ b/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/test/java/FooTest.java @@ -0,0 +1 @@ +class FooTest {} \ No newline at end of file diff --git a/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/test/java/HelloTest.java b/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/test/java/HelloTest.java new file mode 100644 index 00000000000..901b93a5cb4 --- /dev/null +++ b/sonar-batch/test-resources/DefaultModuleFileSystemTest/main_and_test_files/src/test/java/HelloTest.java @@ -0,0 +1 @@ +public class HelloTest {} \ No newline at end of file diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java index 2c785625f71..47027d2108c 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java @@ -108,11 +108,13 @@ public interface CoreProperties { String DYNAMIC_ANALYSIS_PROPERTY = "sonar.dynamicAnalysis"; /* Exclusions */ + String PROJECT_INCLUSIONS_PROPERTY = "sonar.inclusions"; String PROJECT_EXCLUSIONS_PROPERTY = "sonar.exclusions"; /** * @since 3.3 */ + String PROJECT_TEST_INCLUSIONS_PROPERTY = "sonar.test.inclusions"; String PROJECT_TEST_EXCLUSIONS_PROPERTY = "sonar.test.exclusions"; String GLOBAL_EXCLUSIONS_PROPERTY = "sonar.global.exclusions"; String GLOBAL_TEST_EXCLUSIONS_PROPERTY = "sonar.global.test.exclusions"; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/FileFilter.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/FileFilter.java index 4407c33e833..1041bcf5f40 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/FileFilter.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/FileFilter.java @@ -19,8 +19,10 @@ */ package org.sonar.api.batch; -import org.sonar.api.BatchExtension; - -public abstract class FileFilter implements java.io.FileFilter, BatchExtension { +import java.io.File; +public abstract class FileFilter implements java.io.FileFilter, org.sonar.api.scan.filesystem.FileFilter { + public final boolean accept(File file, org.sonar.api.scan.filesystem.FileFilter.Context context) { + return accept(file); + } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/DefaultProjectFileSystem.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/DefaultProjectFileSystem.java index 5bef696d85b..d5553615cd3 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/DefaultProjectFileSystem.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/DefaultProjectFileSystem.java @@ -220,7 +220,7 @@ public class DefaultProjectFileSystem implements ProjectFileSystem { IOFileFilter suffixFilter = getFileSuffixFilter(langs); WildcardPattern[] exclusionPatterns = WildcardPattern.create(patterns); - IOFileFilter initialFilesFilter = TrueFileFilter.INSTANCE; + IOFileFilter initialFilesFilter = TrueFileFilter.TRUE; if (initialFiles != null && !initialFiles.isEmpty()) { initialFilesFilter = new FileSelectionFilter(initialFiles); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FailToCreateFileException.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FailToCreateFileException.java new file mode 100644 index 00000000000..7bf68c6c386 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FailToCreateFileException.java @@ -0,0 +1,32 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.api.scan.filesystem; + +import com.google.common.annotations.Beta; + +/** + * @since 3.5 + */ +@Beta +public class FailToCreateFileException extends FileSystemException { + public FailToCreateFileException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileFilter.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileFilter.java new file mode 100644 index 00000000000..42b98c1fc0d --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileFilter.java @@ -0,0 +1,44 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.api.scan.filesystem; + +import com.google.common.annotations.Beta; +import org.sonar.api.BatchExtension; + +import java.io.File; + +/** + * @since 3.5 + */ +@Beta +public interface FileFilter extends BatchExtension { + enum FileType { + SOURCE, TEST + } + + static interface Context { + ModuleFileSystem fileSystem(); + FileType fileType(); + File sourceDir(); + String fileRelativePath(); + } + + boolean accept(File file, Context context); +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileSystemException.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileSystemException.java new file mode 100644 index 00000000000..fec731b1a8b --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileSystemException.java @@ -0,0 +1,36 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.api.scan.filesystem; + +import com.google.common.annotations.Beta; + +/** + * @since 3.5 + */ +@Beta +public class FileSystemException extends RuntimeException { + public FileSystemException(String message) { + super(message); + } + + public FileSystemException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/IllegalPathException.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/IllegalPathException.java new file mode 100644 index 00000000000..04bd23f10bd --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/IllegalPathException.java @@ -0,0 +1,37 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.api.scan.filesystem; + +import com.google.common.annotations.Beta; + +/** + * @since 3.5 + */ +@Beta +public class IllegalPathException extends FileSystemException { + + public IllegalPathException(String message) { + super(message); + } + + public IllegalPathException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/JavaIoFileFilter.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/JavaIoFileFilter.java new file mode 100644 index 00000000000..d2467300e7e --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/JavaIoFileFilter.java @@ -0,0 +1,44 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.api.scan.filesystem; + +import com.google.common.annotations.Beta; + +import java.io.File; + +/** + * @since 3.5 + */ +@Beta +public class JavaIoFileFilter implements FileFilter { + private java.io.FileFilter ioFilter; + + private JavaIoFileFilter(java.io.FileFilter ioFilter) { + this.ioFilter = ioFilter; + } + + public static JavaIoFileFilter create(java.io.FileFilter filter) { + return new JavaIoFileFilter(filter); + } + + public boolean accept(File file, Context context) { + return ioFilter.accept(file); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/ModuleFileSystem.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/ModuleFileSystem.java new file mode 100644 index 00000000000..49031608d5e --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/ModuleFileSystem.java @@ -0,0 +1,44 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.api.scan.filesystem; + +import com.google.common.annotations.Beta; +import org.sonar.api.BatchComponent; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.List; + +/** + * @since 3.5 + */ +@Beta +public interface ModuleFileSystem extends BatchComponent { + File baseDir(); + List sourceDirs(); + List sourceFiles(); + List sourceFilesOfLang(String language); + List testDirs(); + List testFiles(); + List testFilesOfLang(String language); + List binaryDirs(); + Charset sourceCharset(); + File workingDir(); +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/package-info.java new file mode 100644 index 00000000000..891134cca1f --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/package-info.java @@ -0,0 +1,27 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ + +/** + * This package is a part of bootstrap process, so we should take care about backward compatibility. + */ +@ParametersAreNonnullByDefault +package org.sonar.api.scan.filesystem; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file -- 2.39.5