Beispiel #1
0
        private static ArgumentDefinition CreateArgumentDescriptor(
            IMutableMemberInfo member,
            ArgumentBaseAttribute attribute,
            object defaultValues,
            ArgumentSetDefinition argSet,
            object fixedDestination,
            ArgumentDefinition containingArgument,
            ServiceConfigurer serviceConfigurer)
        {
            if (!member.IsReadable || !member.IsWritable)
            {
                var declaringType = member.MemberInfo.DeclaringType;

                throw new InvalidArgumentSetException(member, string.Format(
                                                          CultureInfo.CurrentCulture,
                                                          Strings.MemberNotSupported,
                                                          member.MemberInfo.Name,
                                                          declaringType?.Name));
            }

            var defaultFieldValue = (defaultValues != null) ? member.GetValue(defaultValues) : null;

            return(new ArgumentDefinition(member,
                                          attribute,
                                          argSet,
                                          defaultValue: defaultFieldValue,
                                          fixedDestination: fixedDestination,
                                          containingArgument: containingArgument,
                                          serviceConfigurer: serviceConfigurer));
        }
        private bool TryParseAndStore(ArgumentDefinition arg, string value, object dest)
        {
            if (!arg.TryParseAndStore(value, dest, out object parsedValue))
            {
                return(false);
            }

            // Inspect the parsed value.
            var argProvider = parsedValue as IArgumentProvider;

            if (argProvider == null)
            {
                argProvider = (arg.FixedDestination ?? dest) as IArgumentProvider;
            }

            if (argProvider != null)
            {
                var definingType = argProvider.GetTypeDefiningArguments();
                if (definingType != null)
                {
                    _argumentSet.AddArgumentsFromTypeWithAttributes(definingType,
                                                                    fixedDestination: argProvider.GetDestinationObject());
                }
            }

            return(true);
        }
Beispiel #3
0
 /// <summary>
 /// Constructs a result for cases where parser is ready.
 /// </summary>
 /// <param name="lastParsedArg">If non-null, indicates the last argument
 /// that was parsed.</param>
 /// <returns>The result object. </returns>
 public static ArgumentSetParseResult Ready(ArgumentDefinition lastParsedArg)
 {
     return(new ArgumentSetParseResult(ArgumentSetParseResultType.Ready)
     {
         LastSeenArg = lastParsedArg
     });
 }
        /// <summary>
        /// Checks if this parser has seen a value provided for the given argument.
        /// </summary>
        /// <param name="arg">The argument to look for.</param>
        /// <returns>True if a value has been seen; false otherwise.</returns>
        public bool HasSeenValueFor(ArgumentDefinition arg)
        {
            if (!_stateByArg.TryGetValue(arg, out ArgumentParser parser))
            {
                return(false);
            }

            return(parser.SeenValue);
        }
Beispiel #5
0
        /// <summary>
        /// Registers an Argument that conflicts with the one described by this
        /// object.  If the specified argument has already previously been
        /// registered, then this operation is a no-op.
        /// </summary>
        /// <param name="arg">The conflicting argument.</param>
        public void AddConflictingArgument(ArgumentDefinition arg)
        {
            if (arg == this)
            {
                throw new ArgumentOutOfRangeException(nameof(arg));
            }

            _conflictingArgs.Add(arg);
        }
Beispiel #6
0
 public ArgumentDefinition(MemberInfo member,
                           ArgumentBaseAttribute attribute,
                           ArgumentSetDefinition argSet,
                           object defaultValue = null,
                           ArgumentDefinition containingArgument = null,
                           ServiceConfigurer serviceConfigurer   = null)
     : this(GetMutableMemberInfo(member), attribute, argSet, defaultValue, /*fixedDestination=*/ null, containingArgument, serviceConfigurer)
 {
 }
Beispiel #7
0
 /// <summary>
 /// Constructs a result for cases where parser is next looking to see an argument
 /// to an option.
 /// </summary>
 /// <param name="arg">Argument that requires option argument.</param>
 /// <returns>The constructed result object.</returns>
 public static ArgumentSetParseResult RequiresOptionArgument(ArgumentDefinition arg)
 {
     if (arg == null)
     {
         throw new ArgumentNullException(nameof(arg));
     }
     return(new ArgumentSetParseResult(ArgumentSetParseResultType.RequiresOptionArgument)
     {
         LastSeenArg = arg
     });
 }
 public static TokenParseResult RequiresOptionArgument(ArgumentDefinition arg)
 {
     if (arg == null)
     {
         throw new ArgumentNullException(nameof(arg));
     }
     return(new TokenParseResult(TokenParseResultState.RequiresOptionArgument)
     {
         Argument = arg
     });
 }
