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 | * Added support to the touch task for a verbose attribute to suppress | ||||
| logging of new file creation. | 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 | 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/java.html">Java</a><br> | ||||
| <a href="CoreTasks/javac.html">Javac</a><br> | <a href="CoreTasks/javac.html">Javac</a><br> | ||||
| <a href="CoreTasks/javadoc.html">Javadoc/<i>Javadoc2</i></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/loadfile.html">LoadFile</a><br> | ||||
| <a href="CoreTasks/loadproperties.html">LoadProperties</a><br> | <a href="CoreTasks/loadproperties.html">LoadProperties</a><br> | ||||
| <a href="CoreTasks/mail.html">Mail</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 | macrodef=org.apache.tools.ant.taskdefs.MacroDef | ||||
| nice=org.apache.tools.ant.taskdefs.Nice | nice=org.apache.tools.ant.taskdefs.Nice | ||||
| libraries=org.apache.tools.ant.taskdefs.repository.Libraries | libraries=org.apache.tools.ant.taskdefs.repository.Libraries | ||||
| length=org.apache.tools.ant.taskdefs.Length | |||||
| # optional tasks | # optional tasks | ||||
| image=org.apache.tools.ant.taskdefs.optional.image.Image | 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"); | |||||
| } | |||||
| } | |||||