Exemple #1
0
        private PropertyInfo FindSpecifiedAction(Type t, ref string[] args)
        {
            var actionProperty = ArgAction.GetActionProperty(t);

            if (actionProperty == null)
            {
                return(null);
            }

            var specifiedAction = args.Length > 0 ? args[0] : null;

            if (actionProperty.Attr <ArgRequired>().PromptIfMissing&& args.Length == 0)
            {
                actionProperty.Attr <ArgRequired>().ValidateAlways(actionProperty, ref specifiedAction);
                args = new string[] { specifiedAction };
            }

            if (specifiedAction == null)
            {
                return(null);
            }

            var actionArgProperty = (from p in t.GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                     where p.MatchesSpecifiedAction(specifiedAction)
                                     select p).SingleOrDefault();

            if (actionArgProperty == null)
            {
                throw new UnknownActionArgException("Unknown Action: " + specifiedAction);
            }

            return(actionArgProperty);
        }
Exemple #2
0
        private void PopulateProperties(ArgHook.HookContext context)
        {
            context.Args.GetType().RunBeforePopulateProperties(context);
            foreach (PropertyInfo prop in context.Args.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                var match = from k in context.ParserData.ExplicitParameters.Keys
                            where prop.MatchesSpecifiedArg(k)
                            select k;

                if (match.Count() > 1)
                {
                    throw new DuplicateArgException("Argument specified more than once: " + prop.GetArgumentName());
                }

                if (match.Count() == 1)
                {
                    var key = match.First();
                    context.ArgumentValue = context.ParserData.ExplicitParameters[key];
                    context.ParserData.ExplicitParameters.Remove(key);
                }
                else
                {
                    if (prop.HasAttr <ArgPosition>() && context.ParserData.ImplicitParameters.ContainsKey(prop.Attr <ArgPosition>().Position))
                    {
                        var position = prop.Attr <ArgPosition>().Position;
                        context.ArgumentValue = context.ParserData.ImplicitParameters[position];
                        context.ParserData.ImplicitParameters.Remove(position);
                    }
                    else
                    {
                        context.ArgumentValue = null;
                    }
                }


                context.Property = prop;

                prop.RunBeforePopulateProperty(context);

                bool shouldValidateAndRevive = true;
                if (prop.Attr <ArgIgnoreAttribute>() != null)
                {
                    shouldValidateAndRevive = false;
                }
                if (prop.IsActionArgProperty() && ArgAction.GetActionProperty(context.Args.GetType()) != null)
                {
                    shouldValidateAndRevive = false;
                }

                if (shouldValidateAndRevive)
                {
                    prop.Validate(context);
                    prop.Revive(context.Args, context);
                }

                prop.RunAfterPopulateProperty(context);
            }
            context.Args.GetType().RunAfterPopulateProperties(context);
        }
