Replaced scripting system with plugin system

This commit is contained in:
mdnapo 2024-06-29 12:59:13 +02:00
parent 96b74e6048
commit 3829eb0d7f
66 changed files with 431 additions and 323 deletions

View File

@ -1,5 +1,6 @@
using Humanizer; using Humanizer;
using MycroForge.CLI.Extensions; using MycroForge.CLI.Extensions;
using MycroForge.Core;
namespace MycroForge.CLI.CodeGen; namespace MycroForge.CLI.CodeGen;

View File

@ -1,5 +1,6 @@
using Humanizer; using Humanizer;
using MycroForge.CLI.Extensions; using MycroForge.CLI.Extensions;
using MycroForge.Core;
namespace MycroForge.CLI.CodeGen; namespace MycroForge.CLI.CodeGen;

View File

@ -1,4 +1,6 @@
namespace MycroForge.CLI.CodeGen; using MycroForge.Core.CodeGen;
namespace MycroForge.CLI.CodeGen;
public class DbEnvInitializer public class DbEnvInitializer
{ {

View File

@ -1,4 +1,6 @@
namespace MycroForge.CLI.CodeGen; using MycroForge.Core.CodeGen;
namespace MycroForge.CLI.CodeGen;
public class DbEnvModifier public class DbEnvModifier
{ {

View File

@ -1,4 +1,5 @@
using Humanizer; using Humanizer;
using MycroForge.Core.CodeGen;
namespace MycroForge.CLI.CodeGen; namespace MycroForge.CLI.CodeGen;

View File

@ -1,4 +1,5 @@
using Humanizer; using Humanizer;
using MycroForge.Core;
namespace MycroForge.CLI.CodeGen; namespace MycroForge.CLI.CodeGen;

View File

@ -1,4 +1,6 @@
namespace MycroForge.CLI.CodeGen; using MycroForge.Core.CodeGen;
namespace MycroForge.CLI.CodeGen;
public class MainModifier public class MainModifier
{ {

View File

@ -1,5 +1,6 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Humanizer; using Humanizer;
using MycroForge.Core;
namespace MycroForge.CLI.CodeGen; namespace MycroForge.CLI.CodeGen;

View File

@ -1,6 +1,7 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.CodeGen; using MycroForge.CLI.CodeGen;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,7 +1,8 @@
using System.CommandLine; using System.CommandLine;
using Humanizer; using Humanizer;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
using MycroForge.CLI.Extensions; using MycroForge.CLI.Extensions;
using MycroForge.Core;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,5 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,5 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,8 +1,9 @@
using System.CommandLine; using System.CommandLine;
using Humanizer; using Humanizer;
using MycroForge.CLI.CodeGen; using MycroForge.CLI.CodeGen;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
using MycroForge.CLI.Extensions; using MycroForge.CLI.Extensions;
using MycroForge.Core;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,5 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,6 +1,7 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.CodeGen; using MycroForge.CLI.CodeGen;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,6 +1,7 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.CodeGen; using MycroForge.CLI.CodeGen;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,5 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,5 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,7 +1,8 @@
using System.CommandLine; using System.CommandLine;
using Humanizer; using Humanizer;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
using MycroForge.CLI.Extensions; using MycroForge.CLI.Extensions;
using MycroForge.Core;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,5 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,6 +1,7 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
using MycroForge.CLI.Features; using MycroForge.CLI.Features;
using MycroForge.Core;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;
@ -95,7 +96,7 @@ public partial class MycroForge
// Create the project directory and change the directory for the ProjectContext // Create the project directory and change the directory for the ProjectContext
var projectRoot = await CreateDirectory(name); var projectRoot = await CreateDirectory(name);
_context.ChangeDirectory(projectRoot); _context.ChangeRootDirectory(projectRoot);
// Create the config file and initialize the config // Create the config file and initialize the config
await _context.CreateFile("m4g.json", "{}"); await _context.CreateFile("m4g.json", "{}");

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -0,0 +1,68 @@
using System.CommandLine;
using Humanizer;
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Plugin
{
public class Install : Command, ISubCommandOf<Plugin>
{
public enum TargetPlatform
{
linux_arm,
linux_arm64,
linux_x64,
osx_arm64,
osx_x64,
}
private static readonly Option<TargetPlatform> PlatformOption = new(
aliases: ["-p", "--platform"],
description: "The platform to target when building the plugin"
) { IsRequired = true };
private readonly ProjectContext _context;
public Install(ProjectContext context) : base("install", "Install a plugin")
{
_context = context;
AddAlias("i");
AddOption(PlatformOption);
this.SetHandler(ExecuteAsync, PlatformOption);
}
private async Task ExecuteAsync(TargetPlatform target)
{
var assemblyName = GetAssemblyName();
var pluginInstallPath = Path.Join(Plugins.RootDirectory, assemblyName);
var platform = target.ToString().Dasherize();
await _context.Bash($"dotnet publish -c Release -r {platform} --output {pluginInstallPath}");
Console.WriteLine($"Successfully installed plugin {assemblyName}");
}
private string GetAssemblyName()
{
var matcher = new Matcher().AddInclude("*.csproj");
var currentDirectory = Environment.CurrentDirectory;
var result = matcher.Execute(
new DirectoryInfoWrapper(
new DirectoryInfo(currentDirectory)
)
);
if (!result.HasMatches)
throw new Exception($"Could not find .csproj file in directory {currentDirectory}");
return Path.GetFileNameWithoutExtension(result.Files.First().Path);
}
}
}
}

View File

@ -0,0 +1,26 @@
using System.CommandLine;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Plugin
{
public class List : Command, ISubCommandOf<Plugin>
{
public List() : base("list", "List all installed plugins")
{
AddAlias("l");
AddAlias("ls");
this.SetHandler(ExecuteAsync);
}
private void ExecuteAsync()
{
foreach (var plugin in Plugins.Loaded)
Console.WriteLine($"name: {plugin.Name}, command: {plugin.Command}");
}
}
}
}

View File

@ -0,0 +1,43 @@
using System.CommandLine;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Plugin
{
public class Uninstall : Command, ISubCommandOf<Plugin>
{
private static readonly Argument<IEnumerable<string>> NamesArgument = new(
name: "name",
description: "The names of the plugins you want to uninstall"
);
public Uninstall() : base("uninstall", "Uninstall a plugin")
{
AddAlias("u");
AddArgument(NamesArgument);
this.SetHandler(ExecuteAsync, NamesArgument);
}
private void ExecuteAsync(IEnumerable<string> names)
{
foreach (var name in names)
{
var dir = Path.Join(Plugins.RootDirectory, name);
if (Directory.Exists(dir))
{
Directory.Delete(dir, true);
Console.WriteLine($"Successfully uninstalled plugin {name}");
}
else
{
Console.WriteLine($"Plugin {name} could not be found");
}
}
}
}
}
}

View File

@ -0,0 +1,18 @@
using System.CommandLine;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Plugin : Command, ISubCommandOf<MycroForge>
{
public Plugin(IEnumerable<ISubCommandOf<Plugin>> commands) :
base("plugin", "Plugin related commands")
{
AddAlias("p");
foreach (var command in commands.Cast<Command>())
AddCommand(command);
}
}
}

View File

@ -1,65 +0,0 @@
using System.CommandLine;
using System.Diagnostics;
using MycroForge.CLI.Commands.Interfaces;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Script
{
public class Create : Command, ISubCommandOf<Script>
{
private static readonly Argument<string> NameArgument =
new(name: "name", description: "The name of the script");
public Create() : base(name: "create", description: "Create a script")
{
AddArgument(NameArgument);
this.SetHandler(ExecuteAsync, NameArgument);
}
private async Task ExecuteAsync(string name)
{
var path = await CreateFile(name);
await OpenFile(path);
}
private static async Task<string> CreateFile(string? name = null, string fileExtension = "py")
{
var folder = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".m4g"
);
Directory.CreateDirectory(folder);
var filePath = Path.Combine(folder, $"{name}.{fileExtension}");
if (File.Exists(filePath))
throw new Exception($"File {filePath} already exists.");
await File.WriteAllTextAsync(filePath, string.Empty);
return filePath;
}
private static async Task OpenFile(string file)
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "code",
Arguments = $"--wait {file}",
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true,
}
};
process.Start();
await process.WaitForExitAsync();
}
}
}
}

