コード例 #1
0
        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);
                }
            });
        }