Exemple #3
0
        internal static List <PropertyInfo> GetActionArgProperties(this Type t)
        {
            if (ArgAction.GetActionProperty(t) == null)
            {
                return(new List <PropertyInfo>());
            }

            return((from prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public)
                    where prop.IsActionArgProperty() select prop).ToList());
        }
        private static string GetShortcutInternal(PropertyInfo info, List <string> knownShortcuts)
        {
            var actionProperty = ArgAction.GetActionProperty(info.DeclaringType);

            if (actionProperty != null && actionProperty.Name == info.Name)
            {
                return(null);
            }

            var attr = info.Attr <ArgShortcut>();

            if (attr == null)
            {
                string shortcutVal = "";
                foreach (char c in info.GetArgumentName())
                {
                    shortcutVal += c;
                    if (knownShortcuts.Contains(shortcutVal) == false)
                    {
                        return(shortcutVal);
                    }
                }
                return(shortcutVal);
            }
            else
            {
                if (attr.policy.HasValue && attr.policy.Value == ArgShortcutPolicy.NoShortcut && attr.Shortcut != null)
                {
                    throw new InvalidArgDefinitionException("You cannot specify a shortcut value and an ArgShortcutPolicy of NoShortcut");
                }

                if (attr.Shortcut == null)
                {
                    return(null);
                }
                if (attr.Shortcut.StartsWith("-"))
                {
                    attr.Shortcut = attr.Shortcut.Substring(1);
                }
                else if (attr.Shortcut.StartsWith("/"))
                {
                    attr.Shortcut = attr.Shortcut.Substring(1);
                }
                return(attr.Shortcut);
            }
        }
        internal static void RegisterShortcuts(Type t, List <string> shortcuts = null)
        {
            RegisteredTypes.Add(t);
            bool isNested = shortcuts != null;

            shortcuts = isNested ? shortcuts : new List <string>();
            var actionProp = ArgAction.GetActionProperty(t);

            foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                if (prop.Attr <ArgIgnoreAttribute>() != null)
                {
                    continue;
                }
                if (prop.IsActionArgProperty() && actionProp != null)
                {
                    continue;
                }

                var shortcut = ArgShortcut.GetShortcutInternal(prop, shortcuts);
                if (shortcut != null)
                {
                    shortcuts.Add(shortcut);
                    if (KnownShortcuts.ContainsKey(prop) == false)
                    {
                        KnownShortcuts.Add(prop, shortcut);
                    }
                    else
                    {
                        KnownShortcuts[prop] = shortcut;
                    }
                }
            }

            if (actionProp != null)
            {
                foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    if (prop.IsActionArgProperty())
                    {
                        RegisterShortcuts(prop.PropertyType, shortcuts);
                    }
                }
            }
        }
Exemple #6
0
        private void ValidateArgScaffold(Type t, List <string> shortcuts = null, Type parentType = null)
        {
            /*
             * Today, this validates the following:
             *
             *     - IgnoreCase can't be different on parent and child scaffolds.
             *     - No collisions on shortcut values for properties and enum values
             *     - No reviver for type
             *
             */

            if (parentType != null)
            {
                if (parentType.HasAttr <ArgIgnoreCase>() ^ t.HasAttr <ArgIgnoreCase>())
                {
                    throw new InvalidArgDefinitionException("If you specify the " + typeof(ArgIgnoreCase).Name + " attribute on your base type then you must also specify it on each action type.");
                }
                else if (parentType.HasAttr <ArgIgnoreCase>() && parentType.Attr <ArgIgnoreCase>().IgnoreCase != t.Attr <ArgIgnoreCase>().IgnoreCase)
                {
                    throw new InvalidArgDefinitionException("If you specify the " + typeof(ArgIgnoreCase).Name + " attribute on your base and acton types then they must be configured to use the same value for IgnoreCase.");
                }
            }

            if (t.Attrs <ArgIgnoreCase>().Count > 1)
            {
                throw new InvalidArgDefinitionException("An attribute that is or derives from " + typeof(ArgIgnoreCase).Name + " was specified on your type more than once");
            }


            var actionProp = ArgAction.GetActionProperty(t);

            shortcuts = shortcuts ?? new List <string>();
            bool ignoreCase = true;

            if (t.HasAttr <ArgIgnoreCase>() && t.Attr <ArgIgnoreCase>().IgnoreCase == false)
            {
                ignoreCase = false;
            }

            foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                if (prop.Attr <ArgIgnoreAttribute>() != null)
                {
                    continue;
                }
                if (CommandLineAction.IsActionImplementation(prop))
                {
                    continue;
                }

                // This check happens in the CommandLineArgumentsDefinition validation method and should not be repeated here.  Leaving the code commented while this bakes, but this code
                // should be removable in the future.
                //if (ArgRevivers.CanRevive(prop.PropertyType) == false)
                //{
                //    throw new InvalidArgDefinitionException("There is no reviver for type " + prop.PropertyType.Name + ". Offending Property: " + prop.DeclaringType.Name + "." + prop.Name);
                //}

                if (prop.PropertyType.IsEnum)
                {
                    prop.PropertyType.ValidateNoDuplicateEnumShortcuts(ignoreCase);
                }

                var attrs = prop.Attrs <ArgShortcut>();
                var noShortcutsAllowed   = attrs.Where(a => a.Policy == ArgShortcutPolicy.NoShortcut).Count() != 0;
                var shortcutsOnly        = attrs.Where(a => a.Policy == ArgShortcutPolicy.ShortcutsOnly).Count() != 0;
                var actualShortcutValues = attrs.Where(a => a.Policy == ArgShortcutPolicy.Default && a.Shortcut != null).Count() != 0;

                if (noShortcutsAllowed && shortcutsOnly)
                {
                    throw new InvalidArgDefinitionException("You cannot specify a policy of NoShortcut and another policy of ShortcutsOnly.");
                }
                if (noShortcutsAllowed && actualShortcutValues)
                {
                    throw new InvalidArgDefinitionException("You cannot specify a policy of NoShortcut and then also specify shortcut values via another attribute.");
                }
                if (shortcutsOnly && actualShortcutValues == false)
                {
                    throw new InvalidArgDefinitionException("You specified a policy of ShortcutsOnly, but did not specify any shortcuts by adding another ArgShortcut attrivute.");
                }
            }

            if (actionProp != null)
            {
                foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    if (CommandLineAction.IsActionImplementation(prop))
                    {
                        ArgAction.ResolveMethod(t, prop);
                        ValidateArgScaffold(prop.PropertyType, shortcuts.ToArray().ToList(), t);
                    }
                }
            }

            foreach (var actionMethod in t.GetActionMethods())
            {
                if (actionMethod.GetParameters().Length == 0)
                {
                    continue;
                }

                ValidateArgScaffold(actionMethod.GetParameters()[0].ParameterType, shortcuts.ToArray().ToList(), t);
            }
        }