Beispiel #9
0
 /// <summary>
 /// Constructor that forms the info from the argument's metadata.
 /// </summary>
 /// <param name="arg">Argument metadata.</param>
 /// <param name="currentValue">Current value.</param>
 public ArgumentUsageInfo(ArgumentDefinition arg, object currentValue = null) : this(
         syntax : arg.GetSyntaxSummary(detailed : false),
         detailedSyntax : arg.GetSyntaxSummary(detailed : true),
         description : arg.Attribute.Description,
         required : arg.IsRequired,
         shortName : arg.ShortName,
         defaultValue : TryGetDefaultValueString(arg, onlyReturnExplicitDefaults : true),
         argType : arg.ArgumentType,
         currentValue : currentValue)
 {
 }
Beispiel #10
0
        /// <summary>
        /// Tries to find the argument's default value.
        /// </summary>
        /// <param name="arg">The argument to retrieve a default value from.</param>
        /// <param name="onlyReturnExplicitDefaults">True to only return
        /// a default if it was explicitly specified; false to report on
        /// the default, even if it was defaulted itself.</param>
        /// <param name="value">On success, receives the default value
        /// for this argument; otherwise, receives null.</param>
        /// <returns>True on success, false otherwise.</returns>
        public static bool TryGetDefaultValue(ArgumentDefinition arg, bool onlyReturnExplicitDefaults, out object value)
        {
            // Firstly, if the argument is required, then there's no need to
            // indicate any default value.
            if (arg.IsRequired)
            {
                value = null;
                return(false);
            }

            // Next, go check for the actual *effective* default value for the
            // argument; we may still receive back a value here even if one
            // wasn't explicitly declared, as we will have consulted with the
            // argument's type to determine its default value.
            if (onlyReturnExplicitDefaults && !arg.HasDefaultValue)
            {
                value = null;
                return(false);
            }

            // If the default value is null, then that's not useful to show the
            // user.
            var defaultValue = arg.EffectiveDefaultValue;

            if (defaultValue == null)
            {
                value = null;
                return(false);
            }

            // Special case: if the argument type is bool, then the argument
            // will be like a switch, and that's typically assumed to be false
            // if not present.  So if the default value is indeed 'false', then
            // don't bother displaying it; but if it's 'true', then it's
            // important to indicate that.
            if ((defaultValue is bool) && !((bool)defaultValue))
            {
                value = null;
                return(false);
            }

            // Special case: if the argument type is string, then it's safe
            // to assume that its default value is an empty string.
            if ((defaultValue is string stringDefaultValue) &&
                string.IsNullOrEmpty(stringDefaultValue))
            {
                value = null;
                return(false);
            }

            // Okay, we have the value.
            value = defaultValue;
            return(true);
        }
