Browse Source

Add <redirector>.

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276257 13f79535-47bb-0310-9956-ffa450edef68
master
Matthew Jason Benson 21 years ago
parent
commit
b0507d4451
23 changed files with 3032 additions and 478 deletions
  1. +3
    -0
      WHATSNEW
  2. +36
    -0
      docs/manual/CoreTasks/apply.html
  3. +35
    -1
      docs/manual/CoreTasks/exec.html
  4. +13
    -0
      docs/manual/CoreTasks/java.html
  5. +1
    -0
      docs/manual/conceptstypeslist.html
  6. +210
    -17
      src/etc/testcases/taskdefs/exec/apply.xml
  7. +217
    -1
      src/etc/testcases/taskdefs/exec/exec.xml
  8. +1
    -0
      src/etc/testcases/taskdefs/exec/expected/utf-8
  9. +1
    -0
      src/etc/testcases/taskdefs/exec/input/iso8859-1
  10. +154
    -22
      src/etc/testcases/taskdefs/java.xml
  11. +6
    -156
      src/main/org/apache/tools/ant/filters/StringInputStream.java
  12. +55
    -9
      src/main/org/apache/tools/ant/taskdefs/ExecTask.java
  13. +43
    -10
      src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java
  14. +55
    -8
      src/main/org/apache/tools/ant/taskdefs/Java.java
  15. +413
    -80
      src/main/org/apache/tools/ant/taskdefs/Redirector.java
  16. +511
    -0
      src/main/org/apache/tools/ant/types/RedirectorElement.java
  17. +120
    -0
      src/main/org/apache/tools/ant/util/ConcatFileInputStream.java
  18. +95
    -0
      src/main/org/apache/tools/ant/util/LeadPipeInputStream.java
  19. +175
    -0
      src/main/org/apache/tools/ant/util/OutputStreamFunneler.java
  20. +203
    -0
      src/main/org/apache/tools/ant/util/ReaderInputStream.java
  21. +224
    -73
      src/testcases/org/apache/tools/ant/taskdefs/ExecTaskTest.java
  22. +408
    -101
      src/testcases/org/apache/tools/ant/taskdefs/ExecuteOnTest.java
  23. +53
    -0
      src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java

+ 3
- 0
WHATSNEW View File

@@ -48,6 +48,9 @@ Other changes:


* New attribute "negate" on <propertyset> to invert selection criteria. * New attribute "negate" on <propertyset> to invert selection criteria.


* New <redirector> type introduced to provide extreme I/O flexibility.
Initial support for <exec>, <apply>, and <java> tasks.

Changes from Ant 1.6.1 to current Ant 1.6 CVS version Changes from Ant 1.6.1 to current Ant 1.6 CVS version
============================================= =============================================




+ 36
- 0
docs/manual/CoreTasks/apply.html View File

@@ -290,6 +290,19 @@ attribute.</p>
<p>It is possible to specify environment variables to pass to the <p>It is possible to specify environment variables to pass to the
system command via nested <code>&lt;env&gt;</code> elements. See the system command via nested <code>&lt;env&gt;</code> elements. See the
description in the section about <a href="exec.html#env">exec</a></p> description in the section about <a href="exec.html#env">exec</a></p>
<h4>redirector</h4>
<i><b>Since Ant 1.6.2</b></i>
<p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a>
can be specified. &lt;apply&gt;'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 &quot;Enough Rope To Hang Yourself With.&quot;
</p>
<h3>Examples</h3> <h3>Examples</h3>
<blockquote><pre> <blockquote><pre>
&lt;apply executable=&quot;ls&quot;&gt; &lt;apply executable=&quot;ls&quot;&gt;
@@ -334,6 +347,29 @@ of all files separated by spaces.</p>
<code>.o</code>, replacing TARGETFILE with the absolute filename of <code>.o</code>, replacing TARGETFILE with the absolute filename of
the <code>.o</code> and SOURCEFILE with the absolute name of the the <code>.o</code> and SOURCEFILE with the absolute name of the
<code>.c</code> file.</p> <code>.c</code> file.</p>
<blockquote><pre>
&lt;mapper id=&quot;out&quot; type=&quot;glob&quot;
from=&quot;src${file.separator}*.file&quot;
to=&quot;dest${file.separator}*.out&quot; /&gt;

&lt;apply executable=&quot;processfile&quot; dest=&quot;dest&quot;&gt;
&lt;fileset dir=&quot;src&quot; includes=&quot;*.file&quot;/&gt;
&lt;mapper refid=&quot;out&quot; /&gt;
&lt;redirector&gt;
&lt;outputmapper refid=&quot;out&quot; /&gt;
&lt;/redirector&gt;
&lt;/apply&gt;
</pre></blockquote>
Applies the fictitious &quot;processfile&quot; executable to all
files matching <code>*.file</code> in the <CODE>src</CODE> directory.
The <CODE>out</CODE> &lt;mapper&gt; has been set up to map
<CODE>*.file</CODE> to <CODE>*.out</CODE>, then this &lt;mapper&gt;
is used to specify <CODE>targetfile</CODE>s for this &lt;apply&gt;
task. A reference to <CODE>out</CODE> is then used as an
&lt;outputmapper&gt; nested in a &lt;redirector&gt;, which in turn is
nested beneath this &lt;apply&gt; instance. This allows us to perform
dependency checking against output files--the target files in this case.

<hr><p align="center">Copyright &copy; 2000-2004 The Apache Software Foundation. All rights <hr><p align="center">Copyright &copy; 2000-2004 The Apache Software Foundation. All rights
Reserved.</p> Reserved.</p>




+ 35
- 1
docs/manual/CoreTasks/exec.html View File

@@ -241,7 +241,19 @@ system command via nested <code>&lt;env&gt;</code> elements.</p>
replaced by the absolute filename of the file by Ant.</td> replaced by the absolute filename of the file by Ant.</td>
</tr> </tr>
</table> </table>

<a name="redirector"><h4>redirector</h4></a>
<i><b>Since Ant 1.6.2</b></i>
<p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a>
can be specified. In general, the attributes of the redirector behave
as the corresponding attributes available at the task level. The most
notable peculiarity stems from the retention of the &lt;exec&gt;
attributes for backwards compatibility. Any file mapping is done
using a <CODE>null</CODE> sourcefile; therefore not all
<a href="../CoreTypes/mapper.html">Mapper</a> types will return
results. When no results are returned, redirection specifications
will fall back to the task level attributes. In practice this means that
defaults can be specified for input, output, and error output files.
</p>
<h3>Errors and return codes</h3> <h3>Errors and return codes</h3>
By default the return code of a &lt;exec&gt; is ignored; when you set By default the return code of a &lt;exec&gt; is ignored; when you set
<code>failonerror="true"</code> then any return code signaling failure <code>failonerror="true"</code> then any return code signaling failure
@@ -287,6 +299,27 @@ system command.</p>
<p>Starts the <i>${browser}</i> with the specified <i>${file}</i> and end the <p>Starts the <i>${browser}</i> with the specified <i>${file}</i> and end the
ant process. The browser will let be open.</p> ant process. The browser will let be open.</p>


<blockquote><pre>
&lt;exec executable=&quot;cat&quot;&gt;
&lt;redirector outputproperty=&quot;redirector.out&quot;
errorproperty=&quot;redirector.err&quot;
inputstring=&quot;blah before blah&quot;&gt;
&lt;inputfilterchain&gt;
&lt;replacestring from=&quot;before&quot; to=&quot;after&quot; /&gt;
&lt;/inputfilterchain&gt;
&lt;outputmapper type=&quot;merge&quot; to=&quot;redirector.out&quot; /&gt;
&lt;errormapper type=&quot;merge&quot; to=&quot;redirector.err&quot; /&gt;
&lt;/redirector&gt;
&lt;/exec&gt;
</pre></blockquote>

Sends the string &quot;blah before blah&quot; to the &quot;cat&quot; executable,
using an <a href="../CoreTypes/filterchain.html">&lt;inputfilterchain&gt;</a>
to replace &quot;before&quot; with &quot;after&quot; on the way in.
Output is sent to the file &quot;redirector.out&quot; and stored
in a property of the same name. Similarly, error output is sent to
a file and a property, both named &quot;redirector.err&quot;.



<p><b>Note:</b> Although it may work for you to specify arguments using <p><b>Note:</b> Although it may work for you to specify arguments using
a simple arg-element and separate them by spaces it may fail if you switch to a simple arg-element and separate them by spaces it may fail if you switch to
@@ -301,6 +334,7 @@ This problem may occur with all JDK's &lt; 1.2.</p>
sub process is killed and a message printed to the log. The return sub process is killed and a message printed to the log. The return
value of the execution will be "-1", which will halt the build if value of the execution will be "-1", which will halt the build if
<tt>failonerror=true</tt>, but be ignored otherwise. <tt>failonerror=true</tt>, but be ignored otherwise.

<hr> <hr>
<p align="center">Copyright &copy; 2000-2004 The Apache Software Foundation. All rights <p align="center">Copyright &copy; 2000-2004 The Apache Software Foundation. All rights
Reserved.</p> Reserved.</p>


+ 13
- 0
docs/manual/CoreTasks/java.html View File

@@ -243,6 +243,19 @@ subelement.</p>
<p><em>since Ant 1.6.</em></p> <p><em>since Ant 1.6.</em></p>


