diff --git a/build.xml b/build.xml index 041ff84d1..8901bb165 100644 --- a/build.xml +++ b/build.xml @@ -158,14 +158,6 @@ - - - - - - - @@ -647,7 +639,6 @@ - @@ -1670,4 +1661,4 @@ description="--> creates a minimum distribution in ./dist" depends="dist-lite"/> - + \ No newline at end of file diff --git a/src/etc/testcases/taskdefs/sync.xml b/src/etc/testcases/taskdefs/sync.xml index 67602b136..ca1bf439c 100644 --- a/src/etc/testcases/taskdefs/sync.xml +++ b/src/etc/testcases/taskdefs/sync.xml @@ -35,6 +35,17 @@ + + + + + + + + + + + @@ -69,9 +80,22 @@ - - - + + + + + + + + + + + + + + + + diff --git a/src/main/org/apache/tools/ant/taskdefs/Sync.java b/src/main/org/apache/tools/ant/taskdefs/Sync.java index a9cc65ca3..54b7afd19 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Sync.java +++ b/src/main/org/apache/tools/ant/taskdefs/Sync.java @@ -34,6 +34,9 @@ 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; +import org.apache.tools.ant.types.PatternSet; +import org.apache.tools.ant.types.selectors.FileSelector; +import org.apache.tools.ant.types.selectors.NoneSelector; /** * Synchronize a local target directory from the files defined @@ -163,8 +166,33 @@ public class Sync extends Task { DirectoryScanner ds = null; if (syncTarget != null) { - syncTarget.setTargetDir(toDir); - ds = syncTarget.getDirectoryScanner(getProject()); + FileSet fs = new FileSet(); + fs.setDir(toDir); + fs.setCaseSensitive(syncTarget.isCaseSensitive()); + fs.setFollowSymlinks(syncTarget.isFollowSymlinks()); + + // preserveInTarget would find all files we want to keep, + // but we need to find all that we want to delete - so the + // meaning of all patterns and selectors must be inverted + PatternSet ps = syncTarget.mergePatterns(getProject()); + String[] excludes = ps.getExcludePatterns(getProject()); + fs.appendExcludes(ps.getIncludePatterns(getProject())); + fs.appendIncludes(ps.getExcludePatterns(getProject())); + fs.setDefaultexcludes(!syncTarget.getDefaultexcludes()); + + // selectors are implicitly ANDed in DirectoryScanner. To + // revert their logic we wrap them into a selector + // instead. + FileSelector[] s = syncTarget.getSelectors(getProject()); + if (s.length > 0) { + NoneSelector ns = new NoneSelector(); + for (int i = 0; i < s.length; i++) { + ns.appendSelector(s[i]); + } + fs.appendSelector(ns); + } + + ds = fs.getDirectoryScanner(getProject()); } else { ds = new DirectoryScanner(); ds.setBasedir(toDir); @@ -180,7 +208,7 @@ public class Sync extends Task { ++removedCount[1]; } String[] dirs = ds.getIncludedDirectories(); - // ds returns the directories as it has visited them. + // ds returns the directories in lexicographic order. // iterating through the array backwards means we are deleting // leaves before their parent nodes - thus making sure (well, // more likely) that the directories are empty when we try to @@ -306,13 +334,13 @@ public class Sync extends Task { * are not present in any source directory. * *

You must not invoke this method more than once.

- * @param s a deletefromtarget nested element + * @param s a preserveintarget nested element * @since Ant 1.7 */ - public void addDeleteFromTarget(SyncTarget s) { + public void addPreserveInTarget(SyncTarget s) { if (syncTarget != null) { throw new BuildException("you must not specify multiple " - + "deletefromtaget elements."); + + "preserveintarget elements."); } syncTarget = s; } @@ -381,24 +409,19 @@ public class Sync extends Task { */ public SyncTarget() { super(); - setDefaultexcludes(false); } /** * Override AbstractFileSet#setDir(File) to disallow - * setting the directory. This is now set by #setTargetDir(File). + * setting the directory. * @param dir ignored * @throws BuildException always */ public void setDir(File dir) throws BuildException { - throw new BuildException("synctarget doesn't support the dir " + throw new BuildException("preserveintarget doesn't support the dir " + "attribute"); } - private void setTargetDir(File dir) throws BuildException { - super.setDir(dir); - } - } /** diff --git a/src/main/org/apache/tools/ant/types/AbstractFileSet.java b/src/main/org/apache/tools/ant/types/AbstractFileSet.java index 7f57cc52d..1edd24aba 100644 --- a/src/main/org/apache/tools/ant/types/AbstractFileSet.java +++ b/src/main/org/apache/tools/ant/types/AbstractFileSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2004 The Apache Software Foundation + * Copyright 2002-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. @@ -63,7 +63,7 @@ public abstract class AbstractFileSet extends DataType private File dir; private boolean useDefaultExcludes = true; - private boolean isCaseSensitive = true; + private boolean caseSensitive = true; private boolean followSymlinks = true; /** @@ -84,7 +84,7 @@ public abstract class AbstractFileSet extends DataType this.additionalPatterns = fileset.additionalPatterns; this.selectors = fileset.selectors; this.useDefaultExcludes = fileset.useDefaultExcludes; - this.isCaseSensitive = fileset.isCaseSensitive; + this.caseSensitive = fileset.caseSensitive; this.followSymlinks = fileset.followSymlinks; setProject(fileset.getProject()); } @@ -215,6 +215,24 @@ public abstract class AbstractFileSet extends DataType defaultPatterns.setIncludes(includes); } + /** + * Appends includes to the current list of include + * patterns. + * + * @param includes array containing the include patterns. + * @since Ant 1.7 + */ + public void appendIncludes(String[] includes) { + if (isReference()) { + throw tooManyAttributes(); + } + if (includes != null) { + for (int i = 0; i < includes.length; i++) { + defaultPatterns.createInclude().setName(includes[i]); + } + } + } + /** * Appends excludes to the current list of exclude * patterns. @@ -230,6 +248,24 @@ public abstract class AbstractFileSet extends DataType defaultPatterns.setExcludes(excludes); } + /** + * Appends excludes to the current list of include + * patterns. + * + * @param excludes array containing the exclude patterns. + * @since Ant 1.7 + */ + public void appendExcludes(String[] excludes) { + if (isReference()) { + throw tooManyAttributes(); + } + if (excludes != null) { + for (int i = 0; i < excludes.length; i++) { + defaultPatterns.createExclude().setName(excludes[i]); + } + } + } + /** * Sets the File containing the includes patterns. * @@ -266,16 +302,38 @@ public abstract class AbstractFileSet extends DataType this.useDefaultExcludes = useDefaultExcludes; } + /** + * Whether default exclusions should be used or not. + * @since Ant 1.7 + */ + public boolean getDefaultexcludes() { + return (isReference()) + ? getRef(getProject()).getDefaultexcludes() : useDefaultExcludes; + } + /** * Sets case sensitivity of the file system. * * @param isCaseSensitive boolean. */ - public void setCaseSensitive(boolean isCaseSensitive) { + public void setCaseSensitive(boolean caseSensitive) { if (isReference()) { throw tooManyAttributes(); } - this.isCaseSensitive = isCaseSensitive; + this.caseSensitive = caseSensitive; + } + + /** + * Find out if the fileset is case sensitive. + * + * @return boolean indicating whether the fileset is + * case sensitive. + * + * @since Ant 1.7 + */ + public boolean isCaseSensitive() { + return (isReference()) + ? getRef(getProject()).isCaseSensitive() : caseSensitive; } /** @@ -365,16 +423,12 @@ public abstract class AbstractFileSet extends DataType } ds.setBasedir(dir); - final int count = additionalPatterns.size(); - for (int i = 0; i < count; i++) { - Object o = additionalPatterns.elementAt(i); - defaultPatterns.append((PatternSet) o, p); - } + PatternSet ps = mergePatterns(p); p.log(getDataTypeName() + ": Setup scanner in dir " + dir - + " with " + defaultPatterns, Project.MSG_DEBUG); + + " with " + ps, Project.MSG_DEBUG); - ds.setIncludes(defaultPatterns.getIncludePatterns(p)); - ds.setExcludes(defaultPatterns.getExcludePatterns(p)); + ds.setIncludes(ps.getIncludePatterns(p)); + ds.setExcludes(ps.getExcludePatterns(p)); if (ds instanceof SelectorScanner) { SelectorScanner ss = (SelectorScanner) ds; ss.setSelectors(getSelectors(p)); @@ -382,7 +436,7 @@ public abstract class AbstractFileSet extends DataType if (useDefaultExcludes) { ds.addDefaultExcludes(); } - ds.setCaseSensitive(isCaseSensitive); + ds.setCaseSensitive(caseSensitive); } /** @@ -683,4 +737,44 @@ public abstract class AbstractFileSet extends DataType } } + /** + * @return the include patterns of the default pattern set and all + * nested patternsets. + * + * @since Ant 1.7 + */ + public String[] mergeIncludes(Project p) { + return mergePatterns(p).getIncludePatterns(p); + } + + /** + * @return the exclude patterns of the default pattern set and all + * nested patternsets. + * + * @since Ant 1.7 + */ + public String[] mergeExcludes(Project p) { + return mergePatterns(p).getExcludePatterns(p); + } + + /** + * @return the default patternset merged with the additional sets + * in a new PatternSet instance. + * + * @since Ant 1.7 + */ + public PatternSet mergePatterns(Project p) { + if (isReference()) { + return getRef(p).mergePatterns(p); + } + PatternSet ps = new PatternSet(); + ps.append(defaultPatterns, p); + final int count = additionalPatterns.size(); + for (int i = 0; i < count; i++) { + Object o = additionalPatterns.elementAt(i); + ps.append((PatternSet) o, p); + } + return ps; + } + } diff --git a/src/main/org/apache/tools/ant/types/CommandlineJava.java b/src/main/org/apache/tools/ant/types/CommandlineJava.java index 8e0f7b6f6..0759cf684 100644 --- a/src/main/org/apache/tools/ant/types/CommandlineJava.java +++ b/src/main/org/apache/tools/ant/types/CommandlineJava.java @@ -74,7 +74,7 @@ public class CommandlineJava implements Cloneable { * Specialized Environment class for System properties */ public static class SysProperties extends Environment implements Cloneable { - private Properties sys = null; + Properties sys = null; private Vector propertySets = new Vector(); /** diff --git a/src/main/org/apache/tools/ant/types/selectors/NotSelector.java b/src/main/org/apache/tools/ant/types/selectors/NotSelector.java index aa0636b74..d023a72c8 100644 --- a/src/main/org/apache/tools/ant/types/selectors/NotSelector.java +++ b/src/main/org/apache/tools/ant/types/selectors/NotSelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2004 The Apache Software Foundation + * Copyright 2002-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. @@ -34,6 +34,16 @@ public class NotSelector extends NoneSelector { public NotSelector() { } + /** + * Constructor that inverts the meaning of its argument. + * @param other the selector to invert + * @since Ant 1.7 + */ + public NotSelector(FileSelector other) { + this(); + appendSelector(other); + } + /** * @return a string representation of the selector */ diff --git a/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java b/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java index b6675d438..1593abfd4 100755 --- a/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java +++ b/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java @@ -28,6 +28,7 @@ import org.apache.tools.ant.Project; /** * Special PipedInputStream that will not die * when the writing Thread is no longer alive. + * @since Ant 1.6.2 */ public class LeadPipeInputStream extends PipedInputStream { private ProjectComponent managingPc; @@ -39,6 +40,16 @@ public class LeadPipeInputStream extends PipedInputStream { super(); } + /** + * Construct a new LeadPipeInputStream + * with the specified buffer size. + * @param size the size of the circular buffer. + */ + public LeadPipeInputStream(int size) { + super(); + setBufferSize(size); + } + /** * Construct a new LeadPipeInputStream to pull * from the specified PipedOutputStream. @@ -49,6 +60,18 @@ public class LeadPipeInputStream extends PipedInputStream { super(src); } + /** + * Construct a new LeadPipeInputStream to pull + * from the specified PipedOutputStream, using a + * circular buffer of the specified size. + * @param src the PipedOutputStream source. + * @param size the size of the circular buffer. + */ + public LeadPipeInputStream(PipedOutputStream src, int size) throws IOException { + super(src); + setBufferSize(size); + } + //inherit doc public synchronized int read() throws IOException { int result = -1; @@ -68,6 +91,28 @@ public class LeadPipeInputStream extends PipedInputStream { return result; } + /** + * Set the size of the buffer. + * @param size the new buffer size. Ignored if <= current size. + */ + public synchronized void setBufferSize(int size) { + if (size > buffer.length) { + byte[] newBuffer = new byte[size]; + if (in >= 0) { + if (in > out) { + System.arraycopy(buffer, out, newBuffer, out, in - out); + } else { + int outlen = buffer.length - out; + System.arraycopy(buffer, out, newBuffer, 0, outlen); + System.arraycopy(buffer, 0, newBuffer, outlen, in); + in+= outlen; + out = 0; + } + } + buffer = newBuffer; + } + } + /** * Set a managing Task for * this LeadPipeInputStream. diff --git a/src/testcases/org/apache/tools/ant/ProjectTest.java b/src/testcases/org/apache/tools/ant/ProjectTest.java index a2932e3f1..3f60f935b 100644 --- a/src/testcases/org/apache/tools/ant/ProjectTest.java +++ b/src/testcases/org/apache/tools/ant/ProjectTest.java @@ -34,7 +34,7 @@ import junit.framework.TestSuite; /** * Very limited test class for Project. Waiting to be extended. * -*/ + */ public class ProjectTest extends TestCase { private Project p; diff --git a/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java b/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java index a42ce87d2..e6b76d375 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java @@ -70,6 +70,17 @@ public class SyncTest extends BuildFileTest { assertDebuglogContaining("Removed 1 dangling directory from"); } + public void testCopyAndRemoveEmptyPreserve() { + executeTarget("copyandremove-emptypreserve"); + 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"; @@ -92,6 +103,15 @@ public class SyncTest extends BuildFileTest { assertTrue(getFullLog().indexOf("Removing orphan file:") == -1); } + public void testCopyNoRemoveSelectors() { + executeTarget("copynoremove-selectors"); + 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());