From 904367457dc4707c2e0e44032eb6e4cc56519bc8 Mon Sep 17 00:00:00 2001 From: Romain Manni-Bucau Date: Wed, 10 Jun 2020 11:00:15 +0200 Subject: [PATCH 1/2] rework directory scanner to ensure it can enforce exclusions and it uses Path --- .../shared/utils/io/DirectoryScanner.java | 455 ++++++++---------- .../maven/shared/utils/io/MatchPattern.java | 2 - .../maven/shared/utils/io/MatchPatterns.java | 2 - .../maven/shared/utils/io/ScanConductor.java | 2 - .../maven/shared/utils/io/ScannerAware.java | 29 ++ .../maven/shared/utils/io/SelectorUtils.java | 3 - .../EnforceExcludesOverIncludes.java | 58 +++ .../shared/utils/io/DirectoryScannerTest.java | 10 +- .../EnforceExcludesOverIncludesTest.java | 92 ++++ 9 files changed, 376 insertions(+), 277 deletions(-) create mode 100644 src/main/java/org/apache/maven/shared/utils/io/ScannerAware.java create mode 100644 src/main/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludes.java create mode 100644 src/test/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludesTest.java diff --git a/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanner.java b/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanner.java index 5d03525e..582336fa 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanner.java +++ b/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanner.java @@ -19,11 +19,19 @@ * under the License. */ +import org.apache.maven.shared.utils.io.conductor.EnforceExcludesOverIncludes; + import java.io.File; import java.io.IOException; +import java.nio.file.FileVisitOption; +import java.nio.file.FileVisitResult; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collections; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -31,6 +39,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; +import static java.nio.file.FileVisitOption.FOLLOW_LINKS; + /** * Class for scanning a directory for files/directories which match certain criteria. *

@@ -108,9 +118,7 @@ * @author Magesh Umasankar * @author Bruce Atherton * @author Antoine Levy-Lambert - * @deprecated use {@code java.nio.file.DirectoryStream} and related classes */ -@Deprecated public class DirectoryScanner { /** @@ -158,7 +166,7 @@ public class DirectoryScanner /** * The base directory to be scanned. */ - private File basedir; + private Path basedir; /** * The patterns for the files to be included. @@ -217,8 +225,6 @@ public class DirectoryScanner /** * Whether or not symbolic links should be followed. - * - * */ private boolean followSymlinks = true; @@ -228,11 +234,6 @@ public class DirectoryScanner */ private ScanConductor scanConductor = null; - /** - * The last ScanAction. We need to store this in the instance as the scan() method doesn't return - */ - private ScanConductor.ScanAction scanAction = null; - /** * Sole constructor. */ @@ -258,6 +259,16 @@ public void setBasedir( final String basedir ) * @param basedir The base directory for scanning. Should not be null. */ public void setBasedir( @Nonnull final File basedir ) + { + setBasedir( basedir.toPath() ); + } + + /** + * Sets the base directory to be scanned. This is the directory which is scanned recursively. + * + * @param basedir The base directory for scanning. Should not be null. + */ + public void setBasedir( @Nonnull final Path basedir ) { this.basedir = basedir; } @@ -269,7 +280,7 @@ public void setBasedir( @Nonnull final File basedir ) */ public File getBasedir() { - return basedir; + return basedir.toFile(); } /** @@ -362,6 +373,15 @@ public void setScanConductor( final ScanConductor scanConductor ) this.scanConductor = scanConductor; } + /** + * Set {@link EnforceExcludesOverIncludes} scan conductor for a faster scanning + * and generally no functional side effect. + */ + public void setEnforceExcludesOverIncludes() + { + setScanConductor( new EnforceExcludesOverIncludes() ); + } + /** * Scans the base directory for files which match at least one include pattern and don't match any exclude patterns. * If there are selectors then the files must pass muster there, as well. @@ -376,11 +396,11 @@ public void scan() { throw new IllegalStateException( "No basedir set" ); } - if ( !basedir.exists() ) + if ( !Files.exists( basedir ) ) { throw new IllegalStateException( "basedir " + basedir + " does not exist" ); } - if ( !basedir.isDirectory() ) + if ( !Files.isDirectory( basedir ) ) { throw new IllegalStateException( "basedir " + basedir + " is not a directory" ); } @@ -388,42 +408,164 @@ public void scan() setupDefaultFilters(); setupMatchPatterns(); - filesIncluded = new ArrayList(); - filesNotIncluded = new ArrayList(); - filesExcluded = new ArrayList(); - dirsIncluded = new ArrayList(); - dirsNotIncluded = new ArrayList(); - dirsExcluded = new ArrayList(); - scanAction = ScanConductor.ScanAction.CONTINUE; + if ( scanConductor instanceof ScannerAware ) // after the init + { + ( ( ScannerAware ) scanConductor ).setDirectoryScanner( this ); + } + + filesIncluded = new ArrayList<>(); + filesNotIncluded = new ArrayList<>(); + filesExcluded = new ArrayList<>(); + dirsIncluded = new ArrayList<>(); + dirsNotIncluded = new ArrayList<>(); + dirsExcluded = new ArrayList<>(); + + doScan( basedir, followSymlinks ? EnumSet.of( FOLLOW_LINKS ) : EnumSet.noneOf( FileVisitOption.class ), true ); + } - if ( isIncluded( "" ) ) + private void doScan( final Path root, final Set options, final boolean fast ) + { + try { - if ( !isExcluded( "" ) ) + Files.walkFileTree( root, options, Integer.MAX_VALUE, new SimpleFileVisitor() { - if ( scanConductor != null ) + @Override + public FileVisitResult preVisitDirectory( final Path dir, final BasicFileAttributes attrs ) + throws IOException + { + final String name = root.relativize( dir ).toString(); + if ( isIncluded( name ) ) + { + if ( !isExcluded( name ) ) + { + if ( scanConductor != null ) + { + final ScanConductor.ScanAction scanAction = scanConductor.visitDirectory( + name, dir.toFile() ); + if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) + || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) + { + return FileVisitResult.SKIP_SIBLINGS; + } + if ( ScanConductor.ScanAction.NO_RECURSE.equals( scanAction ) ) + { + return FileVisitResult.SKIP_SUBTREE; + } + } + dirsIncluded.add( name ); + } + else + { + dirsExcluded.add( name ); + if ( fast && !couldHoldIncluded( name ) ) + { + return FileVisitResult.SKIP_SUBTREE; + } + if ( scanConductor != null ) + { + final FileVisitResult result = toVisitResult( dir, name ); + if ( result != null ) + { + return result; + } + } + // else continue to visit + } + } + else + { + if ( fast && couldHoldIncluded( name ) ) + { + if ( scanConductor != null ) + { + final FileVisitResult result = toVisitResult( dir, name ); + if ( result != null ) + { + return result; + } + } + dirsNotIncluded.add( name ); + } + else if ( !fast ) + { + final FileVisitResult result = toVisitResult( dir, name ); + if ( result != null ) + { + return result; + } + } + } + return super.preVisitDirectory( dir, attrs ); + } + + @Override + public FileVisitResult visitFile( final Path file, final BasicFileAttributes attrs ) throws IOException { - scanAction = scanConductor.visitDirectory( "", basedir ); + final String name = root.relativize( file ).toString(); + if ( !followSymlinks && Files.isSymbolicLink( file ) ) + { + final Path resolved = file.toRealPath( ); + if ( Files.isDirectory( resolved ) ) + { + dirsIncluded.add( name ); + return FileVisitResult.SKIP_SUBTREE; + } + } + if ( isIncluded( name ) ) + { + if ( !isExcluded( name ) ) + { + final ScanConductor.ScanAction scanAction; + if ( scanConductor != null ) + { + scanAction = scanConductor.visitFile( name, file.toFile() ); + } + else + { + scanAction = null; + } + + if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) + || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) + { + return FileVisitResult.SKIP_SIBLINGS; + } - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) - || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) - || ScanConductor.ScanAction.NO_RECURSE.equals( scanAction ) ) + filesIncluded.add( name ); + } + else + { + filesExcluded.add( name ); + } + } + else { - return; + filesNotIncluded.add( name ); } + return super.visitFile( file, attrs ); } + } ); + } + catch ( final IOException e ) + { + throw new IllegalStateException( e ); + } + } - dirsIncluded.add( "" ); - } - else - { - dirsExcluded.add( "" ); - } + private FileVisitResult toVisitResult( final Path dir, final String name ) + { + final ScanConductor.ScanAction scanAction = scanConductor.visitDirectory( + name, dir.toFile() ); + if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) + || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) + { + return FileVisitResult.SKIP_SIBLINGS; } - else + if ( ScanConductor.ScanAction.NO_RECURSE.equals( scanAction ) ) { - dirsNotIncluded.add( "" ); + return FileVisitResult.SKIP_SUBTREE; } - scandir( basedir, "", true ); + return null; } /** @@ -523,15 +665,18 @@ void slowScan() return; } - final String[] excl = dirsExcluded.toArray( new String[dirsExcluded.size()] ); + final String[] excl = dirsExcluded.toArray( new String[ 0 ] ); + + final String[] notIncl = dirsNotIncluded.toArray( new String[ 0 ] ); - final String[] notIncl = dirsNotIncluded.toArray( new String[dirsNotIncluded.size()] ); + final EnumSet opts = followSymlinks + ? EnumSet.of( FOLLOW_LINKS ) : EnumSet.noneOf( FileVisitOption.class ); for ( String anExcl : excl ) { if ( !couldHoldIncluded( anExcl ) ) { - scandir( new File( basedir, anExcl ), anExcl + File.separator, false ); + doScan( basedir.resolve( anExcl ), opts, false ); } } @@ -539,214 +684,13 @@ void slowScan() { if ( !couldHoldIncluded( aNotIncl ) ) { - scandir( new File( basedir, aNotIncl ), aNotIncl + File.separator, false ); + doScan( basedir.resolve( aNotIncl ), opts, false ); } } haveSlowResults = true; } - /** - * Scans the given directory for files and directories. Found files and directories are placed in their respective - * collections, based on the matching of includes, excludes, and the selectors. When a directory is found, it is - * scanned recursively. - * - * @param dir The directory to scan. Must not be null. - * @param vpath The path relative to the base directory (needed to prevent problems with an absolute path when using - * dir). Must not be null. - * @param fast Whether or not this call is part of a fast scan. - * @see #filesIncluded - * @see #filesNotIncluded - * @see #filesExcluded - * @see #dirsIncluded - * @see #dirsNotIncluded - * @see #dirsExcluded - * @see #slowScan - */ - void scandir( @Nonnull final File dir, @Nonnull final String vpath, final boolean fast ) - { - String[] newfiles = dir.list(); - - if ( newfiles == null ) - { - /* - * two reasons are mentioned in the API docs for File.list (1) dir is not a directory. This is impossible as - * we wouldn't get here in this case. (2) an IO error occurred (why doesn't it throw an exception then???) - */ - - /* - * [jdcasey] (2) is apparently happening to me, as this is killing one of my tests... this is affecting the - * assembly plugin, fwiw. I will initialize the newfiles array as zero-length for now. NOTE: I can't find - * the problematic code, as it appears to come from a native method in UnixFileSystem... - */ - newfiles = new String[0]; - - // throw new IOException( "IO error scanning directory " + dir.getAbsolutePath() ); - } - - if ( !followSymlinks ) - { - newfiles = doNotFollowSymbolicLinks( dir, vpath, newfiles ); - } - - for ( final String newfile : newfiles ) - { - final String name = vpath + newfile; - final File file = new File( dir, newfile ); - if ( file.isDirectory() ) - { - if ( isIncluded( name ) ) - { - if ( !isExcluded( name ) ) - { - if ( scanConductor != null ) - { - scanAction = scanConductor.visitDirectory( name, file ); - - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) - || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) - { - return; - } - } - - if ( !ScanConductor.ScanAction.NO_RECURSE.equals( scanAction ) ) - { - dirsIncluded.add( name ); - if ( fast ) - { - scandir( file, name + File.separator, fast ); - - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) ) - { - return; - } - } - } - scanAction = null; - - } - else - { - dirsExcluded.add( name ); - if ( fast && couldHoldIncluded( name ) ) - { - scandir( file, name + File.separator, fast ); - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) ) - { - return; - } - scanAction = null; - } - } - } - else - { - if ( fast && couldHoldIncluded( name ) ) - { - if ( scanConductor != null ) - { - scanAction = scanConductor.visitDirectory( name, file ); - - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) - || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) - { - return; - } - } - if ( !ScanConductor.ScanAction.NO_RECURSE.equals( scanAction ) ) - { - dirsNotIncluded.add( name ); - - scandir( file, name + File.separator, fast ); - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) ) - { - return; - } - } - scanAction = null; - } - } - if ( !fast ) - { - scandir( file, name + File.separator, fast ); - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) ) - { - return; - } - scanAction = null; - } - } - else if ( file.isFile() ) - { - if ( isIncluded( name ) ) - { - if ( !isExcluded( name ) ) - { - if ( scanConductor != null ) - { - scanAction = scanConductor.visitFile( name, file ); - } - - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) - || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) - { - return; - } - - filesIncluded.add( name ); - } - else - { - filesExcluded.add( name ); - } - } - else - { - filesNotIncluded.add( name ); - } - } - } - } - - private String[] doNotFollowSymbolicLinks( final File dir, final String vpath, String[] newfiles ) - { - final List noLinks = new ArrayList(); - for ( final String newfile : newfiles ) - { - try - { - if ( isSymbolicLink( dir, newfile ) ) - { - final String name = vpath + newfile; - final File file = new File( dir, newfile ); - if ( file.isDirectory() ) - { - dirsExcluded.add( name ); - } - else - { - filesExcluded.add( name ); - } - } - else - { - noLinks.add( newfile ); - } - } - catch ( final IOException ioe ) - { - final String msg = - "IOException caught while checking " + "for links, couldn't get cannonical path!"; - // will be caught and redirected to Ant's logging system - System.err.println( msg ); - noLinks.add( newfile ); - } - } - newfiles = noLinks.toArray( new String[noLinks.size()] ); - return newfiles; - } - /** * Tests whether or not a name matches against at least one include pattern. * @@ -787,18 +731,16 @@ boolean isExcluded( @Nonnull final String name ) * Returns the names of the files which matched at least one of the include patterns and none of the exclude * patterns. The names are relative to the base directory. * - * @deprecated this method does not work correctly on Windows. * @return the names of the files which matched at least one of the include patterns and none of the exclude * patterns. May also contain symbolic links to files. */ - @Deprecated public String[] getIncludedFiles() { if ( filesIncluded == null ) { return new String[0]; } - return filesIncluded.toArray( new String[filesIncluded.size()] ); + return filesIncluded.toArray( new String[0] ); } /** @@ -891,21 +833,16 @@ public void addDefaultExcludes() excludes = newExcludes; } - /** - * Checks whether a given file is a symbolic link. - *

- * It doesn't really test for symbolic links but whether the canonical and absolute paths of the file are identical - * - this may lead to false positives on some platforms. - *

- * - * @param parent the parent directory of the file to test - * @param name the name of the file to test. - * - */ - boolean isSymbolicLink( final File parent, final String name ) - throws IOException + public MatchPatterns getExcludesPatterns() + { + setupDefaultFilters(); + return excludesPatterns; + } + + public MatchPatterns getIncludesPatterns() { - return Files.isSymbolicLink( parent.toPath() ); + setupDefaultFilters(); + return includesPatterns; } private void setupDefaultFilters() diff --git a/src/main/java/org/apache/maven/shared/utils/io/MatchPattern.java b/src/main/java/org/apache/maven/shared/utils/io/MatchPattern.java index 8abff427..25b35a7b 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/MatchPattern.java +++ b/src/main/java/org/apache/maven/shared/utils/io/MatchPattern.java @@ -33,9 +33,7 @@ * Significantly more efficient than using strings, since re-evaluation and re-tokenizing is avoided. * * @author Kristian Rosenvold - * @deprecated use {@code java.nio.filejava.nio.file.DirectoryStream.Filter} and related classes */ -@Deprecated public class MatchPattern { private final String source; diff --git a/src/main/java/org/apache/maven/shared/utils/io/MatchPatterns.java b/src/main/java/org/apache/maven/shared/utils/io/MatchPatterns.java index 693acb1c..8e59f48f 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/MatchPatterns.java +++ b/src/main/java/org/apache/maven/shared/utils/io/MatchPatterns.java @@ -27,9 +27,7 @@ * A list of patterns to be matched * * @author Kristian Rosenvold - * @deprecated use {@code java.nio.filejava.nio.file.DirectoryStream.Filter} and related classes */ -@Deprecated public class MatchPatterns { private final MatchPattern[] patterns; diff --git a/src/main/java/org/apache/maven/shared/utils/io/ScanConductor.java b/src/main/java/org/apache/maven/shared/utils/io/ScanConductor.java index 08d7a1cd..20c9a10e 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/ScanConductor.java +++ b/src/main/java/org/apache/maven/shared/utils/io/ScanConductor.java @@ -34,9 +34,7 @@ * * @author Mark Struberg * - * @deprecated use {@code java.nio.file.Files.walkFileTree()} and related classes */ -@Deprecated public interface ScanConductor { /** diff --git a/src/main/java/org/apache/maven/shared/utils/io/ScannerAware.java b/src/main/java/org/apache/maven/shared/utils/io/ScannerAware.java new file mode 100644 index 00000000..82542039 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/io/ScannerAware.java @@ -0,0 +1,29 @@ +package org.apache.maven.shared.utils.io; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Enables a {@link ScanConductor} to access the {@link DirectoryScanner} configuration. + * It is set once the scanner is initialized. + */ +public interface ScannerAware +{ + void setDirectoryScanner( DirectoryScanner scanner ); +} diff --git a/src/main/java/org/apache/maven/shared/utils/io/SelectorUtils.java b/src/main/java/org/apache/maven/shared/utils/io/SelectorUtils.java index b716e7c8..8f920da2 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/SelectorUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/io/SelectorUtils.java @@ -38,10 +38,7 @@ * ajkuiper@wxs.nl * @author Magesh Umasankar * @author Bruce Atherton - * - * @deprecated use {@code java.nio.file.Files.walkFileTree()} and related classes */ -@Deprecated public final class SelectorUtils { diff --git a/src/main/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludes.java b/src/main/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludes.java new file mode 100644 index 00000000..47406bf4 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludes.java @@ -0,0 +1,58 @@ +package org.apache.maven.shared.utils.io.conductor; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.shared.utils.io.DirectoryScanner; +import org.apache.maven.shared.utils.io.MatchPatterns; +import org.apache.maven.shared.utils.io.ScanConductor; +import org.apache.maven.shared.utils.io.ScannerAware; + +import java.io.File; + +/** + * If an exclude is defined on a folder it will bypass the visit of the children + * even if some include can match children. + */ +public class EnforceExcludesOverIncludes implements ScanConductor, ScannerAware +{ + private MatchPatterns excludes; + + @Override + public ScanAction visitDirectory( final String name, final File directory ) + { + if ( excludes.matches( name, true ) ) + { + return ScanAction.NO_RECURSE; + } + return ScanAction.CONTINUE; + } + + @Override + public ScanAction visitFile( final String name, final File file ) + { + return ScanAction.CONTINUE; + } + + @Override + public void setDirectoryScanner( final DirectoryScanner scanner ) + { + excludes = scanner.getExcludesPatterns(); + } +} diff --git a/src/test/java/org/apache/maven/shared/utils/io/DirectoryScannerTest.java b/src/test/java/org/apache/maven/shared/utils/io/DirectoryScannerTest.java index 01110069..48956394 100644 --- a/src/test/java/org/apache/maven/shared/utils/io/DirectoryScannerTest.java +++ b/src/test/java/org/apache/maven/shared/utils/io/DirectoryScannerTest.java @@ -162,7 +162,7 @@ public void followSymlinksFalse() ds.scan(); List included = Arrays.asList( ds.getIncludedFiles() ); assertAlwaysIncluded( included ); - assertEquals( 9, included.size() ); + assertEquals( included.toString(), 9, included.size() ); List includedDirs = Arrays.asList( ds.getIncludedDirectories() ); assertTrue( includedDirs.contains( "" ) ); assertTrue( includedDirs.contains( "aRegularDir" ) ); @@ -243,14 +243,6 @@ public void testSimpleExcludes() /* expExclDirs */ NONE ); } - public void testIsSymbolicLink() - throws IOException - { - File file = new File( "." ); - DirectoryScanner ds = new DirectoryScanner(); - ds.isSymbolicLink( file, "abc" ); - } - /** * Performs a scan and test for the given parameters if not null. */ diff --git a/src/test/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludesTest.java b/src/test/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludesTest.java new file mode 100644 index 00000000..42259e55 --- /dev/null +++ b/src/test/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludesTest.java @@ -0,0 +1,92 @@ +package org.apache.maven.shared.utils.io.conductor; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.shared.utils.io.DirectoryScanner; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; + +public class EnforceExcludesOverIncludesTest +{ + @Rule + public final TemporaryFolder folder = new TemporaryFolder(); + + @Test + public void dontVisitChildren() throws IOException + { + createFakeFiles(); + + DirectoryScanner scanner = new DirectoryScanner(); + scanner.setScanConductor(new EnforceExcludesOverIncludes()); + scanner.setExcludes( "**/target/**" ); + scanner.setIncludes( "**" ); // files in target will match include but our conductor will bypass them anyway + scanner.setBasedir( folder.getRoot() ); + scanner.scan(); + assertResultEquals( asList( "bar", "sub/other" ), scanner.getIncludedFiles() ); + assertResultEquals( singletonList( "target" ), scanner.getExcludedDirectories() ); + } + + @Test // we don't set the conductor to ensure we have a "control" test to compare to the other + public void controlTest() throws IOException + { + createFakeFiles(); + + DirectoryScanner scanner = new DirectoryScanner(); + scanner.setExcludes( "**/target/**" ); + scanner.setIncludes( "**" ); // files in target will match include but our conductor will bypass them anyway + scanner.setBasedir( folder.getRoot() ); + scanner.scan(); + assertResultEquals( asList( "bar", "sub/other" ), scanner.getIncludedFiles() ); + assertResultEquals( asList( "target", "target/nested" ), scanner.getExcludedDirectories() ); + } + + private void createFakeFiles() throws IOException + { + touch(new File(folder.getRoot(), "bar")); + touch(new File(folder.getRoot(), "sub/other")); + touch(new File(folder.getRoot(), "target/foo")); + touch(new File(folder.getRoot(), "target/nested/dummy")); + } + + private void assertResultEquals( final List expected, final String[] actual ) + { + final List actualList = new ArrayList<>( asList( actual ) ); + Collections.sort( actualList ); + assertEquals( expected, actualList ); + } + + private void touch( final File file ) throws IOException + { + file.getParentFile().mkdirs(); + new FileWriter( file ).close(); + } +} From cfe9bf1df313d4e4cc0d74b96dcf0c397afcb092 Mon Sep 17 00:00:00 2001 From: Romain Manni-Bucau Date: Wed, 10 Jun 2020 17:31:32 +0200 Subject: [PATCH 2/2] comments --- .../shared/utils/io/conductor/EnforceExcludesOverIncludes.java | 2 +- .../utils/io/conductor/EnforceExcludesOverIncludesTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludes.java b/src/main/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludes.java index 47406bf4..98e44a00 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludes.java +++ b/src/main/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludes.java @@ -27,7 +27,7 @@ import java.io.File; /** - * If an exclude is defined on a folder it will bypass the visit of the children + * If an exclude is defined on a folder it does not visit of the children * even if some include can match children. */ public class EnforceExcludesOverIncludes implements ScanConductor, ScannerAware diff --git a/src/test/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludesTest.java b/src/test/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludesTest.java index 42259e55..9fe0d379 100644 --- a/src/test/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludesTest.java +++ b/src/test/java/org/apache/maven/shared/utils/io/conductor/EnforceExcludesOverIncludesTest.java @@ -87,6 +87,6 @@ private void assertResultEquals( final List expected, final String[] act private void touch( final File file ) throws IOException { file.getParentFile().mkdirs(); - new FileWriter( file ).close(); + file.createNewFile(); } }