<a name="redirector"><h4>redirector</h4></a>
<i><b>Since Ant 1.6.2</b></i>
<p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a>
can be specified. In general, the attributes of the redirector behave
as the corresponding attributes available at the task level. The most
notable peculiarity stems from the retention of the &lt;java&gt;
attributes for backwards compatibility. Any file mapping is done
using a <CODE>null</CODE> sourcefile; therefore not all
<a href="../CoreTypes/mapper.html">Mapper</a> types will return
results. When no results are returned, redirection specifications
will fall back to the task level attributes. In practice this means that
defaults can be specified for input, output, and error output files.
</p>
<h3>Errors and return codes</h3> <h3>Errors and return codes</h3>
By default the return code of a &lt;java&gt; is ignored. Alternatively, you can set <code>resultproperty</code> to the name By default the return code of a &lt;java&gt; is ignored. Alternatively, you can set <code>resultproperty</code> to the name
of a property and have it assigned to the result code (barring immutability, of a property and have it assigned to the result code (barring immutability,


+ 1
- 0
docs/manual/conceptstypeslist.html View File

@@ -27,6 +27,7 @@
<a href="using.html#path">Path-like Structures</a><br> <a href="using.html#path">Path-like Structures</a><br>
<a href="CoreTypes/permissions.html">Permissions</a><br> <a href="CoreTypes/permissions.html">Permissions</a><br>
<a href="CoreTypes/propertyset.html">PropertySet</a><br> <a href="CoreTypes/propertyset.html">PropertySet</a><br>
<a href="CoreTypes/redirector.html">I/O Redirectors</a><br>
<a href="CoreTypes/regexp.html">Regexp</a><br> <a href="CoreTypes/regexp.html">Regexp</a><br>
<a href="CoreTypes/selectors.html">Selectors</a><br> <a href="CoreTypes/selectors.html">Selectors</a><br>
<a href="CoreTypes/xmlcatalog.html">XMLCatalog</a><br> <a href="CoreTypes/xmlcatalog.html">XMLCatalog</a><br>


+ 210
- 17
src/etc/testcases/taskdefs/exec/apply.xml View File

@@ -12,16 +12,6 @@
</or> </or>
</condition> </condition>
<!-- UNIX --> <!-- UNIX -->
<available file="wc" filepath="${env.PATH}" property="wc.executable"/>
<!-- CYGWIN -->
<available file="wc.exe" filepath="${env.PATH}" property="wc.exe.executable"/>
<condition property="wc.can.run">
<or>
<isset property="wc.executable"/>
<isset property="wc.exe.executable"/>
</or>
</condition>
<!-- UNIX -->
<available file="sed" filepath="${env.PATH}" property="sed.executable"/> <available file="sed" filepath="${env.PATH}" property="sed.executable"/>
<!-- CYGWIN --> <!-- CYGWIN -->
<available file="sed.exe" filepath="${env.PATH}" property="sed.exe.executable"/> <available file="sed.exe" filepath="${env.PATH}" property="sed.exe.executable"/>
@@ -38,6 +28,7 @@
<echo file="y">s/y/blah/g${line.separator}</echo> <echo file="y">s/y/blah/g${line.separator}</echo>
<echo file="z">s/z/blah/g${line.separator}</echo> <echo file="z">s/z/blah/g${line.separator}</echo>
<fileset id="xyz" dir="${basedir}" includes="x,y,z" /> <fileset id="xyz" dir="${basedir}" includes="x,y,z" />
<filelist id="xyzlist" dir="${basedir}" files="x,y,z" />
</target> </target>


<target name="no-redirect" depends="init,xyz" if="test.can.run"> <target name="no-redirect" depends="init,xyz" if="test.can.run">
@@ -83,7 +74,7 @@
<apply executable="sed" inputstring="x y z${line.separator}" append="true" <apply executable="sed" inputstring="x y z${line.separator}" append="true"
error="redirect.err" errorproperty="redirect.err" error="redirect.err" errorproperty="redirect.err"
output="redirect.out" outputproperty="redirect.out"> output="redirect.out" outputproperty="redirect.out">
<arg value="-f"/>
<arg value="-f" />
<fileset refid="xyz" /> <fileset refid="xyz" />
</apply> </apply>
</target> </target>
@@ -93,8 +84,8 @@
<apply executable="sed" input="redirect.in" append="true" <apply executable="sed" input="redirect.in" append="true"
error="redirect.err" errorproperty="redirect.err" error="redirect.err" errorproperty="redirect.err"
output="redirect.out" outputproperty="redirect.out"> output="redirect.out" outputproperty="redirect.out">
<arg value="-f"/>
<fileset refid="xyz" />
<arg value="-f" />
<filelist refid="xyzlist" />
</apply> </apply>
</target> </target>


@@ -102,19 +93,221 @@
<apply executable="sed" inputstring="x y z${line.separator}" <apply executable="sed" inputstring="x y z${line.separator}"
error="redirect.err" output="redirect.out" error="redirect.err" output="redirect.out"
outputproperty="redirect.out"> outputproperty="redirect.out">
<arg value="-f"/>
<arg value="-f" />
<fileset refid="xyz" /> <fileset refid="xyz" />
</apply> </apply>
</target> </target>
<target name="redirect7b" depends="redirect7">
<echo>redirect.out=${redirect.out}</echo>
<target name="redirector1" description="fail"
depends="init,xyz" if="test.can.run">
<apply executable="sh">
<arg value="parrot.sh"/>
<fileset refid="xyz" />
<redirector output="redirector.out" />
<redirector output="whocares" />
</apply>
</target>

<target name="redirector2" depends="init,xyz" if="test.can.run">
<apply executable="sh">
<arg value="parrot.sh"/>
<fileset refid="xyz" />
<redirector output="redirector.out" append="true" />
</apply>
</target>

<target name="redirector3" depends="init,xyz" if="test.can.run">
<apply executable="sh">
<arg value="parrot.sh"/>
<fileset refid="xyz" />
<redirector append="true"
output="redirector.out" error="redirector.err" />
</apply>
</target>

<target name="redirector4" depends="init,xyz" if="test.can.run">
<apply executable="sh">
<arg value="parrot.sh"/>
<fileset refid="xyz" />
<redirector output="redirector.out" logerror="true"
append="true" outputproperty="redirector.out" />
</apply>
</target>

<target name="redirector5" depends="init,xyz" if="test.can.run">
<apply executable="sh">
<redirector error="redirector.err" errorproperty="redirector.err"
output="redirector.out" outputproperty="redirector.out"
append="true" />
<arg value="parrot.sh"/>
<fileset refid="xyz" />
</apply>
</target>

<target name="redirector6" depends="init,xyz" if="test.can.run">
<apply executable="sh">
<redirector append="true" outputproperty="redirector.out"
errorproperty="redirector.err">
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
<arg value="parrot.sh" />
<filelist refid="xyzlist" />
</apply>
</target>

<target name="redirector7" depends="init,xyz" if="test.can.run">
<apply executable="sh">
<redirector append="true" outputproperty="redirector.out"
errorproperty="redirector.err">
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
<errorfilterchain>
<replacestring from="err" to="ERROR!!!" />
</errorfilterchain>
</redirector>
<arg value="parrot.sh" />
<fileset refid="xyz" />
</apply>
</target>

<target name="redirector8" depends="init,xyz" if="sed.can.run">
<echo file="redirector.in">x y z${line.separator}</echo>
<apply executable="sed">
<redirector append="true" outputproperty="redirector.out"
errorproperty="redirector.err">
<inputmapper type="merge" to="redirector.in" />
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
<arg value="-f" />
<fileset refid="xyz" />
</apply>
</target>

<target name="redirector9" depends="init,xyz" if="sed.can.run">
<echo file="redirector.in">x before y before z${line.separator}</echo>
<apply executable="sed">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err" append="true">
<inputfilterchain>
<replacestring from="before" to="after" />
</inputfilterchain>
<inputmapper type="merge" to="redirector.in" />
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
<arg value="-f" />
<fileset refid="xyz" />
</apply>
</target>

<target name="redirector10" depends="init,xyz" if="sed.can.run">
<echo file="redirector.in">x before y before z${line.separator}</echo>
<apply executable="sed">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err" append="true">
<outputfilterchain>
<replacestring from="before" to="after" />
</outputfilterchain>
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
<arg value="-f" />
<srcfile />
<arg value="redirector.in"/>
<filelist refid="xyzlist" />
</apply>
</target>

<target name="redirector11" depends="init,xyz" if="sed.can.run">
<apply executable="sed">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err"
inputstring="x before y before z${line.separator}"
append="true">
<inputfilterchain>
<replacestring from="before" to="after" />
</inputfilterchain>
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
<arg value="-f" />
<fileset refid="xyz" />
</apply>
</target>

<target name="redirector12" depends="init,xyz" if="sed.can.run">
<echo file="redirector.in">x before y before z${line.separator}</echo>
<apply executable="sed" output="redirector.out" error="redirector.err">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err" append="true">
<outputfilterchain>
<replacestring from="before" to="after" />
</outputfilterchain>
<outputmapper type="glob" from="nomatch" to="nomatchout" />
<errormapper type="glob" from="nomatch" to="nomatcherr" />
</redirector>
<arg value="-f" />
<srcfile />
<arg value="redirector.in"/>
<filelist refid="xyzlist" />
</apply>
</target>

<target name="redirector13" depends="init,xyz" if="test.can.run">
<apply executable="sh">
<redirector>
<outputfilterchain>
<replacestring from="out" to="OUTPUT???" />
</outputfilterchain>
<errorfilterchain>
<replacestring from="err" to="ERROR!!!" />
</errorfilterchain>
</redirector>
<arg value="parrot.sh" />
<fileset refid="xyz" />
</apply>
</target>

<target name="redirector14" depends="init,xyz" if="sed.can.run">
<echo file="redirector.in">z before y before x${line.separator}</echo>
<apply executable="sed">
<redirector append="true"
inputstring="x before y before z${line.separator}">
<outputfilterchain>
<replacestring from="before" to="after" />
</outputfilterchain>
<inputmapper type="glob" from="x" to="redirector.in" />
<outputmapper type="glob" from="y" to="redirector.out" />
<errormapper type="glob" from="z" to="redirector.err" />
</redirector>
<arg value="-f" />
<fileset refid="xyz" />
</apply>
</target>

<target name="redirector14b" depends="init,xyz" if="sed.can.run">
<apply executable="sed">
<redirector append="true"
inputstring="x before y before z${line.separator}">
<outputfilterchain>
<replacestring from="before" to="after" />
</outputfilterchain>
<inputmapper type="glob" from="x" to="redirector.in" />
<outputmapper type="glob" from="y" to="redirector.out" />
<errormapper type="glob" from="z" to="redirector.err" />
</redirector>
<arg value="-f" />
<fileset file="y" />
</apply>
</target> </target>


<target name="cleanup"> <target name="cleanup">
<delete> <delete>
<fileset dir="${basedir}" includes="redirect.*" />
<fileset refid="xyz" /> <fileset refid="xyz" />
<fileset dir="${basedir}" includes="redirect.*" />
<fileset dir="${basedir}" includes="redirector.*" />
</delete> </delete>
</target> </target>
</project> </project>

+ 217
- 1
src/etc/testcases/taskdefs/exec/exec.xml View File

@@ -25,6 +25,16 @@
<isset property="wc.exe.executable"/> <isset property="wc.exe.executable"/>
</or> </or>
</condition> </condition>
<!-- UNIX -->
<available file="cat" filepath="${env.PATH}" property="cat.executable"/>
<!-- CYGWIN -->
<available file="cat.exe" filepath="${env.PATH}" property="cat.exe.executable"/>
<condition property="cat.can.run">
<or>
<isset property="cat.executable"/>
<isset property="cat.exe.executable"/>
</or>
</condition>
</target> </target>


<target name="spawn" depends="init" if="test.can.run"> <target name="spawn" depends="init" if="test.can.run">
@@ -98,10 +108,216 @@
</exec> </exec>
</target> </target>


<target name="redirector1" description="fail"
depends="init" if="test.can.run">
<exec executable="sh">
<arg value="parrot.sh"/>
<arg value="${ant.file}" />
<redirector output="redirector.out" />
<redirector output="whocares" />
</exec>
</target>

<target name="redirector2" depends="init" if="test.can.run">
<exec executable="sh">
<arg value="parrot.sh"/>
<arg value="${ant.file}" />
<redirector output="redirector.out" />
</exec>
</target>

<target name="redirector3" depends="init" if="test.can.run">
<exec executable="sh">
<arg value="parrot.sh"/>
<arg value="${ant.file}" />
<redirector output="redirector.out" error="redirector.err" />
</exec>
</target>

<target name="redirector4" depends="init" if="test.can.run">
<exec executable="sh">
<arg value="parrot.sh"/>
<arg value="${ant.file}" />
<redirector output="redirector.out" logerror="true"
outputproperty="redirector.out" />
</exec>
</target>

<target name="redirector5" depends="init" if="test.can.run">
<exec executable="sh">
<redirector error="redirector.err" errorproperty="redirector.err"
output="redirector.out" outputproperty="redirector.out" />
<arg value="parrot.sh"/>
<arg value="${ant.file}" />
</exec>
</target>

<target name="redirector6" depends="init" if="test.can.run">
<exec executable="sh">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err">
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
<arg value="parrot.sh" />
<arg value="${ant.file}" />
</exec>
</target>

<target name="redirector7" depends="init" if="test.can.run">
<exec executable="sh">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err">
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
<errorfilterchain>
<replacestring from="err" to="ERROR!!!" />
</errorfilterchain>
</redirector>
<arg value="parrot.sh" />
<arg value="${ant.file}" />
</exec>
</target>

<target name="redirector8" depends="init" if="wc.can.run">
<echo file="redirector.in">x y z</echo>
<exec executable="wc">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err">
<inputmapper type="merge" to="redirector.in" />
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
<arg value="-w"/>
</exec>
</target>

<target name="redirector9" depends="init" if="cat.can.run">
<echo file="redirector.in">blah before blah</echo>
<exec executable="cat">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err">
<inputfilterchain>
<replacestring from="before" to="after" />
</inputfilterchain>
<inputmapper type="merge" to="redirector.in" />
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
</exec>
</target>

<target name="redirector10" depends="init" if="cat.can.run">
<echo file="redirector.in">blah before blah</echo>
<exec executable="cat">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err">
<outputfilterchain>
<replacestring from="before" to="after" />
</outputfilterchain>
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
<arg value="redirector.in"/>
</exec>
</target>

<target name="redirector11" depends="init" if="cat.can.run">
<exec executable="cat">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err"
inputstring="blah before blah">
<inputfilterchain>
<replacestring from="before" to="after" />
</inputfilterchain>
<outputmapper type="merge" to="redirector.out" />
<errormapper type="merge" to="redirector.err" />
</redirector>
</exec>
</target>

<target name="redirector12" depends="init" if="cat.can.run">
<echo file="redirector.in">blah before blah</echo>
<exec executable="cat" output="redirector.out" error="redirector.err">
<redirector outputproperty="redirector.out"
errorproperty="redirector.err">
<outputfilterchain>
<replacestring from="before" to="after" />
</outputfilterchain>
<outputmapper type="glob" from="nomatch" to="nomatchout" />
<errormapper type="glob" from="nomatch" to="nomatcherr" />
</redirector>
<arg value="redirector.in"/>
</exec>
</target>

<target name="redirector13" depends="init" if="test.can.run">
<exec executable="sh">
<redirector>
<outputfilterchain>
<replacestring from="out" to="OUTPUT???" />
</outputfilterchain>
<errorfilterchain>
<replacestring from="err" to="ERROR!!!" />
</errorfilterchain>
</redirector>
<arg value="parrot.sh" />
<arg value="${ant.file}" />
</exec>
</target>

<target name="redirector14" depends="init" if="cat.can.run">
<exec executable="cat">
<redirector inputstring="blah before blah">
<outputfilterchain>
<replacestring from="before" to="after" />
</outputfilterchain>
<outputmapper type="glob" from="nomatch" to="nomatchout" />
<errormapper type="glob" from="nomatch" to="nomatcherr" />
</redirector>
</exec>
</target>

<target name="redirector15" depends="init" if="cat.can.run">
<exec executable="cat">
<redirector input="input/iso8859-1" output="redirector.out"
inputencoding="ISO8859_1" outputencoding="UTF8" />
</exec>
</target>

<target name="redirector16" depends="init" if="test.can.run">
<exec executable="sh">
<redirector inputstring="exit"
output="redirector16.out" error="redirector16.err" />
</exec>
<condition property="16pass">
<and>
<available file="redirector16.out" type="file" />
<available file="redirector16.err" type="file" />
</and>
</condition>
<fail unless="16pass">Files were not created.</fail>
</target>

<target name="redirector17" depends="init" if="test.can.run">
<exec executable="sh">
<redirector inputstring="exit" createemptyfiles="false"
output="redirector17.out" error="redirector17.err" />
</exec>
<condition property="17fail">
<or>
<available file="redirector17.out" type="file" />
<available file="redirector17.err" type="file" />
</or>
</condition>
<fail if="17fail">Files were created.</fail>
</target>

<target name="cleanup"> <target name="cleanup">
<delete> <delete>
<fileset file="${logFile}" /> <fileset file="${logFile}" />
<fileset dir="${basedir}" includes="redirect.*" />
<fileset dir="${basedir}" includes="redirect*" />
<fileset dir="${basedir}" includes="redirector*" />
</delete> </delete>
</target> </target>
</project> </project>

+ 1
- 0
src/etc/testcases/taskdefs/exec/expected/utf-8 View File

@@ -0,0 +1 @@
äöüÄÖÜß

+ 1
- 0
src/etc/testcases/taskdefs/exec/input/iso8859-1 View File

@@ -0,0 +1 @@
蔕�ヨワ゚

+ 154
- 22
src/etc/testcases/taskdefs/java.xml View File

@@ -7,6 +7,7 @@
<property name="timeToWait" value="4"/> <property name="timeToWait" value="4"/>
<!-- this property gets overridden programmatically--> <!-- this property gets overridden programmatically-->
<property name="logFile" value="spawn.log"/> <property name="logFile" value="spawn.log"/>
<property name="tmp" value="${java.io.tmpdir}"/>
<property name="app" <property name="app"
value="org.apache.tools.ant.taskdefs.JavaTest$$EntryPoint" /> value="org.apache.tools.ant.taskdefs.JavaTest$$EntryPoint" />


@@ -16,6 +17,11 @@
<property name="spawnapp" <property name="spawnapp"
value="org.apache.tools.ant.taskdefs.JavaTest$$SpawnEntryPoint" /> value="org.apache.tools.ant.taskdefs.JavaTest$$SpawnEntryPoint" />


<property name="pipeapp"
value="org.apache.tools.ant.taskdefs.JavaTest$$PipeEntryPoint" />

<!--taskdef name="gc" classname="org.apache.tools.ant.taskdefs.optional.Gc" /-->

<target name="testNoJarNoClassname"> <target name="testNoJarNoClassname">
<java/> <java/>
</target> </target>
@@ -126,18 +132,17 @@
<echo message="exitcode = ${exitcode}"/> <echo message="exitcode = ${exitcode}"/>
</target> </target>
<target name="testResultPropertyNonZeroNoFork">
<java classname="${app}"
classpath="${tests-classpath.value}"
resultproperty="exitcode"
failonerror="false"
fork="false"
>
<arg value="-1"/>
<permissions/>
</java>
<echo message="exitcode = ${exitcode}"/>
</target>
<target name="testResultPropertyNonZeroNoFork">
<java classname="${app}"
classpath="${tests-classpath.value}"
resultproperty="exitcode"
failonerror="false"
fork="false">
<arg value="-1"/>
<permissions/>
</java>
<echo message="exitcode = ${exitcode}"/>
</target>


<target name="testRunFailWithFailOnError"> <target name="testRunFailWithFailOnError">
<java classname="${app}" <java classname="${app}"
@@ -157,16 +162,143 @@
</java> </java>
</target> </target>


<target name="testSpawn">
<java classname="${spawnapp}" fork="true" spawn="true" classpath="${tests-classpath.value}">
<arg value="${timeToWait}"/>
<arg value="${logFile}" />
</java>
</target>
<target name="testSpawn">
<java classname="${spawnapp}" fork="true" spawn="true" classpath="${tests-classpath.value}">
<arg value="${timeToWait}"/>
<arg value="${logFile}" />
</java>
</target>


<!--redirection testcases don't want to run under junit unless forked-->
<target name="redirect1">
<java classname="${pipeapp}"
classpath="${tests-classpath.value}"
inputstring="foo"
fork="true"
output="${tmp}/redirect.out"
errorproperty="redirect.err">
<arg value="out" />
</java>
<!-- let dumb Windows catch up -->
<sleep seconds="2" />
<loadfile property="redirect.out.contents" srcfile="${tmp}/redirect.out" />
<condition property="r1pass">
<and>
<equals arg1="${redirect.out.contents}" arg2="foo" />
<equals arg1="${redirect.err}" arg2="" />
</and>
</condition>
<fail unless="r1pass" />
</target>


<target name="cleanup">
<delete file="${logFile}"/>
</target>
<target name="foo" />
<target name="redirect2" depends="redirect1">
<java classname="${pipeapp}"
classpath="${tests-classpath.value}"
inputstring="bar"
append="true"
fork="true"
output="${tmp}/redirect.out"
errorproperty="redirect.err">
<arg value="both" />
</java>
<!-- let dumb Windows catch up -->
<sleep seconds="2" />
<loadfile property="redirect.out.contents2" srcfile="${tmp}/redirect.out" />
<condition property="r2pass">
<and>
<equals arg1="${redirect.out.contents2}" arg2="foobar" />
<!-- property should not be reset -->
<equals arg1="${redirect.err}" arg2="" />
</and>
</condition>
<fail unless="r2pass" />
</target>

<target name="redirect3">
<java classname="${pipeapp}"
classpath="${tests-classpath.value}"
inputstring="foo"
fork="true"
output="${tmp}/redirect.out"
error="${tmp}/redirect.err">
<arg value="both" />
</java>
<!-- let dumb Windows catch up -->
<sleep seconds="2" />
<loadfile property="redirect.out.contents"
srcfile="${tmp}/redirect.out" />
<condition property="r3pass">
<and>
<equals arg1="${redirect.out.contents}" arg2="foo" />
<filesmatch file1="${tmp}/redirect.out"
file2="${tmp}/redirect.err" />
</and>
</condition>
<fail unless="r3pass" />
</target>

<target name="redirector1">
<java taskname="foo" classname="${pipeapp}" fork="true"
classpath="${tests-classpath.value}">
<redirector inputstring="foo"
output="${tmp}/redirector.out"
error="${tmp}/redirector.err"
createemptyfiles="false" />
<arg value="out" />
</java>
<!-- let dumb Windows catch up -->
<sleep seconds="2" />
<loadfile property="redirector.out.contents"
srcfile="${tmp}/redirector.out" />
<condition property="ror1pass">
<and>
<equals arg1="${redirector.out.contents}" arg2="foo" />
<not>
<available file="${tmp}/redirector.err" />
</not>
</and>
</condition>
<fail unless="ror1pass" />
</target>

<target name="redirector2" depends="redirector1">
<!-- fork here, some VMs can be ill-behaved with files,
such as W!nd0ws -->
<java taskname="foo" classname="${pipeapp}" fork="true"
classpath="${tests-classpath.value}">
<redirector inputstring="foo"
append="true"
output="${tmp}/redirector.out"
error="${tmp}/redirector.err"
createemptyfiles="false">
<errorfilterchain>
<replacestring from="foo" to="bar" />
</errorfilterchain>
</redirector>
<arg value="both" />
</java>
<!-- let dumb Windows catch up -->
<sleep seconds="2" />
<loadfile property="redirector.out.contents2"
srcfile="${tmp}/redirector.out" />
<loadfile property="redirector.err.contents"
srcfile="${tmp}/redirector.err" />
<condition property="ror2pass">
<and>
<equals arg1="${redirector.out.contents2}" arg2="foofoo" />
<equals arg1="${redirector.err.contents}" arg2="bar" />
</and>
</condition>
<fail unless="ror2pass" />
</target>

<target name="cleanup">
<delete>
<fileset file="${logFile}" />
<fileset dir="${tmp}" includes="redirect*" />
<fileset dir="${tmp}" includes="redirector*" />
</delete>
</target>

<target name="foo" />
</project> </project>

+ 6
- 156
src/main/org/apache/tools/ant/filters/StringInputStream.java View File

@@ -20,21 +20,13 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader; import java.io.StringReader;


import org.apache.tools.ant.util.ReaderInputStream;

/** /**
* Wraps a String as an InputStream. * Wraps a String as an InputStream.
* *
*/ */
public class StringInputStream
extends InputStream {

/** Source string, stored as a StringReader */
private StringReader in;

private String encoding;

private byte[] slack;

private int begin;
public class StringInputStream extends ReaderInputStream {


/** /**
* Composes a stream from a String * Composes a stream from a String
@@ -42,159 +34,17 @@ public class StringInputStream
* @param source The string to read from. Must not be <code>null</code>. * @param source The string to read from. Must not be <code>null</code>.
*/ */
public StringInputStream(String source) { public StringInputStream(String source) {
in = new StringReader(source);
super(new StringReader(source));
} }


/** /**
* Composes a stream from a String with the specified encoding * Composes a stream from a String with the specified encoding
* *
* @param source The string to read from. Must not be <code>null</code>. * @param source The string to read from. Must not be <code>null</code>.
* @param encoding The encoding scheme.
* @param encoding The encoding scheme. Also must not be <CODE>null</CODE>.
*/ */
public StringInputStream(String source, String encoding) { public StringInputStream(String source, String encoding) {
in = new StringReader(source);
this.encoding = encoding;
}

/**
* Reads from the Stringreader, returning the same value.
*
* @return the value of the next character in the StringReader
*
* @exception IOException if the original StringReader fails to be read
*/
public synchronized int read() throws IOException {
if (in == null) {
throw new IOException("Stream Closed");
}

byte result;
if (slack != null && begin < slack.length) {
result = slack[begin];
if (++begin == slack.length) {
slack = null;
}
} else {
byte[] buf = new byte[1];
if (read(buf, 0, 1) <= 0) {
return -1;
}
result = buf[0];
}
if (result < 0) {
return 256 + result;
} else {
return result;
}
super(new StringReader(source), encoding);
} }


/**
* Reads from the Stringreader into a byte array
*
* @param b the byte array to read into
* @param off the offset in the byte array
* @param len the length in the byte array to fill
* @return the actual number read into the byte array, -1 at
* the end of the stream
* @exception IOException if an error occurs
*/
public synchronized int read(byte[] b, int off, int len)
throws IOException {

if (in == null) {
throw new IOException("Stream Closed");
}

while (slack == null) {
char[] buf = new char[len]; // might read too much
int n = in.read(buf);
if (n == -1) {
return -1;
}
if (n > 0) {
String s = new String(buf, 0, n);
if (encoding == null) {
slack = s.getBytes();
} else {
slack = s.getBytes(encoding);
}
begin = 0;
}
}

if (len > slack.length - begin) {
len = slack.length - begin;
}

System.arraycopy(slack, begin, b, off, len);

if ((begin += len) >= slack.length) {
slack = null;
}
return len;
}

/**
* Marks the read limit of the StringReader.
*
* @param limit the maximum limit of bytes that can be read before the
* mark position becomes invalid
*/
public synchronized void mark(final int limit) {
try {
in.mark(limit);
} catch (IOException ioe) {
throw new RuntimeException(ioe.getMessage());
}
}


/**
* @return the current number of bytes ready for reading
* @exception IOException if an error occurs
*/
public synchronized int available() throws IOException {
if (in == null) {
throw new IOException("Stream Closed");
}
if (slack != null) {
return slack.length - begin;
}
if (in.ready()) {
return 1;
} else {
return 0;
}
}

/**
* @return false - mark is not supported
*/
public boolean markSupported () {
return false; // would be imprecise
}

/**
* Resets the StringReader.
*
* @exception IOException if the StringReader fails to be reset
*/
public synchronized void reset() throws IOException {
if (in == null) {
throw new IOException("Stream Closed");
}
slack = null;
in.reset();
}

/**
* Closes the Stringreader.
*
* @exception IOException if the original StringReader fails to be closed
*/
public synchronized void close() throws IOException {
in.close();
slack = null;
in = null;
}
} }

+ 55
- 9
src/main/org/apache/tools/ant/taskdefs/ExecTask.java View File

@@ -27,6 +27,7 @@ import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.Environment; import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.RedirectorElement;
import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.FileUtils;


/** /**
@@ -53,7 +54,14 @@ public class ExecTask extends Task {
private boolean spawn = false; private boolean spawn = false;
private boolean incompatibleWithSpawn = false; private boolean incompatibleWithSpawn = false;


private Redirector redirector = new Redirector(this);
//include locally for screening purposes
private String inputString;
private File input;
private File output;
private File error;

protected Redirector redirector = new Redirector(this);
protected RedirectorElement redirectorElement;


/** /**
* Controls whether the VM (1.3 and above) is used to execute the * Controls whether the VM (1.3 and above) is used to execute the
@@ -141,7 +149,7 @@ public class ExecTask extends Task {
* @param out name of a file to which send output to * @param out name of a file to which send output to
*/ */
public void setOutput(File out) { public void setOutput(File out) {
redirector.setOutput(out);
this.output = out;
incompatibleWithSpawn = true; incompatibleWithSpawn = true;
} }


@@ -151,7 +159,11 @@ public class ExecTask extends Task {
* @param input name of a file to get input from * @param input name of a file to get input from
*/ */
public void setInput(File input) { public void setInput(File input) {
redirector.setInput(input);
if (inputString != null) {
throw new BuildException("The \"input\" and \"inputstring\" "
+ "attributes cannot both be specified");
}
this.input = input;
incompatibleWithSpawn = true; incompatibleWithSpawn = true;
} }


@@ -161,7 +173,11 @@ public class ExecTask extends Task {
* @param inputString the string which is used as the input source * @param inputString the string which is used as the input source
*/ */
public void setInputString(String inputString) { public void setInputString(String inputString) {
redirector.setInputString(inputString);
if (input != null) {
throw new BuildException("The \"input\" and \"inputstring\" "
+ "attributes cannot both be specified");
}
this.inputString = inputString;
incompatibleWithSpawn = true; incompatibleWithSpawn = true;
} }


@@ -185,7 +201,7 @@ public class ExecTask extends Task {
* @since ant 1.6 * @since ant 1.6
*/ */
public void setError(File error) { public void setError(File error) {
redirector.setError(error);
this.error = error;
incompatibleWithSpawn = true; incompatibleWithSpawn = true;
} }


@@ -325,6 +341,20 @@ public class ExecTask extends Task {
} }




/**
* Add a <CODE>RedirectorElement</CODE> to this task.
*
* @param redirectorElement <CODE>RedirectorElement</CODE>.
*/
public void addConfiguredRedirector(RedirectorElement redirectorElement) {
if (this.redirectorElement != null) {
throw new BuildException("cannot have > 1 nested <redirector>s");
} else {
this.redirectorElement = redirectorElement;
incompatibleWithSpawn = true;
}
}



/** /**
* Attempt to figure out where the executable is so that we can feed * Attempt to figure out where the executable is so that we can feed
@@ -431,10 +461,23 @@ public class ExecTask extends Task {
if (spawn && incompatibleWithSpawn) { if (spawn && incompatibleWithSpawn) {
getProject().log("spawn does not allow attributes related to input, " getProject().log("spawn does not allow attributes related to input, "
+ "output, error, result", Project.MSG_ERR); + "output, error, result", Project.MSG_ERR);
getProject().log("spawn does not also not allow timeout", Project.MSG_ERR);
throw new BuildException("You have used an attribute which is "
+ "not compatible with spawn");
getProject().log("spawn also does not allow timeout", Project.MSG_ERR);
getProject().log( "finally, spawn is not compatible "
+ "with a nested I/O <redirector>", Project.MSG_ERR);
throw new BuildException("You have used an attribute "
+ "or nested element which is not compatible with spawn");
} }
setupRedirector();
}

/**
* Set up properties on the redirector that we needed to store locally.
*/
protected void setupRedirector() {
redirector.setInput(input);
redirector.setInputString(inputString);
redirector.setOutput(output);
redirector.setError(error);
} }


/** /**
@@ -485,6 +528,9 @@ public class ExecTask extends Task {
if (dir == null) { if (dir == null) {
dir = getProject().getBaseDir(); dir = getProject().getBaseDir();
} }
if (redirectorElement != null) {
redirectorElement.configure(redirector);
}
Execute exe = new Execute(createHandler(), createWatchdog()); Execute exe = new Execute(createHandler(), createWatchdog());
exe.setAntRun(getProject()); exe.setAntRun(getProject());
exe.setWorkingDirectory(dir); exe.setWorkingDirectory(dir);
@@ -527,6 +573,7 @@ public class ExecTask extends Task {
} }
} }
maybeSetResultPropertyValue(returnCode); maybeSetResultPropertyValue(returnCode);
redirector.complete();
if (Execute.isFailure(returnCode)) { if (Execute.isFailure(returnCode)) {
if (failOnError) { if (failOnError) {
throw new BuildException(getTaskType() + " returned: " throw new BuildException(getTaskType() + " returned: "
@@ -535,7 +582,6 @@ public class ExecTask extends Task {
log("Result: " + returnCode, Project.MSG_ERR); log("Result: " + returnCode, Project.MSG_ERR);
} }
} }
redirector.complete();
} else { } else {
exe.spawn(); exe.spawn();
} }


+ 43
- 10
src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2000-2004 The Apache Software Foundation
* Copyright 2000-2004 The Apache Software Foundation.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -238,6 +238,17 @@ public class ExecuteOn extends ExecTask {
} }
} }


protected ExecuteStreamHandler createHandler() throws BuildException {
//if we have a RedirectorElement, return a decoy
return (redirectorElement == null)
? super.createHandler() : new PumpStreamHandler();
}

protected void setupRedirector() {
super.setupRedirector();
redirector.setAppendProperties(true);
}

protected void runExec(Execute exe) throws BuildException { protected void runExec(Execute exe) throws BuildException {
int totalFiles = 0; int totalFiles = 0;
int totalDirs = 0; int totalDirs = 0;
@@ -293,10 +304,17 @@ public class ExecuteOn extends ExecTask {
log(Commandline.describeCommand(command), log(Commandline.describeCommand(command),
Project.MSG_VERBOSE); Project.MSG_VERBOSE);
exe.setCommandline(command); exe.setCommandline(command);
if (haveExecuted) {

if (redirectorElement != null) {
setupRedirector();
redirectorElement.configure(redirector, s[j]);
}

if (redirectorElement != null || haveExecuted) {
// need to reset the stream handler to restart // need to reset the stream handler to restart
// reading of pipes
exe.setStreamHandler(createHandler());
// reading of pipes;
// go ahead and do it always w/ nested redirectors
exe.setStreamHandler(redirector.createHandler());
} }
runExecute(exe); runExecute(exe);
haveExecuted = true; haveExecuted = true;
@@ -341,10 +359,17 @@ public class ExecuteOn extends ExecTask {
log(Commandline.describeCommand(command), log(Commandline.describeCommand(command),
Project.MSG_VERBOSE); Project.MSG_VERBOSE);
exe.setCommandline(command); exe.setCommandline(command);
if (haveExecuted) {

if (redirectorElement != null) {
setupRedirector();
redirectorElement.configure(redirector, s[j]);
}

if (redirectorElement != null || haveExecuted) {
// need to reset the stream handler to restart // need to reset the stream handler to restart
// reading of pipes
exe.setStreamHandler(createHandler());
// reading of pipes;
// go ahead and do it always w/ nested redirectors
exe.setStreamHandler(redirector.createHandler());
} }
runExecute(exe); runExecute(exe);
haveExecuted = true; haveExecuted = true;
@@ -373,6 +398,8 @@ public class ExecuteOn extends ExecTask {
} finally { } finally {
// close the output file if required // close the output file if required
logFlush(); logFlush();
redirector.setAppendProperties(false);
redirector.setProperties();
} }
} }


@@ -582,10 +609,16 @@ public class ExecuteOn extends ExecTask {
String[] command = getCommandline(cs, cb); String[] command = getCommandline(cs, cb);
log(Commandline.describeCommand(command), Project.MSG_VERBOSE); log(Commandline.describeCommand(command), Project.MSG_VERBOSE);
exe.setCommandline(command); exe.setCommandline(command);
if (currentOffset > 0) {
if (redirectorElement != null) {
setupRedirector();
redirectorElement.configure(redirector, null);
}

if (redirectorElement != null || currentOffset > 0) {
// need to reset the stream handler to restart // need to reset the stream handler to restart
// reading of pipes
exe.setStreamHandler(createHandler());
// reading of pipes;
// go ahead and do it always w/ nested redirectors
exe.setStreamHandler(redirector.createHandler());
} }
runExecute(exe); runExecute(exe);




+ 55
- 8
src/main/org/apache/tools/ant/taskdefs/Java.java View File

@@ -34,6 +34,7 @@ import org.apache.tools.ant.types.PropertySet;
import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.types.Assertions; import org.apache.tools.ant.types.Assertions;
import org.apache.tools.ant.types.Permissions; import org.apache.tools.ant.types.Permissions;
import org.apache.tools.ant.types.RedirectorElement;


/** /**
* Launcher for Java applications. Allows use of * Launcher for Java applications. Allows use of
@@ -53,7 +54,16 @@ public class Java extends Task {
private File dir = null; private File dir = null;
private boolean failOnError = false; private boolean failOnError = false;
private Long timeout = null; private Long timeout = null;
private Redirector redirector = new Redirector(this);

//include locally for screening purposes
private String inputString;
private File input;
private File output;
private File error;
protected Redirector redirector = new Redirector(this);
protected RedirectorElement redirectorElement;
private String resultProperty; private String resultProperty;
private Permissions perm = null; private Permissions perm = null;


@@ -110,9 +120,11 @@ public class Java extends Task {
if (spawn && incompatibleWithSpawn) { if (spawn && incompatibleWithSpawn) {
getProject().log("spawn does not allow attributes related to input, " getProject().log("spawn does not allow attributes related to input, "
+ "output, error, result", Project.MSG_ERR); + "output, error, result", Project.MSG_ERR);
getProject().log("spawn does not also not allow timeout", Project.MSG_ERR);
throw new BuildException("You have used an attribute which is "
+ "not compatible with spawn");
getProject().log("spawn also does not allow timeout", Project.MSG_ERR);
getProject().log( "finally, spawn is not compatible "
+ "with a nested I/O <redirector>", Project.MSG_ERR);
throw new BuildException("You have used an attribute "
+ "or nested element which is not compatible with spawn");
} }
if (cmdl.getAssertions() != null && !fork) { if (cmdl.getAssertions() != null && !fork) {
log("Assertion statements are currently ignored in non-forked mode"); log("Assertion statements are currently ignored in non-forked mode");
@@ -151,6 +163,7 @@ public class Java extends Task {
Project.MSG_VERBOSE); Project.MSG_VERBOSE);
} }


setupRedirector();
try { try {
if (fork) { if (fork) {
if (!spawn) { if (!spawn) {
@@ -419,7 +432,7 @@ public class Java extends Task {
* @param out name of the output file * @param out name of the output file
*/ */
public void setOutput(File out) { public void setOutput(File out) {
redirector.setOutput(out);
this.output = out;
incompatibleWithSpawn = true; incompatibleWithSpawn = true;
} }


@@ -429,7 +442,11 @@ public class Java extends Task {
* @param input name of the input file * @param input name of the input file
*/ */
public void setInput(File input) { public void setInput(File input) {
redirector.setInput(input);
if (inputString != null) {
throw new BuildException("The \"input\" and \"inputstring\" "
+ "attributes cannot both be specified");
}
this.input = input;
incompatibleWithSpawn = true; incompatibleWithSpawn = true;
} }


@@ -439,7 +456,11 @@ public class Java extends Task {
* @param inputString the string which is used as the input source * @param inputString the string which is used as the input source
*/ */
public void setInputString(String inputString) { public void setInputString(String inputString) {
redirector.setInputString(inputString);
if (input != null) {
throw new BuildException("The \"input\" and \"inputstring\" "
+ "attributes cannot both be specified");
}
this.inputString = inputString;
incompatibleWithSpawn = true; incompatibleWithSpawn = true;
} }


@@ -464,7 +485,7 @@ public class Java extends Task {
* @since ant 1.6 * @since ant 1.6
*/ */
public void setError(File error) { public void setError(File error) {
redirector.setError(error);
this.error = error;
incompatibleWithSpawn = true; incompatibleWithSpawn = true;
} }


@@ -572,6 +593,19 @@ public class Java extends Task {
cmdl.setAssertions(asserts); cmdl.setAssertions(asserts);
} }


/**
* Add a <CODE>RedirectorElement</CODE> to this task.
* @param redirectorElement <CODE>RedirectorElement</CODE>.
*/
public void addConfiguredRedirector(RedirectorElement redirectorElement) {
if (this.redirectorElement != null) {
throw new BuildException("cannot have > 1 nested <redirector>s");
} else {
this.redirectorElement = redirectorElement;
incompatibleWithSpawn = true;
}
}

/** /**
* Pass output sent to System.out to specified output file. * Pass output sent to System.out to specified output file.
* *
@@ -653,6 +687,19 @@ public class Java extends Task {
} }
} }


/**
* Set up properties on the redirector that we needed to store locally.
*/
protected void setupRedirector() {
redirector.setInput(input);
redirector.setInputString(inputString);
redirector.setOutput(output);
redirector.setError(error);
if (redirectorElement != null) {
redirectorElement.configure(redirector);
}
}

/** /**
* Executes the given classname with the given arguments as it * Executes the given classname with the given arguments as it
* was a command line application. * was a command line application.


+ 413
- 80
src/main/org/apache/tools/ant/taskdefs/Redirector.java View File

@@ -16,23 +16,37 @@
*/ */
package org.apache.tools.ant.taskdefs; package org.apache.tools.ant.taskdefs;


import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.InputStream; import java.io.InputStream;
import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.PipedInputStream;
import java.io.InputStreamReader;
import java.io.PipedOutputStream;
import java.io.OutputStreamWriter;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Vector;
import org.apache.tools.ant.Task; import org.apache.tools.ant.Task;
import org.apache.tools.ant.util.LazyFileOutputStream;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.filters.util.ChainReaderHelper;
import org.apache.tools.ant.util.StringUtils; import org.apache.tools.ant.util.StringUtils;
import org.apache.tools.ant.util.TeeOutputStream; import org.apache.tools.ant.util.TeeOutputStream;
import org.apache.tools.ant.util.ReaderInputStream;
import org.apache.tools.ant.util.LeadPipeInputStream;
import org.apache.tools.ant.util.LazyFileOutputStream;
import org.apache.tools.ant.util.OutputStreamFunneler;
import org.apache.tools.ant.util.ConcatFileInputStream;
import org.apache.tools.ant.util.KeepAliveOutputStream;


/** /**
* The Redirector class manages the setup and connection of * The Redirector class manages the setup and connection of
@@ -41,21 +55,43 @@ import org.apache.tools.ant.util.TeeOutputStream;
* @since Ant 1.6 * @since Ant 1.6
*/ */
public class Redirector { public class Redirector {

private static final String defaultEncoding
= System.getProperty("file.encoding");

private class PropertyOutputStream extends ByteArrayOutputStream {
String property;
boolean closed = false;

PropertyOutputStream(String property) {
super();
this.property = property;
}

public void close() throws IOException {
if (!closed && !(append && appendProperties)) {
setPropertyFromBAOS(this, property);
closed = true;
}
}
}

/** /**
* The file receiving standard output. Will also receive standard error
* unless standard error is redirected or logError is true.
* The file(s) from which standard input is being taken.
* If > 1, files' content will be concatenated in the order received.
*/ */
private File out;
private File[] input;


/** /**
* The file to which standard error is being redirected
* The file(s) receiving standard output. Will also receive standard error
* unless standard error is redirected or logError is true.
*/ */
private File error;
private File[] out;


/** /**
* The file from which standard input is being taken.
* The file(s) to which standard error is being redirected
*/ */
private File input;
private File[] error;


/** /**
* Indicates if standard error should be logged to Ant's log system * Indicates if standard error should be logged to Ant's log system
@@ -67,12 +103,12 @@ public class Redirector {
/** /**
* Buffer used to capture output for storage into a property * Buffer used to capture output for storage into a property
*/ */
private ByteArrayOutputStream baos = null;
private PropertyOutputStream baos = null;


/** /**
* Buffer used to capture error output for storage into a property * Buffer used to capture error output for storage into a property
*/ */
private ByteArrayOutputStream errorBaos = null;
private PropertyOutputStream errorBaos = null;


/** The name of the property into which output is to be stored */ /** The name of the property into which output is to be stored */
private String outputProperty; private String outputProperty;
@@ -86,6 +122,9 @@ public class Redirector {
/** Flag which indicates if error and output files are to be appended. */ /** Flag which indicates if error and output files are to be appended. */
private boolean append = false; private boolean append = false;


/** Flag which indicates whether files should be created even when empty. */
private boolean createEmptyFiles = true;

/** The task for which this redirector is working */ /** The task for which this redirector is working */
private Task managingTask; private Task managingTask;


@@ -104,6 +143,30 @@ public class Redirector {
/** Stream which is used for line oriented error output */ /** Stream which is used for line oriented error output */
private PrintStream errorPrintStream = null; private PrintStream errorPrintStream = null;


/** The output filter chains */
private Vector outputFilterChains;

/** The error filter chains */
private Vector errorFilterChains;

/** The input filter chains */
private Vector inputFilterChains;

/** The output encoding */
private String outputEncoding = defaultEncoding;

/** The error encoding */
private String errorEncoding = defaultEncoding;

/** The input encoding */
private String inputEncoding = defaultEncoding;

/** Whether to complete properties settings **/
private boolean appendProperties = true;

/** The thread group used for starting <code>StreamPumper</code> threads */
private ThreadGroup threadGroup = new ThreadGroup("redirector");

/** /**
* Create a redirector instance for the given task * Create a redirector instance for the given task
* *
@@ -119,6 +182,15 @@ public class Redirector {
* @param input the file from which input is read. * @param input the file from which input is read.
*/ */
public void setInput(File input) { public void setInput(File input) {
setInput((input == null) ? null : new File[] {input});
}

/**
* Set the input to use for the task
*
* @param input the files from which input is read.
*/
public synchronized void setInput(File[] input) {
this.input = input; this.input = input;
} }


@@ -127,7 +199,7 @@ public class Redirector {
* *
* @param inputString the string which is used as the input source * @param inputString the string which is used as the input source
*/ */
public void setInputString(String inputString) {
public synchronized void setInputString(String inputString) {
this.inputString = inputString; this.inputString = inputString;
} }


@@ -139,9 +211,61 @@ public class Redirector {
* @param out the file to which output stream is written * @param out the file to which output stream is written
*/ */
public void setOutput(File out) { public void setOutput(File out) {
setOutput((out == null) ? null : new File[] {out});
}

/**
* Files the output of the process is redirected to. If error is not
* redirected, it too will appear in the output
*
* @param out the files to which output stream is written
*/
public synchronized void setOutput(File[] out) {
this.out = out; this.out = out;
} }


/**
* Set the output encoding.
*
* @param outputEncoding <CODE>String</CODE>.
*/
public synchronized void setOutputEncoding(String outputEncoding) {
if (outputEncoding == null) {
throw new IllegalArgumentException(
"outputEncoding must not be null");
} else {
this.outputEncoding = outputEncoding;
}
}

/**
* Set the error encoding.
*
* @param errorEncoding <CODE>String</CODE>.
*/
public synchronized void setErrorEncoding(String errorEncoding) {
if (errorEncoding == null) {
throw new IllegalArgumentException(
"errorEncoding must not be null");
} else {
this.errorEncoding = errorEncoding;
}
}

/**
* Set the input encoding.
*
* @param inputEncoding <CODE>String</CODE>.
*/
public synchronized void setInputEncoding(String inputEncoding) {
if (inputEncoding == null) {
throw new IllegalArgumentException(
"inputEncoding must not be null");
} else {
this.inputEncoding = inputEncoding;
}
}

/** /**
* Controls whether error output of exec is logged. This is only useful * Controls whether error output of exec is logged. This is only useful
* when output is being redirected and error output is desired in the * when output is being redirected and error output is desired in the
@@ -150,16 +274,36 @@ public class Redirector {
* @param logError if true the standard error is sent to the Ant log system * @param logError if true the standard error is sent to the Ant log system
* and not sent to output. * and not sent to output.
*/ */
public void setLogError(boolean logError) {
public synchronized void setLogError(boolean logError) {
this.logError = logError; this.logError = logError;
} }


/**
* This <CODE>Redirector</CODE>'s subordinate
* <CODE>PropertyOutputStream</CODE>s will not set their respective
* properties <CODE>while (appendProperties && append)</CODE>.
*
* @param appendProperties whether to append properties.
*/
public synchronized void setAppendProperties(boolean appendProperties) {
this.appendProperties = appendProperties;
}

/** /**
* Set the file to which standard error is to be redirected. * Set the file to which standard error is to be redirected.
* *
* @param error the file to which error is to be written * @param error the file to which error is to be written
*/ */
public void setError(File error) { public void setError(File error) {
setError((error == null) ? null : new File[] {error});
}

/**
* Set the files to which standard error is to be redirected.
*
* @param error the file to which error is to be written
*/
public synchronized void setError(File[] error) {
this.error = error; this.error = error;
} }


@@ -170,8 +314,12 @@ public class Redirector {
* @param outputProperty the name of the property to be set with the * @param outputProperty the name of the property to be set with the
* task's output. * task's output.
*/ */
public void setOutputProperty(String outputProperty) {
this.outputProperty = outputProperty;
public synchronized void setOutputProperty(String outputProperty) {
if (outputProperty == null
|| !(outputProperty.equals(this.outputProperty))) {
this.outputProperty = outputProperty;
baos = null;
}
} }


/** /**
@@ -181,10 +329,19 @@ public class Redirector {
* @param append if true output and error streams are appended to their * @param append if true output and error streams are appended to their
* respective files, if specified. * respective files, if specified.
*/ */
public void setAppend(boolean append) {
public synchronized void setAppend(boolean append) {
this.append = append; this.append = append;
} }


/**
* Whether output and error files should be created even when empty.
* Defaults to true.
* @param createEmptyFiles <CODE>boolean</CODE>.
*/
public void setCreateEmptyFiles(boolean createEmptyFiles) {
this.createEmptyFiles = createEmptyFiles;
}

/** /**
* Property name whose value should be set to the error of * Property name whose value should be set to the error of
* the process. * the process.
@@ -192,8 +349,39 @@ public class Redirector {
* @param errorProperty the name of the property to be set * @param errorProperty the name of the property to be set
* with the error output. * with the error output.
*/ */
public void setErrorProperty(String errorProperty) {
this.errorProperty = errorProperty;
public synchronized void setErrorProperty(String errorProperty) {
if (errorProperty == null
|| !(errorProperty.equals(this.errorProperty))) {
this.errorProperty = errorProperty;
errorBaos = null;
}
}

/**
* Set the input <CODE>FilterChain</CODE>s.
*
* @param <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>.
*/
public synchronized void setInputFilterChains(Vector inputFilterChains) {
this.inputFilterChains = inputFilterChains;
}

/**
* Set the output <CODE>FilterChain</CODE>s.
*
* @param <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>.
*/
public void setOutputFilterChains(Vector outputFilterChains) {
this.outputFilterChains = outputFilterChains;
}

/**
* Set the error <CODE>FilterChain</CODE>s.
*
* @param <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>.
*/
public void setErrorFilterChains(Vector errorFilterChains) {
this.errorFilterChains = errorFilterChains;
} }


/** /**
@@ -207,8 +395,8 @@ public class Redirector {
private void setPropertyFromBAOS(ByteArrayOutputStream baos, private void setPropertyFromBAOS(ByteArrayOutputStream baos,
String propertyName) throws IOException { String propertyName) throws IOException {


BufferedReader in =
new BufferedReader(new StringReader(Execute.toString(baos)));
BufferedReader in
= new BufferedReader(new StringReader(Execute.toString(baos)));
String line = null; String line = null;
StringBuffer val = new StringBuffer(); StringBuffer val = new StringBuffer();
while ((line = in.readLine()) != null) { while ((line = in.readLine()) != null) {
@@ -220,30 +408,34 @@ public class Redirector {
managingTask.getProject().setNewProperty(propertyName, val.toString()); managingTask.getProject().setNewProperty(propertyName, val.toString());
} }



/** /**
* Create the input, error and output streams based on the * Create the input, error and output streams based on the
* configuration options. * configuration options.
*/ */
public void createStreams() {
if (out == null && outputProperty == null) {
public synchronized void createStreams() {
if ((out == null || out.length == 0) && outputProperty == null) {
outputStream = new LogOutputStream(managingTask, Project.MSG_INFO); outputStream = new LogOutputStream(managingTask, Project.MSG_INFO);
errorStream = new LogOutputStream(managingTask, Project.MSG_WARN);
} else { } else {
if (out != null) {
outputStream = new LazyFileOutputStream(out, append, true);
managingTask.log("Output redirected to " + out,
Project.MSG_VERBOSE);
if (out != null && out.length > 0) {
String logHead = new StringBuffer("Output ").append(
((append) ? "appended" : "redirected")).append(
" to ").toString();
outputStream = foldFiles(out, logHead, Project.MSG_VERBOSE);
} }


if (outputProperty != null) { if (outputProperty != null) {
baos = new ByteArrayOutputStream();
managingTask.log("Output redirected to property: "
+ outputProperty, Project.MSG_VERBOSE);
if (out == null) {
outputStream = baos;
if (baos == null) {
baos = new PropertyOutputStream(outputProperty);
managingTask.log("Output redirected to property: "
+ outputProperty, Project.MSG_VERBOSE);
}
//shield it from being closed by a filtering StreamPumper
OutputStream keepAliveOutput = new KeepAliveOutputStream(baos);
if (outputStream == null) {
outputStream = keepAliveOutput;
} else { } else {
outputStream = new TeeOutputStream(outputStream, baos);
outputStream
= new TeeOutputStream(outputStream, keepAliveOutput);
} }
} else { } else {
baos = null; baos = null;
@@ -252,44 +444,132 @@ public class Redirector {
errorStream = outputStream; errorStream = outputStream;
} }


if (logError) {
errorStream = new LogOutputStream(managingTask, Project.MSG_WARN);
}
if (error != null && error.length > 0) {
String logHead = new StringBuffer("Error ").append(
((append) ? "appended" : "redirected")).append(
" to ").toString();
errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE);


if (error != null) {
errorStream = new LazyFileOutputStream(error, append, true);
managingTask.log("Error redirected to " + error,
Project.MSG_VERBOSE);
} else if (logError || errorStream == null) {
errorStream = new LogOutputStream(managingTask, Project.MSG_WARN);
} else { //must be errorStream == outputStream
long funnelTimeout = 0L;
OutputStreamFunneler funneler
= new OutputStreamFunneler(outputStream, funnelTimeout);
try {
outputStream = funneler.getFunnelInstance();
errorStream = funneler.getFunnelInstance();
} catch (IOException eyeOhEx) {
throw new BuildException(
"error splitting output/error streams", eyeOhEx);
}
} }


if (errorProperty != null) { if (errorProperty != null) {
errorBaos = new ByteArrayOutputStream();
managingTask.log("Error redirected to property: " + errorProperty,
Project.MSG_VERBOSE);
if (error == null) {
errorStream = errorBaos;
} else {
errorStream = new TeeOutputStream(errorStream, errorBaos);
if (errorBaos == null) {
errorBaos = new PropertyOutputStream(errorProperty);
managingTask.log("Error redirected to property: " + errorProperty,
Project.MSG_VERBOSE);
} }
//shield it from being closed by a filtering StreamPumper
OutputStream keepAliveError = new KeepAliveOutputStream(errorBaos);
errorStream = (error == null || error.length == 0) ? keepAliveError
: new TeeOutputStream(errorStream, keepAliveError);
} else { } else {
errorBaos = null; errorBaos = null;
} }


if (input != null && inputString != null) {
throw new BuildException("The \"input\" and \"inputstring\" "
+ "attributes cannot both be specified");
if ((outputFilterChains != null && outputFilterChains.size() > 0)
|| !(outputEncoding.equalsIgnoreCase(inputEncoding))) {
try {
LeadPipeInputStream snk = new LeadPipeInputStream();
snk.setManagingTask(managingTask);
InputStream outPumpIn = snk;

Reader reader = new InputStreamReader(outPumpIn, inputEncoding);

if (outputFilterChains != null && outputFilterChains.size() > 0) {
ChainReaderHelper helper = new ChainReaderHelper();
helper.setPrimaryReader(reader);
helper.setFilterChains(outputFilterChains);
reader = helper.getAssembledReader();
}
outPumpIn = new ReaderInputStream(reader, outputEncoding);

Thread t = new Thread(threadGroup, new StreamPumper(
outPumpIn, outputStream, true), "output pumper");
t.setPriority(Thread.MAX_PRIORITY);
outputStream = new PipedOutputStream(snk);
t.start();
} catch (IOException eyeOhEx) {
throw new BuildException(
"error setting up output stream", eyeOhEx);
}
} }
if (input != null) {

if ((errorFilterChains != null && errorFilterChains.size() > 0)
|| !(errorEncoding.equalsIgnoreCase(inputEncoding))) {
try { try {
inputStream = new FileInputStream(input);
} catch (FileNotFoundException fne) {
throw new BuildException("Cannot read from " + input, fne);
LeadPipeInputStream snk = new LeadPipeInputStream();
snk.setManagingTask(managingTask);
InputStream errPumpIn = snk;

Reader reader = new InputStreamReader(errPumpIn, inputEncoding);

if (errorFilterChains != null && errorFilterChains.size() > 0) {
ChainReaderHelper helper = new ChainReaderHelper();
helper.setPrimaryReader(reader);
helper.setFilterChains(errorFilterChains);
reader = helper.getAssembledReader();
}
errPumpIn = new ReaderInputStream(reader, errorEncoding);

Thread t = new Thread(threadGroup, new StreamPumper(
errPumpIn, errorStream, true), "error pumper");
t.setPriority(Thread.MAX_PRIORITY);
errorStream = new PipedOutputStream(snk);
t.start();
} catch (IOException eyeOhEx) {
throw new BuildException(
"error setting up error stream", eyeOhEx);
} }
}

// if input files are specified, inputString is ignored;
// classes that work with redirector attributes can enforce
// whatever warnings are needed
if (input != null && input.length > 0) {
managingTask.log("Redirecting input from file"
+ ((input.length == 1) ? "" : "s"), Project.MSG_VERBOSE);
try {
inputStream = new ConcatFileInputStream(input);
} catch (IOException eyeOhEx) {
throw new BuildException(eyeOhEx);
}
((ConcatFileInputStream)inputStream).setManagingTask(managingTask);
} else if (inputString != null) { } else if (inputString != null) {
managingTask.log("Using input \"" + inputString + "\"",
Project.MSG_VERBOSE);
inputStream = new ByteArrayInputStream(inputString.getBytes()); inputStream = new ByteArrayInputStream(inputString.getBytes());
} }
}


if (inputStream != null
&& inputFilterChains != null && inputFilterChains.size() > 0) {
ChainReaderHelper helper = new ChainReaderHelper();
try {
helper.setPrimaryReader(
new InputStreamReader(inputStream, inputEncoding));
} catch (IOException eyeOhEx) {
throw new BuildException(
"error setting up input stream", eyeOhEx);
}
helper.setFilterChains(inputFilterChains);
inputStream = new ReaderInputStream(
helper.getAssembledReader(), inputEncoding);
}
}


/** /**
* Create the StreamHandler to use with our Execute instance. * Create the StreamHandler to use with our Execute instance.
@@ -299,7 +579,8 @@ public class Redirector {
* *
* @throws BuildException if the execute stream handler cannot be created. * @throws BuildException if the execute stream handler cannot be created.
*/ */
public ExecuteStreamHandler createHandler() throws BuildException {
public synchronized ExecuteStreamHandler createHandler()
throws BuildException {
createStreams(); createStreams();
return new PumpStreamHandler(outputStream, errorStream, inputStream); return new PumpStreamHandler(outputStream, errorStream, inputStream);
} }
@@ -309,7 +590,7 @@ public class Redirector {
* *
* @param output the data to be output * @param output the data to be output
*/ */
protected void handleOutput(String output) {
protected synchronized void handleOutput(String output) {
if (outPrintStream == null) { if (outPrintStream == null) {
outPrintStream = new PrintStream(outputStream); outPrintStream = new PrintStream(outputStream);
} }
@@ -327,8 +608,8 @@ public class Redirector {
* *
* @exception IOException if the data cannot be read * @exception IOException if the data cannot be read
*/ */
protected int handleInput(byte[] buffer, int offset, int length)
throws IOException {
protected synchronized int handleInput(byte[] buffer, int offset,
int length) throws IOException {
if (inputStream == null) { if (inputStream == null) {
return managingTask.getProject().defaultInput(buffer, offset, return managingTask.getProject().defaultInput(buffer, offset,
length); length);
@@ -342,7 +623,7 @@ public class Redirector {
* *
* @param output the data being flushed. * @param output the data being flushed.
*/ */
protected void handleFlush(String output) {
protected synchronized void handleFlush(String output) {
if (outPrintStream == null) { if (outPrintStream == null) {
outPrintStream = new PrintStream(outputStream); outPrintStream = new PrintStream(outputStream);
} }
@@ -355,7 +636,7 @@ public class Redirector {
* *
* @param output the error output data. * @param output the error output data.
*/ */
protected void handleErrorOutput(String output) {
protected synchronized void handleErrorOutput(String output) {
if (errorPrintStream == null) { if (errorPrintStream == null) {
errorPrintStream = new PrintStream(errorStream); errorPrintStream = new PrintStream(errorStream);
} }
@@ -367,7 +648,7 @@ public class Redirector {
* *
* @param output the error information being flushed. * @param output the error information being flushed.
*/ */
protected void handleErrorFlush(String output) {
protected synchronized void handleErrorFlush(String output) {
if (errorPrintStream == null) { if (errorPrintStream == null) {
errorPrintStream = new PrintStream(errorStream); errorPrintStream = new PrintStream(errorStream);
} }
@@ -380,7 +661,7 @@ public class Redirector {
* @return the redirector's output stream or null if no output * @return the redirector's output stream or null if no output
* has been configured * has been configured
*/ */
public OutputStream getOutputStream() {
public synchronized OutputStream getOutputStream() {
return outputStream; return outputStream;
} }


@@ -390,7 +671,7 @@ public class Redirector {
* @return the redirector's error stream or null if no output * @return the redirector's error stream or null if no output
* has been configured * has been configured
*/ */
public OutputStream getErrorStream() {
public synchronized OutputStream getErrorStream() {
return errorStream; return errorStream;
} }


@@ -400,7 +681,7 @@ public class Redirector {
* @return the redirector's input stream or null if no output * @return the redirector's input stream or null if no output
* has been configured * has been configured
*/ */
public InputStream getInputStream() {
public synchronized InputStream getInputStream() {
return inputStream; return inputStream;
} }


@@ -413,7 +694,7 @@ public class Redirector {
* @throws IOException if the output properties cannot be read from their * @throws IOException if the output properties cannot be read from their
* output streams. * output streams.
*/ */
public void complete() throws IOException {
public synchronized void complete() throws IOException {
System.out.flush(); System.out.flush();
System.err.flush(); System.err.flush();


@@ -421,17 +702,69 @@ public class Redirector {
inputStream.close(); inputStream.close();
} }


outputStream.flush();
outputStream.close(); outputStream.close();


if (errorStream != outputStream) {
errorStream.close();
errorStream.flush();
errorStream.close();

//wait for the StreamPumpers to finish
while (threadGroup.activeCount() > 0) {
try {
managingTask.log("waiting for " + threadGroup.activeCount()
+ " Threads:", Project.MSG_DEBUG);
Thread[] thread = new Thread[threadGroup.activeCount()];
threadGroup.enumerate(thread);
for (int i = 0; i < thread.length && thread[i] != null; i++) {
try {
managingTask.log(thread[i].toString(), Project.MSG_DEBUG);
} catch (NullPointerException enPeaEx) {
}
}
Thread.sleep(1000);
} catch (InterruptedException eyeEx) {
}
} }


setProperties();

inputStream = null;
outputStream = errorStream = outPrintStream = errorPrintStream = null;
}

/**
* Notify the <CODE>Redirector</CODE> that it is now okay
* to set any output and/or error properties.
*/
public synchronized void setProperties() {
if (baos != null) { if (baos != null) {
setPropertyFromBAOS(baos, outputProperty);
try {
baos.close();
} catch (IOException eyeOhEx) {
}
} }
if (errorBaos != null) { if (errorBaos != null) {
setPropertyFromBAOS(errorBaos, errorProperty);
try {
errorBaos.close();
} catch (IOException eyeOhEx) {
}
}
}

private OutputStream foldFiles(File[] file, String logHead, int loglevel) {
OutputStream result
= new LazyFileOutputStream(file[0], append, createEmptyFiles);

managingTask.log(logHead + file[0], loglevel);
char[] c = new char[logHead.length()];
Arrays.fill(c, ' ');
String indent = new String(c);

for (int i = 1; i < file.length ; i++) {
outputStream = new TeeOutputStream(outputStream,
new LazyFileOutputStream(file[i], append, createEmptyFiles));
managingTask.log(indent + file[i], loglevel);
} }
return result;
} }
} }

+ 511
- 0
src/main/org/apache/tools/ant/types/RedirectorElement.java View File

@@ -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()]));
}

}

+ 120
- 0
src/main/org/apache/tools/ant/util/ConcatFileInputStream.java View File

@@ -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;
}
}
}


+ 95
- 0
src/main/org/apache/tools/ant/util/LeadPipeInputStream.java View File

@@ -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);
}
}
}
}


+ 175
- 0
src/main/org/apache/tools/ant/util/OutputStreamFunneler.java View File

@@ -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 &quot;funnel&quot;
* 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 &quot;funnel&quot; 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 &quot;funnel&quot; <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.");
}
}

}

+ 203
- 0
src/main/org/apache/tools/ant/util/ReaderInputStream.java View File

@@ -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;
}
}

+ 224
- 73
src/testcases/org/apache/tools/ant/taskdefs/ExecTaskTest.java View File

@@ -29,6 +29,7 @@ import java.util.GregorianCalendar;
import junit.framework.ComparisonFailure; import junit.framework.ComparisonFailure;


/** /**
* Unit test for the &lt;exec&gt; task.
*/ */
public class ExecTaskTest extends BuildFileTest { public class ExecTaskTest extends BuildFileTest {
private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/";
@@ -61,11 +62,12 @@ public class ExecTaskTest extends BuildFileTest {
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
} }
assertEquals(getProject().getProperty("ant.file") + " out"
assertEquals("unexpected log content",
getProject().getProperty("ant.file") + " out"
+ getProject().getProperty("ant.file") + " err", getLog()); + getProject().getProperty("ant.file") + " err", getLog());
} }


public void testRedirect1() {
public void testRedirect1() throws IOException {
executeTarget("redirect1"); executeTarget("redirect1");
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
@@ -73,55 +75,39 @@ public class ExecTaskTest extends BuildFileTest {
String expectedOut = getProject().getProperty("ant.file") + " out\n" String expectedOut = getProject().getProperty("ant.file") + " out\n"
+ getProject().getProperty("ant.file") + " err\n"; + getProject().getProperty("ant.file") + " err\n";


String actualOut = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
} catch (IOException eyeOhEx) {
}
assertEquals("unexpected output", expectedOut, actualOut);
assertEquals("unexpected output",
expectedOut, getFileString("redirect.out"));
} }


public void testRedirect2() {
public void testRedirect2() throws IOException {
executeTarget("redirect2"); executeTarget("redirect2");
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
} }
String expectedOut = getProject().getProperty("ant.file") + " out\n";
String expectedErr = getProject().getProperty("ant.file") + " err\n";


String actualOut = null;
String actualErr = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
actualErr = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.err")));
} catch (IOException eyeOhEx) {
}
assertEquals("unexpected output", expectedOut, actualOut);
assertEquals("unexpected error output", expectedErr, actualErr);
assertEquals("unexpected output",
getProject().getProperty("ant.file") + " out\n",
getFileString("redirect.out"));
assertEquals("unexpected error output",
getProject().getProperty("ant.file") + " err\n",
getFileString("redirect.err"));
} }


public void testRedirect3() {
public void testRedirect3() throws IOException {
executeTarget("redirect3"); executeTarget("redirect3");
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
} }
assertEquals(getProject().getProperty("ant.file") + " err", getLog());
assertEquals("unexpected log content",
getProject().getProperty("ant.file") + " err", getLog());
String expectedOut = getProject().getProperty("ant.file") + " out\n"; String expectedOut = getProject().getProperty("ant.file") + " out\n";


String actualOut = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
} catch (IOException eyeOhEx) {
}
assertEquals("unexpected output", expectedOut, actualOut);
assertEquals("unexpected output",
expectedOut, getFileString("redirect.out"));
assertPropertyEquals("redirect.out", expectedOut.trim()); assertPropertyEquals("redirect.out", expectedOut.trim());
} }


public void testRedirect4() {
public void testRedirect4() throws IOException {
executeTarget("redirect4"); executeTarget("redirect4");
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
@@ -129,72 +115,218 @@ public class ExecTaskTest extends BuildFileTest {
String expectedOut = getProject().getProperty("ant.file") + " out\n"; String expectedOut = getProject().getProperty("ant.file") + " out\n";
String expectedErr = getProject().getProperty("ant.file") + " err\n"; String expectedErr = getProject().getProperty("ant.file") + " err\n";


String actualOut = null;
String actualErr = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
actualErr = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.err")));
} catch (IOException eyeOhEx) {
}
assertEquals("unexpected output", expectedOut, actualOut);
assertEquals("unexpected output",
expectedOut, getFileString("redirect.out"));
assertPropertyEquals("redirect.out", expectedOut.trim()); assertPropertyEquals("redirect.out", expectedOut.trim());
assertEquals("unexpected error output", expectedErr, actualErr);
assertEquals("unexpected error output",
expectedErr, getFileString("redirect.err"));
assertPropertyEquals("redirect.err", expectedErr.trim()); assertPropertyEquals("redirect.err", expectedErr.trim());
} }


public void testRedirect5() {
public void testRedirect5() throws IOException {
testRedirect5or6("redirect5"); testRedirect5or6("redirect5");
} }


public void testRedirect6() {
public void testRedirect6() throws IOException {
testRedirect5or6("redirect6"); testRedirect5or6("redirect6");
} }


public void testRedirect5or6(String target) {
public void testRedirect5or6(String target) throws IOException {
executeTarget(target); executeTarget(target);
if (getProject().getProperty("wc.can.run") == null) { if (getProject().getProperty("wc.can.run") == null) {
return; return;
} }


String expectedOut = getProject().getProperty("ant.file") + " out\n";

String actualOut = null;
String actualErr = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
actualErr = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.err")));
} catch (IOException eyeOhEx) {
}
assertEquals("unexpected output", "3", actualOut.trim());
assertEquals(getProject().getProperty("redirect.out").trim(), "3");
assertEquals("unexpected error output", null, actualErr);
assertEquals("unexpected output", "3", getFileString("redirect.out").trim());
assertEquals("property redirect.out", "3",
getProject().getProperty("redirect.out").trim());
assertNull("unexpected error output", getFileString("redirect.err"));
assertPropertyEquals("redirect.err", ""); assertPropertyEquals("redirect.err", "");
} }


public void testRedirect7() {
public void testRedirect7() throws IOException {
executeTarget("redirect7"); executeTarget("redirect7");
if (getProject().getProperty("wc.can.run") == null) { if (getProject().getProperty("wc.can.run") == null) {
return; return;
} }


assertEquals("unexpected output", "3", getFileString("redirect.out").trim());
assertEquals("property redirect.out", "3",
getProject().getProperty("redirect.out").trim());
assertNull("unexpected error output", getFileString("redirect.err"));
}

public void testRedirector1() {
executeTarget("init");
if (getProject().getProperty("test.can.run") == null) {
return;
}
expectBuildException("redirector1", "cannot have > 1 nested <redirector>s");
}

public void testRedirector2() throws IOException {
executeTarget("redirector2");
if (getProject().getProperty("test.can.run") == null) {
return;
}

assertEquals("unexpected output",
getProject().getProperty("ant.file") + " out\n"
+ getProject().getProperty("ant.file") + " err\n",
getFileString("redirector.out"));
}

public void testRedirector3() throws IOException {
executeTarget("redirector3");
if (getProject().getProperty("test.can.run") == null) {
return;
}

assertEquals("unexpected output",
getProject().getProperty("ant.file") + " out\n",
getFileString("redirector.out"));
assertEquals("unexpected error output",
getProject().getProperty("ant.file") + " err\n",
getFileString("redirector.err"));
}

public void testRedirector4() throws IOException {
executeTarget("redirector4");
if (getProject().getProperty("test.can.run") == null) {
return;
}
String expectedOut = getProject().getProperty("ant.file") + " out\n";

assertEquals("unexpected log content",
getProject().getProperty("ant.file") + " err", getLog());
assertEquals("unexpected output", expectedOut,
getFileString("redirector.out"));
assertPropertyEquals("redirector.out", expectedOut.trim());
}

public void testRedirector5() throws IOException {
testRedirector5or6("redirector5");
}

public void testRedirector6() throws IOException {
testRedirector5or6("redirector6");
}

private void testRedirector5or6(String target) throws IOException {
executeTarget(target);
if (getProject().getProperty("test.can.run") == null) {
return;
}
String expectedOut = getProject().getProperty("ant.file") + " out\n";
String expectedErr = getProject().getProperty("ant.file") + " err\n";

assertEquals("unexpected output", expectedOut,
getFileString("redirector.out"));
assertPropertyEquals("redirector.out", expectedOut.trim());
assertEquals("unexpected error output", expectedErr,
getFileString("redirector.err"));
assertPropertyEquals("redirector.err", expectedErr.trim());
}

public void testRedirector7() throws IOException {
executeTarget("redirector7");
if (getProject().getProperty("test.can.run") == null) {
return;
}
String expectedOut = getProject().getProperty("ant.file") + " out\n"; String expectedOut = getProject().getProperty("ant.file") + " out\n";
String expectedErr = getProject().getProperty("ant.file") + " ERROR!!!\n";

assertEquals("unexpected output", expectedOut,
getFileString("redirector.out"));
assertPropertyEquals("redirector.out", expectedOut.trim());
assertEquals("unexpected error output", expectedErr,
getFileString("redirector.err"));
assertPropertyEquals("redirector.err", expectedErr.trim());
}

public void testRedirector8() throws IOException {
executeTarget("redirector8");
if (getProject().getProperty("wc.can.run") == null) {
return;
}

assertEquals("unexpected output", "3", getFileString("redirector.out").trim());
assertEquals("property redirector.out", "3",
getProject().getProperty("redirector.out").trim());
assertNull("unexpected error output", getFileString("redirector.err"));
assertPropertyEquals("redirector.err", "");
}

public void testRedirector9() throws IOException {
testRedirector9Thru12("redirector9");
}

public void testRedirector10() throws IOException {
testRedirector9Thru12("redirector10");
}

public void testRedirector11() throws IOException {
testRedirector9Thru12("redirector11");
}

public void testRedirector12() throws IOException {
testRedirector9Thru12("redirector12");
}

private void testRedirector9Thru12(String target) throws IOException {
executeTarget(target);
if (getProject().getProperty("cat.can.run") == null) {
return;
}
String expectedOut = "blah after blah";


String actualOut = null;
String actualErr = null;
assertEquals("unexpected output",
expectedOut, getFileString("redirector.out").trim());
assertPropertyEquals("redirector.out", expectedOut.trim());
assertNull("unexpected error output", getFileString("redirector.err"));
assertPropertyEquals("redirector.err", "");
}

public void testRedirector13() {
executeTarget("redirector13");
if (getProject().getProperty("test.can.run") == null) {
return;
}
String antfile = getProject().getProperty("ant.file");
try { try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
actualErr = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.err")));
} catch (IOException eyeOhEx) {
//no point in setting a message
assertEquals(antfile + " OUTPUT???" + antfile + " ERROR!!!", getLog());
} catch (ComparisonFailure cf) {
assertEquals("unexpected log content",
antfile + " ERROR!!!" + antfile + " OUTPUT???", getLog());
}
}

public void testRedirector14() {
executeTarget("redirector14");
if (getProject().getProperty("cat.can.run") == null) {
return;
}
assertEquals("unexpected log output", "blah after blah", getLog());
}

public void testRedirector15() throws IOException {
executeTarget("redirector15");
if (getProject().getProperty("cat.can.run") == null) {
return;
} }
assertEquals("unexpected output", "3", actualOut.trim());
assertEquals(getProject().getProperty("redirect.out").trim(), "3");
assertEquals("unexpected error output", null, actualErr);
assertTrue("error with transcoding",
FileUtils.newFileUtils().contentEquals(
getProject().resolveFile("expected/utf-8"),
getProject().resolveFile("redirector.out")));
}

public void testRedirector16() {
executeTarget("redirector16");
}

public void testRedirector17() {
executeTarget("redirector17");
} }


public void testspawn() { public void testspawn() {
@@ -256,7 +388,6 @@ public class ExecTaskTest extends BuildFileTest {
project.setProperty("logFile", logFile); project.setProperty("logFile", logFile);
} }



public void setTimeToWait(int timeToWait) { public void setTimeToWait(int timeToWait) {
this.timeToWait = timeToWait; this.timeToWait = timeToWait;
project.setProperty("timeToWait", Long.toString(timeToWait)); project.setProperty("timeToWait", Long.toString(timeToWait));
@@ -319,4 +450,24 @@ public class ExecTaskTest extends BuildFileTest {
public void messageLogged(BuildEvent event) { public void messageLogged(BuildEvent event) {
} }
} }

//borrowed from TokenFilterTest
private String getFileString(String filename) throws IOException {
String result = null;
FileReader reader = null;
try {
reader = new FileReader(getProject().resolveFile(filename));
result = FileUtils.newFileUtils().readFully(reader);
} catch (IOException eyeOhEx) {
} finally {
if (reader != null) {
try {
reader.close();
} catch (Throwable ignore) {
}
}
}
return result;
}

} }

+ 408
- 101
src/testcases/org/apache/tools/ant/taskdefs/ExecuteOnTest.java View File

@@ -17,23 +17,21 @@


package org.apache.tools.ant.taskdefs; package org.apache.tools.ant.taskdefs;


import org.apache.tools.ant.*;
import org.apache.tools.ant.BuildFileTest;
import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.FileUtils;


import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.GregorianCalendar;

import junit.framework.ComparisonFailure;


/** /**
* Unit test for the &lt;apply&gt; task.
*/ */
public class ExecuteOnTest extends BuildFileTest { public class ExecuteOnTest extends BuildFileTest {
private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/";
private static final String BUILD_FILE = BUILD_PATH + "apply.xml"; private static final String BUILD_FILE = BUILD_PATH + "apply.xml";
public ExecuteOnTest(String name) { public ExecuteOnTest(String name) {
super(name); super(name);
} }
@@ -62,29 +60,25 @@ public class ExecuteOnTest extends BuildFileTest {
int xerr = log.indexOf(x + " err"); int xerr = log.indexOf(x + " err");
int yerr = log.indexOf(y + " err"); int yerr = log.indexOf(y + " err");
int zerr = log.indexOf(z + " err"); int zerr = log.indexOf(z + " err");
assertFalse("xout < 0", xout < 0);
assertFalse("yout < 0", yout < 0);
assertFalse("zout < 0", zout < 0);
assertFalse("xerr < 0", xerr < 0);
assertFalse("yerr < 0", yerr < 0);
assertFalse("zerr < 0", zerr < 0);
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout); assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout); assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr); assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr); assertFalse("zerr < yerr", zerr < yerr);
} }


public void testRedirect1() {
public void testRedirect1() throws IOException {
executeTarget("redirect1"); executeTarget("redirect1");
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
} }
String actualOut = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
} catch (IOException eyeOhEx) {
}
String actualOut = getFileString("redirect.out");

File x = getProject().resolveFile("x"); File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y"); File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z"); File z = getProject().resolveFile("z");
@@ -94,32 +88,26 @@ public class ExecuteOnTest extends BuildFileTest {
int xerr = actualOut.indexOf(x + " err"); int xerr = actualOut.indexOf(x + " err");
int yerr = actualOut.indexOf(y + " err"); int yerr = actualOut.indexOf(y + " err");
int zerr = actualOut.indexOf(z + " err"); int zerr = actualOut.indexOf(z + " err");
assertFalse("xout < 0", xout < 0);
assertFalse("yout < 0", yout < 0);
assertFalse("zout < 0", zout < 0);
assertFalse("xerr < 0", xerr < 0);
assertFalse("yerr < 0", yerr < 0);
assertFalse("zerr < 0", zerr < 0);
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout); assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout); assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr); assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr); assertFalse("zerr < yerr", zerr < yerr);
} }


