/// <summary>
        /// Starts a child process as specified in <paramref name="startInfo"/>.
        /// </summary>
        /// <param name="startInfo"><see cref="ChildProcessStartInfo"/>.</param>
        /// <returns>The started process.</returns>
        /// <exception cref="IOException">Failed to open a specified file.</exception>
        /// <exception cref="ProcessCreationFailedException">Process creation failed.</exception>
        public static ChildProcess Start(ChildProcessStartInfo startInfo)
        {
            startInfo = startInfo ?? throw new ArgumentNullException(nameof(startInfo));

            using (var stdHandles = new PipelineStdHandleCreator(startInfo))
            {
                var processHandle = ProcessPal.SpawnProcess(
                    fileName: startInfo.FileName,
                    arguments: startInfo.Arguments,
                    workingDirectory: startInfo.WorkingDirectory,
                    environmentVariables: startInfo.EnvironmentVariables,
                    stdIn: stdHandles.PipelineStdIn,
                    stdOut: stdHandles.PipelineStdOut,
                    stdErr: stdHandles.PipelineStdErr);

                try
                {
                    var process = new ChildProcess(processHandle, stdHandles.InputStream, stdHandles.OutputStream, stdHandles.ErrorStream);
                    stdHandles.DetachStreams();
                    return(process);
                }
                catch
                {
                    processHandle.Dispose();
                    throw;
                }
            }
        }
        public async Task PipesAreAsynchronous()
        {
            var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoBack")
            {
                StdInputRedirection  = InputRedirection.InputPipe,
                StdOutputRedirection = OutputRedirection.OutputPipe,
                StdErrorRedirection  = OutputRedirection.ErrorPipe,
            };

            using (var sut = ChildProcess.Start(si))
            {
                Assert.True(((FileStream)sut.StandardInput).IsAsync);
                Assert.True(((FileStream)sut.StandardOutput).IsAsync);
                Assert.True(((FileStream)sut.StandardError).IsAsync);

                using (var sr = new StreamReader(sut.StandardOutput))
                {
                    const string text       = "foobar";
                    var          stdoutTask = sr.ReadToEndAsync();
                    using (var sw = new StreamWriter(sut.StandardInput))
                    {
                        await sw.WriteAsync(text);
                    }
                    Assert.Equal(text, await stdoutTask);
                }

                sut.WaitForExit();
                Assert.Equal(0, sut.ExitCode);
            }
        }
Example #3
0
        public async Task CorrectlyConnectOutputPipes()
        {
            {
                var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoOutAndError")
                {
                    StdOutputRedirection = OutputRedirection.OutputPipe,
                    StdErrorRedirection  = OutputRedirection.ErrorPipe,
                };

                using (var sut = ChildProcess.Start(si))
                {
                    await ChildProcessAssert.CorrectlyConnectsPipesAsync(sut, "TestChild.Out", "TestChild.Error");
                }
            }

            {
                // invert stdout and stderr
                var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoOutAndError")
                {
                    StdOutputRedirection = OutputRedirection.ErrorPipe,
                    StdErrorRedirection  = OutputRedirection.OutputPipe,
                };

                using (var sut = ChildProcess.Start(si))
                {
                    await ChildProcessAssert.CorrectlyConnectsPipesAsync(sut, "TestChild.Error", "TestChild.Out");
                }
            }
        }
Example #4
0
        public void RedirectionToHandle()
        {
            using (var tmp = new TemporaryDirectory())
            {
                var inFile  = Path.Combine(tmp.Location, "in");
                var outFile = Path.Combine(tmp.Location, "out");
                var errFile = Path.Combine(tmp.Location, "err");

                // StdOutputHandle StdErrorHandle
                {
                    using (var fsOut = File.Create(outFile))
                        using (var fsErr = File.Create(errFile))
                        {
                            // File
                            var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoOutAndError")
                            {
                                StdOutputRedirection = OutputRedirection.Handle,
                                StdOutputHandle      = fsOut.SafeFileHandle,
                                StdErrorRedirection  = OutputRedirection.Handle,
                                StdErrorHandle       = fsErr.SafeFileHandle,
                            };

                            using (var sut = ChildProcess.Start(si))
                            {
                                sut.WaitForExit();
                                Assert.True(sut.IsSuccessful);
                            }
                        }

                    Assert.Equal("TestChild.Out", File.ReadAllText(outFile));
                    Assert.Equal("TestChild.Error", File.ReadAllText(errFile));
                }

                // StdInputHandle
                {
                    const string text = "foobar";
                    File.WriteAllText(inFile, text);

                    using (var fsIn = File.OpenRead(inFile))
                    {
                        var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoBack")
                        {
                            StdInputRedirection  = InputRedirection.Handle,
                            StdInputHandle       = fsIn.SafeFileHandle,
                            StdOutputRedirection = OutputRedirection.File,
                            StdOutputFile        = outFile,
                        };

                        using (var sut = ChildProcess.Start(si))
                        {
                            sut.WaitForExit();
                            Assert.True(sut.IsSuccessful);
                        }
                    }

                    Assert.Equal(text, File.ReadAllText(outFile));
                }
            }
        }
