git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277277 13f79535-47bb-0310-9956-ffa450edef68master
@@ -110,6 +110,8 @@ Other changes: | |||
* Added support to the touch task for a verbose attribute to suppress | |||
logging of new file creation. | |||
* Added length task to get strings' and files' lengths. | |||
Changes from Ant 1.6.2 to current Ant 1.6 CVS version | |||
===================================================== | |||
@@ -0,0 +1,68 @@ | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Language" content="en-us"> | |||
<title>Length Task</title> | |||
</head> | |||
<body> | |||
<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> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
<td valign="top"><b>Attribute</b></td> | |||
<td valign="top"><b>Description</b></td> | |||
<td align="center" valign="top"><b>Required</b></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">property</td> | |||
<td valign="top">The property to set. If omitted | |||
the length is written to the log.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">file</td> | |||
<td valign="top">Single file whose length to report.</td> | |||
<td valign="top" align="center" rowspan="2">One of these, | |||
or one or more nested filesets</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">string</td> | |||
<td valign="top">The string whose length to report.</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">mode</td> | |||
<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> | |||
<td valign="top" align="center">No; default is "all"</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">trim</td> | |||
<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> | |||
</table> | |||
<h3>Parameters specified as nested elements</h3> | |||
<h4>fileset</h4><p>You can include files via nested | |||
<a href="../CoreTypes/fileset.html">fileset</a>s.</p> | |||
<h3>Examples</h3> | |||
<pre><length string="foo" property="length.foo" /> | |||
</pre> | |||
<p>Stores the length of the string "foo" in the property named | |||
<i>length.foo</i>.</p> | |||
<pre><length file="bar" property="length.bar" /> | |||
</pre> | |||
<p>Stores the length of file "bar" in the property named | |||
<i>length.bar</i>.</p> | |||
<hr /> | |||
<p align="center">Copyright © 2005 The Apache Software Foundation. | |||
All rights Reserved.</p> | |||
</body> | |||
</html> | |||
@@ -59,6 +59,7 @@ | |||
<a href="CoreTasks/java.html">Java</a><br> | |||
<a href="CoreTasks/javac.html">Javac</a><br> | |||
<a href="CoreTasks/javadoc.html">Javadoc/<i>Javadoc2</i></a><br> | |||
<a href="CoreTasks/length.html">Length</a><br> | |||
<a href="CoreTasks/loadfile.html">LoadFile</a><br> | |||
<a href="CoreTasks/loadproperties.html">LoadProperties</a><br> | |||
<a href="CoreTasks/mail.html">Mail</a><br> | |||
@@ -0,0 +1,103 @@ | |||
<project name="length"> | |||
<property name="dir" location="lengthtestdir" /> | |||
<property name="dir.a" location="${dir}/a" /> | |||
<property name="dir.b" location="${dir}/b" /> | |||
<target name="init"> | |||
<mkdir dir="${dir.a}" /> | |||
<mkdir dir="${dir.b}" /> | |||
<concat destfile="${dir.a}/foo">foo</concat> | |||
<concat destfile="${dir.b}/bar">bar</concat> | |||
</target> | |||
<target name="testEach" depends="init"> | |||
<length mode="each" property="length.each"> | |||
<fileset id="fs" dir="${dir}" /> | |||
</length> | |||
<pathconvert property="expected" refid="fs" pathsep="${line.separator}"> | |||
<globmapper from="*" to="* : 3" /> | |||
</pathconvert> | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="${expected}" arg2="${length.each}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testAll" depends="init"> | |||
<length property="length.all"> | |||
<fileset id="foo" file="${dir.a}/foo" /> | |||
<fileset id="bar" file="${dir.b}/bar" /> | |||
</length> | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="6" arg2="${length.all}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testFile" depends="init"> | |||
<length property="length.foo" file="${dir.a}/foo" /> | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="3" arg2="${length.foo}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testBoth" depends="init"> | |||
<length property="length.foo" file="${dir.a}/foo"> | |||
<fileset file="${dir.b}/bar" /> | |||
</length> | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="6" arg2="${length.foo}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testDupes" depends="init"> | |||
<length property="length.foo" file="${dir.a}/foo"> | |||
<fileset dir="${dir}" /> | |||
</length> | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="6" arg2="${length.foo}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testString"> | |||
<length string="foo" property="length.string" /> | |||
<fail> | |||
<condition> | |||
<not> | |||
<equals arg1="3" arg2="${length.string}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="testTrimFile" description="should fail"> | |||
<length file="${ant.file}" trim="false" /> | |||
</target> | |||
<target name="testStringFile" description="should fail"> | |||
<length string="foo" file="${ant.file}" /> | |||
</target> | |||
<target name="cleanup"> | |||
<delete dir="${dir}" /> | |||
</target> | |||
</project> |
@@ -0,0 +1,239 @@ | |||
/* | |||
* Copyright 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. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
import java.io.File; | |||
import java.io.PrintStream; | |||
import java.io.OutputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.util.Arrays; | |||
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.dispatch.Dispatchable; | |||
import org.apache.tools.ant.types.FileSet; | |||
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). | |||
* The task is overloaded in this way for semantic reasons, much like Available. | |||
* @since Ant 1.7 | |||
*/ | |||
public class Length extends Task { | |||
private static final String ALL = "all"; | |||
private static final String EACH = "each"; | |||
private static final String STRING = "string"; | |||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||
private String property; | |||
private String string; | |||
private Boolean trim; | |||
private Vector filesets; | |||
private String mode = ALL; | |||
/** | |||
* The property in which the length will be stored. | |||
* @param property the <code>String</code> property key. | |||
*/ | |||
public synchronized void setProperty(String property) { | |||
this.property = property; | |||
} | |||
/** | |||
* Set the single file for this task. | |||
* @param file the <code>File</code> whose length to retrieve. | |||
*/ | |||
public synchronized void setFile(File file) { | |||
FileSet fs = new FileSet(); | |||
fs.setFile(file); | |||
add(fs); | |||
} | |||
/** | |||
* Add a FileSet. | |||
* @param fs the <code>FileSet</code> to add. | |||
*/ | |||
public synchronized void add(FileSet fs) { | |||
filesets = (filesets == null) ? new Vector() : filesets; | |||
filesets.add(fs); | |||
} | |||
/** | |||
* Set the execution mode for working with files. | |||
* @param m the <code>FileMode</code> to use. | |||
*/ | |||
public synchronized void setMode(FileMode m) { | |||
this.mode = m.getValue(); | |||
} | |||
/** | |||
* Set the string whose length to get. | |||
* @param string <code>String</code>. | |||
*/ | |||
public synchronized void setString(String string) { | |||
this.string = string; | |||
this.mode = STRING; | |||
} | |||
/** | |||
* Set whether to trim in string mode. | |||
* @param trim <code>boolean</code>. | |||
*/ | |||
public synchronized void setTrim(boolean trim) { | |||
this.trim = trim ? Boolean.TRUE : Boolean.FALSE; | |||
} | |||
/** | |||
* Execute the length task. | |||
*/ | |||
public void execute() { | |||
validate(); | |||
PrintStream ps = new PrintStream((property != null) | |||
? (OutputStream) new PropertyOutputStream() | |||
: (OutputStream) new LogOutputStream(this, Project.MSG_INFO)); | |||
if (STRING.equals(mode)) { | |||
ps.print(((trim != null && trim.booleanValue()) | |||
? string.trim() : string).length()); | |||
ps.close(); | |||
} else if (EACH.equals(mode)) { | |||
handleFilesets(new EachHandler(ps)); | |||
} else if (ALL.equals(mode)) { | |||
handleFilesets(new AllHandler(ps)); | |||
} | |||
} | |||
private void validate() { | |||
if (string != null) { | |||
if (filesets != null && filesets.size() > 0) { | |||
throw new BuildException("the string length function" | |||
+ " is incompatible with the file length function"); | |||
} | |||
if (!(STRING.equals(mode))) { | |||
throw new BuildException("the mode attribute is for use" | |||
+ " with the file length function"); | |||
} | |||
} else if (filesets != null && filesets.size() > 0) { | |||
if (!(EACH.equals(mode) || ALL.equals(mode))) { | |||
throw new BuildException("invalid mode setting for" | |||
+ " file length function: \"" + mode + "\""); | |||
} else if (trim != null) { | |||
throw new BuildException("the trim attribute is" | |||
+ " for use with the string length function only"); | |||
} | |||
} else { | |||
throw new BuildException("you must set either the string attribute" | |||
+ " or specify one or more files using the file attribute or" | |||
+ " nested filesets"); | |||
} | |||
} | |||
private void handleFilesets(Handler h) { | |||
HashSet included = new HashSet(filesets.size() * 10); | |||
for (int i = 0; i < filesets.size(); i++) { | |||
FileSet fs = (FileSet)(filesets.get(i)); | |||
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||
File basedir = fs.getDir(getProject()); | |||
String[] f = ds.getIncludedFiles(); | |||
for (int j = 0; j < f.length; j++) { | |||
included.add(FILE_UTILS.resolveFile(basedir, f[j])); | |||
} | |||
} | |||
for (Iterator iter = included.iterator(); iter.hasNext();) { | |||
h.handle((File)(iter.next())); | |||
} | |||
included.clear(); | |||
included = null; | |||
h.complete(); | |||
} | |||
private static long getLength(File f) { | |||
//should be an existing file | |||
if (!(f.isFile())) { | |||
throw new BuildException("The absolute pathname " + f | |||
+ " does not denote an existing file."); | |||
} | |||
return f.length(); | |||
} | |||
/** EnumeratedAttribute operation mode */ | |||
public static class FileMode extends EnumeratedAttribute { | |||
static final String[] MODES = new String[] {EACH, ALL}; | |||
/** | |||
* Return the possible values for FileMode. | |||
* @return <code>String[]</code>. | |||
*/ | |||
public String[] getValues() { | |||
return MODES; | |||
} | |||
} | |||
private class PropertyOutputStream extends ByteArrayOutputStream { | |||
public void close() { | |||
getProject().setProperty(property, new String(toByteArray()).trim()); | |||
} | |||
} | |||
private abstract class Handler { | |||
PrintStream ps; | |||
Handler(PrintStream ps) { | |||
this.ps = ps; | |||
} | |||
protected abstract void handle(File f); | |||
void complete() { | |||
ps.close(); | |||
} | |||
} | |||
private class EachHandler extends Handler { | |||
EachHandler(PrintStream ps) { | |||
super(ps); | |||
} | |||
protected void handle(File f) { | |||
ps.print(f); | |||
ps.print(" : "); | |||
//when writing to the log, we'll see what's happening: | |||
ps.println(getLength(f)); | |||
} | |||
} | |||
private class AllHandler extends Handler { | |||
long length = 0L; | |||
AllHandler(PrintStream ps) { | |||
super(ps); | |||
} | |||
protected synchronized void handle(File f) { | |||
length += getLength(f); | |||
} | |||
void complete() { | |||
ps.print(length); | |||
super.complete(); | |||
} | |||
} | |||
} |
@@ -81,6 +81,7 @@ presetdef=org.apache.tools.ant.taskdefs.PreSetDef | |||
macrodef=org.apache.tools.ant.taskdefs.MacroDef | |||
nice=org.apache.tools.ant.taskdefs.Nice | |||
libraries=org.apache.tools.ant.taskdefs.repository.Libraries | |||
length=org.apache.tools.ant.taskdefs.Length | |||
# optional tasks | |||
image=org.apache.tools.ant.taskdefs.optional.image.Image | |||
@@ -0,0 +1,70 @@ | |||
/* | |||
* Copyright 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. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.BuildFileTest; | |||
public class LengthTest extends BuildFileTest { | |||
public LengthTest(String name) { | |||
super(name); | |||
} | |||
public void setUp() { | |||
configureProject("src/etc/testcases/taskdefs/length.xml"); | |||
} | |||
public void tearDown() { | |||
executeTarget("cleanup"); | |||
} | |||
public void testEach() { | |||
executeTarget("testEach"); | |||
} | |||
public void testAll() { | |||
executeTarget("testAll"); | |||
} | |||
public void testFile() { | |||
executeTarget("testFile"); | |||
} | |||
public void testBoth() { | |||
executeTarget("testBoth"); | |||
} | |||
public void testDupes() { | |||
executeTarget("testDupes"); | |||
} | |||
public void testString() { | |||
executeTarget("testString"); | |||
} | |||
public void testStringFile() { | |||
expectBuildExceptionContaining("testStringFile", | |||
"should fail", "incompatible"); | |||
} | |||
public void testTrimFile() { | |||
expectBuildExceptionContaining("testTrimFile", | |||
"should fail", "string length function only"); | |||
} | |||
} |