public void testRedirect2() {
public void testRedirect2() throws IOException {
executeTarget("redirect2"); executeTarget("redirect2");
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
} }
String actualOut = null;
String actualErr = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
actualErr = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.err")));
} catch (IOException eyeOhEx) {
}
String actualOut = getFileString("redirect.out");
String actualErr = getFileString("redirect.err");

File x = getProject().resolveFile("x"); File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y"); File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z"); File z = getProject().resolveFile("z");
@@ -129,29 +117,25 @@ public class ExecuteOnTest extends BuildFileTest {
int xerr = actualErr.indexOf(x + " err"); int xerr = actualErr.indexOf(x + " err");
int yerr = actualErr.indexOf(y + " err"); int yerr = actualErr.indexOf(y + " err");
int zerr = actualErr.indexOf(z + " err"); int zerr = actualErr.indexOf(z + " err");
assertFalse("xout < 0", xout < 0);
assertFalse("yout < 0", yout < 0);
assertFalse("zout < 0", zout < 0);
assertFalse("xerr < 0", xerr < 0);
assertFalse("yerr < 0", yerr < 0);
assertFalse("zerr < 0", zerr < 0);
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout); assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout); assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr); assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr); assertFalse("zerr < yerr", zerr < yerr);
} }


public void testRedirect3() {
public void testRedirect3() throws IOException {
executeTarget("redirect3"); executeTarget("redirect3");
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
} }
String actualOut = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
} catch (IOException eyeOhEx) {
}
String actualOut = getFileString("redirect.out");

