Esempio n. 1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="options">Object decorated by Plossum's attributes.</param>
        public CommandLineParser(object options)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            Options = options;

            CommandLineManagerAttribute = PlossumAttributesHelper.GetCommandLineManagerAttribute(options.GetType());

            OptionAttributes = PlossumAttributesHelper.GetCommandLineOptionAttributes(options.GetType());

            GroupAttributesDic = PlossumAttributesHelper.GetCommandLineOptionGroupAttributesDic(options.GetType());
        }
Esempio n. 2
0
        public static string AnalyzeAssignedOptions(object optionsAssigned)
        {
            if (optionsAssigned == null)
            {
                throw new ArgumentNullException("optionsAssigned");
            }

            var typeOfParametersAndOptions       = optionsAssigned.GetType();
            var propertiesOfParametersAndOptions = new List <PropertyInfo>(typeOfParametersAndOptions.GetProperties());
            var managerAttribute = PlossumAttributesHelper.GetCommandLineManagerAttribute(typeOfParametersAndOptions);
            var isCaseSensitive  = managerAttribute.IsCaseSensitive;

            var allOptionAttributes = PlossumAttributesHelper.GetCommandLineOptionAttributes(typeOfParametersAndOptions);
            var allPropertyInfo     = PlossumAttributesHelper.GetOptionProperties(typeOfParametersAndOptions);

            List <PropertyInfo> propertyInfoOfAssignedProperties = new List <PropertyInfo>();
            List <CommandLineOptionAttribute> optionAttributesOfAssignedProperties = new List <CommandLineOptionAttribute>();

            foreach (PropertyInfo propertyInfo in propertiesOfParametersAndOptions)
            {
                var propertyValue = propertyInfo.GetValue(optionsAssigned, null);
                if (propertyValue == null)
                {
                    continue;
                }

                int parameterOrder = PropertyHelper.GetParameterOrder(propertyInfo);
                if (parameterOrder < int.MaxValue)//so this is a fixed parameter
                {
                    continue;
                }
                else//option
                {
                    var defaultValue    = PropertyHelper.ReadDefaultValue(propertyInfo);
                    var optionAttribute = PlossumAttributesHelper.GetCommandLineOptionAttribute(propertyInfo);

                    if (!propertyValue.Equals(defaultValue))
                    {
                        optionAttributesOfAssignedProperties.Add(optionAttribute);
                        propertyInfoOfAssignedProperties.Add(propertyInfo);
                    }
                }
            }

            #region about Grouped options

            var optionAttributesGrouped = optionAttributesOfAssignedProperties.GroupBy(d => d.GroupId).OrderBy(k => k.Key);
            var allGroupAttributesDic   = PlossumAttributesHelper.GetCommandLineOptionGroupAttributesDic(typeOfParametersAndOptions);

            StringBuilder builder = new StringBuilder();
            foreach (var item in allGroupAttributesDic)
            {
                var groupId          = item.Key;
                var groupAttribute   = item.Value;
                var optionAttributes = optionAttributesGrouped.FirstOrDefault(d => d.Key == groupId);

                switch (groupAttribute.Require)
                {
                case OptionGroupRequirement.None:
                    continue;

                case OptionGroupRequirement.AtMostOne:
                    if (optionAttributes == null)
                    {
                        continue;
                    }

                    if (!(optionAttributes.Count() <= 1))
                    {
                        builder.AppendLine(String.Format("Group {0} requires at most one option defined, but actually these are {1} options defined", groupAttribute.Name, optionAttributes.Count()));
                    }
                    break;

                case OptionGroupRequirement.AtLeastOne:
                    if ((optionAttributes == null) ||
                        !(optionAttributes.Count() >= 1))
                    {
                        builder.AppendLine(String.Format("Group {0} requires at least one option defined, but actually these is none defined", groupAttribute.Name));
                    }

                    break;

                case OptionGroupRequirement.ExactlyOne:
                    if (optionAttributes == null)
                    {
                        builder.AppendLine(String.Format("Group {0} requires exactly one option defined, but actually these is none defined", groupAttribute.Name));
                    }
                    else if (!(optionAttributes.Count() == 1))
                    {
                        builder.AppendLine(String.Format("Group {0} requires exactly one option defined, but actually these are {1} options defined.", groupAttribute.Name, optionAttributes.Count()));
                    }

                    break;

                case OptionGroupRequirement.All:
                    if (optionAttributes == null)
                    {
                        builder.AppendLine(String.Format("Group {0} requires all options defined, but actually these is none defined", groupAttribute.Name));
                    }
                    else
                    {
                        var numberOfOptionsOfGroup = allOptionAttributes.Count(d => d.GroupId == groupId);
                        var delta = numberOfOptionsOfGroup - optionAttributes.Count();
                        if (delta != 0)
                        {
                            builder.AppendLine(String.Format("Group {0} requires all options defined, but actually there are {1} options(s) missing.", groupAttribute.Name, delta));
                        }
                    }
                    break;

                default:
                    break;
                }
            }

            #endregion

            #region about Prohibits


            for (int i = 0; i < propertyInfoOfAssignedProperties.Count; i++)
            {
                var optionAttribute = optionAttributesOfAssignedProperties[i];
                if (String.IsNullOrEmpty(optionAttribute.Prohibits))
                {
                    continue;
                }

                var propertyInfo = propertyInfoOfAssignedProperties[i];

                string[] optionNamesProhibited = optionAttribute.Prohibits.Split(mSeparators, StringSplitOptions.RemoveEmptyEntries);
                if (optionNamesProhibited.Length == 0)
                {
                    continue;
                }

                for (int k = 0; k < propertyInfoOfAssignedProperties.Count; k++)
                {
                    var  nextPropertyInfo = propertyInfoOfAssignedProperties[k];
                    bool matched          = false;
                    if (optionNamesProhibited.Contains(nextPropertyInfo.Name, isCaseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase))
                    {
                        matched = true;
                    }
                    else
                    {
                        var nextOptionAttribute = optionAttributesOfAssignedProperties[k];
                        if (optionNamesProhibited.Contains(nextOptionAttribute.Name, isCaseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase))
                        {
                            matched = true;
                        }
                        else
                        {
                            if ((nextOptionAttribute.AliasesArray != null) && (nextOptionAttribute.AliasesArray.Length > 0))
                            {
                                matched = optionNamesProhibited.Any(d => nextOptionAttribute.AliasesArray.Contains(d, isCaseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase));
                            }
                        }
                    }

                    if (matched)
                    {
                        builder.AppendLine(String.Format("Option {0} defined is prohibited since option {1} is already defined.", nextPropertyInfo.Name, propertyInfo.Name));
                    }
                }
            }


            #endregion


            for (int i = 0; i < propertyInfoOfAssignedProperties.Count; i++)
            {
                var optionAttribute = optionAttributesOfAssignedProperties[i];
                var propertyInfo    = propertyInfoOfAssignedProperties[i];

                if (propertyInfo.PropertyType.IsArray)
                {
                    var array       = propertyInfo.GetValue(optionsAssigned, null);
                    var list        = array as Array;
                    var arrayLength = list.Length;
                    if ((optionAttribute.MaxOccurs > 1) && (arrayLength > optionAttribute.MaxOccurs))
                    {
                        builder.AppendLine(String.Format("Option {0} with MaxOccurs={1} has {2} presented.", propertyInfo.Name, optionAttribute.MaxOccurs, arrayLength));
                    }

                    if ((optionAttribute.MinOccurs > 0) && (arrayLength < optionAttribute.MinOccurs))
                    {
                        builder.AppendLine(String.Format("Option {0} with MinOccurs={1} has {2} presented.", propertyInfo.Name, optionAttribute.MinOccurs, arrayLength));
                    }

                    if ((optionAttribute.MaxOccurs > 0) && (optionAttribute.MinOccurs > optionAttribute.MaxOccurs))
                    {
                        builder.AppendLine(String.Format("In option {0} MinOccurs={1} is greater than MaxOccurs={2} .", propertyInfo.Name, optionAttribute.MinOccurs, optionAttribute.MaxOccurs));
                    }
                }
            }

            for (int i = 0; i < allPropertyInfo.Length; i++)
            {
                var optionAttribute = allOptionAttributes[i];
                var propertyInfo    = allPropertyInfo[i];

                if (propertyInfo.PropertyType.IsArray)
                {
                    var array = propertyInfo.GetValue(optionsAssigned, null);
                    var list  = array as Array;
                    //                var arrayLength = list.Length;
                    if ((list == null) && (optionAttribute.MinOccurs > 0))
                    {
                        builder.AppendLine(String.Format("Option {0} with MinOccurs={1} has no value.", propertyInfo.Name, optionAttribute.MinOccurs));
                    }
                }
                else
                {
                    if (optionAttribute.MaxOccurs > 1)
                    {
                        builder.AppendLine(String.Format("Option {0} must not have MaxOccurs greater than 1.", propertyInfo.Name));
                    }
                }
            }


            #region about MaxValue and MinValue

            for (int i = 0; i < propertyInfoOfAssignedProperties.Count; i++)
            {
                var optionAttribute = optionAttributesOfAssignedProperties[i];
                var propertyInfo    = propertyInfoOfAssignedProperties[i];
                var maxValue        = optionAttribute.MaxValue;
                var minValue        = optionAttribute.MinValue;
                if ((maxValue == null) && (minValue == null))
                {
                    continue;
                }

                if (propertyInfo.PropertyType.IsArray)
                {
                    var array = propertyInfo.GetValue(optionsAssigned, null);
                    var list  = array as Array;
                    if (list == null)
                    {
                        continue;
                    }

                    var firstMember = list.GetValue(0);
                    var memberType  = firstMember.GetType();
                    if (!IsNumericType(memberType))
                    {
                        builder.AppendLine(String.Format("Options {0} is not of numeric type, and must not have either MaxValue or MinValue defined in CommandLineOptionAttribute.", propertyInfo.Name));
                        continue;
                    }

                    if (maxValue != null)
                    {
                        if (memberType.Equals(decimalType) && !decimalType.Equals(maxValue))
                        {
                            maxValue = Convert.ToDecimal(maxValue);
                        }

                        foreach (var m in list)
                        {
                            IComparable comparable = m as IComparable;

                            if (comparable.CompareTo(maxValue) > 0)
                            {
                                builder.AppendLine(String.Format("In option {0}, this member {1} is greater than maxValue {2}.", propertyInfo.Name, m, maxValue));
                            }
                        }
                    }

                    if (minValue != null)
                    {
                        if (memberType.Equals(decimalType) && !decimalType.Equals(minValue))
                        {
                            minValue = Convert.ToDecimal(minValue);
                        }

                        foreach (var m in list)
                        {
                            IComparable comparable = m as IComparable;
                            if (comparable.CompareTo(minValue) < 0)
                            {
                                builder.AppendLine(String.Format("In option {0}, this member {1} is less than than minValue {2}.", propertyInfo.Name, m, minValue));
                            }
                        }
                    }
                }
                else
                {
                    if (!IsNumericType(propertyInfo.PropertyType))
                    {
                        builder.AppendLine(String.Format("Options {0} is not of numeric type, and must not have either MaxValue or MinValue defined in CommandLineOptionAttribute.", propertyInfo.Name));
                        continue;
                    }
                    if (maxValue != null)
                    {
                        var         m          = propertyInfo.GetValue(optionsAssigned, null);
                        IComparable comparable = m as IComparable;
                        if (propertyInfo.PropertyType.Equals(decimalType) && !decimalType.Equals(maxValue))
                        {
                            maxValue = Convert.ToDecimal(maxValue);
                        }

                        if (comparable.CompareTo(maxValue) > 0)
                        {
                            builder.AppendLine(String.Format("In option {0}, this member {1} is greater than maxValue {2}.", propertyInfo.Name, m, maxValue));
                        }
                    }

                    if (minValue != null)
                    {
                        var         m          = propertyInfo.GetValue(optionsAssigned, null);
                        IComparable comparable = m as IComparable;
                        if (propertyInfo.PropertyType.Equals(decimalType) && !decimalType.Equals(minValue))
                        {
                            minValue = Convert.ToDecimal(minValue);
                        }

                        if (comparable.CompareTo(minValue) < 0)
                        {
                            builder.AppendLine(String.Format("In option {0}, this member {1} is less than than minValue {2}.", propertyInfo.Name, m, minValue));
                        }
                    }
                }
            }
            #endregion

            return(builder.ToString());
        }