Example #5
0
        private static ChildProcess CreateForWaitForExitTest()
        {
            var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoBack")
            {
                StdInputRedirection  = InputRedirection.InputPipe,
                StdOutputRedirection = OutputRedirection.NullDevice,
            };

            return(ChildProcess.Start(si));
        }
Example #6
0
        public void CanCreateChildProcess()
        {
            var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath)
            {
                StdOutputRedirection = OutputRedirection.OutputPipe,
            };

            using (var sut = ChildProcess.Start(si))
            {
                ChildProcessAssert.CanCreateChildProcess(sut);
            }
        }
Example #7
0
        public void ChildProcessWaitForAsyncIsTrulyAsynchronous()
        {
            var si = new ChildProcessStartInfo(TestUtil.TestChildPath, "Sleep", "1000")
            {
                StdOutputRedirection = OutputRedirection.NullDevice,
                StdErrorRedirection  = OutputRedirection.NullDevice,
            };

            using (var sut = ChildProcess.Start(si))
            {
                WaitForAsyncIsTrulyAsynchronous(sut);
            }
        }
Example #8
0
        public void ChildProcessWaitForAsyncIsTrulyAsynchronous()
        {
            var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath, "Sleep", "1000")
            {
                StdOutputRedirection = OutputRedirection.NullDevice,
                StdErrorRedirection  = OutputRedirection.NullDevice,
            };

            using var sut = ChildProcess.Start(si);
            WaitForAsyncIsTrulyAsynchronous(sut);
            sut.WaitForExit();
            Assert.True(sut.IsSuccessful);
        }
Example #9
0
        public async Task PipesAreAsynchronous()
        {
            var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoBack")
            {
                StdInputRedirection  = InputRedirection.InputPipe,
                StdOutputRedirection = OutputRedirection.OutputPipe,
                StdErrorRedirection  = OutputRedirection.ErrorPipe,
            };

            using (var sut = ChildProcess.Start(si))
            {
                await ChildProcessAssert.PipesAreAsynchronousAsync(sut);
            }
        }
Example #10
0
        /// <summary>
        /// Starts a child process as specified in <paramref name="startInfo"/>.
        /// </summary>
        /// <param name="startInfo"><see cref="ChildProcessStartInfo"/>.</param>
        /// <returns>The started process.</returns>
        /// <exception cref="ArgumentException"><paramref name="startInfo"/> has an invalid value.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="startInfo"/> is null.</exception>
        /// <exception cref="FileNotFoundException">The executable not found.</exception>
        /// <exception cref="IOException">Failed to open a specified file.</exception>
        /// <exception cref="AsmichiChildProcessLibraryCrashedException">The operation failed due to critical disturbance.</exception>
        /// <exception cref="Win32Exception">Another kind of native errors.</exception>
        public static IChildProcess Start(ChildProcessStartInfo startInfo)
        {
            _ = startInfo ?? throw new ArgumentNullException(nameof(startInfo));

            var startInfoInternal = new ChildProcessStartInfoInternal(startInfo);

            _ = startInfoInternal.FileName ?? throw new ArgumentException("ChildProcessStartInfo.FileName must not be null.", nameof(startInfo));
            _ = startInfoInternal.Arguments ?? throw new ArgumentException("ChildProcessStartInfo.Arguments must not be null.", nameof(startInfo));

            var flags = startInfoInternal.Flags;

            if (flags.HasUseCustomCodePage() && !flags.HasCreateNewConsole())
            {
                throw new ArgumentException(
                          $"{nameof(ChildProcessFlags.UseCustomCodePage)} requires {nameof(ChildProcessFlags.CreateNewConsole)}.", nameof(startInfo));
            }

            var resolvedPath = ResolveExecutablePath(startInfoInternal.FileName, startInfoInternal.Flags);

            using var stdHandles = new PipelineStdHandleCreator(ref startInfoInternal);
            IChildProcessStateHolder processState;

            try
            {
                processState = ChildProcessContext.Shared.SpawnProcess(
                    startInfo: ref startInfoInternal,
                    resolvedPath: resolvedPath,
                    stdIn: stdHandles.PipelineStdIn,
                    stdOut: stdHandles.PipelineStdOut,
                    stdErr: stdHandles.PipelineStdErr);
            }
            catch (Win32Exception ex)
            {
                if (EnvironmentPal.IsFileNotFoundError(ex.NativeErrorCode))
                {
                    ThrowHelper.ThrowExecutableNotFoundException(resolvedPath, startInfoInternal.Flags, ex);
                }

                // Win32Exception does not provide detailed information by its type.
                // The NativeErrorCode and Message property should be enough because normally there is
                // nothing we can do to programmatically recover from this error.
                throw;
            }

            var process = new ChildProcessImpl(processState, stdHandles.InputStream, stdHandles.OutputStream, stdHandles.ErrorStream);

            stdHandles.DetachStreams();
            return(process);
        }