File x = getProject().resolveFile("x"); File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y"); File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z"); File z = getProject().resolveFile("z");
@@ -161,33 +145,36 @@ public class ExecuteOnTest extends BuildFileTest {
int xerr = getLog().indexOf(x + " err"); int xerr = getLog().indexOf(x + " err");
int yerr = getLog().indexOf(y + " err"); int yerr = getLog().indexOf(y + " err");
int zerr = getLog().indexOf(z + " err"); int zerr = getLog().indexOf(z + " err");
assertFalse("xout < 0", xout < 0);
assertFalse("yout < 0", yout < 0);
assertFalse("zout < 0", zout < 0);
assertFalse("xerr < 0", xerr < 0);
assertFalse("yerr < 0", yerr < 0);
assertFalse("zerr < 0", zerr < 0);
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout); assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout); assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr); assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr); assertFalse("zerr < yerr", zerr < yerr);
assertPropertyEquals("redirect.out", x + " out");

String outProperty = getProject().getProperty("redirect.out");
int pxout = outProperty.indexOf(x + " out");
int pyout = outProperty.indexOf(y + " out");
int pzout = outProperty.indexOf(z + " out");
assertFalse("pxout=" + pxout, pxout < 0);
assertFalse("pyout=" + pyout, pyout < 0);
assertFalse("pzout=" + pzout, pzout < 0);
assertFalse("pyout < pxout", pyout < pxout);
assertFalse("pzout < pyout", pzout < pyout);
} }


