git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277591 13f79535-47bb-0310-9956-ffa450edef68master
@@ -158,14 +158,6 @@ | |||
</or> | |||
</selector> | |||
<!-- classes that should be present in Sun based JVMs, but not in | |||
Kaffe for example --> | |||
<selector id="needs.sun.tools"> | |||
<or> | |||
<filename name="${optional.package}/Javah*"/> | |||
</or> | |||
</selector> | |||
<selector id="needs.sun.uue"> | |||
<filename name="${ant.package}/taskdefs/email/UUMailer*"/> | |||
</selector> | |||
@@ -647,7 +639,6 @@ | |||
<selector refid="needs.jdk1.3+" unless="jdk1.3+"/> | |||
<selector refid="needs.jdk1.4+" unless="jdk1.4+"/> | |||
<selector refid="needs.jdk1.5+" unless="jdk1.5+"/> | |||
<selector refid="needs.sun.tools" unless="sun.tools.present"/> | |||
<selector refid="needs.sun.uue" unless="sunuue.present"/> | |||
<selector refid="needs.sun.b64" unless="base64.present"/> | |||
@@ -1670,4 +1661,4 @@ | |||
description="--> creates a minimum distribution in ./dist" | |||
depends="dist-lite"/> | |||
</project> | |||
</project> |
@@ -35,6 +35,17 @@ | |||
</sync> | |||
</target> | |||
<target name="copyandremove-emptypreserve" 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}"/> | |||
<preserveintarget/> | |||
</sync> | |||
</target> | |||
<target name="emptycopy" depends="setup"> | |||
<mkdir dir="${src}/a/b/c"/> | |||
<touch file="${src}/a/b/c/d"/> | |||
@@ -69,9 +80,22 @@ | |||
<touch file="${dest}/e/f"/> | |||
<sync todir="${dest}"> | |||
<fileset dir="${src}"/> | |||
<deletefromtarget> | |||
<exclude name="e/f"/> | |||
</deletefromtarget> | |||
<preserveintarget> | |||
<include name="e/f"/> | |||
</preserveintarget> | |||
</sync> | |||
</target> | |||
<target name="copynoremove-selectors" 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}"/> | |||
<preserveintarget> | |||
<filename name="e/f"/> | |||
</preserveintarget> | |||
</sync> | |||
</target> | |||
@@ -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 <none> 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. | |||
* | |||
* <p>You must not invoke this method more than once.</p> | |||
* @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); | |||
} | |||
} | |||
/** | |||
@@ -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 <code>includes</code> 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 <code>excludes</code> to the current list of exclude | |||
* patterns. | |||
@@ -230,6 +248,24 @@ public abstract class AbstractFileSet extends DataType | |||
defaultPatterns.setExcludes(excludes); | |||
} | |||
/** | |||
* Appends <code>excludes</code> 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 <code>File</code> 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 <code>boolean</code>. | |||
*/ | |||
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 <code>boolean</code> 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; | |||
} | |||
} |
@@ -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(); | |||
/** | |||
@@ -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 | |||
*/ | |||
@@ -28,6 +28,7 @@ import org.apache.tools.ant.Project; | |||
/** | |||
* Special <CODE>PipedInputStream</CODE> that will not die | |||
* when the writing <CODE>Thread</CODE> 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 <CODE>LeadPipeInputStream</CODE> | |||
* with the specified buffer size. | |||
* @param size the size of the circular buffer. | |||
*/ | |||
public LeadPipeInputStream(int size) { | |||
super(); | |||
setBufferSize(size); | |||
} | |||
/** | |||
* Construct a new <CODE>LeadPipeInputStream</CODE> to pull | |||
* from the specified <CODE>PipedOutputStream</CODE>. | |||
@@ -49,6 +60,18 @@ public class LeadPipeInputStream extends PipedInputStream { | |||
super(src); | |||
} | |||
/** | |||
* Construct a new <CODE>LeadPipeInputStream</CODE> to pull | |||
* from the specified <CODE>PipedOutputStream</CODE>, using a | |||
* circular buffer of the specified size. | |||
* @param src the <CODE>PipedOutputStream</CODE> 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 <CODE>Task</CODE> for | |||
* this <CODE>LeadPipeInputStream</CODE>. | |||
@@ -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; | |||
@@ -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()); | |||