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 MycroForge.CLI.Extensions;
using MycroForge.Core;
namespace MycroForge.CLI.CodeGen;

View File

@ -1,5 +1,6 @@
using Humanizer;
using MycroForge.CLI.Extensions;
using MycroForge.Core;
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
{

View File

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

View File

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

View File

@ -1,4 +1,5 @@
using Humanizer;
using MycroForge.Core;
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
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
using System.CommandLine;
using MycroForge.CLI.Commands.Interfaces;
using MycroForge.Core;
using MycroForge.Core.Contract;
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 MycroForge.CLI.Commands.Interfaces;
using MycroForge.Core;
using MycroForge.Core.Contract;
namespace MycroForge.CLI.Commands;

View File

@ -1,16 +1,23 @@
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;
public partial class MycroForge : RootCommand
public sealed partial class MycroForge : Core_RootCommand
{
public override string Name => "m4g";
public MycroForge(IEnumerable<ISubCommandOf<MycroForge>> commands) :
base("The MycroForge CLI tool.")
public MycroForge(
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);
}
}

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
namespace MycroForge.CLI.CodeGen;
namespace MycroForge.Core.CodeGen;
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;
namespace MycroForge.CLI.Commands.Interfaces;
namespace MycroForge.Core.Contract;
public interface ISubCommandOf<T> where T : Command
{

View File

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

View File

@ -1,9 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</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>

View File

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

View File

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

View File

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

View File

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

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;
namespace MycroForge.CLI;
namespace MycroForge.Core;
public static class Shared
public static class Serialization
{
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
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.Core", "MycroForge.Core\MycroForge.Core.csproj", "{CFF8BD4E-520D-4319-BA80-3F49B5F493BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MycroForge.TestPlugin", "MycroForge.TestPlugin\MycroForge.TestPlugin.csproj", "{7C479E68-98FA-4FBC-B5E4-7116015774B3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|Any CPU.ActiveCfg = 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
EndGlobal