Example #11
0
        public void CanCreateChildProcess()
        {
            var si = new ChildProcessStartInfo(TestUtil.DotnetCommandName, TestUtil.TestChildPath)
            {
                StdOutputRedirection = OutputRedirection.OutputPipe,
            };

            using var sut = ChildProcess.Start(si);
            sut.WaitForExit();
            Assert.Equal(0, sut.ExitCode);

            // This closes StandardOutput, which should be acceptable.
            using var sr = new StreamReader(sut.StandardOutput !);
            Assert.Equal("TestChild", sr.ReadToEnd());
        }
Example #12
0
        public void DefaultValueTest()
        {
            var sut = new ChildProcessStartInfo();

            Assert.Equal(InputRedirection.NullDevice, sut.StdInputRedirection);
            Assert.Equal(OutputRedirection.ParentOutput, sut.StdOutputRedirection);
            Assert.Equal(OutputRedirection.ParentError, sut.StdErrorRedirection);
            Assert.Null(sut.StdInputFile);
            Assert.Null(sut.StdInputHandle);
            Assert.Null(sut.StdOutputFile);
            Assert.Null(sut.StdOutputHandle);
            Assert.Null(sut.StdErrorFile);
            Assert.Null(sut.StdErrorHandle);
            Assert.Null(sut.FileName);
            Assert.Null(sut.Arguments);
            Assert.Null(sut.WorkingDirectory);
            Assert.Null(sut.EnvironmentVariables);
        }
Example #13
0
        public void CanRedirectToSameFile()
        {
            using (var tmp = new TemporaryDirectory())
            {
                var outFile = Path.Combine(tmp.Location, "out");

                // StdOutputFile StdErrorFile
                {
                    // File
                    var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoOutAndError")
                    {
                        StdOutputRedirection = OutputRedirection.File,
                        StdOutputFile        = outFile,
                        StdErrorRedirection  = OutputRedirection.File,
                        StdErrorFile         = outFile,
                    };

                    using (var sut = ChildProcess.Start(si))
                    {
                        sut.WaitForExit();
                        Assert.True(sut.IsSuccessful);
                    }

                    Assert.Equal("TestChild.OutTestChild.Error", File.ReadAllText(outFile));

                    // AppendToFile
                    si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoOutAndError")
                    {
                        StdOutputRedirection = OutputRedirection.AppendToFile,
                        StdOutputFile        = outFile,
                        StdErrorRedirection  = OutputRedirection.AppendToFile,
                        StdErrorFile         = outFile,
                    };

                    using (var sut = ChildProcess.Start(si))
                    {
                        sut.WaitForExit();
                        Assert.True(sut.IsSuccessful);
                    }

                    Assert.Equal("TestChild.OutTestChild.ErrorTestChild.OutTestChild.Error", File.ReadAllText(outFile));
                }
            }
        }
Example #14
0
        public void ExitCodeThrowsBeforeChildExits()
        {
            var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "EchoBack")
            {
                StdInputRedirection = InputRedirection.InputPipe,
            };

            using (var sut = ChildProcess.Start(si))
            {
                Assert.Throws <InvalidOperationException>(() => sut.IsSuccessful);
                Assert.Throws <InvalidOperationException>(() => sut.ExitCode);

                sut.StandardInput.Close();
                sut.WaitForExit();

                Assert.True(sut.IsSuccessful);
                Assert.Equal(0, sut.ExitCode);
            }
        }
        public void DefaultValueTest()
        {
            var sut = new ChildProcessStartInfo();

            Assert.Equal(InputRedirection.NullDevice, sut.StdInputRedirection);
            Assert.Equal(OutputRedirection.ParentOutput, sut.StdOutputRedirection);
            Assert.Equal(OutputRedirection.ParentError, sut.StdErrorRedirection);
            Assert.Null(sut.StdInputFile);
            Assert.Null(sut.StdInputHandle);
            Assert.Null(sut.StdOutputFile);
            Assert.Null(sut.StdOutputHandle);
            Assert.Null(sut.StdErrorFile);
            Assert.Null(sut.StdErrorHandle);
            Assert.Null(sut.FileName);
            Assert.Equal(sut.Arguments, Array.Empty <string>());
            Assert.Null(sut.WorkingDirectory);
            Assert.Null(sut.EnvironmentVariables);
            Assert.Equal(ChildProcessFlags.None, sut.Flags);
            Assert.Equal(65001, sut.CodePage);
        }
