Click here to Skip to main content
15,891,431 members
Articles / Programming Languages / C#

TortoiseHg Manager (Repository Verification)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
1 Sep 2015GPL33 min read 16.2K   147  
TortoiseHgManager, a repositories verification tool for TortoiseHg.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Management;
using System.ComponentModel;

namespace TortoiseHgManager
{
    /// <summary>
    /// Execution result returned from ProcessExecutor
    /// </summary>
    class ProcessResult : EventArgs
    {
        /// <summary>
        /// Standard output lines.
        /// </summary>
        public string[] Output { get; set; }
        /// <summary>
        /// Exit code return from process.
        /// </summary>
        public int ExitCode { get; set; }
        /// <summary>
        /// This flag is set if any stderr message is received.
        /// </summary>
        public bool ErrorDetected { get; set; }

        public ProcessResult() { Output = new string[] { }; }
    }

    /// <summary>
    /// Execute Console based application without showing the console window.
    /// </summary>
    class ProcessExecutor
    {
        ProcessStartInfo processInfo;
        List<string> outputData;
        private bool errorDetected;

        /// <summary>
        /// Constructor
        /// </summary>
        public ProcessExecutor(string name = "Unnamed")
        {
            Name = name;
            TraceLogEnabled = false;
        }
        /// <summary>
        /// Instance Name
        /// </summary>
        [Category("General")]
        public string Name { get; set; }
        /// <summary>
        /// Application EXE - Full path.
        /// </summary>
        [Category("General")]
        public string Application { get; set; }
        /// <summary>
        /// Arguments that passed to application.
        /// </summary>
        [Browsable(false)]
        [Category("General")]
        public string Arguments { get; set; }
        /// <summary>
        /// Start location of command prompt.
        /// </summary>
        [Category("General")]
        public string WorkingDirectory { get; set; }
        /// <summary>
        /// Enable / Disable Trace Log
        /// </summary>
        [Browsable(false)]
        [Category("General")]
        public bool TraceLogEnabled { get; set; }
        
        /// <summary>
        /// Get Process Handler
        /// </summary>
        [Browsable(false)]
        [Category("General")]
        public Process ProcessHandler { get; private set; }

        private bool RedirectToFile;
        private string LogFile;

        /// <summary>
        /// Redirect standard output and standrad error to file. By default, standard output and
        /// standard error are stored in ProcessResult which returned at the end of Execute()
        /// </summary>
        /// <param name="logFile">Target file to store output logs.</param>
        public void RedirectOutputToFile(string logFile)
        {
            LogFile = logFile;
            RedirectToFile = true;
        }

        /// <summary>
        /// Execute process and return result in the form of ProcessResult.
        /// </summary>
        /// <remarks>No exception is expected from this application. Execution error will be reflected in ExitCode.</remarks>
        /// <returns></returns>
        public ProcessResult Execute(bool waitForExit = true)
        {
            ProcessResult result = new ProcessResult();
            outputData = new List<string>();
            errorDetected = false;
            try
            {
                processInfo = new ProcessStartInfo();
                processInfo.FileName = Application;
                if (Application.Contains(" ")) processInfo.FileName = "\"" + processInfo.FileName + "\"";
                processInfo.WorkingDirectory = WorkingDirectory;
                processInfo.Arguments = Arguments;
                processInfo.CreateNoWindow = true;
                processInfo.UseShellExecute = false;
                processInfo.RedirectStandardOutput = true;
                processInfo.RedirectStandardError = true;

                Trace.WriteLine(Name + ": Executing: " + processInfo.FileName + " " + processInfo.Arguments);
                ProcessHandler = Process.Start(processInfo);
                ProcessHandler.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
                ProcessHandler.ErrorDataReceived += new DataReceivedEventHandler(process_ErrorDataReceived);
                ProcessHandler.BeginOutputReadLine();
                ProcessHandler.BeginErrorReadLine();
                if (!waitForExit) return null;

                ProcessHandler.WaitForExit();
                result.ExitCode = ProcessHandler.ExitCode;
            }
            catch (Exception ex)
            {
                result.Output = new string[] { ex.ToString() };
                result.ErrorDetected = true;
                result.ExitCode = -999;
                return result;
            }
            ProcessHandler.OutputDataReceived -= process_OutputDataReceived;
            ProcessHandler.ErrorDataReceived -= process_ErrorDataReceived;

            result.ErrorDetected = errorDetected;
            result.Output = outputData.ToArray();
            return result;
        }

