Browse Source

Turn <deleteFromTarget> into <preserveInTarget> in <sync>

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277591 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 20 years ago
parent
commit
a799f17a4e
9 changed files with 250 additions and 43 deletions
  1. +1
    -10
      build.xml
  2. +27
    -3
      src/etc/testcases/taskdefs/sync.xml
  3. +36
    -13
      src/main/org/apache/tools/ant/taskdefs/Sync.java
  4. +108
    -14
      src/main/org/apache/tools/ant/types/AbstractFileSet.java
  5. +1
    -1
      src/main/org/apache/tools/ant/types/CommandlineJava.java
  6. +11
    -1
      src/main/org/apache/tools/ant/types/selectors/NotSelector.java
  7. +45
    -0
      src/main/org/apache/tools/ant/util/LeadPipeInputStream.java
  8. +1
    -1
      src/testcases/org/apache/tools/ant/ProjectTest.java
  9. +20
    -0
      src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java

+ 1
- 10
build.xml View File

@@ -158,14 +158,6 @@
</or> </or>
</selector> </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"> <selector id="needs.sun.uue">
<filename name="${ant.package}/taskdefs/email/UUMailer*"/> <filename name="${ant.package}/taskdefs/email/UUMailer*"/>
</selector> </selector>
@@ -647,7 +639,6 @@
<selector refid="needs.jdk1.3+" unless="jdk1.3+"/> <selector refid="needs.jdk1.3+" unless="jdk1.3+"/>
<selector refid="needs.jdk1.4+" unless="jdk1.4+"/> <selector refid="needs.jdk1.4+" unless="jdk1.4+"/>
<selector refid="needs.jdk1.5+" unless="jdk1.5+"/> <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.uue" unless="sunuue.present"/>
<selector refid="needs.sun.b64" unless="base64.present"/> <selector refid="needs.sun.b64" unless="base64.present"/>


@@ -1670,4 +1661,4 @@
description="--> creates a minimum distribution in ./dist" description="--> creates a minimum distribution in ./dist"
depends="dist-lite"/> depends="dist-lite"/>


</project>
</project>

+ 27
- 3
src/etc/testcases/taskdefs/sync.xml View File

@@ -35,6 +35,17 @@
</sync> </sync>
</target> </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"> <target name="emptycopy" depends="setup">
<mkdir dir="${src}/a/b/c"/> <mkdir dir="${src}/a/b/c"/>
<touch file="${src}/a/b/c/d"/> <touch file="${src}/a/b/c/d"/>
@@ -69,9 +80,22 @@
<touch file="${dest}/e/f"/> <touch file="${dest}/e/f"/>
<sync todir="${dest}"> <sync todir="${dest}">
<fileset dir="${src}"/> <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> </sync>
</target> </target>



+ 36
- 13
src/main/org/apache/tools/ant/taskdefs/Sync.java View File

@@ -34,6 +34,9 @@ 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.AbstractFileSet;
import org.apache.tools.ant.types.FileSet; 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 * Synchronize a local target directory from the files defined
@@ -163,8 +166,33 @@ public class Sync extends Task {


DirectoryScanner ds = null; DirectoryScanner ds = null;
if (syncTarget != 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 { } else {
ds = new DirectoryScanner(); ds = new DirectoryScanner();
ds.setBasedir(toDir); ds.setBasedir(toDir);
@@ -180,7 +208,7 @@ public class Sync extends Task {
++removedCount[1]; ++removedCount[1];
} }
String[] dirs = ds.getIncludedDirectories(); 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 // iterating through the array backwards means we are deleting
// leaves before their parent nodes - thus making sure (well, // leaves before their parent nodes - thus making sure (well,
// more likely) that the directories are empty when we try to // 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. * are not present in any source directory.
* *
* <p>You must not invoke this method more than once.</p> * <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 * @since Ant 1.7
*/ */
public void addDeleteFromTarget(SyncTarget s) {
public void addPreserveInTarget(SyncTarget s) {
if (syncTarget != null) { if (syncTarget != null) {
throw new BuildException("you must not specify multiple " throw new BuildException("you must not specify multiple "
+ "deletefromtaget elements.");
+ "preserveintarget elements.");
} }
syncTarget = s; syncTarget = s;
} }
@@ -381,24 +409,19 @@ public class Sync extends Task {
*/ */
public SyncTarget() { public SyncTarget() {
super(); super();
setDefaultexcludes(false);
} }


/** /**
* Override AbstractFileSet#setDir(File) to disallow * Override AbstractFileSet#setDir(File) to disallow
* setting the directory. This is now set by #setTargetDir(File).
* setting the directory.
* @param dir ignored * @param dir ignored
* @throws BuildException always * @throws BuildException always
*/ */
public void setDir(File dir) throws BuildException { 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"); + "attribute");
} }


private void setTargetDir(File dir) throws BuildException {
super.setDir(dir);
}

} }


