Пример #1
0
        public static bool IsAsync(ConsoleCommand command,
            CommandList commands)
        {
            // Validate the command name:
            var found = false;
            Dictionary<string, ConsoleExecutingMethod> methodDictionary = null;
            foreach (var key in commands.Keys.Where(key => key.Namespace == command.LibraryClassName))
            {
                found = true;
                methodDictionary = commands[key];
                break;
            }
            if (!found)
            {
                return false;

            }
            if (!methodDictionary.ContainsKey(command.Name))
            {
                var newCommand = char.ToUpperInvariant(command.Name[0]) + command.Name.Substring(1);
                if (!methodDictionary.ContainsKey(newCommand))
                {
                    return false;
                }
                command.Name = char.ToUpperInvariant(command.Name[0]) + command.Name.Substring(1);
            }
            return methodDictionary[command.Name].Async;
        }
Пример #2
0
        public static async Task<ConsoleExecuteResult> ExecuteAsync(ConsoleCommand command,
            CommandList commands)
        {
            ConsoleExecutingAssembly instance;
            Dictionary<string, ConsoleExecutingMethod> methodDictionary;
            if (!ValidateCommand(command, commands, out instance, out methodDictionary))
            {
                return new ConsoleExecuteResult($"Unrecognized command \'{command.LibraryClassName}.{command.Name}\'. " +
                                       "Please type a valid command.");
            }

            object[] inputArgs;
            Type typeInfo;
            string errorMessage;
            if (BuildCommand(command, instance, methodDictionary,
                out inputArgs,
                out typeInfo,
                out errorMessage))
            {

                // This will throw if the number of arguments provided does not match the number 
                // required by the method signature, even if some are optional:
                int? id = -1;
                try
                {
                    //add the command to the current macro if capture is enabled
                    id = _consoleMacro?.Add(command.RawCommand);
                    var result = await ((Task<ConsoleExecuteResult>) typeInfo.InvokeMember(
                        command.Name,
                        BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
                        null, instance.Instance, inputArgs)).ConfigureAwait(false);
                    return result;
                }
                catch (TargetInvocationException ex)
                {
                    //remove bad commands from the macro
                    if (id.HasValue && id > -1)
                    {
                        _consoleMacro?.Remove(id.Value);
                    }
                    throw ex.InnerException;
                }
            }
            return new ConsoleExecuteResult(errorMessage);
        }
Пример #3
0
        private static bool BuildCommand(ConsoleCommand command,
            ConsoleExecutingAssembly instance,
            IReadOnlyDictionary<string, ConsoleExecutingMethod> methodDictionary,
            out object[] inputArgs,
            out Type typeInfo,
            out string errorMessage)
        {
            inputArgs = null;
            typeInfo = null;
            errorMessage = null;

            // Make sure the correct number of required arguments are provided:
            // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            var methodParameterValueList = new List<object>();
            IEnumerable<ParameterInfo> paramInfoList = methodDictionary[command.Name].Parameters.ToList();

            // Validate proper # of required arguments provided. Some may be optional:
            var requiredParams = paramInfoList.Where(p => !p.IsOptional).ToList();
            var optionalParams = paramInfoList.Where(p => p.IsOptional).ToList();
            var requiredCount = requiredParams.Count;
            var optionalCount = optionalParams.Count;
            var providedCount = command.Arguments.Count();

            if (requiredCount > providedCount)
            {
                var message = new StringBuilder();
                message.AppendLine(
                    $"Missing required argument. {requiredCount} required, {optionalCount} optional, {providedCount} provided");

                if (requiredCount > 0)
                {
                    message.AppendLine("");
                    message.AppendLine("Required");
                    foreach (var required in requiredParams)
                    {
                        message.Append(required.Name);
                        message.Append(":");
                        message.AppendLine(required.ParameterType.ToString());
                    }
                }

                if (optionalParams.Count > 0)
                {
                    message.AppendLine("");
                    message.AppendLine("Optional");
                    foreach (var required in optionalParams)
                    {
                        message.Append(required.Name);
                        message.Append(":");
                        message.Append(required.ParameterType);
                        message.Append(":");
                        message.AppendLine(required.RawDefaultValue?.ToString() ?? "null");
                    }
                }

                errorMessage = message.ToString();
                return false; 
            }

            // Make sure all arguments are coerced to the proper type, and that there is a 
            // value for every method parameter. The InvokeMember method fails if the number 
            // of arguments provided does not match the number of parameters in the 
            // method signature, even if some are optional:
            // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            if (paramInfoList.Any())
            {
                // Populate the list with default values:
                methodParameterValueList.AddRange(paramInfoList.Select(param => param.DefaultValue));

                // Now walk through all the arguments passed from the console and assign 
                // accordingly. Any optional arguments not provided have already been set to 
                // the default specified by the method signature:
                for (var i = 0; i < command.Arguments.Count(); i++)
                {
                    var methodParam = paramInfoList.ElementAt(i);
                    var typeRequired = methodParam.ParameterType;
                    try
                    {
                        // Coming from the Console, all of our arguments are passed in as 
                        // strings. Coerce to the type to match the method parameter:
                        var value = ConsoleParseArgument.CoerceArgument(typeRequired, command.Arguments.ElementAt(i));
                        methodParameterValueList.RemoveAt(i);
                        methodParameterValueList.Insert(i, value);
                    }
                        // ReSharper disable once UncatchableException
                    catch (ArgumentException ex)
                    {
                        var argumentName = methodParam.Name;
                        var argumentTypeName = typeRequired.Name;
                        var message =
                            $"The value passed for argument '{argumentName}' cannot be parsed to type '{argumentTypeName}'";
                        throw new ArgumentException(message, ex);
                    }
                }
            }

            // Set up to invoke the method using reflection:
            // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            // Need the full Namespace for this:
            var commandLibraryClass =
                instance.Instance.GetType();

            if (methodParameterValueList.Count > 0)
            {
                inputArgs = methodParameterValueList.ToArray();
            }
            typeInfo = commandLibraryClass;
            return true;
        }
