From b1186f08a39d23367aefcabd37ef446d36a0afb1 Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Tue, 9 Nov 2004 10:19:51 +0000 Subject: [PATCH] Preparations for PR: 21832, in particular unit tests and some refactorings for Changes to Sync: * drop JDK 1.1 compatibility, * override scan instead of buildMap in MyCopy so that we get the included directories even if includeEmptyDirs is false. * use a DirectoryScanner to find orphaned files instead of the recursive algorithm. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277005 13f79535-47bb-0310-9956-ffa450edef68 --- src/etc/testcases/taskdefs/sync.xml | 64 +++++++++++ .../org/apache/tools/ant/taskdefs/Sync.java | 100 +++++++----------- .../apache/tools/ant/types/PatternSet.java | 2 +- .../org/apache/tools/ant/BuildFileTest.java | 12 +++ .../apache/tools/ant/taskdefs/SyncTest.java | 95 +++++++++++++++++ 5 files changed, 210 insertions(+), 63 deletions(-) create mode 100644 src/etc/testcases/taskdefs/sync.xml create mode 100644 src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java diff --git a/src/etc/testcases/taskdefs/sync.xml b/src/etc/testcases/taskdefs/sync.xml new file mode 100644 index 000000000..36fbe88b5 --- /dev/null +++ b/src/etc/testcases/taskdefs/sync.xml @@ -0,0 +1,64 @@ + + + + + + This file must be used from a test case + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/taskdefs/Sync.java b/src/main/org/apache/tools/ant/taskdefs/Sync.java index 83d763289..e890c1fc4 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Sync.java +++ b/src/main/org/apache/tools/ant/taskdefs/Sync.java @@ -25,12 +25,16 @@ package org.apache.tools.ant.taskdefs; import java.io.File; -import java.util.Hashtable; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.PatternSet; import org.apache.tools.ant.util.FileNameMapper; import org.apache.tools.ant.util.IdentityMapper; @@ -82,7 +86,7 @@ public class Sync extends Task { File toDir = _copy.getToDir(); // The complete list of files to copy - Hashtable allFiles = _copy._dest2src; + Set allFiles = _copy.nonOrphans; // If the destination directory didn't already exist, // or was empty, then no previous file removal is necessary! @@ -143,54 +147,29 @@ public class Sync extends Task { * @return the number of orphaned files and directories actually removed. * Position 0 of the array is the number of orphaned directories. * Position 1 of the array is the number or orphaned files. - * Position 2 is meaningless. */ - private int[] removeOrphanFiles(Hashtable nonOrphans, File file) { - int[] removedCount = new int[] {0, 0, 0}; - if (file.isDirectory()) { - File[] children = file.listFiles(); - for (int i = 0; i < children.length; ++i) { - int[] temp = removeOrphanFiles(nonOrphans, children[i]); - removedCount[0] += temp[0]; - removedCount[1] += temp[1]; - removedCount[2] += temp[2]; - } - - if (nonOrphans.get(file) == null && removedCount[2] == 0) { - log("Removing orphan directory: " + file, Project.MSG_DEBUG); - file.delete(); - ++removedCount[0]; - } else { - /* - Contrary to what is said above, position 2 is not - meaningless inside the recursion. - Position 2 is used to carry information back up the - recursion about whether or not a directory contains - a directory or file at any depth that is not an - orphan - This has to be done, because if you have the - following directory structure: c:\src\a\file and - your mapper src files were constructed like so: - - The folder 'a' will not be in the hashtable of - nonorphans. So, before deleting it as an orphan, we - have to know whether or not any of its children at - any level are orphans. - If no, then this folder is also an orphan, and may - be deleted. I do this by changing position 2 to a - '1'. - */ - removedCount[2] = 1; - } - - } else { - if (nonOrphans.get(file) == null) { - log("Removing orphan file: " + file, Project.MSG_DEBUG); - file.delete(); - ++removedCount[1]; - } else { - removedCount[2] = 1; - } + private int[] removeOrphanFiles(Set nonOrphans, File toDir) { + int[] removedCount = new int[] {0, 0}; + DirectoryScanner ds = new DirectoryScanner(); + ds.setBasedir(toDir); + Set s = new HashSet(nonOrphans); + s.add(""); + String[] excls = (String[]) s.toArray(new String[s.size()]); + ds.setExcludes(excls); + ds.scan(); + String[] files = ds.getIncludedFiles(); + for (int i = 0; i < files.length; i++) { + File f = new File(toDir, files[i]); + log("Removing orphan file: " + f, Project.MSG_DEBUG); + f.delete(); + ++removedCount[1]; + } + String[] dirs = ds.getIncludedDirectories(); + for (int i = dirs.length - 1 ; i >= 0 ; --i) { + File f = new File(toDir, dirs[i]); + log("Removing orphan directory: " + f, Project.MSG_DEBUG); + f.delete(); + ++removedCount[0]; } return removedCount; } @@ -303,25 +282,22 @@ public class Sync extends Task { // List of files that must be copied, irrelevant from the // fact that they are newer or not than the destination. - private Hashtable _dest2src = new Hashtable(); + private Set nonOrphans = new HashSet(); public MyCopy() { } - protected void buildMap(File fromDir, File toDir, String[] names, - FileNameMapper mapper, Hashtable map) { - assertTrue("No mapper", mapper instanceof IdentityMapper); + protected void scan(File fromDir, File toDir, String[] files, + String[] dirs) { + assertTrue("No mapper", mapperElement == null); - super.buildMap(fromDir, toDir, names, mapper, map); + super.scan(fromDir, toDir, files, dirs); - for (int i = 0; i < names.length; ++i) { - String name = names[i]; - File dest = new File(toDir, name); - // No need to instantiate the src file, as we use the - // table as a set (to remain Java 1.1 compatible!!!). - //File src = new File(fromDir, name); - //_dest2src.put(dest, src); - _dest2src.put(dest, fromDir); + for (int i = 0; i < files.length; ++i) { + nonOrphans.add(files[i]); + } + for (int i = 0; i < dirs.length; ++i) { + nonOrphans.add(dirs[i]); } } diff --git a/src/main/org/apache/tools/ant/types/PatternSet.java b/src/main/org/apache/tools/ant/types/PatternSet.java index b0f494fcc..4c7538b89 100644 --- a/src/main/org/apache/tools/ant/types/PatternSet.java +++ b/src/main/org/apache/tools/ant/types/PatternSet.java @@ -434,7 +434,7 @@ public class PatternSet extends DataType implements Cloneable { */ private String[] makeArray(Vector list, Project p) { if (list.size() == 0) { - return null; + return null; } Vector tmpNames = new Vector(); diff --git a/src/testcases/org/apache/tools/ant/BuildFileTest.java b/src/testcases/org/apache/tools/ant/BuildFileTest.java index c8a0889f6..bb50df880 100644 --- a/src/testcases/org/apache/tools/ant/BuildFileTest.java +++ b/src/testcases/org/apache/tools/ant/BuildFileTest.java @@ -111,6 +111,18 @@ public abstract class BuildFileTest extends TestCase { assertEquals(log, realLog); } + /** + * Assert that the given substring is in the log messages + */ + + protected void assertDebuglogContaining(String substring) { + String realLog = getFullLog(); + assertTrue("expecting debug log to contain \"" + substring + + "\" log was \"" + + realLog + "\"", + realLog.indexOf(substring) >= 0); + } + /** * Gets the log the BuildFileTest object. * only valid if configureProject() has diff --git a/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java b/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java new file mode 100644 index 000000000..909b3d43b --- /dev/null +++ b/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2000-2004 The Apache Software 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. + * + */ + +package org.apache.tools.ant.taskdefs; + +import org.apache.tools.ant.BuildFileTest; +import java.io.File; + +public class SyncTest extends BuildFileTest { + + public SyncTest(String name) { + super(name); + } + + public void setUp() { + configureProject("src/etc/testcases/taskdefs/sync.xml"); + } + + public void tearDown() { + executeTarget("cleanup"); + } + + public void testSimpleCopy() { + executeTarget("simplecopy"); + String d = getProject().getProperty("dest") + "/a/b/c/d"; + assertFileIsPresent(d); + assertTrue(getFullLog().indexOf("dangling") == -1); + } + + public void testEmptyCopy() { + executeTarget("emptycopy"); + String d = getProject().getProperty("dest") + "/a/b/c/d"; + assertFileIsNotPresent(d); + String c = getProject().getProperty("dest") + "/a/b/c"; + assertFileIsNotPresent(c); + assertTrue(getFullLog().indexOf("dangling") == -1); + } + + public void testEmptyDirCopy() { + executeTarget("emptydircopy"); + String d = getProject().getProperty("dest") + "/a/b/c/d"; + assertFileIsNotPresent(d); + String c = getProject().getProperty("dest") + "/a/b/c"; + assertFileIsPresent(c); + assertTrue(getFullLog().indexOf("dangling") == -1); + } + + public void testCopyAndRemove() { + executeTarget("copyandremove"); + String d = getProject().getProperty("dest") + "/a/b/c/d"; + assertFileIsPresent(d); + String f = getProject().getProperty("dest") + "/e/f"; + assertFileIsNotPresent(f); + assertTrue(getFullLog().indexOf("Removing orphan file:") > -1); + assertDebuglogContaining("Removed 1 dangling file from"); + assertDebuglogContaining("Removed 1 dangling directory from"); + } + + public void testEmptyDirCopyAndRemove() { + executeTarget("emptydircopyandremove"); + String d = getProject().getProperty("dest") + "/a/b/c/d"; + assertFileIsNotPresent(d); + String c = getProject().getProperty("dest") + "/a/b/c"; + assertFileIsPresent(c); + String f = getProject().getProperty("dest") + "/e/f"; + assertFileIsNotPresent(f); + assertTrue(getFullLog().indexOf("Removing orphan directory:") > -1); + assertDebuglogContaining("NO dangling file to remove from"); + assertDebuglogContaining("Removed 2 dangling directories from"); + } + + public void assertFileIsPresent(String f) { + assertTrue("Expected file " + f, + getProject().resolveFile(f).exists()); + } + + public void assertFileIsNotPresent(String f) { + assertTrue("Didn't expect file " + f, + !getProject().resolveFile(f).exists()); + } +} \ No newline at end of file