using System.Diagnostics; using System.Text.Json; using Humanizer; using MycroForge.Core.Extensions; namespace MycroForge.Core; public class ProjectContext { public string RootDirectory { get; private set; } = Environment.CurrentDirectory; public string AppName => Path.GetFileNameWithoutExtension(RootDirectory).Underscore().ToLower(); private string ConfigPath => Path.Join(RootDirectory, "m4g.json"); public async Task LoadConfig(bool create = false) { if (!File.Exists(ConfigPath)) { if (create) await CreateFile("m4g.json", "{}"); else throw new FileNotFoundException($"File {ConfigPath} does not exist."); } var config = await JsonSerializer.DeserializeAsync( File.OpenRead(ConfigPath), Serialization.DefaultJsonSerializerOptions.CamelCasePrettyPrint ); if (config is null) throw new Exception($"Could not load {ConfigPath}"); return config; } public void ChangeRootDirectory(string path) { Directory.SetCurrentDirectory(path); RootDirectory = path; } public async Task CreateFile(string path, params string[] content) { var fullPath = Path.Join(RootDirectory, path); var fileInfo = new FileInfo(fullPath); if (fileInfo.Exists) return; Directory.CreateDirectory(fileInfo.Directory!.FullName); await File.WriteAllTextAsync(fullPath, string.Join("\n", content)); await Bash($"chmod 777 {fullPath}"); Console.WriteLine($"Created file {path}"); } public async Task ReadFile(string path) { var fullPath = Path.Join(RootDirectory, path); var fileInfo = new FileInfo(fullPath); if (!fileInfo.Exists) throw new Exception($"File {fullPath} does not exist."); return await File.ReadAllTextAsync(fullPath); } public async Task WriteFile(string path, params string[] content) { var fullPath = Path.Join(RootDirectory, path); var fileInfo = new FileInfo(fullPath); Directory.CreateDirectory(fileInfo.Directory!.FullName); await File.WriteAllTextAsync(fullPath, string.Join("\n", content)); Console.WriteLine($"Modified file {path}"); } public async Task Bash(params string[] script) { var info = new ProcessStartInfo { FileName = "bash", UseShellExecute = false, CreateNoWindow = true, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, }; using var process = Process.Start(info); if (process is null) throw new NullReferenceException("Could not initialize bash process."); process.OutputDataReceived += (sender, args) => { // Only print data when it's not empty to prevent noise in the shell if (!string.IsNullOrEmpty(args.Data)) Console.WriteLine(args.Data); }; process.BeginOutputReadLine(); process.ErrorDataReceived += (sender, args) => { // Only print data when it's not empty to prevent noise in the shell if (!string.IsNullOrEmpty(args.Data)) Console.WriteLine(args.Data); }; process.BeginErrorReadLine(); await using var input = process.StandardInput; // Concat with '&&' operator to make sure that script does not continue on failure. await input.WriteAsync(string.Join(" && ", script)); await input.FlushAsync(); input.Close(); await process.WaitForExitAsync(); Environment.ExitCode = process.ExitCode; } public async Task SaveConfig(ProjectConfig config) { var json = await config.SerializeAsync(Serialization.DefaultJsonSerializerOptions.CamelCasePrettyPrint); await File.WriteAllTextAsync(ConfigPath, json); } }