Beispiel #1
0
        private static async Task CopyStreamAsync(Stream from, Stream to, IdleManager idleManager, CancellationToken cancellationToken, bool closeAfterCopy = false)
        {
            try
            {
                byte[] bytes = new byte[1024];
                int    read  = 0;
                while ((read = await from.ReadAsync(bytes, 0, bytes.Length, cancellationToken)) != 0)
                {
                    idleManager.UpdateActivity();
                    await to.WriteAsync(bytes, 0, read, cancellationToken);
                }

                idleManager.UpdateActivity();
            }
            finally
            {
                // this is needed specifically for input stream
                // in order to tell executable that the input is done
                if (closeAfterCopy)
                {
                    to.Close();
                }
            }
        }
Beispiel #2
0
        public CommandResult ExecuteCommand(string command, string workingDirectory)
        {
            var idleManager = new IdleManager(_settings.GetCommandIdleTimeout(), _tracer);
            var result = new CommandResult();

            int exitCode = 0;
            var outputBuilder = new StringBuilder();
            var errorBuilder = new StringBuilder();

            Action<CommandEvent> handler = args =>
            {
                idleManager.UpdateActivity();
                switch (args.EventType)
                {
                    case CommandEventType.Output:
                        outputBuilder.AppendLine(args.Data);
                        break;
                    case CommandEventType.Error:
                        errorBuilder.AppendLine(args.Data);
                        break;
                    case CommandEventType.Complete:
                        exitCode = args.ExitCode;
                        break;
                    default:
                        break;
                }
            };

            try
            {
                // Code reuse is good
                CommandEvent += handler;

                ExecuteCommandAsync(command, workingDirectory);
            }
            finally
            {
                CommandEvent -= handler;
            }

            idleManager.WaitForExit(_executingProcess);

            result.Output = outputBuilder.ToString();
            result.Error = errorBuilder.ToString();
            result.ExitCode = exitCode;

            return result;
        }
Beispiel #3
0
        public void WaitForExitPollsAllowsExecutableToContinueAfterTimeoutIfIOActivity()
        {
            // Arrange
            var idleTimeout = TimeSpan.MinValue;
            var tracer = new Mock<ITracer>(MockBehavior.Strict);
            var idleManager = new IdleManager(idleTimeout, tracer.Object);
            var process = new Mock<IProcess>(MockBehavior.Strict);

            // Setup
            int num = 10;
            process.SetupGet(f => f.Name)
                   .Returns("Test-Process");
            process.Setup(f => f.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(() =>
                    {
                        if (--num == 0)
                        {
                            return true;
                        }
                        else
                        {
                            Thread.Sleep(10);
                            idleManager.UpdateActivity();
                            return false;
                        }
                    });
            process.Setup(f => f.WaitUntilEOF())
                   .Verifiable();

            // Act
            idleManager.WaitForExit(process.Object);

            // Assert
            process.Verify();
            Assert.Equal(0, num);
        }
        private static async Task CopyStreamAsync(Stream from, Stream to, IdleManager idleManager, CancellationToken cancellationToken, bool closeAfterCopy = false)
        {
            try
            {
                byte[] bytes = new byte[1024];
                int read = 0;
                while ((read = await from.ReadAsync(bytes, 0, bytes.Length, cancellationToken)) != 0)
                {
                    idleManager.UpdateActivity();
                    await to.WriteAsync(bytes, 0, read, cancellationToken);
                }

                idleManager.UpdateActivity();
            }
            finally
            {
                // this is needed specifically for input stream
                // in order to tell executable that the input is done
                if (closeAfterCopy)
                {
                    to.Close();
                }
            }
        }
Beispiel #5
0
        private Tuple<string, string> ExecuteInternal(ITracer tracer, Func<string, bool> onWriteOutput, Func<string, bool> onWriteError, Encoding encoding, string arguments, params object[] args)
        {
            var cmdArguments = String.Format(arguments, args);
            var errorBuffer = new StringBuilder();
            var outputBuffer = new StringBuilder();
            var idleManager = new IdleManager(IdleTimeout, tracer);
            var outputStream = new AsyncStreamWriter(data =>
            {
                idleManager.UpdateActivity();
                if (data != null)
                {
                    if (onWriteOutput(data))
                    {
                        outputBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(data)));
                    }
                }
            }, Encoding ?? Console.OutputEncoding);
            var errorStream = new AsyncStreamWriter(data =>
            {
                idleManager.UpdateActivity();
                if (data != null)
                {
                    if (onWriteError(data))
                    {
                        errorBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(data)));
                    }
                }
            }, Encoding ?? Console.OutputEncoding);

            int exitCode;
            try
            {
                // common execute
                exitCode = Task.Run(() => ExecuteAsync(tracer, cmdArguments, outputStream, errorStream, idleManager: idleManager)).Result;
            }
            catch (AggregateException ex)
            {
                foreach (var inner in ex.Flatten().InnerExceptions)
                {
                    onWriteError(inner.Message);
                }
                throw;
            }
            catch (Exception ex)
            {
                onWriteError(ex.Message);
                throw;
            }
            finally
            {
                // flush out last buffer if any
                outputStream.Dispose();
                errorStream.Dispose();
            }

            string output = outputBuffer.ToString().Trim();
            string error = errorBuffer.ToString().Trim();

            if (exitCode != 0)
            {
                throw new CommandLineException(Path, cmdArguments, !String.IsNullOrEmpty(error) ? error : output)
                {
                    ExitCode = exitCode,
                    Output = output,
                    Error = error
                };
            }

            return Tuple.Create(output, error);
        }
