예제 #1
0
        private void SetPropertyValue(CmdLineProperty prop, string val, IEnumerable <string> arrayVals)
        {
            if (prop == null)
            {
                return;
            }

            object value = null;

            // Array conversion.
            if (arrayVals != null)
            {
                value = arrayVals.ToArray().Convert(prop.PropertyType.GetElementType());
            }

            // Standard type conversion.
            else if (val != null)
            {
                value = ConvertEx.To(val, prop.PropertyType);
            }

            // Flag with no additional values is true.
            else if (prop.PropertyType == typeof(bool))
            {
                value = true;
            }

            // Name defined, but no value. Set to default for type.
            else if (prop.PropertyType.IsValueType)
            {
                value = Activator.CreateInstance(prop.PropertyType);
            }

            prop.Value = value;
        }
예제 #2
0
        private CmdLineProperty GetCmdLineProperty(PropertyDescriptor propDesc, T obj)
        {
            var prop      = new CmdLineProperty(propDesc, obj);
            var claAtt    = propDesc.GetAttribute <CmdLineArgAttribute>();
            var showUsage = (bool?)null;

            if (claAtt != null)
            {
                prop.Aliases          = claAtt.Aliases;
                showUsage             = claAtt.mShowInUsage;     // Use internal field instead of property so we can get null value.
                prop.ShowInHelp       = claAtt.ShowInHelp;
                prop.ShowDefaultValue = claAtt.ShowDefaultValue;
            }

            prop.Required = propDesc.GetAttribute <RequiredAttribute>() != null;

            // Determine if we should show this in the usage or not.
            if (showUsage ?? false)
            {
                prop.ShowInUsage = true;
            }
            else if (showUsage ?? prop.Required)
            {
                prop.ShowInUsage = true;
            }
            else
            {
                prop.ShowInUsage = false;
            }

            prop.DefaultValue = prop.Value;

            // Make sure aliases has a valid value so we don't have to check for nulls everywhere.
            if (prop.Aliases == null)
            {
                prop.Aliases = new string[] { }
            }
            ;

            return(prop);
        }
예제 #3
0
        /// <summary>
        /// Fills an existing command-line object from the command-line arguments.
        /// </summary>
        /// <param name="obj">The instance to fill.</param>
        /// <param name="args"></param>
        /// <returns></returns>
        public CmdLineParseResults <T> Fill(T obj, IEnumerable <string> args)
        {
            VerifyCmdLineOptions();

            if (Options.ExitCodes == null)
            {
                Options.ExitCodes = FindExitCodes();
            }
            if (Options.ExitCodes != null)
            {
                if (Options.InvalidArgsExitCode == null)
                {
                    Options.InvalidArgsExitCode = FindExitCode(Options.ExitCodes, "InvalidArgs");
                }
                if (Options.FatalErrorExitCode == null)
                {
                    Options.FatalErrorExitCode = FindExitCode(Options.ExitCodes, "FatalError");
                }
            }

            var results = new CmdLineParseResults <T>(Options);

            results.Args = obj;
            var             props     = results.Properties = GetCmdLineProperties(obj);
            var             errors    = new List <string>();
            CmdLineProperty prop      = null;
            List <string>   arrayVals = null;
            var             notSpecifiedRequiredProps = props.Where(p => p.Required).ToList();

            // To keep the parsing logic as simple as possible,
            // normalize the argument list.
            // Normalize for assignment first so other transforms
            // can work with the same type of list.
            args = TransformAssignedArgs(args);
            args = TransformDefaultArgs(args);

            foreach (var arg in args)
            {
                try
                {
                    if (arg.StartsWith(Options.ArgumentPrefix))                     // Named value.
                    {
                        // We might be setting a flag or array value.
                        SetPropertyValue(prop, null, arrayVals);
                        arrayVals = null;

                        var name = arg.Substring(Options.ArgumentPrefix.Length);

                        var falseVal = false;
                        if (name.EndsWith("-"))
                        {
                            name     = name.Substring(0, name.Length - 1);
                            falseVal = true;
                        }
                        prop = props[name];
                        if (prop != null)
                        {
                            if (prop.Required)
                            {
                                notSpecifiedRequiredProps.Remove(prop);
                            }

                            if (falseVal && prop.PropertyType == typeof(bool))
                            {
                                SetPropertyValue(prop, "false", null);
                                prop = null;
                            }
                        }
                    }
                    else if (prop != null)
                    {
                        // Either setting a value or adding to an array.
                        if (prop.PropertyType.IsArray)
                        {
                            if (Options.ArraySeparator != null)
                            {
                                var values = Regex.Split(arg, Regex.Escape(Options.ArraySeparator));
                                SetPropertyValue(prop, null, values);
                                prop = null;
                            }
                            else
                            {
                                if (arrayVals == null)
                                {
                                    arrayVals = new List <string>();
                                }
                                arrayVals.Add(arg);
                            }
                        }
                        else
                        {
                            SetPropertyValue(prop, arg, null);
                            prop = null;
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (prop == null || prop.Name.IsEmpty())
                    {
                        errors.Add("ERR: " + ex.Message);
                    }
                    else if (arrayVals == null)
                    {
                        errors.Add("Unable to set {0}. Value <{1}> is not valid.".Fmt(prop.Name, arg));
                    }
                    else
                    {
                        errors.Add("Unable to set {0}. Invalid value.".Fmt(prop.Name, arg));
                    }
                }
            }
            try
            {
                SetPropertyValue(prop, null, arrayVals);
            }
            catch (Exception ex)
            {
                if (prop == null || prop.Name.IsEmpty())
                {
                    errors.Add("ERR: " + ex.Message);
                }
                else
                {
                    errors.Add("Unable to set {0}. Invalid value.".Fmt(prop.Name));
                }
            }

            // Populate header-level information, such as the title.
            FillCmdLineObjInfo(results);

            // Set errors for any missing, required properties.
            // https://github.com/BizArk/BizArk3/issues/7
            errors.AddRange(notSpecifiedRequiredProps.Select(p =>
            {
                var reqAtt = p.Property.GetAttribute <RequiredAttribute>();
                var msg    = reqAtt?.ErrorMessage ?? $"{p.Name} is required.";
                return(msg);
            }));

            // Validate the object using validation attributes.
            errors.AddRange(ValidateCmdLineObject(obj));
            results.Errors = errors.Distinct().ToArray();             // Required messages might show up twice.

            return(results);
        }