View File

@ -1,55 +0,0 @@
using System.CommandLine;
using System.Diagnostics;
using MycroForge.CLI.Commands.Interfaces;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Script
{
public class Edit : Command, ISubCommandOf<Script>
{
private static readonly Argument<string> NameArgument =
new(name: "name", description: "The name of the script");
public Edit() : base(name: "edit", description: "Edit a script")
{
AddArgument(NameArgument);
this.SetHandler(ExecuteAsync, NameArgument);
}
private async Task ExecuteAsync(string name)
{
await EditFile(name);
}
private static async Task EditFile(string name)
{
var folder = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".m4g"
);
var file = Path.Combine(folder, $"{name}.py");
if (!File.Exists(file))
throw new Exception($"File {file} does not exists.");
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "code",
Arguments = $"--wait {file}",
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true,
}
};
process.Start();
await process.WaitForExitAsync();
}
}
}
}

View File

@ -1,32 +0,0 @@
using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Script
{
public class List : Command, ISubCommandOf<Script>
{
public List() : base("list", "Show available scripts")
{
this.SetHandler(Execute);
}
private void Execute()
{
var folder = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".m4g"
);
var files = Directory.GetFiles(folder)
.Select(Path.GetFileName)
.Select(p => p.Replace(".py", ""));
foreach (var file in files)
Console.WriteLine(file);
}
}
}
}

