Bugs item #1010223, was opened at 2004-08-16 21:03
Message generated for change (Comment added) made by trevi_trev
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=402868&aid=1010223&group_id=31650

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Tasks
Group: 0.85
Status: Open
Resolution: None
Priority: 7
Private: No
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: Trevor Green (trevi_trev)
Date: 2007-03-06 10:14

Message:
Logged In: YES 
user_id=832163
Originator: NO

Perhaps this functionality can be configured using an attribute on the
exec node? Something like

<exec program="xyz.exe" output="xyz.log" console="false"/>

----------------------------------------------------------------------

Comment By: Gary Feldman (garyfx)
Date: 2005-04-14 19: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 23: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

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
nant-developers mailing list
nant-developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nant-developers

Reply via email to