feat: plugins
This commit is contained in:
parent
cea3d11a41
commit
e676e35e02
4
.gitignore
vendored
4
.gitignore
vendored
@ -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
|
@ -7,7 +7,11 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<ProjectReference Include="../Automancer.Common/Automancer.Common.csproj" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0-preview.3.25171.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0-preview.3.25171.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.0-preview.3.25171.5" />
|
||||
|
@ -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<PsCommand>("ps").WithDescription("List containers");
|
||||
});
|
||||
|
@ -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<BuildCommand>("build").WithDescription("Build a docker image");
|
||||
image.AddCommand<PushCommand>("push").WithDescription("Push a docker image");
|
||||
|
@ -1,13 +0,0 @@
|
||||
namespace Automancer.Common;
|
||||
|
||||
public record CommandInfo(string Path, string? Description);
|
||||
|
||||
public class CommandRegistry
|
||||
{
|
||||
public List<CommandInfo> Commands { get; } = new();
|
||||
|
||||
public void Add(string path, string? description)
|
||||
{
|
||||
Commands.Add(new CommandInfo(path, description));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
42
Program.cs
42
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
0
plugins/.gitkeep
Normal file
0
plugins/.gitkeep
Normal file
Loading…
x
Reference in New Issue
Block a user