From 89997f3c4660c10e902cf74256ee922e79b0c7e4 Mon Sep 17 00:00:00 2001 From: wisberg Date: Mon, 6 Jan 2003 22:41:40 +0000 Subject: [PATCH] - generalized copyFiles to handle file-file, file-dir, and dir-dir --- util/src/org/aspectj/util/FileUtil.java | 197 ++++++++++++------ .../org/aspectj/util/FileUtilTest.java | 64 ++++++ 2 files changed, 201 insertions(+), 60 deletions(-) diff --git a/util/src/org/aspectj/util/FileUtil.java b/util/src/org/aspectj/util/FileUtil.java index 0d4d76989..939329eb3 100644 --- a/util/src/org/aspectj/util/FileUtil.java +++ b/util/src/org/aspectj/util/FileUtil.java @@ -24,6 +24,9 @@ import java.util.zip.ZipFile; * */ public class FileUtil { + /** default parent directory File when a file has a null parent */ + public static final File DEFAULT_PARENT = new File("."); // XXX user.dir? + /** unmodifiable List of String source file suffixes (including leading ".") */ public static final List SOURCE_SUFFIXES = Collections.unmodifiableList(Arrays.asList(new String[] { ".java", ".aj"})); @@ -237,9 +240,14 @@ public class FileUtil { } /** - * Flatten File[] to String. - * @param files the File[] of paths to flatten - null ignored - * @param infix the String infix to use - null treated as File.pathSeparator + * Render a set of files to String as a path by getting absolute + * paths of each and delimiting with infix. + * @param files the File[] to flatten - may be null or empty + * @param infix the String delimiter internally between entries + * (if null, then use File.pathSeparator). + * (alias to flatten(getAbsolutePaths(files), infix) + * @return String with absolute paths to entries in order, + * delimited with infix */ public static String flatten(File[] files, String infix) { if (LangUtil.isEmpty(files)) { @@ -293,7 +301,7 @@ public class FileUtil { } return path; } - + /** @return array same length as input, with String absolute paths */ public static String[] getAbsolutePaths(File[] files) { if ((null == files) || (0 == files.length)) { @@ -393,19 +401,6 @@ public class FileUtil { return copyDir(fromDir, toDir, fromSuffix, toSuffix, (FileFilter) null); } - /** map name to result, removing any fromSuffix and adding any toSuffix */ - private static String map(String name, String fromSuffix, String toSuffix) { - if (null != name) { - if (null != fromSuffix) { - name = name.substring(0, name.length()-fromSuffix.length()); - } - if (null != toSuffix) { - name = name + toSuffix; - } - } - return name; - } - /** * Recursively copy files in fromDir (with any fromSuffix) to toDir, * replacing fromSuffix with toSuffix if any, @@ -512,21 +507,6 @@ public class FileUtil { } return (String[]) result.toArray(new String[0]); } - - private static void listFiles(final File baseDir, String dir, ArrayList result) { - final String dirPrefix = (null == dir ? "" : dir + "/"); - final File dirFile = (null == dir ? baseDir : new File(baseDir.getPath() + "/" + dir)); - final String[] files = dirFile.list(); - for (int i = 0; i < files.length; i++) { - File f = new File(dirFile, files[i]); - String path = dirPrefix + files[i]; - if (f.isDirectory()) { - listFiles(baseDir, path, result); - } else { - result.add(path); - } - } - } public static final FileFilter aspectjSourceFileFilter = new FileFilter() { public boolean accept(File pathname) { @@ -548,18 +528,6 @@ public class FileUtil { return (File[]) result.toArray(new File[result.size()]); } - private static void listFiles(final File baseDir, ArrayList result, FileFilter filter) { - File[] files = baseDir.listFiles(); - for (int i = 0; i < files.length; i++) { - File f = files[i]; - if (f.isDirectory()) { - listFiles(f, result, filter); - } else { - if (filter.accept(f)) result.add(f); - } - } - } - /** * Convert String[] paths to File[] as offset of base directory * @param basedir the non-null File base directory for File to create with paths @@ -612,6 +580,7 @@ public class FileUtil { * Copy files from source dir into destination directory, * creating any needed directories. This differs from copyDir in not * being recursive; each input with the source dir creates a full path. + * However, if the source is a directory, it is copied as such. * @param srcDir an existing, readable directory containing relativePaths files * @param relativePaths a set of paths relative to srcDir to readable File to copy * @param destDir an existing, writable directory to copy files to @@ -628,21 +597,88 @@ public class FileUtil { String path = paths[i]; LangUtil.throwIaxIfNull(path, "relativePaths-entry"); File src = new File(srcDir, relativePaths[i]); - throwIaxUnlessCanReadFile(src, "src-entry"); File dest = new File(destDir, path); File destParent = dest.getParentFile(); if (!destParent.exists()) { destParent.mkdirs(); - } + } LangUtil.throwIaxIfFalse(canWriteDir(destParent), "dest-entry-parent"); - copyFile(src, dest); + copyFile(src, dest); // both file-dir and dir-dir copies result[i] = dest; } return result; } - /** copy fromFile to toFile */ + /** + * Copy fromFile to toFile, handling file-file, dir-dir, and file-dir + * copies. + * @param fromFile the File path of the file or directory to copy - must be + * readable + * @param toFile the File path of the target file or directory - must be + * writable (will be created if it does not exist) + */ public static void copyFile(File fromFile, File toFile) throws IOException { + LangUtil.throwIaxIfNull(fromFile, "fromFile"); + LangUtil.throwIaxIfNull(toFile, "toFile"); + LangUtil.throwIaxIfFalse(!toFile.equals(fromFile), "same file"); + if (toFile.isDirectory()) { // existing directory + throwIaxUnlessCanWriteDir(toFile, "toFile"); + if (fromFile.isFile()) { // file-dir + File targFile = new File(toFile, fromFile.getName()); + copyValidFiles(fromFile, targFile); + } else if (fromFile.isDirectory()) { // dir-dir + copyDir(fromFile, toFile); + } else { + LangUtil.throwIaxIfFalse(false, "not dir or file: " + fromFile); + } + } else if (toFile.isFile()) { // target file exists + if (fromFile.isDirectory()) { + LangUtil.throwIaxIfFalse(false, "can't copy to file dir: " + fromFile); + } + copyValidFiles(fromFile, toFile); // file-file + } else { // target file is a non-existent path -- could be file or dir + File toFileParent = ensureParentWritable(toFile); + if (fromFile.isFile()) { + copyValidFiles(fromFile, toFile); + } else if (fromFile.isDirectory()) { + toFile.mkdirs(); + throwIaxUnlessCanWriteDir(toFile, "toFile"); + copyDir(fromFile, toFile); + } else { + LangUtil.throwIaxIfFalse(false, "not dir or file: " + fromFile); + } + } + } + + /** + * Ensure that the parent directory to path can be written. + * If the path has a null parent, DEFAULT_PARENT is tested. + * If the path parent does not exist, this tries to create it. + * @param path the File path whose parent should be writable + * @return the File path of the writable parent directory + * @throws IllegalArgumentException if parent cannot be written + * or path is null. + */ + public static File ensureParentWritable(File path) { + LangUtil.throwIaxIfNull(path, "path"); + File pathParent = path.getParentFile(); + if (null == pathParent) { + pathParent = DEFAULT_PARENT; + } + if (!pathParent.canWrite()) { + pathParent.mkdirs(); + } + throwIaxUnlessCanWriteDir(pathParent, "pathParent"); + return pathParent; + } + + /** + * Copy file to file. + * @param fromFile the File to copy (readable, non-null file) + * @param toFile the File to copy to (non-null, parent dir exists) + * @throws IOException + */ + public static void copyValidFiles(File fromFile, File toFile) throws IOException { FileInputStream in = null; FileOutputStream out = null; try { @@ -688,11 +724,7 @@ public class FileUtil { out.write(buf, 0, bytesRead); } } - - private static boolean isValidFileName(String input) { - return ((null != input) && (-1 == input.indexOf(File.pathSeparator))); - } - + /** * Make a new child directory of parent * @param parent a File for the parent (writable) @@ -750,7 +782,7 @@ public class FileUtil { return result; } - public static URL[] getFileURLs(File[] files) { // XXX prints errors to System.err + public static URL[] getFileURLs(File[] files) { if ((null == files) || (0 == files.length)) { return new URL[0]; } @@ -785,6 +817,9 @@ public class FileUtil { /** * Write contents to file, returning null on success or error message otherwise. * This tries to make any necessary parent directories first. + * @param file the File to write (not null) + * @param contents the String to write (use "" if null) + * @return String null on no error, error otherwise */ public static String writeAsString(File file, String contents) { LangUtil.throwIaxIfNull(file, "file"); @@ -949,9 +984,8 @@ public class FileUtil { System.arraycopy(ba, 0, newBa, 0, readSoFar); return newBa; } - final static String FILECHARS = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - /** @return String usable in a File name which is random */ + final static String FILECHARS = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; /** @return semi-random String of length 6 usable as filename suffix */ static String randomFileString() { final double FILECHARS_length = FILECHARS.length(); @@ -1002,10 +1036,6 @@ public class FileUtil { zs.close(); } - private FileUtil() { throw new Error("utility class"); } - - - /** * Do line-based search for literal text in source files, * returning file:line where found. @@ -1090,4 +1120,51 @@ public class FileUtil { return new BufferedOutputStream(new FileOutputStream(file)); } + /** map name to result, removing any fromSuffix and adding any toSuffix */ + private static String map(String name, String fromSuffix, String toSuffix) { + if (null != name) { + if (null != fromSuffix) { + name = name.substring(0, name.length()-fromSuffix.length()); + } + if (null != toSuffix) { + name = name + toSuffix; + } + } + return name; + } + + private static void listFiles(final File baseDir, ArrayList result, FileFilter filter) { + File[] files = baseDir.listFiles(); + for (int i = 0; i < files.length; i++) { + File f = files[i]; + if (f.isDirectory()) { + listFiles(f, result, filter); + } else { + if (filter.accept(f)) result.add(f); + } + } + } + + /** @return true if input is not null and contains no path separator */ + private static boolean isValidFileName(String input) { + return ((null != input) && (-1 == input.indexOf(File.pathSeparator))); + } + + private static void listFiles(final File baseDir, String dir, ArrayList result) { + final String dirPrefix = (null == dir ? "" : dir + "/"); + final File dirFile = (null == dir ? baseDir : new File(baseDir.getPath() + "/" + dir)); + final String[] files = dirFile.list(); + for (int i = 0; i < files.length; i++) { + File f = new File(dirFile, files[i]); + String path = dirPrefix + files[i]; + if (f.isDirectory()) { + listFiles(baseDir, path, result); + } else { + result.add(path); + } + } + } + + private FileUtil() { throw new Error("utility class"); } + } diff --git a/util/testsrc/org/aspectj/util/FileUtilTest.java b/util/testsrc/org/aspectj/util/FileUtilTest.java index 7cda1692c..e528867da 100644 --- a/util/testsrc/org/aspectj/util/FileUtilTest.java +++ b/util/testsrc/org/aspectj/util/FileUtilTest.java @@ -58,6 +58,70 @@ public class FileUtilTest extends TestCase { } } + public void testNotIsFileIsDirectory() { + File noSuchFile = new File("foo"); + assertTrue(!noSuchFile.isFile()); + assertTrue(!noSuchFile.isDirectory()); + } + + public void testCopyFiles() { + // bad input + Class iaxClass = IllegalArgumentException.class; + + checkCopyFiles(null, null, iaxClass, false); + + File noSuchFile = new File("foo"); + checkCopyFiles(noSuchFile, null, iaxClass, false); + checkCopyFiles(noSuchFile, noSuchFile, iaxClass, false); + + File tempDir = FileUtil.getTempDir("testCopyFiles"); + tempFiles.add(tempDir); + File fromFile = new File(tempDir, "fromFile"); + String err = FileUtil.writeAsString(fromFile, "contents of from file"); + assertTrue(err, null == err); + checkCopyFiles(fromFile, null, iaxClass, false); + checkCopyFiles(fromFile, fromFile, iaxClass, false); + + // file-file + File toFile = new File(tempDir, "toFile"); + checkCopyFiles(fromFile, toFile, null, true); + + // file-dir + File toDir= new File(tempDir, "toDir"); + assertTrue(toDir.mkdirs()); + checkCopyFiles(fromFile, toDir, null, true); + + // dir-dir + File fromDir= new File(tempDir, "fromDir"); + assertTrue(fromDir.mkdirs()); + checkCopyFiles(fromFile, fromDir, null, false); + File toFile2 = new File(fromDir, "toFile2"); + checkCopyFiles(fromFile, toFile2, null, false); + checkCopyFiles(fromDir, toDir, null, true); + } + + void checkCopyFiles(File from, File to, Class exceptionClass, boolean clean) { + try { + FileUtil.copyFile(from, to); + assertTrue(null == exceptionClass); + if (to.isFile()) { + assertTrue(from.length() == to.length()); // XXX cheap test + } else { + File toFile = new File(to, from.getName()); + assertTrue(from.length() == toFile.length()); + } + } catch (Throwable t) { + assertTrue(null != exceptionClass); + assertTrue(exceptionClass.isAssignableFrom(t.getClass())); + } finally { + if (clean && (null != to) && (to.exists())) { + if (to.isDirectory()) { + FileUtil.deleteContents(to); + } + to.delete(); + } + } + } public void testDirCopySubdirs() throws IOException { // XXX dir diff File srcDir = new File("src"); File destDir = FileUtil.getTempDir("testDirCopySubdirs"); -- 2.39.5