using System.Reflection; using System.Text; using System.Text.Json; namespace Nerfed.Compiler; public static class Generator { public const string AssemblyDefinitionExtensionName = ".asmdef"; public const string CSProjectExtensionName = ".csproj"; public const string SolutionExtensionName = ".sln"; public static void GenerateSolution(string projectDirectory, Project project, out string solutionFilePath) { // Clear files. ClearCSProjectFiles(projectDirectory); // Generate projects. string[] assemblyDefinitionFilePaths = Directory.GetFiles(projectDirectory, AssemblyDefinitionExtensionName, SearchOption.AllDirectories); foreach (string assemblyDefinitionFilePath in assemblyDefinitionFilePaths) { GenerateCSProject(assemblyDefinitionFilePath, projectDirectory, out string csProjectFilePath); } // Generate solution. string[] csProjectPaths = Directory.GetFiles(projectDirectory, $"*{CSProjectExtensionName}", SearchOption.TopDirectoryOnly); string[] csProjectGuids = new string[csProjectPaths.Length]; for (int i = 0; i < csProjectPaths.Length; i++) { csProjectGuids[i] = Guid.NewGuid().ToString("B").ToUpper(); } StringBuilder content = new StringBuilder(); // Write the solution file header content.AppendLine("Microsoft Visual Studio Solution File, Format Version 12.00"); content.AppendLine("# Visual Studio Version 17"); content.AppendLine("VisualStudioVersion = 17.10.35013.160"); content.AppendLine("MinimumVisualStudioVersion = 10.0.40219.1"); // Add each project to the solution file for (int i = 0; i < csProjectPaths.Length; i++) { string csProjectPath = csProjectPaths[i]; string csProjectGuid = csProjectGuids[i]; string csProjectName = Path.GetFileNameWithoutExtension(csProjectPath); string csProjectRelativePath = Path.GetRelativePath(projectDirectory, csProjectPath); // FAE04EC0-301F-11D3-BF4B-00C04F79EFBC for C# projects. content.AppendLine($"Project(\"{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}\") = \"{csProjectName}\", \"{csProjectRelativePath}\", \"{csProjectGuid}\""); content.AppendLine("EndProject"); } // Add global sections (these can be extended as needed) content.AppendLine("Global"); content.AppendLine(" GlobalSection(SolutionConfigurationPlatforms) = preSolution"); content.AppendLine(" Test|x64 = Test|x64"); content.AppendLine(" Release|x64 = Release|x64"); content.AppendLine(" Debug|x64 = Debug|x64"); content.AppendLine(" EndGlobalSection"); content.AppendLine(" GlobalSection(ProjectConfigurationPlatforms) = postSolution"); for (int i = 0; i < csProjectPaths.Length; i++) { string projectGuid = csProjectGuids[i]; content.AppendLine($" {projectGuid}.Test|x64.ActiveCfg = Test|x64"); content.AppendLine($" {projectGuid}.Test|x64.Build.0 = Test|x64"); content.AppendLine($" {projectGuid}.Release|x64.ActiveCfg = Release|x64"); content.AppendLine($" {projectGuid}.Release|x64.Build.0 = Release|x64"); content.AppendLine($" {projectGuid}.Debug|x64.ActiveCfg = Debug|x64"); content.AppendLine($" {projectGuid}.Debug|x64.Build.0 = Debug|x64"); } content.AppendLine(" EndGlobalSection"); content.AppendLine(" GlobalSection(SolutionProperties) = preSolution"); content.AppendLine(" HideSolutionNode = FALSE"); content.AppendLine(" EndGlobalSection"); content.AppendLine("EndGlobal"); // Write the solution file content to disk string solutionName = project.Name + SolutionExtensionName; solutionFilePath = Path.Combine(projectDirectory, solutionName); File.WriteAllText(solutionFilePath, content.ToString()); } private static bool GenerateCSProject(string assemblyDefinitionFilePath, string projectPath, out string csProjectFilePath) { if (!File.Exists(assemblyDefinitionFilePath)) { csProjectFilePath = string.Empty; return false; } string jsonString = File.ReadAllText(assemblyDefinitionFilePath); AssemblyDefinition assemblyDefinition = JsonSerializer.Deserialize(jsonString, AssemblyDefinitionContext.Default.AssemblyDefinition); Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly runtimeAssembly = loadedAssemblies.FirstOrDefault(assembly => assembly.GetName().Name == "Nerfed.Runtime") ?? throw new Exception("Failed to find Runtime Assembly!"); // TODO: get all dependencies. // TODO: properly get assemblies. StringBuilder content = new StringBuilder(); content.AppendLine(""); content.AppendLine(" "); content.AppendLine(" net8.0"); content.AppendLine(" enable"); content.AppendLine(" disable"); content.AppendLine(" true"); content.AppendLine(" true"); content.AppendLine(" true"); content.AppendLine(" false"); content.AppendLine(" false"); content.AppendLine(" Debug;Test;Release"); content.AppendLine(" x64"); content.AppendLine(" "); content.AppendLine(" "); content.AppendLine(" TRACE;LOG_INFO;PROFILING"); content.AppendLine(" "); content.AppendLine(" "); content.AppendLine(" TRACE;LOG_ERROR;PROFILING"); content.AppendLine(" true"); content.AppendLine(" "); content.AppendLine(" "); content.AppendLine(" TRACE;LOG_ERROR"); content.AppendLine(" true"); content.AppendLine(" "); content.AppendLine(" "); content.AppendLine($" "); content.AppendLine(" "); content.AppendLine(" "); content.AppendLine(" "); content.AppendLine($" {runtimeAssembly.Location}"); content.AppendLine(" false"); content.AppendLine(" "); content.AppendLine(" "); content.AppendLine(""); string csProjectName = assemblyDefinition.Name + CSProjectExtensionName; csProjectFilePath = Path.Combine(projectPath, csProjectName); File.WriteAllText(csProjectFilePath, content.ToString()); return true; } private static void ClearCSProjectFiles(string projectPath) { string[] csProjectFiles = Directory.GetFiles(projectPath, $"*{CSProjectExtensionName}", SearchOption.TopDirectoryOnly); foreach (string csProjectFile in csProjectFiles) { File.Delete(csProjectFile); } } }