namespace Unosquare.Swan.Components { using System.Linq; using System.Reflection; using Attributes; using System; using System.Collections.Generic; /// /// Provides methods to parse command line arguments. /// Based on CommandLine (Copyright 2005-2015 Giacomo Stelluti Scala and Contributors.). /// public partial class ArgumentParser { private sealed class Validator { private readonly object _instance; private readonly IEnumerable _args; private readonly List _updatedList = new List(); private readonly ArgumentParserSettings _settings; private readonly PropertyInfo[] _properties; public Validator( PropertyInfo[] properties, IEnumerable args, object instance, ArgumentParserSettings settings) { _args = args; _instance = instance; _settings = settings; _properties = properties; PopulateInstance(); SetDefaultValues(); GetRequiredList(); } public List UnknownList { get; } = new List(); public List RequiredList { get; } = new List(); public bool IsValid() => (_settings.IgnoreUnknownArguments || !UnknownList.Any()) && !RequiredList.Any(); public IEnumerable GetPropertiesOptions() => _properties.Select(p => Runtime.AttributeCache.RetrieveOne(p)) .Where(x => x != null); private void GetRequiredList() { foreach (var targetProperty in _properties) { var optionAttr = Runtime.AttributeCache.RetrieveOne(targetProperty); if (optionAttr == null || optionAttr.Required == false) continue; if (targetProperty.GetValue(_instance) == null) { RequiredList.Add(optionAttr.LongName ?? optionAttr.ShortName); } } } private void SetDefaultValues() { foreach (var targetProperty in _properties.Except(_updatedList)) { var optionAttr = Runtime.AttributeCache.RetrieveOne(targetProperty); var defaultValue = optionAttr?.DefaultValue; if (defaultValue == null) continue; if (SetPropertyValue(targetProperty, defaultValue.ToString(), _instance, optionAttr)) _updatedList.Add(targetProperty); } } private void PopulateInstance() { const char dash = '-'; var propertyName = string.Empty; foreach (var arg in _args) { var ignoreSetValue = string.IsNullOrWhiteSpace(propertyName); if (ignoreSetValue) { if (string.IsNullOrWhiteSpace(arg) || arg[0] != dash) continue; propertyName = arg.Substring(1); if (!string.IsNullOrWhiteSpace(propertyName) && propertyName[0] == dash) propertyName = propertyName.Substring(1); } var targetProperty = TryGetProperty(propertyName); if (targetProperty == null) { // Skip if the property is not found UnknownList.Add(propertyName); continue; } if (!ignoreSetValue && SetPropertyValue(targetProperty, arg, _instance)) { _updatedList.Add(targetProperty); propertyName = string.Empty; } else if (targetProperty.PropertyType == typeof(bool)) { // If the arg is a boolean property set it to true. targetProperty.SetValue(_instance, true); _updatedList.Add(targetProperty); propertyName = string.Empty; } } if (!string.IsNullOrEmpty(propertyName)) { UnknownList.Add(propertyName); } } private bool SetPropertyValue( PropertyInfo targetProperty, string propertyValueString, object result, ArgumentOptionAttribute optionAttr = null) { if (targetProperty.PropertyType.GetTypeInfo().IsEnum) { var parsedValue = Enum.Parse( targetProperty.PropertyType, propertyValueString, _settings.CaseInsensitiveEnumValues); targetProperty.SetValue(result, Enum.ToObject(targetProperty.PropertyType, parsedValue)); return true; } return targetProperty.PropertyType.IsArray ? targetProperty.TrySetArray(propertyValueString.Split(optionAttr?.Separator ?? ','), result) : targetProperty.TrySetBasicType(propertyValueString, result); } private PropertyInfo TryGetProperty(string propertyName) => _properties.FirstOrDefault(p => string.Equals(Runtime.AttributeCache.RetrieveOne(p)?.LongName, propertyName, _settings.NameComparer) || string.Equals(Runtime.AttributeCache.RetrieveOne(p)?.ShortName, propertyName, _settings.NameComparer)); } } }