git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@278120 13f79535-47bb-0310-9956-ffa450edef68master
@@ -605,6 +605,23 @@ Probe for the maven repository being reachable. | |||
<p> | |||
Probe for the maven repository being reachable using the hostname, ten second timeout.. | |||
</p> | |||
<h4>length</h4> | |||
<p>This condition is a facet of the <a href="length.html">Length</a> task. | |||
It is used to test the length of a string or one or more files. | |||
<b>Since Ant 1.6.3</b> | |||
</p> | |||
Verify a string is of a certain length: | |||
<pre> | |||
<length string=" foo " trim="true" length="3"/> | |||
</pre> | |||
Verify a file is not empty: | |||
<pre> | |||
<length file="foo" when="greater" length="0"/> | |||
</pre> | |||
<hr> | |||
<p align="center">Copyright © 2001-2005 Apache Software | |||
Foundation. All rights Reserved.</p> | |||
@@ -11,7 +11,8 @@ | |||
<h2>Length</h2> | |||
<h3>Description</h3> | |||
<p>Display or set a property containing length information for | |||
a string, a file, or one or more nested filesets.</p> | |||
a string, a file, or one or more nested filesets. Can also | |||
be used as a condition. <b>Since Ant 1.6.3</b></p> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
@@ -22,7 +23,8 @@ | |||
<tr> | |||
<td valign="top">property</td> | |||
<td valign="top">The property to set. If omitted | |||
the length is written to the log.</td> | |||
the results are written to the log. Ignored when | |||
processing as a condition.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
@@ -40,7 +42,7 @@ | |||
<td valign="top">File length mode; when "all" the resulting | |||
value is the sum of all included files' lengths; when "each" | |||
the task outputs the absolute path and length of each included file, | |||
one per line.</td> | |||
one per line. Ignored when processing as a condition.</td> | |||
<td valign="top" align="center">No; default is "all"</td> | |||
</tr> | |||
<tr> | |||
@@ -48,6 +50,17 @@ | |||
<td valign="top">Whether to trim when operating on a string.</td> | |||
<td valign="top" align="center">No; only valid when string is set</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">length</td> | |||
<td valign="top">Comparison length for processing as a condition.</td> | |||
<td valign="top" align="center">Yes, in condition mode</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">when</td> | |||
<td valign="top">Comparison type: "equal", "greater", "less" | |||
for use when operating as a condition.</td> | |||
<td valign="top" align="center">No; default is "equal"</td> | |||
</tr> | |||
</table> | |||
<h3>Parameters specified as nested elements</h3> | |||
<h4>fileset</h4><p>You can include files via nested | |||
@@ -35,6 +35,27 @@ | |||
</fail> | |||
</target> | |||
<target name="testEachCondition" depends="init"> | |||
<length mode="each" property="length.each"> | |||
<fileset id="fs" dir="${dir}" /> | |||
</length> | |||
<length string="${foo}${bar}........${line.separator}" | |||
property="length.expected" /> | |||
<fail> | |||
<!-- test that both files are represented, and that the | |||
output is the expected length; do not assume order. --> | |||
<condition> | |||
<not> | |||
<and> | |||
<contains string="${length.each}" substring="${foo} : 3" /> | |||
<contains string="${length.each}" substring="${bar} : 3" /> | |||
<length string="${length.each}" length="${length.expected}" /> | |||
</and> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testAll" depends="init"> | |||
<length property="length.all"> | |||
<fileset id="foo" file="${dir.a}/foo" /> | |||
@@ -49,6 +70,19 @@ | |||
</fail> | |||
</target> | |||
<target name="testAllCondition" depends="init"> | |||
<fail> | |||
<condition> | |||
<not> | |||
<length length="6"> | |||
<fileset id="foo" file="${dir.a}/foo" /> | |||
<fileset id="bar" file="${dir.b}/bar" /> | |||
</length> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testFile" depends="init"> | |||
<length property="length.foo" file="${dir.a}/foo" /> | |||
<fail> | |||
@@ -60,6 +94,16 @@ | |||
</fail> | |||
</target> | |||
<target name="testFileCondition" depends="init"> | |||
<fail> | |||
<condition> | |||
<not> | |||
<length length="3" file="${dir.a}/foo" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testBoth" depends="init"> | |||
<length property="length.foo" file="${dir.a}/foo"> | |||
<fileset file="${dir.b}/bar" /> | |||
@@ -73,6 +117,18 @@ | |||
</fail> | |||
</target> | |||
<target name="testBothCondition" depends="init"> | |||
<fail> | |||
<condition> | |||
<not> | |||
<length length="6" file="${dir.a}/foo"> | |||
<fileset file="${dir.b}/bar" /> | |||
</length> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testDupes" depends="init"> | |||
<length property="length.foo" file="${dir.a}/foo"> | |||
<fileset dir="${dir}" /> | |||
@@ -80,7 +136,19 @@ | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="6" arg2="${length.foo}" /> | |||
<equals arg1="9" arg2="${length.foo}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testDupesCondition" depends="init"> | |||
<fail> | |||
<condition> | |||
<not> | |||
<length length="9" file="${dir.a}/foo"> | |||
<fileset dir="${dir}" /> | |||
</length> | |||
</not> | |||
</condition> | |||
</fail> | |||
@@ -97,6 +165,58 @@ | |||
</fail> | |||
</target> | |||
<target name="testStringCondition"> | |||
<fail> | |||
<condition> | |||
<not> | |||
<length string="foo" length="3" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testTrimString"> | |||
<length string=" foo " trim="true" property="length.string" /> | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="3" arg2="${length.string}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testTrimStringCondition"> | |||
<fail> | |||
<condition> | |||
<not> | |||
<length string=" foo " trim="true" length="3" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testNoTrimString"> | |||
<length string=" foo " property="length.string" /> | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="5" arg2="${length.string}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testNoTrimStringCondition"> | |||
<fail> | |||
<condition> | |||
<not> | |||
<length string=" foo " length="5" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testTrimFile" description="should fail"> | |||
<length file="${ant.file}" trim="false" /> | |||
</target> | |||
@@ -117,11 +237,14 @@ | |||
</fail> | |||
</target> | |||
<target name="testZipFileSet" depends="init"> | |||
<target name="zip" depends="init"> | |||
<zip destfile="${zipfile}"> | |||
<fileset file="${foo}" /> | |||
<fileset file="${bar}" /> | |||
</zip> | |||
</target> | |||
<target name="testZipFileSet" depends="zip"> | |||
<length property="length.zipfile1"> | |||
<zipfileset src="${zipfile}" /> | |||
</length> | |||
@@ -140,6 +263,23 @@ | |||
</fail> | |||
</target> | |||
<target name="testZipFileSetCondition" depends="zip"> | |||
<fail> | |||
<condition> | |||
<not> | |||
<and> | |||
<length length="6"> | |||
<zipfileset src="${zipfile}" /> | |||
</length> | |||
<length length="3"> | |||
<zipfileset src="${zipfile}" includes="bar" /> | |||
</length> | |||
</and> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="cleanup"> | |||
<delete dir="${dir}" /> | |||
<delete file="${zipfile}" /> | |||
@@ -22,33 +22,39 @@ import java.io.PrintStream; | |||
import java.io.OutputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.util.Vector; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.taskdefs.condition.Condition; | |||
import org.apache.tools.ant.types.FileSet; | |||
import org.apache.tools.ant.types.Resource; | |||
import org.apache.tools.ant.types.EnumeratedAttribute; | |||
import org.apache.tools.ant.util.FileUtils; | |||
/** | |||
* Gets lengths: of files, byte size; of strings, length (optionally trimmed). | |||
* Gets lengths: of files/resources, byte size; of strings, length (optionally trimmed). | |||
* The task is overloaded in this way for semantic reasons, much like Available. | |||
* @since Ant 1.6.3 | |||
*/ | |||
public class Length extends Task { | |||
public class Length extends Task implements Condition { | |||
private static final String ALL = "all"; | |||
private static final String EACH = "each"; | |||
private static final String STRING = "string"; | |||
private static final String LENGTH_REQUIRED | |||
= "Use of the Length condition requires that the length attribute be set."; | |||
private String property; | |||
private String string; | |||
private Boolean trim; | |||
private Vector filesets; | |||
private String mode = ALL; | |||
private When when = When.EQUAL; | |||
private Long length; | |||
private Vector filesets; | |||
/** | |||
* The property in which the length will be stored. | |||
@@ -73,10 +79,30 @@ public class Length extends Task { | |||
* @param fs the <code>FileSet</code> to add. | |||
*/ | |||
public synchronized void add(FileSet fs) { | |||
if (fs == null) { | |||
return; | |||
} | |||
filesets = (filesets == null) ? new Vector() : filesets; | |||
filesets.add(fs); | |||
} | |||
/** | |||
* Set the target count number for use as a Condition. | |||
* @param ell the long length to compare with. | |||
*/ | |||
public synchronized void setLength(long ell) { | |||
length = new Long(ell); | |||
} | |||
/** | |||
* Set the comparison criteria for use as a Condition: | |||
* "equal", "greater", "less". Default is "equal". | |||
* @param w EnumeratedAttribute When. | |||
*/ | |||
public synchronized void setWhen(When w) { | |||
when = w; | |||
} | |||
/** | |||
* Set the execution mode for working with files. | |||
* @param m the <code>FileMode</code> to use. | |||
@@ -102,6 +128,14 @@ public class Length extends Task { | |||
this.trim = trim ? Boolean.TRUE : Boolean.FALSE; | |||
} | |||
/** | |||
* Learn whether strings will be trimmed. | |||
* @return boolean trim setting. | |||
*/ | |||
public boolean getTrim() { | |||
return trim != null && trim.booleanValue(); | |||
} | |||
/** | |||
* Execute the length task. | |||
*/ | |||
@@ -112,14 +146,38 @@ public class Length extends Task { | |||
: (OutputStream) new LogOutputStream(this, Project.MSG_INFO)); | |||
if (STRING.equals(mode)) { | |||
ps.print(((trim != null && trim.booleanValue()) | |||
? string.trim() : string).length()); | |||
ps.print(getLength(string, getTrim())); | |||
ps.close(); | |||
} else if (EACH.equals(mode)) { | |||
handleFilesets(new EachHandler(ps)); | |||
handleResources(new EachHandler(ps)); | |||
} else if (ALL.equals(mode)) { | |||
handleFilesets(new AllHandler(ps)); | |||
handleResources(new AllHandler(ps)); | |||
} | |||
} | |||
/** | |||
* Fulfill the condition contract. | |||
* @return true if the condition is true. | |||
* @throws BuildException if an error occurs. | |||
*/ | |||
public boolean eval() { | |||
validate(); | |||
if (length == null) { | |||
throw new BuildException(LENGTH_REQUIRED); | |||
} | |||
Long ell = null; | |||
if (STRING.equals(mode)) { | |||
ell = new Long(getLength(string, getTrim())); | |||
} else { | |||
ConditionHandler h = new ConditionHandler(); | |||
handleResources(h); | |||
ell = new Long(h.getLength()); | |||
} | |||
int w = when.getIndex(); | |||
int comp = ell.compareTo(length); | |||
return (w == 0 && comp == 0) | |||
|| (w == 1 && comp > 0) | |||
|| (w == 2 && comp < 0); | |||
} | |||
private void validate() { | |||
@@ -130,9 +188,9 @@ public class Length extends Task { | |||
} | |||
if (!(STRING.equals(mode))) { | |||
throw new BuildException("the mode attribute is for use" | |||
+ " with the file length function"); | |||
+ " with the file/resource length function"); | |||
} | |||
} else if (filesets != null && filesets.size() > 0) { | |||
} else if (filesets != null) { | |||
if (!(EACH.equals(mode) || ALL.equals(mode))) { | |||
throw new BuildException("invalid mode setting for" | |||
+ " file length function: \"" + mode + "\""); | |||
@@ -147,10 +205,9 @@ public class Length extends Task { | |||
} | |||
} | |||
private void handleFilesets(Handler h) { | |||
HashSet included = new HashSet(filesets.size()); | |||
for (int i = 0; i < filesets.size(); i++) { | |||
FileSet fs = (FileSet) (filesets.get(i)); | |||
private void handleResources(Handler h) { | |||
for (Iterator i = filesets.iterator(); i.hasNext();) { | |||
FileSet fs = (FileSet) i.next(); | |||
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||
String[] f = ds.getIncludedFiles(); | |||
for (int j = 0; j < f.length; j++) { | |||
@@ -161,24 +218,22 @@ public class Length extends Task { | |||
log(r.getName() + " is a directory; length unspecified", | |||
Project.MSG_ERR); | |||
} else { | |||
//clone the Resource and alter path | |||
//force a full path: | |||
File basedir = ds.getBasedir(); | |||
if (basedir != null) { | |||
r = (Resource) (r.clone()); | |||
r.setName(FileUtils.getFileUtils().resolveFile( | |||
basedir, r.getName()).getAbsolutePath()); | |||
} | |||
if (included.add(r.getName())) { | |||
h.handle(r); | |||
} | |||
String s = FileUtils.getFileUtils().resolveFile( | |||
basedir, r.getName()).getAbsolutePath(); | |||
h.handle(new Resource(s, true, | |||
r.getLastModified(), false, r.getSize())); | |||
} | |||
} | |||
} | |||
included.clear(); | |||
included = null; | |||
h.complete(); | |||
} | |||
private static long getLength(String s, boolean t) { | |||
return (t ? s.trim() : s).length(); | |||
} | |||
/** EnumeratedAttribute operation mode */ | |||
public static class FileMode extends EnumeratedAttribute { | |||
static final String[] MODES = new String[] {EACH, ALL}; | |||
@@ -193,6 +248,25 @@ public class Length extends Task { | |||
} | |||
/** | |||
* EnumeratedAttribute for the when attribute. | |||
*/ | |||
public static class When extends EnumeratedAttribute { | |||
private static final String[] VALUES | |||
= new String[] {"equal", "greater", "less"}; | |||
private static final When EQUAL = new When("equal"); | |||
public When() { | |||
} | |||
public When(String value) { | |||
setValue(value); | |||
} | |||
public String[] getValues() { | |||
return VALUES; | |||
} | |||
} | |||
private class PropertyOutputStream extends ByteArrayOutputStream { | |||
public void close() { | |||
getProject().setNewProperty( | |||
@@ -231,7 +305,7 @@ public class Length extends Task { | |||
} | |||
private class AllHandler extends Handler { | |||
long length = 0L; | |||
long accum = 0L; | |||
AllHandler(PrintStream ps) { | |||
super(ps); | |||
} | |||
@@ -240,12 +314,23 @@ public class Length extends Task { | |||
if (size == Resource.UNKNOWN_SIZE) { | |||
log("Size unknown for " + r.getName(), Project.MSG_WARN); | |||
} else { | |||
length += size; | |||
accum += size; | |||
} | |||
} | |||
void complete() { | |||
ps.print(length); | |||
ps.print(accum); | |||
super.complete(); | |||
} | |||
} | |||
private class ConditionHandler extends AllHandler { | |||
ConditionHandler() { | |||
super(null); | |||
} | |||
void complete() { | |||
} | |||
long getLength() { | |||
return accum; | |||
} | |||
} | |||
} |
@@ -37,26 +37,66 @@ public class LengthTest extends BuildFileTest { | |||
executeTarget("testEach"); | |||
} | |||
public void testEachCondition() { | |||
executeTarget("testEachCondition"); | |||
} | |||
public void testAll() { | |||
executeTarget("testAll"); | |||
} | |||
public void testAllCondition() { | |||
executeTarget("testAllCondition"); | |||
} | |||
public void testFile() { | |||
executeTarget("testFile"); | |||
} | |||
public void testFileCondition() { | |||
executeTarget("testFileCondition"); | |||
} | |||
public void testBoth() { | |||
executeTarget("testBoth"); | |||
} | |||
public void testBothCondition() { | |||
executeTarget("testBothCondition"); | |||
} | |||
public void testDupes() { | |||
executeTarget("testDupes"); | |||
} | |||
public void testDupesCondition() { | |||
executeTarget("testDupesCondition"); | |||
} | |||
public void testString() { | |||
executeTarget("testString"); | |||
} | |||
public void testStringCondition() { | |||
executeTarget("testStringCondition"); | |||
} | |||
public void testTrimString() { | |||
executeTarget("testTrimString"); | |||
} | |||
public void testTrimStringCondition() { | |||
executeTarget("testTrimStringCondition"); | |||
} | |||
public void testNoTrimString() { | |||
executeTarget("testNoTrimString"); | |||
} | |||
public void testNoTrimStringCondition() { | |||
executeTarget("testNoTrimStringCondition"); | |||
} | |||
public void testStringFile() { | |||
expectBuildExceptionContaining("testStringFile", | |||
"should fail", "incompatible"); | |||
@@ -74,4 +114,9 @@ public class LengthTest extends BuildFileTest { | |||
public void testZipFileSet() { | |||
executeTarget("testZipFileSet"); | |||
} | |||
public void testZipFileSetCondition() { | |||
executeTarget("testZipFileSetCondition"); | |||
} | |||
} |