Beispiel #11
0
        /// <summary>
        /// Internal constructor.
        /// </summary>
        /// <param name="member">Field to describe.</param>
        /// <param name="attribute">Argument attribute on the field.</param>
        /// <param name="argSet">Argument set containing this argument.</param>
        /// <param name="defaultValue">Default value for the field.</param>
        /// <param name="fixedDestination">Optionally provides fixed parse destination object.</param>
        /// <param name="containingArgument">Optionally provides a reference
        /// to the definition of the argument that "contains" these arguments.
        /// </param>
        /// <param name="serviceConfigurer">Optionally provides a service configurer.</param>
        internal ArgumentDefinition(IMutableMemberInfo member,
                                    ArgumentBaseAttribute attribute,
                                    ArgumentSetDefinition argSet,
                                    object defaultValue     = null,
                                    object fixedDestination = null,
                                    ArgumentDefinition containingArgument = null,
                                    ServiceConfigurer serviceConfigurer   = null)
        {
            Member                 = member ?? throw new ArgumentNullException(nameof(member));
            Attribute              = attribute ?? throw new ArgumentNullException(nameof(attribute));
            ContainingSet          = argSet ?? throw new ArgumentNullException(nameof(argSet));
            ContainingArgument     = containingArgument;
            FixedDestination       = fixedDestination;
            IsPositional           = attribute is PositionalArgumentAttribute;
            ArgumentType           = GetArgumentType(Attribute, member, member.MemberType, serviceConfigurer);
            CollectionArgumentType = AsCollectionType(ArgumentType);
            HasDefaultValue        = attribute.ExplicitDefaultValue || attribute.DynamicDefaultValue;
            ValidationAttributes   = GetValidationAttributes(ArgumentType, Member);

            LongName          = GetLongName(attribute, argSet.Attribute, member.MemberInfo);
            ExplicitShortName = HasExplicitShortName(attribute);
            ShortName         = GetShortNameOrNull(attribute, argSet.Attribute, member.MemberInfo);
            DefaultValue      = GetDefaultValue(attribute, member, defaultValue);

            var nullableBase = Nullable.GetUnderlyingType(member.MemberType);

            if (CollectionArgumentType != null)
            {
                ValueType = CollectionArgumentType.ElementType;
            }
            else if (nullableBase != null)
            {
                // For nullable arguments, we use the wrapped type (T in
                // Nullable<T>) as the value type. Parsing an enum or int is the
                // same as parsing an enum? or int?, for example, since null can
                // only arise if the value was not provided at all.
                ValueType = GetArgumentType(Attribute, member, nullableBase, serviceConfigurer);
            }
            else
            {
                ValueType = ArgumentType;
            }

            Debug.Assert(ValueType != null);

            if (Unique && !IsCollection)
            {
                throw new InvalidArgumentSetException(member, Strings.UniqueUsedOnNonCollectionArgument);
            }

            Debug.Assert(!string.IsNullOrEmpty(LongName));
        }
Beispiel #12
0
        /// <summary>
        /// Constructs a new stateful parser for the given argument.
        /// </summary>
        /// <param name="argSet">The argument set containing the argument to be parsed.</param>
        /// <param name="arg">The definition of the argument.</param>
        /// <param name="options">General options for parsing this argument set.</param>
        /// <param name="destination">The destination object into which the parsed result should go,
        /// if so desired; null otherwise to parse without saving results.</param>
        public ArgumentParser(ArgumentSetDefinition argSet, ArgumentDefinition arg, CommandLineParserOptions options,
                              object destination = null)
        {
            ArgumentSet       = argSet ?? throw new ArgumentNullException(nameof(argSet));
            Argument          = arg ?? throw new ArgumentNullException(nameof(arg));
            Reporter          = options?.Reporter ?? (s => { });
            DestinationObject = arg.FixedDestination ?? destination;
            ParseContext      = CreateParseContext(Argument, ArgumentSet.Attribute, options, DestinationObject);

            if (Argument.IsCollection)
            {
                CollectionValues = GenericCollectionFactory.CreateList(Argument.CollectionArgumentType.ElementType.Type);
            }
        }
Beispiel #13
0
        /// <summary>
        /// Tries to construct a string describing the argument's default value.
        /// </summary>
        /// <param name="arg">The argument to retrieve a default value string
        /// from.</param>
        /// <param name="onlyReturnExplicitDefaults">True to only return
        /// a default if it was explicitly specified; false to report on
        /// the default, even if it was defaulted itself.</param>
        /// <returns>If one should be advertised, returns the string version of
        /// the default value for this argument; otherwise, returns null.
        /// </returns>
        public static string TryGetDefaultValueString(ArgumentDefinition arg, bool onlyReturnExplicitDefaults = false)
        {
            // Try to get the default value.
            if (!TryGetDefaultValue(arg, onlyReturnExplicitDefaults, out object defaultValue))
            {
                return(null);
            }

            // Now turn the value into a string.
            var formattedArg = arg.Format(defaultValue, suppressArgNames: true).ToList();

            if (formattedArg.Count == 0)
            {
                return(null);
            }

            return(string.Join(" ", formattedArg));
        }