/** /**


+ 108
- 14
src/main/org/apache/tools/ant/types/AbstractFileSet.java View File

@@ -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"); * 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.
@@ -63,7 +63,7 @@ public abstract class AbstractFileSet extends DataType


private File dir; private File dir;
private boolean useDefaultExcludes = true; private boolean useDefaultExcludes = true;
private boolean isCaseSensitive = true;
private boolean caseSensitive = true;
private boolean followSymlinks = true; private boolean followSymlinks = true;


/** /**
@@ -84,7 +84,7 @@ public abstract class AbstractFileSet extends DataType
this.additionalPatterns = fileset.additionalPatterns; this.additionalPatterns = fileset.additionalPatterns;
this.selectors = fileset.selectors; this.selectors = fileset.selectors;
this.useDefaultExcludes = fileset.useDefaultExcludes; this.useDefaultExcludes = fileset.useDefaultExcludes;
this.isCaseSensitive = fileset.isCaseSensitive;
this.caseSensitive = fileset.caseSensitive;
this.followSymlinks = fileset.followSymlinks; this.followSymlinks = fileset.followSymlinks;
setProject(fileset.getProject()); setProject(fileset.getProject());
} }
@@ -215,6 +215,24 @@ public abstract class AbstractFileSet extends DataType
defaultPatterns.setIncludes(includes); 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 * Appends <code>excludes</code> to the current list of exclude
* patterns. * patterns.
@@ -230,6 +248,24 @@ public abstract class AbstractFileSet extends DataType
defaultPatterns.setExcludes(excludes); 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. * Sets the <code>File</code> containing the includes patterns.
* *
@@ -266,16 +302,38 @@ public abstract class AbstractFileSet extends DataType
this.useDefaultExcludes = useDefaultExcludes; 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. * Sets case sensitivity of the file system.
* *
* @param isCaseSensitive <code>boolean</code>. * @param isCaseSensitive <code>boolean</code>.
*/ */
public void setCaseSensitive(boolean isCaseSensitive) {
public void setCaseSensitive(boolean caseSensitive) {
if (isReference()) { if (isReference()) {
throw tooManyAttributes(); 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); 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 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) { if (ds instanceof SelectorScanner) {
SelectorScanner ss = (SelectorScanner) ds; SelectorScanner ss = (SelectorScanner) ds;
ss.setSelectors(getSelectors(p)); ss.setSelectors(getSelectors(p));
@@ -382,7 +436,7 @@ public abstract class AbstractFileSet extends DataType
if (useDefaultExcludes) { if (useDefaultExcludes) {
ds.addDefaultExcludes(); 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;
}

} }

+ 1
- 1
src/main/org/apache/tools/ant/types/CommandlineJava.java View File

@@ -74,7 +74,7 @@ public class CommandlineJava implements Cloneable {
* Specialized Environment class for System properties * Specialized Environment class for System properties
*/ */
public static class SysProperties extends Environment implements Cloneable { public static class SysProperties extends Environment implements Cloneable {
private Properties sys = null;
Properties sys = null;
private Vector propertySets = new Vector(); private Vector propertySets = new Vector();


/** /**


+ 11
- 1
src/main/org/apache/tools/ant/types/selectors/NotSelector.java View File

@@ -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"); * 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.
@@ -34,6 +34,16 @@ public class NotSelector extends NoneSelector {
public NotSelector() { 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 * @return a string representation of the selector
*/ */


+ 45
- 0
src/main/org/apache/tools/ant/util/LeadPipeInputStream.java View File

@@ -28,6 +28,7 @@ import org.apache.tools.ant.Project;
/** /**
* Special <CODE>PipedInputStream</CODE> that will not die * Special <CODE>PipedInputStream</CODE> that will not die
* when the writing <CODE>Thread</CODE> is no longer alive. * when the writing <CODE>Thread</CODE> is no longer alive.
* @since Ant 1.6.2
*/ */
public class LeadPipeInputStream extends PipedInputStream { public class LeadPipeInputStream extends PipedInputStream {
private ProjectComponent managingPc; private ProjectComponent managingPc;
@@ -39,6 +40,16 @@ public class LeadPipeInputStream extends PipedInputStream {
super(); 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 * Construct a new <CODE>LeadPipeInputStream</CODE> to pull
* from the specified <CODE>PipedOutputStream</CODE>. * from the specified <CODE>PipedOutputStream</CODE>.
@@ -49,6 +60,18 @@ public class LeadPipeInputStream extends PipedInputStream {
super(src); 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 //inherit doc
public synchronized int read() throws IOException { public synchronized int read() throws IOException {
int result = -1; int result = -1;
@@ -68,6 +91,28 @@ public class LeadPipeInputStream extends PipedInputStream {
return result; 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 * Set a managing <CODE>Task</CODE> for
* this <CODE>LeadPipeInputStream</CODE>. * this <CODE>LeadPipeInputStream</CODE>.


+ 1
- 1
src/testcases/org/apache/tools/ant/ProjectTest.java View File

@@ -34,7 +34,7 @@ import junit.framework.TestSuite;
/** /**
* Very limited test class for Project. Waiting to be extended. * Very limited test class for Project. Waiting to be extended.
* *
*/
*/
public class ProjectTest extends TestCase { public class ProjectTest extends TestCase {


private Project p; private Project p;


+ 20
- 0
src/testcases/org/apache/tools/ant/taskdefs/SyncTest.java View File

@@ -70,6 +70,17 @@ public class SyncTest extends BuildFileTest {
assertDebuglogContaining("Removed 1 dangling directory from"); 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() { public void testEmptyDirCopyAndRemove() {
executeTarget("emptydircopyandremove"); executeTarget("emptydircopyandremove");
String d = getProject().getProperty("dest") + "/a/b/c/d"; 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); 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) { public void assertFileIsPresent(String f) {
assertTrue("Expected file " + f, assertTrue("Expected file " + f,
getProject().resolveFile(f).exists()); getProject().resolveFile(f).exists());


Loading…
Cancel
Save