private static void ValidateArguments(IEnumerable <CommandLineArgument> arguments) { List <string> knownAliases = new List <string>(); foreach (var argument in arguments) { foreach (var alias in argument.Aliases) { if (knownAliases.Contains(alias, new CaseAwareStringComparer(argument.IgnoreCase))) { throw new InvalidArgDefinitionException("Duplicate alias '" + alias + "' on argument '" + argument.Aliases.First() + "'"); } knownAliases.Add(alias); } } foreach (var argument in arguments) { if (argument.ArgumentType == null) { throw new InvalidArgDefinitionException("Argument '" + argument.DefaultAlias + "' has a null ArgumentType"); } if (argument.MustBeRevivable && ArgRevivers.CanRevive(argument.ArgumentType) == false) { throw new InvalidArgDefinitionException("There is no reviver for type '" + argument.ArgumentType.Name + '"'); } if (argument.ArgumentType.IsEnum) { argument.ArgumentType.ValidateNoDuplicateEnumShortcuts(argument.IgnoreCase); } } }
internal static CommandLineAction Create(MethodInfo actionMethod, List <string> knownAliases) { var ret = PropertyInitializer.CreateInstance <CommandLineAction>(); ret.ActionMethod = actionMethod; ret.Source = actionMethod; ret.Aliases.Add(actionMethod.Name); ret.Metadata.AddRange(actionMethod.Attrs <IArgMetadata>().AssertAreAllInstanceOf <ICommandLineActionMetadata>()); ret.IgnoreCase = true; if (actionMethod.DeclaringType.HasAttr <ArgIgnoreCase>() && actionMethod.DeclaringType.Attr <ArgIgnoreCase>().IgnoreCase == false) { ret.IgnoreCase = false; } if (actionMethod.HasAttr <ArgIgnoreCase>() && actionMethod.Attr <ArgIgnoreCase>().IgnoreCase == false) { ret.IgnoreCase = false; } var directPipelineTarget = (from p in actionMethod.GetParameters() where p.HasAttr <ArgPipelineTarget>() select p).SingleOrDefault(); if (directPipelineTarget != null) { if (directPipelineTarget.Attr <ArgPipelineTarget>().PipelineOnly == false && ArgRevivers.CanRevive(directPipelineTarget.ParameterType) == false) { throw new InvalidArgDefinitionException("Method " + actionMethod.DeclaringType.FullName + "." + actionMethod.Name + " has parameter " + directPipelineTarget.Name + " of type " + directPipelineTarget.ParameterType.FullName + " which has set PipelineOnly to false, but has no reviver"); } ret.Arguments.AddRange(actionMethod.GetParameters().Where(p => CommandLineArgument.IsArgument(p)).Select(p => CommandLineArgument.Create(p))); foreach (var arg in (ret.Arguments).Where(a => a.Position >= 0)) { arg.Position++; // Since position 0 is reserved for the action specifier } } else { if (actionMethod.GetParameters().Length == 1 && ArgRevivers.CanRevive(actionMethod.GetParameters()[0].ParameterType) == false) { ret.Arguments.AddRange(actionMethod.GetParameters()[0].ParameterType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => CommandLineArgument.IsArgument(p)).Select(p => CommandLineArgument.Create(p, knownAliases))); } else if (actionMethod.GetParameters().Length > 0 && actionMethod.GetParameters().Where(p => ArgRevivers.CanRevive(p.ParameterType) == false).Count() == 0) { ret.Arguments.AddRange(actionMethod.GetParameters().Where(p => CommandLineArgument.IsArgument(p)).Select(p => CommandLineArgument.Create(p))); foreach (var arg in (ret.Arguments).Where(a => a.Position >= 0)) { arg.Position++; // Since position 0 is reserved for the action specifier } } else if (actionMethod.GetParameters().Length > 0) { throw new InvalidArgDefinitionException("Your action method contains a parameter that cannot be revived on its own. That is only valid if the non-revivable parameter is the only parameter. In that case, the properties of that parameter type will be used."); } } return(ret); }
internal static void Revive(this PropertyInfo prop, object toRevive, ArgHook.HookContext context) { if (ArgRevivers.CanRevive(prop.PropertyType) && context.ArgumentValue != null) { try { if (prop.PropertyType.IsEnum) { bool ignoreCase = true; if (prop.HasAttr <ArgIgnoreCase>() && prop.Attr <ArgIgnoreCase>().IgnoreCase == false) { ignoreCase = true; } context.RevivedProperty = ArgRevivers.ReviveEnum(prop.PropertyType, context.ArgumentValue, ignoreCase); } else { context.RevivedProperty = ArgRevivers.Revive(prop.PropertyType, prop.GetArgumentName(), context.ArgumentValue); } prop.SetValue(toRevive, context.RevivedProperty, null); } catch (ArgException) { throw; } catch (Exception ex) { if (ex.InnerException != null && ex.InnerException is ArgException) { throw ex.InnerException; } else { if (prop.PropertyType.IsEnum) { throw new ArgException("'" + context.ArgumentValue + "' is not a valid value for " + prop.GetArgumentName() + ". Available values are [" + string.Join(", ", Enum.GetNames(prop.PropertyType)) + "]", ex); } else { throw new ArgException(ex.Message, ex); } } } } else if (ArgRevivers.CanRevive(prop.PropertyType) && prop.PropertyType == typeof(SecureStringArgument)) { context.RevivedProperty = ArgRevivers.Revive(prop.PropertyType, prop.GetArgumentName(), context.ArgumentValue); prop.SetValue(toRevive, context.RevivedProperty, null); } else if (context.ArgumentValue != null) { throw new ArgException("Unexpected argument '" + prop.GetArgumentName() + "' with value '" + context.ArgumentValue + "'"); } }
private static void ValidateArguments(IEnumerable <CommandLineArgument> arguments) { List <string> knownAliases = new List <string>(); foreach (var argument in arguments) { foreach (var alias in argument.Aliases) { if (knownAliases.Contains(alias, new CaseAwareStringComparer(argument.IgnoreCase))) { throw new InvalidArgDefinitionException("Duplicate alias '" + alias + "' on argument '" + argument.Aliases.First() + "'"); } knownAliases.Add(alias); } } foreach (var argument in arguments) { if (argument.ArgumentType == null) { throw new InvalidArgDefinitionException("Argument '" + argument.DefaultAlias + "' has a null ArgumentType"); } if (argument.MustBeRevivable && ArgRevivers.CanRevive(argument.ArgumentType) == false) { throw new InvalidArgDefinitionException("There is no reviver for type '" + argument.ArgumentType.Name + '"'); } if (argument.ArgumentType.IsEnum) { argument.ArgumentType.ValidateNoDuplicateEnumShortcuts(argument.IgnoreCase); } foreach (var property in argument.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { // Getting each property will result in all AttrOverrides being validated try { var val = property.GetValue(argument, null); } catch (TargetInvocationException ex) { if (ex.InnerException is InvalidArgDefinitionException) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } else { throw; } } } } }
internal void Revive(string commandLineValue) { if (ArgRevivers.CanRevive(ArgumentType) && commandLineValue != null) { try { if (ArgumentType.IsEnum) { RevivedValue = ArgRevivers.ReviveEnum(ArgumentType, commandLineValue, IgnoreCase); } else { RevivedValue = ArgRevivers.Revive(ArgumentType, Aliases.First(), commandLineValue); } } catch (ArgException) { throw; } catch (Exception ex) { if (ex.InnerException != null && ex.InnerException is ArgException) { throw ex.InnerException; } else { if (ArgumentType.IsEnum) { throw new ArgException("'" + commandLineValue + "' is not a valid value for " + Aliases.First() + ". Available values are [" + string.Join(", ", Enum.GetNames(ArgumentType)) + "]", ex); } else { throw new ArgException(ex.Message, ex); } } } } else if (ArgRevivers.CanRevive(ArgumentType) && ArgumentType == typeof(SecureStringArgument)) { RevivedValue = ArgRevivers.Revive(ArgumentType, Aliases.First(), commandLineValue); } else if (commandLineValue != null && ArgRevivers.CanRevive(ArgumentType)) { throw new ArgException("Unexpected argument '" + Aliases.First() + "' with value '" + commandLineValue + "'"); } else if (commandLineValue != null && ArgRevivers.CanRevive(ArgumentType) == false) { throw new InvalidArgDefinitionException("There is no reviver for type '" + ArgumentType.Name + '"'); } }
internal object PopulateArguments(object parent, ref object[] parameters) { Type actionArgsType = null; if (Source is PropertyInfo) { actionArgsType = (Source as PropertyInfo).PropertyType; } else if (Source is MethodInfo && (Source as MethodInfo).GetParameters().Length > 0) { if ((Source as MethodInfo).GetParameters().Length > 1 || ArgRevivers.CanRevive((Source as MethodInfo).GetParameters()[0].ParameterType)) { parameters = Arguments.Select(a => a.RevivedValue).ToArray(); return(null); } else { actionArgsType = (Source as MethodInfo).GetParameters()[0].ParameterType; } } else { return(null); } var ret = Activator.CreateInstance(actionArgsType); foreach (var argument in Arguments) { var argumentProperty = argument.Source as PropertyInfo; if (argumentProperty != null) { argumentProperty.SetValue(ret, argument.RevivedValue, null); } } if (Source is PropertyInfo) { (Source as PropertyInfo).SetValue(parent, ret, null); } return(ret); }
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; 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); } }
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); } } } }