Beispiel #14
0
        private void AddPositionalArgument(ArgumentDefinition arg, int positionalIndexBias)
        {
            var attrib   = (PositionalArgumentAttribute)arg.Attribute;
            var position = positionalIndexBias + attrib.Position;

            if (_positionalArguments.ContainsKey(position))
            {
                throw new InvalidArgumentSetException(arg, string.Format(
                                                          CultureInfo.CurrentCulture,
                                                          Strings.DuplicatePositionArguments,
                                                          _positionalArguments[position].Member.MemberInfo.Name,
                                                          arg.Member.MemberInfo.Name,
                                                          position));
            }

            _positionalArguments.Add(position, arg);
            _nextPositionalArgIndexToDefine = position + 1;
        }
Beispiel #15
0
        /// <summary>
        /// Retrieves the parse state for the given argument.  If no such state exists,
        /// then a state object is constructed and persisted.
        /// </summary>
        /// <param name="arg">The argument to look up.</param>
        /// <param name="destination">Optionally provides the destination object
        /// being parsed into.</param>
        /// <returns>The parse state for the given argument.</returns>
        private ArgumentParser GetStateForArgument(ArgumentDefinition arg, object destination)
        {
            ArgumentParser parser;

            if (_stateByArg.ContainsKey(arg))
            {
                parser = _stateByArg[arg];

                if (destination != null &&
                    parser.Argument.FixedDestination == null &&
                    parser.DestinationObject != destination)
                {
                    throw new InvalidOperationException();
                }
            }
            else
            {
                parser = _stateByArg[arg] = new ArgumentParser(ArgumentSet, arg, _options, destination);
            }

            return(parser);
        }
Beispiel #16
0
        public static void AddToArgumentSet(
            ArgumentSetDefinition argSet,
            Type typeToReflectOn,
            object defaultValues    = null,
            object fixedDestination = null,
            ArgumentDefinition containingArgument = null,
            ServiceConfigurer serviceConfigurer   = null)
        {
            // Extract argument descriptors from the defining type.
            var args = GetArgumentDescriptors(
                typeToReflectOn,
                argSet,
                defaultValues,
                fixedDestination,
                containingArgument,
                serviceConfigurer).ToList();

            // Define the arguments.
            argSet.Add(args);

            // If the provided type we're reflecting on has an ArgumentSetAttribute,
            // then add that as auxiliary information.
            var auxiliaryAttrib = TryGetSetAttribute(typeToReflectOn);

            if (auxiliaryAttrib != null)
            {
                argSet.AddAuxiliaryAttribute(auxiliaryAttrib);
            }

            // If the argument set doesn't already have a default assembly associated
            // with it, then fill that out.
            if (argSet.DefaultAssembly == null)
            {
                argSet.DefaultAssembly = typeToReflectOn.GetTypeInfo().Assembly;
            }
        }
Beispiel #17
0
 /// <summary>
 /// Try to look up a positional argument by position.
 /// </summary>
 /// <param name="position">0-based position index to look up.</param>
 /// <param name="arg">On success, receives the argument.</param>
 /// <returns>True on success; false otherwise.</returns>
 public bool TryGetPositionalArgument(int position, out ArgumentDefinition arg) => _positionalArguments.TryGetValue(position, out arg);
        /// <summary>
        /// Try to look up a named argument by short or long name.
        /// </summary>
        /// <param name="nameType">Type of name to look up.</param>
        /// <param name="name">Name to look up.</param>
        /// <param name="arg">On success, receives the named argument.</param>
        /// <returns>True on success; false otherwise.</returns>
        public bool TryGetNamedArgument(ArgumentNameType nameType, string name, out ArgumentDefinition arg)
        {
            var dict = GetNamedArgumentDictionary(nameType);

            return(dict.TryGetValue(name, out arg));
        }
Beispiel #19
0
 /// <summary>
 /// Adds an argument.
 /// </summary>
 /// <param name="arg">Argument to define.</param>
 public void AddArgument(ArgumentDefinition arg) => Add(new[] { arg });
