| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using Quadarax.Foundation.Core.Console;
- using Quadarax.Foundation.Core.QConsole.Attributes;
- using Quadarax.Foundation.Core.QConsole.Command.Base;
- using Quadarax.Foundation.Core.QConsole.Configuration;
- using Quadarax.Foundation.Core.QConsole.Context;
- namespace Quadarax.Foundation.Core.QConsole
- {
- public class Engine : IDisposable
- {
- #region *** Private Fields ***
- private bool _isDispoising;
- private bool _isExitSignal;
- private IList<AbstractCommand> _commands = new List<AbstractCommand>();
- private StartupConfiguration _configuration;
- private IList<ISelectionEntry> _selections = new List<ISelectionEntry>();
- #endregion
- #region *** Properties ***
- public string[] RawArguments { get; }
- public StartupConfiguration Configuration => _configuration;
- public AbstractCommand[] Commands => _commands.ToArray();
- public ISelectionEntry[] Selections => _selections.ToArray();
- public IEngineContext Context { get; }
- public int ReturnCode { get; private set; }
- #endregion
- #region *** Constructor ***
- public Engine(StartupConfiguration configuration, IEngineContext context, string[] args)
- {
- _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
- Context = context ?? throw new ArgumentNullException(nameof(context));
- ReturnCode = 0;
- if (args == null)
- args = new string[0];
- // correction of arguments (fix " values)
- for (var i = 0; i < args.Length; i++)
- {
- if (args[i].Contains(" ") && args[i].Contains(configuration.CharacterNamedArgumentValueSeparator) ||
- args[i].Contains(configuration.CharacterNamedArgumentSeparator) && args[i].Contains(configuration.CharacterNamedArgumentValueSeparator))
- {
- var parts = args[i].Split(new[] {configuration.CharacterNamedArgumentValueSeparator},
- StringSplitOptions.RemoveEmptyEntries);
- if (parts.Length == 2)
- args[i] = parts[0] + configuration.CharacterNamedArgumentValueSeparator + configuration.CharacterTextValueBraceSeparator + parts[1] +
- configuration.CharacterTextValueBraceSeparator;
- else
- args[i] = parts[0] + configuration.CharacterNamedArgumentValueSeparator + configuration.CharacterTextValueBraceSeparator + string.Join(":",parts.Skip(1).Take(parts.Length - 1)) +
- configuration.CharacterTextValueBraceSeparator;
- }
- }
- // Ensure if debug mode -> Enable debug mode and remove explicit argument
- if (args.Any(x => x.Trim().ToLower() == Constants.Console.DebugModeExplicitArg))
- {
- configuration.EnableDebugMode();
- var newArgs = new List<string>(args);
- newArgs.Remove(Constants.Console.DebugModeExplicitArg);
- args = newArgs.ToArray();
- }
- WriteDebugInfo($"Console '{_configuration.ConsoleName}' initialization started.");
- WriteDebugInfo($"Engine assembly version '{Assembly.GetExecutingAssembly().GetName().Version}'.");
- WriteDebugInfo($"IsInitFromXml is set to '{_configuration.IsInitFromXml}'.");
- ShowHeader();
- RawArguments = args;
- WriteDebugInfo($"Input {args.Length} arguments appended.");
- WriteDebugInfo($"Context set: {Context}");
- var commandClasses = GetTypesWithHelpAttribute(new CommandDefinitionAttribute());
- WriteDebugInfo($"Console found {commandClasses.Count()} command definitions.");
- var paramConstrTypes = new Type[] { typeof(Engine) };
- var paramConstrValues = new object[] { this };
- foreach (var commandClass in commandClasses)
- {
- var command = Construct<AbstractCommand>(commandClass, paramConstrTypes, paramConstrValues);
- _commands.Add(command);
- WriteDebugInfo($"Command definition '{command}' added - class '{command.GetType().FullName}', assembly '{command.GetType().Assembly.GetName().Name}'.");
- }
- WriteDebugInfo("Console initialized.");
- }
- public void Start()
- {
- WriteDebugInfo("Console starting.");
- var commandLineArguments = string.Join(" ", RawArguments);
- using (var writer = new ConsoleWriter(ConsoleColor.White))
- {
- while (!_isExitSignal)
- {
- var input = string.Empty;
- if (commandLineArguments.Length == 0 && Configuration.AllowInteractive)
- {
- // interactive command entry
- writer.Write(_configuration.CharacterLineIntroduce);
- input = System.Console.ReadLine();
- }
- else
- {
- // inline command entry
- input = commandLineArguments;
- _isExitSignal = true;
- }
- var args = input.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
- if (args.Length == 0)
- {
- if (_isExitSignal == true && !Configuration.AllowInteractive &&
- Configuration.HandlerNothingToDo != null)
- {
- Configuration.HandlerNothingToDo.Invoke(this);
- }
- continue;
- }
- var command = GetCommand(args[0]);
- if (command == null)
- {
- using (var writerError = new ConsoleWriter(ConsoleColor.Red))
- {
- writerError.WriteLine($"Unknown command '{args[0]}'.");
- }
- continue;
- }
- var result = command.Execute(input);
- ReturnCode = result.Code;
- if (result.IsSuccess)
- {
- using (var writerSucc = new ConsoleWriter(ConsoleColor.Green))
- {
- writerSucc.WriteLine("Done.");
- }
- }
- else
- {
- using (var writerError = new ConsoleWriter(ConsoleColor.Red))
- {
- writerError.WriteLine("Error:");
- var e = result.ThrownException;
- if (e is AggregateException aggr)
- {
- foreach (var ex in aggr.InnerExceptions)
- DumpException(writerError, ex);
- }
- else
- while (e != null)
- {
- writerError.WriteLine(e.Message);
- e = e.InnerException;
- }
- }
- }
- }
- if (!Configuration.AllowInteractive && Configuration.WaitOnKeyInNonInteractiveMode)
- {
- WriteDebugInfo("Waiting for the key by configuration settings...");
- using (var writerGreen = new ConsoleWriter(ConsoleColor.Magenta))
- {
- writerGreen.WriteLine("Press any key to close...");
- System.Console.ReadKey();
- }
- }
- }
- }
- public void Stop()
- {
- _isExitSignal = true;
- WriteDebugInfo("Console stopped.");
- }
- public AbstractCommand GetCommand(string commandName)
- {
- return _commands.FirstOrDefault(x => x.Name.ToUpper() == commandName.ToUpper());
- }
- public void AppendSelection(params ISelectionEntry[] selectionEntries)
- {
- if (selectionEntries == null)
- throw new ArgumentNullException(nameof(selectionEntries));
- foreach (var entry in selectionEntries)
- {
- _selections.Add(entry);
- }
- WriteDebugInfo($"{selectionEntries.Length} was added to global selections. Total count {_selections.Count} entries.");
- }
- public void ClearSelection()
- {
- _selections.Clear();
- WriteDebugInfo("Global selections was cleared.");
- }
- public ISelectionEntry GetSelection(int ordinal)
- {
- if (ordinal==0)
- throw new ArgumentOutOfRangeException(nameof(ordinal), "Ordinal value must be greater than 0.");
- if (_selections.Count < ordinal)
- throw new ArgumentOutOfRangeException(nameof(ordinal), $"Ordinal value must be less than {_selections.Count}.");
- return _selections[ordinal - 1];
- }
-
- #endregion
- #region *** Public Operations ***
- public void Dispose()
- {
- if (_isDispoising)
- return;
- _isDispoising = true;
- WriteDebugInfo("Dispoising called.");
- OnDispoising();
- WriteDebugInfo("Dispoising done.");
- }
- #endregion
- #region *** Protected Operations ***
- protected virtual void OnDispoising()
- {
- }
- protected virtual void OnShowHeader()
- {
- var headerText = string.IsNullOrEmpty(_configuration.ConsoleCopyright) ? @"{0} * {1}" : @"{0} * {1} * {2}";
- using (var writer = new ConsoleWriter(ConsoleColor.Green))
- {
- writer.WriteLine(!string.IsNullOrEmpty(_configuration.ConsoleCopyright)
- ? string.Format(headerText, _configuration.ConsoleName, _configuration.ConsoleVersion,
- _configuration.ConsoleCopyright)
- : string.Format(headerText, _configuration.ConsoleName, _configuration.ConsoleVersion));
- }
- }
- #endregion
- #region *** Private Operations ***
- private static T Construct<T>(Type instance, Type[] paramTypes, object[] paramValues)
- {
- var ci = instance.GetConstructor(
- BindingFlags.Instance | BindingFlags.Public,
- null, paramTypes, null);
- if (ci == null)
- throw new Exception($"Command class '{instance.FullName}' has not public constuctor defined or has bad constructor's format.");
- return (T)ci.Invoke(paramValues);
- }
- private IEnumerable<Type> GetTypesWithHelpAttribute(Attribute attribute)
- {
-
- WriteDebugInfo($"Loading command assemblies ...");
- var defaultTypes = Assembly.GetExecutingAssembly().GetTypes().Where(type => type.GetCustomAttributes(attribute.GetType(), true).Length > 0).Distinct().ToList();
-
- var customTypes = new List<Type>();
- if (_configuration.CommandDefinitionAssebmly != null)
- {
- foreach (var assembly in _configuration.CommandDefinitionAssebmly)
- {
- customTypes.AddRange(assembly.GetTypes().Where(type => type.GetCustomAttributes(attribute.GetType(), true).Length > 0).Distinct().ToArray());
- WriteDebugInfo(assembly.GetName().Name + " was scanned for commands.");
- }
- }
- else
- {
- WriteDebugInfo("Custom CommandDefinitionAssembly is not defined. Skip.");
- }
- WriteDebugInfo($"Command definition obtaining process found {defaultTypes.Count} default definitions and {customTypes.Count} custom definitions.");
- defaultTypes.AddRange(customTypes);
- defaultTypes = defaultTypes.Distinct().ToList();
- foreach (var disabledCommand in _configuration.DisabledCommands)
- {
- var disabled = defaultTypes.FirstOrDefault(x => x.Name == disabledCommand);
- if (disabled==null)
- continue;
- defaultTypes.Remove(disabled);
- WriteDebugInfo($"Commnad class '{disabled.Name}', fullname '{disabled.FullName}', assembly '{disabled.Assembly.GetName().Name}' was skipped by configuration.");
- }
- return defaultTypes.ToArray();
- }
- private void WriteDebugInfo(string text)
- {
- using (var debug = new DebugConsoleWriter())
- {
- debug.WriteDebugLine(text);
- }
- }
- private void DumpException(ConsoleWriter writer, Exception e)
- {
- while (e != null)
- {
- writer.WriteLine("- " + e.Message);
- e = e.InnerException;
- }
- }
- private void ShowHeader()
- {
- OnShowHeader();
- }
- #endregion
- }
- }
|