git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277393 13f79535-47bb-0310-9956-ffa450edef68master
@@ -61,4 +61,18 @@ | |||
<fileset dir="${src}" excludes="**/d"/> | |||
</sync> | |||
</target> | |||
<target name="copynoremove" depends="setup"> | |||
<mkdir dir="${src}/a/b/c"/> | |||
<touch file="${src}/a/b/c/d"/> | |||
<mkdir dir="${dest}/e"/> | |||
<touch file="${dest}/e/f"/> | |||
<sync todir="${dest}"> | |||
<fileset dir="${src}"/> | |||
<deletefromtarget> | |||
<exclude name="e/f"/> | |||
</deletefromtarget> | |||
</sync> | |||
</target> | |||
</project> |
@@ -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 <code>File.separatorChar</code>, so | |||
* the separator used need not match | |||
* <code>File.separatorChar</code>. | |||
* <p> | |||
* When a pattern ends with a '/' or '\', "**" is appended. | |||
* | |||
* @param excludes A list of exclude patterns. | |||
* May be <code>null</code>, 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 | |||
* <code>File.separatorChar</code>, so the separator used need not | |||
* match <code>File.separatorChar</code>. | |||
* | |||
* <p> 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. | |||
@@ -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 <copy> 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. | |||
* | |||
* <p>You must not invoke this method more than once.</p> | |||
* | |||
* @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. | |||
*/ | |||
@@ -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()); | |||