public void testRedirect4() {
public void testRedirect4() throws IOException {
executeTarget("redirect4"); executeTarget("redirect4");
if (getProject().getProperty("test.can.run") == null) { if (getProject().getProperty("test.can.run") == null) {
return; return;
} }
String actualOut = null;
String actualErr = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
actualErr = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.err")));
} catch (IOException eyeOhEx) {
}
String actualOut = getFileString("redirect.out");
String actualErr = getFileString("redirect.err");

File x = getProject().resolveFile("x"); File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y"); File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z"); File z = getProject().resolveFile("z");
@@ -197,68 +184,388 @@ public class ExecuteOnTest extends BuildFileTest {
int xerr = actualErr.indexOf(x + " err"); int xerr = actualErr.indexOf(x + " err");
int yerr = actualErr.indexOf(y + " err"); int yerr = actualErr.indexOf(y + " err");
int zerr = actualErr.indexOf(z + " err"); int zerr = actualErr.indexOf(z + " err");
assertFalse("xout < 0", xout < 0);
assertFalse("yout < 0", yout < 0);
assertFalse("zout < 0", zout < 0);
assertFalse("xerr < 0", xerr < 0);
assertFalse("yerr < 0", yerr < 0);
assertFalse("zerr < 0", zerr < 0);
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout); assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout); assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr); assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr); assertFalse("zerr < yerr", zerr < yerr);
assertPropertyEquals("redirect.out", x + " out");
assertPropertyEquals("redirect.err", x + " err");