Example #16
0
        public ChildProcessStartInfoInternal(ChildProcessStartInfo startInfo)
        {
            FileName             = startInfo.FileName;
            Arguments            = startInfo.Arguments;
            WorkingDirectory     = startInfo.WorkingDirectory;
            EnvironmentVariables = startInfo.EnvironmentVariables;
            Flags                = startInfo.Flags;
            CodePage             = startInfo.CodePage;
            SearchPath           = startInfo.SearchPath;
            StdInputRedirection  = startInfo.StdInputRedirection;
            StdOutputRedirection = startInfo.StdOutputRedirection;
            StdErrorRedirection  = startInfo.StdErrorRedirection;
            StdInputFile         = startInfo.StdInputFile;
            StdOutputFile        = startInfo.StdOutputFile;
            StdErrorFile         = startInfo.StdErrorFile;
            StdInputHandle       = startInfo.StdInputHandle;
            StdOutputHandle      = startInfo.StdOutputHandle;
            StdErrorHandle       = startInfo.StdErrorHandle;

            // Additional parameters
            CreateNewConsole = Flags.HasCreateNewConsole() || !ConsolePal.HasConsoleWindow();
        }
Example #17
0
        public void CanObtainExitCode()
        {
            {
                var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "ExitCode", "0");

                using (var sut = ChildProcess.Start(si))
                {
                    sut.WaitForExit();
                    Assert.True(sut.IsSuccessful);
                    Assert.Equal(0, sut.ExitCode);
                }
            }

            {
                var si = new ChildProcessStartInfo(TestUtil.DotnetCommand, TestUtil.TestChildPath, "ExitCode", "-1");

                using (var sut = ChildProcess.Start(si))
                {
                    sut.WaitForExit();
                    Assert.False(sut.IsSuccessful);
                    Assert.Equal(-1, sut.ExitCode);
                }
            }
        }
        public void RedirectionToFile()
        {
            using (var tmp = new TemporaryDirectory())
            {
                var inFile  = Path.Combine(tmp.Location, "in");
                var outFile = Path.Combine(tmp.Location, "out");
                var errFile = Path.Combine(tmp.Location, "err");

                // StdOutputFile StdErrorFile
                {
                    // File
                    var si = new ChildProcessStartInfo(TestUtil.TestChildPath, "EchoOutAndError")
                    {
                        StdOutputRedirection = OutputRedirection.File,
                        StdOutputFile        = outFile,
                        StdErrorRedirection  = OutputRedirection.File,
                        StdErrorFile         = errFile,
                    };

                    using (var sut = ChildProcess.Start(si))
                    {
                        sut.WaitForExit();
                        Assert.True(sut.IsSuccessful);
                    }

                    Assert.Equal("TestChild.Out", File.ReadAllText(outFile));
                    Assert.Equal("TestChild.Error", File.ReadAllText(errFile));

                    // AppendToFile
                    si = new ChildProcessStartInfo(TestUtil.TestChildPath, "EchoOutAndError")
                    {
                        StdOutputRedirection = OutputRedirection.AppendToFile,
                        StdOutputFile        = errFile,
                        StdErrorRedirection  = OutputRedirection.AppendToFile,
                        StdErrorFile         = outFile,
                    };

                    using (var sut = ChildProcess.Start(si))
                    {
                        sut.WaitForExit();
                        Assert.True(sut.IsSuccessful);
                    }

                    Assert.Equal("TestChild.OutTestChild.Error", File.ReadAllText(outFile));
                    Assert.Equal("TestChild.ErrorTestChild.Out", File.ReadAllText(errFile));
                }

                // StdInputFile
                {
                    const string text = "foobar";
                    File.WriteAllText(inFile, text);

                    var si = new ChildProcessStartInfo(TestUtil.TestChildPath, "EchoBack")
                    {
                        StdInputRedirection  = InputRedirection.File,
                        StdInputFile         = inFile,
                        StdOutputRedirection = OutputRedirection.File,
                        StdOutputFile        = outFile,
                    };

                    using (var sut = ChildProcess.Start(si))
                    {
                        sut.WaitForExit();
                        Assert.True(sut.IsSuccessful);
                    }

                    Assert.Equal(text, File.ReadAllText(outFile));
                }
            }
        }
Example #19
0
        public void ReportsCreationFailure()
        {
            var si = new ChildProcessStartInfo("nonexistentfile");

            Assert.Throws <ProcessCreationFailedException>(() => ChildProcess.Start(si));
        }
        public PipelineStdHandleCreator(ChildProcessStartInfo startInfo)
        {
            var stdInputRedirection  = startInfo.StdInputRedirection;
            var stdOutputRedirection = startInfo.StdOutputRedirection;
            var stdErrorRedirection  = startInfo.StdErrorRedirection;
            var stdInputFile         = startInfo.StdInputFile;
            var stdOutputFile        = startInfo.StdOutputFile;
            var stdErrorFile         = startInfo.StdErrorFile;
            var stdInputHandle       = startInfo.StdInputHandle;
            var stdOutputHandle      = startInfo.StdOutputHandle;
            var stdErrorHandle       = startInfo.StdErrorHandle;

            if (stdInputRedirection == InputRedirection.Handle && stdInputHandle == null)
            {
                throw new ArgumentNullException(nameof(startInfo), "ChildProcessStartInfo.StdInputHandle must not be null.");
            }
            if (stdInputRedirection == InputRedirection.File && stdInputFile == null)
            {
                throw new ArgumentNullException(nameof(startInfo), "ChildProcessStartInfo.StdInputFile must not be null.");
            }
            if (stdOutputRedirection == OutputRedirection.Handle && stdOutputHandle == null)
            {
                throw new ArgumentNullException(nameof(startInfo), "ChildProcessStartInfo.StdOutputHandle must not be null.");
            }
            if (IsFileRedirection(stdOutputRedirection) && stdOutputFile == null)
            {
                throw new ArgumentNullException(nameof(startInfo), "ChildProcessStartInfo.StdOutputFile must not be null.");
            }
            if (stdErrorRedirection == OutputRedirection.Handle && stdErrorHandle == null)
            {
                throw new ArgumentNullException(nameof(startInfo), "ChildProcessStartInfo.StdErrorHandle must not be null.");
            }
            if (IsFileRedirection(stdErrorRedirection) && stdErrorFile == null)
            {
                throw new ArgumentNullException(nameof(startInfo), "ChildProcessStartInfo.StdErrorFile must not be null.");
            }

            bool redirectingToSameFile = IsFileRedirection(stdOutputRedirection) && IsFileRedirection(stdErrorRedirection) && stdOutputFile == stdErrorFile;

            if (redirectingToSameFile && stdErrorRedirection != stdOutputRedirection)
            {
                throw new ArgumentException(
                          "StdOutputRedirection and StdErrorRedirection must be the same value when both stdout and stderr redirect to the same file.",
                          nameof(startInfo));
            }

            try
            {
                if (stdInputRedirection == InputRedirection.InputPipe)
                {
                    (this.InputStream, _inputReadPipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.Out);
                }

                if (stdOutputRedirection == OutputRedirection.OutputPipe ||
                    stdErrorRedirection == OutputRedirection.OutputPipe)
                {
                    (this.OutputStream, _outputWritePipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.In);
                }

                if (stdOutputRedirection == OutputRedirection.ErrorPipe ||
                    stdErrorRedirection == OutputRedirection.ErrorPipe)
                {
                    (this.ErrorStream, _errorWritePipe) = FilePal.CreatePipePairWithAsyncServerSide(System.IO.Pipes.PipeDirection.In);
                }

                this.PipelineStdIn = ChooseInput(
                    stdInputRedirection,
                    stdInputFile,
                    stdInputHandle,
                    _inputReadPipe);

                this.PipelineStdOut = ChooseOutput(
                    stdOutputRedirection,
                    stdOutputFile,
                    stdOutputHandle,
                    _outputWritePipe,
                    _errorWritePipe);

                if (redirectingToSameFile)
                {
                    this.PipelineStdErr = this.PipelineStdOut;
                }
                else
                {
                    this.PipelineStdErr = ChooseOutput(
                        stdErrorRedirection,
                        stdErrorFile,
                        stdErrorHandle,
                        _outputWritePipe,
                        _errorWritePipe);
                }
            }
            catch
            {
                Dispose();
                throw;
            }
        }