        /// <summary>
        /// Check if the specific tool exists.
        /// </summary>
        /// <returns></returns>
        public void Validate() 
        {
            if (!System.IO.File.Exists(Application))
            {
                throw new System.IO.FileNotFoundException(Application);
            }
        }

        /// <summary>
        /// Get tools version.
        /// </summary>
        /// <param name="command">Command to retrieve version number, e.g. "/?", "--version"</param>
        /// <returns>Version information, null if not success.</returns>
        protected virtual Version Version(string command)
        {
            if(string.IsNullOrEmpty(command)) return null;
            Arguments = command;
            ProcessResult procResult = Execute();
            if (procResult.ExitCode != 0) return null;

            for (int x = 0; x < procResult.Output.Length; x++)
            {
                //Get First non-empty line
                if (string.IsNullOrEmpty(procResult.Output[x])) continue;

                string firstLine = procResult.Output[x];
                string [] firstLineParams = firstLine.Split(' ');

                Version verInfo;
                int tVal;
                for (int n = 0; n < firstLineParams.Length; n++)
                {
                    //Find parameter which begin with number
                    if (int.TryParse(firstLineParams[n][0].ToString(), out tVal))
                    {
                        string verString = firstLineParams[n];
                        
                        //HACK: Trim end character "." for Visual Studio (devenv)
                        while (!int.TryParse(verString.Last().ToString(), out tVal))
                        {
                            verString = verString.Substring(0, verString.Length - 1);
                        }
                        //---- end HACK

                        try
                        {
                            verInfo = new Version(verString);
                            return verInfo;
                        }
                        catch { continue; }
                    }
                }
            }
            return null; //No output returned from command.
        }

        /// <summary>
        /// Stop the current process and all its child process.
        /// </summary>
        public void Abort()
        {
            if (ProcessHandler == null) return;
            if (ProcessHandler.HasExited) return;
            KillProcessAndChildren(ProcessHandler.Id);
        }

        #region [ Private Functions ]

        private static void KillProcessAndChildren(int pid)
        {

            ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
            ManagementObjectCollection moc = searcher.Get();
            foreach (ManagementObject mo in moc)
            {
                KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
            }
            try
            {
                Process proc = Process.GetProcessById(pid);
                proc.Kill();
            }
            catch (ArgumentException)
            {
                // Process already exited.
            }
        }
        private void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            //ToDo: Review exception : "Source array was not long enough. Check srcIndex and length, and the array's lower bounds."
            if (e.Data != null)
            {
                string data = e.Data;
                errorDetected = true;
                if (RedirectToFile) System.IO.File.AppendAllText(LogFile, data + "\r\n");
                else outputData.Add(data);
                if (TraceLogEnabled) Trace.WriteLine(Name + ": " + data);
            }
        }
        private void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            //ToDo: Review exception : "Source array was not long enough. Check srcIndex and length, and the array's lower bounds."
            if (e.Data != null)
            {
                string data = e.Data;
                if (RedirectToFile) System.IO.File.AppendAllText(LogFile, data + "\r\n");
                else outputData.Add(data);
                if (TraceLogEnabled) Trace.WriteLine(Name + ": " + data);
            }
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Technical Lead
Malaysia Malaysia
Official Page: www.codearteng.com

Comments and Discussions