Esempio n. 1
0
        /// <summary>
        /// Attempts to resolve a valid parsed input to a registered command
        /// </summary>
        /// <param name="input">The valid parsed input</param>
        /// <returns>A resolved command</returns>
        public ResolvedCommand Resolve(ParsedInput input)
        {
            // is input valid

            if (!input.IsValid)
            {
                throw new CommandResolutionException(input, "The provided input is invalid and cannot be resolved");
            }

            // does cmd exist

            var cmdInfo = _registry.Commands.FirstOrDefault(c => c.Name.Equals(input.GetCommandElement().Value, StringComparison.OrdinalIgnoreCase));

            if (cmdInfo == null)
            {
                return(new ResolvedCommand(input, CommandResolutionErrorType.CommandNotFound));
            }

            // begin to accumulate errors

            var errors = new List <ResolveCommandError>();

            // capture argument errors - unknown arguments, options with values

            var inputMap = new Dictionary <ArgumentInfo, ParsedInputElement>();

            foreach (var node in input.Elements.Where(n => n.ElementType == InputElementType.ArgumentName || n.ElementType == InputElementType.ArgumentAlias))
            {
                var argInfo = node.ElementType == InputElementType.ArgumentName
                        ? cmdInfo.Arguments.SingleOrDefault(p => p.Name.Equals(node.Value, StringComparison.OrdinalIgnoreCase))
                        : cmdInfo.Arguments.SingleOrDefault(p => p.Alias.Equals(node.Value.Single()));

                CaptureArgumentErrors(
                    errors,
                    argInfo,
                    node);

                if (argInfo != null)
                {
                    if (!inputMap.ContainsKey(argInfo))
                    {
                        inputMap.Add(argInfo, node);
                    }
                    else
                    {
                        errors.Add(new ResolveCommandError
                        {
                            Type    = CommandResolutionErrorType.DuplicateArgument,
                            Element = node,
                            Message = $"Arguments \"{node.Raw}\" and \"{inputMap[argInfo].Raw}\" resolve the same argument property."
                        });
                    }
                }
            }

            return(new ResolvedCommand(input, cmdInfo, new ReadOnlyDictionary <ArgumentInfo, ParsedInputElement>(inputMap), errors));
        }
        public async Task <int> Run(string inputStr)
        {
            try
            {
                // create new cancellation token source

                _currentCancellationTokenSource = new CancellationTokenSource();

                // ensure only one execution at a time

                if (IsRunning)
                {
                    throw new InvalidOperationException("Another command is already executing");
                }
                IsRunning = true;

                // parse input

                var input = new ParsedInput(inputStr);

                if (!input.IsValid)
                {
                    // process input parsing errors

                    foreach (var err in input.Errors)
                    {
                        switch (err.Type)
                        {
                        case ParsedInputValidationErrorType.NoCommandElement:
                            _interface.WriterCollection.Error.WriteLine("Invalid input :: no command element defined");
                            break;

                        case ParsedInputValidationErrorType.InvalidAlias:
                            _interface.WriterCollection.Error.WriteLine($"Invalid alisas :: [{err.Element.StartPosition}] {err.Element.Raw} - {err.Message}");
                            break;

                        default:
                            throw new ArgumentOutOfRangeException($"Value \"{err.Type}\" not defined for switch.");
                        }
                    }

                    // list unexpected values

                    foreach (var elem in input.Elements.Where(e => e.ElementType == InputElementType.Unexpected))
                    {
                        _interface.WriterCollection.Error.WriteLine($"Unexpected element :: [{elem.StartPosition}] {elem.Raw}");
                    }

                    return((int)ExecutionReturnCode.UnexpectedElements);
                }

                // resolve command

                var resCmd = _resolver.Resolve(input);

                if (!resCmd.IsValid)
                {
                    foreach (var err in resCmd.Errors)
                    {
                        switch (err.Type)
                        {
                        case CommandResolutionErrorType.CommandNotFound:
                            _interface.WriterCollection.Error.WriteLine($"Command, \"{input.GetCommandElement().Value}\" not found");
                            break;

                        case CommandResolutionErrorType.ArgumentNotFound:
                        case CommandResolutionErrorType.UnexpectedValue:
                        case CommandResolutionErrorType.DuplicateArgument:
                            _interface.WriterCollection.Error.WriteLine($"{err.Message} :: [{err.Element.StartPosition}] {err.Element.Raw}");
                            break;

                        default:
                            throw new ArgumentOutOfRangeException($"Value \"{err.Type}\" not defined for switch.");
                        }
                    }
                    return((int)ExecutionReturnCode.CommandResolutionError);
                }

                // activate and execute

                return(await ExecuteCommand(_activator.Activate(resCmd)));
            }
            finally
            {
                IsRunning = false;
                _currentCancellationTokenSource.Dispose();
            }
        }