Example #1
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;
        }
Example #2
0
        public static async Task <int> Start(this IProcess process, ITracer tracer, Stream output, Stream error, Stream input = null, IdleManager idleManager = null)
        {
            var cancellationTokenSource = new CancellationTokenSource();

            process.Start();

            var tasks = new List <Task>();

            if (input != null)
            {
                tasks.Add(CopyStreamAsync(input, process.StandardInput.BaseStream, idleManager, cancellationTokenSource.Token, closeAfterCopy: true));
            }

            tasks.Add(CopyStreamAsync(process.StandardOutput.BaseStream, output, idleManager, cancellationTokenSource.Token));
            tasks.Add(CopyStreamAsync(process.StandardError.BaseStream, error, idleManager, cancellationTokenSource.Token));

            idleManager.WaitForExit(process);

            // Process has exited, draining the stdout and stderr
            await FlushAllAsync(process, tracer, idleManager, cancellationTokenSource, tasks);

            return(process.ExitCode);
        }
Example #3
0
        public void WaitForExitWaitsForEOFPriorToExiting()
        {
            // Arrange
            var idleTimeout = DeploymentSettingsExtension.DefaultCommandIdleTimeout;
            var tracer = new Mock<ITracer>(MockBehavior.Strict);
            var idleManager = new IdleManager(idleTimeout, tracer.Object);
            var process = new Mock<IProcess>(MockBehavior.Strict);

            // Setup
            process.SetupGet(f => f.Name)
                   .Returns("Test-Process");
            process.Setup(f => f.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(true)
                   .Verifiable();
            process.Setup(f => f.WaitUntilEOF())
                   .Verifiable();

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

            // Assert
            process.Verify();
        }
Example #4
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);
        }
        public static async Task<int> Start(this IProcess process, ITracer tracer, Stream output, Stream error, Stream input = null, IdleManager idleManager = null)
        {
            var cancellationTokenSource = new CancellationTokenSource();

            process.Start();

            var tasks = new List<Task>();

            if (input != null)
            {
                tasks.Add(CopyStreamAsync(input, process.StandardInput.BaseStream, idleManager, cancellationTokenSource.Token, closeAfterCopy: true));
            }

            tasks.Add(CopyStreamAsync(process.StandardOutput.BaseStream, output, idleManager, cancellationTokenSource.Token));
            tasks.Add(CopyStreamAsync(process.StandardError.BaseStream, error, idleManager, cancellationTokenSource.Token));

            idleManager.WaitForExit(process);

            // Process has exited, draining the stdout and stderr
            await FlushAllAsync(process, tracer, idleManager, cancellationTokenSource, tasks);

            return process.ExitCode;
        }
Example #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));
            }
        }
Example #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
                          };
                }
            }
        }
Example #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
        }
Example #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);
            }
        }
Example #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
                    };
                }
            }
        }
Example #11
0
        public void WaitForExitPollsAllowsExecutableToContinueAfterTimeoutIfCpuActivity()
        {
            // 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, cpu = 0;
            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(() => TimeSpan.FromSeconds(++cpu))
                   .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);
        }
Example #12
0
        public void WaitForExitPollsKillsProcessIfProcessorTimeDoesNotChangeAndNotUpdated()
        {
            // Arrange
            var tracer = new Mock<ITracer>(MockBehavior.Strict);
            DateTime startTime = DateTime.UtcNow;
            TimeSpan idleTimeout = TimeSpan.FromMilliseconds(100);
            var idleManager = new IdleManager(idleTimeout, tracer.Object);
            var process = new Mock<IProcess>(MockBehavior.Strict);

            // Setup
            process.SetupGet(f => f.Name)
                   .Returns("Test-Process");
            process.SetupGet(f => f.Arguments)
                   .Returns("");
            process.Setup(f => f.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(() => { Thread.Sleep(10); return false; });
            process.Setup(f => f.GetTotalProcessorTime(It.IsAny<ITracer>()))
                   .Returns(TimeSpan.Zero);
            process.Setup(f => f.Kill(tracer.Object))
                   .Verifiable();
            tracer.Setup(t => t.Trace(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()))
                  .Verifiable();

            // Act
            var ex = Assert.Throws<CommandLineException>(() => idleManager.WaitForExit(process.Object));

            // Assert
            process.Verify();

            Assert.True(DateTime.UtcNow - startTime >= idleTimeout);
            Assert.Contains("Command 'Test-Process ' aborted due to no output and CPU activity for", ex.Message);
        }