Browse Source

Allow <sync> to keep files in target even if they are not in any source directories, PR 21832

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277393 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 20 years ago
parent
commit
28d39b09a7
4 changed files with 131 additions and 17 deletions
  1. +14
    -0
      src/etc/testcases/taskdefs/sync.xml
  2. +50
    -13
      src/main/org/apache/tools/ant/DirectoryScanner.java
  3. +57
    -3
      src/main/org/apache/tools/ant/taskdefs/Sync.java
  4. +10
    -1
      src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java

+ 14
- 0
src/etc/testcases/taskdefs/sync.xml View File

@@ -61,4 +61,18 @@
<fileset dir="${src}" excludes="**/d"/> <fileset dir="${src}" excludes="**/d"/>
</sync> </sync>
</target> </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> </project>

+ 50
- 13
src/main/org/apache/tools/ant/DirectoryScanner.java View File

@@ -584,13 +584,7 @@ public class DirectoryScanner
} else { } else {
this.includes = new String[includes.length]; this.includes = new String[includes.length];
for (int i = 0; i < includes.length; i++) { 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 { } else {
this.excludes = new String[excludes.length]; this.excludes = new String[excludes.length];
for (int i = 0; i < excludes.length; i++) { 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. * Sets the selectors that will select the filelist.


+ 57
- 3
src/main/org/apache/tools/ant/taskdefs/Sync.java View File

@@ -32,6 +32,7 @@ import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task; import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.AbstractFileSet;
import org.apache.tools.ant.types.FileSet; 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! // Same as regular <copy> task... see at end-of-file!
private MyCopy myCopy; private MyCopy myCopy;


// Similar to a fileset, but doesn't allow dir attribute to be set
private SyncTarget syncTarget;

// Override Task#init // Override Task#init
/** /**
* @see Task#init() * @see Task#init()
@@ -152,13 +156,21 @@ public class Sync extends Task {
*/ */
private int[] removeOrphanFiles(Set nonOrphans, File toDir) { private int[] removeOrphanFiles(Set nonOrphans, File toDir) {
int[] removedCount = new int[] {0, 0}; int[] removedCount = new int[] {0, 0};
DirectoryScanner ds = new DirectoryScanner();
ds.setBasedir(toDir);
String[] excls = String[] excls =
(String[]) nonOrphans.toArray(new String[nonOrphans.size() + 1]); (String[]) nonOrphans.toArray(new String[nonOrphans.size() + 1]);
// want to keep toDir itself // want to keep toDir itself
excls[nonOrphans.size()] = ""; 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(); ds.scan();
String[] files = ds.getIncludedFiles(); String[] files = ds.getIncludedFiles();
for (int i = 0; i < files.length; i++) { for (int i = 0; i < files.length; i++) {
@@ -288,6 +300,23 @@ public class Sync extends Task {
myCopy.setGranularity(granularity); 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. * 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. * Pseudo-assert method.
*/ */


+ 10
- 1
src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java View File

@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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"); 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) { public void assertFileIsPresent(String f) {
assertTrue("Expected file " + f, assertTrue("Expected file " + f,
getProject().resolveFile(f).exists()); getProject().resolveFile(f).exists());


Loading…
Cancel
Save