Пример #4
0
        private static bool ValidateCommand(ConsoleCommand command, 
            CommandList commands, 
            out ConsoleExecutingAssembly instance,
            out Dictionary<string, ConsoleExecutingMethod> methodDictionary)
        {
            instance = null;
            methodDictionary = null;
            // Validate the command name:
            var found = false;
            foreach (var key in commands.Keys.Where(key => key.Namespace == command.LibraryClassName))
            {
                found = true;
                instance = key;
                methodDictionary = commands[key];
                break;
            }
            if (!found)
            {
                return false;

            }
            if (!methodDictionary.ContainsKey(command.Name))
            {
                var newCommand = char.ToUpperInvariant(command.Name[0]) + command.Name.Substring(1);
                if (!methodDictionary.ContainsKey(newCommand))
                {
                    return false;
                }
                command.Name = char.ToUpperInvariant(command.Name[0]) + command.Name.Substring(1);
            }
            return true; 
        }
Пример #5
0
        /// <summary>
        /// Shells the control1 on command entered.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="commandEnteredEventArgs">The <see cref="CommandEnteredEventArgs"/> instance containing the event data.</param>
        private async void ShellControl1OnCommandEntered(object sender, CommandEnteredEventArgs commandEnteredEventArgs)
        {
            if (string.IsNullOrWhiteSpace(commandEnteredEventArgs.Command)) return;
            var async = false;
            try
            {
                // Create a ConsoleCommand instance:
                var cmd = new ConsoleCommand(commandEnteredEventArgs.Command.Trim().Replace("\t", ""));

                // Execute the command:
                ConsoleExecuteResult result;
                if (ConsoleExecute.IsAsync(cmd, _commandLibraries))
                {
                    Interlocked.Increment(ref _asyncCount);
                    async = true;
                    result =
                        await
                            ConsoleExecute.ExecuteAsync(cmd, _commandLibraries).ConfigureAwait(false);
                }
                else
                {
                    result = ConsoleExecute.Execute(cmd, _commandLibraries);
                }

                // Write out the result:
                WriteToConsole(result.Message);

                if (result.Action != null && result.Action.Action == ConsoleExecuteActions.Exit)
                {
                    //If we exit here and async tasks are running, we won't ever finish them. That's because they are tied to the shell's command event...
                    if (Interlocked.Read(ref _asyncCount) == 0)
                    {
                        shellControl1.CommandEntered -= ShellControl1OnCommandEntered;
                        Close();
                    }
                    else
                    {
                        WriteToConsole($"Async tasks are still running {Interlocked.Read(ref _asyncCount)}");
                    }
                }
                else if (result.Action != null && result.Action.Action == ConsoleExecuteActions.StatusUri)
                {
                    queueStatusControl1.Display(result.Action.Target);
                }
                else if (result.Action != null && result.Action.Action == ConsoleExecuteActions.StartProcess)
                {
                    Process.Start(result.Action.Target);
                }
                else if (result.Action != null && result.Action.Action == ConsoleExecuteActions.StartMacro)
                {
                    ConsoleExecute.StartMacroCapture();
                }
                else if (result.Action != null && result.Action.Action == ConsoleExecuteActions.CancelMacro)
                {
                    ConsoleExecute.CancelMacroCapture();
                }
                else if (result.Action != null && result.Action.Action == ConsoleExecuteActions.SaveMacro)
                {
                    ConsoleExecute.SaveMacro(Path.Combine(Path.GetDirectoryName(_commandAssembly.Location) + @"\Macro\", result.Action.Target));
                }
                else if (result.Action != null && result.Action.Action == ConsoleExecuteActions.RunMacro)
                {
                    shellControl1.PrintLine();
                    foreach(ConsoleExecuteResult command in ConsoleExecute.RunMacro(Path.Combine(Path.GetDirectoryName(_commandAssembly.Location) + @"\Macro\", result.Action.Target)))
                    {
                        if (command.Action.Action == ConsoleExecuteActions.RunCommand)
                        {
                            shellControl1.SendCommand(command.Action.Target);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                WriteToConsole(ex.ToString());
            }
            finally
            {
                if (async)
                {
                    Interlocked.Decrement(ref _asyncCount);
                }
            }
        }