From 956d9b28bae0c151fdd6abb8377fb2e422aa8d59 Mon Sep 17 00:00:00 2001 From: Avius Date: Sun, 28 Jul 2024 11:14:31 +0200 Subject: [PATCH] AsyncCommandBase & auto syntax & .NET 8.0 --- source/ECF.AutoFac/.nuspec | 16 +++++++++--- source/ECF.AutoFac/ECF.AutoFac.csproj | 9 +++++-- .../ECF.Microsoft.DependencyInjection/.nuspec | 16 +++++++++--- .../ECF.Microsoft.DependencyInjection.csproj | 9 +++++-- source/ECF.Templates/ECFTemplates.csproj | 2 +- .../templates/ECF.Autofac/NewProject.csproj | 4 +-- .../templates/ECF/NewProject.csproj | 4 +-- source/ECF/.nuspec | 10 +++++++- source/ECF/AsyncCommandBase.cs | 8 ++++++ source/ECF/CommandArguments.cs | 6 +++++ source/ECF/CommandBase.cs | 25 ++++++++++++++----- .../CommandBaseComponents/CommandArgument.cs | 4 +++ .../ECF/CommandBaseComponents/CommandFlag.cs | 6 +++++ .../CommandBaseComponents/CommandParameter.cs | 12 +++++++++ .../ICommandBaseParameter.cs | 5 ++++ .../CommandBaseComponents/PropertyArgument.cs | 12 ++++++--- .../ECF/CommandBaseComponents/PropertyFlag.cs | 14 ++++++++--- .../PropertyParameter.cs | 21 ++++++++++++---- source/ECF/Commands/NotFoundCommand.cs | 2 +- source/ECF/ECF.csproj | 8 ++++-- source/ECF/Engine/CommandProcessor.cs | 9 +++---- source/ECF/Utilities/CommandDispatcher.cs | 5 +++- source/publish-templates.cmd | 4 +-- 23 files changed, 165 insertions(+), 46 deletions(-) create mode 100644 source/ECF/AsyncCommandBase.cs diff --git a/source/ECF.AutoFac/.nuspec b/source/ECF.AutoFac/.nuspec index 9355d1d..4b5af9e 100644 --- a/source/ECF.AutoFac/.nuspec +++ b/source/ECF.AutoFac/.nuspec @@ -2,7 +2,7 @@ EasyConsoleFramework.AutoFac - 0.2.1 + 0.2.2 Easy Console Framewok - Framework for building command based IoC console application. This package is using AutoFac library for IoC. Aviuz console IoC ecf autofac @@ -18,16 +18,22 @@ - + - + + + + + + + @@ -41,5 +47,9 @@ + + + + \ No newline at end of file diff --git a/source/ECF.AutoFac/ECF.AutoFac.csproj b/source/ECF.AutoFac/ECF.AutoFac.csproj index 2a810dc..b2f505d 100644 --- a/source/ECF.AutoFac/ECF.AutoFac.csproj +++ b/source/ECF.AutoFac/ECF.AutoFac.csproj @@ -1,10 +1,10 @@  - net6.0;net7.0 + net6.0;net7.0;net8.0 enable enable - 0.2.0 + 0.2.2 @@ -17,6 +17,11 @@ + + + + + diff --git a/source/ECF.Microsoft.DependencyInjection/.nuspec b/source/ECF.Microsoft.DependencyInjection/.nuspec index 92524fd..4a03c05 100644 --- a/source/ECF.Microsoft.DependencyInjection/.nuspec +++ b/source/ECF.Microsoft.DependencyInjection/.nuspec @@ -2,7 +2,7 @@ ECF - 0.2.1 + 0.2.2 Easy Console Framewok - Framework for building command based IoC console application. This package is using Microsoft.Extensions.DependencyInjection library for IoC Aviuz console IoC ecf DependencyInjection @@ -18,16 +18,22 @@ - + - + + + + + + + @@ -41,5 +47,9 @@ + + + + \ No newline at end of file diff --git a/source/ECF.Microsoft.DependencyInjection/ECF.Microsoft.DependencyInjection.csproj b/source/ECF.Microsoft.DependencyInjection/ECF.Microsoft.DependencyInjection.csproj index d1b1ab3..b090a00 100644 --- a/source/ECF.Microsoft.DependencyInjection/ECF.Microsoft.DependencyInjection.csproj +++ b/source/ECF.Microsoft.DependencyInjection/ECF.Microsoft.DependencyInjection.csproj @@ -1,10 +1,10 @@ - net6.0;net7.0 + net6.0;net7.0;net8.0 enable enable - 0.2.0 + 0.2.2 ECF ECF @@ -18,6 +18,11 @@ + + + + + diff --git a/source/ECF.Templates/ECFTemplates.csproj b/source/ECF.Templates/ECFTemplates.csproj index c9ca034..c58bf06 100644 --- a/source/ECF.Templates/ECFTemplates.csproj +++ b/source/ECF.Templates/ECFTemplates.csproj @@ -2,7 +2,7 @@ Template - 0.2.0 + 0.2.2 ECFTemplates ECF Templates Aviuz diff --git a/source/ECF.Templates/templates/ECF.Autofac/NewProject.csproj b/source/ECF.Templates/templates/ECF.Autofac/NewProject.csproj index 00a062f..4a26e65 100644 --- a/source/ECF.Templates/templates/ECF.Autofac/NewProject.csproj +++ b/source/ECF.Templates/templates/ECF.Autofac/NewProject.csproj @@ -2,13 +2,13 @@ Exe - net6.0 + net8.0 enable enable - + diff --git a/source/ECF.Templates/templates/ECF/NewProject.csproj b/source/ECF.Templates/templates/ECF/NewProject.csproj index c5b6255..82a95f8 100644 --- a/source/ECF.Templates/templates/ECF/NewProject.csproj +++ b/source/ECF.Templates/templates/ECF/NewProject.csproj @@ -2,13 +2,13 @@ Exe - net6.0 + net8.0 enable enable - + diff --git a/source/ECF/.nuspec b/source/ECF/.nuspec index 15cf66c..71be2fa 100644 --- a/source/ECF/.nuspec +++ b/source/ECF/.nuspec @@ -2,7 +2,7 @@ EasyConsoleFramework.Base - 0.2.0 + 0.2.2 Easy Console Framewok - Framework for building command based IoC console application. This package is base library without any IoC dependency. Aviuz console IoC ecf @@ -24,6 +24,10 @@ + + + + @@ -37,5 +41,9 @@ + + + + \ No newline at end of file diff --git a/source/ECF/AsyncCommandBase.cs b/source/ECF/AsyncCommandBase.cs new file mode 100644 index 0000000..f2e886d --- /dev/null +++ b/source/ECF/AsyncCommandBase.cs @@ -0,0 +1,8 @@ +namespace ECF; + +public abstract class AsyncCommandBase : CommandBase +{ + public override sealed void Execute() => ExecuteAsync().Wait(); + + public abstract Task ExecuteAsync(); +} \ No newline at end of file diff --git a/source/ECF/CommandArguments.cs b/source/ECF/CommandArguments.cs index 761b00c..6bca943 100644 --- a/source/ECF/CommandArguments.cs +++ b/source/ECF/CommandArguments.cs @@ -4,5 +4,11 @@ public class CommandArguments { public string CommandName { get; set; } public string[] Arguments { get; set; } + + public CommandArguments(string commandName, string[] arguments) + { + CommandName = commandName; + Arguments = arguments; + } } } diff --git a/source/ECF/CommandBase.cs b/source/ECF/CommandBase.cs index bb1ff57..c7b754a 100644 --- a/source/ECF/CommandBase.cs +++ b/source/ECF/CommandBase.cs @@ -61,11 +61,7 @@ public virtual void ApplyArguments(CommandArguments args) public virtual string GetHelp() { - var commandAttribute = GetType().GetCustomAttributes() - .Select(attr => attr as ICommandAttribute) - .Where(attr => attr != null) - .Cast() - .First(); + ICommandAttribute commandAttribute = GetCommandAttribute(); string usageParameters = GetSyntaxExpression(); string description = GetDescription(); string parametersHelp = GetParametersHelp(); @@ -130,9 +126,26 @@ public bool IsFlagActive(string key) return values.BoolValues[key]; } + private ICommandAttribute GetCommandAttribute() + { + return GetType().GetCustomAttributes() + .Select(attr => attr as ICommandAttribute) + .Where(attr => attr != null) + .Cast() + .First(); + } + private string GetSyntaxExpression() { - return GetType().GetCustomAttribute()?.SyntaxExpression ?? string.Empty; + string? customSyntax = GetType().GetCustomAttribute()?.SyntaxExpression; + if (customSyntax != null) return customSyntax; // for developer specified syntax + + var strParts = parameters + .OrderBy(x => x.GetOrder()) + .Select(x => x.GetSyntaxToken()) + .Where(x => x != null); + + return string.Join(" ", strParts); } private string GetDescription() diff --git a/source/ECF/CommandBaseComponents/CommandArgument.cs b/source/ECF/CommandBaseComponents/CommandArgument.cs index f2c62c9..45d00b2 100644 --- a/source/ECF/CommandBaseComponents/CommandArgument.cs +++ b/source/ECF/CommandBaseComponents/CommandArgument.cs @@ -44,5 +44,9 @@ public void AppendHelp(StringBuilder sb) } public string SectionName() => "Arguments"; + + public int GetOrder() => attribute.Index; + + public string GetSyntaxToken() => $"<{attribute.Name}>"; } } diff --git a/source/ECF/CommandBaseComponents/CommandFlag.cs b/source/ECF/CommandBaseComponents/CommandFlag.cs index 9a1aa0a..9648bcc 100644 --- a/source/ECF/CommandBaseComponents/CommandFlag.cs +++ b/source/ECF/CommandBaseComponents/CommandFlag.cs @@ -41,5 +41,11 @@ public void AppendHelp(StringBuilder sb) } public string SectionName() => "Flags"; + + public int GetOrder() => int.MaxValue; + + public string GetSyntaxToken() => !string.IsNullOrWhiteSpace(attribute.LongName) + ? "--" + attribute.LongName + : "-" + attribute.ShortName; } } diff --git a/source/ECF/CommandBaseComponents/CommandParameter.cs b/source/ECF/CommandBaseComponents/CommandParameter.cs index 603b162..940f2d7 100644 --- a/source/ECF/CommandBaseComponents/CommandParameter.cs +++ b/source/ECF/CommandBaseComponents/CommandParameter.cs @@ -45,5 +45,17 @@ public void AppendHelp(StringBuilder sb) } public string SectionName() => "Parameters"; + + public int GetOrder() => int.MaxValue - 1; + + public string? GetSyntaxToken() + { + if(!string.IsNullOrEmpty(attribute.LongName)) + return $"--{attribute.LongName} "; + else if(string.IsNullOrEmpty(attribute.ShortName)) + return $"-{attribute.ShortName} "; + else + return null; + } } } diff --git a/source/ECF/CommandBaseComponents/ICommandBaseParameter.cs b/source/ECF/CommandBaseComponents/ICommandBaseParameter.cs index 43e1d58..331eb2d 100644 --- a/source/ECF/CommandBaseComponents/ICommandBaseParameter.cs +++ b/source/ECF/CommandBaseComponents/ICommandBaseParameter.cs @@ -4,9 +4,14 @@ namespace ECF.CommandBaseComponents { internal interface ICommandBaseParameter { + // command execution bool TryMatch(ArgumentIterator visitor); void Apply(ArgumentIterator visitor, ValueDictionary valueDictionary); + + // help generation void AppendHelp(StringBuilder sb); string SectionName(); + int GetOrder(); + string? GetSyntaxToken(); } } diff --git a/source/ECF/CommandBaseComponents/PropertyArgument.cs b/source/ECF/CommandBaseComponents/PropertyArgument.cs index 744ede0..0a0e005 100644 --- a/source/ECF/CommandBaseComponents/PropertyArgument.cs +++ b/source/ECF/CommandBaseComponents/PropertyArgument.cs @@ -5,13 +5,13 @@ namespace ECF.CommandBaseComponents { internal class PropertyArgument : ICommandBaseParameter { - private readonly CommandBase command; + private readonly object parent; private readonly PropertyInfo propertyInfo; private readonly ArgumentAttribute attribute; - public PropertyArgument(CommandBase command, PropertyInfo propertyInfo, ArgumentAttribute attribute) + public PropertyArgument(object parent, PropertyInfo propertyInfo, ArgumentAttribute attribute) { - this.command = command; + this.parent = parent; this.propertyInfo = propertyInfo; this.attribute = attribute; } @@ -32,7 +32,7 @@ public bool TryMatch(ArgumentIterator visitor) public void Apply(ArgumentIterator visitor, ValueDictionary valueDictionary) { - propertyInfo.SetValue(command, Convert.ChangeType(visitor.Take(false), propertyInfo.PropertyType)); + propertyInfo.SetValue(parent, Convert.ChangeType(visitor.Take(false), propertyInfo.PropertyType)); } public void AppendHelp(StringBuilder sb) @@ -49,5 +49,9 @@ public void AppendHelp(StringBuilder sb) } public string SectionName() => "Arguments"; + + public int GetOrder() => attribute.Index; + + public string GetSyntaxToken() => $"<{attribute.Name}>"; } } diff --git a/source/ECF/CommandBaseComponents/PropertyFlag.cs b/source/ECF/CommandBaseComponents/PropertyFlag.cs index 622bb2c..ab1e897 100644 --- a/source/ECF/CommandBaseComponents/PropertyFlag.cs +++ b/source/ECF/CommandBaseComponents/PropertyFlag.cs @@ -6,13 +6,13 @@ namespace ECF.CommandBaseComponents { internal class PropertyFlag : ICommandBaseParameter { - private readonly CommandBase command; + private readonly object parent; private readonly PropertyInfo propertyInfo; private readonly FlagAttribute attribute; - public PropertyFlag(CommandBase command, PropertyInfo propertyInfo, FlagAttribute attribute) + public PropertyFlag(object parent, PropertyInfo propertyInfo, FlagAttribute attribute) { - this.command = command; + this.parent = parent; this.propertyInfo = propertyInfo; this.attribute = attribute; } @@ -32,7 +32,7 @@ public void Apply(ArgumentIterator visitor, ValueDictionary valueDictionary) if (propertyInfo.PropertyType != typeof(bool)) throw new CommandBaseParseException($"Property {propertyInfo.Name} need to be of type bool to be treated as flag."); - propertyInfo.SetValue(command, true); + propertyInfo.SetValue(parent, true); } public void AppendHelp(StringBuilder sb) @@ -51,5 +51,11 @@ public void AppendHelp(StringBuilder sb) } public string SectionName() => "Flags"; + + public int GetOrder() => int.MaxValue; + + public string GetSyntaxToken() => !string.IsNullOrWhiteSpace(attribute.LongName) + ? "--" + attribute.LongName + : "-" + attribute.ShortName; } } diff --git a/source/ECF/CommandBaseComponents/PropertyParameter.cs b/source/ECF/CommandBaseComponents/PropertyParameter.cs index c9cb68e..86dc930 100644 --- a/source/ECF/CommandBaseComponents/PropertyParameter.cs +++ b/source/ECF/CommandBaseComponents/PropertyParameter.cs @@ -1,5 +1,4 @@ using ECF.Exceptions; -using ECF.Utilities; using System.Reflection; using System.Text; @@ -7,13 +6,13 @@ namespace ECF.CommandBaseComponents { internal class PropertyParameter : ICommandBaseParameter { - private readonly CommandBase command; + private readonly object parent; private readonly PropertyInfo propertyInfo; private readonly ParameterAttribute attribute; - public PropertyParameter(CommandBase command, PropertyInfo propertyInfo, ParameterAttribute attribute) + public PropertyParameter(object parent, PropertyInfo propertyInfo, ParameterAttribute attribute) { - this.command = command; + this.parent = parent; this.propertyInfo = propertyInfo; this.attribute = attribute; } @@ -35,7 +34,7 @@ public void Apply(ArgumentIterator visitor, ValueDictionary valueDictionary) string? value = visitor.Take(true); try { - propertyInfo.SetValue(command, Convert.ChangeType(value, propertyInfo.PropertyType)); + propertyInfo.SetValue(parent, Convert.ChangeType(value, propertyInfo.PropertyType)); } catch (FormatException) { @@ -59,5 +58,17 @@ public void AppendHelp(StringBuilder sb) } public string SectionName() => "Parameters"; + + public int GetOrder() => int.MaxValue - 1; + + public string? GetSyntaxToken() + { + if (!string.IsNullOrEmpty(attribute.LongName)) + return $"--{attribute.LongName} "; + else if (string.IsNullOrEmpty(attribute.ShortName)) + return $"-{attribute.ShortName} "; + else + return null; + } } } diff --git a/source/ECF/Commands/NotFoundCommand.cs b/source/ECF/Commands/NotFoundCommand.cs index a3eb0f6..3669b0b 100644 --- a/source/ECF/Commands/NotFoundCommand.cs +++ b/source/ECF/Commands/NotFoundCommand.cs @@ -2,7 +2,7 @@ { public class NotFoundCommand : ICommand { - private string commandName; + private string? commandName; public void ApplyArguments(CommandArguments args) { diff --git a/source/ECF/ECF.csproj b/source/ECF/ECF.csproj index 8ea67c4..b3fe855 100644 --- a/source/ECF/ECF.csproj +++ b/source/ECF/ECF.csproj @@ -1,10 +1,10 @@  - net6.0;net7.0 + net6.0;net7.0;net8.0 enable enable - 0.2.0 + 0.2.2 ECF ECF.Base @@ -17,4 +17,8 @@ + + + + diff --git a/source/ECF/Engine/CommandProcessor.cs b/source/ECF/Engine/CommandProcessor.cs index 81c28d3..80bf3f8 100644 --- a/source/ECF/Engine/CommandProcessor.cs +++ b/source/ECF/Engine/CommandProcessor.cs @@ -34,10 +34,9 @@ public void Process(string[] args) private CommandArguments ParseArguments(string[] args) { - return new CommandArguments() - { - CommandName = args[0], - Arguments = args.Skip(1).ToArray(), - }; + return new CommandArguments( + commandName: args[0], + arguments: args.Skip(1).ToArray() + ); } } \ No newline at end of file diff --git a/source/ECF/Utilities/CommandDispatcher.cs b/source/ECF/Utilities/CommandDispatcher.cs index d875d6e..dfa512d 100644 --- a/source/ECF/Utilities/CommandDispatcher.cs +++ b/source/ECF/Utilities/CommandDispatcher.cs @@ -16,7 +16,10 @@ public void ExecuteCommand(params string[] commandArgs) where T : ICommand using (var nestedScope = iocProvider.BeginNestedScope()) { var command = nestedScope.Resolve(); - command.ApplyArguments(new CommandArguments() { Arguments = commandArgs }); + command.ApplyArguments(new CommandArguments( + commandName: string.Empty, + arguments: commandArgs + )); command.Execute(); } } diff --git a/source/publish-templates.cmd b/source/publish-templates.cmd index 4e77e13..3d6032a 100644 --- a/source/publish-templates.cmd +++ b/source/publish-templates.cmd @@ -1,3 +1,3 @@ dotnet build ./ECF.Templates/ECFTemplates.csproj -nuget pack ./ECF.Templates/ECFTemplates.csproj -move ./ECFTemplates*.nupkg ../packages/ \ No newline at end of file +dotnet pack ./ECF.Templates/ECFTemplates.csproj +move .\ECF.Templates\bin\Release\ECFTemplates*.nupkg ..\packages\