feat: Dynamic command loader, default command with module registry
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -402,3 +402,4 @@ FodyWeavers.xsd
 | 
				
			|||||||
# End of https://www.toptal.com/developers/gitignore/api/csharp
 | 
					# End of https://www.toptal.com/developers/gitignore/api/csharp
 | 
				
			||||||
.DS_Store
 | 
					.DS_Store
 | 
				
			||||||
.vscode
 | 
					.vscode
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,11 @@
 | 
				
			|||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <PackageReference Include="Spectre.Console.Cli" Version="0.50.1-preview.0.5" />
 | 
					    <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" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Spectre.Console" Version="0.50.0" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Spectre.Console.Cli" Version="0.50.0" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								Commands/Container/Module.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								Commands/Container/Module.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					using Automancer.Command.Image;
 | 
				
			||||||
 | 
					using Automancer.Common;
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Automancer.Command.Container;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Module : ICommandModuleWithRegistry
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public void Configure(IConfigurator config)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // No implementation needed here
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Configure(IConfigurator config, CommandRegistry registry)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config.AddBranch("container", container =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var description = "Container operations";
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            container.SetDescription(description);
 | 
				
			||||||
 | 
					            registry.Add("container", description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            container.AddCommand<PsCommand>("ps").WithDescription("List containers");
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								Commands/Container/PsCommand.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Commands/Container/PsCommand.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Automancer.Command.Image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class PsSettings: CommandSettings
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [CommandArgument(0, "[path]")]
 | 
				
			||||||
 | 
					    [Description("Path to the Dockerfile")]
 | 
				
			||||||
 | 
					    public string? Path { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [CommandOption("-t|--tag")]
 | 
				
			||||||
 | 
					    [Description("Tag to use for the image")]
 | 
				
			||||||
 | 
					    public string? Tag { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [CommandOption("-f|--file")]
 | 
				
			||||||
 | 
					    [Description("Path to the Dockerfile")]
 | 
				
			||||||
 | 
					    public string? File { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class PsCommand: Command<BuldSettings>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public override int Execute(CommandContext context, BuldSettings settings)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Console.WriteLine($"Building image from {settings.Path} with tag {settings.Tag}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								Commands/Image/BuildCommand.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Commands/Image/BuildCommand.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Automancer.Command.Image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BuldSettings: CommandSettings
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [CommandArgument(0, "[path]")]
 | 
				
			||||||
 | 
					    [Description("Path to the Dockerfile")]
 | 
				
			||||||
 | 
					    public string? Path { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [CommandOption("-t|--tag")]
 | 
				
			||||||
 | 
					    [Description("Tag to use for the image")]
 | 
				
			||||||
 | 
					    public string? Tag { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [CommandOption("-f|--file")]
 | 
				
			||||||
 | 
					    [Description("Path to the Dockerfile")]
 | 
				
			||||||
 | 
					    public string? File { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [CommandOption("--push")]
 | 
				
			||||||
 | 
					    [Description("Push the image after building it")]
 | 
				
			||||||
 | 
					    public bool Push { get; set; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BuildCommand : Command<BuldSettings>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public override int Execute(CommandContext context, BuldSettings settings)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Console.WriteLine($"Building image from {settings.Path} with tag {settings.Tag}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								Commands/Image/Module.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Commands/Image/Module.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					using Automancer.Common;
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Automancer.Command.Image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Module : ICommandModuleWithRegistry
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public void Configure(IConfigurator config)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // No implementation needed here
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public void Configure(IConfigurator config, CommandRegistry registry)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        config.AddBranch("image", image => {
 | 
				
			||||||
 | 
					            var description = "Docker/podman image operations";
 | 
				
			||||||
 | 
					            image.SetDescription(description);
 | 
				
			||||||
 | 
					            registry.Add("image", description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            image.AddCommand<BuildCommand>("build").WithDescription("Build a docker image");
 | 
				
			||||||
 | 
					            image.AddCommand<PushCommand>("push").WithDescription("Push a docker image");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								Commands/Image/PushCommand.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Commands/Image/PushCommand.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Automancer.Command.Image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class PushSettings: CommandSettings
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [CommandArgument(0, "[path]")]
 | 
				
			||||||
 | 
					    [Description("Path to the Dockerfile")]
 | 
				
			||||||
 | 
					    public string? Path { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [CommandOption("-t|--tag")]
 | 
				
			||||||
 | 
					    [Description("Tag to use for the image")]
 | 
				
			||||||
 | 
					    public string? Tag { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [CommandOption("-f|--file")]
 | 
				
			||||||
 | 
					    [Description("Path to the Dockerfile")]
 | 
				
			||||||
 | 
					    public string? File { get; set; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class PushCommand : Command<BuldSettings>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public override int Execute(CommandContext context, BuldSettings settings)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Console.WriteLine($"Building image from {settings.Path} with tag {settings.Tag}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										38
									
								
								Commands/RootCommand.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Commands/RootCommand.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					using Automancer.Common;
 | 
				
			||||||
 | 
					using Spectre.Console;
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					using System.Diagnostics.CodeAnalysis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Automancer.Commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class RootCommand : Spectre.Console.Cli.Command
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly CommandRegistry _registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public RootCommand(CommandRegistry registry)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _registry = registry;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public override int Execute([NotNull] CommandContext context)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        AnsiConsole.Write(
 | 
				
			||||||
 | 
					            new FigletText("AUTOMANCER")
 | 
				
			||||||
 | 
					                .Centered()
 | 
				
			||||||
 | 
					                .Color(Color.Cyan1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        AnsiConsole.MarkupLine("[bold]Automancer[/] is a modular CLI automation tool. It is designed to be extensible and easy to use.");
 | 
				
			||||||
 | 
					        AnsiConsole.MarkupLine("Use [green]--help[/] or [green]<command> --help[/] to get started.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var table = new Table().Border(TableBorder.Rounded);
 | 
				
			||||||
 | 
					        table.AddColumn("[bold yellow]Module[/]");
 | 
				
			||||||
 | 
					        table.AddColumn("[bold yellow]Description[/]");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (var cmd in _registry.Commands.OrderBy(c => c.Path))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            table.AddRow($"[green]{cmd.Path}[/]", cmd.Description ?? "[dim]n/a[/]");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        AnsiConsole.Write(table);   
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								Common/CommandRegistry.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Common/CommandRegistry.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					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));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								Common/ICommandModule.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Common/ICommandModule.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					namespace Automancer.Common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface ICommandModule
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void Configure(IConfigurator config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface ICommandModuleWithRegistry : ICommandModule
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    void Configure(IConfigurator config, CommandRegistry registry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								Common/TypeRegistrar.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Common/TypeRegistrar.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Automancer.Common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public sealed class TypeRegistrar : ITypeRegistrar
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly IServiceCollection _builder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TypeRegistrar(IServiceCollection builder)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _builder = builder;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ITypeResolver Build()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return new TypeResolver(_builder.BuildServiceProvider());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Register(Type service, Type implementation)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _builder.AddSingleton(service, implementation);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void RegisterInstance(Type service, object implementation)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _builder.AddSingleton(service, implementation);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void RegisterLazy(Type service, Func<object> factory)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _builder.AddSingleton(service, _ => factory());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								Common/TypeResolver.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Common/TypeResolver.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					using Spectre.Console.Cli;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Automancer.Common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public sealed class TypeResolver : ITypeResolver, IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ServiceProvider _provider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TypeResolver(ServiceProvider provider)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _provider = provider;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public object? Resolve(Type? type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return type is null ? null : _provider.GetService(type);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _provider.Dispose();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										99
									
								
								Program.cs
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								Program.cs
									
									
									
									
									
								
							@@ -1,2 +1,97 @@
 | 
				
			|||||||
// See https://aka.ms/new-console-template for more information
 | 
					namespace Automancer;
 | 
				
			||||||
Console.WriteLine("Hello, World!");
 | 
					
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Automancer.Common;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Configuration;
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public abstract class Program
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static async Task<int> Main(string[] args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        CommandApp? app = null;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var host = Host.CreateDefaultBuilder(args)
 | 
				
			||||||
 | 
					            .ConfigureLogging(logging =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logging.ClearProviders();
 | 
				
			||||||
 | 
					                logging.AddConsole();
 | 
				
			||||||
 | 
					                logging.SetMinimumLevel(LogLevel.Information);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .ConfigureAppConfiguration((hostingContext, config) => {
 | 
				
			||||||
 | 
					                var env = hostingContext.HostingEnvironment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                config.SetBasePath(AppContext.BaseDirectory)
 | 
				
			||||||
 | 
					                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
 | 
				
			||||||
 | 
					                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
 | 
				
			||||||
 | 
					                    .AddEnvironmentVariables(prefix: "AUTOMANCER_")
 | 
				
			||||||
 | 
					                    .AddCommandLine(args);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .ConfigureServices((context, services) =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var registry = new CommandRegistry();
 | 
				
			||||||
 | 
					                services.AddSingleton(registry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                RegisterCommandModules(services);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var registrar = new TypeRegistrar(services);
 | 
				
			||||||
 | 
					                app = new CommandApp(registrar);
 | 
				
			||||||
 | 
					                app.SetDefaultCommand<RootCommand>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var provider = services.BuildServiceProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                app.Configure(config =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    config.SetApplicationName("automancer");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var modules = provider.GetServices<ICommandModule>();
 | 
				
			||||||
 | 
					                    var registry = provider.GetRequiredService<CommandRegistry>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    foreach (var module in modules)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (module is ICommandModuleWithRegistry withRegistry)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            withRegistry.Configure(config, registry);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            module.Configure(config);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return app != null ? await app.RunAsync(args) : 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 []; }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .Where(t => moduleType.IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)
 | 
				
			||||||
 | 
					            .ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (var type in moduleTypes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            services.AddSingleton(type);
 | 
				
			||||||
 | 
					            services.AddSingleton(typeof(ICommandModule), type);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user