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 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 | 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 | <p>It is possible to specify environment variables to pass to the | ||||
system command via nested <code><env></code> elements. See the | system command via nested <code><env></code> elements. See the | ||||
description in the section about <a href="exec.html#env">exec</a></p> | 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> | <h3>Examples</h3> | ||||
<blockquote><pre> | <blockquote><pre> | ||||
<apply executable="ls"> | <apply executable="ls"> | ||||
@@ -334,6 +347,29 @@ of all files separated by spaces.</p> | |||||
<code>.o</code>, replacing TARGETFILE with the absolute filename of | <code>.o</code>, replacing TARGETFILE with the absolute filename of | ||||
the <code>.o</code> and SOURCEFILE with the absolute name of the | the <code>.o</code> and SOURCEFILE with the absolute name of the | ||||
<code>.c</code> file.</p> | <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 | <hr><p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights | ||||
Reserved.</p> | 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> | replaced by the absolute filename of the file by Ant.</td> | ||||
</tr> | </tr> | ||||
</table> | </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> | <h3>Errors and return codes</h3> | ||||
By default the return code of a <exec> is ignored; when you set | By default the return code of a <exec> is ignored; when you set | ||||
<code>failonerror="true"</code> then any return code signaling failure | <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 | <p>Starts the <i>${browser}</i> with the specified <i>${file}</i> and end the | ||||
ant process. The browser will let be open.</p> | 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 | <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 | 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 | 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 | value of the execution will be "-1", which will halt the build if | ||||
<tt>failonerror=true</tt>, but be ignored otherwise. | <tt>failonerror=true</tt>, but be ignored otherwise. | ||||
<hr> | <hr> | ||||
<p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights | <p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights | ||||
Reserved.</p> | Reserved.</p> | ||||
@@ -243,6 +243,19 @@ subelement.</p> | |||||
<p><em>since Ant 1.6.</em></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> | <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 | 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, | 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="using.html#path">Path-like Structures</a><br> | ||||
<a href="CoreTypes/permissions.html">Permissions</a><br> | <a href="CoreTypes/permissions.html">Permissions</a><br> | ||||
<a href="CoreTypes/propertyset.html">PropertySet</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/regexp.html">Regexp</a><br> | ||||
<a href="CoreTypes/selectors.html">Selectors</a><br> | <a href="CoreTypes/selectors.html">Selectors</a><br> | ||||
<a href="CoreTypes/xmlcatalog.html">XMLCatalog</a><br> | <a href="CoreTypes/xmlcatalog.html">XMLCatalog</a><br> | ||||
@@ -12,16 +12,6 @@ | |||||
</or> | </or> | ||||
</condition> | </condition> | ||||
<!-- UNIX --> | <!-- 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"/> | <available file="sed" filepath="${env.PATH}" property="sed.executable"/> | ||||
<!-- CYGWIN --> | <!-- CYGWIN --> | ||||
<available file="sed.exe" filepath="${env.PATH}" property="sed.exe.executable"/> | <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="y">s/y/blah/g${line.separator}</echo> | ||||
<echo file="z">s/z/blah/g${line.separator}</echo> | <echo file="z">s/z/blah/g${line.separator}</echo> | ||||
<fileset id="xyz" dir="${basedir}" includes="x,y,z" /> | <fileset id="xyz" dir="${basedir}" includes="x,y,z" /> | ||||
<filelist id="xyzlist" dir="${basedir}" files="x,y,z" /> | |||||
</target> | </target> | ||||
<target name="no-redirect" depends="init,xyz" if="test.can.run"> | <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" | <apply executable="sed" inputstring="x y z${line.separator}" append="true" | ||||
error="redirect.err" errorproperty="redirect.err" | error="redirect.err" errorproperty="redirect.err" | ||||
output="redirect.out" outputproperty="redirect.out"> | output="redirect.out" outputproperty="redirect.out"> | ||||
<arg value="-f"/> | |||||
<arg value="-f" /> | |||||
<fileset refid="xyz" /> | <fileset refid="xyz" /> | ||||
</apply> | </apply> | ||||
</target> | </target> | ||||
@@ -93,8 +84,8 @@ | |||||
<apply executable="sed" input="redirect.in" append="true" | <apply executable="sed" input="redirect.in" append="true" | ||||
error="redirect.err" errorproperty="redirect.err" | error="redirect.err" errorproperty="redirect.err" | ||||
output="redirect.out" outputproperty="redirect.out"> | output="redirect.out" outputproperty="redirect.out"> | ||||
<arg value="-f"/> | |||||
<fileset refid="xyz" /> | |||||
<arg value="-f" /> | |||||
<filelist refid="xyzlist" /> | |||||
</apply> | </apply> | ||||
</target> | </target> | ||||
@@ -102,19 +93,221 @@ | |||||
<apply executable="sed" inputstring="x y z${line.separator}" | <apply executable="sed" inputstring="x y z${line.separator}" | ||||
error="redirect.err" output="redirect.out" | error="redirect.err" output="redirect.out" | ||||
outputproperty="redirect.out"> | outputproperty="redirect.out"> | ||||
<arg value="-f"/> | |||||
<arg value="-f" /> | |||||
<fileset refid="xyz" /> | <fileset refid="xyz" /> | ||||
</apply> | </apply> | ||||
</target> | </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> | ||||
<target name="cleanup"> | <target name="cleanup"> | ||||
<delete> | <delete> | ||||
<fileset dir="${basedir}" includes="redirect.*" /> | |||||
<fileset refid="xyz" /> | <fileset refid="xyz" /> | ||||
<fileset dir="${basedir}" includes="redirect.*" /> | |||||
<fileset dir="${basedir}" includes="redirector.*" /> | |||||
</delete> | </delete> | ||||
</target> | </target> | ||||
</project> | </project> |
@@ -25,6 +25,16 @@ | |||||
<isset property="wc.exe.executable"/> | <isset property="wc.exe.executable"/> | ||||
</or> | </or> | ||||
</condition> | </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> | ||||
<target name="spawn" depends="init" if="test.can.run"> | <target name="spawn" depends="init" if="test.can.run"> | ||||
@@ -98,10 +108,216 @@ | |||||
</exec> | </exec> | ||||
</target> | </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"> | <target name="cleanup"> | ||||
<delete> | <delete> | ||||
<fileset file="${logFile}" /> | <fileset file="${logFile}" /> | ||||
<fileset dir="${basedir}" includes="redirect.*" /> | |||||
<fileset dir="${basedir}" includes="redirect*" /> | |||||
<fileset dir="${basedir}" includes="redirector*" /> | |||||
</delete> | </delete> | ||||
</target> | </target> | ||||
</project> | </project> |
@@ -0,0 +1 @@ | |||||
äöüÄÖÜß |
@@ -0,0 +1 @@ | |||||
蔕�ヨワ゚ |
@@ -7,6 +7,7 @@ | |||||
<property name="timeToWait" value="4"/> | <property name="timeToWait" value="4"/> | ||||
<!-- this property gets overridden programmatically--> | <!-- this property gets overridden programmatically--> | ||||
<property name="logFile" value="spawn.log"/> | <property name="logFile" value="spawn.log"/> | ||||
<property name="tmp" value="${java.io.tmpdir}"/> | |||||
<property name="app" | <property name="app" | ||||
value="org.apache.tools.ant.taskdefs.JavaTest$$EntryPoint" /> | value="org.apache.tools.ant.taskdefs.JavaTest$$EntryPoint" /> | ||||
@@ -16,6 +17,11 @@ | |||||
<property name="spawnapp" | <property name="spawnapp" | ||||
value="org.apache.tools.ant.taskdefs.JavaTest$$SpawnEntryPoint" /> | 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"> | <target name="testNoJarNoClassname"> | ||||
<java/> | <java/> | ||||
</target> | </target> | ||||
@@ -126,18 +132,17 @@ | |||||
<echo message="exitcode = ${exitcode}"/> | <echo message="exitcode = ${exitcode}"/> | ||||
</target> | </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"> | <target name="testRunFailWithFailOnError"> | ||||
<java classname="${app}" | <java classname="${app}" | ||||
@@ -157,16 +162,143 @@ | |||||
</java> | </java> | ||||
</target> | </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> | </project> |
@@ -20,21 +20,13 @@ import java.io.IOException; | |||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.io.StringReader; | import java.io.StringReader; | ||||
import org.apache.tools.ant.util.ReaderInputStream; | |||||
/** | /** | ||||
* Wraps a String as an InputStream. | * 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 | * 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>. | * @param source The string to read from. Must not be <code>null</code>. | ||||
*/ | */ | ||||
public StringInputStream(String source) { | public StringInputStream(String source) { | ||||
in = new StringReader(source); | |||||
super(new StringReader(source)); | |||||
} | } | ||||
/** | /** | ||||
* Composes a stream from a String with the specified encoding | * Composes a stream from a String with the specified encoding | ||||
* | * | ||||
* @param source The string to read from. Must not be <code>null</code>. | * @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) { | 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.Commandline; | ||||
import org.apache.tools.ant.types.Environment; | import org.apache.tools.ant.types.Environment; | ||||
import org.apache.tools.ant.types.Path; | import org.apache.tools.ant.types.Path; | ||||
import org.apache.tools.ant.types.RedirectorElement; | |||||
import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
/** | /** | ||||
@@ -53,7 +54,14 @@ public class ExecTask extends Task { | |||||
private boolean spawn = false; | private boolean spawn = false; | ||||
private boolean incompatibleWithSpawn = 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 | * 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 | * @param out name of a file to which send output to | ||||
*/ | */ | ||||
public void setOutput(File out) { | public void setOutput(File out) { | ||||
redirector.setOutput(out); | |||||
this.output = out; | |||||
incompatibleWithSpawn = true; | incompatibleWithSpawn = true; | ||||
} | } | ||||
@@ -151,7 +159,11 @@ public class ExecTask extends Task { | |||||
* @param input name of a file to get input from | * @param input name of a file to get input from | ||||
*/ | */ | ||||
public void setInput(File input) { | 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; | incompatibleWithSpawn = true; | ||||
} | } | ||||
@@ -161,7 +173,11 @@ public class ExecTask extends Task { | |||||
* @param inputString the string which is used as the input source | * @param inputString the string which is used as the input source | ||||
*/ | */ | ||||
public void setInputString(String inputString) { | 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; | incompatibleWithSpawn = true; | ||||
} | } | ||||
@@ -185,7 +201,7 @@ public class ExecTask extends Task { | |||||
* @since ant 1.6 | * @since ant 1.6 | ||||
*/ | */ | ||||
public void setError(File error) { | public void setError(File error) { | ||||
redirector.setError(error); | |||||
this.error = error; | |||||
incompatibleWithSpawn = true; | 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 | * 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) { | if (spawn && incompatibleWithSpawn) { | ||||
getProject().log("spawn does not allow attributes related to input, " | getProject().log("spawn does not allow attributes related to input, " | ||||
+ "output, error, result", Project.MSG_ERR); | + "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) { | if (dir == null) { | ||||
dir = getProject().getBaseDir(); | dir = getProject().getBaseDir(); | ||||
} | } | ||||
if (redirectorElement != null) { | |||||
redirectorElement.configure(redirector); | |||||
} | |||||
Execute exe = new Execute(createHandler(), createWatchdog()); | Execute exe = new Execute(createHandler(), createWatchdog()); | ||||
exe.setAntRun(getProject()); | exe.setAntRun(getProject()); | ||||
exe.setWorkingDirectory(dir); | exe.setWorkingDirectory(dir); | ||||
@@ -527,6 +573,7 @@ public class ExecTask extends Task { | |||||
} | } | ||||
} | } | ||||
maybeSetResultPropertyValue(returnCode); | maybeSetResultPropertyValue(returnCode); | ||||
redirector.complete(); | |||||
if (Execute.isFailure(returnCode)) { | if (Execute.isFailure(returnCode)) { | ||||
if (failOnError) { | if (failOnError) { | ||||
throw new BuildException(getTaskType() + " returned: " | throw new BuildException(getTaskType() + " returned: " | ||||
@@ -535,7 +582,6 @@ public class ExecTask extends Task { | |||||
log("Result: " + returnCode, Project.MSG_ERR); | log("Result: " + returnCode, Project.MSG_ERR); | ||||
} | } | ||||
} | } | ||||
redirector.complete(); | |||||
} else { | } else { | ||||
exe.spawn(); | 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"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
@@ -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 { | protected void runExec(Execute exe) throws BuildException { | ||||
int totalFiles = 0; | int totalFiles = 0; | ||||
int totalDirs = 0; | int totalDirs = 0; | ||||
@@ -293,10 +304,17 @@ public class ExecuteOn extends ExecTask { | |||||
log(Commandline.describeCommand(command), | log(Commandline.describeCommand(command), | ||||
Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
exe.setCommandline(command); | 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 | // 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); | runExecute(exe); | ||||
haveExecuted = true; | haveExecuted = true; | ||||
@@ -341,10 +359,17 @@ public class ExecuteOn extends ExecTask { | |||||
log(Commandline.describeCommand(command), | log(Commandline.describeCommand(command), | ||||
Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
exe.setCommandline(command); | 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 | // 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); | runExecute(exe); | ||||
haveExecuted = true; | haveExecuted = true; | ||||
@@ -373,6 +398,8 @@ public class ExecuteOn extends ExecTask { | |||||
} finally { | } finally { | ||||
// close the output file if required | // close the output file if required | ||||
logFlush(); | logFlush(); | ||||
redirector.setAppendProperties(false); | |||||
redirector.setProperties(); | |||||
} | } | ||||
} | } | ||||
@@ -582,10 +609,16 @@ public class ExecuteOn extends ExecTask { | |||||
String[] command = getCommandline(cs, cb); | String[] command = getCommandline(cs, cb); | ||||
log(Commandline.describeCommand(command), Project.MSG_VERBOSE); | log(Commandline.describeCommand(command), Project.MSG_VERBOSE); | ||||
exe.setCommandline(command); | 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 | // 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); | 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.Reference; | ||||
import org.apache.tools.ant.types.Assertions; | import org.apache.tools.ant.types.Assertions; | ||||
import org.apache.tools.ant.types.Permissions; | import org.apache.tools.ant.types.Permissions; | ||||
import org.apache.tools.ant.types.RedirectorElement; | |||||
/** | /** | ||||
* Launcher for Java applications. Allows use of | * Launcher for Java applications. Allows use of | ||||
@@ -53,7 +54,16 @@ public class Java extends Task { | |||||
private File dir = null; | private File dir = null; | ||||
private boolean failOnError = false; | private boolean failOnError = false; | ||||
private Long timeout = null; | 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 String resultProperty; | ||||
private Permissions perm = null; | private Permissions perm = null; | ||||
@@ -110,9 +120,11 @@ public class Java extends Task { | |||||
if (spawn && incompatibleWithSpawn) { | if (spawn && incompatibleWithSpawn) { | ||||
getProject().log("spawn does not allow attributes related to input, " | getProject().log("spawn does not allow attributes related to input, " | ||||
+ "output, error, result", Project.MSG_ERR); | + "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) { | if (cmdl.getAssertions() != null && !fork) { | ||||
log("Assertion statements are currently ignored in non-forked mode"); | log("Assertion statements are currently ignored in non-forked mode"); | ||||
@@ -151,6 +163,7 @@ public class Java extends Task { | |||||
Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
} | } | ||||
setupRedirector(); | |||||
try { | try { | ||||
if (fork) { | if (fork) { | ||||
if (!spawn) { | if (!spawn) { | ||||
@@ -419,7 +432,7 @@ public class Java extends Task { | |||||
* @param out name of the output file | * @param out name of the output file | ||||
*/ | */ | ||||
public void setOutput(File out) { | public void setOutput(File out) { | ||||
redirector.setOutput(out); | |||||
this.output = out; | |||||
incompatibleWithSpawn = true; | incompatibleWithSpawn = true; | ||||
} | } | ||||
@@ -429,7 +442,11 @@ public class Java extends Task { | |||||
* @param input name of the input file | * @param input name of the input file | ||||
*/ | */ | ||||
public void setInput(File input) { | 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; | incompatibleWithSpawn = true; | ||||
} | } | ||||
@@ -439,7 +456,11 @@ public class Java extends Task { | |||||
* @param inputString the string which is used as the input source | * @param inputString the string which is used as the input source | ||||
*/ | */ | ||||
public void setInputString(String inputString) { | 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; | incompatibleWithSpawn = true; | ||||
} | } | ||||
@@ -464,7 +485,7 @@ public class Java extends Task { | |||||
* @since ant 1.6 | * @since ant 1.6 | ||||
*/ | */ | ||||
public void setError(File error) { | public void setError(File error) { | ||||
redirector.setError(error); | |||||
this.error = error; | |||||
incompatibleWithSpawn = true; | incompatibleWithSpawn = true; | ||||
} | } | ||||
@@ -572,6 +593,19 @@ public class Java extends Task { | |||||
cmdl.setAssertions(asserts); | 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. | * 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 | * Executes the given classname with the given arguments as it | ||||
* was a command line application. | * was a command line application. | ||||
@@ -16,23 +16,37 @@ | |||||
*/ | */ | ||||
package org.apache.tools.ant.taskdefs; | 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.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.InputStream; | ||||
import java.io.IOException; | |||||
import java.io.PrintStream; | 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.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.StringUtils; | ||||
import org.apache.tools.ant.util.TeeOutputStream; | 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 | * The Redirector class manages the setup and connection of | ||||
@@ -41,21 +55,43 @@ import org.apache.tools.ant.util.TeeOutputStream; | |||||
* @since Ant 1.6 | * @since Ant 1.6 | ||||
*/ | */ | ||||
public class Redirector { | 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 | * 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 | * 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 | * 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 */ | /** The name of the property into which output is to be stored */ | ||||
private String outputProperty; | private String outputProperty; | ||||
@@ -86,6 +122,9 @@ public class Redirector { | |||||
/** Flag which indicates if error and output files are to be appended. */ | /** Flag which indicates if error and output files are to be appended. */ | ||||
private boolean append = false; | 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 */ | /** The task for which this redirector is working */ | ||||
private Task managingTask; | private Task managingTask; | ||||
@@ -104,6 +143,30 @@ public class Redirector { | |||||
/** Stream which is used for line oriented error output */ | /** Stream which is used for line oriented error output */ | ||||
private PrintStream errorPrintStream = null; | 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 | * Create a redirector instance for the given task | ||||
* | * | ||||
@@ -119,6 +182,15 @@ public class Redirector { | |||||
* @param input the file from which input is read. | * @param input the file from which input is read. | ||||
*/ | */ | ||||
public void setInput(File input) { | 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; | this.input = input; | ||||
} | } | ||||
@@ -127,7 +199,7 @@ public class Redirector { | |||||
* | * | ||||
* @param inputString the string which is used as the input source | * @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; | this.inputString = inputString; | ||||
} | } | ||||
@@ -139,9 +211,61 @@ public class Redirector { | |||||
* @param out the file to which output stream is written | * @param out the file to which output stream is written | ||||
*/ | */ | ||||
public void setOutput(File out) { | 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; | 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 | * Controls whether error output of exec is logged. This is only useful | ||||
* when output is being redirected and error output is desired in the | * 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 | * @param logError if true the standard error is sent to the Ant log system | ||||
* and not sent to output. | * and not sent to output. | ||||
*/ | */ | ||||
public void setLogError(boolean logError) { | |||||
public synchronized void setLogError(boolean logError) { | |||||
this.logError = 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. | * Set the file to which standard error is to be redirected. | ||||
* | * | ||||
* @param error the file to which error is to be written | * @param error the file to which error is to be written | ||||
*/ | */ | ||||
public void setError(File error) { | 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; | this.error = error; | ||||
} | } | ||||
@@ -170,8 +314,12 @@ public class Redirector { | |||||
* @param outputProperty the name of the property to be set with the | * @param outputProperty the name of the property to be set with the | ||||
* task's output. | * 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 | * @param append if true output and error streams are appended to their | ||||
* respective files, if specified. | * respective files, if specified. | ||||
*/ | */ | ||||
public void setAppend(boolean append) { | |||||
public synchronized void setAppend(boolean append) { | |||||
this.append = 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 | * Property name whose value should be set to the error of | ||||
* the process. | * the process. | ||||
@@ -192,8 +349,39 @@ public class Redirector { | |||||
* @param errorProperty the name of the property to be set | * @param errorProperty the name of the property to be set | ||||
* with the error output. | * 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, | private void setPropertyFromBAOS(ByteArrayOutputStream baos, | ||||
String propertyName) throws IOException { | 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; | String line = null; | ||||
StringBuffer val = new StringBuffer(); | StringBuffer val = new StringBuffer(); | ||||
while ((line = in.readLine()) != null) { | while ((line = in.readLine()) != null) { | ||||
@@ -220,30 +408,34 @@ public class Redirector { | |||||
managingTask.getProject().setNewProperty(propertyName, val.toString()); | managingTask.getProject().setNewProperty(propertyName, val.toString()); | ||||
} | } | ||||
/** | /** | ||||
* Create the input, error and output streams based on the | * Create the input, error and output streams based on the | ||||
* configuration options. | * 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); | outputStream = new LogOutputStream(managingTask, Project.MSG_INFO); | ||||
errorStream = new LogOutputStream(managingTask, Project.MSG_WARN); | |||||
} else { | } 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) { | 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 { | } else { | ||||
outputStream = new TeeOutputStream(outputStream, baos); | |||||
outputStream | |||||
= new TeeOutputStream(outputStream, keepAliveOutput); | |||||
} | } | ||||
} else { | } else { | ||||
baos = null; | baos = null; | ||||
@@ -252,44 +444,132 @@ public class Redirector { | |||||
errorStream = outputStream; | 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) { | 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 { | } else { | ||||
errorBaos = null; | 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 { | 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) { | } else if (inputString != null) { | ||||
managingTask.log("Using input \"" + inputString + "\"", | |||||
Project.MSG_VERBOSE); | |||||
inputStream = new ByteArrayInputStream(inputString.getBytes()); | 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. | * 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. | * @throws BuildException if the execute stream handler cannot be created. | ||||
*/ | */ | ||||
public ExecuteStreamHandler createHandler() throws BuildException { | |||||
public synchronized ExecuteStreamHandler createHandler() | |||||
throws BuildException { | |||||
createStreams(); | createStreams(); | ||||
return new PumpStreamHandler(outputStream, errorStream, inputStream); | return new PumpStreamHandler(outputStream, errorStream, inputStream); | ||||
} | } | ||||
@@ -309,7 +590,7 @@ public class Redirector { | |||||
* | * | ||||
* @param output the data to be output | * @param output the data to be output | ||||
*/ | */ | ||||
protected void handleOutput(String output) { | |||||
protected synchronized void handleOutput(String output) { | |||||
if (outPrintStream == null) { | if (outPrintStream == null) { | ||||
outPrintStream = new PrintStream(outputStream); | outPrintStream = new PrintStream(outputStream); | ||||
} | } | ||||
@@ -327,8 +608,8 @@ public class Redirector { | |||||
* | * | ||||
* @exception IOException if the data cannot be read | * @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) { | if (inputStream == null) { | ||||
return managingTask.getProject().defaultInput(buffer, offset, | return managingTask.getProject().defaultInput(buffer, offset, | ||||
length); | length); | ||||
@@ -342,7 +623,7 @@ public class Redirector { | |||||
* | * | ||||
* @param output the data being flushed. | * @param output the data being flushed. | ||||
*/ | */ | ||||
protected void handleFlush(String output) { | |||||
protected synchronized void handleFlush(String output) { | |||||
if (outPrintStream == null) { | if (outPrintStream == null) { | ||||
outPrintStream = new PrintStream(outputStream); | outPrintStream = new PrintStream(outputStream); | ||||
} | } | ||||
@@ -355,7 +636,7 @@ public class Redirector { | |||||
* | * | ||||
* @param output the error output data. | * @param output the error output data. | ||||
*/ | */ | ||||
protected void handleErrorOutput(String output) { | |||||
protected synchronized void handleErrorOutput(String output) { | |||||
if (errorPrintStream == null) { | if (errorPrintStream == null) { | ||||
errorPrintStream = new PrintStream(errorStream); | errorPrintStream = new PrintStream(errorStream); | ||||
} | } | ||||
@@ -367,7 +648,7 @@ public class Redirector { | |||||
* | * | ||||
* @param output the error information being flushed. | * @param output the error information being flushed. | ||||
*/ | */ | ||||
protected void handleErrorFlush(String output) { | |||||
protected synchronized void handleErrorFlush(String output) { | |||||
if (errorPrintStream == null) { | if (errorPrintStream == null) { | ||||
errorPrintStream = new PrintStream(errorStream); | errorPrintStream = new PrintStream(errorStream); | ||||
} | } | ||||
@@ -380,7 +661,7 @@ public class Redirector { | |||||
* @return the redirector's output stream or null if no output | * @return the redirector's output stream or null if no output | ||||
* has been configured | * has been configured | ||||
*/ | */ | ||||
public OutputStream getOutputStream() { | |||||
public synchronized OutputStream getOutputStream() { | |||||
return outputStream; | return outputStream; | ||||
} | } | ||||
@@ -390,7 +671,7 @@ public class Redirector { | |||||
* @return the redirector's error stream or null if no output | * @return the redirector's error stream or null if no output | ||||
* has been configured | * has been configured | ||||
*/ | */ | ||||
public OutputStream getErrorStream() { | |||||
public synchronized OutputStream getErrorStream() { | |||||
return errorStream; | return errorStream; | ||||
} | } | ||||
@@ -400,7 +681,7 @@ public class Redirector { | |||||
* @return the redirector's input stream or null if no output | * @return the redirector's input stream or null if no output | ||||
* has been configured | * has been configured | ||||
*/ | */ | ||||
public InputStream getInputStream() { | |||||
public synchronized InputStream getInputStream() { | |||||
return inputStream; | return inputStream; | ||||
} | } | ||||
@@ -413,7 +694,7 @@ public class Redirector { | |||||
* @throws IOException if the output properties cannot be read from their | * @throws IOException if the output properties cannot be read from their | ||||
* output streams. | * output streams. | ||||
*/ | */ | ||||
public void complete() throws IOException { | |||||
public synchronized void complete() throws IOException { | |||||
System.out.flush(); | System.out.flush(); | ||||
System.err.flush(); | System.err.flush(); | ||||
@@ -421,17 +702,69 @@ public class Redirector { | |||||
inputStream.close(); | inputStream.close(); | ||||
} | } | ||||
outputStream.flush(); | |||||
outputStream.close(); | 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) { | if (baos != null) { | ||||
setPropertyFromBAOS(baos, outputProperty); | |||||
try { | |||||
baos.close(); | |||||
} catch (IOException eyeOhEx) { | |||||
} | |||||
} | } | ||||
if (errorBaos != null) { | 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; | import junit.framework.ComparisonFailure; | ||||
/** | /** | ||||
* Unit test for the <exec> task. | |||||
*/ | */ | ||||
public class ExecTaskTest extends BuildFileTest { | public class ExecTaskTest extends BuildFileTest { | ||||
private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; | 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) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | return; | ||||
} | } | ||||
assertEquals(getProject().getProperty("ant.file") + " out" | |||||
assertEquals("unexpected log content", | |||||
getProject().getProperty("ant.file") + " out" | |||||
+ getProject().getProperty("ant.file") + " err", getLog()); | + getProject().getProperty("ant.file") + " err", getLog()); | ||||
} | } | ||||
public void testRedirect1() { | |||||
public void testRedirect1() throws IOException { | |||||
executeTarget("redirect1"); | executeTarget("redirect1"); | ||||
if (getProject().getProperty("test.can.run") == null) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | return; | ||||
@@ -73,55 +75,39 @@ public class ExecTaskTest extends BuildFileTest { | |||||
String expectedOut = getProject().getProperty("ant.file") + " out\n" | String expectedOut = getProject().getProperty("ant.file") + " out\n" | ||||
+ getProject().getProperty("ant.file") + " err\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"); | executeTarget("redirect2"); | ||||
if (getProject().getProperty("test.can.run") == null) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | 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"); | executeTarget("redirect3"); | ||||
if (getProject().getProperty("test.can.run") == null) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | 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 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()); | assertPropertyEquals("redirect.out", expectedOut.trim()); | ||||
} | } | ||||
public void testRedirect4() { | |||||
public void testRedirect4() throws IOException { | |||||
executeTarget("redirect4"); | executeTarget("redirect4"); | ||||
if (getProject().getProperty("test.can.run") == null) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | return; | ||||
@@ -129,72 +115,218 @@ public class ExecTaskTest extends BuildFileTest { | |||||
String expectedOut = getProject().getProperty("ant.file") + " out\n"; | String expectedOut = getProject().getProperty("ant.file") + " out\n"; | ||||
String expectedErr = getProject().getProperty("ant.file") + " err\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()); | assertPropertyEquals("redirect.out", expectedOut.trim()); | ||||
assertEquals("unexpected error output", expectedErr, actualErr); | |||||
assertEquals("unexpected error output", | |||||
expectedErr, getFileString("redirect.err")); | |||||
assertPropertyEquals("redirect.err", expectedErr.trim()); | assertPropertyEquals("redirect.err", expectedErr.trim()); | ||||
} | } | ||||
public void testRedirect5() { | |||||
public void testRedirect5() throws IOException { | |||||
testRedirect5or6("redirect5"); | testRedirect5or6("redirect5"); | ||||
} | } | ||||
public void testRedirect6() { | |||||
public void testRedirect6() throws IOException { | |||||
testRedirect5or6("redirect6"); | testRedirect5or6("redirect6"); | ||||
} | } | ||||
public void testRedirect5or6(String target) { | |||||
public void testRedirect5or6(String target) throws IOException { | |||||
executeTarget(target); | executeTarget(target); | ||||
if (getProject().getProperty("wc.can.run") == null) { | if (getProject().getProperty("wc.can.run") == null) { | ||||
return; | 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", ""); | assertPropertyEquals("redirect.err", ""); | ||||
} | } | ||||
public void testRedirect7() { | |||||
public void testRedirect7() throws IOException { | |||||
executeTarget("redirect7"); | executeTarget("redirect7"); | ||||
if (getProject().getProperty("wc.can.run") == null) { | if (getProject().getProperty("wc.can.run") == null) { | ||||
return; | 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 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 { | 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() { | public void testspawn() { | ||||
@@ -256,7 +388,6 @@ public class ExecTaskTest extends BuildFileTest { | |||||
project.setProperty("logFile", logFile); | project.setProperty("logFile", logFile); | ||||
} | } | ||||
public void setTimeToWait(int timeToWait) { | public void setTimeToWait(int timeToWait) { | ||||
this.timeToWait = timeToWait; | this.timeToWait = timeToWait; | ||||
project.setProperty("timeToWait", Long.toString(timeToWait)); | project.setProperty("timeToWait", Long.toString(timeToWait)); | ||||
@@ -319,4 +450,24 @@ public class ExecTaskTest extends BuildFileTest { | |||||
public void messageLogged(BuildEvent event) { | 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; | 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 org.apache.tools.ant.util.FileUtils; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileReader; | import java.io.FileReader; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.GregorianCalendar; | |||||
import junit.framework.ComparisonFailure; | |||||
/** | /** | ||||
* Unit test for the <apply> task. | |||||
*/ | */ | ||||
public class ExecuteOnTest extends BuildFileTest { | public class ExecuteOnTest extends BuildFileTest { | ||||
private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; | private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; | ||||
private static final String BUILD_FILE = BUILD_PATH + "apply.xml"; | private static final String BUILD_FILE = BUILD_PATH + "apply.xml"; | ||||
public ExecuteOnTest(String name) { | public ExecuteOnTest(String name) { | ||||
super(name); | super(name); | ||||
} | } | ||||
@@ -62,29 +60,25 @@ public class ExecuteOnTest extends BuildFileTest { | |||||
int xerr = log.indexOf(x + " err"); | int xerr = log.indexOf(x + " err"); | ||||
int yerr = log.indexOf(y + " err"); | int yerr = log.indexOf(y + " err"); | ||||
int zerr = log.indexOf(z + " 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("yout < xout", yout < xout); | ||||
assertFalse("zout < yout", zout < yout); | assertFalse("zout < yout", zout < yout); | ||||
assertFalse("yerr < xerr", yerr < xerr); | assertFalse("yerr < xerr", yerr < xerr); | ||||
assertFalse("zerr < yerr", zerr < yerr); | assertFalse("zerr < yerr", zerr < yerr); | ||||
} | } | ||||
public void testRedirect1() { | |||||
public void testRedirect1() throws IOException { | |||||
executeTarget("redirect1"); | executeTarget("redirect1"); | ||||
if (getProject().getProperty("test.can.run") == null) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | 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 x = getProject().resolveFile("x"); | ||||
File y = getProject().resolveFile("y"); | File y = getProject().resolveFile("y"); | ||||
File z = getProject().resolveFile("z"); | File z = getProject().resolveFile("z"); | ||||
@@ -94,32 +88,26 @@ public class ExecuteOnTest extends BuildFileTest { | |||||
int xerr = actualOut.indexOf(x + " err"); | int xerr = actualOut.indexOf(x + " err"); | ||||
int yerr = actualOut.indexOf(y + " err"); | int yerr = actualOut.indexOf(y + " err"); | ||||
int zerr = actualOut.indexOf(z + " 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("yout < xout", yout < xout); | ||||
assertFalse("zout < yout", zout < yout); | assertFalse("zout < yout", zout < yout); | ||||
assertFalse("yerr < xerr", yerr < xerr); | assertFalse("yerr < xerr", yerr < xerr); | ||||
assertFalse("zerr < yerr", zerr < yerr); | assertFalse("zerr < yerr", zerr < yerr); | ||||
} | } | ||||
public void testRedirect2() { | |||||
public void testRedirect2() throws IOException { | |||||
executeTarget("redirect2"); | executeTarget("redirect2"); | ||||
if (getProject().getProperty("test.can.run") == null) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | 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 x = getProject().resolveFile("x"); | ||||
File y = getProject().resolveFile("y"); | File y = getProject().resolveFile("y"); | ||||
File z = getProject().resolveFile("z"); | File z = getProject().resolveFile("z"); | ||||
@@ -129,29 +117,25 @@ public class ExecuteOnTest extends BuildFileTest { | |||||
int xerr = actualErr.indexOf(x + " err"); | int xerr = actualErr.indexOf(x + " err"); | ||||
int yerr = actualErr.indexOf(y + " err"); | int yerr = actualErr.indexOf(y + " err"); | ||||
int zerr = actualErr.indexOf(z + " 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("yout < xout", yout < xout); | ||||
assertFalse("zout < yout", zout < yout); | assertFalse("zout < yout", zout < yout); | ||||
assertFalse("yerr < xerr", yerr < xerr); | assertFalse("yerr < xerr", yerr < xerr); | ||||
assertFalse("zerr < yerr", zerr < yerr); | assertFalse("zerr < yerr", zerr < yerr); | ||||
} | } | ||||
public void testRedirect3() { | |||||
public void testRedirect3() throws IOException { | |||||
executeTarget("redirect3"); | executeTarget("redirect3"); | ||||
if (getProject().getProperty("test.can.run") == null) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | 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 x = getProject().resolveFile("x"); | ||||
File y = getProject().resolveFile("y"); | File y = getProject().resolveFile("y"); | ||||
File z = getProject().resolveFile("z"); | File z = getProject().resolveFile("z"); | ||||
@@ -161,33 +145,36 @@ public class ExecuteOnTest extends BuildFileTest { | |||||
int xerr = getLog().indexOf(x + " err"); | int xerr = getLog().indexOf(x + " err"); | ||||
int yerr = getLog().indexOf(y + " err"); | int yerr = getLog().indexOf(y + " err"); | ||||
int zerr = getLog().indexOf(z + " 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("yout < xout", yout < xout); | ||||
assertFalse("zout < yout", zout < yout); | assertFalse("zout < yout", zout < yout); | ||||
assertFalse("yerr < xerr", yerr < xerr); | assertFalse("yerr < xerr", yerr < xerr); | ||||
assertFalse("zerr < yerr", zerr < yerr); | 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"); | executeTarget("redirect4"); | ||||
if (getProject().getProperty("test.can.run") == null) { | if (getProject().getProperty("test.can.run") == null) { | ||||
return; | 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 x = getProject().resolveFile("x"); | ||||
File y = getProject().resolveFile("y"); | File y = getProject().resolveFile("y"); | ||||
File z = getProject().resolveFile("z"); | File z = getProject().resolveFile("z"); | ||||
@@ -197,68 +184,388 @@ public class ExecuteOnTest extends BuildFileTest { | |||||
int xerr = actualErr.indexOf(x + " err"); | int xerr = actualErr.indexOf(x + " err"); | ||||
int yerr = actualErr.indexOf(y + " err"); | int yerr = actualErr.indexOf(y + " err"); | ||||
int zerr = actualErr.indexOf(z + " 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("yout < xout", yout < xout); | ||||
assertFalse("zout < yout", zout < yout); | assertFalse("zout < yout", zout < yout); | ||||
assertFalse("yerr < xerr", yerr < xerr); | assertFalse("yerr < xerr", yerr < xerr); | ||||
assertFalse("zerr < yerr", zerr < yerr); | 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"); | testRedirect5or6("redirect5"); | ||||
} | } | ||||
public void testRedirect6() { | |||||
public void testRedirect6() throws IOException { | |||||
testRedirect5or6("redirect6"); | testRedirect5or6("redirect6"); | ||||
} | } | ||||
private void testRedirect5or6(String target) { | |||||
private void testRedirect5or6(String target) throws IOException { | |||||
executeTarget(target); | executeTarget(target); | ||||
if (getProject().getProperty("sed.can.run") == null) { | if (getProject().getProperty("sed.can.run") == null) { | ||||
return; | 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", ""); | 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"); | executeTarget("redirect7"); | ||||
if (getProject().getProperty("sed.can.run") == null) { | if (getProject().getProperty("sed.can.run") == null) { | ||||
return; | 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", "blah y z"); | ||||
assertPropertyUnset("redirect.err"); | 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 junit.framework.*; | ||||
import java.io.*; | import java.io.*; | ||||
import org.apache.tools.ant.*; | 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.FileUtils; | ||||
import org.apache.tools.ant.util.TeeOutputStream; | |||||
/** | /** | ||||
* stress out java task | * stress out java task | ||||
@@ -186,6 +188,26 @@ public class JavaTest extends BuildFileTest { | |||||
assertTrue("log file exists", logFile.exists()); | 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 | * entry point class with no dependencies other | ||||
* than normal JRE runtime | * 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) { | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | } |