//******************************************************************************************************
// Command.cs - Gbtc
//
// Copyright © 2010, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 08/27/2014 - J. Ritchie Carroll
// Generated original version of source code.
//
//******************************************************************************************************
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
namespace GSF.Console
{
///
/// Defines methods related to command line operations
///
public static class Command
{
// Defines a command process.
private sealed class CommandProcess : IDisposable
{
#region [ Members ]
// Fields
private readonly Process m_process;
private readonly StringBuilder m_standardOutput;
private readonly StringBuilder m_standardError;
private int m_exitCode;
private bool m_disposed;
#endregion
#region [ Constructors ]
///
/// Creates a new instance.
///
/// File name to execute.
/// Command line parameters, if any. Set to empty string for none.
public CommandProcess(string fileName, string arguments)
{
m_standardOutput = new StringBuilder();
m_standardError = new StringBuilder();
m_exitCode = -1;
m_process = new Process
{
StartInfo =
{
FileName = fileName,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
m_process.OutputDataReceived += m_process_OutputDataReceived;
m_process.ErrorDataReceived += m_process_ErrorDataReceived;
}
///
/// Releases the unmanaged resources before the object is reclaimed by .
///
~CommandProcess()
{
Dispose(false);
}
#endregion
#region [ Properties ]
///
/// Gets any standard output from process after execution.
///
public string StandardOutput
{
get
{
return m_standardOutput.ToString();
}
}
///
/// Gets any standard error from process after execution.
///
public string StandardError
{
get
{
return m_standardError.ToString();
}
}
///
/// Gets exit code assuming process
///
public int ExitCode
{
get
{
return m_exitCode;
}
}
#endregion
#region [ Methods ]
///
/// Releases all the resources used by the object.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Releases the unmanaged resources and optionally releases the managed resources.
private void Dispose(bool disposing)
{
if (!m_disposed)
{
try
{
if (disposing)
{
if ((object)m_process != null)
{
m_process.OutputDataReceived -= m_process_OutputDataReceived;
m_process.ErrorDataReceived -= m_process_ErrorDataReceived;
m_process.Dispose();
}
}
}
finally
{
m_disposed = true; // Prevent duplicate dispose.
}
}
}
///
/// Attempts to execute process.
///
/// Timeout, in milliseconds, to wait for command line operation to complete.
/// true if process completed; otherwise, false if process timed-out.
public bool Execute(int timeout)
{
m_process.Start();
m_process.BeginOutputReadLine();
m_process.BeginErrorReadLine();
if (!m_process.WaitForExit(timeout))
{
m_process.CancelOutputRead();
m_process.CancelErrorRead();
return false;
}
m_exitCode = m_process.ExitCode;
return true;
}
private void m_process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
m_standardOutput.AppendLine(e.Data);
}
private void m_process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
m_standardError.AppendLine(e.Data);
}
#endregion
}
///
/// Executes a command line operation and returns its standard output and exit code or throws an exception with the standard error.
///
/// Command line file name to execute.
/// Command line arguments to use, if any.
/// Timeout, in milliseconds, to wait for command line operation to complete.
/// A containing the standard output received from command and the exit code.
///
/// Exception occurs when executed command process reports standard error output or process times-out.
///
public static CommandResponse Execute(string fileName, string arguments = null, int timeout = Timeout.Infinite)
{
string standardOutput, standardError;
bool processCompleted;
int exitCode;
if (!Execute(fileName, arguments, out standardOutput, out standardError, out processCompleted, out exitCode, timeout))
throw new CommandException(standardError, processCompleted, exitCode);
if (!processCompleted)
throw new CommandException("Process timed-out.", false, -1);
return new CommandResponse(standardOutput, exitCode);
}
///
/// Executes a command line operation and returns true if there was no standard error reported.
///
/// Command line file name to execute.
/// Command line arguments to use, if any.
/// Any standard output reported by the command line operation.
/// Any standard error reported by the command line operation.
/// Exit code of the process, assuming process successfully completed.
/// true if there was no standard error reported; otherwise, false.
/// This function waits indefinitely for the command line operation to complete.
public static bool Execute(string fileName, string arguments, out string standardOutput, out string standardError, out int exitCode)
{
bool processCompleted;
return Execute(fileName, arguments, out standardOutput, out standardError, out processCompleted, out exitCode, Timeout.Infinite);
}
///
/// Executes a command line operation and returns true if there was no standard error reported.
///
/// Command line file name to execute.
/// Command line arguments to use, if any.
/// Any standard output reported by the command line operation.
/// Any standard error reported by the command line operation.
/// Flag that determines if process completed or timed-out. This is only relevant if is not -1.
/// Exit code of the process, assuming process successfully completed.
/// Timeout, in milliseconds, to wait for command line operation to complete. Set to , i.e., -1, for infinite wait.
/// true if there was no standard error reported; otherwise, false.
public static bool Execute(string fileName, string arguments, out string standardOutput, out string standardError, out bool processCompleted, out int exitCode, int timeout)
{
using (CommandProcess process = new CommandProcess(fileName, arguments ?? ""))
{
processCompleted = process.Execute(timeout);
standardOutput = process.StandardOutput;
standardError = process.StandardError;
exitCode = process.ExitCode;
}
return string.IsNullOrWhiteSpace(standardError);
}
///
/// Shell encodes a command line parameter by converting "\" to "\\".
///
/// Parameter to shell encode.
/// Shell encoded .
public static string ShellEncode(this string parameter)
{
if ((object)parameter == null)
throw new ArgumentNullException(nameof(parameter));
return parameter.Replace("\\", "\\\\");
}
///
/// Decodes a command line parameter previously encoded by .
///
/// Parameter to decode.
/// Decoded .
public static string ShellDecode(this string parameter)
{
if ((object)parameter == null)
throw new ArgumentNullException(nameof(parameter));
return parameter.Replace("\\\\", "\\");
}
}
}