Esempio n. 3
0
        /// <summary>
        /// Parse option text and assign property values to options accordingly.
        /// </summary>
        /// <param name="optionsText">For options only. The caller should toss all fixed parameters out.</param>
        /// <param name="options"></param>
        /// <returns>Error message</returns>
        public static string ReadOptions(string optionsText, object options)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            if (String.IsNullOrWhiteSpace(optionsText))
            {
                return(null);
            }

            var parserResult = ArgumentParserResult.Parse(optionsText);

            var fixedParameters = parserResult.FixedParameters;



            var optionsDic = parserResult.OptionsDictionary;

            if (optionsDic.Count == 0)
            {
                return("Cannot find any token when parsing optionsText.");
            }

            var optionsType         = options.GetType();
            var propertiesOfOptions = optionsType.GetProperties();


            #region Handle fixed parameters

            List <PropertyInfo> propertiesOfFixedParameters = new List <PropertyInfo>();
            foreach (var propertyItem in propertiesOfOptions)
            {
                var orderAttribute = PropertyHelper.ReadAttribute <ParameterOrderAttribute>(propertyItem);
                if (orderAttribute != null)
                {
                    propertiesOfFixedParameters.Add(propertyItem);
                }
            }

            int upperBoundOfFixedParameters = fixedParameters.Count();
            int lastAssignedIndex           = 0;
            for (int i = 0; i < propertiesOfFixedParameters.Count; i++)
            {
                var propertyInfo = propertiesOfFixedParameters[i];
                if ((i < upperBoundOfFixedParameters) && (!propertyInfo.PropertyType.IsArray))  // in case fixed parameters in command line is less then those properties in the object, so the rest won't be assigned.
                {
                    propertyInfo.SetValue(options, fixedParameters[i], null);
                    lastAssignedIndex = i;
                }
                else
                {
                    break;
                }
            }

            if (lastAssignedIndex < propertiesOfFixedParameters.Count - 1)
            {
                var lastIndex    = lastAssignedIndex + 1;
                var propertyInfo = propertiesOfFixedParameters[lastIndex];
                if (propertyInfo.PropertyType.IsArray)
                {
                    var restParameters = fixedParameters.Skip(lastIndex).ToArray();
                    propertyInfo.SetValue(options, restParameters, null);
                }
            }

            #endregion


            StringBuilder builder = new StringBuilder();

            List <string> allParameterNames = new List <string>();

            foreach (var propertyItem in propertiesOfOptions)
            {
                var optionAttribute = PlossumAttributesHelper.GetCommandLineOptionAttribute(propertyItem);

                if (optionAttribute != null)
                {
                    string[] optionValues = null;
                    string   optionName;
                    if (String.IsNullOrWhiteSpace(optionAttribute.Name))
                    {
                        optionName           = propertyItem.Name;
                        optionAttribute.Name = optionName;
                    }
                    else
                    {
                        optionName = optionAttribute.Name;
                    }

                    allParameterNames.Add(optionName);

                    bool parameterNameFound = false;

                    Action tryGetValuesArrayFromDic = () =>
                    {
                        List <string> list = new List <string>();
                        string[]      array;
                        if (optionsDic.TryGetValue(optionName, out array))
                        {
                            list.AddRange(array);
                            parameterNameFound = true;
                        }

                        if (optionAttribute.AliasesArray != null)
                        {
                            allParameterNames.AddRange(optionAttribute.AliasesArray);

                            foreach (var a in optionAttribute.AliasesArray)
                            {
                                if (optionsDic.TryGetValue(a, out array))
                                {
                                    list.AddRange(array);
                                    parameterNameFound = true;
                                }
                            }
                        }

                        optionValues = list.ToArray();
                    };

                    tryGetValuesArrayFromDic();


                    if (parameterNameFound)
                    {
                        if (propertyItem.PropertyType == typeof(bool)) //bool parameter has no explicit value defined
                        {
                            propertyItem.SetValue(options, true, null);
                            if (optionValues.Length > 0)
                            {
                                builder.AppendLine(String.Format("Boolean option {0} should not have explicit values.", optionName));
                            }
                            continue;
                        }

                        if (optionValues.Length == 0)
                        {
                            builder.AppendLine(String.Format("Option {0} expects some values but no value is found with this option.", optionAttribute.Name));
                            continue;
                        }

                        if (!propertyItem.PropertyType.IsArray)
                        {
                            var valueText = optionValues[0];

                            if (optionValues.Length > 1)
                            {
                                builder.Append(String.Format(String.Format("Option {0} of type {1} has more than one value assigned: {2}. However, the first value {3} is used."
                                                                           , optionName, propertyItem.PropertyType.ToString(), String.Join(", ", optionValues), valueText)));
                            }

                            if (propertyItem.PropertyType == typeof(string))
                            {
                                propertyItem.SetValue(options, valueText, null);
                                continue;
                            }

                            Action addError = () => { builder.AppendLine(String.Format("Option {0} of type {1} has some invalid value {2}", optionName, propertyItem.PropertyType.ToString(), valueText)); };

                            if (propertyItem.PropertyType == typeof(int))
                            {
                                int value;
                                if (!int.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(byte))
                            {
                                byte value;
                                if (!byte.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(sbyte))
                            {
                                sbyte value;
                                if (!sbyte.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(char))
                            {
                                char value;
                                if (!char.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(decimal))
                            {
                                decimal value;
                                if (!decimal.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(double))
                            {
                                double value;
                                if (!double.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(float))
                            {
                                float value;
                                if (!float.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(uint))
                            {
                                uint value;
                                if (!uint.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(long))
                            {
                                long value;
                                if (!long.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(ulong))
                            {
                                ulong value;
                                if (!ulong.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(short))
                            {
                                short value;
                                if (!short.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType == typeof(ushort))
                            {
                                ushort value;
                                if (!ushort.TryParse(valueText, out value))
                                {
                                    addError();
                                }
                                else
                                {
                                    propertyItem.SetValue(options, value, null);
                                }

                                continue;
                            }

                            if (propertyItem.PropertyType.IsEnum)
                            {
                                try
                                {
                                    var converter = PropertyHelper.CreateTypeConverter(propertyItem.PropertyType);

                                    object value = converter == null?Enum.Parse(propertyItem.PropertyType, valueText, true) //starndard conversion
                                                       : converter.ConvertFromString(valueText);                            //custom

                                    propertyItem.SetValue(options, value, null);
                                }
                                catch (ArgumentException e)
                                {
                                    builder.AppendLine(String.Format("Option {0} has some invalid values {1}. {2}", optionAttribute.Name, optionValues, e.Message));
                                }
                                catch (OverflowException e)
                                {
                                    builder.AppendLine(String.Format("Option {0} has some values {1} out of range. {2}", optionAttribute.Name, optionValues, e.Message));
                                }


                                continue;
                            }
                        }
                        else //Handle values array of parameter
                        {
                            if (propertyItem.PropertyType == typeof(string[]))
                            {
                                propertyItem.SetValue(options, optionValues, null);
                                continue;
                            }


                            //bool array haven't been seen, not supported

                            if (HandleValueArray <int>(int.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <byte>(byte.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <sbyte>(sbyte.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <decimal>(decimal.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <double>(double.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <float>(float.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <uint>(uint.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <long>(long.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <ulong>(ulong.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <short>(short.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }

                            if (HandleValueArray <ushort>(ushort.Parse, propertyItem, options, optionValues, optionAttribute, builder))
                            {
                                continue;
                            }
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
            }


            var unknown = optionsDic.Keys.Where(d => !allParameterNames.Any(p => p.Equals(d, StringComparison.CurrentCultureIgnoreCase))).ToArray();
            if (unknown.Length > 0)
            {
                builder.AppendLine("Unknown options: " + String.Join(" ", unknown));
            }

            return(builder.ToString());
        }