<commit_before>﻿//-----------------------------------------------------------------------
// <copyright file="ShellWrapper.cs">(c) http://www.codeplex.com/MSBuildExtensionPack. This source is subject to the Microsoft Permissive License. See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. All other rights reserved.</copyright>
//-----------------------------------------------------------------------
namespace MSBuild.ExtensionPack
{
    using System;
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.IO;

    /// <summary>
    /// ShellExecute.
    /// </summary>
    internal sealed class ShellWrapper
    {
        private System.Collections.Specialized.NameValueCollection envars = new NameValueCollection();

        public ShellWrapper(string executable, string arguments)
        {
            this.Executable = executable;
            this.Arguments = arguments;
        }

        public ShellWrapper(string executable)
        {
            this.Executable = executable;
        }

        /// <summary>
        /// Gets the standard output.
        /// </summary>
        public string StandardOutput { get; private set; }

        /// <summary>
        /// Gets the standard error.
        /// </summary>
        public string StandardError { get; private set; }

        /// <summary>
        /// Gets the exit code.
        /// </summary>
        public int ExitCode { get; private set; }

        /// <summary>
        /// Sets the working directory.
        /// </summary>
        public string WorkingDirectory { get; set; }

        /// <summary>
        /// Sets the Executable.
        /// </summary>
        public string Executable { get; set; }

        /// <summary>
        /// Sets the arguments.
        /// </summary>
        public string Arguments { get; set; }

        public NameValueCollection EnvironmentVariables
        {
            get { return this.envars; }
        }

        /// <summary>
        /// Executes this instance.
        /// </summary>
        /// <returns>int</returns>
        public int Execute()
        {
            Process proc = null;
            try
            {
                string cmdPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "cmd.exe");
                string commandLine = "/C \"" + cmdPath + " /S /C \"\"" + this.Executable + "\" " + this.Arguments;
                ProcessStartInfo startInfo = new ProcessStartInfo(cmdPath, commandLine)
                                                 {
                                                     UseShellExecute = false,
                                                     CreateNoWindow = true,
                                                     WorkingDirectory = this.WorkingDirectory,
                                                     RedirectStandardOutput = true,
                                                     RedirectStandardError = true
                                                 };

                foreach (string key in this.EnvironmentVariables)
                {
                    startInfo.EnvironmentVariables[key] = this.EnvironmentVariables[key];
                }

                proc = System.Diagnostics.Process.Start(startInfo);
                if (proc != null)
                {
                    proc.WaitForExit(Int32.MaxValue);
                    this.StandardOutput = proc.StandardOutput.ReadToEnd();
                    this.StandardError = proc.StandardError.ReadToEnd();
                }
            }
            finally
            {
                // get the exit code and release the process handle
                if (proc != null)
                {
                    if (!proc.HasExited)
                    {
                        // not exited yet within our timeout so kill the process
                        proc.Kill();
                        while (!proc.HasExited)
                        {                            
                            System.Threading.Thread.Sleep(50);
                        }
                    }

                    this.ExitCode = proc.ExitCode;
                    proc.Close();
                }
            }

            return this.ExitCode;
        }
    }
}<commit_msg>ShellWrapper.cs: Fix for deadlocking on a full stdout or stderr buffer<commit_after>﻿//-----------------------------------------------------------------------
// <copyright file="ShellWrapper.cs">(c) http://www.codeplex.com/MSBuildExtensionPack. This source is subject to the Microsoft Permissive License. See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. All other rights reserved.</copyright>
//-----------------------------------------------------------------------
namespace MSBuild.ExtensionPack
{
    using System;
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.IO;
    using System.Text;

    /// <summary>
    /// ShellExecute.
    /// </summary>
    internal sealed class ShellWrapper
    {
        private static StringBuilder stdOut;
        private System.Collections.Specialized.NameValueCollection envars = new NameValueCollection();

        public ShellWrapper(string executable, string arguments)
        {
            this.Executable = executable;
            this.Arguments = arguments;
        }

        public ShellWrapper(string executable)
        {
            this.Executable = executable;
        }

        /// <summary>
        /// Gets the standard output.
        /// </summary>
        public string StandardOutput { get; private set; }

        /// <summary>
        /// Gets the standard error.
        /// </summary>
        public string StandardError { get; private set; }

        /// <summary>
        /// Gets the exit code.
        /// </summary>
        public int ExitCode { get; private set; }

        /// <summary>
        /// Sets the working directory.
        /// </summary>
        public string WorkingDirectory { get; set; }

        /// <summary>
        /// Sets the Executable.
        /// </summary>
        public string Executable { get; set; }

        /// <summary>
        /// Sets the arguments.
        /// </summary>
        public string Arguments { get; set; }

        public NameValueCollection EnvironmentVariables
        {
            get { return this.envars; }
        }

        /// <summary>
        /// Executes this instance.
        /// </summary>
        /// <returns>int</returns>
        public int Execute()
        {
            Process proc = new Process();
            try
            {
                string cmdPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "cmd.exe");
                string commandLine = "/C \"" + cmdPath + " /S /C \"\"" + this.Executable + "\" " + this.Arguments;
                ProcessStartInfo startInfo = new ProcessStartInfo(cmdPath, commandLine)
                                                 {
                                                     UseShellExecute = false,
                                                     CreateNoWindow = true,
                                                     WorkingDirectory = this.WorkingDirectory,
                                                     RedirectStandardOutput = true,
                                                     RedirectStandardError = true
                                                 };

                foreach (string key in this.EnvironmentVariables)
                {
                    startInfo.EnvironmentVariables[key] = this.EnvironmentVariables[key];
                }

                // Set event handler to asynchronously read the output. We need to do this to avoid deadlock conditions.
                stdOut = new StringBuilder(string.Empty);
                proc.OutputDataReceived += SortOutputHandler;

                proc.StartInfo = startInfo;
                proc.Start();
                proc.BeginOutputReadLine();

                // its ok to read the one stream synchronously
                this.StandardError = proc.StandardError.ReadToEnd();

                // wait for exit after reading the streams to avoid deadlock
                proc.WaitForExit(Int32.MaxValue);

                // now we can read all the output.
                this.StandardOutput = stdOut.ToString();
            }
            finally
            {
                // get the exit code and release the process handle
                if (!proc.HasExited)
                {
                    // not exited yet within our timeout so kill the process
                    proc.Kill();
                    while (!proc.HasExited)
                    {
                        System.Threading.Thread.Sleep(50);
                    }
                }

                this.ExitCode = proc.ExitCode;
                proc.Close();
            }

            return this.ExitCode;
        }

        private static void SortOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (!String.IsNullOrEmpty(outLine.Data))
            {
                stdOut.Append(Environment.NewLine + outLine.Data);
            }
        }
    }
}
{'fraction_non_alphanumeric': 0.1155012020487091, 'fraction_numerical': 0.000836207797637713, 'mean_word_length': 1.0804522722330943, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5210820', 'n_tokens_mistral': 2106, 'n_tokens_neox': 1941, 'n_words': 509}