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