Beispiel #6
0
        public Tuple <string, string> Execute(ITracer tracer, Func <string, bool> onWriteOutput, Func <string, bool> onWriteError, Encoding encoding, string arguments, params object[] args)
        {
            using (GetProcessStep(tracer, arguments, args))
            {
                Process process = CreateProcess(arguments, args);
                process.EnableRaisingEvents = true;

                var errorBuffer  = new StringBuilder();
                var outputBuffer = new StringBuilder();

                var idleManager = new IdleManager(IdleTimeout, tracer);
                process.OutputDataReceived += (sender, e) =>
                {
                    idleManager.UpdateActivity();
                    if (e.Data != null)
                    {
                        if (onWriteOutput(e.Data))
                        {
                            outputBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(e.Data)));
                        }
                    }
                };

                process.ErrorDataReceived += (sender, e) =>
                {
                    idleManager.UpdateActivity();
                    if (e.Data != null)
                    {
                        if (onWriteError(e.Data))
                        {
                            errorBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(e.Data)));
                        }
                    }
                };

                process.Start();

                process.BeginErrorReadLine();
                process.BeginOutputReadLine();

                try
                {
                    idleManager.WaitForExit(process);
                }
                catch (Exception ex)
                {
                    onWriteError(ex.Message);
                    throw;
                }

                tracer.TraceProcessExitCode(process);

                string output = outputBuffer.ToString().Trim();
                string error  = errorBuffer.ToString().Trim();

                if (process.ExitCode != 0)
                {
                    string text = String.IsNullOrEmpty(error) ? output : error;

                    throw new CommandLineException(Path, process.StartInfo.Arguments, text)
                          {
                              ExitCode = process.ExitCode,
                              Output   = output,
                              Error    = error
                          };
                }

                return(Tuple.Create(output, error));
            }
        }
Beispiel #7
0
        public void Execute(ITracer tracer, Stream input, Stream output, string arguments, params object[] args)
        {
            using (GetProcessStep(tracer, arguments, args))
            {
                var process = CreateProcess(arguments, args);
                process.Start();

                var idleManager = new IdleManager(IdleTimeout, tracer, output);
                Func <StreamReader, string>   reader     = (StreamReader streamReader) => streamReader.ReadToEnd();
                Action <Stream, Stream, bool> copyStream = (Stream from, Stream to, bool closeAfterCopy) =>
                {
                    try
                    {
                        byte[] bytes      = new byte[1024];
                        int    read       = 0;
                        bool   writeError = false;
                        while ((read = from.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            idleManager.UpdateActivity();
                            try
                            {
                                if (!writeError)
                                {
                                    to.Write(bytes, 0, read);
                                }
                            }
                            catch (Exception ex)
                            {
                                writeError = true;
                                tracer.TraceError(ex);
                            }
                        }

                        idleManager.UpdateActivity();
                        if (closeAfterCopy)
                        {
                            to.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        tracer.TraceError(ex);
                    }
                };

                IAsyncResult errorReader = reader.BeginInvoke(process.StandardError, null, null);
                IAsyncResult inputResult = null;

                if (input != null)
                {
                    // Copy into the input stream, and close it to tell the exe it can process it
                    inputResult = copyStream.BeginInvoke(input,
                                                         process.StandardInput.BaseStream,
                                                         true,
                                                         null,
                                                         null);
                }

                // Copy the exe's output into the output stream
                IAsyncResult outputResult = copyStream.BeginInvoke(process.StandardOutput.BaseStream,
                                                                   output,
                                                                   false,
                                                                   null,
                                                                   null);

                idleManager.WaitForExit(process);

                // Wait for the input operation to complete
                if (inputResult != null)
                {
                    inputResult.AsyncWaitHandle.WaitOne();
                }

                // Wait for the output operation to be complete
                outputResult.AsyncWaitHandle.WaitOne();

                string error = reader.EndInvoke(errorReader);

                tracer.TraceProcessExitCode(process);

                if (process.ExitCode != 0)
                {
                    throw new CommandLineException(Path, process.StartInfo.Arguments, error)
                          {
                              ExitCode = process.ExitCode,
                              Error    = error
                          };
                }
            }
        }
Beispiel #8
0
        public Tuple<string, string> Execute(string arguments, params object[] args)
#endif
        {

#if !SITEMANAGEMENT
            using (GetProcessStep(tracer, arguments, args))
            {
#endif
                var process = CreateProcess(arguments, args);
                process.Start();

#if !SITEMANAGEMENT
                var idleManager = new IdleManager(Path, IdleTimeout, tracer);
#else
                var idleManager = new IdleManager();
#endif
                Func<StreamReader, string> reader = (StreamReader streamReader) =>
                {
                    var strb = new StringBuilder();
                    char[] buffer = new char[1024];
                    int read;
                    while ((read = streamReader.ReadBlock(buffer, 0, buffer.Length)) != 0)
                    {
                        idleManager.UpdateActivity();
                        strb.Append(buffer, 0, read);
                    }
                    idleManager.UpdateActivity();
                    return strb.ToString();
                };

                IAsyncResult outputReader = reader.BeginInvoke(process.StandardOutput, null, null);
                IAsyncResult errorReader = reader.BeginInvoke(process.StandardError, null, null);

                process.StandardInput.Close();

                idleManager.WaitForExit(process);

                string output = reader.EndInvoke(outputReader);
                string error = reader.EndInvoke(errorReader);

#if !SITEMANAGEMENT
                tracer.Trace("Process dump", new Dictionary<string, string>
                {
                    { "exitCode", process.ExitCode.ToString() },
                    { "type", "processOutput" }
                });
#endif

                // Sometimes, we get an exit code of 1 even when the command succeeds (e.g. with 'git reset .').
                // So also make sure there is an error string
                if (process.ExitCode != 0)
                {
                    string text = String.IsNullOrEmpty(error) ? output : error;

                    throw new CommandLineException(text)
                    {
                        ExitCode = process.ExitCode,
                        Output = output,
                        Error = error
                    };
                }

                return Tuple.Create(output, error);

#if !SITEMANAGEMENT
            }
#endif
        }
Beispiel #9
0
        public Tuple<string, string> Execute(ITracer tracer, Func<string, bool> onWriteOutput, Func<string, bool> onWriteError, Encoding encoding, string arguments, params object[] args)
        {
            using (GetProcessStep(tracer, arguments, args))
            {
                Process process = CreateProcess(arguments, args);
                process.EnableRaisingEvents = true;

                var errorBuffer = new StringBuilder();
                var outputBuffer = new StringBuilder();

                var idleManager = new IdleManager(Path, IdleTimeout, tracer);
                process.OutputDataReceived += (sender, e) =>
                {
                    idleManager.UpdateActivity();
                    if (e.Data != null)
                    {
                        if (onWriteOutput(e.Data))
                        {
                            outputBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(e.Data)));
                        }
                    }
                };

                process.ErrorDataReceived += (sender, e) =>
                {
                    idleManager.UpdateActivity();
                    if (e.Data != null)
                    {
                        if (onWriteError(e.Data))
                        {
                            errorBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(e.Data)));
                        }
                    }
                };

                process.Start();

                process.BeginErrorReadLine();
                process.BeginOutputReadLine();

                try
                {
                    idleManager.WaitForExit(process);
                }
                catch (Exception ex)
                {
                    onWriteError(ex.Message);
                    throw;
                }

                tracer.Trace("Process dump", new Dictionary<string, string>
                {
                    { "exitCode", process.ExitCode.ToString() },
                    { "type", "processOutput" }
                });

                string output = outputBuffer.ToString().Trim();
                string error = errorBuffer.ToString().Trim();

                if (process.ExitCode != 0)
                {
                    string text = String.IsNullOrEmpty(error) ? output : error;

                    throw new CommandLineException(text)
                    {
                        ExitCode = process.ExitCode,
                        Output = output,
                        Error = error
                    };
                }

                return Tuple.Create(output, error);
            }
        }
Beispiel #10
0
        public void Execute(ITracer tracer, Stream input, Stream output, string arguments, params object[] args)
        {
            using (GetProcessStep(tracer, arguments, args))
            {
                var process = CreateProcess(arguments, args);
                process.Start();

                var idleManager = new IdleManager(Path, IdleTimeout, tracer);
                Func<StreamReader, string> reader = (StreamReader streamReader) => streamReader.ReadToEnd();
                Action<Stream, Stream, bool> copyStream = (Stream from, Stream to, bool closeAfterCopy) =>
                {
                    try
                    {
                        byte[] bytes = new byte[1024];
                        int read = 0;
                        while ((read = from.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            idleManager.UpdateActivity();
                            to.Write(bytes, 0, read);
                        }

                        idleManager.UpdateActivity();
                        if (closeAfterCopy)
                        {
                            to.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        tracer.TraceError(ex);
                    }
                };

                IAsyncResult errorReader = reader.BeginInvoke(process.StandardError, null, null);
                IAsyncResult inputResult = null;

                if (input != null)
                {
                    // Copy into the input stream, and close it to tell the exe it can process it
                    inputResult = copyStream.BeginInvoke(input,
                                                         process.StandardInput.BaseStream,
                                                         true,
                                                         null,
                                                         null);
                }

                // Copy the exe's output into the output stream
                IAsyncResult outputResult = copyStream.BeginInvoke(process.StandardOutput.BaseStream,
                                                                   output,
                                                                   false,
                                                                   null,
                                                                   null);

                idleManager.WaitForExit(process);

                // Wait for the input operation to complete
                if (inputResult != null)
                {
                    inputResult.AsyncWaitHandle.WaitOne();
                }

                // Wait for the output operation to be complete
                outputResult.AsyncWaitHandle.WaitOne();

                string error = reader.EndInvoke(errorReader);

                tracer.Trace("Process dump", new Dictionary<string, string>
                {
                    { "exitCode", process.ExitCode.ToString() },
                    { "type", "processOutput" }
                });

                if (process.ExitCode != 0)
                {
                    throw new CommandLineException(error)
                    {
                        ExitCode = process.ExitCode,
                        Error = error
                    };
                }
            }
        }
Beispiel #11
0
        public void WaitForExitPollsAllowsExecutableToContinueAfterTimeoutIfCpuOrIOActivity()
        {
            // Arrange
            var idleTimeout = TimeSpan.MinValue;
            var tracer = new Mock<ITracer>(MockBehavior.Strict);
            var idleManager = new IdleManager(idleTimeout, tracer.Object);
            var process = new Mock<IProcess>(MockBehavior.Strict);

            // Setup
            int num = 10;
            process.SetupGet(f => f.Name)
                   .Returns("Test-Process");
            process.Setup(f => f.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(() => --num == 0);
            process.Setup(f => f.GetTotalProcessorTime(It.IsAny<ITracer>()))
                   .Returns(() => 
                   {
                       Thread.Sleep(10);
                       idleManager.UpdateActivity(); 
                       return TimeSpan.FromSeconds(5); 
                   })
                   .Verifiable();
            process.Setup(f => f.WaitUntilEOF())
                   .Verifiable();
            tracer.Setup(t => t.Trace(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()))
                  .Verifiable();

            // Act
            idleManager.WaitForExit(process.Object);

            // Assert
            process.Verify();
            Assert.Equal(0, num);
        }
Beispiel #12
0
        private Tuple <string, string> ExecuteInternal(ITracer tracer, Func <string, bool> onWriteOutput, Func <string, bool> onWriteError, Encoding encoding, string arguments, params object[] args)
        {
            var cmdArguments = String.Format(arguments, args);
            var errorBuffer  = new StringBuilder();
            var outputBuffer = new StringBuilder();
            var idleManager  = new IdleManager(IdleTimeout, tracer);
            var outputStream = new AsyncStreamWriter(data =>
            {
                idleManager.UpdateActivity();
                if (data != null)
                {
                    if (onWriteOutput(data))
                    {
                        outputBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(data)));
                    }
                }
            }, Encoding ?? Console.OutputEncoding);
            var errorStream = new AsyncStreamWriter(data =>
            {
                idleManager.UpdateActivity();
                if (data != null)
                {
                    if (onWriteError(data))
                    {
                        errorBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(data)));
                    }
                }
            }, Encoding ?? Console.OutputEncoding);

            int exitCode;

            try
            {
                // common execute
                exitCode = Task.Run(() => ExecuteAsync(tracer, cmdArguments, outputStream, errorStream, idleManager: idleManager)).Result;
            }
            catch (AggregateException ex)
            {
                foreach (var inner in ex.Flatten().InnerExceptions)
                {
                    onWriteError(inner.Message);
                }
                throw;
            }
            catch (Exception ex)
            {
                onWriteError(ex.Message);
                throw;
            }
            finally
            {
                // flush out last buffer if any
                outputStream.Dispose();
                errorStream.Dispose();
            }

            string output = outputBuffer.ToString().Trim();
            string error  = errorBuffer.ToString().Trim();

            if (exitCode != 0)
            {
                throw new CommandLineException(Path, cmdArguments, error)
                      {
                          ExitCode = exitCode,
                          Output   = output,
                          Error    = error
                      };
            }

            return(Tuple.Create(output, error));
        }