diff --git a/src/etc/testcases/taskdefs/sync.xml b/src/etc/testcases/taskdefs/sync.xml
index 36fbe88b5..67602b136 100644
--- a/src/etc/testcases/taskdefs/sync.xml
+++ b/src/etc/testcases/taskdefs/sync.xml
@@ -61,4 +61,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/DirectoryScanner.java b/src/main/org/apache/tools/ant/DirectoryScanner.java
index 7ae98a7f4..039421ad8 100644
--- a/src/main/org/apache/tools/ant/DirectoryScanner.java
+++ b/src/main/org/apache/tools/ant/DirectoryScanner.java
@@ -584,13 +584,7 @@ public class DirectoryScanner
} else {
this.includes = new String[includes.length];
for (int i = 0; i < includes.length; i++) {
- String pattern;
- pattern = includes[i].replace('/', File.separatorChar).replace(
- '\\', File.separatorChar);
- if (pattern.endsWith(File.separator)) {
- pattern += "**";
- }
- this.includes[i] = pattern;
+ this.includes[i] = normalizePattern(includes[i]);
}
}
}
@@ -614,17 +608,60 @@ public class DirectoryScanner
} else {
this.excludes = new String[excludes.length];
for (int i = 0; i < excludes.length; i++) {
- String pattern;
- pattern = excludes[i].replace('/', File.separatorChar).replace(
- '\\', File.separatorChar);
- if (pattern.endsWith(File.separator)) {
- pattern += "**";
+ this.excludes[i] = normalizePattern(excludes[i]);
+ }
+ }
+ }
+
+ /**
+ * Adds to the list of exclude patterns to use. All '/' and '\'
+ * characters are replaced by File.separatorChar
, so
+ * the separator used need not match
+ * File.separatorChar
.
+ *
+ * When a pattern ends with a '/' or '\', "**" is appended.
+ *
+ * @param excludes A list of exclude patterns.
+ * May be null
, in which case the
+ * exclude patterns don't get changed at all.
+ *
+ * @since Ant 1.7
+ */
+ public void addExcludes(String[] excludes) {
+ if (excludes != null) {
+ if (this.excludes != null) {
+ String[] tmp = new String[excludes.length
+ + this.excludes.length];
+ System.arraycopy(this.excludes, 0, tmp, 0,
+ this.excludes.length);
+ for (int i = 0; i < excludes.length; i++) {
+ tmp[this.excludes.length + i] =
+ normalizePattern(excludes[i]);
}
- this.excludes[i] = pattern;
+ this.excludes = tmp;
+ } else {
+ setExcludes(excludes);
}
}
}
+ /**
+ * All '/' and '\' characters are replaced by
+ * File.separatorChar
, so the separator used need not
+ * match File.separatorChar
.
+ *
+ *
When a pattern ends with a '/' or '\', "**" is appended.
+ *
+ * @since Ant 1.7
+ */
+ private static String normalizePattern(String p) {
+ String pattern = p.replace('/', File.separatorChar)
+ .replace('\\', File.separatorChar);
+ if (pattern.endsWith(File.separator)) {
+ pattern += "**";
+ }
+ return pattern;
+ }
/**
* Sets the selectors that will select the filelist.
diff --git a/src/main/org/apache/tools/ant/taskdefs/Sync.java b/src/main/org/apache/tools/ant/taskdefs/Sync.java
index 45b6acdd0..f3ecf01b1 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Sync.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Sync.java
@@ -32,6 +32,7 @@ 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.AbstractFileSet;
import org.apache.tools.ant.types.FileSet;
/**
@@ -55,6 +56,9 @@ public class Sync extends Task {
// Same as regular task... see at end-of-file!
private MyCopy myCopy;
+ // Similar to a fileset, but doesn't allow dir attribute to be set
+ private SyncTarget syncTarget;
+
// Override Task#init
/**
* @see Task#init()
@@ -152,13 +156,21 @@ public class Sync extends Task {
*/
private int[] removeOrphanFiles(Set nonOrphans, File toDir) {
int[] removedCount = new int[] {0, 0};
- DirectoryScanner ds = new DirectoryScanner();
- ds.setBasedir(toDir);
String[] excls =
(String[]) nonOrphans.toArray(new String[nonOrphans.size() + 1]);
// want to keep toDir itself
excls[nonOrphans.size()] = "";
- ds.setExcludes(excls);
+
+ DirectoryScanner ds = null;
+ if (syncTarget != null) {
+ syncTarget.setTargetDir(toDir);
+ ds = syncTarget.getDirectoryScanner(getProject());
+ } else {
+ ds = new DirectoryScanner();
+ ds.setBasedir(toDir);
+ }
+ ds.addExcludes(excls);
+
ds.scan();
String[] files = ds.getIncludedFiles();
for (int i = 0; i < files.length; i++) {
@@ -288,6 +300,23 @@ public class Sync extends Task {
myCopy.setGranularity(granularity);
}
+ /**
+ * A container for patterns and selectors that can be used to
+ * specify files that should be kept in the target even if they
+ * are not present in any source directory.
+ *
+ * You must not invoke this method more than once.
+ *
+ * @since Ant 1.7
+ */
+ public void addDeleteFromTarget(SyncTarget s) {
+ if (syncTarget != null) {
+ throw new BuildException("you must not specify multiple "
+ + "deletefromtaget elements.");
+ }
+ syncTarget = s;
+ }
+
/**
* Subclass Copy in order to access it's file/dir maps.
*/
@@ -336,6 +365,31 @@ public class Sync extends Task {
}
+ /**
+ * Inner class used to hold exclude patterns and selectors to save
+ * stuff that happens to live in the target directory but should
+ * not get removed.
+ *
+ * @since Ant 1.7
+ */
+ public static class SyncTarget extends AbstractFileSet {
+
+ public SyncTarget() {
+ super();
+ setDefaultexcludes(false);
+ }
+
+ public void setDir(File dir) throws BuildException {
+ throw new BuildException("synctarget doesn't support the dir "
+ + "attribute");
+ }
+
+ private void setTargetDir(File dir) throws BuildException {
+ super.setDir(dir);
+ }
+
+ }
+
/**
* Pseudo-assert method.
*/
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java b/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java
index 7f6fd80a1..a42ce87d2 100644
--- a/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java
+++ b/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2004 The Apache Software Foundation
+ * Copyright 2004-2005 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.
@@ -83,6 +83,15 @@ public class SyncTest extends BuildFileTest {
assertDebuglogContaining("Removed 2 dangling directories from");
}
+ public void testCopyNoRemove() {
+ executeTarget("copynoremove");
+ String d = getProject().getProperty("dest") + "/a/b/c/d";
+ assertFileIsPresent(d);
+ String f = getProject().getProperty("dest") + "/e/f";
+ assertFileIsPresent(f);
+ assertTrue(getFullLog().indexOf("Removing orphan file:") == -1);
+ }
+
public void assertFileIsPresent(String f) {
assertTrue("Expected file " + f,
getProject().resolveFile(f).exists());