git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276889 13f79535-47bb-0310-9956-ffa450edef68master
@@ -77,13 +77,15 @@ Other changes: | |||
* Enable to choose the regexp implementation without system property. | |||
Bugzilla Report 15390. | |||
* Expose objects and methods in IntrospectionHelper. Bugzilla Report 30794. | |||
* Expose objects and methods in IntrospectionHelper. Bugzilla Report 30794. | |||
* Allow file attribute of <move> to rename a directory. | |||
Bugzilla Report 22863. | |||
* Add xmlcatalog nested element to XmlProperty. Bugzilla report 27053. | |||
* New attribute alwayslog for <redirector> type. | |||
Fixed bugs: | |||
----------- | |||
@@ -27,62 +27,66 @@ source (input) and destination (output/error) files. <em>Since Ant 1.6.2</em> | |||
</tr> | |||
<tr> | |||
<td valign="top">output</td> | |||
<td valign="top">Name of a file to which to write the output. If the error stream | |||
is not also redirected to a file or property, it will appear in this output.</td> | |||
<td valign="top">Name of a file to which output should be written. | |||
If the error stream is not also redirected to a file or property, | |||
it will appear in this output.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">error</td> | |||
<td valign="top">The file to which the standard error of the | |||
command should be redirected.</td> | |||
command should be redirected.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">logError</td> | |||
<td valign="top">This attribute is used when you wish to see error output in Ant's | |||
log and you are redirecting output to a file/property. The error | |||
output will not be included in the output file/property. If you | |||
redirect error with the <i>error</i> or <i>errorProperty</i> | |||
attributes, this will have no effect.</td> | |||
<td valign="top">This attribute is used when you wish to see | |||
error output in Ant's log and you are redirecting output to | |||
a file/property. The error output will not be included in | |||
the output file/property. If you redirect error with the | |||
<i>error</i> or <i>errorProperty</i> attributes, this will | |||
have no effect.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">append</td> | |||
<td valign="top">Whether output and error files should be appended to or overwritten. | |||
Defaults to <code>false</code>.</td> | |||
<td valign="top">Whether output and error files should be | |||
appended to rather than overwritten. Defaults to | |||
<code>false</code>.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">createemptyfiles</td> | |||
<td valign="top">Whether output and error files should be created even when empty. | |||
Defaults to <code>true</code>.</td> | |||
<td valign="top">Whether output and error files should be | |||
created even when empty. Defaults to <code>true</code>.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">outputproperty</td> | |||
<td valign="top">The name of a property in which the output of the | |||
command should be stored. Unless the error stream is redirected to a separate | |||
file or stream, this property will include the error output.</td> | |||
command should be stored. Unless the error stream is redirected | |||
to a separate file or stream, this property will include the | |||
error output.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">errorproperty</td> | |||
<td valign="top">The name of a property in which the standard error of the | |||
command should be stored.</td> | |||
<td valign="top">The name of a property in which the standard error | |||
of the command should be stored.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">input</td> | |||
<td valign="top">A file from which the executed command's standard input | |||
is taken. This attribute is mutually exclusive with the | |||
<i>inputstring</i> attribute.</td> | |||
is taken. This attribute is mutually exclusive with the | |||
<i>inputstring</i> attribute.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">inputstring</td> | |||
<td valign="top">A string which serves as the input stream for the | |||
executed command. This attribute is mutually exclusive with the | |||
<i>input</i> attribute.</td> | |||
executed command. This attribute is mutually exclusive with the | |||
<i>input</i> attribute.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
@@ -100,6 +104,14 @@ source (input) and destination (output/error) files. <em>Since Ant 1.6.2</em> | |||
<td valign="top">The error encoding.</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">alwayslog</td> | |||
<td valign="top">Always send to the log in addition to | |||
any other destination. Default <code>false</code>. | |||
<i>Since Ant 1.6.3</i>. | |||
</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
</table> | |||
<h3>Parameters specified as nested elements</h3> | |||
<h4>inputmapper</h4> | |||
@@ -122,13 +134,13 @@ consult the documentation of the individual task for more details. | |||
A nested <errormapper> is not compatible with the | |||
<i>error</i> attribute.</p> | |||
<h4>inputfilterchain</h4> | |||
<p>One or more <a href="./filterchain.html">FilterChain</a>s can be | |||
<p>A <a href="./filterchain.html">FilterChain</a> can be | |||
applied to the process input.</p> | |||
<h4>outputfilterchain</h4> | |||
<p>One or more <a href="./filterchain.html">FilterChain</a>s can be | |||
<p>A <a href="./filterchain.html">FilterChain</a> can be | |||
applied to the process output.</p> | |||
<h4>errorfilterchain</h4> | |||
<p>One or more <a href="./filterchain.html">FilterChain</a>s can be | |||
<p>A <a href="./filterchain.html">FilterChain</a> can be | |||
applied to the error output.</p> | |||
<h3>Usage</h3> | |||
Tasks known to support I/O redirection: | |||
@@ -313,6 +313,22 @@ | |||
<fail if="17fail">Files were created.</fail> | |||
</target> | |||
<target name="redirector18" depends="init" if="test.can.run"> | |||
<exec executable="sh"> | |||
<arg value="parrot.sh"/> | |||
<arg value="${ant.file}" /> | |||
<redirector alwayslog="true" logerror="true" | |||
outputproperty="redirector.out" /> | |||
</exec> | |||
<fail message="property redirector.out has unexpected content"> | |||
<condition> | |||
<not> | |||
<equals arg1="${ant.file} out" arg2="${redirector.out}" /> | |||
</not> | |||
</condition> | |||
</fail> | |||
</target> | |||
<target name="cleanup"> | |||
<delete> | |||
<fileset file="${logFile}" /> | |||
@@ -122,6 +122,9 @@ public class Redirector { | |||
/** Flag which indicates if error and output files are to be appended. */ | |||
private boolean append = false; | |||
/** Flag which indicates that output should be always sent to the log */ | |||
private boolean alwaysLog = false; | |||
/** Flag which indicates whether files should be created even when empty. */ | |||
private boolean createEmptyFiles = true; | |||
@@ -333,12 +336,23 @@ public class Redirector { | |||
this.append = append; | |||
} | |||
/** | |||
* If true, (error and non-error) output will be "teed", redirected | |||
* as specified while being sent to Ant's logging mechanism as if no | |||
* redirection had taken place. Defaults to false. | |||
* @param alwaysLog <code>boolean</code> | |||
* @since Ant 1.6.3 | |||
*/ | |||
public synchronized void setAlwaysLog(boolean alwaysLog) { | |||
this.alwaysLog = alwaysLog; | |||
} | |||
/** | |||
* Whether output and error files should be created even when empty. | |||
* Defaults to true. | |||
* @param createEmptyFiles <CODE>boolean</CODE>. | |||
*/ | |||
public void setCreateEmptyFiles(boolean createEmptyFiles) { | |||
public synchronized void setCreateEmptyFiles(boolean createEmptyFiles) { | |||
this.createEmptyFiles = createEmptyFiles; | |||
} | |||
@@ -371,7 +385,7 @@ public class Redirector { | |||
* | |||
* @param outputFilterChains <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | |||
*/ | |||
public void setOutputFilterChains(Vector outputFilterChains) { | |||
public synchronized void setOutputFilterChains(Vector outputFilterChains) { | |||
this.outputFilterChains = outputFilterChains; | |||
} | |||
@@ -380,7 +394,7 @@ public class Redirector { | |||
* | |||
* @param errorFilterChains <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | |||
*/ | |||
public void setErrorFilterChains(Vector errorFilterChains) { | |||
public synchronized void setErrorFilterChains(Vector errorFilterChains) { | |||
this.errorFilterChains = errorFilterChains; | |||
} | |||
@@ -413,35 +427,24 @@ public class Redirector { | |||
* configuration options. | |||
*/ | |||
public synchronized void createStreams() { | |||
if ((out == null || out.length == 0) && outputProperty == null) { | |||
outputStream = new LogOutputStream(managingTask, Project.MSG_INFO); | |||
} else { | |||
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 (baos == null) { | |||
baos = new PropertyOutputStream(outputProperty); | |||
managingTask.log("Output redirected to property: " | |||
+ outputProperty, Project.MSG_VERBOSE); | |||
} | |||
//shield it from being closed by a filtering StreamPumper | |||
OutputStream keepAliveOutput = new KeepAliveOutputStream(baos); | |||
if (outputStream == null) { | |||
outputStream = keepAliveOutput; | |||
} else { | |||
outputStream | |||
= new TeeOutputStream(outputStream, keepAliveOutput); | |||
} | |||
} else { | |||
baos = null; | |||
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 (baos == null) { | |||
baos = new PropertyOutputStream(outputProperty); | |||
managingTask.log("Output redirected to property: " | |||
+ outputProperty, Project.MSG_VERBOSE); | |||
} | |||
errorStream = outputStream; | |||
//shield it from being closed by a filtering StreamPumper | |||
OutputStream keepAliveOutput = new KeepAliveOutputStream(baos); | |||
outputStream = (outputStream == null) ? keepAliveOutput | |||
: new TeeOutputStream(outputStream, keepAliveOutput); | |||
} else { | |||
baos = null; | |||
} | |||
if (error != null && error.length > 0) { | |||
@@ -449,10 +452,7 @@ public class Redirector { | |||
((append) ? "appended" : "redirected")).append( | |||
" to ").toString(); | |||
errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE); | |||
} else if (logError || errorStream == null) { | |||
errorStream = new LogOutputStream(managingTask, Project.MSG_WARN); | |||
} else { //must be errorStream == outputStream | |||
} else if (!(logError || outputStream == null)) { | |||
long funnelTimeout = 0L; | |||
OutputStreamFunneler funneler | |||
= new OutputStreamFunneler(outputStream, funnelTimeout); | |||
@@ -464,7 +464,6 @@ public class Redirector { | |||
"error splitting output/error streams", eyeOhEx); | |||
} | |||
} | |||
if (errorProperty != null) { | |||
if (errorBaos == null) { | |||
errorBaos = new PropertyOutputStream(errorProperty); | |||
@@ -478,7 +477,18 @@ public class Redirector { | |||
} else { | |||
errorBaos = null; | |||
} | |||
if (alwaysLog || outputStream == null) { | |||
OutputStream outputLog | |||
= new LogOutputStream(managingTask, Project.MSG_INFO); | |||
outputStream = (outputStream == null) | |||
? outputLog : new TeeOutputStream(outputLog, outputStream); | |||
} | |||
if (alwaysLog || errorStream == null) { | |||
OutputStream errorLog | |||
= new LogOutputStream(managingTask, Project.MSG_WARN); | |||
errorStream = (errorStream == null) | |||
? errorLog : new TeeOutputStream(errorLog, errorStream); | |||
} | |||
if ((outputFilterChains != null && outputFilterChains.size() > 0) | |||
|| !(outputEncoding.equalsIgnoreCase(inputEncoding))) { | |||
try { | |||
@@ -65,6 +65,9 @@ public class RedirectorElement extends DataType { | |||
/** Flag which indicates if error and output files are to be appended. */ | |||
private Boolean append; | |||
/** Flag which indicates that output should be always sent to the log */ | |||
private Boolean alwaysLog; | |||
/** Flag which indicates whether files should be created even if empty. */ | |||
private Boolean createEmptyFiles; | |||
@@ -316,6 +319,21 @@ public class RedirectorElement extends DataType { | |||
this.append = ((append) ? Boolean.TRUE : Boolean.FALSE); | |||
} | |||
/** | |||
* If true, (error and non-error) output will be "teed", redirected | |||
* as specified while being sent to Ant's logging mechanism as if no | |||
* redirection had taken place. Defaults to false. | |||
* @param alwaysLog <code>boolean</code> | |||
* @since Ant 1.6.3 | |||
*/ | |||
public void setAlwaysLog(boolean alwaysLog) { | |||
if (isReference()) { | |||
throw tooManyAttributes(); | |||
} | |||
//pre JDK 1.4 compatible | |||
this.alwaysLog = ((alwaysLog) ? Boolean.TRUE : Boolean.FALSE); | |||
} | |||
/** | |||
* Whether output and error files should be created even when empty. | |||
* Defaults to true. | |||
@@ -400,6 +418,9 @@ public class RedirectorElement extends DataType { | |||
* @param sourcefile <CODE>String</CODE>. | |||
*/ | |||
public void configure(Redirector redirector, String sourcefile) { | |||
if (alwaysLog != null) { | |||
redirector.setAlwaysLog(alwaysLog.booleanValue()); | |||
} | |||
if (logError != null) { | |||
redirector.setLogError(logError.booleanValue()); | |||
} | |||
@@ -329,6 +329,14 @@ public class ExecTaskTest extends BuildFileTest { | |||
executeTarget("redirector17"); | |||
} | |||
public void testRedirector18() { | |||
if (getProject().getProperty("test.can.run") == null) { | |||
return; | |||
} | |||
expectLog("redirector18", getProject().getProperty("ant.file") | |||
+ " out" + getProject().getProperty("ant.file") + " err"); | |||
} | |||
public void testspawn() { | |||
project.executeTarget("init"); | |||
if (project.getProperty("test.can.run") == null) { | |||