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. | * Enable to choose the regexp implementation without system property. | ||||
Bugzilla Report 15390. | 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. | * Allow file attribute of <move> to rename a directory. | ||||
Bugzilla Report 22863. | Bugzilla Report 22863. | ||||
* Add xmlcatalog nested element to XmlProperty. Bugzilla report 27053. | * Add xmlcatalog nested element to XmlProperty. Bugzilla report 27053. | ||||
* New attribute alwayslog for <redirector> type. | |||||
Fixed bugs: | Fixed bugs: | ||||
----------- | ----------- | ||||
@@ -27,62 +27,66 @@ source (input) and destination (output/error) files. <em>Since Ant 1.6.2</em> | |||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">output</td> | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">error</td> | <td valign="top">error</td> | ||||
<td valign="top">The file to which the standard error of the | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">logError</td> | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">append</td> | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">createemptyfiles</td> | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">outputproperty</td> | <td valign="top">outputproperty</td> | ||||
<td valign="top">The name of a property in which the output of the | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">errorproperty</td> | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">input</td> | <td valign="top">input</td> | ||||
<td valign="top">A file from which the executed command's standard input | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">inputstring</td> | <td valign="top">inputstring</td> | ||||
<td valign="top">A string which serves as the input stream for the | <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> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<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 valign="top">The error encoding.</td> | ||||
<td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
</tr> | </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> | </table> | ||||
<h3>Parameters specified as nested elements</h3> | <h3>Parameters specified as nested elements</h3> | ||||
<h4>inputmapper</h4> | <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 | A nested <errormapper> is not compatible with the | ||||
<i>error</i> attribute.</p> | <i>error</i> attribute.</p> | ||||
<h4>inputfilterchain</h4> | <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> | applied to the process input.</p> | ||||
<h4>outputfilterchain</h4> | <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> | applied to the process output.</p> | ||||
<h4>errorfilterchain</h4> | <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> | applied to the error output.</p> | ||||
<h3>Usage</h3> | <h3>Usage</h3> | ||||
Tasks known to support I/O redirection: | Tasks known to support I/O redirection: | ||||
@@ -313,6 +313,22 @@ | |||||
<fail if="17fail">Files were created.</fail> | <fail if="17fail">Files were created.</fail> | ||||
</target> | </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"> | <target name="cleanup"> | ||||
<delete> | <delete> | ||||
<fileset file="${logFile}" /> | <fileset file="${logFile}" /> | ||||
@@ -122,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 that output should be always sent to the log */ | |||||
private boolean alwaysLog = false; | |||||
/** Flag which indicates whether files should be created even when empty. */ | /** Flag which indicates whether files should be created even when empty. */ | ||||
private boolean createEmptyFiles = true; | private boolean createEmptyFiles = true; | ||||
@@ -333,12 +336,23 @@ public class Redirector { | |||||
this.append = append; | 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. | * Whether output and error files should be created even when empty. | ||||
* Defaults to true. | * Defaults to true. | ||||
* @param createEmptyFiles <CODE>boolean</CODE>. | * @param createEmptyFiles <CODE>boolean</CODE>. | ||||
*/ | */ | ||||
public void setCreateEmptyFiles(boolean createEmptyFiles) { | |||||
public synchronized void setCreateEmptyFiles(boolean createEmptyFiles) { | |||||
this.createEmptyFiles = createEmptyFiles; | this.createEmptyFiles = createEmptyFiles; | ||||
} | } | ||||
@@ -371,7 +385,7 @@ public class Redirector { | |||||
* | * | ||||
* @param outputFilterChains <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | * @param outputFilterChains <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | ||||
*/ | */ | ||||
public void setOutputFilterChains(Vector outputFilterChains) { | |||||
public synchronized void setOutputFilterChains(Vector outputFilterChains) { | |||||
this.outputFilterChains = outputFilterChains; | this.outputFilterChains = outputFilterChains; | ||||
} | } | ||||
@@ -380,7 +394,7 @@ public class Redirector { | |||||
* | * | ||||
* @param errorFilterChains <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | * @param errorFilterChains <CODE>Vector</CODE> containing <CODE>FilterChain</CODE>. | ||||
*/ | */ | ||||
public void setErrorFilterChains(Vector errorFilterChains) { | |||||
public synchronized void setErrorFilterChains(Vector errorFilterChains) { | |||||
this.errorFilterChains = errorFilterChains; | this.errorFilterChains = errorFilterChains; | ||||
} | } | ||||
@@ -413,35 +427,24 @@ public class Redirector { | |||||
* configuration options. | * configuration options. | ||||
*/ | */ | ||||
public synchronized void createStreams() { | 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) { | if (error != null && error.length > 0) { | ||||
@@ -449,10 +452,7 @@ public class Redirector { | |||||
((append) ? "appended" : "redirected")).append( | ((append) ? "appended" : "redirected")).append( | ||||
" to ").toString(); | " to ").toString(); | ||||
errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE); | 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; | long funnelTimeout = 0L; | ||||
OutputStreamFunneler funneler | OutputStreamFunneler funneler | ||||
= new OutputStreamFunneler(outputStream, funnelTimeout); | = new OutputStreamFunneler(outputStream, funnelTimeout); | ||||
@@ -464,7 +464,6 @@ public class Redirector { | |||||
"error splitting output/error streams", eyeOhEx); | "error splitting output/error streams", eyeOhEx); | ||||
} | } | ||||
} | } | ||||
if (errorProperty != null) { | if (errorProperty != null) { | ||||
if (errorBaos == null) { | if (errorBaos == null) { | ||||
errorBaos = new PropertyOutputStream(errorProperty); | errorBaos = new PropertyOutputStream(errorProperty); | ||||
@@ -478,7 +477,18 @@ public class Redirector { | |||||
} else { | } else { | ||||
errorBaos = null; | 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) | if ((outputFilterChains != null && outputFilterChains.size() > 0) | ||||
|| !(outputEncoding.equalsIgnoreCase(inputEncoding))) { | || !(outputEncoding.equalsIgnoreCase(inputEncoding))) { | ||||
try { | try { | ||||
@@ -65,6 +65,9 @@ public class RedirectorElement extends DataType { | |||||
/** 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; | 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. */ | /** Flag which indicates whether files should be created even if empty. */ | ||||
private Boolean createEmptyFiles; | private Boolean createEmptyFiles; | ||||
@@ -316,6 +319,21 @@ public class RedirectorElement extends DataType { | |||||
this.append = ((append) ? Boolean.TRUE : Boolean.FALSE); | 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. | * Whether output and error files should be created even when empty. | ||||
* Defaults to true. | * Defaults to true. | ||||
@@ -400,6 +418,9 @@ public class RedirectorElement extends DataType { | |||||
* @param sourcefile <CODE>String</CODE>. | * @param sourcefile <CODE>String</CODE>. | ||||
*/ | */ | ||||
public void configure(Redirector redirector, String sourcefile) { | public void configure(Redirector redirector, String sourcefile) { | ||||
if (alwaysLog != null) { | |||||
redirector.setAlwaysLog(alwaysLog.booleanValue()); | |||||
} | |||||
if (logError != null) { | if (logError != null) { | ||||
redirector.setLogError(logError.booleanValue()); | redirector.setLogError(logError.booleanValue()); | ||||
} | } | ||||
@@ -329,6 +329,14 @@ public class ExecTaskTest extends BuildFileTest { | |||||
executeTarget("redirector17"); | 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() { | public void testspawn() { | ||||
project.executeTarget("init"); | project.executeTarget("init"); | ||||
if (project.getProperty("test.can.run") == null) { | if (project.getProperty("test.can.run") == null) { | ||||