String outProperty = getProject().getProperty("redirect.out");
int pxout = outProperty.indexOf(x + " out");
int pyout = outProperty.indexOf(y + " out");
int pzout = outProperty.indexOf(z + " out");
assertFalse("pxout=" + pxout, pxout < 0);
assertFalse("pyout=" + pyout, pyout < 0);
assertFalse("pzout=" + pzout, pzout < 0);
assertFalse("pyout < pxout", pyout < pxout);
assertFalse("pzout < pyout", pzout < pyout);

String errorProperty = getProject().getProperty("redirect.err");
int pxerr = errorProperty.indexOf(x + " err");
int pyerr = errorProperty.indexOf(y + " err");
int pzerr = errorProperty.indexOf(z + " err");
assertFalse("pxerr=" + pxerr, pxerr < 0);
assertFalse("pyerr=" + pyerr, pyerr < 0);
assertFalse("pzerr=" + pzerr, pzerr < 0);
assertFalse("pyerr < pxerr", pyerr < pxerr);
assertFalse("pzerr < pyerr", pzerr < pyerr);
} }


public void testRedirect5() {
public void testRedirect5() throws IOException {
testRedirect5or6("redirect5"); testRedirect5or6("redirect5");
} }


public void testRedirect6() {
public void testRedirect6() throws IOException {
testRedirect5or6("redirect6"); testRedirect5or6("redirect6");
} }