View File

@ -1,82 +0,0 @@
using System.CommandLine;
using System.Dynamic;
using System.Text;
using IronPython.Hosting;
using MycroForge.CLI.Commands.Interfaces;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Script
{
public class Run : Command, ISubCommandOf<Script>
{
private readonly ProjectContext _context;
private static readonly Argument<string> NameArgument =
new(name: "name", description: "The name of the script");
private static readonly Argument<IEnumerable<string>> ArgsArgument =
new(name: "args", description: "The args to the script");
public Run(ProjectContext context) : base("run", "Run a script")
{
_context = context;
AddArgument(NameArgument);
AddArgument(ArgsArgument);
this.SetHandler(ExecuteAsync, NameArgument, ArgsArgument);
}
private void ExecuteAsync(string name, IEnumerable<string> args)
{
var engine = Python.CreateEngine();
using var output = new MemoryStream();
using var error = new MemoryStream();
engine.Runtime.IO.SetOutput(output, Encoding.Default);
engine.Runtime.IO.SetErrorOutput(error, Encoding.Default);
var scope = engine.CreateScope();
scope.SetVariable("args", args.ToArray());
scope.SetVariable("context", CreateScriptContext());
try
{
var scriptPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".m4g", $"{name}.py"
);
engine.ExecuteFile(scriptPath, scope);
if (output.Length > 0)
Console.WriteLine(Encoding.Default.GetString(output.ToArray()));
if (error.Length > 0)
Console.WriteLine(Encoding.Default.GetString(error.ToArray()));
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
engine.Runtime.Shutdown();
}
}
private dynamic CreateScriptContext()
{
var createFile = _context.CreateFile;
var readFile = _context.ReadFile;
var writeFile = _context.WriteFile;
var bash = _context.Bash;
dynamic context = new ExpandoObject();
context.create_file = createFile;
context.read_file = readFile;
context.write_file = writeFile;
context.bash = bash;
return context;
}
}
}
}

View File

@ -1,18 +0,0 @@
using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces;
namespace MycroForge.CLI.Commands;
public partial class MycroForge
{
public partial class Script : Command, ISubCommandOf<MycroForge>
{
public Script(IEnumerable<ISubCommandOf<Script>> commands) :
base("script", "Script related commands")
{
AddAlias("s");
foreach (var command in commands.Cast<Command>())
AddCommand(command);
}
}
}

View File

@ -1,5 +1,6 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;

View File

@ -1,16 +1,23 @@
using System.CommandLine; using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.Core.Contract;
using Core_RootCommand = MycroForge.Core.RootCommand;
using RootCommand = MycroForge.Core.RootCommand;
namespace MycroForge.CLI.Commands; namespace MycroForge.CLI.Commands;
public partial class MycroForge : RootCommand public sealed partial class MycroForge : Core_RootCommand
{ {
public override string Name => "m4g"; public override string Name => "m4g";
public MycroForge(IEnumerable<ISubCommandOf<MycroForge>> commands) : public MycroForge(
base("The MycroForge CLI tool.") IEnumerable<ISubCommandOf<MycroForge>> defaults,
IEnumerable<ISubCommandOf<RootCommand>> plugins
) : base("The MycroForge CLI tool.")
{ {
foreach (var command in commands.Cast<Command>()) foreach (var command in defaults.Cast<Command>())
AddCommand(command);
foreach (var command in plugins.Cast<Command>())
AddCommand(command); AddCommand(command);
} }
} }

View File

@ -0,0 +1,57 @@
using System.Reflection;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands;
public static class Plugins
{
public static readonly string RootDirectory = Path.Join(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".m4g", "plugins"
);
private static readonly List<ICommandPlugin> _loaded = [];
public static IReadOnlyList<ICommandPlugin> Loaded => _loaded;
static Plugins()
{
if (!Directory.Exists(RootDirectory))
{
Directory.CreateDirectory(RootDirectory);
}
}
public static List<ICommandPlugin> Load()
{
if (_loaded.Count > 0) return _loaded;
var pluginDirectories = Directory
.GetDirectories(RootDirectory)
.ToArray();
foreach (var directory in pluginDirectories)
{
var dlls = Directory.GetFiles(directory)
.Where(file => file.EndsWith(".dll"))
.ToArray();
foreach (var dll in dlls)
{
var assembly = Assembly.LoadFrom(dll);
var plugin = assembly.GetTypes()
.Where(IsPluginType)
.Select(Activator.CreateInstance)
.Cast<ICommandPlugin>()
.First();
_loaded.Add(plugin);
}
}
return _loaded;
}
private static bool IsPluginType(Type type) =>
type is { IsClass: true, IsAbstract: false } &&
typeof(ICommandPlugin).IsAssignableFrom(type);
}

View File

