Bugs item #1010223, was opened at 2004-08-16 15:03
Message generated for change (Comment added) made by garyfx
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=402868&aid=1010223&group_id=31650
Category: Tasks
Group: 0.85
Status: Open
Resolution: None
Priority: 7
Submitted By: Michael Flanakin (flanakin)
Assigned to: Nobody/Anonymous (nobody)
Summary: Exec Task Output
Initial Comment:
I'm using the Aug 14 nightly build and I'm having a
problem the exec task. It isn't a huge problem, just a
beautification one. I specified the output attribute,
which is working fine, but for some reason, the output is
going to both the screen and the file. My understanding
was that, when the output attribute was specified, the
screen output is hidden. I believe this is how Ant works.
If this is the intended mode of operation, there needs to
be an option to hide console output.
Here's my stripped exec task:
<exec program="xyz.exe" output="xyz.log">
<arg value="/a:abc" />
<arg value="/1:123" />
</exec>
The reason this is a problem is because the program
outputs a screen's worth of text and, on top of that, it
runs for each project within a solution - 5 times for my
current project. This is all just wasted space that clogs
up the build log and makes it harder to read/debug.
Thanks in advance!
----------------------------------------------------------------------
Comment By: Gary Feldman (garyfx)
Date: 2005-04-14 13:29
Message:
Logged In: YES
user_id=847172
I've submitted a very simple patch for this in in the
Patches database, ID 1183217
Gary
----------------------------------------------------------------------
Comment By: Rutger Dijkstra (rutgerdijkstra)
Date: 2004-11-28 16:33
Message:
Logged In: YES
user_id=1131474
Index: src/NAnt.Core/Tasks/ExternalProgramBase.cs
==============================================
=====================
RCS
file: /cvsroot/nant/nant/src/NAnt.Core/Tasks/ExternalProgram
Base.cs,v
retrieving revision 1.63
diff -u -r1.63 ExternalProgramBase.cs
--- src/NAnt.Core/Tasks/ExternalProgramBase.cs 10
Nov 2004 07:17:23 -0000 1.63
+++ src/NAnt.Core/Tasks/ExternalProgramBase.cs 28
Nov 2004 18:35:13 -0000
@@ -40,8 +40,6 @@
public abstract class ExternalProgramBase : Task {
#region Private Instance Fields
- private StreamReader _stdError;
- private StreamReader _stdOut;
private ArgumentCollection _arguments = new
ArgumentCollection();
private bool _useRuntimeEngine;
private string _exeName;
@@ -204,9 +202,16 @@
/// </remarks>
public virtual TextWriter OutputWriter {
get {
- if (_outputWriter == null) {
+ if(_outputWriter != null) return _outputWriter;
+ if(Output == null) {
_outputWriter = new LogWriter(this,
Level.Info,
CultureInfo.InvariantCulture);
+ } else if(string.Compare
(Output.Name,"NUL",true) == 0) {
+ _outputWriter = TextWriter.Null;
+ } else {
+ FileMode mode = OutputAppend?
FileMode.Append: FileMode.Create;
+ _outputWriter = TextWriter.Synchronized(
+ new StreamWriter( Output.Open
(mode,FileAccess.Write)));
}
return _outputWriter;
}
@@ -227,9 +232,12 @@
/// </remarks>
public virtual TextWriter ErrorWriter {
get {
- if (_errorWriter == null) {
+ if(_errorWriter != null) return _outputWriter;
+ if(Output == null) {
_errorWriter = new LogWriter(this,
Level.Warning,
CultureInfo.InvariantCulture);
+ } else {
+ _errorWriter = OutputWriter;
}
return _errorWriter;
}
@@ -261,27 +269,19 @@
/// <para>The exit code of the external process
indicates a failure.</para>
/// </exception>
protected override void ExecuteTask() {
- Thread outputThread = null;
- Thread errorThread = null;
+ Pipe stdoutPipe = null;
+ Pipe stderrPipe = null;
try {
- // Start the external process
+ // Start the external process and the IO-pipes
Process process = StartProcess();
- outputThread = new Thread(new ThreadStart
(StreamReaderThread_Output));
- errorThread = new Thread(new ThreadStart
(StreamReaderThread_Error));
-
- _stdOut = process.StandardOutput;
- _stdError = process.StandardError;
-
- outputThread.Start();
- errorThread.Start();
-
- // Wait for the process to terminate
+ stdoutPipe = new Pipe
(process.StandardOutput,OutputWriter);
+ stderrPipe = new Pipe
(process.StandardError,ErrorWriter);
+
+ // Wait for everything to finnish
process.WaitForExit(TimeOut);
-
- // Wait for the threads to terminate
- outputThread.Join(2000);
- errorThread.Join(2000);
+ stdoutPipe.WaitFinish(2000);
+ stderrPipe.WaitFinish(2000);
if (!process.HasExited) {
try {
@@ -324,14 +324,12 @@
Location,
e);
} finally {
- // ensure outputThread is always aborted
- if (outputThread != null && outputThread.IsAlive)
{
- outputThread.Abort();
- }
- // ensure errorThread is always aborted
- if (errorThread != null && errorThread.IsAlive) {
- errorThread.Abort();
- }
+ if(stderrPipe != null) stderrPipe.WaitFinish(0);
+ if(stdoutPipe != null) stdoutPipe.WaitFinish(0);
+ ErrorWriter.Close();
+ OutputWriter.Close();
+ //make sure the writers are re-created on a
second run
+ _errorWriter = _outputWriter = null;
}
}
@@ -427,55 +425,6 @@
#region Private Instance Methods
- /// <summary> /// Reads from the stream until
the external program is ended. /// </summary>
- private void StreamReaderThread_Output() {
- StreamReader reader = _stdOut;
- bool doAppend = OutputAppend;
-
- while (true) {
- string logContents = reader.ReadLine();
- if (logContents == null) {
- break;
- }
-
- // ensure only one thread writes to the log at
any time
- lock (_lockObject) {
- OutputWriter.WriteLine(logContents);
- if (Output != null) {
- StreamWriter writer = new StreamWriter
(Output.FullName, doAppend);
- writer.WriteLine(logContents);
- doAppend = true;
- writer.Close();
- }
- }
- }
- OutputWriter.Flush();
- }
- /// <summary> /// Reads from the stream until
the external program is ended. /// </summary>
- private void StreamReaderThread_Error() {
- StreamReader reader = _stdError;
- bool doAppend = OutputAppend;
-
- while (true) {
- string logContents = reader.ReadLine();
- if (logContents == null) {
- break;
- }
-
- // ensure only one thread writes to the log at
any time
- lock (_lockObject) {
- ErrorWriter.WriteLine(logContents);
- if (Output != null) {
- StreamWriter writer = new StreamWriter
(Output.FullName, doAppend);
- writer.WriteLine(logContents);
- doAppend = true;
- writer.Close();
- }
- }
- }
- ErrorWriter.Flush();
- }
-
/// <summary>
/// Determines the path of the external program that
should be executed.
/// </summary>
Index: tests/NAnt.Core/Tasks/ExecTaskTest.cs
==============================================
=====================
RCS
file: /cvsroot/nant/nant/tests/NAnt.Core/Tasks/ExecTaskTest.
cs,v
retrieving revision 1.10
diff -u -r1.10 ExecTaskTest.cs
--- tests/NAnt.Core/Tasks/ExecTaskTest.cs 11 Aug 2004
07:17:07 -0000 1.10
+++ tests/NAnt.Core/Tasks/ExecTaskTest.cs 28 Nov 2004
18:21:08 -0000
@@ -74,6 +74,33 @@
// if we get here then we passed, ie, no hang = bug
fixed
}
+ [Test]
+ public void Test_OutputRedirect() {
+ string output = Path.Combine
(this.TempDirectory.FullName,"redirected.txt");
+ if(File.Exists(output)) File.Delete(output);
+ string result = "";
+ if (PlatformHelper.IsWin32) {
+ result = RunBuild(FormatBuildFile
("program='cmd.exe' output='"+output+"'", "<arg value='/c
echo Hello, World!'/>"));
+ } else {
+ result = RunBuild(FormatBuildFile("program='echo'
output='"+output+"'", "<arg value='Hello, World!'/>"));
+ }
+ Assert.IsTrue(File.Exists(output),"output redirection
to file failed");
+ Assert.IsFalse(result.IndexOf("Hello, World!") != -
1, "unexpected text on stdout");
+ }
+ [Test,ExpectedException(typeof(TestBuildException))]
+ public void Test_OutputRedirectToRoFile() {
+ string output = Path.Combine
(this.TempDirectory.FullName,"ro.txt");
+ FileInfo outputInfo = new FileInfo(output);
+ if(!outputInfo.Exists) outputInfo.Create();
+ outputInfo.Attributes = FileAttributes.ReadOnly;
+ string result = "";
+ if (PlatformHelper.IsWin32) {
+ result = RunBuild(FormatBuildFile
("program='cmd.exe' output='"+output+"'", "<arg value='/c
echo Hello, World!'/>"));
+ } else {
+ result = RunBuild(FormatBuildFile("program='echo'
output='"+output+"'", "<arg value='Hello, World!'/>"));
+ }
+ }
+
private string FormatBuildFile(string attributes, string
nestedElements) {
return String.Format(CultureInfo.InvariantCulture,
_format, attributes, nestedElements);
}
--- src/NAnt.Core/Util/Pipe.cs
+++ src/NAnt.Core/Util/Pipe.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+using System.Threading;
+
+namespace NAnt.Core.Util {
+ /// <summary>
+ /// Pipes text line-by-line from a TextReader to a
TextWriter.
+ /// </summary>
+ public class Pipe {
+
+ TextReader reader;
+ TextWriter writer;
+ Thread thread;
+ object synch;
+
+ /// <summary>
+ /// Create a Pipe without synchronization.
+ /// </summary>
+ /// <param name="reader">source</param>
+ /// <param name="writer">destination</param>
+ public Pipe(TextReader reader, TextWriter writer):this
(reader,writer,null) {
+ }
+ /// <summary>
+ /// Create a Pipe that synchronizes the writes on
<c>synch</c>.
+ /// </summary>
+ /// <param name="reader"></param>
+ /// <param name="writer"></param>
+ /// <param name="synch"></param>
+ public Pipe(TextReader reader, TextWriter writer,
object synch) {
+ this.reader = reader;
+ this.writer = writer;
+ this.synch = synch != null? synch: new Object();
+ this.thread = new Thread(new ThreadStart
(this.Pump));
+ this.thread.Start();
+ }
+ private void Pump() {
+ do {
+ string line = reader.ReadLine();
+ if(line == null) break;
+ lock(synch) {
+ writer.WriteLine(line);
+ writer.Flush();
+ }
+ } while(true);
+ }
+ /// <summary>
+ /// Wait for the pipe to finish it's job
+ /// </summary>
+ public void WaitFinish() {
+ this.thread.Join();
+ }
+ /// <summary>
+ /// Wait for the pipe to finish it's job for a maximum of
+ /// <c>timeout</c> millisecond; after that, abort the
thread.
+ /// </summary>
+ /// <param name="timeout">timeout in
milliseconds</param>
+ public void WaitFinish(int timeout) {
+ if(this.thread.Join(timeout)) return;
+ this.thread.Abort();
+ this.thread.Interrupt();
+ }
+ }
+}
----------------------------------------------------------------------
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=402868&aid=1010223&group_id=31650
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
nant-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/nant-developers