Exemple #7
0
        private ArgAction ParseInternal(CommandLineArgumentsDefinition definition, string[] input)
        {
            // TODO - Validation should be consistently done against the definition, not against the raw type
            if (definition.ArgumentScaffoldType != null)
            {
                ValidateArgScaffold(definition.ArgumentScaffoldType);
            }

            var context = ArgHook.HookContext.Current;

            context.Definition = definition;
            _ambientDefinition = definition;

            definition.Validate(context);

            if (definition.ArgumentScaffoldType != null)
            {
                context.Args = Activator.CreateInstance(definition.ArgumentScaffoldType);
            }
            context.CmdLineArgs = input;

            context.RunBeforeParse();
            context.ParserData = ArgParser.Parse(definition, context.CmdLineArgs);

            var actionToken = context.CmdLineArgs.FirstOrDefault();
            var actionQuery = context.Definition.Actions.Where(a => a.IsMatch(actionToken));

            if (actionQuery.Count() == 1)
            {
                context.SpecifiedAction = actionQuery.First();
            }
            else if (actionQuery.Count() > 1)
            {
                throw new InvalidArgDefinitionException("There are multiple actions that match argument '" + actionToken + "'");
            }

            context.RunBeforePopulateProperties();
            CommandLineArgument.PopulateArguments(context.Definition.Arguments, context);
            context.Definition.SetPropertyValues(context.Args);

            object actionArgs = null;

            object[] actionParameters = null;

            if (context.SpecifiedAction == null && context.Definition.Actions.Count > 0)
            {
                if (context.CmdLineArgs.FirstOrDefault() == null)
                {
                    throw new MissingArgException("No action was specified");
                }
                else
                {
                    throw new UnknownActionArgException(string.Format("Unknown action: '{0}'", context.CmdLineArgs.FirstOrDefault()));
                }
            }
            else if (context.SpecifiedAction != null)
            {
                PropertyInfo actionProp = null;
                if (context.Definition.ArgumentScaffoldType != null)
                {
                    actionProp = ArgAction.GetActionProperty(context.Definition.ArgumentScaffoldType);
                }

                if (actionProp != null)
                {
                    actionProp.SetValue(context.Args, context.SpecifiedAction.Aliases.First(), null);
                }

                context.ParserData.ImplicitParameters.Remove(0);
                CommandLineArgument.PopulateArguments(context.SpecifiedAction.Arguments, context);
            }

            context.RunAfterPopulateProperties();

            if (context.SpecifiedAction != null)
            {
                actionArgs = context.SpecifiedAction.PopulateArguments(context.Args, ref actionParameters);
            }

            if (context.Definition.Metadata.HasMeta <AllowUnexpectedArgs>() == false)
            {
                if (context.ParserData.ImplicitParameters.Count > 0)
                {
                    throw new UnexpectedArgException("Unexpected unnamed argument: " + context.ParserData.ImplicitParameters.First().Value);
                }

                if (context.ParserData.ExplicitParameters.Count > 0)
                {
                    throw new UnexpectedArgException("Unexpected named argument: " + context.ParserData.ExplicitParameters.First().Key);
                }
            }
            else
            {
                definition.UnexpectedExplicitArguments = context.ParserData.ExplicitParameters;
                definition.UnexpectedImplicitArguments = context.ParserData.ImplicitParameters;
            }


            if (definition.ArgumentScaffoldType != null)
            {
                if (AmbientArgs.ContainsKey(definition.ArgumentScaffoldType))
                {
                    AmbientArgs[definition.ArgumentScaffoldType] = context.Args;
                }
                else
                {
                    AmbientArgs.Add(definition.ArgumentScaffoldType, context.Args);
                }
            }

            PropertyInfo actionArgsPropertyInfo = null;

            if (context.SpecifiedAction != null)
            {
                if (context.SpecifiedAction.Source is PropertyInfo)
                {
                    actionArgsPropertyInfo = context.SpecifiedAction.Source as PropertyInfo;
                }
                else if (context.SpecifiedAction.Source is MethodInfo)
                {
                    actionArgsPropertyInfo = new ArgActionMethodVirtualProperty(context.SpecifiedAction.Source as MethodInfo);
                }
            }

            return(new ArgAction()
            {
                Value = context.Args,
                ActionArgs = actionArgs,
                ActionParameters = actionParameters,
                ActionArgsProperty = actionArgsPropertyInfo,
                ActionArgsMethod = context.SpecifiedAction != null ? context.SpecifiedAction.ActionMethod : null,
                Definition = context.Definition,
                Context = context,
            });
        }
 internal static bool IsActionImplementation(PropertyInfo property)
 {
     return(property.Name.EndsWith(Constants.ActionArgConventionSuffix) &&
            property.HasAttr <ArgIgnoreAttribute>() == false &&
            ArgAction.GetActionProperty(property.DeclaringType) != null);
 }
Exemple #9
0
        /// <summary>
        /// Generates color styled usage documentation for the given argument scaffold type.
        /// </summary>
        /// <typeparam name="T">Your custom argument scaffold type</typeparam>
        /// <param name="exeName">The name of your program or null if you want PowerArgs to automatically detect it.</param>
        /// <param name="options">Specify custom usage options</param>
        /// <returns></returns>
        public static ConsoleString GetStyledUsage <T>(string exeName = null, ArgUsageOptions options = null)
        {
            options = options ?? new ArgUsageOptions();
            if (exeName == null)
            {
                var assembly = Assembly.GetEntryAssembly();
                if (assembly == null)
                {
                    throw new ArgException("PowerArgs could not determine the name of your executable automatically.  This may happen if you run GetUsage<T>() from within unit tests.  Use GetUsageT>(string exeName) in unit tests to avoid this exception.");
                }
                exeName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
            }

            ConsoleString ret = new ConsoleString();

            ret += new ConsoleString("Usage: " + exeName, ConsoleColor.Cyan);

            var actionProperty = ArgAction.GetActionProperty <T>();

            if (actionProperty != null)
            {
                ret.AppendUsingCurrentFormat(" <action> options\n\n");

                foreach (var example in typeof(T).Attrs <ArgExample>())
                {
                    ret += new ConsoleString("EXAMPLE: " + example.Example + "\n" + example.Description + "\n\n", ConsoleColor.DarkGreen);
                }

                var global = GetOptionsUsage(typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public), true, options);

                if (string.IsNullOrEmpty(global.ToString()) == false)
                {
                    ret += new ConsoleString("Global options:\n\n", ConsoleColor.Cyan) + global + "\n";
                }

                ret += "Actions:";

                foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    if (prop.IsActionArgProperty() == false)
                    {
                        continue;
                    }

                    var actionDescription = prop.HasAttr <ArgDescription>() ? " - " + prop.Attr <ArgDescription>().Description : "";

                    ret += "\n\n" + prop.GetArgumentName().Substring(0, prop.GetArgumentName().Length - Constants.ActionArgConventionSuffix.Length) + actionDescription + "\n\n";

                    foreach (var example in prop.Attrs <ArgExample>())
                    {
                        ret += new ConsoleString() + "   EXAMPLE: " + new ConsoleString(example.Example + "\n", ConsoleColor.Green) +
                               new ConsoleString("   " + example.Description + "\n\n", ConsoleColor.DarkGreen);
                    }

                    ret += GetOptionsUsage(prop.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public), false, options);
                }
            }
            else
            {
                ret.AppendUsingCurrentFormat(" options\n\n");

                ret += GetOptionsUsage(typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public), false, options);

                ret += "\n";

                foreach (var example in typeof(T).Attrs <ArgExample>())
                {
                    ret += new ConsoleString() + "   EXAMPLE: " + new ConsoleString(example.Example + "\n", ConsoleColor.Green) +
                           new ConsoleString("   " + example.Description + "\n\n", ConsoleColor.DarkGreen);
                }
            }

            return(ret);
        }
Exemple #10
0
        private void ValidateArgScaffold(Type t, List <string> shortcuts = null, Type parentType = null)
        {
            if (parentType != null)
            {
                if (parentType.HasAttr <ArgIgnoreCase>() ^ t.HasAttr <ArgIgnoreCase>())
                {
                    throw new InvalidArgDefinitionException("If you specify the " + typeof(ArgIgnoreCase).Name + " attribute on your base type then you must also specify it on each action type.");
                }
                else if (parentType.HasAttr <ArgIgnoreCase>() && parentType.Attr <ArgIgnoreCase>().IgnoreCase != t.Attr <ArgIgnoreCase>().IgnoreCase)
                {
                    throw new InvalidArgDefinitionException("If you specify the " + typeof(ArgIgnoreCase).Name + " attribute on your base and acton types then they must be configured to use the same value for IgnoreCase.");
                }
            }

            if (t.Attrs <ArgIgnoreCase>().Count > 1)
            {
                throw new InvalidArgDefinitionException("An attribute that is or derives from " + typeof(ArgIgnoreCase).Name + " was specified on your type more than once");
            }


            var actionProp = ArgAction.GetActionProperty(t);

            shortcuts = shortcuts ?? new List <string>();
            bool ignoreCase = true;

            if (t.HasAttr <ArgIgnoreCase>() && t.Attr <ArgIgnoreCase>().IgnoreCase == false)
            {
                ignoreCase = false;
            }

            foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                if (prop.Attr <ArgIgnoreAttribute>() != null)
                {
                    continue;
                }
                if (prop.IsActionArgProperty() && actionProp != null)
                {
                    continue;
                }

                if (ArgRevivers.CanRevive(prop.PropertyType) == false)
                {
                    throw new InvalidArgDefinitionException("There is no reviver for type " + prop.PropertyType.Name + ". Offending Property: " + prop.DeclaringType.Name + "." + prop.GetArgumentName());
                }

                var shortcut = ArgShortcut.GetShortcut(prop);

                if (ignoreCase && shortcut != null)
                {
                    shortcut = shortcut.ToLower();
                }

                if (shortcut != null && shortcuts.Contains(shortcut))
                {
                    throw new InvalidArgDefinitionException("Duplicate arg options with shortcut '" + ArgShortcut.GetShortcut(prop) + "'.  Keep in mind that shortcuts are not case sensitive unless you use the [ArgIgnoreCase(false)] attribute.  For example, Without this attribute the shortcuts '-a' and '-A' would cause this exception.");
                }
                else if (shortcut != null)
                {
                    shortcuts.Add(shortcut);
                }
            }

            if (actionProp != null)
            {
                foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    if (prop.IsActionArgProperty())
                    {
                        ArgAction.ResolveMethod(t, prop);
                        ValidateArgScaffold(prop.PropertyType, shortcuts.ToArray().ToList(), t);
                    }
                }
            }
        }