@ -1,12 +1,14 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using MycroForge.CLI.Commands.Interfaces; using MycroForge.CLI.Commands;
using MycroForge.Core.Contract;
using MycroForge.CLI.Features; using MycroForge.CLI.Features;
using MycroForge.Core;
namespace MycroForge.CLI.Extensions; namespace MycroForge.CLI.Extensions;
public static class ServiceCollectionExtensions public static class ServiceCollectionExtensions
{ {
public static IServiceCollection RegisterServices(this IServiceCollection services) public static IServiceCollection RegisterCommandDefaults(this IServiceCollection services)
{ {
// Register ProjectContext & features // Register ProjectContext & features
services.AddScoped<ProjectContext>(); services.AddScoped<ProjectContext>();
@ -46,12 +48,21 @@ public static class ServiceCollectionExtensions
services.AddScoped<ISubCommandOf<Commands.MycroForge.Db.Link>, Commands.MycroForge.Db.Link.One>(); services.AddScoped<ISubCommandOf<Commands.MycroForge.Db.Link>, Commands.MycroForge.Db.Link.One>();
services.AddScoped<ISubCommandOf<Commands.MycroForge.Db.Link>, Commands.MycroForge.Db.Link.Many>(); services.AddScoped<ISubCommandOf<Commands.MycroForge.Db.Link>, Commands.MycroForge.Db.Link.Many>();
// Register "m4g script" // Register "m4g plugin"
services.AddScoped<ISubCommandOf<Commands.MycroForge>, Commands.MycroForge.Script>(); services.AddScoped<ISubCommandOf<Commands.MycroForge>, Commands.MycroForge.Plugin>();
services.AddScoped<ISubCommandOf<Commands.MycroForge.Script>, Commands.MycroForge.Script.Create>(); services.AddScoped<ISubCommandOf<Commands.MycroForge.Plugin>, Commands.MycroForge.Plugin.List>();
services.AddScoped<ISubCommandOf<Commands.MycroForge.Script>, Commands.MycroForge.Script.List>(); services.AddScoped<ISubCommandOf<Commands.MycroForge.Plugin>, Commands.MycroForge.Plugin.Install>();
services.AddScoped<ISubCommandOf<Commands.MycroForge.Script>, Commands.MycroForge.Script.Edit>(); services.AddScoped<ISubCommandOf<Commands.MycroForge.Plugin>, Commands.MycroForge.Plugin.Uninstall>();
services.AddScoped<ISubCommandOf<Commands.MycroForge.Script>, Commands.MycroForge.Script.Run>();
return services;
}
public static IServiceCollection RegisterCommandPlugins(this IServiceCollection services)
{
var plugins = Plugins.Load();
foreach (var plugin in plugins)
plugin.RegisterServices(services);
return services; return services;
} }

View File

@ -1,4 +1,6 @@
namespace MycroForge.CLI.Features; using MycroForge.Core;
namespace MycroForge.CLI.Features;
public sealed class Api : IFeature public sealed class Api : IFeature
{ {

View File

@ -1,4 +1,5 @@
using MycroForge.CLI.CodeGen; using MycroForge.CLI.CodeGen;
using MycroForge.Core;
namespace MycroForge.CLI.Features; namespace MycroForge.CLI.Features;

View File

@ -1,3 +1,5 @@
using MycroForge.Core;
namespace MycroForge.CLI.Features; namespace MycroForge.CLI.Features;
public class Git : IFeature public class Git : IFeature

View File

@ -1,4 +1,6 @@
namespace MycroForge.CLI.Features; using MycroForge.Core;
namespace MycroForge.CLI.Features;
public interface IFeature public interface IFeature

View File

@ -19,9 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="MycroForge.Parsing"> <ProjectReference Include="..\MycroForge.Core\MycroForge.Core.csproj" />
<HintPath>bin\Debug\net8.0\MycroForge.Parsing.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,7 +5,13 @@ using Microsoft.Extensions.Hosting;
using var host = Host using var host = Host
.CreateDefaultBuilder() .CreateDefaultBuilder()
.ConfigureServices((_, services) => services.RegisterServices()) .ConfigureServices((_, services) =>
{
services
.RegisterCommandDefaults()
.RegisterCommandPlugins()
;
})
.Build(); .Build();
try try

View File

@ -1,6 +1,6 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace MycroForge.CLI.CodeGen; namespace MycroForge.Core.CodeGen;
public class Source public class Source
{ {

View File

@ -1,4 +1,4 @@
namespace MycroForge.CLI.CodeGen; namespace MycroForge.Core.CodeGen;
public class SourceMatch public class SourceMatch
{ {

View File

@ -0,0 +1,11 @@
using Microsoft.Extensions.DependencyInjection;
namespace MycroForge.Core.Contract;
public interface ICommandPlugin
{
public string? Name { get; }
public string Command { get; }
public void RegisterServices(IServiceCollection services);
}

View File

@ -1,6 +1,6 @@
using System.CommandLine; using System.CommandLine;
namespace MycroForge.CLI.Commands.Interfaces; namespace MycroForge.Core.Contract;
public interface ISubCommandOf<T> where T : Command public interface ISubCommandOf<T> where T : Command
{ {

View File

@ -1,6 +1,6 @@
using System.Text.Json; using System.Text.Json;
namespace MycroForge.CLI.Extensions; namespace MycroForge.Core.Extensions;
public static class ObjectStreamExtensions public static class ObjectStreamExtensions
{ {
@ -11,7 +11,7 @@ public static class ObjectStreamExtensions
{ {
using var stream = new MemoryStream(); using var stream = new MemoryStream();
using var reader = new StreamReader(stream); using var reader = new StreamReader(stream);
var options = jsonSerializerOptions ?? Shared.DefaultJsonSerializerOptions.Default; var options = jsonSerializerOptions ?? Serialization.DefaultJsonSerializerOptions.Default;
await JsonSerializer.SerializeAsync(stream, @object, options); await JsonSerializer.SerializeAsync(stream, @object, options);
stream.Position = 0; stream.Position = 0;

View File

@ -6,4 +6,10 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
</ItemGroup>
</Project> </Project>

View File

@ -1,4 +1,4 @@
namespace MycroForge.CLI; namespace MycroForge.Core;
public partial class ProjectConfig public partial class ProjectConfig
{ {

View File

@ -1,4 +1,4 @@
namespace MycroForge.CLI; namespace MycroForge.Core;
public partial class ProjectConfig public partial class ProjectConfig
{ {

View File

@ -1,4 +1,4 @@
namespace MycroForge.CLI; namespace MycroForge.Core;
public partial class ProjectConfig public partial class ProjectConfig
{ {

View File

@ -1,9 +1,9 @@
using System.Diagnostics; using System.Diagnostics;
using System.Text.Json; using System.Text.Json;
using Humanizer; using Humanizer;
using MycroForge.CLI.Extensions; using MycroForge.Core.Extensions;
namespace MycroForge.CLI; namespace MycroForge.Core;
public class ProjectContext public class ProjectContext
{ {
@ -19,7 +19,7 @@ public class ProjectContext
var config = await JsonSerializer.DeserializeAsync<ProjectConfig>( var config = await JsonSerializer.DeserializeAsync<ProjectConfig>(
File.OpenRead(ConfigPath), File.OpenRead(ConfigPath),
Shared.DefaultJsonSerializerOptions.CamelCasePrettyPrint Serialization.DefaultJsonSerializerOptions.CamelCasePrettyPrint
); );
if (config is null) if (config is null)
@ -28,7 +28,7 @@ public class ProjectContext
return config; return config;
} }
public void ChangeDirectory(string path) public void ChangeRootDirectory(string path)
{ {
Directory.SetCurrentDirectory(path); Directory.SetCurrentDirectory(path);
RootDirectory = path; RootDirectory = path;
@ -125,7 +125,7 @@ public class ProjectContext
public async Task SaveConfig(ProjectConfig config) public async Task SaveConfig(ProjectConfig config)
{ {
var json = await config.SerializeAsync(Shared.DefaultJsonSerializerOptions.CamelCasePrettyPrint); var json = await config.SerializeAsync(Serialization.DefaultJsonSerializerOptions.CamelCasePrettyPrint);
await File.WriteAllTextAsync(ConfigPath, json); await File.WriteAllTextAsync(ConfigPath, json);
} }
} }

View File

@ -0,0 +1,8 @@
namespace MycroForge.Core;
public abstract class RootCommand : System.CommandLine.RootCommand
{
protected RootCommand(string description = "") : base(description)
{
}
}

View File

@ -1,8 +1,8 @@
using System.Text.Json; using System.Text.Json;
namespace MycroForge.CLI; namespace MycroForge.Core;
public static class Shared public static class Serialization
{ {
public static class DefaultJsonSerializerOptions public static class DefaultJsonSerializerOptions
{ {

View File

@ -0,0 +1,6 @@
namespace MycroForge.TestPlugin;
public static class Constants
{
public const string MainCommandName = "mj";
}

View File

@ -0,0 +1,25 @@
using System.CommandLine;
using MycroForge.Core;
using MycroForge.Core.Contract;
using RootCommand = MycroForge.Core.RootCommand;
namespace MycroForge.TestPlugin;
public class MyJewelleryCommand : Command, ISubCommandOf<RootCommand>
{
private readonly ProjectContext _context;
public MyJewelleryCommand(ProjectContext context) :
base(Constants.MainCommandName, "Custom command for My Jewellery specific stuff")
{
_context = context;
this.SetHandler(ExecuteAsync);
}
private async Task ExecuteAsync()
{
await _context.CreateFile("hello_world.txt",
"My Jewellery command plugin is working!"
);
}
}

View File

@ -0,0 +1,16 @@
using Microsoft.Extensions.DependencyInjection;
using MycroForge.Core.Contract;
using RootCommand = MycroForge.Core.RootCommand;
namespace MycroForge.TestPlugin;
public class MyJewelleryCommandPlugin : ICommandPlugin
{
public string Name => $"{nameof(MycroForge)}.{nameof(TestPlugin)}";
public string Command => Constants.MainCommandName;
public void RegisterServices(IServiceCollection services)
{
services.AddScoped<ISubCommandOf<RootCommand>, MyJewelleryCommand>();
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MycroForge.Core\MycroForge.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.CLI", "MycroForg
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.Core", "MycroForge.Core\MycroForge.Core.csproj", "{CFF8BD4E-520D-4319-BA80-3F49B5F493BA}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.Core", "MycroForge.Core\MycroForge.Core.csproj", "{CFF8BD4E-520D-4319-BA80-3F49B5F493BA}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.TestPlugin", "MycroForge.TestPlugin\MycroForge.TestPlugin.csproj", "{7C479E68-98FA-4FBC-B5E4-7116015774B3}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -18,5 +20,9 @@ Global
{CFF8BD4E-520D-4319-BA80-3F49B5F493BA}.Debug|Any CPU.Build.0 = Debug|Any CPU {CFF8BD4E-520D-4319-BA80-3F49B5F493BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CFF8BD4E-520D-4319-BA80-3F49B5F493BA}.Release|Any CPU.ActiveCfg = Release|Any CPU {CFF8BD4E-520D-4319-BA80-3F49B5F493BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CFF8BD4E-520D-4319-BA80-3F49B5F493BA}.Release|Any CPU.Build.0 = Release|Any CPU {CFF8BD4E-520D-4319-BA80-3F49B5F493BA}.Release|Any CPU.Build.0 = Release|Any CPU
{7C479E68-98FA-4FBC-B5E4-7116015774B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C479E68-98FA-4FBC-B5E4-7116015774B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C479E68-98FA-4FBC-B5E4-7116015774B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C479E68-98FA-4FBC-B5E4-7116015774B3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal