git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276257 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -48,6 +48,9 @@ Other changes: | |||
| * New attribute "negate" on <propertyset> to invert selection criteria. | |||
| * New <redirector> type introduced to provide extreme I/O flexibility. | |||
| Initial support for <exec>, <apply>, and <java> tasks. | |||
| Changes from Ant 1.6.1 to current Ant 1.6 CVS version | |||
| ============================================= | |||
| @@ -290,6 +290,19 @@ attribute.</p> | |||
| <p>It is possible to specify environment variables to pass to the | |||
| system command via nested <code><env></code> elements. See the | |||
| description in the section about <a href="exec.html#env">exec</a></p> | |||
| <h4>redirector</h4> | |||
| <i><b>Since Ant 1.6.2</b></i> | |||
| <p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a> | |||
| can be specified. <apply>'s behavior is like that of | |||
| <a href="exec.html#redirector">exec</a> with regard to | |||
| redirectors, with the exception that, in non-<i>parallel</i> mode, | |||
| file mapping will take place with each iteration. This grants the | |||
| user the capacity to receive input from, and send output to, different | |||
| files for each sourcefile. In this context it may be apparent | |||
| that no provision has been made whereby output/error properties | |||
| can be mapped per sourcefile; we humbly accept your gratitude for | |||
| having denied you "Enough Rope To Hang Yourself With." | |||
| </p> | |||
| <h3>Examples</h3> | |||
| <blockquote><pre> | |||
| <apply executable="ls"> | |||
| @@ -334,6 +347,29 @@ of all files separated by spaces.</p> | |||
| <code>.o</code>, replacing TARGETFILE with the absolute filename of | |||
| the <code>.o</code> and SOURCEFILE with the absolute name of the | |||
| <code>.c</code> file.</p> | |||
| <blockquote><pre> | |||
| <mapper id="out" type="glob" | |||
| from="src${file.separator}*.file" | |||
| to="dest${file.separator}*.out" /> | |||
| <apply executable="processfile" dest="dest"> | |||
| <fileset dir="src" includes="*.file"/> | |||
| <mapper refid="out" /> | |||
| <redirector> | |||
| <outputmapper refid="out" /> | |||
| </redirector> | |||
| </apply> | |||
| </pre></blockquote> | |||
| Applies the fictitious "processfile" executable to all | |||
| files matching <code>*.file</code> in the <CODE>src</CODE> directory. | |||
| The <CODE>out</CODE> <mapper> has been set up to map | |||
| <CODE>*.file</CODE> to <CODE>*.out</CODE>, then this <mapper> | |||
| is used to specify <CODE>targetfile</CODE>s for this <apply> | |||
| task. A reference to <CODE>out</CODE> is then used as an | |||
| <outputmapper> nested in a <redirector>, which in turn is | |||
| nested beneath this <apply> instance. This allows us to perform | |||
| dependency checking against output files--the target files in this case. | |||
| <hr><p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights | |||
| Reserved.</p> | |||
| @@ -241,7 +241,19 @@ system command via nested <code><env></code> elements.</p> | |||
| replaced by the absolute filename of the file by Ant.</td> | |||
| </tr> | |||
| </table> | |||
| <a name="redirector"><h4>redirector</h4></a> | |||
| <i><b>Since Ant 1.6.2</b></i> | |||
| <p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a> | |||
| can be specified. In general, the attributes of the redirector behave | |||
| as the corresponding attributes available at the task level. The most | |||
| notable peculiarity stems from the retention of the <exec> | |||
| attributes for backwards compatibility. Any file mapping is done | |||
| using a <CODE>null</CODE> sourcefile; therefore not all | |||
| <a href="../CoreTypes/mapper.html">Mapper</a> types will return | |||
| results. When no results are returned, redirection specifications | |||
| will fall back to the task level attributes. In practice this means that | |||
| defaults can be specified for input, output, and error output files. | |||
| </p> | |||
| <h3>Errors and return codes</h3> | |||
| By default the return code of a <exec> is ignored; when you set | |||
| <code>failonerror="true"</code> then any return code signaling failure | |||
| @@ -287,6 +299,27 @@ system command.</p> | |||
| <p>Starts the <i>${browser}</i> with the specified <i>${file}</i> and end the | |||
| ant process. The browser will let be open.</p> | |||
| <blockquote><pre> | |||
| <exec executable="cat"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err" | |||
| inputstring="blah before blah"> | |||
| <inputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </inputfilterchain> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| </exec> | |||
| </pre></blockquote> | |||
| Sends the string "blah before blah" to the "cat" executable, | |||
| using an <a href="../CoreTypes/filterchain.html"><inputfilterchain></a> | |||
| to replace "before" with "after" on the way in. | |||
| Output is sent to the file "redirector.out" and stored | |||
| in a property of the same name. Similarly, error output is sent to | |||
| a file and a property, both named "redirector.err". | |||
| <p><b>Note:</b> Although it may work for you to specify arguments using | |||
| a simple arg-element and separate them by spaces it may fail if you switch to | |||
| @@ -301,6 +334,7 @@ This problem may occur with all JDK's < 1.2.</p> | |||
| sub process is killed and a message printed to the log. The return | |||
| value of the execution will be "-1", which will halt the build if | |||
| <tt>failonerror=true</tt>, but be ignored otherwise. | |||
| <hr> | |||
| <p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights | |||
| Reserved.</p> | |||
| @@ -243,6 +243,19 @@ subelement.</p> | |||
| <p><em>since Ant 1.6.</em></p> | |||
| <a name="redirector"><h4>redirector</h4></a> | |||
| <i><b>Since Ant 1.6.2</b></i> | |||
| <p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a> | |||
| can be specified. In general, the attributes of the redirector behave | |||
| as the corresponding attributes available at the task level. The most | |||
| notable peculiarity stems from the retention of the <java> | |||
| attributes for backwards compatibility. Any file mapping is done | |||
| using a <CODE>null</CODE> sourcefile; therefore not all | |||
| <a href="../CoreTypes/mapper.html">Mapper</a> types will return | |||
| results. When no results are returned, redirection specifications | |||
| will fall back to the task level attributes. In practice this means that | |||
| defaults can be specified for input, output, and error output files. | |||
| </p> | |||
| <h3>Errors and return codes</h3> | |||
| By default the return code of a <java> is ignored. Alternatively, you can set <code>resultproperty</code> to the name | |||
| of a property and have it assigned to the result code (barring immutability, | |||
| @@ -27,6 +27,7 @@ | |||
| <a href="using.html#path">Path-like Structures</a><br> | |||
| <a href="CoreTypes/permissions.html">Permissions</a><br> | |||
| <a href="CoreTypes/propertyset.html">PropertySet</a><br> | |||
| <a href="CoreTypes/redirector.html">I/O Redirectors</a><br> | |||
| <a href="CoreTypes/regexp.html">Regexp</a><br> | |||
| <a href="CoreTypes/selectors.html">Selectors</a><br> | |||
| <a href="CoreTypes/xmlcatalog.html">XMLCatalog</a><br> | |||
| @@ -12,16 +12,6 @@ | |||
| </or> | |||
| </condition> | |||
| <!-- UNIX --> | |||
| <available file="wc" filepath="${env.PATH}" property="wc.executable"/> | |||
| <!-- CYGWIN --> | |||
| <available file="wc.exe" filepath="${env.PATH}" property="wc.exe.executable"/> | |||
| <condition property="wc.can.run"> | |||
| <or> | |||
| <isset property="wc.executable"/> | |||
| <isset property="wc.exe.executable"/> | |||
| </or> | |||
| </condition> | |||
| <!-- UNIX --> | |||
| <available file="sed" filepath="${env.PATH}" property="sed.executable"/> | |||
| <!-- CYGWIN --> | |||
| <available file="sed.exe" filepath="${env.PATH}" property="sed.exe.executable"/> | |||
| @@ -38,6 +28,7 @@ | |||
| <echo file="y">s/y/blah/g${line.separator}</echo> | |||
| <echo file="z">s/z/blah/g${line.separator}</echo> | |||
| <fileset id="xyz" dir="${basedir}" includes="x,y,z" /> | |||
| <filelist id="xyzlist" dir="${basedir}" files="x,y,z" /> | |||
| </target> | |||
| <target name="no-redirect" depends="init,xyz" if="test.can.run"> | |||
| @@ -83,7 +74,7 @@ | |||
| <apply executable="sed" inputstring="x y z${line.separator}" append="true" | |||
| error="redirect.err" errorproperty="redirect.err" | |||
| output="redirect.out" outputproperty="redirect.out"> | |||
| <arg value="-f"/> | |||
| <arg value="-f" /> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| @@ -93,8 +84,8 @@ | |||
| <apply executable="sed" input="redirect.in" append="true" | |||
| error="redirect.err" errorproperty="redirect.err" | |||
| output="redirect.out" outputproperty="redirect.out"> | |||
| <arg value="-f"/> | |||
| <fileset refid="xyz" /> | |||
| <arg value="-f" /> | |||
| <filelist refid="xyzlist" /> | |||
| </apply> | |||
| </target> | |||
| @@ -102,19 +93,221 @@ | |||
| <apply executable="sed" inputstring="x y z${line.separator}" | |||
| error="redirect.err" output="redirect.out" | |||
| outputproperty="redirect.out"> | |||
| <arg value="-f"/> | |||
| <arg value="-f" /> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirect7b" depends="redirect7"> | |||
| <echo>redirect.out=${redirect.out}</echo> | |||
| <target name="redirector1" description="fail" | |||
| depends="init,xyz" if="test.can.run"> | |||
| <apply executable="sh"> | |||
| <arg value="parrot.sh"/> | |||
| <fileset refid="xyz" /> | |||
| <redirector output="redirector.out" /> | |||
| <redirector output="whocares" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector2" depends="init,xyz" if="test.can.run"> | |||
| <apply executable="sh"> | |||
| <arg value="parrot.sh"/> | |||
| <fileset refid="xyz" /> | |||
| <redirector output="redirector.out" append="true" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector3" depends="init,xyz" if="test.can.run"> | |||
| <apply executable="sh"> | |||
| <arg value="parrot.sh"/> | |||
| <fileset refid="xyz" /> | |||
| <redirector append="true" | |||
| output="redirector.out" error="redirector.err" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector4" depends="init,xyz" if="test.can.run"> | |||
| <apply executable="sh"> | |||
| <arg value="parrot.sh"/> | |||
| <fileset refid="xyz" /> | |||
| <redirector output="redirector.out" logerror="true" | |||
| append="true" outputproperty="redirector.out" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector5" depends="init,xyz" if="test.can.run"> | |||
| <apply executable="sh"> | |||
| <redirector error="redirector.err" errorproperty="redirector.err" | |||
| output="redirector.out" outputproperty="redirector.out" | |||
| append="true" /> | |||
| <arg value="parrot.sh"/> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector6" depends="init,xyz" if="test.can.run"> | |||
| <apply executable="sh"> | |||
| <redirector append="true" outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="parrot.sh" /> | |||
| <filelist refid="xyzlist" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector7" depends="init,xyz" if="test.can.run"> | |||
| <apply executable="sh"> | |||
| <redirector append="true" outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| <errorfilterchain> | |||
| <replacestring from="err" to="ERROR!!!" /> | |||
| </errorfilterchain> | |||
| </redirector> | |||
| <arg value="parrot.sh" /> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector8" depends="init,xyz" if="sed.can.run"> | |||
| <echo file="redirector.in">x y z${line.separator}</echo> | |||
| <apply executable="sed"> | |||
| <redirector append="true" outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <inputmapper type="merge" to="redirector.in" /> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="-f" /> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector9" depends="init,xyz" if="sed.can.run"> | |||
| <echo file="redirector.in">x before y before z${line.separator}</echo> | |||
| <apply executable="sed"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err" append="true"> | |||
| <inputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </inputfilterchain> | |||
| <inputmapper type="merge" to="redirector.in" /> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="-f" /> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector10" depends="init,xyz" if="sed.can.run"> | |||
| <echo file="redirector.in">x before y before z${line.separator}</echo> | |||
| <apply executable="sed"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err" append="true"> | |||
| <outputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </outputfilterchain> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="-f" /> | |||
| <srcfile /> | |||
| <arg value="redirector.in"/> | |||
| <filelist refid="xyzlist" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector11" depends="init,xyz" if="sed.can.run"> | |||
| <apply executable="sed"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err" | |||
| inputstring="x before y before z${line.separator}" | |||
| append="true"> | |||
| <inputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </inputfilterchain> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="-f" /> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector12" depends="init,xyz" if="sed.can.run"> | |||
| <echo file="redirector.in">x before y before z${line.separator}</echo> | |||
| <apply executable="sed" output="redirector.out" error="redirector.err"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err" append="true"> | |||
| <outputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </outputfilterchain> | |||
| <outputmapper type="glob" from="nomatch" to="nomatchout" /> | |||
| <errormapper type="glob" from="nomatch" to="nomatcherr" /> | |||
| </redirector> | |||
| <arg value="-f" /> | |||
| <srcfile /> | |||
| <arg value="redirector.in"/> | |||
| <filelist refid="xyzlist" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector13" depends="init,xyz" if="test.can.run"> | |||
| <apply executable="sh"> | |||
| <redirector> | |||
| <outputfilterchain> | |||
| <replacestring from="out" to="OUTPUT???" /> | |||
| </outputfilterchain> | |||
| <errorfilterchain> | |||
| <replacestring from="err" to="ERROR!!!" /> | |||
| </errorfilterchain> | |||
| </redirector> | |||
| <arg value="parrot.sh" /> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector14" depends="init,xyz" if="sed.can.run"> | |||
| <echo file="redirector.in">z before y before x${line.separator}</echo> | |||
| <apply executable="sed"> | |||
| <redirector append="true" | |||
| inputstring="x before y before z${line.separator}"> | |||
| <outputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </outputfilterchain> | |||
| <inputmapper type="glob" from="x" to="redirector.in" /> | |||
| <outputmapper type="glob" from="y" to="redirector.out" /> | |||
| <errormapper type="glob" from="z" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="-f" /> | |||
| <fileset refid="xyz" /> | |||
| </apply> | |||
| </target> | |||
| <target name="redirector14b" depends="init,xyz" if="sed.can.run"> | |||
| <apply executable="sed"> | |||
| <redirector append="true" | |||
| inputstring="x before y before z${line.separator}"> | |||
| <outputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </outputfilterchain> | |||
| <inputmapper type="glob" from="x" to="redirector.in" /> | |||
| <outputmapper type="glob" from="y" to="redirector.out" /> | |||
| <errormapper type="glob" from="z" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="-f" /> | |||
| <fileset file="y" /> | |||
| </apply> | |||
| </target> | |||
| <target name="cleanup"> | |||
| <delete> | |||
| <fileset dir="${basedir}" includes="redirect.*" /> | |||
| <fileset refid="xyz" /> | |||
| <fileset dir="${basedir}" includes="redirect.*" /> | |||
| <fileset dir="${basedir}" includes="redirector.*" /> | |||
| </delete> | |||
| </target> | |||
| </project> | |||
| @@ -25,6 +25,16 @@ | |||
| <isset property="wc.exe.executable"/> | |||
| </or> | |||
| </condition> | |||
| <!-- UNIX --> | |||
| <available file="cat" filepath="${env.PATH}" property="cat.executable"/> | |||
| <!-- CYGWIN --> | |||
| <available file="cat.exe" filepath="${env.PATH}" property="cat.exe.executable"/> | |||
| <condition property="cat.can.run"> | |||
| <or> | |||
| <isset property="cat.executable"/> | |||
| <isset property="cat.exe.executable"/> | |||
| </or> | |||
| </condition> | |||
| </target> | |||
| <target name="spawn" depends="init" if="test.can.run"> | |||
| @@ -98,10 +108,216 @@ | |||
| </exec> | |||
| </target> | |||
| <target name="redirector1" description="fail" | |||
| depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <arg value="parrot.sh"/> | |||
| <arg value="${ant.file}" /> | |||
| <redirector output="redirector.out" /> | |||
| <redirector output="whocares" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector2" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <arg value="parrot.sh"/> | |||
| <arg value="${ant.file}" /> | |||
| <redirector output="redirector.out" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector3" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <arg value="parrot.sh"/> | |||
| <arg value="${ant.file}" /> | |||
| <redirector output="redirector.out" error="redirector.err" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector4" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <arg value="parrot.sh"/> | |||
| <arg value="${ant.file}" /> | |||
| <redirector output="redirector.out" logerror="true" | |||
| outputproperty="redirector.out" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector5" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <redirector error="redirector.err" errorproperty="redirector.err" | |||
| output="redirector.out" outputproperty="redirector.out" /> | |||
| <arg value="parrot.sh"/> | |||
| <arg value="${ant.file}" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector6" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="parrot.sh" /> | |||
| <arg value="${ant.file}" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector7" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| <errorfilterchain> | |||
| <replacestring from="err" to="ERROR!!!" /> | |||
| </errorfilterchain> | |||
| </redirector> | |||
| <arg value="parrot.sh" /> | |||
| <arg value="${ant.file}" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector8" depends="init" if="wc.can.run"> | |||
| <echo file="redirector.in">x y z</echo> | |||
| <exec executable="wc"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <inputmapper type="merge" to="redirector.in" /> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="-w"/> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector9" depends="init" if="cat.can.run"> | |||
| <echo file="redirector.in">blah before blah</echo> | |||
| <exec executable="cat"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <inputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </inputfilterchain> | |||
| <inputmapper type="merge" to="redirector.in" /> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector10" depends="init" if="cat.can.run"> | |||
| <echo file="redirector.in">blah before blah</echo> | |||
| <exec executable="cat"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <outputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </outputfilterchain> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| <arg value="redirector.in"/> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector11" depends="init" if="cat.can.run"> | |||
| <exec executable="cat"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err" | |||
| inputstring="blah before blah"> | |||
| <inputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </inputfilterchain> | |||
| <outputmapper type="merge" to="redirector.out" /> | |||
| <errormapper type="merge" to="redirector.err" /> | |||
| </redirector> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector12" depends="init" if="cat.can.run"> | |||
| <echo file="redirector.in">blah before blah</echo> | |||
| <exec executable="cat" output="redirector.out" error="redirector.err"> | |||
| <redirector outputproperty="redirector.out" | |||
| errorproperty="redirector.err"> | |||
| <outputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </outputfilterchain> | |||
| <outputmapper type="glob" from="nomatch" to="nomatchout" /> | |||
| <errormapper type="glob" from="nomatch" to="nomatcherr" /> | |||
| </redirector> | |||
| <arg value="redirector.in"/> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector13" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <redirector> | |||
| <outputfilterchain> | |||
| <replacestring from="out" to="OUTPUT???" /> | |||
| </outputfilterchain> | |||
| <errorfilterchain> | |||
| <replacestring from="err" to="ERROR!!!" /> | |||
| </errorfilterchain> | |||
| </redirector> | |||
| <arg value="parrot.sh" /> | |||
| <arg value="${ant.file}" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector14" depends="init" if="cat.can.run"> | |||
| <exec executable="cat"> | |||
| <redirector inputstring="blah before blah"> | |||
| <outputfilterchain> | |||
| <replacestring from="before" to="after" /> | |||
| </outputfilterchain> | |||
| <outputmapper type="glob" from="nomatch" to="nomatchout" /> | |||
| <errormapper type="glob" from="nomatch" to="nomatcherr" /> | |||
| </redirector> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector15" depends="init" if="cat.can.run"> | |||
| <exec executable="cat"> | |||
| <redirector input="input/iso8859-1" output="redirector.out" | |||
| inputencoding="ISO8859_1" outputencoding="UTF8" /> | |||
| </exec> | |||
| </target> | |||
| <target name="redirector16" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <redirector inputstring="exit" | |||
| output="redirector16.out" error="redirector16.err" /> | |||
| </exec> | |||
| <condition property="16pass"> | |||
| <and> | |||
| <available file="redirector16.out" type="file" /> | |||
| <available file="redirector16.err" type="file" /> | |||
| </and> | |||
| </condition> | |||
| <fail unless="16pass">Files were not created.</fail> | |||
| </target> | |||
| <target name="redirector17" depends="init" if="test.can.run"> | |||
| <exec executable="sh"> | |||
| <redirector inputstring="exit" createemptyfiles="false" | |||
| output="redirector17.out" error="redirector17.err" /> | |||
| </exec> | |||
| <condition property="17fail"> | |||
| <or> | |||
| <available file="redirector17.out" type="file" /> | |||
| <available file="redirector17.err" type="file" /> | |||
| </or> | |||
| </condition> | |||
| <fail if="17fail">Files were created.</fail> | |||
| </target> | |||
| <target name="cleanup"> | |||
| <delete> | |||
| <fileset file="${logFile}" /> | |||
| <fileset dir="${basedir}" includes="redirect.*" /> | |||
| <fileset dir="${basedir}" includes="redirect*" /> | |||
| <fileset dir="${basedir}" includes="redirector*" /> | |||
| </delete> | |||
| </target> | |||
| </project> | |||
| @@ -0,0 +1 @@ | |||
| äöüÄÖÜß | |||
| @@ -0,0 +1 @@ | |||
| 蔕�ヨワ゚ | |||
| @@ -7,6 +7,7 @@ | |||
| <property name="timeToWait" value="4"/> | |||
| <!-- this property gets overridden programmatically--> | |||
| <property name="logFile" value="spawn.log"/> | |||
| <property name="tmp" value="${java.io.tmpdir}"/> | |||
| <property name="app" | |||
| value="org.apache.tools.ant.taskdefs.JavaTest$$EntryPoint" /> | |||
| @@ -16,6 +17,11 @@ | |||
| <property name="spawnapp" | |||
| value="org.apache.tools.ant.taskdefs.JavaTest$$SpawnEntryPoint" /> | |||
| <property name="pipeapp" | |||
| value="org.apache.tools.ant.taskdefs.JavaTest$$PipeEntryPoint" /> | |||
| <!--taskdef name="gc" classname="org.apache.tools.ant.taskdefs.optional.Gc" /--> | |||
| <target name="testNoJarNoClassname"> | |||
| <java/> | |||
| </target> | |||
| @@ -126,18 +132,17 @@ | |||
| <echo message="exitcode = ${exitcode}"/> | |||
| </target> | |||
| <target name="testResultPropertyNonZeroNoFork"> | |||
| <java classname="${app}" | |||
| classpath="${tests-classpath.value}" | |||
| resultproperty="exitcode" | |||
| failonerror="false" | |||
| fork="false" | |||
| > | |||
| <arg value="-1"/> | |||
| <permissions/> | |||
| </java> | |||
| <echo message="exitcode = ${exitcode}"/> | |||
| </target> | |||
| <target name="testResultPropertyNonZeroNoFork"> | |||
| <java classname="${app}" | |||
| classpath="${tests-classpath.value}" | |||
| resultproperty="exitcode" | |||
| failonerror="false" | |||
| fork="false"> | |||
| <arg value="-1"/> | |||
| <permissions/> | |||
| </java> | |||
| <echo message="exitcode = ${exitcode}"/> | |||
| </target> | |||
| <target name="testRunFailWithFailOnError"> | |||
| <java classname="${app}" | |||
| @@ -157,16 +162,143 @@ | |||
| </java> | |||
| </target> | |||
| <target name="testSpawn"> | |||
| <java classname="${spawnapp}" fork="true" spawn="true" classpath="${tests-classpath.value}"> | |||
| <arg value="${timeToWait}"/> | |||
| <arg value="${logFile}" /> | |||
| </java> | |||
| </target> | |||
| <target name="testSpawn"> | |||
| <java classname="${spawnapp}" fork="true" spawn="true" classpath="${tests-classpath.value}"> | |||
| <arg value="${timeToWait}"/> | |||
| <arg value="${logFile}" /> | |||
| </java> | |||
| </target> | |||
| <!--redirection testcases don't want to run under junit unless forked--> | |||
| <target name="redirect1"> | |||
| <java classname="${pipeapp}" | |||
| classpath="${tests-classpath.value}" | |||
| inputstring="foo" | |||
| fork="true" | |||
| output="${tmp}/redirect.out" | |||
| errorproperty="redirect.err"> | |||
| <arg value="out" /> | |||
| </java> | |||
| <!-- let dumb Windows catch up --> | |||
| <sleep seconds="2" /> | |||
| <loadfile property="redirect.out.contents" srcfile="${tmp}/redirect.out" /> | |||
| <condition property="r1pass"> | |||
| <and> | |||
| <equals arg1="${redirect.out.contents}" arg2="foo" /> | |||
| <equals arg1="${redirect.err}" arg2="" /> | |||
| </and> | |||
| </condition> | |||
| <fail unless="r1pass" /> | |||
| </target> | |||
| <target name="cleanup"> | |||
| <delete file="${logFile}"/> | |||
| </target> | |||
| <target name="foo" /> | |||
| <target name="redirect2" depends="redirect1"> | |||
| <java classname="${pipeapp}" | |||
| classpath="${tests-classpath.value}" | |||
| inputstring="bar" | |||
| append="true" | |||
| fork="true" | |||
| output="${tmp}/redirect.out" | |||
| errorproperty="redirect.err"> | |||
| <arg value="both" /> | |||
| </java> | |||
| <!-- let dumb Windows catch up --> | |||
| <sleep seconds="2" /> | |||
| <loadfile property="redirect.out.contents2" srcfile="${tmp}/redirect.out" /> | |||
| <condition property="r2pass"> | |||
| <and> | |||
| <equals arg1="${redirect.out.contents2}" arg2="foobar" /> | |||
| <!-- property should not be reset --> | |||
| <equals arg1="${redirect.err}" arg2="" /> | |||
| </and> | |||
| </condition> | |||
| <fail unless="r2pass" /> | |||
| </target> | |||
| <target name="redirect3"> | |||
| <java classname="${pipeapp}" | |||
| classpath="${tests-classpath.value}" | |||
| inputstring="foo" | |||
| fork="true" | |||
| output="${tmp}/redirect.out" | |||
| error="${tmp}/redirect.err"> | |||
| <arg value="both" /> | |||
| </java> | |||
| <!-- let dumb Windows catch up --> | |||
| <sleep seconds="2" /> | |||
| <loadfile property="redirect.out.contents" | |||
| srcfile="${tmp}/redirect.out" /> | |||
| <condition property="r3pass"> | |||
| <and> | |||
| <equals arg1="${redirect.out.contents}" arg2="foo" /> | |||
| <filesmatch file1="${tmp}/redirect.out" | |||
| file2="${tmp}/redirect.err" /> | |||
| </and> | |||
| </condition> | |||
| <fail unless="r3pass" /> | |||
| </target> | |||
| <target name="redirector1"> | |||
| <java taskname="foo" classname="${pipeapp}" fork="true" | |||
| classpath="${tests-classpath.value}"> | |||
| <redirector inputstring="foo" | |||
| output="${tmp}/redirector.out" | |||
| error="${tmp}/redirector.err" | |||
| createemptyfiles="false" /> | |||
| <arg value="out" /> | |||
| </java> | |||
| <!-- let dumb Windows catch up --> | |||
| <sleep seconds="2" /> | |||
| <loadfile property="redirector.out.contents" | |||
| srcfile="${tmp}/redirector.out" /> | |||
| <condition property="ror1pass"> | |||
| <and> | |||
| <equals arg1="${redirector.out.contents}" arg2="foo" /> | |||
| <not> | |||
| <available file="${tmp}/redirector.err" /> | |||
| </not> | |||
| </and> | |||
| </condition> | |||
| <fail unless="ror1pass" /> | |||
| </target> | |||
| <target name="redirector2" depends="redirector1"> | |||
| <!-- fork here, some VMs can be ill-behaved with files, | |||
| such as W!nd0ws --> | |||
| <java taskname="foo" classname="${pipeapp}" fork="true" | |||
| classpath="${tests-classpath.value}"> | |||
| <redirector inputstring="foo" | |||
| append="true" | |||
| output="${tmp}/redirector.out" | |||
| error="${tmp}/redirector.err" | |||
| createemptyfiles="false"> | |||
| <errorfilterchain> | |||
| <replacestring from="foo" to="bar" /> | |||
| </errorfilterchain> | |||
| </redirector> | |||
| <arg value="both" /> | |||
| </java> | |||
| <!-- let dumb Windows catch up --> | |||
| <sleep seconds="2" /> | |||
| <loadfile property="redirector.out.contents2" | |||
| srcfile="${tmp}/redirector.out" /> | |||
| <loadfile property="redirector.err.contents" | |||
| srcfile="${tmp}/redirector.err" /> | |||
| <condition property="ror2pass"> | |||
| <and> | |||
| <equals arg1="${redirector.out.contents2}" arg2="foofoo" /> | |||
| <equals arg1="${redirector.err.contents}" arg2="bar" /> | |||
| </and> | |||
| </condition> | |||
| <fail unless="ror2pass" /> | |||
| </target> | |||
| <target name="cleanup"> | |||
| <delete> | |||
| <fileset file="${logFile}" /> | |||
| <fileset dir="${tmp}" includes="redirect*" /> | |||
| <fileset dir="${tmp}" includes="redirector*" /> | |||
| </delete> | |||
| </target> | |||
| <target name="foo" /> | |||
| </project> | |||
| @@ -20,21 +20,13 @@ import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.StringReader; | |||
| import org.apache.tools.ant.util.ReaderInputStream; | |||
| /** | |||
| * Wraps a String as an InputStream. | |||
| * | |||
| */ | |||
| public class StringInputStream | |||
| extends InputStream { | |||
| /** Source string, stored as a StringReader */ | |||
| private StringReader in; | |||
| private String encoding; | |||
| private byte[] slack; | |||
| private int begin; | |||
| public class StringInputStream extends ReaderInputStream { | |||
| /** | |||
| * Composes a stream from a String | |||
| @@ -42,159 +34,17 @@ public class StringInputStream | |||
| * @param source The string to read from. Must not be <code>null</code>. | |||
| */ | |||
| public StringInputStream(String source) { | |||
| in = new StringReader(source); | |||
| super(new StringReader(source)); | |||
| } | |||
| /** | |||
| * Composes a stream from a String with the specified encoding | |||
| * | |||
| * @param source The string to read from. Must not be <code>null</code>. | |||
| * @param encoding The encoding scheme. | |||
| * @param encoding The encoding scheme. Also must not be <CODE>null</CODE>. | |||
| */ | |||
| public StringInputStream(String source, String encoding) { | |||
| in = new StringReader(source); | |||
| this.encoding = encoding; | |||
| } | |||
| /** | |||
| * Reads from the Stringreader, returning the same value. | |||
| * | |||
| * @return the value of the next character in the StringReader | |||
| * | |||
| * @exception IOException if the original StringReader fails to be read | |||
| */ | |||
| public synchronized int read() throws IOException { | |||
| if (in == null) { | |||
| throw new IOException("Stream Closed"); | |||
| } | |||
| byte result; | |||
| if (slack != null && begin < slack.length) { | |||
| result = slack[begin]; | |||
| if (++begin == slack.length) { | |||
| slack = null; | |||
| } | |||
| } else { | |||
| byte[] buf = new byte[1]; | |||
| if (read(buf, 0, 1) <= 0) { | |||
| return -1; | |||
| } | |||
| result = buf[0]; | |||
| } | |||
| if (result < 0) { | |||
| return 256 + result; | |||
| } else { | |||
| return result; | |||
| } | |||
| super(new StringReader(source), encoding); | |||
| } | |||
| /** | |||
| * Reads from the Stringreader into a byte array | |||
| * | |||
| * @param b the byte array to read into | |||
| * @param off the offset in the byte array | |||
| * @param len the length in the byte array to fill | |||
| * @return the actual number read into the byte array, -1 at | |||
| * the end of the stream | |||
| * @exception IOException if an error occurs | |||
| */ | |||
| public synchronized int read(byte[] b, int off, int len) | |||
| throws IOException { | |||
| if (in == null) { | |||
| throw new IOException("Stream Closed"); | |||
| } | |||
| while (slack == null) { | |||
| char[] buf = new char[len]; // might read too much | |||
| int n = in.read(buf); | |||
| if (n == -1) { | |||
| return -1; | |||
| } | |||
| if (n > 0) { | |||
| String s = new String(buf, 0, n); | |||
| if (encoding == null) { | |||
| slack = s.getBytes(); | |||
| } else { | |||
| slack = s.getBytes(encoding); | |||
| } | |||
| begin = 0; | |||
| } | |||
| } | |||
| if (len > slack.length - begin) { | |||
| len = slack.length - begin; | |||
| } | |||
| System.arraycopy(slack, begin, b, off, len); | |||
| if ((begin += len) >= slack.length) { | |||
| slack = null; | |||
| } | |||
| return len; | |||
| } | |||
| /** | |||
| * Marks the read limit of the StringReader. | |||
| * | |||
| * @param limit the maximum limit of bytes that can be read before the | |||
| * mark position becomes invalid | |||
| */ | |||
| public synchronized void mark(final int limit) { | |||
| try { | |||
| in.mark(limit); | |||
| } catch (IOException ioe) { | |||
| throw new RuntimeException(ioe.getMessage()); | |||
| } | |||
| } | |||
| /** | |||
| * @return the current number of bytes ready for reading | |||
| * @exception IOException if an error occurs | |||
| */ | |||
| public synchronized int available() throws IOException { | |||
| if (in == null) { | |||
| throw new IOException("Stream Closed"); | |||
| } | |||
| if (slack != null) { | |||
| return slack.length - begin; | |||
| } | |||
| if (in.ready()) { | |||
| return 1; | |||
| } else { | |||
| return 0; | |||
| } | |||
| } | |||
| /** | |||
| * @return false - mark is not supported | |||
| */ | |||
| public boolean markSupported () { | |||
| return false; // would be imprecise | |||
| } | |||
| /** | |||
| * Resets the StringReader. | |||
| * | |||
| * @exception IOException if the StringReader fails to be reset | |||
| */ | |||
| public synchronized void reset() throws IOException { | |||
| if (in == null) { | |||
| throw new IOException("Stream Closed"); | |||
| } | |||
| slack = null; | |||
| in.reset(); | |||
| } | |||
| /** | |||
| * Closes the Stringreader. | |||
| * | |||
| * @exception IOException if the original StringReader fails to be closed | |||
| */ | |||
| public synchronized void close() throws IOException { | |||
| in.close(); | |||
| slack = null; | |||
| in = null; | |||
| } | |||
| } | |||
| @@ -27,6 +27,7 @@ import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.Commandline; | |||
| import org.apache.tools.ant.types.Environment; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.RedirectorElement; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| @@ -53,7 +54,14 @@ public class ExecTask extends Task { | |||
| private boolean spawn = false; | |||
| private boolean incompatibleWithSpawn = false; | |||
| private Redirector redirector = new Redirector(this); | |||
| //include locally for screening purposes | |||
| private String inputString; | |||
| private File input; | |||
| private File output; | |||
| private File error; | |||
| protected Redirector redirector = new Redirector(this); | |||
| protected RedirectorElement redirectorElement; | |||
| /** | |||
| * Controls whether the VM (1.3 and above) is used to execute the | |||
| @@ -141,7 +149,7 @@ public class ExecTask extends Task { | |||
| * @param out name of a file to which send output to | |||
| */ | |||
| public void setOutput(File out) { | |||
| redirector.setOutput(out); | |||
| this.output = out; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| @@ -151,7 +159,11 @@ public class ExecTask extends Task { | |||
| * @param input name of a file to get input from | |||
| */ | |||
| public void setInput(File input) { | |||
| redirector.setInput(input); | |||
| if (inputString != null) { | |||
| throw new BuildException("The \"input\" and \"inputstring\" " | |||
| + "attributes cannot both be specified"); | |||
| } | |||
| this.input = input; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| @@ -161,7 +173,11 @@ public class ExecTask extends Task { | |||
| * @param inputString the string which is used as the input source | |||
| */ | |||
| public void setInputString(String inputString) { | |||
| redirector.setInputString(inputString); | |||
| if (input != null) { | |||
| throw new BuildException("The \"input\" and \"inputstring\" " | |||
| + "attributes cannot both be specified"); | |||
| } | |||
| this.inputString = inputString; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| @@ -185,7 +201,7 @@ public class ExecTask extends Task { | |||
| * @since ant 1.6 | |||
| */ | |||
| public void setError(File error) { | |||
| redirector.setError(error); | |||
| this.error = error; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| @@ -325,6 +341,20 @@ public class ExecTask extends Task { | |||
| } | |||
| /** | |||
| * Add a <CODE>RedirectorElement</CODE> to this task. | |||
| * | |||
| * @param redirectorElement <CODE>RedirectorElement</CODE>. | |||
| */ | |||
| public void addConfiguredRedirector(RedirectorElement redirectorElement) { | |||
| if (this.redirectorElement != null) { | |||
| throw new BuildException("cannot have > 1 nested <redirector>s"); | |||
| } else { | |||
| this.redirectorElement = redirectorElement; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| } | |||
| /** | |||
| * Attempt to figure out where the executable is so that we can feed | |||
| @@ -431,10 +461,23 @@ public class ExecTask extends Task { | |||
| if (spawn && incompatibleWithSpawn) { | |||
| getProject().log("spawn does not allow attributes related to input, " | |||
| + "output, error, result", Project.MSG_ERR); | |||
| getProject().log("spawn does not also not allow timeout", Project.MSG_ERR); | |||
| throw new BuildException("You have used an attribute which is " | |||
| + "not compatible with spawn"); | |||
| getProject().log("spawn also does not allow timeout", Project.MSG_ERR); | |||
| getProject().log( "finally, spawn is not compatible " | |||
| + "with a nested I/O <redirector>", Project.MSG_ERR); | |||
| throw new BuildException("You have used an attribute " | |||
| + "or nested element which is not compatible with spawn"); | |||
| } | |||
| setupRedirector(); | |||
| } | |||
| /** | |||
| * Set up properties on the redirector that we needed to store locally. | |||
| */ | |||
| protected void setupRedirector() { | |||
| redirector.setInput(input); | |||
| redirector.setInputString(inputString); | |||
| redirector.setOutput(output); | |||
| redirector.setError(error); | |||
| } | |||
| /** | |||
| @@ -485,6 +528,9 @@ public class ExecTask extends Task { | |||
| if (dir == null) { | |||
| dir = getProject().getBaseDir(); | |||
| } | |||
| if (redirectorElement != null) { | |||
| redirectorElement.configure(redirector); | |||
| } | |||
| Execute exe = new Execute(createHandler(), createWatchdog()); | |||
| exe.setAntRun(getProject()); | |||
| exe.setWorkingDirectory(dir); | |||
| @@ -527,6 +573,7 @@ public class ExecTask extends Task { | |||
| } | |||
| } | |||
| maybeSetResultPropertyValue(returnCode); | |||
| redirector.complete(); | |||
| if (Execute.isFailure(returnCode)) { | |||
| if (failOnError) { | |||
| throw new BuildException(getTaskType() + " returned: " | |||
| @@ -535,7 +582,6 @@ public class ExecTask extends Task { | |||
| log("Result: " + returnCode, Project.MSG_ERR); | |||
| } | |||
| } | |||
| redirector.complete(); | |||
| } else { | |||
| exe.spawn(); | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * Copyright 2000-2004 The Apache Software Foundation | |||
| * Copyright 2000-2004 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. | |||
| @@ -238,6 +238,17 @@ public class ExecuteOn extends ExecTask { | |||
| } | |||
| } | |||
| protected ExecuteStreamHandler createHandler() throws BuildException { | |||
| //if we have a RedirectorElement, return a decoy | |||
| return (redirectorElement == null) | |||
| ? super.createHandler() : new PumpStreamHandler(); | |||
| } | |||
| protected void setupRedirector() { | |||
| super.setupRedirector(); | |||
| redirector.setAppendProperties(true); | |||
| } | |||
| protected void runExec(Execute exe) throws BuildException { | |||
| int totalFiles = 0; | |||
| int totalDirs = 0; | |||
| @@ -293,10 +304,17 @@ public class ExecuteOn extends ExecTask { | |||
| log(Commandline.describeCommand(command), | |||
| Project.MSG_VERBOSE); | |||
| exe.setCommandline(command); | |||
| if (haveExecuted) { | |||
| if (redirectorElement != null) { | |||
| setupRedirector(); | |||
| redirectorElement.configure(redirector, s[j]); | |||
| } | |||
| if (redirectorElement != null || haveExecuted) { | |||
| // need to reset the stream handler to restart | |||
| // reading of pipes | |||
| exe.setStreamHandler(createHandler()); | |||
| // reading of pipes; | |||
| // go ahead and do it always w/ nested redirectors | |||
| exe.setStreamHandler(redirector.createHandler()); | |||
| } | |||
| runExecute(exe); | |||
| haveExecuted = true; | |||
| @@ -341,10 +359,17 @@ public class ExecuteOn extends ExecTask { | |||
| log(Commandline.describeCommand(command), | |||
| Project.MSG_VERBOSE); | |||
| exe.setCommandline(command); | |||
| if (haveExecuted) { | |||
| if (redirectorElement != null) { | |||
| setupRedirector(); | |||
| redirectorElement.configure(redirector, s[j]); | |||
| } | |||
| if (redirectorElement != null || haveExecuted) { | |||
| // need to reset the stream handler to restart | |||
| // reading of pipes | |||
| exe.setStreamHandler(createHandler()); | |||
| // reading of pipes; | |||
| // go ahead and do it always w/ nested redirectors | |||
| exe.setStreamHandler(redirector.createHandler()); | |||
| } | |||
| runExecute(exe); | |||
| haveExecuted = true; | |||
| @@ -373,6 +398,8 @@ public class ExecuteOn extends ExecTask { | |||
| } finally { | |||
| // close the output file if required | |||
| logFlush(); | |||
| redirector.setAppendProperties(false); | |||
| redirector.setProperties(); | |||
| } | |||
| } | |||
| @@ -582,10 +609,16 @@ public class ExecuteOn extends ExecTask { | |||
| String[] command = getCommandline(cs, cb); | |||
| log(Commandline.describeCommand(command), Project.MSG_VERBOSE); | |||
| exe.setCommandline(command); | |||
| if (currentOffset > 0) { | |||
| if (redirectorElement != null) { | |||
| setupRedirector(); | |||
| redirectorElement.configure(redirector, null); | |||
| } | |||
| if (redirectorElement != null || currentOffset > 0) { | |||
| // need to reset the stream handler to restart | |||
| // reading of pipes | |||
| exe.setStreamHandler(createHandler()); | |||
| // reading of pipes; | |||
| // go ahead and do it always w/ nested redirectors | |||
| exe.setStreamHandler(redirector.createHandler()); | |||
| } | |||
| runExecute(exe); | |||
| @@ -34,6 +34,7 @@ import org.apache.tools.ant.types.PropertySet; | |||
| import org.apache.tools.ant.types.Reference; | |||
| import org.apache.tools.ant.types.Assertions; | |||
| import org.apache.tools.ant.types.Permissions; | |||
| import org.apache.tools.ant.types.RedirectorElement; | |||
| /** | |||
| * Launcher for Java applications. Allows use of | |||
| @@ -53,7 +54,16 @@ public class Java extends Task { | |||
| private File dir = null; | |||
| private boolean failOnError = false; | |||
| private Long timeout = null; | |||
| private Redirector redirector = new Redirector(this); | |||
| //include locally for screening purposes | |||
| private String inputString; | |||
| private File input; | |||
| private File output; | |||
| private File error; | |||
| protected Redirector redirector = new Redirector(this); | |||
| protected RedirectorElement redirectorElement; | |||
| private String resultProperty; | |||
| private Permissions perm = null; | |||
| @@ -110,9 +120,11 @@ public class Java extends Task { | |||
| if (spawn && incompatibleWithSpawn) { | |||
| getProject().log("spawn does not allow attributes related to input, " | |||
| + "output, error, result", Project.MSG_ERR); | |||
| getProject().log("spawn does not also not allow timeout", Project.MSG_ERR); | |||
| throw new BuildException("You have used an attribute which is " | |||
| + "not compatible with spawn"); | |||
| getProject().log("spawn also does not allow timeout", Project.MSG_ERR); | |||
| getProject().log( "finally, spawn is not compatible " | |||
| + "with a nested I/O <redirector>", Project.MSG_ERR); | |||
| throw new BuildException("You have used an attribute " | |||
| + "or nested element which is not compatible with spawn"); | |||
| } | |||
| if (cmdl.getAssertions() != null && !fork) { | |||
| log("Assertion statements are currently ignored in non-forked mode"); | |||
| @@ -151,6 +163,7 @@ public class Java extends Task { | |||
| Project.MSG_VERBOSE); | |||
| } | |||
| setupRedirector(); | |||
| try { | |||
| if (fork) { | |||
| if (!spawn) { | |||
| @@ -419,7 +432,7 @@ public class Java extends Task { | |||
| * @param out name of the output file | |||
| */ | |||
| public void setOutput(File out) { | |||
| redirector.setOutput(out); | |||
| this.output = out; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| @@ -429,7 +442,11 @@ public class Java extends Task { | |||
| * @param input name of the input file | |||
| */ | |||
| public void setInput(File input) { | |||
| redirector.setInput(input); | |||
| if (inputString != null) { | |||
| throw new BuildException("The \"input\" and \"inputstring\" " | |||
| + "attributes cannot both be specified"); | |||
| } | |||
| this.input = input; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| @@ -439,7 +456,11 @@ public class Java extends Task { | |||
| * @param inputString the string which is used as the input source | |||
| */ | |||
| public void setInputString(String inputString) { | |||
| redirector.setInputString(inputString); | |||
| if (input != null) { | |||
| throw new BuildException("The \"input\" and \"inputstring\" " | |||
| + "attributes cannot both be specified"); | |||
| } | |||
| this.inputString = inputString; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| @@ -464,7 +485,7 @@ public class Java extends Task { | |||
| * @since ant 1.6 | |||
| */ | |||
| public void setError(File error) { | |||
| redirector.setError(error); | |||
| this.error = error; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| @@ -572,6 +593,19 @@ public class Java extends Task { | |||
| cmdl.setAssertions(asserts); | |||
| } | |||
| /** | |||
| * Add a <CODE>RedirectorElement</CODE> to this task. | |||
| * @param redirectorElement <CODE>RedirectorElement</CODE>. | |||
| */ | |||
| public void addConfiguredRedirector(RedirectorElement redirectorElement) { | |||
| if (this.redirectorElement != null) { | |||
| throw new BuildException("cannot have > 1 nested <redirector>s"); | |||
| } else { | |||
| this.redirectorElement = redirectorElement; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| } | |||
| /** | |||
| * Pass output sent to System.out to specified output file. | |||
| * | |||
| @@ -653,6 +687,19 @@ public class Java extends Task { | |||
| } | |||
| } | |||
| /** | |||
| * Set up properties on the redirector that we needed to store locally. | |||
| */ | |||
| protected void setupRedirector() { | |||
| redirector.setInput(input); | |||
| redirector.setInputString(inputString); | |||
| redirector.setOutput(output); | |||
| redirector.setError(error); | |||
| if (redirectorElement != null) { | |||
| redirectorElement.configure(redirector); | |||
| } | |||
| } | |||
| /** | |||
| * Executes the given classname with the given arguments as it | |||
| * was a command line application. | |||
| @@ -16,23 +16,37 @@ | |||
| */ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import java.io.BufferedReader; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileNotFoundException; | |||
| import java.io.IOException; | |||
| import java.io.StringReader; | |||
| import java.io.OutputStream; | |||
| import java.io.Reader; | |||
| import java.io.InputStream; | |||
| import java.io.IOException; | |||
| import java.io.PrintStream; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import java.io.OutputStream; | |||
| import java.io.StringReader; | |||
| import java.io.BufferedReader; | |||
| import java.io.FileInputStream; | |||
| import java.io.PipedInputStream; | |||
| import java.io.InputStreamReader; | |||
| import java.io.PipedOutputStream; | |||
| import java.io.OutputStreamWriter; | |||
| import java.io.BufferedInputStream; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.FileNotFoundException; | |||
| import java.util.Arrays; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.util.LazyFileOutputStream; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.filters.util.ChainReaderHelper; | |||
| import org.apache.tools.ant.util.StringUtils; | |||
| import org.apache.tools.ant.util.TeeOutputStream; | |||
| import org.apache.tools.ant.util.ReaderInputStream; | |||
| import org.apache.tools.ant.util.LeadPipeInputStream; | |||
| import org.apache.tools.ant.util.LazyFileOutputStream; | |||
| import org.apache.tools.ant.util.OutputStreamFunneler; | |||
| import org.apache.tools.ant.util.ConcatFileInputStream; | |||
| import org.apache.tools.ant.util.KeepAliveOutputStream; | |||
| /** | |||
| * The Redirector class manages the setup and connection of | |||
| @@ -41,21 +55,43 @@ import org.apache.tools.ant.util.TeeOutputStream; | |||
| * @since Ant 1.6 | |||
| */ | |||
| public class Redirector { | |||
| private static final String defaultEncoding | |||
| = System.getProperty("file.encoding"); | |||
| private class PropertyOutputStream extends ByteArrayOutputStream { | |||
| String property; | |||
| boolean closed = false; | |||
| PropertyOutputStream(String property) { | |||
| super(); | |||
| this.property = property; | |||
| } | |||
| public void close() throws IOException { | |||
| if (!closed && !(append && appendProperties)) { | |||
| setPropertyFromBAOS(this, property); | |||
| closed = true; | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * The file receiving standard output. Will also receive standard error | |||
| * unless standard error is redirected or logError is true. | |||
| * The file(s) from which standard input is being taken. | |||
| * If > 1, files' content will be concatenated in the order received. | |||
| */ | |||
| private File out; | |||
| private File[] input; | |||
| /** | |||
| * The file to which standard error is being redirected | |||
| * The file(s) receiving standard output. Will also receive standard error | |||
| * unless standard error is redirected or logError is true. | |||
| */ | |||
| private File error; | |||
| private File[] out; | |||
| /** | |||
| * The file from which standard input is being taken. | |||
| * The file(s) to which standard error is being redirected | |||
| */ | |||
| private File input; | |||
| private File[] error; | |||
| /** | |||
| * Indicates if standard error should be logged to Ant's log system | |||
| @@ -67,12 +103,12 @@ public class Redirector { | |||
| /** | |||
| * Buffer used to capture output for storage into a property | |||
| */ | |||
| private ByteArrayOutputStream baos = null; | |||
| private PropertyOutputStream baos = null; | |||
| /** | |||
| * Buffer used to capture error output for storage into a property | |||
| */ | |||
| private ByteArrayOutputStream errorBaos = null; | |||
| private PropertyOutputStream errorBaos = null; | |||
| /** The name of the property into which output is to be stored */ | |||
| private String outputProperty; | |||
| @@ -86,6 +122,9 @@ public class Redirector { | |||
| /** Flag which indicates if error and output files are to be appended. */ | |||
| private boolean append = false; | |||
| /** Flag which indicates whether files should be created even when empty. */ | |||
| private boolean createEmptyFiles = true; | |||
| /** The task for which this redirector is working */ | |||
| private Task managingTask; | |||
| @@ -104,6 +143,30 @@ public class Redirector { | |||
| /** Stream which is used for line oriented error output */ | |||
| private PrintStream errorPrintStream = null; | |||
| /** The output filter chains */ | |||
| private Vector outputFilterChains; | |||
| /** The error filter chains */ | |||
| private Vector errorFilterChains; | |||
| /** The input filter chains */ | |||
| private Vector inputFilterChains; | |||
| /** The output encoding */ | |||
| private String outputEncoding = defaultEncoding; | |||
| /** The error encoding */ | |||
| private String errorEncoding = defaultEncoding; | |||
| /** The input encoding */ | |||
| private String inputEncoding = defaultEncoding; | |||
| /** Whether to complete properties settings **/ | |||
| private boolean appendProperties = true; | |||
| /** The thread group used for starting <code>StreamPumper</code> threads */ | |||
| private ThreadGroup threadGroup = new ThreadGroup("redirector"); | |||
| /** | |||
| * Create a redirector instance for the given task | |||
| * | |||
| @@ -119,6 +182,15 @@ public class Redirector { | |||
| * @param input the file from which input is read. | |||
| */ | |||
| public void setInput(File input) { | |||
| setInput((input == null) ? null : new File[] {input}); | |||
| } | |||
| /** | |||
| * Set the input to use for the task | |||
| * | |||
| * @param input the files from which input is read. | |||
| */ | |||
| public synchronized void setInput(File[] input) { | |||
| this.input = input; | |||
| } | |||
| @@ -127,7 +199,7 @@ public class Redirector { | |||
| * | |||
| * @param inputString the string which is used as the input source | |||
| */ | |||
| public void setInputString(String inputString) { | |||
| public synchronized void setInputString(String inputString) { | |||
| this.inputString = inputString; | |||
| } | |||
| @@ -139,9 +211,61 @@ public class Redirector { | |||
| * @param out the file to which output stream is written | |||
| */ | |||
| public void setOutput(File out) { | |||
| setOutput((out == null) ? null : new File[] {out}); | |||
| } | |||
| /** | |||
| * Files the output of the process is redirected to. If error is not | |||
| * redirected, it too will appear in the output | |||
| * | |||
| * @param out the files to which output stream is written | |||
| */ | |||
| public synchronized void setOutput(File[] out) { | |||
| this.out = out; | |||
| } | |||
| /** | |||
| * Set the output encoding. | |||
| * | |||
| * @param outputEncoding <CODE>String</CODE>. | |||
| */ | |||
| public synchronized void setOutputEncoding(String outputEncoding) { | |||
| if (outputEncoding == null) { | |||
| throw new IllegalArgumentException( | |||
| "outputEncoding must not be null"); | |||
| } else { | |||
| this.outputEncoding = outputEncoding; | |||
| } | |||
| } | |||
| /** | |||
| * Set the error encoding. | |||
| * | |||
| * @param errorEncoding <CODE>String</CODE>. | |||
| */ | |||
| public synchronized void setErrorEncoding(String errorEncoding) { | |||
| if (errorEncoding == null) { | |||
| throw new IllegalArgumentException( | |||
| "errorEncoding must not be null"); | |||
| } else { | |||
| this.errorEncoding = errorEncoding; | |||
| } | |||
| } | |||
| /** | |||
| * Set the input encoding. | |||
| * | |||
| * @param inputEncoding <CODE>String</CODE>. | |||
| */ | |||
| public synchronized void setInputEncoding(String inputEncoding) { | |||
| if (inputEncoding == null) { | |||
| throw new IllegalArgumentException( | |||
| "inputEncoding must not be null"); | |||
| } else { | |||
| this.inputEncoding = inputEncoding; | |||
| } | |||
| } | |||
| /** | |||
| * Controls whether error output of exec is logged. This is only useful | |||
| * when output is being redirected and error output is desired in the | |||
| @@ -150,16 +274,36 @@ public class Redirector { | |||
| * @param logError if true the standard error is sent to the Ant log system | |||
| * and not sent to output. | |||
| */ | |||
| public void setLogError(boolean logError) { | |||
| public synchronized void setLogError(boolean logError) { | |||
| this.logError = logError; | |||
| } | |||
| /** | |||
| * This <CODE>Redirector</CODE>'s subordinate | |||
| * <CODE>PropertyOutputStream</CODE>s will not set their respective | |||
| * properties <CODE>while (appendProperties && append)</CODE>. | |||
| * | |||
| * @param appendProperties whether to append properties. | |||
| */ | |||
| public synchronized void setAppendProperties(boolean appendProperties) { | |||
| this.appendProperties = appendProperties; | |||
| } | |||
| /** | |||
| * Set the file to which standard error is to be redirected. | |||
| * | |||
| * @param error the file to which error is to be written | |||
| */ | |||
| public void setError(File error) { | |||
| setError((error == null) ? null : new File[] {error}); | |||
| } | |||
| /** | |||
| * Set the files to which standard error is to be redirected. | |||
| * | |||
| * @param error the file to which error is to be written | |||
| */ | |||
| public synchronized void setError(File[] error) { | |||
| this.error = error; | |||
| } | |||
| @@ -170,8 +314,12 @@ public class Redirector { | |||
| * @param outputProperty the name of the property to be set with the | |||
| * task's output. | |||
| */ | |||
| public void setOutputProperty(String outputProperty) { | |||
| this.outputProperty = outputProperty; | |||
| public synchronized void setOutputProperty(String outputProperty) { | |||
| if (outputProperty == null | |||
| || !(outputProperty.equals(this.outputProperty))) { | |||
| this.outputProperty = outputProperty; | |||
| baos = null; | |||
| } | |||
| } | |||
| /** | |||
| @@ -181,10 +329,19 @@ public class Redirector { | |||
| * @param append if true output and error streams are appended to their | |||
| * respective files, if specified. | |||
| */ | |||
| public void setAppend(boolean append) { | |||
| public synchronized void setAppend(boolean append) { | |||
| this.append = append; | |||
| } | |||
| /** | |||
| * Whether output and error files should be created even when empty. | |||
| * Defaults to true. | |||
| * @param createEmptyFiles <CODE>boolean</CODE>. | |||
| */ | |||
| public void setCreateEmptyFiles(boolean createEmptyFiles) { | |||
| this.createEmptyFiles = createEmptyFiles; | |||
| } | |||
| /** | |||
| * Property name whose value should be set to the error of | |||
| * the process. | |||
| @@ -192,8 +349,39 @@ public class Redirector { | |||
| * @param errorProperty the name of the property to be set | |||
| * with the error output. | |||
| */ | |||
| public void setErrorProperty(String errorProperty) { | |||
| this.errorProperty = errorProperty; | |||
| public synchronized void setErrorProperty(String errorProperty) { | |||
| if (errorProperty == null | |||
| || !(errorProperty.equals(this.errorProperty))) { | |||
| this.errorProperty = errorProperty; | |||
| errorBaos = null; | |||
| } | |||
| } | |||
| /** | |||
| * Set the input <CODE>FilterChain</CODE>s. | |||
| * | |||
| * @param <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | |||
| */ | |||
| public synchronized void setInputFilterChains(Vector inputFilterChains) { | |||
| this.inputFilterChains = inputFilterChains; | |||
| } | |||
| /** | |||
| * Set the output <CODE>FilterChain</CODE>s. | |||
| * | |||
| * @param <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | |||
| */ | |||
| public void setOutputFilterChains(Vector outputFilterChains) { | |||
| this.outputFilterChains = outputFilterChains; | |||
| } | |||
| /** | |||
| * Set the error <CODE>FilterChain</CODE>s. | |||
| * | |||
| * @param <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | |||
| */ | |||
| public void setErrorFilterChains(Vector errorFilterChains) { | |||
| this.errorFilterChains = errorFilterChains; | |||
| } | |||
| /** | |||
| @@ -207,8 +395,8 @@ public class Redirector { | |||
| private void setPropertyFromBAOS(ByteArrayOutputStream baos, | |||
| String propertyName) throws IOException { | |||
| BufferedReader in = | |||
| new BufferedReader(new StringReader(Execute.toString(baos))); | |||
| BufferedReader in | |||
| = new BufferedReader(new StringReader(Execute.toString(baos))); | |||
| String line = null; | |||
| StringBuffer val = new StringBuffer(); | |||
| while ((line = in.readLine()) != null) { | |||
| @@ -220,30 +408,34 @@ public class Redirector { | |||
| managingTask.getProject().setNewProperty(propertyName, val.toString()); | |||
| } | |||
| /** | |||
| * Create the input, error and output streams based on the | |||
| * configuration options. | |||
| */ | |||
| public void createStreams() { | |||
| if (out == null && outputProperty == null) { | |||
| public synchronized void createStreams() { | |||
| if ((out == null || out.length == 0) && outputProperty == null) { | |||
| outputStream = new LogOutputStream(managingTask, Project.MSG_INFO); | |||
| errorStream = new LogOutputStream(managingTask, Project.MSG_WARN); | |||
| } else { | |||
| if (out != null) { | |||
| outputStream = new LazyFileOutputStream(out, append, true); | |||
| managingTask.log("Output redirected to " + out, | |||
| Project.MSG_VERBOSE); | |||
| if (out != null && out.length > 0) { | |||
| String logHead = new StringBuffer("Output ").append( | |||
| ((append) ? "appended" : "redirected")).append( | |||
| " to ").toString(); | |||
| outputStream = foldFiles(out, logHead, Project.MSG_VERBOSE); | |||
| } | |||
| if (outputProperty != null) { | |||
| baos = new ByteArrayOutputStream(); | |||
| managingTask.log("Output redirected to property: " | |||
| + outputProperty, Project.MSG_VERBOSE); | |||
| if (out == null) { | |||
| outputStream = baos; | |||
| if (baos == null) { | |||
| baos = new PropertyOutputStream(outputProperty); | |||
| managingTask.log("Output redirected to property: " | |||
| + outputProperty, Project.MSG_VERBOSE); | |||
| } | |||
| //shield it from being closed by a filtering StreamPumper | |||
| OutputStream keepAliveOutput = new KeepAliveOutputStream(baos); | |||
| if (outputStream == null) { | |||
| outputStream = keepAliveOutput; | |||
| } else { | |||
| outputStream = new TeeOutputStream(outputStream, baos); | |||
| outputStream | |||
| = new TeeOutputStream(outputStream, keepAliveOutput); | |||
| } | |||
| } else { | |||
| baos = null; | |||
| @@ -252,44 +444,132 @@ public class Redirector { | |||
| errorStream = outputStream; | |||
| } | |||
| if (logError) { | |||
| errorStream = new LogOutputStream(managingTask, Project.MSG_WARN); | |||
| } | |||
| if (error != null && error.length > 0) { | |||
| String logHead = new StringBuffer("Error ").append( | |||
| ((append) ? "appended" : "redirected")).append( | |||
| " to ").toString(); | |||
| errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE); | |||
| if (error != null) { | |||
| errorStream = new LazyFileOutputStream(error, append, true); | |||
| managingTask.log("Error redirected to " + error, | |||
| Project.MSG_VERBOSE); | |||
| } else if (logError || errorStream == null) { | |||
| errorStream = new LogOutputStream(managingTask, Project.MSG_WARN); | |||
| } else { //must be errorStream == outputStream | |||
| long funnelTimeout = 0L; | |||
| OutputStreamFunneler funneler | |||
| = new OutputStreamFunneler(outputStream, funnelTimeout); | |||
| try { | |||
| outputStream = funneler.getFunnelInstance(); | |||
| errorStream = funneler.getFunnelInstance(); | |||
| } catch (IOException eyeOhEx) { | |||
| throw new BuildException( | |||
| "error splitting output/error streams", eyeOhEx); | |||
| } | |||
| } | |||
| if (errorProperty != null) { | |||
| errorBaos = new ByteArrayOutputStream(); | |||
| managingTask.log("Error redirected to property: " + errorProperty, | |||
| Project.MSG_VERBOSE); | |||
| if (error == null) { | |||
| errorStream = errorBaos; | |||
| } else { | |||
| errorStream = new TeeOutputStream(errorStream, errorBaos); | |||
| if (errorBaos == null) { | |||
| errorBaos = new PropertyOutputStream(errorProperty); | |||
| managingTask.log("Error redirected to property: " + errorProperty, | |||
| Project.MSG_VERBOSE); | |||
| } | |||
| //shield it from being closed by a filtering StreamPumper | |||
| OutputStream keepAliveError = new KeepAliveOutputStream(errorBaos); | |||
| errorStream = (error == null || error.length == 0) ? keepAliveError | |||
| : new TeeOutputStream(errorStream, keepAliveError); | |||
| } else { | |||
| errorBaos = null; | |||
| } | |||
| if (input != null && inputString != null) { | |||
| throw new BuildException("The \"input\" and \"inputstring\" " | |||
| + "attributes cannot both be specified"); | |||
| if ((outputFilterChains != null && outputFilterChains.size() > 0) | |||
| || !(outputEncoding.equalsIgnoreCase(inputEncoding))) { | |||
| try { | |||
| LeadPipeInputStream snk = new LeadPipeInputStream(); | |||
| snk.setManagingTask(managingTask); | |||
| InputStream outPumpIn = snk; | |||
| Reader reader = new InputStreamReader(outPumpIn, inputEncoding); | |||
| if (outputFilterChains != null && outputFilterChains.size() > 0) { | |||
| ChainReaderHelper helper = new ChainReaderHelper(); | |||
| helper.setPrimaryReader(reader); | |||
| helper.setFilterChains(outputFilterChains); | |||
| reader = helper.getAssembledReader(); | |||
| } | |||
| outPumpIn = new ReaderInputStream(reader, outputEncoding); | |||
| Thread t = new Thread(threadGroup, new StreamPumper( | |||
| outPumpIn, outputStream, true), "output pumper"); | |||
| t.setPriority(Thread.MAX_PRIORITY); | |||
| outputStream = new PipedOutputStream(snk); | |||
| t.start(); | |||
| } catch (IOException eyeOhEx) { | |||
| throw new BuildException( | |||
| "error setting up output stream", eyeOhEx); | |||
| } | |||
| } | |||
| if (input != null) { | |||
| if ((errorFilterChains != null && errorFilterChains.size() > 0) | |||
| || !(errorEncoding.equalsIgnoreCase(inputEncoding))) { | |||
| try { | |||
| inputStream = new FileInputStream(input); | |||
| } catch (FileNotFoundException fne) { | |||
| throw new BuildException("Cannot read from " + input, fne); | |||
| LeadPipeInputStream snk = new LeadPipeInputStream(); | |||
| snk.setManagingTask(managingTask); | |||
| InputStream errPumpIn = snk; | |||
| Reader reader = new InputStreamReader(errPumpIn, inputEncoding); | |||
| if (errorFilterChains != null && errorFilterChains.size() > 0) { | |||
| ChainReaderHelper helper = new ChainReaderHelper(); | |||
| helper.setPrimaryReader(reader); | |||
| helper.setFilterChains(errorFilterChains); | |||
| reader = helper.getAssembledReader(); | |||
| } | |||
| errPumpIn = new ReaderInputStream(reader, errorEncoding); | |||
| Thread t = new Thread(threadGroup, new StreamPumper( | |||
| errPumpIn, errorStream, true), "error pumper"); | |||
| t.setPriority(Thread.MAX_PRIORITY); | |||
| errorStream = new PipedOutputStream(snk); | |||
| t.start(); | |||
| } catch (IOException eyeOhEx) { | |||
| throw new BuildException( | |||
| "error setting up error stream", eyeOhEx); | |||
| } | |||
| } | |||
| // if input files are specified, inputString is ignored; | |||
| // classes that work with redirector attributes can enforce | |||
| // whatever warnings are needed | |||
| if (input != null && input.length > 0) { | |||
| managingTask.log("Redirecting input from file" | |||
| + ((input.length == 1) ? "" : "s"), Project.MSG_VERBOSE); | |||
| try { | |||
| inputStream = new ConcatFileInputStream(input); | |||
| } catch (IOException eyeOhEx) { | |||
| throw new BuildException(eyeOhEx); | |||
| } | |||
| ((ConcatFileInputStream)inputStream).setManagingTask(managingTask); | |||
| } else if (inputString != null) { | |||
| managingTask.log("Using input \"" + inputString + "\"", | |||
| Project.MSG_VERBOSE); | |||
| inputStream = new ByteArrayInputStream(inputString.getBytes()); | |||
| } | |||
| } | |||
| if (inputStream != null | |||
| && inputFilterChains != null && inputFilterChains.size() > 0) { | |||
| ChainReaderHelper helper = new ChainReaderHelper(); | |||
| try { | |||
| helper.setPrimaryReader( | |||
| new InputStreamReader(inputStream, inputEncoding)); | |||
| } catch (IOException eyeOhEx) { | |||
| throw new BuildException( | |||
| "error setting up input stream", eyeOhEx); | |||
| } | |||
| helper.setFilterChains(inputFilterChains); | |||
| inputStream = new ReaderInputStream( | |||
| helper.getAssembledReader(), inputEncoding); | |||
| } | |||
| } | |||
| /** | |||
| * Create the StreamHandler to use with our Execute instance. | |||
| @@ -299,7 +579,8 @@ public class Redirector { | |||
| * | |||
| * @throws BuildException if the execute stream handler cannot be created. | |||
| */ | |||
| public ExecuteStreamHandler createHandler() throws BuildException { | |||
| public synchronized ExecuteStreamHandler createHandler() | |||
| throws BuildException { | |||
| createStreams(); | |||
| return new PumpStreamHandler(outputStream, errorStream, inputStream); | |||
| } | |||
| @@ -309,7 +590,7 @@ public class Redirector { | |||
| * | |||
| * @param output the data to be output | |||
| */ | |||
| protected void handleOutput(String output) { | |||
| protected synchronized void handleOutput(String output) { | |||
| if (outPrintStream == null) { | |||
| outPrintStream = new PrintStream(outputStream); | |||
| } | |||
| @@ -327,8 +608,8 @@ public class Redirector { | |||
| * | |||
| * @exception IOException if the data cannot be read | |||
| */ | |||
| protected int handleInput(byte[] buffer, int offset, int length) | |||
| throws IOException { | |||
| protected synchronized int handleInput(byte[] buffer, int offset, | |||
| int length) throws IOException { | |||
| if (inputStream == null) { | |||
| return managingTask.getProject().defaultInput(buffer, offset, | |||
| length); | |||
| @@ -342,7 +623,7 @@ public class Redirector { | |||
| * | |||
| * @param output the data being flushed. | |||
| */ | |||
| protected void handleFlush(String output) { | |||
| protected synchronized void handleFlush(String output) { | |||
| if (outPrintStream == null) { | |||
| outPrintStream = new PrintStream(outputStream); | |||
| } | |||
| @@ -355,7 +636,7 @@ public class Redirector { | |||
| * | |||
| * @param output the error output data. | |||
| */ | |||
| protected void handleErrorOutput(String output) { | |||
| protected synchronized void handleErrorOutput(String output) { | |||
| if (errorPrintStream == null) { | |||
| errorPrintStream = new PrintStream(errorStream); | |||
| } | |||
| @@ -367,7 +648,7 @@ public class Redirector { | |||
| * | |||
| * @param output the error information being flushed. | |||
| */ | |||
| protected void handleErrorFlush(String output) { | |||
| protected synchronized void handleErrorFlush(String output) { | |||
| if (errorPrintStream == null) { | |||
| errorPrintStream = new PrintStream(errorStream); | |||
| } | |||
| @@ -380,7 +661,7 @@ public class Redirector { | |||
| * @return the redirector's output stream or null if no output | |||
| * has been configured | |||
| */ | |||
| public OutputStream getOutputStream() { | |||
| public synchronized OutputStream getOutputStream() { | |||
| return outputStream; | |||
| } | |||
| @@ -390,7 +671,7 @@ public class Redirector { | |||
| * @return the redirector's error stream or null if no output | |||
| * has been configured | |||
| */ | |||
| public OutputStream getErrorStream() { | |||
| public synchronized OutputStream getErrorStream() { | |||
| return errorStream; | |||
| } | |||
| @@ -400,7 +681,7 @@ public class Redirector { | |||
| * @return the redirector's input stream or null if no output | |||
| * has been configured | |||
| */ | |||
| public InputStream getInputStream() { | |||
| public synchronized InputStream getInputStream() { | |||
| return inputStream; | |||
| } | |||
| @@ -413,7 +694,7 @@ public class Redirector { | |||
| * @throws IOException if the output properties cannot be read from their | |||
| * output streams. | |||
| */ | |||
| public void complete() throws IOException { | |||
| public synchronized void complete() throws IOException { | |||
| System.out.flush(); | |||
| System.err.flush(); | |||
| @@ -421,17 +702,69 @@ public class Redirector { | |||
| inputStream.close(); | |||
| } | |||
| outputStream.flush(); | |||
| outputStream.close(); | |||
| if (errorStream != outputStream) { | |||
| errorStream.close(); | |||
| errorStream.flush(); | |||
| errorStream.close(); | |||
| //wait for the StreamPumpers to finish | |||
| while (threadGroup.activeCount() > 0) { | |||
| try { | |||
| managingTask.log("waiting for " + threadGroup.activeCount() | |||
| + " Threads:", Project.MSG_DEBUG); | |||
| Thread[] thread = new Thread[threadGroup.activeCount()]; | |||
| threadGroup.enumerate(thread); | |||
| for (int i = 0; i < thread.length && thread[i] != null; i++) { | |||
| try { | |||
| managingTask.log(thread[i].toString(), Project.MSG_DEBUG); | |||
| } catch (NullPointerException enPeaEx) { | |||
| } | |||
| } | |||
| Thread.sleep(1000); | |||
| } catch (InterruptedException eyeEx) { | |||
| } | |||
| } | |||
| setProperties(); | |||
| inputStream = null; | |||
| outputStream = errorStream = outPrintStream = errorPrintStream = null; | |||
| } | |||
| /** | |||
| * Notify the <CODE>Redirector</CODE> that it is now okay | |||
| * to set any output and/or error properties. | |||
| */ | |||
| public synchronized void setProperties() { | |||
| if (baos != null) { | |||
| setPropertyFromBAOS(baos, outputProperty); | |||
| try { | |||
| baos.close(); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| } | |||
| if (errorBaos != null) { | |||
| setPropertyFromBAOS(errorBaos, errorProperty); | |||
| try { | |||
| errorBaos.close(); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| } | |||
| } | |||
| private OutputStream foldFiles(File[] file, String logHead, int loglevel) { | |||
| OutputStream result | |||
| = new LazyFileOutputStream(file[0], append, createEmptyFiles); | |||
| managingTask.log(logHead + file[0], loglevel); | |||
| char[] c = new char[logHead.length()]; | |||
| Arrays.fill(c, ' '); | |||
| String indent = new String(c); | |||
| for (int i = 1; i < file.length ; i++) { | |||
| outputStream = new TeeOutputStream(outputStream, | |||
| new LazyFileOutputStream(file[i], append, createEmptyFiles)); | |||
| managingTask.log(indent + file[i], loglevel); | |||
| } | |||
| return result; | |||
| } | |||
| } | |||
| @@ -0,0 +1,511 @@ | |||
| /* | |||
| * Copyright 2004 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.types; | |||
| import java.io.File; | |||
| import java.util.Vector; | |||
| import java.util.ArrayList; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.taskdefs.Redirector; | |||
| import org.apache.tools.ant.types.DataType; | |||
| /** | |||
| * Element representation of a <CODE>Redirector</CODE>. | |||
| */ | |||
| public class RedirectorElement extends DataType { | |||
| /** | |||
| * Whether the input mapper was set via <CODE>setOutput</CODE>. | |||
| */ | |||
| private boolean usingInput = false; | |||
| /** | |||
| * Whether the output mapper was set via <CODE>setOutput</CODE>. | |||
| */ | |||
| private boolean usingOutput = false; | |||
| /** | |||
| * Whether the error mapper was set via <CODE>setError</CODE>. | |||
| */ | |||
| private boolean usingError = false; | |||
| /** | |||
| * Indicates if standard error should be logged to Ant's log system | |||
| * rather than the output. This has no effect if standard error is | |||
| * redirected to a file or property. | |||
| */ | |||
| private Boolean logError; | |||
| /** The name of the property into which output is to be stored */ | |||
| private String outputProperty; | |||
| /** The name of the property into which error output is to be stored */ | |||
| private String errorProperty; | |||
| /** String from which input is taken */ | |||
| private String inputString; | |||
| /** Flag which indicates if error and output files are to be appended. */ | |||
| private Boolean append; | |||
| /** Flag which indicates whether files should be created even if empty. */ | |||
| private Boolean createEmptyFiles; | |||
| /** Input file mapper. */ | |||
| private Mapper inputMapper; | |||
| /** Output file mapper. */ | |||
| private Mapper outputMapper; | |||
| /** Error file mapper. */ | |||
| private Mapper errorMapper; | |||
| /** input filter chains. */ | |||
| private Vector inputFilterChains = new Vector(); | |||
| /** output filter chains. */ | |||
| private Vector outputFilterChains = new Vector(); | |||
| /** error filter chains. */ | |||
| private Vector errorFilterChains = new Vector(); | |||
| /** The output encoding */ | |||
| private String outputEncoding; | |||
| /** The error encoding */ | |||
| private String errorEncoding; | |||
| /** The input encoding */ | |||
| private String inputEncoding; | |||
| /** | |||
| * Add the input file mapper. | |||
| * @param inputMapper <CODE>Mapper</CODE>. | |||
| */ | |||
| public void addConfiguredInputMapper(Mapper inputMapper) { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| if (this.inputMapper != null) { | |||
| if (usingInput) { | |||
| throw new BuildException("attribute \"input\"" | |||
| + " cannot coexist with a nested <inputmapper>"); | |||
| } else { | |||
| throw new BuildException("Cannot have > 1 <inputmapper>"); | |||
| } | |||
| } | |||
| this.inputMapper = inputMapper; | |||
| } | |||
| /** | |||
| * Add the output file mapper. | |||
| * @param outputMapper <CODE>Mapper</CODE>. | |||
| */ | |||
| public void addConfiguredOutputMapper(Mapper outputMapper) { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| if (this.outputMapper != null) { | |||
| if (usingOutput) { | |||
| throw new BuildException("attribute \"output\"" | |||
| + " cannot coexist with a nested <outputmapper>"); | |||
| } else { | |||
| throw new BuildException("Cannot have > 1 <outputmapper>"); | |||
| } | |||
| } | |||
| this.outputMapper = outputMapper; | |||
| } | |||
| /** | |||
| * Add the error file mapper. | |||
| * @param errorMapper <CODE>Mapper</CODE>. | |||
| */ | |||
| public void addConfiguredErrorMapper(Mapper errorMapper) { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| if (this.errorMapper != null) { | |||
| if (usingError) { | |||
| throw new BuildException("attribute \"error\"" | |||
| + " cannot coexist with a nested <errormapper>"); | |||
| } else { | |||
| throw new BuildException("Cannot have > 1 <errormapper>"); | |||
| } | |||
| } | |||
| this.errorMapper = errorMapper; | |||
| } | |||
| /** | |||
| * Makes this instance in effect a reference to another instance. | |||
| * | |||
| * <p>You must not set another attribute or nest elements inside | |||
| * this element if you make it a reference.</p> | |||
| */ | |||
| public void setRefid(Reference r) throws BuildException { | |||
| if (usingInput | |||
| || usingOutput | |||
| || usingError | |||
| || inputString != null | |||
| || logError != null | |||
| || append != null | |||
| || outputProperty != null | |||
| || errorProperty != null) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| super.setRefid(r); | |||
| } | |||
| /** | |||
| * Set the input to use for the task | |||
| * @param input the file from which input is read. | |||
| */ | |||
| public void setInput(File input) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| if (inputString != null) { | |||
| throw new BuildException("The \"input\" and \"inputstring\" " | |||
| + "attributes cannot both be specified"); | |||
| } | |||
| usingInput = true; | |||
| inputMapper = createMergeMapper(input); | |||
| } | |||
| /** | |||
| * Set the string to use as input | |||
| * @param inputString the string which is used as the input source | |||
| */ | |||
| public void setInputString(String inputString) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| if (usingInput) { | |||
| throw new BuildException("The \"input\" and \"inputstring\" " | |||
| + "attributes cannot both be specified"); | |||
| } | |||
| this.inputString = inputString; | |||
| } | |||
| /** | |||
| * File the output of the process is redirected to. If error is not | |||
| * redirected, it too will appear in the output | |||
| * | |||
| * @param out the file to which output stream is written | |||
| */ | |||
| public void setOutput(File out) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| if (out == null) { | |||
| throw new IllegalArgumentException("output file specified as null"); | |||
| } | |||
| usingOutput = true; | |||
| outputMapper = createMergeMapper(out); | |||
| } | |||
| /** | |||
| * Set the output encoding. | |||
| * @param outputEncoding <CODE>String</CODE>. | |||
| */ | |||
| public void setOutputEncoding(String outputEncoding) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| this.outputEncoding = outputEncoding; | |||
| } | |||
| /** | |||
| * Set the error encoding. | |||
| * | |||
| * @param errorEncoding <CODE>String</CODE>. | |||
| */ | |||
| public void setErrorEncoding(String errorEncoding) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| this.errorEncoding = errorEncoding; | |||
| } | |||
| /** | |||
| * Set the input encoding. | |||
| * @param inputEncoding <CODE>String</CODE>. | |||
| */ | |||
| public void setInputEncoding(String inputEncoding) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| this.inputEncoding = inputEncoding; | |||
| } | |||
| /** | |||
| * Controls whether error output of exec is logged. This is only useful | |||
| * when output is being redirected and error output is desired in the | |||
| * Ant log | |||
| * @param logError if true the standard error is sent to the Ant log system | |||
| * and not sent to output. | |||
| */ | |||
| public void setLogError(boolean logError) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| //pre JDK 1.4 compatible | |||
| this.logError = ((logError) ? Boolean.TRUE : Boolean.FALSE); | |||
| } | |||
| /** | |||
| * Set the file to which standard error is to be redirected. | |||
| * @param error the file to which error is to be written | |||
| */ | |||
| public void setError(File error) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| if (error == null) { | |||
| throw new IllegalArgumentException("error file specified as null"); | |||
| } | |||
| usingError = true; | |||
| errorMapper = createMergeMapper(error); | |||
| } | |||
| /** | |||
| * Property name whose value should be set to the output of | |||
| * the process. | |||
| * @param outputProperty the name of the property to be set with the | |||
| * task's output. | |||
| */ | |||
| public void setOutputProperty(String outputProperty) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| this.outputProperty = outputProperty; | |||
| } | |||
| /** | |||
| * Whether output should be appended to or overwrite an existing file. | |||
| * Defaults to false. | |||
| * @param append if true output and error streams are appended to their | |||
| * respective files, if specified. | |||
| */ | |||
| public void setAppend(boolean append) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| //pre JDK 1.4 compatible | |||
| this.append = ((append) ? Boolean.TRUE : Boolean.FALSE); | |||
| } | |||
| /** | |||
| * Whether output and error files should be created even when empty. | |||
| * Defaults to true. | |||
| * @param createEmptyFiles <CODE>boolean</CODE>. | |||
| */ | |||
| public void setCreateEmptyFiles(boolean createEmptyFiles) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| //pre JDK 1.4 compatible | |||
| this.createEmptyFiles = ((createEmptyFiles) | |||
| ? Boolean.TRUE : Boolean.FALSE); | |||
| } | |||
| /** | |||
| * Property name whose value should be set to the error of | |||
| * the process. | |||
| * @param errorProperty the name of the property to be set | |||
| * with the error output. | |||
| */ | |||
| public void setErrorProperty(String errorProperty) { | |||
| if (isReference()) { | |||
| throw tooManyAttributes(); | |||
| } | |||
| this.errorProperty = errorProperty; | |||
| } | |||
| /** | |||
| * Create a nested input <CODE>FilterChain</CODE>. | |||
| * @return <CODE>FilterChain</CODE>. | |||
| */ | |||
| public FilterChain createInputFilterChain() { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| FilterChain result = new FilterChain(); | |||
| result.setProject(getProject()); | |||
| inputFilterChains.add(result); | |||
| return result; | |||
| } | |||
| /** | |||
| * Create a nested output <CODE>FilterChain</CODE>. | |||
| * @return <CODE>FilterChain</CODE>. | |||
| */ | |||
| public FilterChain createOutputFilterChain() { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| FilterChain result = new FilterChain(); | |||
| result.setProject(getProject()); | |||
| outputFilterChains.add(result); | |||
| return result; | |||
| } | |||
| /** | |||
| * Create a nested error <CODE>FilterChain</CODE>. | |||
| * @return <CODE>FilterChain</CODE>. | |||
| */ | |||
| public FilterChain createErrorFilterChain() { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| FilterChain result = new FilterChain(); | |||
| result.setProject(getProject()); | |||
| errorFilterChains.add(result); | |||
| return result; | |||
| } | |||
| /** | |||
| * Configure the specified <CODE>Redirector</CODE>. | |||
| * @param redirector <CODE>Redirector</CODE>. | |||
| */ | |||
| public void configure(Redirector redirector) { | |||
| configure(redirector, null); | |||
| } | |||
| /** | |||
| * Configure the specified <CODE>Redirector</CODE> | |||
| * for the specified sourcefile. | |||
| * @param redirector <CODE>Redirector</CODE>. | |||
| * @param sourcefile <CODE>String</CODE>. | |||
| */ | |||
| public void configure(Redirector redirector, String sourcefile) { | |||
| if (logError != null) { | |||
| redirector.setLogError(logError.booleanValue()); | |||
| } | |||
| if (append != null) { | |||
| redirector.setAppend(append.booleanValue()); | |||
| } | |||
| if (createEmptyFiles != null) { | |||
| redirector.setCreateEmptyFiles(createEmptyFiles.booleanValue()); | |||
| } | |||
| if (outputProperty != null) { | |||
| redirector.setOutputProperty(outputProperty); | |||
| } | |||
| if (errorProperty != null) { | |||
| redirector.setErrorProperty(errorProperty); | |||
| } | |||
| if (inputString != null) { | |||
| redirector.setInputString(inputString); | |||
| } | |||
| if (inputMapper != null) { | |||
| String[] inputTargets = null; | |||
| try { | |||
| inputTargets = | |||
| inputMapper.getImplementation().mapFileName(sourcefile); | |||
| } catch (NullPointerException enPeaEx) { | |||
| if (sourcefile != null) { | |||
| throw enPeaEx; | |||
| } | |||
| } | |||
| if (inputTargets != null && inputTargets.length > 0) { | |||
| redirector.setInput(toFileArray(inputTargets)); | |||
| } | |||
| } | |||
| if (outputMapper != null) { | |||
| String[] outputTargets = null; | |||
| try { | |||
| outputTargets = | |||
| outputMapper.getImplementation().mapFileName(sourcefile); | |||
| } catch (NullPointerException enPeaEx) { | |||
| if (sourcefile != null) { | |||
| throw enPeaEx; | |||
| } | |||
| } | |||
| if (outputTargets != null && outputTargets.length > 0) { | |||
| redirector.setOutput(toFileArray(outputTargets)); | |||
| } | |||
| } | |||
| if (errorMapper != null) { | |||
| String[] errorTargets = null; | |||
| try { | |||
| errorTargets = | |||
| errorMapper.getImplementation().mapFileName(sourcefile); | |||
| } catch (NullPointerException enPeaEx) { | |||
| if (sourcefile != null) { | |||
| throw enPeaEx; | |||
| } | |||
| } | |||
| if (errorTargets != null && errorTargets.length > 0) { | |||
| redirector.setError(toFileArray(errorTargets)); | |||
| } | |||
| } | |||
| if (inputFilterChains.size() > 0) { | |||
| redirector.setInputFilterChains(inputFilterChains); | |||
| } | |||
| if (outputFilterChains.size() > 0) { | |||
| redirector.setOutputFilterChains(outputFilterChains); | |||
| } | |||
| if (errorFilterChains.size() > 0) { | |||
| redirector.setErrorFilterChains(errorFilterChains); | |||
| } | |||
| if (inputEncoding != null) { | |||
| redirector.setInputEncoding(inputEncoding); | |||
| } | |||
| if (outputEncoding != null) { | |||
| redirector.setOutputEncoding(outputEncoding); | |||
| } | |||
| if (errorEncoding != null) { | |||
| redirector.setErrorEncoding(errorEncoding); | |||
| } | |||
| } | |||
| /** | |||
| * Create a merge mapper pointing to the specified destination file. | |||
| * @param destfile <CODE>File</CODE> | |||
| * @return <CODE>Mapper</CODE>. | |||
| */ | |||
| protected Mapper createMergeMapper(File destfile) { | |||
| Mapper result = new Mapper(getProject()); | |||
| result.setClassname( | |||
| org.apache.tools.ant.util.MergingMapper.class.getName()); | |||
| result.setTo(destfile.getAbsolutePath()); | |||
| return result; | |||
| } | |||
| /** | |||
| * Return a <CODE>File[]</CODE> from the specified set of filenames. | |||
| * @param name <CODE>String[]</CODE> | |||
| * @return <CODE>File[]</CODE>. | |||
| */ | |||
| protected File[] toFileArray(String[] name) { | |||
| if (name == null) { | |||
| return null; | |||
| } | |||
| //remove any null elements | |||
| ArrayList list = new ArrayList(name.length); | |||
| for (int i = 0; i < name.length; i++) { | |||
| if (name[i] != null) { | |||
| list.add(getProject().resolveFile(name[i])); | |||
| } | |||
| } | |||
| return (File[])(list.toArray(new File[list.size()])); | |||
| } | |||
| } | |||
| @@ -0,0 +1,120 @@ | |||
| /* | |||
| * Copyright 2004 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.util; | |||
| import java.io.File; | |||
| import java.io.InputStream; | |||
| import java.io.BufferedInputStream; | |||
| import java.io.IOException; | |||
| import java.io.FileInputStream; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.Project; | |||
| /** | |||
| * Special <CODE>InputStream</CODE> that will | |||
| * concatenate the contents of an array of files. | |||
| */ | |||
| public class ConcatFileInputStream extends InputStream { | |||
| private static final int EOF = -1; | |||
| private int currentIndex = 0; | |||
| private boolean eof = false; | |||
| private File[] file; | |||
| private InputStream currentStream; | |||
| private Task managingTask; | |||
| /** | |||
| * Construct a new <CODE>ConcatFileInputStream</CODE> | |||
| * with the specified <CODE>File[]</CODE>. | |||
| * @param file <CODE>File[]</CODE>. | |||
| * @throws <CODE>IOException</CODE> if I/O errors occur. | |||
| */ | |||
| public ConcatFileInputStream(File[] file) throws IOException { | |||
| this.file = file; | |||
| openFile(currentIndex); | |||
| } | |||
| // inherit doc | |||
| public void close() throws IOException { | |||
| closeCurrent(); | |||
| eof = true; | |||
| } | |||
| // inherit doc | |||
| public int read() throws IOException { | |||
| int result = readCurrent(); | |||
| if (result == EOF && !eof) { | |||
| openFile(++currentIndex); | |||
| result = readCurrent(); | |||
| } | |||
| return result; | |||
| } | |||
| /** | |||
| * Set a managing <CODE>Task</CODE> for | |||
| * this <CODE>ConcatFileInputStream</CODE>. | |||
| * @param task the managing <CODE>Task</CODE>. | |||
| */ | |||
| public void setManagingTask(Task task) { | |||
| this.managingTask = task; | |||
| } | |||
| /** | |||
| * Log a message with the specified logging level. | |||
| * @param message the <CODE>String</CODE> message. | |||
| * @param loglevel the <CODE>int</CODE> logging level. | |||
| */ | |||
| public void log(String message, int loglevel) { | |||
| if (managingTask != null) { | |||
| managingTask.log(message, loglevel); | |||
| } else { | |||
| if (loglevel > Project.MSG_WARN) { | |||
| System.out.println(message); | |||
| } else { | |||
| System.err.println(message); | |||
| } | |||
| } | |||
| } | |||
| private int readCurrent() throws IOException { | |||
| return (eof || currentStream == null) ? EOF : currentStream.read(); | |||
| } | |||
| private void openFile(int index) throws IOException { | |||
| closeCurrent(); | |||
| if (file != null && index < file.length) { | |||
| log("Opening " + file[index], Project.MSG_VERBOSE); | |||
| currentStream = new BufferedInputStream( | |||
| new FileInputStream(file[index])); | |||
| } else { | |||
| eof = true; | |||
| } | |||
| } | |||
| private void closeCurrent() { | |||
| if (currentStream != null) { | |||
| try { | |||
| currentStream.close(); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| currentStream = null; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,95 @@ | |||
| /* | |||
| * Copyright 2004 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.util; | |||
| import java.io.IOException; | |||
| import java.io.PipedInputStream; | |||
| import java.io.PipedOutputStream; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.Project; | |||
| /** | |||
| * Special <CODE>PipedInputStream</CODE> that will not die | |||
| * when the writing <CODE>Thread</CODE> is no longer alive. | |||
| */ | |||
| public class LeadPipeInputStream extends PipedInputStream { | |||
| private Task managingTask; | |||
| /** | |||
| * Construct a new <CODE>LeadPipeInputStream</CODE>. | |||
| */ | |||
| public LeadPipeInputStream() { | |||
| super(); | |||
| } | |||
| /** | |||
| * Construct a new <CODE>LeadPipeInputStream</CODE> to pull | |||
| * from the specified <CODE>PipedOutputStream</CODE>. | |||
| * @param src the <CODE>PipedOutputStream</CODE> source. | |||
| */ | |||
| public LeadPipeInputStream(PipedOutputStream src) throws IOException { | |||
| super(src); | |||
| } | |||
| //inherit doc | |||
| public synchronized int read() throws IOException { | |||
| int result = -1; | |||
| try { | |||
| result = super.read(); | |||
| } catch (IOException eyeOhEx) { | |||
| if ("write end dead".equalsIgnoreCase(eyeOhEx.getMessage())) { | |||
| if (super.in > 0 && super.out < super.buffer.length | |||
| && super.out > super.in) { | |||
| result = super.buffer[super.out++] & 0xFF; | |||
| } | |||
| } else { | |||
| log("error at LeadPipeInputStream.read(): " | |||
| + eyeOhEx.getMessage(), Project.MSG_INFO); | |||
| } | |||
| } | |||
| return result; | |||
| } | |||
| /** | |||
| * Set a managing <CODE>Task</CODE> for | |||
| * this <CODE>LeadPipeInputStream</CODE>. | |||
| * @param task the managing <CODE>Task</CODE>. | |||
| */ | |||
| public void setManagingTask(Task task) { | |||
| this.managingTask = task; | |||
| } | |||
| /** | |||
| * Log a message with the specified logging level. | |||
| * @param message the <CODE>String</CODE> message. | |||
| * @param loglevel the <CODE>int</CODE> logging level. | |||
| */ | |||
| public void log(String message, int loglevel) { | |||
| if (managingTask != null) { | |||
| managingTask.log(message, loglevel); | |||
| } else { | |||
| if (loglevel > Project.MSG_WARN) { | |||
| System.out.println(message); | |||
| } else { | |||
| System.err.println(message); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,175 @@ | |||
| /* | |||
| * Copyright 2004 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.util; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.io.FilterOutputStream; | |||
| /** | |||
| * Manages a set of <CODE>OutputStream</CODE>s to | |||
| * write to a single underlying stream, which is | |||
| * closed only when the last "funnel" | |||
| * has been closed. | |||
| */ | |||
| public class OutputStreamFunneler { | |||
| /** | |||
| * Default timeout. | |||
| * @see #setTimeout() | |||
| */ | |||
| public static final long DEFAULT_TIMEOUT_MILLIS = 1000; | |||
| private class Funnel extends OutputStream { | |||
| private boolean closed = false; | |||
| private Funnel() { | |||
| synchronized (OutputStreamFunneler.this) { | |||
| ++count; | |||
| } | |||
| } | |||
| public void flush() throws IOException { | |||
| synchronized (OutputStreamFunneler.this) { | |||
| dieIfClosed(); | |||
| out.flush(); | |||
| } | |||
| } | |||
| public void write(int b) throws IOException { | |||
| synchronized (OutputStreamFunneler.this) { | |||
| dieIfClosed(); | |||
| out.write(b); | |||
| } | |||
| } | |||
| public void write(byte[] b) throws IOException { | |||
| synchronized (OutputStreamFunneler.this) { | |||
| dieIfClosed(); | |||
| out.write(b); | |||
| } | |||
| } | |||
| public void write(byte[] b, int off, int len) throws IOException { | |||
| synchronized (OutputStreamFunneler.this) { | |||
| dieIfClosed(); | |||
| out.write(b, off, len); | |||
| } | |||
| } | |||
| public void close() throws IOException { | |||
| release(this); | |||
| } | |||
| } | |||
| private OutputStream out; | |||
| private int count = 0; | |||
| private boolean closed; | |||
| private long timeoutMillis; | |||
| /** | |||
| * Create a new <CODE>OutputStreamFunneler</CODE> for | |||
| * the specified <CODE>OutputStream</CODE>. | |||
| * @param out <CODE>OutputStream</CODE>. | |||
| */ | |||
| public OutputStreamFunneler(OutputStream out) { | |||
| this(out, DEFAULT_TIMEOUT_MILLIS); | |||
| } | |||
| /** | |||
| * Create a new <CODE>OutputStreamFunneler</CODE> for | |||
| * the specified <CODE>OutputStream</CODE>, with the | |||
| * specified timeout value. | |||
| * @param out <CODE>OutputStream</CODE>. | |||
| * @param timeoutMillis <CODE>long</CODE>. | |||
| * @see #setTimeout() | |||
| */ | |||
| public OutputStreamFunneler(OutputStream out, long timeoutMillis) { | |||
| if (out == null) { | |||
| throw new IllegalArgumentException( | |||
| "OutputStreamFunneler.<init>: out == null"); | |||
| } | |||
| this.out = out; | |||
| this.closed = false; //as far as we know | |||
| setTimeout(timeoutMillis); | |||
| } | |||
| /** | |||
| * Set the timeout for this <CODE>OutputStreamFunneler</CODE>. | |||
| * This is the maximum time that may elapse between the closure | |||
| * of the last "funnel" and the next call to | |||
| * <CODE>getOutputStream()</CODE> without closing the | |||
| * underlying stream. | |||
| * @param timeoutMillis <CODE>long</CODE> timeout value. | |||
| */ | |||
| public synchronized void setTimeout(long timeoutMillis) { | |||
| this.timeoutMillis = timeoutMillis; | |||
| } | |||
| /** | |||
| * Get a "funnel" <CODE>OutputStream</CODE> instance to | |||
| * write to this <CODE>OutputStreamFunneler</CODE>'s underlying | |||
| * <CODE>OutputStream</CODE>. | |||
| * @return <code>OutputStream</code>. | |||
| */ | |||
| public synchronized OutputStream getFunnelInstance() | |||
| throws IOException { | |||
| dieIfClosed(); | |||
| try { | |||
| return new Funnel(); | |||
| } finally { | |||
| notifyAll(); | |||
| } | |||
| } | |||
| private synchronized void release(Funnel funnel) throws IOException { | |||
| //ignore release of an already-closed funnel | |||
| if (!funnel.closed) { | |||
| try { | |||
| if (timeoutMillis > 0) { | |||
| try { | |||
| wait(timeoutMillis); | |||
| } catch (InterruptedException eyeEx) { | |||
| //ignore | |||
| } | |||
| } | |||
| if (--count == 0) { | |||
| close(); | |||
| } | |||
| } finally { | |||
| funnel.closed = true; | |||
| } | |||
| } | |||
| } | |||
| private synchronized void close() throws IOException { | |||
| try { | |||
| dieIfClosed(); | |||
| out.close(); | |||
| } finally { | |||
| closed = true; | |||
| } | |||
| } | |||
| private synchronized void dieIfClosed() throws IOException { | |||
| if (closed) { | |||
| throw new IOException("The funneled OutputStream has been closed."); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,203 @@ | |||
| /* | |||
| * Copyright 2004 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.util; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.Reader; | |||
| /** | |||
| * Adapts a <code>Reader</code> as an <code>InputStream</code>. | |||
| * Adapted from <CODE>StringInputStream</CODE>. | |||
| * | |||
| */ | |||
| public class ReaderInputStream extends InputStream { | |||
| /** Source Reader */ | |||
| private Reader in; | |||
| private String encoding = System.getProperty("file.encoding"); | |||
| private byte[] slack; | |||
| private int begin; | |||
| /** | |||
| * Construct a <CODE>ReaderInputStream</CODE> | |||
| * for the specified <CODE>Reader</CODE>. | |||
| * | |||
| * @param reader <CODE>Reader</CODE>. Must not be <code>null</code>. | |||
| */ | |||
| public ReaderInputStream(Reader reader) { | |||
| in = reader; | |||
| } | |||
| /** | |||
| * Construct a <CODE>ReaderInputStream</CODE> | |||
| * for the specified <CODE>Reader</CODE>, | |||
| * with the specified encoding. | |||
| * | |||
| * @param reader non-null <CODE>Reader</CODE>. | |||
| * @param encoding non-null <CODE>String</CODE> encoding. | |||
| */ | |||
| public ReaderInputStream(Reader reader, String encoding) { | |||
| this(reader); | |||
| if (encoding == null) { | |||
| throw new IllegalArgumentException("encoding must not be null"); | |||
| } else { | |||
| this.encoding = encoding; | |||
| } | |||
| } | |||
| /** | |||
| * Reads from the <CODE>Reader</CODE>, returning the same value. | |||
| * | |||
| * @return the value of the next character in the <CODE>Reader</CODE>. | |||
| * | |||
| * @exception IOException if the original <code>Reader</code> fails to be read | |||
| */ | |||
| public synchronized int read() throws IOException { | |||
| if (in == null) { | |||
| throw new IOException("Stream Closed"); | |||
| } | |||
| byte result; | |||
| if (slack != null && begin < slack.length) { | |||
| result = slack[begin]; | |||
| if (++begin == slack.length) { | |||
| slack = null; | |||
| } | |||
| } else { | |||
| byte[] buf = new byte[1]; | |||
| if (read(buf, 0, 1) <= 0) { | |||
| result = -1; | |||
| } | |||
| result = buf[0]; | |||
| } | |||
| if (result < -1) { | |||
| result+= 256; | |||
| } | |||
| return result; | |||
| } | |||
| /** | |||
| * Reads from the <code>Reader</code> into a byte array | |||
| * | |||
| * @param b the byte array to read into | |||
| * @param off the offset in the byte array | |||
| * @param len the length in the byte array to fill | |||
| * @return the actual number read into the byte array, -1 at | |||
| * the end of the stream | |||
| * @exception IOException if an error occurs | |||
| */ | |||
| public synchronized int read(byte[] b, int off, int len) | |||
| throws IOException { | |||
| if (in == null) { | |||
| throw new IOException("Stream Closed"); | |||
| } | |||
| while (slack == null) { | |||
| char[] buf = new char[len]; // might read too much | |||
| int n = in.read(buf); | |||
| if (n == -1) { | |||
| return -1; | |||
| } | |||
| if (n > 0) { | |||
| slack = new String(buf, 0, n).getBytes(encoding); | |||
| begin = 0; | |||
| } | |||
| } | |||
| if (len > slack.length - begin) { | |||
| len = slack.length - begin; | |||
| } | |||
| System.arraycopy(slack, begin, b, off, len); | |||
| if ((begin+= len) >= slack.length) { | |||
| slack = null; | |||
| } | |||
| return len; | |||
| } | |||
| /** | |||
| * Marks the read limit of the StringReader. | |||
| * | |||
| * @param limit the maximum limit of bytes that can be read before the | |||
| * mark position becomes invalid | |||
| */ | |||
| public synchronized void mark(final int limit) { | |||
| try { | |||
| in.mark(limit); | |||
| } catch (IOException ioe) { | |||
| throw new RuntimeException(ioe.getMessage()); | |||
| } | |||
| } | |||
| /** | |||
| * @return the current number of bytes ready for reading | |||
| * @exception IOException if an error occurs | |||
| */ | |||
| public synchronized int available() throws IOException { | |||
| if (in == null) { | |||
| throw new IOException("Stream Closed"); | |||
| } | |||
| if (slack != null) { | |||
| return slack.length - begin; | |||
| } | |||
| if (in.ready()) { | |||
| return 1; | |||
| } else { | |||
| return 0; | |||
| } | |||
| } | |||
| /** | |||
| * @return false - mark is not supported | |||
| */ | |||
| public boolean markSupported () { | |||
| return false; // would be imprecise | |||
| } | |||
| /** | |||
| * Resets the StringReader. | |||
| * | |||
| * @exception IOException if the StringReader fails to be reset | |||
| */ | |||
| public synchronized void reset() throws IOException { | |||
| if (in == null) { | |||
| throw new IOException("Stream Closed"); | |||
| } | |||
| slack = null; | |||
| in.reset(); | |||
| } | |||
| /** | |||
| * Closes the Stringreader. | |||
| * | |||
| * @exception IOException if the original StringReader fails to be closed | |||
| */ | |||
| public synchronized void close() throws IOException { | |||
| in.close(); | |||
| slack = null; | |||
| in = null; | |||
| } | |||
| } | |||
| @@ -29,6 +29,7 @@ import java.util.GregorianCalendar; | |||
| import junit.framework.ComparisonFailure; | |||
| /** | |||
| * Unit test for the <exec> task. | |||
| */ | |||
| public class ExecTaskTest extends BuildFileTest { | |||
| private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; | |||
| @@ -61,11 +62,12 @@ public class ExecTaskTest extends BuildFileTest { | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals(getProject().getProperty("ant.file") + " out" | |||
| assertEquals("unexpected log content", | |||
| getProject().getProperty("ant.file") + " out" | |||
| + getProject().getProperty("ant.file") + " err", getLog()); | |||
| } | |||
| public void testRedirect1() { | |||
| public void testRedirect1() throws IOException { | |||
| executeTarget("redirect1"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| @@ -73,55 +75,39 @@ public class ExecTaskTest extends BuildFileTest { | |||
| String expectedOut = getProject().getProperty("ant.file") + " out\n" | |||
| + getProject().getProperty("ant.file") + " err\n"; | |||
| String actualOut = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| assertEquals("unexpected output", expectedOut, actualOut); | |||
| assertEquals("unexpected output", | |||
| expectedOut, getFileString("redirect.out")); | |||
| } | |||
| public void testRedirect2() { | |||
| public void testRedirect2() throws IOException { | |||
| executeTarget("redirect2"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String expectedOut = getProject().getProperty("ant.file") + " out\n"; | |||
| String expectedErr = getProject().getProperty("ant.file") + " err\n"; | |||
| String actualOut = null; | |||
| String actualErr = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| actualErr = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.err"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| assertEquals("unexpected output", expectedOut, actualOut); | |||
| assertEquals("unexpected error output", expectedErr, actualErr); | |||
| assertEquals("unexpected output", | |||
| getProject().getProperty("ant.file") + " out\n", | |||
| getFileString("redirect.out")); | |||
| assertEquals("unexpected error output", | |||
| getProject().getProperty("ant.file") + " err\n", | |||
| getFileString("redirect.err")); | |||
| } | |||
| public void testRedirect3() { | |||
| public void testRedirect3() throws IOException { | |||
| executeTarget("redirect3"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals(getProject().getProperty("ant.file") + " err", getLog()); | |||
| assertEquals("unexpected log content", | |||
| getProject().getProperty("ant.file") + " err", getLog()); | |||
| String expectedOut = getProject().getProperty("ant.file") + " out\n"; | |||
| String actualOut = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| assertEquals("unexpected output", expectedOut, actualOut); | |||
| assertEquals("unexpected output", | |||
| expectedOut, getFileString("redirect.out")); | |||
| assertPropertyEquals("redirect.out", expectedOut.trim()); | |||
| } | |||
| public void testRedirect4() { | |||
| public void testRedirect4() throws IOException { | |||
| executeTarget("redirect4"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| @@ -129,72 +115,218 @@ public class ExecTaskTest extends BuildFileTest { | |||
| String expectedOut = getProject().getProperty("ant.file") + " out\n"; | |||
| String expectedErr = getProject().getProperty("ant.file") + " err\n"; | |||
| String actualOut = null; | |||
| String actualErr = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| actualErr = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.err"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| assertEquals("unexpected output", expectedOut, actualOut); | |||
| assertEquals("unexpected output", | |||
| expectedOut, getFileString("redirect.out")); | |||
| assertPropertyEquals("redirect.out", expectedOut.trim()); | |||
| assertEquals("unexpected error output", expectedErr, actualErr); | |||
| assertEquals("unexpected error output", | |||
| expectedErr, getFileString("redirect.err")); | |||
| assertPropertyEquals("redirect.err", expectedErr.trim()); | |||
| } | |||
| public void testRedirect5() { | |||
| public void testRedirect5() throws IOException { | |||
| testRedirect5or6("redirect5"); | |||
| } | |||
| public void testRedirect6() { | |||
| public void testRedirect6() throws IOException { | |||
| testRedirect5or6("redirect6"); | |||
| } | |||
| public void testRedirect5or6(String target) { | |||
| public void testRedirect5or6(String target) throws IOException { | |||
| executeTarget(target); | |||
| if (getProject().getProperty("wc.can.run") == null) { | |||
| return; | |||
| } | |||
| String expectedOut = getProject().getProperty("ant.file") + " out\n"; | |||
| String actualOut = null; | |||
| String actualErr = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| actualErr = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.err"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| assertEquals("unexpected output", "3", actualOut.trim()); | |||
| assertEquals(getProject().getProperty("redirect.out").trim(), "3"); | |||
| assertEquals("unexpected error output", null, actualErr); | |||
| assertEquals("unexpected output", "3", getFileString("redirect.out").trim()); | |||
| assertEquals("property redirect.out", "3", | |||
| getProject().getProperty("redirect.out").trim()); | |||
| assertNull("unexpected error output", getFileString("redirect.err")); | |||
| assertPropertyEquals("redirect.err", ""); | |||
| } | |||
| public void testRedirect7() { | |||
| public void testRedirect7() throws IOException { | |||
| executeTarget("redirect7"); | |||
| if (getProject().getProperty("wc.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals("unexpected output", "3", getFileString("redirect.out").trim()); | |||
| assertEquals("property redirect.out", "3", | |||
| getProject().getProperty("redirect.out").trim()); | |||
| assertNull("unexpected error output", getFileString("redirect.err")); | |||
| } | |||
| public void testRedirector1() { | |||
| executeTarget("init"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| expectBuildException("redirector1", "cannot have > 1 nested <redirector>s"); | |||
| } | |||
| public void testRedirector2() throws IOException { | |||
| executeTarget("redirector2"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals("unexpected output", | |||
| getProject().getProperty("ant.file") + " out\n" | |||
| + getProject().getProperty("ant.file") + " err\n", | |||
| getFileString("redirector.out")); | |||
| } | |||
| public void testRedirector3() throws IOException { | |||
| executeTarget("redirector3"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals("unexpected output", | |||
| getProject().getProperty("ant.file") + " out\n", | |||
| getFileString("redirector.out")); | |||
| assertEquals("unexpected error output", | |||
| getProject().getProperty("ant.file") + " err\n", | |||
| getFileString("redirector.err")); | |||
| } | |||
| public void testRedirector4() throws IOException { | |||
| executeTarget("redirector4"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String expectedOut = getProject().getProperty("ant.file") + " out\n"; | |||
| assertEquals("unexpected log content", | |||
| getProject().getProperty("ant.file") + " err", getLog()); | |||
| assertEquals("unexpected output", expectedOut, | |||
| getFileString("redirector.out")); | |||
| assertPropertyEquals("redirector.out", expectedOut.trim()); | |||
| } | |||
| public void testRedirector5() throws IOException { | |||
| testRedirector5or6("redirector5"); | |||
| } | |||
| public void testRedirector6() throws IOException { | |||
| testRedirector5or6("redirector6"); | |||
| } | |||
| private void testRedirector5or6(String target) throws IOException { | |||
| executeTarget(target); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String expectedOut = getProject().getProperty("ant.file") + " out\n"; | |||
| String expectedErr = getProject().getProperty("ant.file") + " err\n"; | |||
| assertEquals("unexpected output", expectedOut, | |||
| getFileString("redirector.out")); | |||
| assertPropertyEquals("redirector.out", expectedOut.trim()); | |||
| assertEquals("unexpected error output", expectedErr, | |||
| getFileString("redirector.err")); | |||
| assertPropertyEquals("redirector.err", expectedErr.trim()); | |||
| } | |||
| public void testRedirector7() throws IOException { | |||
| executeTarget("redirector7"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String expectedOut = getProject().getProperty("ant.file") + " out\n"; | |||
| String expectedErr = getProject().getProperty("ant.file") + " ERROR!!!\n"; | |||
| assertEquals("unexpected output", expectedOut, | |||
| getFileString("redirector.out")); | |||
| assertPropertyEquals("redirector.out", expectedOut.trim()); | |||
| assertEquals("unexpected error output", expectedErr, | |||
| getFileString("redirector.err")); | |||
| assertPropertyEquals("redirector.err", expectedErr.trim()); | |||
| } | |||
| public void testRedirector8() throws IOException { | |||
| executeTarget("redirector8"); | |||
| if (getProject().getProperty("wc.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals("unexpected output", "3", getFileString("redirector.out").trim()); | |||
| assertEquals("property redirector.out", "3", | |||
| getProject().getProperty("redirector.out").trim()); | |||
| assertNull("unexpected error output", getFileString("redirector.err")); | |||
| assertPropertyEquals("redirector.err", ""); | |||
| } | |||
| public void testRedirector9() throws IOException { | |||
| testRedirector9Thru12("redirector9"); | |||
| } | |||
| public void testRedirector10() throws IOException { | |||
| testRedirector9Thru12("redirector10"); | |||
| } | |||
| public void testRedirector11() throws IOException { | |||
| testRedirector9Thru12("redirector11"); | |||
| } | |||
| public void testRedirector12() throws IOException { | |||
| testRedirector9Thru12("redirector12"); | |||
| } | |||
| private void testRedirector9Thru12(String target) throws IOException { | |||
| executeTarget(target); | |||
| if (getProject().getProperty("cat.can.run") == null) { | |||
| return; | |||
| } | |||
| String expectedOut = "blah after blah"; | |||
| String actualOut = null; | |||
| String actualErr = null; | |||
| assertEquals("unexpected output", | |||
| expectedOut, getFileString("redirector.out").trim()); | |||
| assertPropertyEquals("redirector.out", expectedOut.trim()); | |||
| assertNull("unexpected error output", getFileString("redirector.err")); | |||
| assertPropertyEquals("redirector.err", ""); | |||
| } | |||
| public void testRedirector13() { | |||
| executeTarget("redirector13"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String antfile = getProject().getProperty("ant.file"); | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| actualErr = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.err"))); | |||
| } catch (IOException eyeOhEx) { | |||
| //no point in setting a message | |||
| assertEquals(antfile + " OUTPUT???" + antfile + " ERROR!!!", getLog()); | |||
| } catch (ComparisonFailure cf) { | |||
| assertEquals("unexpected log content", | |||
| antfile + " ERROR!!!" + antfile + " OUTPUT???", getLog()); | |||
| } | |||
| } | |||
| public void testRedirector14() { | |||
| executeTarget("redirector14"); | |||
| if (getProject().getProperty("cat.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals("unexpected log output", "blah after blah", getLog()); | |||
| } | |||
| public void testRedirector15() throws IOException { | |||
| executeTarget("redirector15"); | |||
| if (getProject().getProperty("cat.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals("unexpected output", "3", actualOut.trim()); | |||
| assertEquals(getProject().getProperty("redirect.out").trim(), "3"); | |||
| assertEquals("unexpected error output", null, actualErr); | |||
| assertTrue("error with transcoding", | |||
| FileUtils.newFileUtils().contentEquals( | |||
| getProject().resolveFile("expected/utf-8"), | |||
| getProject().resolveFile("redirector.out"))); | |||
| } | |||
| public void testRedirector16() { | |||
| executeTarget("redirector16"); | |||
| } | |||
| public void testRedirector17() { | |||
| executeTarget("redirector17"); | |||
| } | |||
| public void testspawn() { | |||
| @@ -256,7 +388,6 @@ public class ExecTaskTest extends BuildFileTest { | |||
| project.setProperty("logFile", logFile); | |||
| } | |||
| public void setTimeToWait(int timeToWait) { | |||
| this.timeToWait = timeToWait; | |||
| project.setProperty("timeToWait", Long.toString(timeToWait)); | |||
| @@ -319,4 +450,24 @@ public class ExecTaskTest extends BuildFileTest { | |||
| public void messageLogged(BuildEvent event) { | |||
| } | |||
| } | |||
| //borrowed from TokenFilterTest | |||
| private String getFileString(String filename) throws IOException { | |||
| String result = null; | |||
| FileReader reader = null; | |||
| try { | |||
| reader = new FileReader(getProject().resolveFile(filename)); | |||
| result = FileUtils.newFileUtils().readFully(reader); | |||
| } catch (IOException eyeOhEx) { | |||
| } finally { | |||
| if (reader != null) { | |||
| try { | |||
| reader.close(); | |||
| } catch (Throwable ignore) { | |||
| } | |||
| } | |||
| } | |||
| return result; | |||
| } | |||
| } | |||
| @@ -17,23 +17,21 @@ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.*; | |||
| import org.apache.tools.ant.BuildFileTest; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| import java.io.File; | |||
| import java.io.FileReader; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.util.GregorianCalendar; | |||
| import junit.framework.ComparisonFailure; | |||
| /** | |||
| * Unit test for the <apply> task. | |||
| */ | |||
| public class ExecuteOnTest extends BuildFileTest { | |||
| private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; | |||
| private static final String BUILD_FILE = BUILD_PATH + "apply.xml"; | |||
| public ExecuteOnTest(String name) { | |||
| super(name); | |||
| } | |||
| @@ -62,29 +60,25 @@ public class ExecuteOnTest extends BuildFileTest { | |||
| int xerr = log.indexOf(x + " err"); | |||
| int yerr = log.indexOf(y + " err"); | |||
| int zerr = log.indexOf(z + " err"); | |||
| assertFalse("xout < 0", xout < 0); | |||
| assertFalse("yout < 0", yout < 0); | |||
| assertFalse("zout < 0", zout < 0); | |||
| assertFalse("xerr < 0", xerr < 0); | |||
| assertFalse("yerr < 0", yerr < 0); | |||
| assertFalse("zerr < 0", zerr < 0); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| } | |||
| public void testRedirect1() { | |||
| public void testRedirect1() throws IOException { | |||
| executeTarget("redirect1"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| String actualOut = getFileString("redirect.out"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| @@ -94,32 +88,26 @@ public class ExecuteOnTest extends BuildFileTest { | |||
| int xerr = actualOut.indexOf(x + " err"); | |||
| int yerr = actualOut.indexOf(y + " err"); | |||
| int zerr = actualOut.indexOf(z + " err"); | |||
| assertFalse("xout < 0", xout < 0); | |||
| assertFalse("yout < 0", yout < 0); | |||
| assertFalse("zout < 0", zout < 0); | |||
| assertFalse("xerr < 0", xerr < 0); | |||
| assertFalse("yerr < 0", yerr < 0); | |||
| assertFalse("zerr < 0", zerr < 0); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| } | |||
| public void testRedirect2() { | |||
| public void testRedirect2() throws IOException { | |||
| executeTarget("redirect2"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = null; | |||
| String actualErr = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| actualErr = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.err"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| String actualOut = getFileString("redirect.out"); | |||
| String actualErr = getFileString("redirect.err"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| @@ -129,29 +117,25 @@ public class ExecuteOnTest extends BuildFileTest { | |||
| int xerr = actualErr.indexOf(x + " err"); | |||
| int yerr = actualErr.indexOf(y + " err"); | |||
| int zerr = actualErr.indexOf(z + " err"); | |||
| assertFalse("xout < 0", xout < 0); | |||
| assertFalse("yout < 0", yout < 0); | |||
| assertFalse("zout < 0", zout < 0); | |||
| assertFalse("xerr < 0", xerr < 0); | |||
| assertFalse("yerr < 0", yerr < 0); | |||
| assertFalse("zerr < 0", zerr < 0); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| } | |||
| public void testRedirect3() { | |||
| public void testRedirect3() throws IOException { | |||
| executeTarget("redirect3"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| String actualOut = getFileString("redirect.out"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| @@ -161,33 +145,36 @@ public class ExecuteOnTest extends BuildFileTest { | |||
| int xerr = getLog().indexOf(x + " err"); | |||
| int yerr = getLog().indexOf(y + " err"); | |||
| int zerr = getLog().indexOf(z + " err"); | |||
| assertFalse("xout < 0", xout < 0); | |||
| assertFalse("yout < 0", yout < 0); | |||
| assertFalse("zout < 0", zout < 0); | |||
| assertFalse("xerr < 0", xerr < 0); | |||
| assertFalse("yerr < 0", yerr < 0); | |||
| assertFalse("zerr < 0", zerr < 0); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| assertPropertyEquals("redirect.out", x + " out"); | |||
| String outProperty = getProject().getProperty("redirect.out"); | |||
| int pxout = outProperty.indexOf(x + " out"); | |||
| int pyout = outProperty.indexOf(y + " out"); | |||
| int pzout = outProperty.indexOf(z + " out"); | |||
| assertFalse("pxout=" + pxout, pxout < 0); | |||
| assertFalse("pyout=" + pyout, pyout < 0); | |||
| assertFalse("pzout=" + pzout, pzout < 0); | |||
| assertFalse("pyout < pxout", pyout < pxout); | |||
| assertFalse("pzout < pyout", pzout < pyout); | |||
| } | |||
| public void testRedirect4() { | |||
| public void testRedirect4() throws IOException { | |||
| executeTarget("redirect4"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = null; | |||
| String actualErr = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| actualErr = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.err"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| String actualOut = getFileString("redirect.out"); | |||
| String actualErr = getFileString("redirect.err"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| @@ -197,68 +184,388 @@ public class ExecuteOnTest extends BuildFileTest { | |||
| int xerr = actualErr.indexOf(x + " err"); | |||
| int yerr = actualErr.indexOf(y + " err"); | |||
| int zerr = actualErr.indexOf(z + " err"); | |||
| assertFalse("xout < 0", xout < 0); | |||
| assertFalse("yout < 0", yout < 0); | |||
| assertFalse("zout < 0", zout < 0); | |||
| assertFalse("xerr < 0", xerr < 0); | |||
| assertFalse("yerr < 0", yerr < 0); | |||
| assertFalse("zerr < 0", zerr < 0); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| assertPropertyEquals("redirect.out", x + " out"); | |||
| assertPropertyEquals("redirect.err", x + " err"); | |||
| String outProperty = getProject().getProperty("redirect.out"); | |||
| int pxout = outProperty.indexOf(x + " out"); | |||
| int pyout = outProperty.indexOf(y + " out"); | |||
| int pzout = outProperty.indexOf(z + " out"); | |||
| assertFalse("pxout=" + pxout, pxout < 0); | |||
| assertFalse("pyout=" + pyout, pyout < 0); | |||
| assertFalse("pzout=" + pzout, pzout < 0); | |||
| assertFalse("pyout < pxout", pyout < pxout); | |||
| assertFalse("pzout < pyout", pzout < pyout); | |||
| String errorProperty = getProject().getProperty("redirect.err"); | |||
| int pxerr = errorProperty.indexOf(x + " err"); | |||
| int pyerr = errorProperty.indexOf(y + " err"); | |||
| int pzerr = errorProperty.indexOf(z + " err"); | |||
| assertFalse("pxerr=" + pxerr, pxerr < 0); | |||
| assertFalse("pyerr=" + pyerr, pyerr < 0); | |||
| assertFalse("pzerr=" + pzerr, pzerr < 0); | |||
| assertFalse("pyerr < pxerr", pyerr < pxerr); | |||
| assertFalse("pzerr < pyerr", pzerr < pyerr); | |||
| } | |||
| public void testRedirect5() { | |||
| public void testRedirect5() throws IOException { | |||
| testRedirect5or6("redirect5"); | |||
| } | |||
| public void testRedirect6() { | |||
| public void testRedirect6() throws IOException { | |||
| testRedirect5or6("redirect6"); | |||
| } | |||
| private void testRedirect5or6(String target) { | |||
| private void testRedirect5or6(String target) throws IOException { | |||
| executeTarget(target); | |||
| if (getProject().getProperty("sed.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = null; | |||
| String actualErr = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| actualErr = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.err"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| assertPropertyEquals("redirect.out", "blah y z"); | |||
| assertPropertyEquals("redirect.out", getProject().replaceProperties( | |||
| "blah y z${line.separator}x blah z${line.separator}x y blah")); | |||
| assertPropertyEquals("redirect.err", ""); | |||
| assertEquals("unexpected content in redirect.out", | |||
| "blah y z\nx blah z\nx y blah\n", actualOut); | |||
| assertEquals("unexpected content in redirect.err", null, actualErr); | |||
| assertEquals("unexpected output", | |||
| "blah y z\nx blah z\nx y blah\n", getFileString("redirect.out")); | |||
| assertNull("unexpected error output", getFileString("redirect.err")); | |||
| } | |||
| public void testRedirect7() { | |||
| public void testRedirect7() throws IOException { | |||
| executeTarget("redirect7"); | |||
| if (getProject().getProperty("sed.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = null; | |||
| String actualErr = null; | |||
| try { | |||
| actualOut = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.out"))); | |||
| actualErr = FileUtils.newFileUtils().readFully(new FileReader( | |||
| getProject().resolveFile("redirect.err"))); | |||
| } catch (IOException eyeOhEx) { | |||
| } | |||
| assertPropertyEquals("redirect.out", "blah y z"); | |||
| assertPropertyUnset("redirect.err"); | |||
| assertEquals("unexpected content in redirect.out", | |||
| "x y blah\n", actualOut); | |||
| assertEquals("unexpected content in redirect.err", null, actualErr); | |||
| assertEquals("unexpected output", | |||
| "x y blah\n", getFileString("redirect.out")); | |||
| assertNull("unexpected error output", getFileString("redirect.err")); | |||
| } | |||
| public void testRedirector1() { | |||
| executeTarget("init"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| expectBuildException("redirector1", "cannot have > 1 nested <redirector>s"); | |||
| } | |||
| public void testRedirector2() throws IOException { | |||
| executeTarget("redirector2"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = getFileString("redirector.out"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| int xout = actualOut.indexOf(x + " out"); | |||
| int yout = actualOut.indexOf(y + " out"); | |||
| int zout = actualOut.indexOf(z + " out"); | |||
| int xerr = actualOut.indexOf(x + " err"); | |||
| int yerr = actualOut.indexOf(y + " err"); | |||
| int zerr = actualOut.indexOf(z + " err"); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| } | |||
| public void testRedirector3() throws IOException { | |||
| executeTarget("redirector3"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = getFileString("redirector.out"); | |||
| String actualErr = getFileString("redirector.err"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| int xout = actualOut.indexOf(x + " out"); | |||
| int yout = actualOut.indexOf(y + " out"); | |||
| int zout = actualOut.indexOf(z + " out"); | |||
| int xerr = actualErr.indexOf(x + " err"); | |||
| int yerr = actualErr.indexOf(y + " err"); | |||
| int zerr = actualErr.indexOf(z + " err"); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| } | |||
| public void testRedirector4() throws IOException { | |||
| executeTarget("redirector4"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = getFileString("redirector.out"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| int xout = actualOut.indexOf(x + " out"); | |||
| int yout = actualOut.indexOf(y + " out"); | |||
| int zout = actualOut.indexOf(z + " out"); | |||
| int xerr = getLog().indexOf(x + " err"); | |||
| int yerr = getLog().indexOf(y + " err"); | |||
| int zerr = getLog().indexOf(z + " err"); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| String outProperty = getProject().getProperty("redirector.out"); | |||
| int pxout = outProperty.indexOf(x + " out"); | |||
| int pyout = outProperty.indexOf(y + " out"); | |||
| int pzout = outProperty.indexOf(z + " out"); | |||
| assertFalse("pxout=" + pxout, pxout < 0); | |||
| assertFalse("pyout=" + pyout, pyout < 0); | |||
| assertFalse("pzout=" + pzout, pzout < 0); | |||
| assertFalse("pyout < pxout", pyout < pxout); | |||
| assertFalse("pzout < pyout", pzout < pyout); | |||
| } | |||
| public void testRedirector5() throws IOException { | |||
| testRedirector5or6("redirector5"); | |||
| } | |||
| public void testRedirector6() throws IOException { | |||
| testRedirector5or6("redirector6"); | |||
| } | |||
| private void testRedirector5or6(String target) throws IOException { | |||
| executeTarget(target); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = getFileString("redirector.out"); | |||
| String actualErr = getFileString("redirector.err"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| int xout = actualOut.indexOf(x + " out"); | |||
| int yout = actualOut.indexOf(y + " out"); | |||
| int zout = actualOut.indexOf(z + " out"); | |||
| int xerr = actualErr.indexOf(x + " err"); | |||
| int yerr = actualErr.indexOf(y + " err"); | |||
| int zerr = actualErr.indexOf(z + " err"); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| String outProperty = getProject().getProperty("redirector.out"); | |||
| int pxout = outProperty.indexOf(x + " out"); | |||
| int pyout = outProperty.indexOf(y + " out"); | |||
| int pzout = outProperty.indexOf(z + " out"); | |||
| assertFalse("pxout=" + pxout, pxout < 0); | |||
| assertFalse("pyout=" + pyout, pyout < 0); | |||
| assertFalse("pzout=" + pzout, pzout < 0); | |||
| assertFalse("pyout < pxout", pyout < pxout); | |||
| assertFalse("pzout < pyout", pzout < pyout); | |||
| String errorProperty = getProject().getProperty("redirector.err"); | |||
| int pxerr = errorProperty.indexOf(x + " err"); | |||
| int pyerr = errorProperty.indexOf(y + " err"); | |||
| int pzerr = errorProperty.indexOf(z + " err"); | |||
| assertFalse("pxerr=" + pxerr, pxerr < 0); | |||
| assertFalse("pyerr=" + pyerr, pyerr < 0); | |||
| assertFalse("pzerr=" + pzerr, pzerr < 0); | |||
| assertFalse("pyerr < pxerr", pyerr < pxerr); | |||
| assertFalse("pzerr < pyerr", pzerr < pyerr); | |||
| } | |||
| public void testRedirector7() throws IOException { | |||
| executeTarget("redirector7"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String actualOut = getFileString("redirector.out"); | |||
| String actualErr = getFileString("redirector.err"); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| int xout = actualOut.indexOf(x + " out"); | |||
| int yout = actualOut.indexOf(y + " out"); | |||
| int zout = actualOut.indexOf(z + " out"); | |||
| int xerr = actualErr.indexOf(x + " ERROR!!!"); | |||
| int yerr = actualErr.indexOf(y + " ERROR!!!"); | |||
| int zerr = actualErr.indexOf(z + " ERROR!!!"); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| String outProperty = getProject().getProperty("redirector.out"); | |||
| int pxout = outProperty.indexOf(x + " out"); | |||
| int pyout = outProperty.indexOf(y + " out"); | |||
| int pzout = outProperty.indexOf(z + " out"); | |||
| assertFalse("pxout=" + pxout, pxout < 0); | |||
| assertFalse("pyout=" + pyout, pyout < 0); | |||
| assertFalse("pzout=" + pzout, pzout < 0); | |||
| assertFalse("pyout < pxout", pyout < pxout); | |||
| assertFalse("pzout < pyout", pzout < pyout); | |||
| String errorProperty = getProject().getProperty("redirector.err"); | |||
| int pxerr = errorProperty.indexOf(x + " ERROR!!!"); | |||
| int pyerr = errorProperty.indexOf(y + " ERROR!!!"); | |||
| int pzerr = errorProperty.indexOf(z + " ERROR!!!"); | |||
| assertFalse("pxerr=" + pxerr, pxerr < 0); | |||
| assertFalse("pyerr=" + pyerr, pyerr < 0); | |||
| assertFalse("pzerr=" + pzerr, pzerr < 0); | |||
| assertFalse("pyerr < pxerr", pyerr < pxerr); | |||
| assertFalse("pzerr < pyerr", pzerr < pyerr); | |||
| } | |||
| public void testRedirector8() throws IOException { | |||
| executeTarget("redirector8"); | |||
| if (getProject().getProperty("sed.can.run") == null) { | |||
| return; | |||
| } | |||
| assertPropertyEquals("redirector.out", getProject().replaceProperties( | |||
| "blah y z${line.separator}x blah z${line.separator}x y blah")); | |||
| assertPropertyEquals("redirector.err", ""); | |||
| assertEquals("unexpected output", | |||
| "blah y z\nx blah z\nx y blah\n", getFileString("redirector.out")); | |||
| assertNull("unexpected error output", getFileString("redirector.err")); | |||
| } | |||
| public void testRedirector9() throws IOException { | |||
| testRedirector9Thru12("redirector9"); | |||
| } | |||
| public void testRedirector10() throws IOException { | |||
| testRedirector9Thru12("redirector10"); | |||
| } | |||
| public void testRedirector11() throws IOException { | |||
| testRedirector9Thru12("redirector11"); | |||
| } | |||
| public void testRedirector12() throws IOException { | |||
| testRedirector9Thru12("redirector12"); | |||
| } | |||
| private void testRedirector9Thru12(String target) throws IOException { | |||
| executeTarget(target); | |||
| if (getProject().getProperty("sed.can.run") == null) { | |||
| return; | |||
| } | |||
| assertNull("unexpected error output", getFileString("redirector.err")); | |||
| assertPropertyEquals("redirector.out", getProject().replaceProperties( | |||
| "blah after y after z${line.separator}x after blah after z" | |||
| + "${line.separator}x after y after blah")); | |||
| assertPropertyEquals("redirector.err", ""); | |||
| assertEquals("unexpected output", | |||
| "blah after y after z\nx after blah after z" | |||
| + "\nx after y after blah\n", getFileString("redirector.out")); | |||
| } | |||
| public void testRedirector13() { | |||
| executeTarget("redirector13"); | |||
| if (getProject().getProperty("test.can.run") == null) { | |||
| return; | |||
| } | |||
| String log = getLog(); | |||
| File x = getProject().resolveFile("x"); | |||
| File y = getProject().resolveFile("y"); | |||
| File z = getProject().resolveFile("z"); | |||
| int xout = log.indexOf(x + " OUTPUT???"); | |||
| int yout = log.indexOf(y + " OUTPUT???"); | |||
| int zout = log.indexOf(z + " OUTPUT???"); | |||
| int xerr = log.indexOf(x + " ERROR!!!"); | |||
| int yerr = log.indexOf(y + " ERROR!!!"); | |||
| int zerr = log.indexOf(z + " ERROR!!!"); | |||
| assertFalse("xout=" + xout, xout < 0); | |||
| assertFalse("yout=" + yout, yout < 0); | |||
| assertFalse("zout=" + zout, zout < 0); | |||
| assertFalse("xerr=" + xerr, xerr < 0); | |||
| assertFalse("yerr=" + yerr, yerr < 0); | |||
| assertFalse("zerr=" + zerr, zerr < 0); | |||
| assertFalse("yout < xout", yout < xout); | |||
| assertFalse("zout < yout", zout < yout); | |||
| assertFalse("yerr < xerr", yerr < xerr); | |||
| assertFalse("zerr < yerr", zerr < yerr); | |||
| } | |||
| public void testRedirector14() throws IOException { | |||
| executeTarget("redirector14"); | |||
| if (getProject().getProperty("sed.can.run") == null) { | |||
| return; | |||
| } | |||
| assertEquals("unexpected log content", | |||
| "z after y after blahx after y after blah", getLog()); | |||
| assertEquals("unexpected redirector.out content", | |||
| "x after blah after z\n", getFileString("redirector.out")); | |||
| assertNull("unexpected redirector.err content", getFileString("redirector.err")); | |||
| } | |||
| //borrowed from TokenFilterTest | |||
| private String getFileString(String filename) throws IOException { | |||
| String result = null; | |||
| FileReader reader = null; | |||
| try { | |||
| reader = new FileReader(getProject().resolveFile(filename)); | |||
| result = FileUtils.newFileUtils().readFully(reader); | |||
| } finally { | |||
| if (reader != null) { | |||
| try { | |||
| reader.close(); | |||
| } catch (Throwable ignore) { | |||
| } | |||
| } | |||
| } | |||
| return result; | |||
| } | |||
| } | |||
| @@ -20,7 +20,9 @@ package org.apache.tools.ant.taskdefs; | |||
| import junit.framework.*; | |||
| import java.io.*; | |||
| import org.apache.tools.ant.*; | |||
| //import org.apache.tools.ant.taskdefs.StreamPumper; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| import org.apache.tools.ant.util.TeeOutputStream; | |||
| /** | |||
| * stress out java task | |||
| @@ -186,6 +188,26 @@ public class JavaTest extends BuildFileTest { | |||
| assertTrue("log file exists", logFile.exists()); | |||
| } | |||
| public void testRedirect1() { | |||
| executeTarget("redirect1"); | |||
| } | |||
| public void testRedirect2() { | |||
| executeTarget("redirect2"); | |||
| } | |||
| public void testRedirect3() { | |||
| executeTarget("redirect3"); | |||
| } | |||
| public void testRedirector1() { | |||
| executeTarget("redirector1"); | |||
| } | |||
| public void testRedirector2() { | |||
| executeTarget("redirector2"); | |||
| } | |||
| /** | |||
| * entry point class with no dependencies other | |||
| * than normal JRE runtime | |||
| @@ -266,4 +288,35 @@ public class JavaTest extends BuildFileTest { | |||
| } | |||
| } | |||
| /** | |||
| * entry point class to pipe System.in to the specified stream: | |||
| * "out", "err", or "both". If none specified, swallow the input. | |||
| */ | |||
| public static class PipeEntryPoint { | |||
| /** | |||
| * pipe input to specified output | |||
| */ | |||
| public static void main(String[] args) { | |||
| OutputStream os = null; | |||
| if (args.length > 0) { | |||
| if ("out".equalsIgnoreCase(args[0])) { | |||
| os = System.out; | |||
| } else if ("err".equalsIgnoreCase(args[0])) { | |||
| os = System.err; | |||
| } else if ("both".equalsIgnoreCase(args[0])) { | |||
| os = new TeeOutputStream(System.out, System.err); | |||
| } | |||
| } | |||
| if (os != null) { | |||
| Thread t = new Thread(new StreamPumper(System.in, os, true)); | |||
| t.start(); | |||
| try { | |||
| t.join(); | |||
| } catch (InterruptedException eyeEx) { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||