AssemblyTool/RecodeItLib/CrossCompiler/ReCodeItCrossCompiler.cs
2024-06-19 09:20:57 -04:00

168 lines
6.1 KiB
C#

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using ReCodeIt.Models;
using ReCodeIt.ReMapper;
using ReCodeIt.Utils;
using System.Diagnostics;
namespace ReCodeIt.CrossCompiler;
public class ReCodeItCrossCompiler
{
public ReCodeItCrossCompiler()
{
Remapper = new(this);
}
private ReCodeItRemapper Remapper { get; }
public CrossCompilerSettings Settings => DataProvider.Settings.CrossCompiler;
public CrossCompilerProjectModel ActiveProject => ProjectManager.ActiveProject;
private int _identifiersChanged = 0;
public void StartRemap()
{
ActiveProject.ChangedTypes.Clear();
if (ActiveProject == null)
{
Logger.Log("ERROR: No Cross Compiler Project is loaded, create or load one first.", ConsoleColor.Red);
return;
}
if (ActiveProject.ReCodeItProjectPath == string.Empty)
{
Logger.Log("ERROR: No ReCodeIt Project directory is set. (Project Creation Failed)", ConsoleColor.Red);
return;
}
Remapper.InitializeRemap(
ActiveProject.RemapModels,
ActiveProject.OriginalAssemblyPath,
ActiveProject.RemappedAssemblyPath,
true);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
Logger.Log($"Generated Cross Mapped DLL for project {ActiveProject.SolutionName}", ConsoleColor.Green);
Logger.Log($"Changed {ActiveProject.ChangedTypes.Count} types", ConsoleColor.Green);
Logger.Log($"Original assembly path: {ActiveProject.OriginalAssemblyPath}", ConsoleColor.Green);
Logger.Log($"Original assembly hash: {ActiveProject.OriginalAssemblyHash}", ConsoleColor.Green);
Logger.Log($"Original patched assembly path: {ActiveProject.RemappedAssemblyPath}", ConsoleColor.Green);
//Logger.Log($"Original patched assembly hash: {ActiveProject.RemappedAssemblyHash}", ConsoleColor.Green);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
}
public void StartCrossCompile()
{
_identifiersChanged = 0;
AnalyzeSourceFiles();
StartBuild();
MoveResult();
}
private void AnalyzeSourceFiles()
{
foreach (var file in ProjectManager.AllProjectSourceFiles)
{
AnalyzeSourcefile(file);
}
var fileName = Path.GetFileName(ActiveProject.OriginalAssemblyPath);
var outPath = Path.Combine(ActiveProject.RemappedAssemblyPath, fileName);
Logger.Log($"Placing original reference into cloned build directory", ConsoleColor.Green);
File.Copy(ActiveProject.OriginalAssemblyPath, outPath, true);
}
private void AnalyzeSourcefile(string file)
{
var source = File.ReadAllText(file);
var syntaxTree = CSharpSyntaxTree.ParseText(source);
var root = syntaxTree.GetCompilationUnitRoot();
// Get the things we want to change
var identifiers = root.DescendantNodes()
.OfType<IdentifierNameSyntax>()
.Where(id => ActiveProject.ChangedTypes.ContainsKey(id.Identifier.Text));
if (!identifiers.Any()) { return; }
_identifiersChanged += identifiers.Count();
Logger.Log($"changing {_identifiersChanged} identifiers in file {Path.GetFileName(file)}", ConsoleColor.Green);
// Do Black Voodoo Magic
var newRoot = root.ReplaceNodes(identifiers, (oldNode, newNode) =>
SyntaxFactory.IdentifierName(ActiveProject.ChangedTypes[oldNode.Identifier.Text])
.WithLeadingTrivia(oldNode.GetLeadingTrivia())
.WithTrailingTrivia(oldNode.GetTrailingTrivia()));
File.WriteAllText(file, newRoot.ToFullString());
}
/// <summary>
/// Starts the build process for the active project.
/// </summary>
private void StartBuild()
{
var arguements = $"build {ActiveProject.VisualStudioClonedSolutionPath} " +
$"/p:Configuration=Debug " +
$"/p:Platform=\"Any CPU\"";
var path = ActiveProject.VisualStudioClonedSolutionDirectory;
// clean the project first
ExecuteDotnetCommand("clean", path);
// Restore packages
ExecuteDotnetCommand("restore", path);
// Then build the project
ExecuteDotnetCommand(arguements, path);
}
private static void ExecuteDotnetCommand(string arguments, string workingDirectory)
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "dotnet",
Arguments = arguments,
WorkingDirectory = workingDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (Process process = new Process())
{
process.StartInfo = startInfo;
process.OutputDataReceived += (sender, e) => Logger.Log(e.Data);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
int exitCode = process.ExitCode;
Logger.Log($"dotnet {arguments} exited with code {exitCode}");
}
}
private void MoveResult()
{
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
Logger.Log($"Successfully Cross Compiled Project {ActiveProject.SolutionName}", ConsoleColor.Green);
Logger.Log($"Reversed {_identifiersChanged} Remaps", ConsoleColor.Green);
Logger.Log($"Original assembly path: {ActiveProject.OriginalAssemblyPath}", ConsoleColor.Green);
Logger.Log($"Original assembly hash: {ActiveProject.OriginalAssemblyHash}", ConsoleColor.Green);
Logger.Log($"Final build directory: {ActiveProject.BuildDirectory}", ConsoleColor.Green);
//Logger.Log($"Original patched assembly hash: {ActiveProject.RemappedAssemblyHash}", ConsoleColor.Green);
Logger.Log("-----------------------------------------------", ConsoleColor.Green);
}
}