private int Execute(List <string> args) { CommandLineApplication command = this; CommandOption option = null; IEnumerator <CommandArgument> arguments = null; for (var index = 0; index < args.Count; index++) { var arg = args[index]; if (command.ResponseFileHandling != ResponseFileHandling.Disabled && index > _responseFileArgsEnd && arg.Length > 1 && arg[0] == '@') { var path = arg.Substring(1); var fullPath = Path.IsPathRooted(path) ? path : Path.Combine(command.WorkingDirectory, path); IList <string> rspArgs; try { rspArgs = ResponseFileParser.Parse(fullPath, command.ResponseFileHandling); } catch (Exception ex) { throw new CommandParsingException(this, $"Could not parse the response file '{arg}'", ex); } args.InsertRange(index + 1, rspArgs); _responseFileArgsEnd = index + rspArgs.Count; continue; } var processed = false; if (!processed && option == null) { string[] longOption = null; string[] shortOption = null; if (arg != null) { if (arg.StartsWith("--")) { longOption = arg.Substring(2).Split(new[] { ':', '=' }, 2); } else if (arg.StartsWith("-")) { shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2); } } if (longOption != null) { processed = true; var longOptionName = longOption[0]; option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.LongName, longOptionName, StringComparison.Ordinal)); if (option == null) { if (string.IsNullOrEmpty(longOptionName) && !command.ThrowOnUnexpectedArgument && AllowArgumentSeparator) { // skip over the '--' argument separator index++; } HandleUnexpectedArg(command, args, index, argTypeName: "option"); break; } // If we find a help/version option, show information and stop parsing if (command.OptionHelp == option) { command.ShowHelp(); option.TryParse(null); var parent = command; while (parent.Parent != null) { parent = parent.Parent; } parent.SelectedCommand = command; if (StopParsingAfterHelpOption) { return(0); } } else if (command.OptionVersion == option) { command.ShowVersion(); option.TryParse(null); var parent = command; while (parent.Parent != null) { parent = parent.Parent; } parent.SelectedCommand = command; if (StopParsingAfterVersionOption) { return(0); } } if (longOption.Length == 2) { if (!option.TryParse(longOption[1])) { command.ShowHint(); throw new CommandParsingException(command, $"Unexpected value '{longOption[1]}' for option '{option.LongName}'"); } option = null; } else if (option.OptionType == CommandOptionType.NoValue) { // No value is needed for this option option.TryParse(null); option = null; } } if (shortOption != null) { processed = true; option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.ShortName, shortOption[0], StringComparison.Ordinal)); // If not a short option, try symbol option if (option == null) { option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.SymbolName, shortOption[0], StringComparison.Ordinal)); } if (option == null) { HandleUnexpectedArg(command, args, index, argTypeName: "option"); break; } // If we find a help/version option, show information and stop parsing if (command.OptionHelp == option) { command.ShowHelp(); return(0); } else if (command.OptionVersion == option) { command.ShowVersion(); return(0); } if (shortOption.Length == 2) { if (!option.TryParse(shortOption[1])) { command.ShowHint(); throw new CommandParsingException(command, $"Unexpected value '{shortOption[1]}' for option '{option.LongName}'"); } option = null; } else if (option.OptionType == CommandOptionType.NoValue) { // No value is needed for this option option.TryParse(null); option = null; } } } if (!processed && option != null) { processed = true; if (!option.TryParse(arg)) { command.ShowHint(); throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{option.LongName}'"); } option = null; } if (!processed && arguments == null) { var currentCommand = command; foreach (var subcommand in command.Commands) { if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase)) { processed = true; command = subcommand; break; } } // If we detect a subcommand if (command != currentCommand) { processed = true; } } if (!processed) { if (arguments == null) { arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator()); } if (arguments.MoveNext()) { processed = true; arguments.Current.Values.Add(arg); } } if (!processed) { HandleUnexpectedArg(command, args, index, argTypeName: "command or argument"); break; } } if (option != null) { command.ShowHint(); throw new CommandParsingException(command, $"Missing value for option '{option.LongName}'"); } return(command.Invoke()); }
private static void _ConfigureInvoker(CommandLineApplication command, Type type, MethodInfo methodInfo) { var helpOpt = command.HelpOption(); var parameters = methodInfo.GetParameters(); foreach (var param in parameters) { if (param.GetCustomAttribute <ConventionOptionAttribute>() != null) { _RegisterOption(command, param.ParameterType, _PascalToKebab(param.Name), param.GetCustomAttribute <ConventionDescriptionAttribute>()?.Text ?? "", param.GetCustomAttribute <ConventionIsRequiredAttribute>() != null); } else if (_IsExpectingSingleValue(param.ParameterType) || _IsExpectingMultiValue(param.ParameterType)) { var desc = param.GetCustomAttribute <ConventionDescriptionAttribute>(); var description = desc?.Text ?? ""; command.Argument(param.Name, description, _IsExpectingMultiValue(param.ParameterType)); } } command.OnExecute(() => { if (helpOpt.HasValue()) { return(0); } CancellationTokenSource cts = null; var obj = Activator.CreateInstance(type); var alloptions = command.GetOptions(); foreach (var prop in type.GetProperties()) { var option = alloptions.FirstOrDefault(opt => opt.LongName == _PascalToKebab(prop.Name)); if (option != null) { prop.SetValue(obj, _ExtractValueFromOption(prop.PropertyType, option)); } } if (type.GetMethod("Initialize") != null) { type.GetMethod("Initialize").Invoke(obj, null); } var allArgs = command.Arguments; var handlerParams = new List <object>(); foreach (var param in methodInfo.GetParameters()) { var arg = allArgs.FirstOrDefault(a => a.Name == param.Name); var option = alloptions.FirstOrDefault(opt => opt.LongName == _PascalToKebab(param.Name)); object valueToAdd = null; if (arg != null) { if (arg.MultipleValues) { valueToAdd = _ParseMultiValue(param.ParameterType, arg.Values); } else if (param.HasDefaultValue && arg.Value == null) { valueToAdd = param.DefaultValue; } else { valueToAdd = _ParseSingleValue(param.ParameterType, arg.Value); } } else if (option != null) { if (param.HasDefaultValue && option.HasValue() == false) { valueToAdd = param.DefaultValue; } else { valueToAdd = _ExtractValueFromOption(param.ParameterType, option); } } else if (param.ParameterType == typeof(CancellationToken)) { if (cts == null) { cts = new CancellationTokenSource(); } valueToAdd = cts.Token; } else { if (type.GetMethod("ResolveType") != null) { valueToAdd = type.GetMethod("ResolveType").Invoke(obj, new[] { param.ParameterType }); } else { throw new Exception("Cannot resolve parameter type"); } } if (param.GetCustomAttribute <ConventionIsRequiredAttribute>() != null && valueToAdd == null) { throw new Exception($"{param.Name} is required"); } handlerParams.Add(valueToAdd); } var res = methodInfo.Invoke(obj, handlerParams.ToArray()); if (res.GetType() == typeof(Task <int>)) { var task = (Task <int>)res; System.Console.CancelKeyPress += (sender, e) => { cts?.Cancel(); Task.WaitAll(new[] { task }, 10000); }; AppDomain.CurrentDomain.ProcessExit += (sender, e) => { cts?.Cancel(); Task.WaitAll(new[] { task }, 10000); }; Task.WaitAll(task); return(task.Result); } else { return((int)res); } }); }