From e676e35e023d09ed21c95ddad9646a7337f85562 Mon Sep 17 00:00:00 2001 From: Aleksander Cynarski Date: Mon, 21 Apr 2025 08:15:19 +0200 Subject: [PATCH] feat: plugins --- .gitignore | 4 ++++ Automancer.csproj | 4 ++++ Commands/Container/Module.cs | 17 ++++++--------- Commands/Image/Module.cs | 15 ++++++------- Common/CommandRegistry.cs | 13 ----------- Common/ICommandModule.cs | 15 ------------- Program.cs | 42 +++++++++++++++++++++++++----------- plugins/.gitkeep | 0 8 files changed, 50 insertions(+), 60 deletions(-) delete mode 100644 Common/CommandRegistry.cs delete mode 100644 Common/ICommandModule.cs create mode 100644 plugins/.gitkeep diff --git a/.gitignore b/.gitignore index e4a167e..39b78d5 100644 --- a/.gitignore +++ b/.gitignore @@ -400,6 +400,10 @@ FodyWeavers.xsd *.sln.iml # End of https://www.toptal.com/developers/gitignore/api/csharp + .DS_Store .vscode .idea + +plugins/* +!plugins/.gitkeep \ No newline at end of file diff --git a/Automancer.csproj b/Automancer.csproj index f4d5391..f42b80d 100644 --- a/Automancer.csproj +++ b/Automancer.csproj @@ -7,7 +7,11 @@ enable + + + + diff --git a/Commands/Container/Module.cs b/Commands/Container/Module.cs index 5599757..5155dd9 100644 --- a/Commands/Container/Module.cs +++ b/Commands/Container/Module.cs @@ -4,21 +4,16 @@ using Spectre.Console.Cli; namespace Automancer.Command.Container; -public class Module : ICommandModuleWithRegistry +public class Module : ICommandModule { - public void Configure(IConfigurator config) - { - // No implementation needed here - } - + public string Name => "container"; + public string Description => "Container operations"; public void Configure(IConfigurator config, CommandRegistry registry) { - config.AddBranch("container", container => + config.AddBranch(Name, container => { - var description = "Container operations"; - - container.SetDescription(description); - registry.Add("container", description); + container.SetDescription(Description); + registry.Add(Name, Description); container.AddCommand("ps").WithDescription("List containers"); }); diff --git a/Commands/Image/Module.cs b/Commands/Image/Module.cs index 111d209..2722d8c 100644 --- a/Commands/Image/Module.cs +++ b/Commands/Image/Module.cs @@ -3,18 +3,15 @@ using Spectre.Console.Cli; namespace Automancer.Command.Image; -public class Module : ICommandModuleWithRegistry +public class Module : ICommandModule { - public void Configure(IConfigurator config) - { - // No implementation needed here - } + public string Name => "image"; + public string Description => "Docker/podman image operations"; public void Configure(IConfigurator config, CommandRegistry registry) { - config.AddBranch("image", image => { - var description = "Docker/podman image operations"; - image.SetDescription(description); - registry.Add("image", description); + config.AddBranch(Name, image => { + image.SetDescription(Description); + registry.Add(Name, Description); image.AddCommand("build").WithDescription("Build a docker image"); image.AddCommand("push").WithDescription("Push a docker image"); diff --git a/Common/CommandRegistry.cs b/Common/CommandRegistry.cs deleted file mode 100644 index 3c4a611..0000000 --- a/Common/CommandRegistry.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Automancer.Common; - -public record CommandInfo(string Path, string? Description); - -public class CommandRegistry -{ - public List Commands { get; } = new(); - - public void Add(string path, string? description) - { - Commands.Add(new CommandInfo(path, description)); - } -} diff --git a/Common/ICommandModule.cs b/Common/ICommandModule.cs deleted file mode 100644 index 1fadae4..0000000 --- a/Common/ICommandModule.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Automancer.Common; - -using Spectre.Console.Cli; - -public interface ICommandModule -{ - - void Configure(IConfigurator config); - -} - -public interface ICommandModuleWithRegistry : ICommandModule -{ - void Configure(IConfigurator config, CommandRegistry registry); -} \ No newline at end of file diff --git a/Program.cs b/Program.cs index bca5197..eff5883 100644 --- a/Program.cs +++ b/Program.cs @@ -9,10 +9,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Spectre.Console.Cli; -using Spectre.Console; -using System.Diagnostics.CodeAnalysis; + using Automancer.Commands; +using System.Reflection; public abstract class Program { @@ -41,6 +41,7 @@ public abstract class Program var registry = new CommandRegistry(); services.AddSingleton(registry); + LoadPluginAssemblies("plugins"); RegisterCommandModules(services); var registrar = new TypeRegistrar(services); @@ -58,15 +59,9 @@ public abstract class Program foreach (var module in modules) { - if (module is ICommandModuleWithRegistry withRegistry) - { - withRegistry.Configure(config, registry); - } - else - { - module.Configure(config); - } + module.Configure(config, registry); } + }); }) .Build(); @@ -76,14 +71,17 @@ public abstract class Program private static void RegisterCommandModules(IServiceCollection services) { + var moduleType = typeof(ICommandModule); var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - + var moduleTypes = assemblies .SelectMany(a => { try { return a.GetTypes(); } - catch { return []; } + catch { + return []; + } }) .Where(t => moduleType.IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract) .ToList(); @@ -94,4 +92,24 @@ public abstract class Program services.AddSingleton(typeof(ICommandModule), type); } } + + private static void LoadPluginAssemblies(string pluginDirectory) + { + if (!Directory.Exists(pluginDirectory)) + return; + + var dlls = Directory.GetFiles(pluginDirectory, "*.dll", SearchOption.AllDirectories); + + foreach (var dll in dlls) + { + try + { + var asm = Assembly.LoadFrom(dll); + } + catch (Exception ex) + { + Console.WriteLine($"[WARN] Failed to load plugin '{dll}': {ex.Message}"); + } + } + } } \ No newline at end of file diff --git a/plugins/.gitkeep b/plugins/.gitkeep new file mode 100644 index 0000000..e69de29