Beispiel #20
0
        private void AddNamedArgument(ArgumentDefinition argument)
        {
            //
            // Validate and register the long name.
            //

            if (_namedArgumentsByName.ContainsKey(argument.LongName))
            {
                throw new InvalidArgumentSetException(argument, string.Format(
                                                          CultureInfo.CurrentCulture,
                                                          Strings.DuplicateArgumentLongName,
                                                          argument.LongName));
            }

            _namedArgumentsByName.Add(argument.LongName, argument);

            //
            // Validate and register the short name.
            //

            if (!string.IsNullOrEmpty(argument.ShortName))
            {
                if (_namedArgumentsByName.TryGetValue(argument.ShortName, out ArgumentDefinition conflictingArg))
                {
                    Debug.Assert(conflictingArg != null);
                    if (argument.ExplicitShortName)
                    {
                        if (conflictingArg.ExplicitShortName)
                        {
                            throw new InvalidArgumentSetException(argument, string.Format(CultureInfo.CurrentCulture,
                                                                                          Strings.DuplicateArgumentShortName,
                                                                                          argument.ShortName));
                        }
                        else
                        {
                            // TODO: Decide whether this works for dynamically imported args.
                            _namedArgumentsByName.Remove(conflictingArg.ShortName);
                            conflictingArg.ClearShortName();
                        }
                    }
                    else
                    {
                        argument.ClearShortName();
                    }
                }
            }

            if (!string.IsNullOrEmpty(argument.ShortName))
            {
                if (Attribute.AllowMultipleShortNamesInOneToken &&
                    argument.ShortName.Length > 1)
                {
                    throw new InvalidArgumentSetException(argument, string.Format(CultureInfo.CurrentCulture,
                                                                                  Strings.ArgumentShortNameTooLong,
                                                                                  argument.ShortName));
                }

                _namedArgumentsByName.Add(argument.ShortName, argument);
            }

            // Add to unique list.
            _namedArguments.Add(argument);
        }
Beispiel #21
0
        private static IEnumerable <ArgumentDefinition> CreateArgumentDescriptorsIfApplicable(IMutableMemberInfo member, object defaultValues,
                                                                                              ArgumentSetDefinition argSet, object fixedDestination, ArgumentDefinition containingArgument, ServiceConfigurer serviceConfigurer)
        {
            var descriptors = Enumerable.Empty <ArgumentDefinition>();

            var argAttrib = member.MemberInfo.GetSingleAttribute <ArgumentBaseAttribute>();

            if (argAttrib != null)
            {
                descriptors = descriptors.Concat(
                    new[]
                {
                    CreateArgumentDescriptor(
                        member,
                        argAttrib,
                        defaultValues,
                        argSet,
                        fixedDestination,
                        containingArgument,
                        serviceConfigurer)
                });
            }

            return(descriptors);
        }
Beispiel #22
0
        private static IEnumerable <ArgumentDefinition> GetArgumentDescriptors(Type type, ArgumentSetDefinition argSet, object defaultValues, object fixedDestination, ArgumentDefinition containingArgument, ServiceConfigurer serviceConfigurer)
        {
            // Find all fields and properties that have argument attributes on
            // them. For each that we find, capture information about them.
            var argList = GetAllFieldsAndProperties(type, includeNonPublicMembers: true)
                          .SelectMany(member => CreateArgumentDescriptorsIfApplicable(member, defaultValues, argSet, fixedDestination, containingArgument, serviceConfigurer));

            // If the argument set attribute indicates that we should also
            // include un-attributed, public, writable members as named
            // arguments, then look for them now.
            if (argSet.Attribute.PublicMembersAreNamedArguments)
            {
                argList = argList.Concat(GetAllFieldsAndProperties(type, includeNonPublicMembers: false)
                                         .Where(member => member.IsWritable)
                                         .Where(member => member.MemberInfo.GetSingleAttribute <ArgumentBaseAttribute>() == null)
                                         .Select(member => CreateArgumentDescriptor(
                                                     member,
                                                     new NamedArgumentAttribute(),
                                                     defaultValues,
                                                     argSet,
                                                     fixedDestination,
                                                     containingArgument,
                                                     serviceConfigurer)));
            }

            return(argList);
        }
Beispiel #23
0
 /// <summary>
 /// Try to look up a named argument by name (short name or long name).
 /// </summary>
 /// <param name="name">Name to look up.</param>
 /// <param name="arg">On success, receives the named argument.</param>
 /// <returns>True on success; false otherwise.</returns>
 public bool TryGetNamedArgument(string name, out ArgumentDefinition arg) => _namedArgumentsByName.TryGetValue(name, out arg);