private void testRedirect5or6(String target) {
private void testRedirect5or6(String target) throws IOException {
executeTarget(target); executeTarget(target);
if (getProject().getProperty("sed.can.run") == null) { if (getProject().getProperty("sed.can.run") == null) {
return; return;
} }
String actualOut = null;
String actualErr = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
actualErr = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.err")));
} catch (IOException eyeOhEx) {
}
assertPropertyEquals("redirect.out", "blah y z");

assertPropertyEquals("redirect.out", getProject().replaceProperties(
"blah y z${line.separator}x blah z${line.separator}x y blah"));
assertPropertyEquals("redirect.err", ""); assertPropertyEquals("redirect.err", "");
assertEquals("unexpected content in redirect.out",
"blah y z\nx blah z\nx y blah\n", actualOut);
assertEquals("unexpected content in redirect.err", null, actualErr);
assertEquals("unexpected output",
"blah y z\nx blah z\nx y blah\n", getFileString("redirect.out"));
assertNull("unexpected error output", getFileString("redirect.err"));
} }


public void testRedirect7() {
public void testRedirect7() throws IOException {
executeTarget("redirect7"); executeTarget("redirect7");
if (getProject().getProperty("sed.can.run") == null) { if (getProject().getProperty("sed.can.run") == null) {
return; return;
} }
String actualOut = null;
String actualErr = null;
try {
actualOut = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.out")));
actualErr = FileUtils.newFileUtils().readFully(new FileReader(
getProject().resolveFile("redirect.err")));
} catch (IOException eyeOhEx) {
}

assertPropertyEquals("redirect.out", "blah y z"); assertPropertyEquals("redirect.out", "blah y z");
assertPropertyUnset("redirect.err"); assertPropertyUnset("redirect.err");
assertEquals("unexpected content in redirect.out",
"x y blah\n", actualOut);
assertEquals("unexpected content in redirect.err", null, actualErr);
assertEquals("unexpected output",
"x y blah\n", getFileString("redirect.out"));
assertNull("unexpected error output", getFileString("redirect.err"));
}

public void testRedirector1() {
executeTarget("init");
if (getProject().getProperty("test.can.run") == null) {
return;
}
expectBuildException("redirector1", "cannot have > 1 nested <redirector>s");
}

public void testRedirector2() throws IOException {
executeTarget("redirector2");
if (getProject().getProperty("test.can.run") == null) {
return;
}

String actualOut = getFileString("redirector.out");

File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z");
int xout = actualOut.indexOf(x + " out");
int yout = actualOut.indexOf(y + " out");
int zout = actualOut.indexOf(z + " out");
int xerr = actualOut.indexOf(x + " err");
int yerr = actualOut.indexOf(y + " err");
int zerr = actualOut.indexOf(z + " err");
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr);
}

