//
// NConsoler 0.9.3
// http://nconsoler.csharpus.com
//
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;
using System.Threading;
namespace NConsoler
{
///
/// Entry point for NConsoler applications
///
public sealed class Consolery
{
///
/// Runs an appropriate Action method.
/// Uses the class this call lives in as target type and command line arguments from Environment
///
public static int Run()
{
Type declaringType = new StackTrace().GetFrame(1).GetMethod().DeclaringType;
string[] args = new string[Environment.GetCommandLineArgs().Length - 1];
new List(Environment.GetCommandLineArgs()).CopyTo(1, args, 0, Environment.GetCommandLineArgs().Length - 1);
return Run(declaringType, args);
}
///
/// Runs an appropriate Action method
///
/// Type where to search for Action methods
/// Arguments that will be converted to Action method arguments
public static int Run(Type targetType, string[] args)
{
return Run(targetType, args, new ConsoleMessenger());
}
///
/// Runs an appropriate Action method
///
/// Type where to search for Action methods
/// Arguments that will be converted to Action method arguments
/// Uses for writing messages instead of Console class methods
public static int Run(Type targetType, string[] args, IMessenger messenger)
{
try
{
return new Consolery(targetType, args, messenger, false, null).RunAction();
}
catch (NConsolerException e)
{
messenger.Write(e.Message);
return 100;
}
}
///
/// Runs an appropriate Action method
///
/// Object where to search for Action methods
/// Arguments that will be converted to Action method arguments
public static int RunInstance(object targetObject, string[] args)
{
return RunInstance(targetObject, args, new ConsoleMessenger());
}
///
/// Runs an appropriate Action method
///
/// Object where to search for Action methods
/// Arguments that will be converted to Action method arguments
/// Uses for writing messages instead of Console class methods
public static int RunInstance(object targetObject, string[] args, IMessenger messenger)
{
try
{
return new Consolery(targetObject.GetType(), args, messenger, true, targetObject).RunAction();
}
catch (NConsolerException e)
{
messenger.Write(e.Message);
return 100;
}
}
///
/// Validates specified type and throws NConsolerException if an error
///
/// Type where to search for Action methods
public static void Validate(Type targetType)
{
new Consolery(targetType, new string[] {}, new ConsoleMessenger(), false, null).ValidateMetadata();
}
private readonly Type _targetType;
private readonly string[] _args;
private readonly List _actionMethods = new List();
private readonly IMessenger _messenger;
private readonly bool _isInstance;
private readonly object _targetObject;
private Consolery(Type targetType, string[] args, IMessenger messenger, bool isInstance, object targetObject)
{
#region Parameter Validation
if (targetType == null)
{
throw new ArgumentNullException("targetType");
}
if (args == null)
{
throw new ArgumentNullException("args");
}
if (messenger == null)
{
throw new ArgumentNullException("messenger");
}
if (isInstance && (targetObject == null))
{
throw new AbandonedMutexException("targetObject");
}
#endregion
_targetType = targetType;
_args = args;
_messenger = messenger;
_isInstance = isInstance;
_targetObject = targetObject;
BindingFlags flags;
if(_isInstance)
{
flags = BindingFlags.Instance;
} else
{
flags = BindingFlags.Static;
}
MethodInfo[] methods = _targetType.GetMethods(BindingFlags.Public | flags);
foreach (MethodInfo method in methods)
{
object[] attributes = method.GetCustomAttributes(false);
foreach (object attribute in attributes)
{
if (attribute is ActionAttribute)
{
_actionMethods.Add(method);
break;
}
}
}
}
static object ConvertValue(string value, Type argumentType)
{
if (argumentType == typeof(int))
{
try
{
return Convert.ToInt32(value);
}
catch (FormatException)
{
throw new NConsolerException("Could not convert \"{0}\" to integer", value);
}
catch (OverflowException)
{
throw new NConsolerException("Value \"{0}\" is too big or too small", value);
}
}
if (argumentType == typeof(string))
{
return value;
}
if (argumentType == typeof(bool))
{
try
{
return Convert.ToBoolean(value);
}
catch (FormatException)
{
throw new NConsolerException("Could not convert \"{0}\" to boolean", value);
}
}
if (argumentType == typeof(string[]))
{
return value.Split('+');
}
if (argumentType == typeof(int[]))
{
string[] values = value.Split('+');
int[] valuesArray = new int[values.Length];
for (int i = 0; i < values.Length; i++)
{
valuesArray[i] = (int)ConvertValue(values[i], typeof(int));
}
return valuesArray;
}
if (argumentType == typeof(DateTime))
{
return ConvertToDateTime(value);
}
throw new NConsolerException("Unknown type is used in your method {0}", argumentType.FullName);
}
private static DateTime ConvertToDateTime(string parameter)
{
string[] parts = parameter.Split('-');
if (parts.Length != 3)
{
throw new NConsolerException("Could not convert {0} to Date", parameter);
}
int day = (int)ConvertValue(parts[0], typeof(int));
int month = (int)ConvertValue(parts[1], typeof(int));
int year = (int)ConvertValue(parts[2], typeof(int));
try
{
return new DateTime(year, month, day);
}
catch (ArgumentException)
{
throw new NConsolerException("Could not convert {0} to Date", parameter);
}
}
private static bool CanBeConvertedToDate(string parameter)
{
try
{
ConvertToDateTime(parameter);
return true;
}
catch(NConsolerException)
{
return false;
}
}
private bool SingleActionWithOnlyOptionalParametersSpecified() {
if (IsMulticommand) return false;
MethodInfo method = _actionMethods[0];
return OnlyOptionalParametersSpecified(method);
}
private static bool OnlyOptionalParametersSpecified(MethodBase method)
{
foreach (ParameterInfo parameter in method.GetParameters())
{
if (IsRequired(parameter))
{
return false;
}
}
return true;
}
private int RunAction()
{
ValidateMetadata();
if (IsHelpRequested())
{
PrintUsage();
return 0;
}
MethodInfo currentMethod = GetCurrentMethod();
if (currentMethod == null)
{
PrintUsage();
throw new NConsolerException("Unknown subcommand \"{0}\"", _args[0]);
}
ValidateInput(currentMethod);
return InvokeMethod(currentMethod);
}
private struct ParameterData
{
public readonly int position;
public readonly Type type;
public ParameterData(int position, Type type)
{
this.position = position;
this.type = type;
}
}
private static bool IsRequired(ICustomAttributeProvider info)
{
object[] attributes = info.GetCustomAttributes(typeof(ParameterAttribute), false);
return attributes.Length == 0 || attributes[0].GetType() == typeof(RequiredAttribute);
}
private static bool IsOptional(ICustomAttributeProvider info)
{
return !IsRequired(info);
}
private static OptionalAttribute GetOptional(ICustomAttributeProvider info)
{
object[] attributes = info.GetCustomAttributes(typeof(OptionalAttribute), false);
return (OptionalAttribute)attributes[0];
}
private bool IsMulticommand
{
get
{
return _actionMethods.Count > 1;
}
}
private bool IsHelpRequested()
{
return (_args.Length == 0 && !SingleActionWithOnlyOptionalParametersSpecified())
|| (_args.Length > 0 && (_args[0] == "/?"
|| _args[0] == "/help"
|| _args[0] == "/h"
|| _args[0] == "help"));
}
private int InvokeMethod(MethodInfo method)
{
try
{
return (int)method.Invoke(_isInstance ? _targetObject : null, BuildParameterArray(method));
}
catch (TargetInvocationException e)
{
if (e.InnerException != null)
{
throw new NConsolerException(e.InnerException.Message, e);
}
throw;
}
}
private object[] BuildParameterArray(MethodInfo method)
{
int argumentIndex = IsMulticommand ? 1 : 0;
List