using System.CommandLine; using MycroForge.Core.Contract; using MycroForge.CLI.Features; using MycroForge.Core; namespace MycroForge.CLI.Commands; public partial class MycroForge { public partial class Init : Command, ISubCommandOf { private static readonly string[] DefaultFeatures = [ Features.Git.FeatureName, Features.GitIgnore.FeatureName, Features.Api.FeatureName, Features.Db.FeatureName ]; private static readonly Argument NameArgument = new(name: "name", description: "The name of your project"); private static readonly Option> WithoutOption = new Option>(name: "--without", description: "Features to exclude") { AllowMultipleArgumentsPerToken = true }.FromAmong(DefaultFeatures); private static readonly Option ApiPortOption = new(name: "--api-port", description: "The API port"); private static readonly Option DbhPortOption = new( aliases: ["--database-host-port", "--dbh-port"], description: "The database host port" ); private static readonly Option DbuPortOption = new( aliases: ["--database-ui-port", "--dbu-port"], description: "The database UI port" ); private static readonly Option DbuPlatformOption = new( aliases: ["--database-ui-platform", "--dbu-platform"], description: "The docker platform for the PhpMyAdmin image" ); private readonly ProjectContext _context; private readonly List _features; private readonly OptionsContainer _optionsContainer; public Init(ProjectContext context, OptionsContainer optionsContainer, IEnumerable features) : base("init", "Initialize a new project") { _context = context; _optionsContainer = optionsContainer; _features = features.ToList(); AddArgument(NameArgument); AddOption(WithoutOption); AddOption(ApiPortOption); AddOption(DbhPortOption); AddOption(DbuPortOption); AddOption(DbuPlatformOption); this.SetHandler(ExecuteAsync, new Binder()); } private async Task ExecuteAsync(Options options) { // Validate excluded features var withoutList = (options.Without ?? Enumerable.Empty()).ToList(); foreach (var feature in withoutList) if (_features.All(f => f.Name != feature)) throw new Exception($"Feature {feature} does not exist."); // Create the project directory and change the directory for the ProjectContext var projectRoot = await CreateDirectory(options.Name); _context.ChangeRootDirectory(projectRoot); // Create the entrypoint file await _context.CreateFile("main.py"); // Create the venv await _context.Bash($"python3 -m venv {Path.Join(projectRoot, ".venv")}"); // Pass feature arguments to the ArgsContainer _optionsContainer.Set(options.ApiOptions); _optionsContainer.Set(options.DbOptions); // Initialize default features foreach (var feature in _features.Where(f => DefaultFeatures.Contains(f.Name))) { if (!withoutList.Contains(feature.Name)) { Console.WriteLine($"Initializing feature {feature.Name}"); await feature.ExecuteAsync(_context); } else { Console.WriteLine($"Skipping feature {feature.Name}"); } } Console.WriteLine($"Directory {projectRoot} was successfully initialized"); } private async Task CreateDirectory(string name) { var directory = Path.Join(Directory.GetCurrentDirectory(), name); if (Directory.Exists(directory)) throw new Exception($"Directory {directory} already exists."); Console.WriteLine($"Creating directory {directory}"); Directory.CreateDirectory(directory); await _context.Bash($"chmod -R 777 {directory}"); return directory; } } }