From b5999a6f555ea36e64ce4b024a7327596cbd73f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Thu, 24 Nov 2022 07:49:27 +0100 Subject: [PATCH] Move Directory Scanner to Path API --- .../codehaus/plexus/util/AbstractScanner.java | 13 + .../plexus/util/DirectoryScanner.java | 319 ++++++++---------- .../org/codehaus/plexus/util/FileUtils.java | 118 +++---- .../org/codehaus/plexus/util/NioFiles.java | 145 -------- .../org/codehaus/plexus/util/Scanner.java | 52 +-- .../plexus/util/DirectoryScannerTest.java | 82 +++-- .../codehaus/plexus/util/FileUtilsTest.java | 5 +- 7 files changed, 301 insertions(+), 433 deletions(-) delete mode 100644 src/main/java/org/codehaus/plexus/util/NioFiles.java diff --git a/src/main/java/org/codehaus/plexus/util/AbstractScanner.java b/src/main/java/org/codehaus/plexus/util/AbstractScanner.java index 16d64ef9..078a4935 100644 --- a/src/main/java/org/codehaus/plexus/util/AbstractScanner.java +++ b/src/main/java/org/codehaus/plexus/util/AbstractScanner.java @@ -17,6 +17,7 @@ */ import java.io.File; +import java.nio.file.LinkOption; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -125,6 +126,8 @@ public abstract class AbstractScanner */ protected Comparator filenameComparator; + protected LinkOption[] options = new LinkOption[0]; + /** * Sets whether or not the file system should be regarded as case sensitive. * @@ -415,4 +418,14 @@ public void setFilenameComparator( Comparator filenameComparator ) { this.filenameComparator = filenameComparator; } + + @Override + public void setLinkOptions(LinkOption[] options) { + this.options = options; + } + + @Override + public LinkOption[] getLinkOptions() { + return options; + } } diff --git a/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java b/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java index 5db6a903..638eb5b1 100644 --- a/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java +++ b/src/main/java/org/codehaus/plexus/util/DirectoryScanner.java @@ -56,8 +56,19 @@ import java.io.File; import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** *

Class for scanning a directory for files/directories which match certain criteria.

@@ -140,7 +151,7 @@ public class DirectoryScanner /** * The base directory to be scanned. */ - protected File basedir; + protected Path basedir; /** * The files which matched at least one include and no excludes and were selected. @@ -217,7 +228,7 @@ public DirectoryScanner() */ public void setBasedir( String basedir ) { - setBasedir( new File( basedir.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ) ) ); + setBasedir(new File(basedir.replace('/', File.separatorChar).replace('\\', File.separatorChar)).toPath()); } /** @@ -225,7 +236,7 @@ public void setBasedir( String basedir ) * * @param basedir The base directory for scanning. Should not be null. */ - public void setBasedir( File basedir ) + public void setBasedir(Path basedir) { this.basedir = basedir; } @@ -236,7 +247,7 @@ public void setBasedir( File basedir ) * @return the base directory to be scanned */ @Override - public File getBasedir() + public Path getBasedir() { return basedir; } @@ -249,6 +260,13 @@ public File getBasedir() public void setFollowSymlinks( boolean followSymlinks ) { this.followSymlinks = followSymlinks; + HashSet newOptions = new HashSet<>(Arrays.asList(getLinkOptions())); + if (followSymlinks) { + newOptions.remove(LinkOption.NOFOLLOW_LINKS); + } else { + newOptions.add(LinkOption.NOFOLLOW_LINKS); + } + setLinkOptions(newOptions.toArray(new LinkOption[newOptions.size()])); } /** @@ -262,25 +280,28 @@ public boolean isEverythingIncluded() } /** - * 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. - * - * @throws IllegalStateException if the base directory was set incorrectly (i.e. if it is null, doesn't - * exist, or isn't a directory). - */ + * 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. + * + * @throws IllegalStateException if the base directory was set incorrectly (i.e. + * if it is null, doesn't exist, or + * isn't a directory). + * @throws IOException + */ @Override public void scan() - throws IllegalStateException + throws IllegalStateException, IOException { if ( basedir == null ) { throw new IllegalStateException( "No basedir set" ); } - if ( !basedir.exists() ) + if (!Files.exists(basedir, getLinkOptions())) { throw new IllegalStateException( "basedir " + basedir + " does not exist" ); } - if ( !basedir.isDirectory() ) + if (!Files.isDirectory(basedir, getLinkOptions())) { throw new IllegalStateException( "basedir " + basedir + " is not a directory" ); } @@ -324,13 +345,19 @@ public void scan() } /** - *

Top level invocation for a slow scan. A slow scan builds up a full list of excluded/included files/directories, - * whereas a fast scan will only have full results for included files, as it ignores directories which can't - * possibly hold any included files/directories.

- * - *

Returns immediately if a slow scan has already been completed.

- */ - protected void slowScan() + *

+ * Top level invocation for a slow scan. A slow scan builds up a full list of + * excluded/included files/directories, whereas a fast scan will only have full + * results for included files, as it ignores directories which can't possibly + * hold any included files/directories. + *

+ * + *

+ * Returns immediately if a slow scan has already been completed. + *

+ * + */ + protected void slowScan() { if ( haveSlowResults ) { @@ -344,7 +371,11 @@ protected void slowScan() { if ( !couldHoldIncluded( anExcl ) ) { - scandir( new File( basedir, anExcl ), anExcl + File.separator, false ); + try { + scandir(basedir.resolve(anExcl), anExcl + File.separator, false); + } catch (IOException e) { + // ignored + } } } @@ -352,7 +383,11 @@ protected void slowScan() { if ( !couldHoldIncluded( aNotIncl ) ) { - scandir( new File( basedir, aNotIncl ), aNotIncl + File.separator, false ); + try { + scandir(basedir.resolve(aNotIncl), aNotIncl + File.separator, false); + } catch (IOException e) { + // ignored + } } } @@ -376,150 +411,90 @@ protected void slowScan() * @see #dirsExcluded * @see #slowScan */ - protected void scandir( File dir, String vpath, boolean fast ) + protected void scandir(Path dir, String vpath, boolean fast) throws IOException { - 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... - */ - /* - * [bentmann] A null array will also be returned from list() on NTFS when dir refers to a soft link or - * junction point whose target is not existent. - */ - newfiles = EMPTY_STRING_ARRAY; - - // throw new IOException( "IO error scanning directory " + dir.getAbsolutePath() ); - } - - if ( !followSymlinks ) - { - try - { - if ( isParentSymbolicLink( dir, null ) ) - { - for ( String newfile : newfiles ) - { - String name = vpath + newfile; - File file = new File( dir, newfile ); - if ( file.isDirectory() ) - { - dirsExcluded.add( name ); - } - else - { - filesExcluded.add( name ); - } - } - return; - } - } - catch ( IOException ioe ) - { - String msg = "IOException caught while checking for links!"; - // will be caught and redirected to Ant's logging system - System.err.println( msg ); - } - } - - if ( filenameComparator != null ) - { - Arrays.sort( newfiles, filenameComparator ); - } - - for ( String newfile : newfiles ) - { - String name = vpath + newfile; - char[][] tokenizedName = MatchPattern.tokenizePathToCharArray( name, File.separator ); - File file = new File( dir, newfile ); - if ( file.isDirectory() ) - { - - if ( isIncluded( name, tokenizedName ) ) - { - if ( !isExcluded( name, tokenizedName ) ) - { - if ( isSelected( name, file ) ) - { - dirsIncluded.add( name ); - if ( fast ) - { - scandir( file, name + File.separator, fast ); - } - } - else - { - everythingIncluded = false; - dirsDeselected.add( name ); - if ( fast && couldHoldIncluded( name ) ) - { - scandir( file, name + File.separator, fast ); - } - } - - } - else - { - everythingIncluded = false; - dirsExcluded.add( name ); - if ( fast && couldHoldIncluded( name ) ) - { - scandir( file, name + File.separator, fast ); - } - } - } - else - { - everythingIncluded = false; - dirsNotIncluded.add( name ); - if ( fast && couldHoldIncluded( name ) ) - { - scandir( file, name + File.separator, fast ); - } - } - if ( !fast ) - { - scandir( file, name + File.separator, fast ); - } - } - else if ( file.isFile() ) - { - if ( isIncluded( name, tokenizedName ) ) - { - if ( !isExcluded( name, tokenizedName ) ) - { - if ( isSelected( name, file ) ) - { - filesIncluded.add( name ); - } - else - { - everythingIncluded = false; - filesDeselected.add( name ); - } - } - else - { - everythingIncluded = false; - filesExcluded.add( name ); - } - } - else - { - everythingIncluded = false; - filesNotIncluded.add( name ); - } - } - } + if (!isFollowSymlinks() && isParentSymbolicLink(dir, null)) { + LinkOption[] linkOptionsFollowingLinks = Arrays.stream(getLinkOptions()) + .filter(l -> l == LinkOption.NOFOLLOW_LINKS).toArray(LinkOption[]::new); + try (DirectoryStream directoryStream = Files.newDirectoryStream(dir)) { + for (Path file : directoryStream) { + if (Files.isDirectory(file, linkOptionsFollowingLinks)) { + dirsExcluded.add(file.toString()); + } else { + filesExcluded.add(file.toString()); + } + } + } + return; + } + try (DirectoryStream directoryStream = Files.newDirectoryStream(dir)) { + Iterator iterator; + if (filenameComparator == null) { + iterator = directoryStream.iterator(); + } else { + Stream stream = StreamSupport.stream( + Spliterators.spliteratorUnknownSize(directoryStream.iterator(), Spliterator.ORDERED), false); + iterator = stream.sorted(Comparator.comparing(Path::getFileName, + Comparator.comparing(Path::toString, filenameComparator))).iterator(); + } + while (iterator.hasNext()) { + Path file = iterator.next(); + String name = vpath + file.getFileName().toString(); + char[][] tokenizedName = MatchPattern.tokenizePathToCharArray(name, File.separator); + if (Files.isDirectory(file, getLinkOptions())) { + + if (isIncluded(name, tokenizedName)) { + if (!isExcluded(name, tokenizedName)) { + if (isSelected(name, file)) { + dirsIncluded.add(name); + if (fast) { + scandir(file, name + File.separator, fast); + } + } else { + everythingIncluded = false; + dirsDeselected.add(name); + if (fast && couldHoldIncluded(name)) { + scandir(file, name + File.separator, fast); + } + } + + } else { + everythingIncluded = false; + dirsExcluded.add(name); + if (fast && couldHoldIncluded(name)) { + scandir(file, name + File.separator, fast); + } + } + } else { + everythingIncluded = false; + dirsNotIncluded.add(name); + if (fast && couldHoldIncluded(name)) { + scandir(file, name + File.separator, fast); + } + } + if (!fast) { + scandir(file, name + File.separator, fast); + } + } else if (Files.isRegularFile(file, getLinkOptions())) { + if (isIncluded(name, tokenizedName)) { + if (!isExcluded(name, tokenizedName)) { + if (isSelected(name, file)) { + filesIncluded.add(name); + } else { + everythingIncluded = false; + filesDeselected.add(name); + } + } else { + everythingIncluded = false; + filesExcluded.add(name); + } + } else { + everythingIncluded = false; + filesNotIncluded.add(name); + } + } + } + } } /** @@ -530,7 +505,7 @@ else if ( file.isFile() ) * @return false when the selectors says that the file should not be selected, true * otherwise. */ - protected boolean isSelected( String name, File file ) + protected boolean isSelected(String name, Path file) { return true; } @@ -660,10 +635,10 @@ public String[] getDeselectedDirectories() * @throws java.io.IOException . * @since Ant 1.5 */ - public boolean isSymbolicLink( File parent, String name ) + public boolean isSymbolicLink(Path parent, String name) throws IOException { - return NioFiles.isSymbolicLink( new File( parent, name ) ); + return Files.isSymbolicLink(parent.resolve(name)); } /** @@ -678,9 +653,13 @@ public boolean isSymbolicLink( File parent, String name ) * @throws java.io.IOException . * @since Ant 1.5 */ - public boolean isParentSymbolicLink( File parent, String name ) + public boolean isParentSymbolicLink(Path parent, String name) throws IOException { - return NioFiles.isSymbolicLink( parent ); + return Files.isSymbolicLink(parent); } + + protected boolean isFollowSymlinks() { + return followSymlinks || Arrays.stream(getLinkOptions()).noneMatch(o -> o == LinkOption.NOFOLLOW_LINKS); + } } diff --git a/src/main/java/org/codehaus/plexus/util/FileUtils.java b/src/main/java/org/codehaus/plexus/util/FileUtils.java index 4dca8b3c..85161b48 100644 --- a/src/main/java/org/codehaus/plexus/util/FileUtils.java +++ b/src/main/java/org/codehaus/plexus/util/FileUtils.java @@ -1,5 +1,29 @@ package org.codehaus.plexus.util; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.security.SecureRandom; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + /* ==================================================================== * The Apache Software License, Version 1.1 * @@ -58,27 +82,6 @@ import org.codehaus.plexus.util.io.InputStreamFacade; import org.codehaus.plexus.util.io.URLInputStreamFacade; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.security.SecureRandom; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - /** *

This class provides basic facilities for manipulating files and file paths.

* @@ -392,7 +395,8 @@ private static InputStreamReader getInputStreamReader( File file, String encodin * @deprecated use {@code java.nio.files.Files.write(filename, data.getBytes(encoding), * StandardOpenOption.APPEND, StandardOpenOption.CREATE)} */ - public static void fileAppend( String fileName, String data ) + @Deprecated + public static void fileAppend( String fileName, String data ) throws IOException { fileAppend( fileName, null, data ); @@ -408,7 +412,8 @@ public static void fileAppend( String fileName, String data ) * @deprecated use {@code java.nio.files.Files.write(filename, data.getBytes(encoding), * StandardOpenOption.APPEND, StandardOpenOption.CREATE)} */ - public static void fileAppend( String fileName, String encoding, String data ) + @Deprecated + public static void fileAppend( String fileName, String encoding, String data ) throws IOException { try ( OutputStream out = Files.newOutputStream( Paths.get(fileName), @@ -510,7 +515,7 @@ public static void fileDelete( String fileName ) File file = new File( fileName ); try { - NioFiles.deleteIfExists( file ); + Files.deleteIfExists(file.toPath()); } catch ( IOException e ) { @@ -999,10 +1004,14 @@ public static void mkDirs( final File sourceBase, String[] dirs, final File dest { File src = new File( sourceBase, dir ); File dst = new File( destination, dir ); - if ( NioFiles.isSymbolicLink( src ) ) + if (Files.isSymbolicLink(src.toPath())) { - File target = NioFiles.readSymbolicLink( src ); - NioFiles.createSymbolicLink( dst, target ); + Path target = Files.readSymbolicLink(src.toPath()); + Path link = dst.toPath(); + if (Files.exists(link, LinkOption.NOFOLLOW_LINKS)) { + Files.delete(link); + } + link = Files.createSymbolicLink(link, target); } else { @@ -1040,7 +1049,8 @@ public static void copyFile( final File source, final File destination ) } mkdirsFor( destination ); - doCopyFile( source, destination ); + Files.copy(source.toPath(), destination.toPath(), StandardCopyOption.REPLACE_EXISTING, + StandardCopyOption.COPY_ATTRIBUTES); if ( source.length() != destination.length() ) { @@ -1049,18 +1059,6 @@ public static void copyFile( final File source, final File destination ) } } - private static void doCopyFile( File source, File destination ) - throws IOException - { - doCopyFileUsingNewIO( source, destination ); - } - - private static void doCopyFileUsingNewIO( File source, File destination ) - throws IOException - { - NioFiles.copy( source, destination ); - } - /** * Link file from destination to source. The directories up to destination will be created if they * don't already exist. destination will be overwritten if it already exists. @@ -1090,7 +1088,11 @@ public static void linkFile( final File source, final File destination ) } mkdirsFor( destination ); - NioFiles.createSymbolicLink( destination, source ); + Path link = destination.toPath(); + if (Files.exists(link, LinkOption.NOFOLLOW_LINKS)) { + Files.delete(link); + } + Files.createSymbolicLink(link, source.toPath()); } /** @@ -1734,7 +1736,7 @@ public static long sizeOfDirectory( final File directory ) * @throws IOException io issue * @see #getFileNames(File, String, String, boolean) */ - public static List getFiles( File directory, String includes, String excludes ) + public static List getFiles(Path directory, String includes, String excludes) throws IOException { return getFiles( directory, includes, excludes, true ); @@ -1751,7 +1753,7 @@ public static List getFiles( File directory, String includes, String exclu * @throws IOException io issue * @see #getFileNames(File, String, String, boolean) */ - public static List getFiles( File directory, String includes, String excludes, boolean includeBasedir ) + public static List getFiles(Path directory, String includes, String excludes, boolean includeBasedir) throws IOException { List fileNames = getFileNames( directory, includes, excludes, includeBasedir ); @@ -1776,7 +1778,7 @@ public static List getFiles( File directory, String includes, String exclu * @return a list of files as String * @throws IOException io issue */ - public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir ) + public static List getFileNames(Path directory, String includes, String excludes, boolean includeBasedir) throws IOException { return getFileNames( directory, includes, excludes, includeBasedir, true ); @@ -1793,7 +1795,7 @@ public static List getFileNames( File directory, String includes, String * @return a list of files as String * @throws IOException io issue */ - public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir, + public static List getFileNames(Path directory, String includes, String excludes, boolean includeBasedir, boolean isCaseSensitive ) throws IOException { @@ -1810,7 +1812,7 @@ public static List getFileNames( File directory, String includes, String * @return a list of directories as String * @throws IOException io issue */ - public static List getDirectoryNames( File directory, String includes, String excludes, + public static List getDirectoryNames(Path directory, String includes, String excludes, boolean includeBasedir ) throws IOException { @@ -1828,7 +1830,7 @@ public static List getDirectoryNames( File directory, String includes, S * @return a list of directories as String * @throws IOException io issue */ - public static List getDirectoryNames( File directory, String includes, String excludes, + public static List getDirectoryNames(Path directory, String includes, String excludes, boolean includeBasedir, boolean isCaseSensitive ) throws IOException { @@ -1848,7 +1850,7 @@ public static List getDirectoryNames( File directory, String includes, S * @return a list of files as String * @throws IOException io issue */ - public static List getFileAndDirectoryNames( File directory, String includes, String excludes, + public static List getFileAndDirectoryNames(Path directory, String includes, String excludes, boolean includeBasedir, boolean isCaseSensitive, boolean getFiles, boolean getDirectories ) throws IOException @@ -1917,7 +1919,7 @@ public static List getFileAndDirectoryNames( File directory, String incl * @param destinationDirectory the target dir * @throws IOException if any */ - public static void copyDirectory( File sourceDirectory, File destinationDirectory ) + public static void copyDirectory(Path sourceDirectory, File destinationDirectory) throws IOException { copyDirectory( sourceDirectory, destinationDirectory, "**", null ); @@ -1933,11 +1935,11 @@ public static void copyDirectory( File sourceDirectory, File destinationDirector * @throws IOException if any * @see #getFiles(File, String, String) */ - public static void copyDirectory( File sourceDirectory, File destinationDirectory, String includes, + public static void copyDirectory(Path sourceDirectory, File destinationDirectory, String includes, String excludes ) throws IOException { - if ( !sourceDirectory.exists() ) + if (!Files.exists(sourceDirectory)) { return; } @@ -1966,7 +1968,7 @@ public static void copyDirectory( File sourceDirectory, File destinationDirector * @throws IOException if any * @since 1.5.7 */ - public static void copyDirectoryLayout( File sourceDirectory, File destinationDirectory, String[] includes, + public static void copyDirectoryLayout(Path sourceDirectory, Path destinationDirectory, String[] includes, String[] excludes ) throws IOException { @@ -1985,9 +1987,9 @@ public static void copyDirectoryLayout( File sourceDirectory, File destinationDi throw new IOException( "source and destination are the same directory." ); } - if ( !sourceDirectory.exists() ) + if (!Files.exists(sourceDirectory)) { - throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." ); + throw new IOException("Source directory doesn't exists (" + sourceDirectory.toAbsolutePath() + ")."); } DirectoryScanner scanner = new DirectoryScanner(); @@ -2014,15 +2016,15 @@ public static void copyDirectoryLayout( File sourceDirectory, File destinationDi for ( String name : includedDirectories ) { - File source = new File( sourceDirectory, name ); + Path source = sourceDirectory.resolve(name); if ( source.equals( sourceDirectory ) ) { continue; } - File destination = new File( destinationDirectory, name ); - destination.mkdirs(); + Path destination = destinationDirectory.resolve(name); + Files.createDirectories(destination); } } @@ -2198,7 +2200,7 @@ public static File createTempFile( String prefix, String suffix, File parentDir parent = parentDir.getPath(); } DecimalFormat fmt = new DecimalFormat( "#####" ); - SecureRandom secureRandom = new SecureRandom(); + SecureRandom secureRandom = new SecureRandom(); long secureInitializer = secureRandom.nextLong(); Random rand = new Random( secureInitializer + Runtime.getRuntime().freeMemory() ); synchronized ( rand ) diff --git a/src/main/java/org/codehaus/plexus/util/NioFiles.java b/src/main/java/org/codehaus/plexus/util/NioFiles.java deleted file mode 100644 index eb62bac7..00000000 --- a/src/main/java/org/codehaus/plexus/util/NioFiles.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.codehaus.plexus.util; - -/* - * Copyright 2007 The Codehaus Foundation. - * - * Licensed 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 java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.PosixFilePermission; -import java.util.HashSet; -import java.util.Set; - -/** - * Encapsulates use of java7 features, exposing mostly backward compatible types - */ -@SuppressWarnings( "Since15" ) -public class NioFiles -{ - public static boolean isSymbolicLink( File file ) - { - return Files.isSymbolicLink( file.toPath() ); - } - - public static void chmod( File file, int mode ) - throws IOException - { - Path path = file.toPath(); - if ( !Files.isSymbolicLink( path ) ) - { - Files.setPosixFilePermissions( path, getPermissions( mode ) ); - } - } - - @SuppressWarnings( { "OctalInteger", "MagicNumber" } ) - private static Set getPermissions( int mode ) - { - Set perms = new HashSet<>(); - // add owners permission - if ( ( mode & 0400 ) > 0 ) - { - perms.add( PosixFilePermission.OWNER_READ ); - } - if ( ( mode & 0200 ) > 0 ) - { - perms.add( PosixFilePermission.OWNER_WRITE ); - } - if ( ( mode & 0100 ) > 0 ) - { - perms.add( PosixFilePermission.OWNER_EXECUTE ); - } - // add group permissions - if ( ( mode & 0040 ) > 0 ) - { - perms.add( PosixFilePermission.GROUP_READ ); - } - if ( ( mode & 0020 ) > 0 ) - { - perms.add( PosixFilePermission.GROUP_WRITE ); - } - if ( ( mode & 0010 ) > 0 ) - { - perms.add( PosixFilePermission.GROUP_EXECUTE ); - } - // add others permissions - if ( ( mode & 0004 ) > 0 ) - { - perms.add( PosixFilePermission.OTHERS_READ ); - } - if ( ( mode & 0002 ) > 0 ) - { - perms.add( PosixFilePermission.OTHERS_WRITE ); - } - if ( ( mode & 0001 ) > 0 ) - { - perms.add( PosixFilePermission.OTHERS_EXECUTE ); - } - return perms; - } - - public static long getLastModified( File file ) - throws IOException - { - BasicFileAttributes basicFileAttributes = Files.readAttributes( file.toPath(), BasicFileAttributes.class ); - return basicFileAttributes.lastModifiedTime().toMillis(); - } - - /** - * Reads the target of the symbolic link - * - * @param symlink A file that is a symlink - * @return A file that is the target of the symlink - * @throws java.io.IOException io issue - */ - - public static File readSymbolicLink( File symlink ) - throws IOException - { - Path path = Files.readSymbolicLink( symlink.toPath() ); - return path.toFile(); - } - - public static File createSymbolicLink( File symlink, File target ) - throws IOException - { - Path link = symlink.toPath(); - if ( Files.exists( link, LinkOption.NOFOLLOW_LINKS ) ) - { - Files.delete( link ); - } - link = Files.createSymbolicLink( link, target.toPath() ); - return link.toFile(); - } - - public static boolean deleteIfExists( File file ) - throws IOException - { - return Files.deleteIfExists( file.toPath() ); - } - - public static File copy( File source, File target ) - throws IOException - { - Path copy = Files.copy( source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING, - StandardCopyOption.COPY_ATTRIBUTES ); - return copy.toFile(); - } - -} diff --git a/src/main/java/org/codehaus/plexus/util/Scanner.java b/src/main/java/org/codehaus/plexus/util/Scanner.java index 20bf85fb..4a1b1cc3 100644 --- a/src/main/java/org/codehaus/plexus/util/Scanner.java +++ b/src/main/java/org/codehaus/plexus/util/Scanner.java @@ -1,22 +1,8 @@ package org.codehaus.plexus.util; -/* - * Copyright The Codehaus Foundation. - * - * Licensed 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 java.io.File; +import java.io.IOException; +import java.nio.file.LinkOption; +import java.nio.file.Path; import java.util.Comparator; /** @@ -53,12 +39,16 @@ public interface Scanner void addDefaultExcludes(); /** - * Scans the base directory for files which match at least one include pattern and don't match any exclude patterns. - * - * @exception IllegalStateException if the base directory was set incorrectly (i.e. if it is null, - * doesn't exist, or isn't a directory). - */ - void scan(); + * Scans the base directory for files which match at least one include pattern + * and don't match any exclude patterns. + * + * @throws IOException if any IO problem occurs while scanning + * + * @exception IllegalStateException if the base directory was set incorrectly + * (i.e. if it is null, doesn't + * exist, or isn't a directory). + */ + void scan() throws IllegalStateException, IOException; /** * Returns the names of the files which matched at least one of the include patterns and none of the exclude @@ -83,7 +73,21 @@ public interface Scanner * * @return the base directory to be scanned */ - File getBasedir(); + Path getBasedir(); + + /** + * Return the link options used for scanning operations + * + * @return the link options used for scanning + */ + LinkOption[] getLinkOptions(); + + /** + * set the link options to be used for scanning operations + * + * @param options the nes link options + */ + void setLinkOptions(LinkOption[] options); /** * Use a filename comparator in each directory when scanning. diff --git a/src/test/java/org/codehaus/plexus/util/DirectoryScannerTest.java b/src/test/java/org/codehaus/plexus/util/DirectoryScannerTest.java index 86c6dd20..7feece06 100644 --- a/src/test/java/org/codehaus/plexus/util/DirectoryScannerTest.java +++ b/src/test/java/org/codehaus/plexus/util/DirectoryScannerTest.java @@ -28,6 +28,7 @@ import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -82,7 +83,8 @@ public void testCrossPlatformIncludesString() throws IOException, URISyntaxException { DirectoryScanner ds = new DirectoryScanner(); - ds.setBasedir( new File( getTestResourcesDir() + File.separator + "directory-scanner" ).getCanonicalFile() ); + ds.setBasedir( + new File(getTestResourcesDir() + File.separator + "directory-scanner").getCanonicalFile().toPath()); String fs; if ( File.separatorChar == '/' ) @@ -113,7 +115,8 @@ public void testCrossPlatformExcludesString() throws IOException, URISyntaxException { DirectoryScanner ds = new DirectoryScanner(); - ds.setBasedir( new File( getTestResourcesDir() + File.separator + "directory-scanner" ).getCanonicalFile() ); + ds.setBasedir( + new File(getTestResourcesDir() + File.separator + "directory-scanner").getCanonicalFile().toPath()); ds.setIncludes( new String[] { "**" } ); String fs; @@ -173,7 +176,8 @@ private boolean checkTestFilesSymlinks() try { List symlinks = - FileUtils.getFileAndDirectoryNames( symlinksDirectory, "sym*", null, true, true, true, true ); + FileUtils.getFileAndDirectoryNames(symlinksDirectory.toPath(), "sym*", null, true, true, true, + true); if ( symlinks.isEmpty() ) { throw new IOException( "Symlinks files/directories are not present" ); @@ -215,7 +219,7 @@ public void testGeneral() String includes = "scanner1.dat,scanner2.dat,scanner3.dat,scanner4.dat,scanner5.dat"; String excludes = "scanner1.dat,scanner2.dat"; - List fileNames = FileUtils.getFiles( new File( testDir ), includes, excludes, false ); + List fileNames = FileUtils.getFiles(new File(testDir).toPath(), includes, excludes, false); assertEquals( "Wrong number of results.", 3, fileNames.size() ); assertTrue( "3 not found.", fileNames.contains( new File( "scanner3.dat" ) ) ); @@ -239,7 +243,7 @@ public void testIncludesExcludesWithWhiteSpaces() String excludes = "scanner1.dat,\n \n,scanner2.dat \n\r,,"; - List fileNames = FileUtils.getFiles( new File( testDir ), includes, excludes, false ); + List fileNames = FileUtils.getFiles(new File(testDir).toPath(), includes, excludes, false); assertEquals( "Wrong number of results.", 3, fileNames.size() ); assertTrue( "3 not found.", fileNames.contains( new File( "scanner3.dat" ) ) ); @@ -248,15 +252,20 @@ public void testIncludesExcludesWithWhiteSpaces() } /** - *

testFollowSymlinksFalse.

- */ + *

+ * testFollowSymlinksFalse. + *

+ * + * @throws IOException + * @throws IllegalStateException + */ @Test - public void testFollowSymlinksFalse() + public void testFollowSymlinksFalse() throws IllegalStateException, IOException { assumeTrue( checkTestFilesSymlinks() ); DirectoryScanner ds = new DirectoryScanner(); - ds.setBasedir( new File( "src/test/resources/symlinks/src/" ) ); + ds.setBasedir(new File("src/test/resources/symlinks/src/").toPath()); ds.setFollowSymlinks( false ); ds.scan(); List included = Arrays.asList( ds.getIncludedFiles() ); @@ -285,15 +294,20 @@ private void assertAlwaysIncluded( List included ) } /** - *

testFollowSymlinks.

- */ + *

+ * testFollowSymlinks. + *

+ * + * @throws IOException + * @throws IllegalStateException + */ @Test - public void testFollowSymlinks() + public void testFollowSymlinks() throws IllegalStateException, IOException { assumeTrue( checkTestFilesSymlinks() ); DirectoryScanner ds = new DirectoryScanner(); - ds.setBasedir( new File( "src/test/resources/symlinks/src/" ) ); + ds.setBasedir(new File("src/test/resources/symlinks/src/").toPath()); ds.setFollowSymlinks( true ); ds.scan(); List included = Arrays.asList( ds.getIncludedFiles() ); @@ -342,7 +356,7 @@ public void testDirectoriesWithHyphens() String[] excludes = { "" }; ds.setIncludes( includes ); ds.setExcludes( excludes ); - ds.setBasedir( new File( testDir + File.separator + "directoryTest" ) ); + ds.setBasedir(new File(testDir + File.separator + "directoryTest").toPath()); ds.setCaseSensitive( true ); ds.scan(); @@ -384,7 +398,7 @@ public void testAntExcludesOverrideIncludes() ds.setIncludes( includes ); ds.setExcludes( excludes ); - ds.setBasedir( dir ); + ds.setBasedir(dir.toPath()); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); @@ -425,7 +439,7 @@ public void testAntExcludesOverrideIncludesWithExplicitAntPrefix() ds.setIncludes( includes ); ds.setExcludes( excludes ); - ds.setBasedir( dir ); + ds.setBasedir(dir.toPath()); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); @@ -461,7 +475,7 @@ public void testRegexIncludeWithExcludedPrefixDirs() String[] includes = { includeExpr }; ds.setIncludes( includes ); - ds.setBasedir( dir ); + ds.setBasedir(dir.toPath()); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); @@ -505,7 +519,7 @@ public void testRegexExcludeWithNegativeLookahead() String[] excludes = { excludeExpr }; ds.setExcludes( excludes ); - ds.setBasedir( dir ); + ds.setBasedir(dir.toPath()); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); @@ -550,7 +564,7 @@ public void testRegexWithSlashInsideCharacterClass() String[] excludes = { excludeExpr }; ds.setExcludes( excludes ); - ds.setBasedir( dir ); + ds.setBasedir(dir.toPath()); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); @@ -603,9 +617,9 @@ public void testDoNotScanUnnecesaryDirectories() DirectoryScanner ds = new DirectoryScanner() { @Override - protected void scandir( File dir, String vpath, boolean fast ) + protected void scandir(Path dir, String vpath, boolean fast) throws IOException { - scannedDirSet.add( dir.getName() ); + scannedDirSet.add(dir.getFileName().toString()); super.scandir( dir, vpath, fast ); } @@ -614,7 +628,7 @@ protected void scandir( File dir, String vpath, boolean fast ) // one '*' matches only ONE directory level String[] includes = { "directoryTest" + File.separator + "*" + File.separator + "file1.dat" }; ds.setIncludes( includes ); - ds.setBasedir( new File( testDir ) ); + ds.setBasedir(new File(testDir).toPath()); ds.scan(); assertInclusionsAndExclusions( ds.getIncludedFiles(), excludedPaths, includedPaths ); @@ -636,12 +650,12 @@ public void testIsSymbolicLink() { assumeTrue( checkTestFilesSymlinks() ); - final File directory = new File( "src/test/resources/symlinks/src" ); + final Path directory = new File("src/test/resources/symlinks/src").toPath(); DirectoryScanner ds = new DirectoryScanner(); - assertTrue( ds.isSymbolicLink( directory, "symR" ) ); - assertTrue( ds.isSymbolicLink( directory, "symDir" ) ); - assertFalse( ds.isSymbolicLink( directory, "fileR.txt" ) ); - assertFalse( ds.isSymbolicLink( directory, "aRegularDir" ) ); + assertTrue(ds.isSymbolicLink(directory, "symR")); + assertTrue(ds.isSymbolicLink(directory, "symDir")); + assertFalse(ds.isSymbolicLink(directory, "fileR.txt")); + assertFalse(ds.isSymbolicLink(directory, "aRegularDir")); } /** @@ -657,13 +671,13 @@ public void testIsParentSymbolicLink() final File directory = new File( "src/test/resources/symlinks/src" ); DirectoryScanner ds = new DirectoryScanner(); - assertFalse( ds.isParentSymbolicLink( directory, "symR" ) ); - assertFalse( ds.isParentSymbolicLink( directory, "symDir" ) ); - assertFalse( ds.isParentSymbolicLink( directory, "fileR.txt" ) ); - assertFalse( ds.isParentSymbolicLink( directory, "aRegularDir" ) ); - assertFalse( ds.isParentSymbolicLink( new File( directory, "aRegularDir" ), "aRegulatFile.txt" ) ); - assertTrue( ds.isParentSymbolicLink( new File( directory, "symDir" ), "targetFile.txt" ) ); - assertTrue( ds.isParentSymbolicLink( new File( directory, "symLinkToDirOnTheOutside" ), + assertFalse(ds.isParentSymbolicLink(directory.toPath(), "symR")); + assertFalse(ds.isParentSymbolicLink(directory.toPath(), "symDir")); + assertFalse(ds.isParentSymbolicLink(directory.toPath(), "fileR.txt")); + assertFalse(ds.isParentSymbolicLink(directory.toPath(), "aRegularDir")); + assertFalse(ds.isParentSymbolicLink(new File(directory, "aRegularDir").toPath(), "aRegulatFile.txt")); + assertTrue(ds.isParentSymbolicLink(new File(directory, "symDir").toPath(), "targetFile.txt")); + assertTrue(ds.isParentSymbolicLink(new File(directory, "symLinkToDirOnTheOutside").toPath(), "FileInDirOnTheOutside.txt" ) ); } diff --git a/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java b/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java index 4e9093d0..91e3d82d 100644 --- a/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java +++ b/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java @@ -1238,7 +1238,8 @@ public void testFilteredFileCopy() // test ${token} FileUtils.FilterWrapper[] wrappers1 = new FileUtils.FilterWrapper[] { new FileUtils.FilterWrapper() { - public Reader getReader( Reader reader ) + @Override + public Reader getReader( Reader reader ) { return new InterpolationFilterReader( reader, filterProperties, "${", "}" ); } @@ -1709,7 +1710,7 @@ public void testcopyDirectoryLayoutWithExcludesIncludes() File source = new File( "src/test/resources/dir-layout-copy" ); - FileUtils.copyDirectoryLayout( source, destination, null, null ); + FileUtils.copyDirectoryLayout(source.toPath(), destination.toPath(), null, null); assertTrue( destination.exists() );