public void testRedirector3() throws IOException {
executeTarget("redirector3");
if (getProject().getProperty("test.can.run") == null) {
return;
}

String actualOut = getFileString("redirector.out");
String actualErr = getFileString("redirector.err");

File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z");
int xout = actualOut.indexOf(x + " out");
int yout = actualOut.indexOf(y + " out");
int zout = actualOut.indexOf(z + " out");
int xerr = actualErr.indexOf(x + " err");
int yerr = actualErr.indexOf(y + " err");
int zerr = actualErr.indexOf(z + " err");
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr);
}

public void testRedirector4() throws IOException {
executeTarget("redirector4");
if (getProject().getProperty("test.can.run") == null) {
return;
}
String actualOut = getFileString("redirector.out");

File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z");
int xout = actualOut.indexOf(x + " out");
int yout = actualOut.indexOf(y + " out");
int zout = actualOut.indexOf(z + " out");
int xerr = getLog().indexOf(x + " err");
int yerr = getLog().indexOf(y + " err");
int zerr = getLog().indexOf(z + " err");
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr);

String outProperty = getProject().getProperty("redirector.out");
int pxout = outProperty.indexOf(x + " out");
int pyout = outProperty.indexOf(y + " out");
int pzout = outProperty.indexOf(z + " out");
assertFalse("pxout=" + pxout, pxout < 0);
assertFalse("pyout=" + pyout, pyout < 0);
assertFalse("pzout=" + pzout, pzout < 0);
assertFalse("pyout < pxout", pyout < pxout);
assertFalse("pzout < pyout", pzout < pyout);
}

public void testRedirector5() throws IOException {
testRedirector5or6("redirector5");
}

public void testRedirector6() throws IOException {
testRedirector5or6("redirector6");
}

private void testRedirector5or6(String target) throws IOException {
executeTarget(target);
if (getProject().getProperty("test.can.run") == null) {
return;
}
String actualOut = getFileString("redirector.out");
String actualErr = getFileString("redirector.err");

File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z");
int xout = actualOut.indexOf(x + " out");
int yout = actualOut.indexOf(y + " out");
int zout = actualOut.indexOf(z + " out");
int xerr = actualErr.indexOf(x + " err");
int yerr = actualErr.indexOf(y + " err");
int zerr = actualErr.indexOf(z + " err");
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr);

String outProperty = getProject().getProperty("redirector.out");
int pxout = outProperty.indexOf(x + " out");
int pyout = outProperty.indexOf(y + " out");
int pzout = outProperty.indexOf(z + " out");
assertFalse("pxout=" + pxout, pxout < 0);
assertFalse("pyout=" + pyout, pyout < 0);
assertFalse("pzout=" + pzout, pzout < 0);
assertFalse("pyout < pxout", pyout < pxout);
assertFalse("pzout < pyout", pzout < pyout);

String errorProperty = getProject().getProperty("redirector.err");
int pxerr = errorProperty.indexOf(x + " err");
int pyerr = errorProperty.indexOf(y + " err");
int pzerr = errorProperty.indexOf(z + " err");
assertFalse("pxerr=" + pxerr, pxerr < 0);
assertFalse("pyerr=" + pyerr, pyerr < 0);
assertFalse("pzerr=" + pzerr, pzerr < 0);
assertFalse("pyerr < pxerr", pyerr < pxerr);
assertFalse("pzerr < pyerr", pzerr < pyerr);
}

public void testRedirector7() throws IOException {
executeTarget("redirector7");
if (getProject().getProperty("test.can.run") == null) {
return;
}
String actualOut = getFileString("redirector.out");
String actualErr = getFileString("redirector.err");

File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z");
int xout = actualOut.indexOf(x + " out");
int yout = actualOut.indexOf(y + " out");
int zout = actualOut.indexOf(z + " out");
int xerr = actualErr.indexOf(x + " ERROR!!!");
int yerr = actualErr.indexOf(y + " ERROR!!!");
int zerr = actualErr.indexOf(z + " ERROR!!!");
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr);

String outProperty = getProject().getProperty("redirector.out");
int pxout = outProperty.indexOf(x + " out");
int pyout = outProperty.indexOf(y + " out");
int pzout = outProperty.indexOf(z + " out");
assertFalse("pxout=" + pxout, pxout < 0);
assertFalse("pyout=" + pyout, pyout < 0);
assertFalse("pzout=" + pzout, pzout < 0);
assertFalse("pyout < pxout", pyout < pxout);
assertFalse("pzout < pyout", pzout < pyout);

String errorProperty = getProject().getProperty("redirector.err");
int pxerr = errorProperty.indexOf(x + " ERROR!!!");
int pyerr = errorProperty.indexOf(y + " ERROR!!!");
int pzerr = errorProperty.indexOf(z + " ERROR!!!");
assertFalse("pxerr=" + pxerr, pxerr < 0);
assertFalse("pyerr=" + pyerr, pyerr < 0);
assertFalse("pzerr=" + pzerr, pzerr < 0);
assertFalse("pyerr < pxerr", pyerr < pxerr);
assertFalse("pzerr < pyerr", pzerr < pyerr);
}

public void testRedirector8() throws IOException {
executeTarget("redirector8");
if (getProject().getProperty("sed.can.run") == null) {
return;
}

assertPropertyEquals("redirector.out", getProject().replaceProperties(
"blah y z${line.separator}x blah z${line.separator}x y blah"));
assertPropertyEquals("redirector.err", "");
assertEquals("unexpected output",
"blah y z\nx blah z\nx y blah\n", getFileString("redirector.out"));
assertNull("unexpected error output", getFileString("redirector.err"));
}

public void testRedirector9() throws IOException {
testRedirector9Thru12("redirector9");
}

public void testRedirector10() throws IOException {
testRedirector9Thru12("redirector10");
}

public void testRedirector11() throws IOException {
testRedirector9Thru12("redirector11");
}

public void testRedirector12() throws IOException {
testRedirector9Thru12("redirector12");
}

private void testRedirector9Thru12(String target) throws IOException {
executeTarget(target);
if (getProject().getProperty("sed.can.run") == null) {
return;
}

assertNull("unexpected error output", getFileString("redirector.err"));
assertPropertyEquals("redirector.out", getProject().replaceProperties(
"blah after y after z${line.separator}x after blah after z"
+ "${line.separator}x after y after blah"));
assertPropertyEquals("redirector.err", "");
assertEquals("unexpected output",
"blah after y after z\nx after blah after z"
+ "\nx after y after blah\n", getFileString("redirector.out"));
}

public void testRedirector13() {
executeTarget("redirector13");
if (getProject().getProperty("test.can.run") == null) {
return;
}
String log = getLog();
File x = getProject().resolveFile("x");
File y = getProject().resolveFile("y");
File z = getProject().resolveFile("z");
int xout = log.indexOf(x + " OUTPUT???");
int yout = log.indexOf(y + " OUTPUT???");
int zout = log.indexOf(z + " OUTPUT???");
int xerr = log.indexOf(x + " ERROR!!!");
int yerr = log.indexOf(y + " ERROR!!!");
int zerr = log.indexOf(z + " ERROR!!!");
assertFalse("xout=" + xout, xout < 0);
assertFalse("yout=" + yout, yout < 0);
assertFalse("zout=" + zout, zout < 0);
assertFalse("xerr=" + xerr, xerr < 0);
assertFalse("yerr=" + yerr, yerr < 0);
assertFalse("zerr=" + zerr, zerr < 0);
assertFalse("yout < xout", yout < xout);
assertFalse("zout < yout", zout < yout);
assertFalse("yerr < xerr", yerr < xerr);
assertFalse("zerr < yerr", zerr < yerr);
}

public void testRedirector14() throws IOException {
executeTarget("redirector14");
if (getProject().getProperty("sed.can.run") == null) {
return;
}

assertEquals("unexpected log content",
"z after y after blahx after y after blah", getLog());

assertEquals("unexpected redirector.out content",
"x after blah after z\n", getFileString("redirector.out"));

assertNull("unexpected redirector.err content", getFileString("redirector.err"));
}

//borrowed from TokenFilterTest
private String getFileString(String filename) throws IOException {
String result = null;
FileReader reader = null;
try {
reader = new FileReader(getProject().resolveFile(filename));
result = FileUtils.newFileUtils().readFully(reader);
} finally {
if (reader != null) {
try {
reader.close();
} catch (Throwable ignore) {
}
}
}
return result;
} }


} }

+ 53
- 0
src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java View File

@@ -20,7 +20,9 @@ package org.apache.tools.ant.taskdefs;
import junit.framework.*; import junit.framework.*;
import java.io.*; import java.io.*;
import org.apache.tools.ant.*; import org.apache.tools.ant.*;
//import org.apache.tools.ant.taskdefs.StreamPumper;
import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.TeeOutputStream;


/** /**
* stress out java task * stress out java task
@@ -186,6 +188,26 @@ public class JavaTest extends BuildFileTest {
assertTrue("log file exists", logFile.exists()); assertTrue("log file exists", logFile.exists());
} }


public void testRedirect1() {
executeTarget("redirect1");
}

public void testRedirect2() {
executeTarget("redirect2");
}

public void testRedirect3() {
executeTarget("redirect3");
}

public void testRedirector1() {
executeTarget("redirector1");
}

public void testRedirector2() {
executeTarget("redirector2");
}

/** /**
* entry point class with no dependencies other * entry point class with no dependencies other
* than normal JRE runtime * than normal JRE runtime
@@ -266,4 +288,35 @@ public class JavaTest extends BuildFileTest {


} }
} }

/**
* entry point class to pipe System.in to the specified stream:
* "out", "err", or "both". If none specified, swallow the input.
*/
public static class PipeEntryPoint {

/**
* pipe input to specified output
*/
public static void main(String[] args) {
OutputStream os = null;
if (args.length > 0) {
if ("out".equalsIgnoreCase(args[0])) {
os = System.out;
} else if ("err".equalsIgnoreCase(args[0])) {
os = System.err;
} else if ("both".equalsIgnoreCase(args[0])) {
os = new TeeOutputStream(System.out, System.err);
}
}
if (os != null) {
Thread t = new Thread(new StreamPumper(System.in, os, true));
t.start();
try {
t.join();
} catch (InterruptedException eyeEx) {
}
}
}
}
} }

Loading…
Cancel
Save