2024-06-19 04:10:46 -04:00
using Microsoft.CodeAnalysis ;
using Microsoft.CodeAnalysis.CSharp ;
using Microsoft.CodeAnalysis.CSharp.Syntax ;
using ReCodeIt.Models ;
2024-06-18 17:35:31 -04:00
using ReCodeIt.ReMapper ;
using ReCodeIt.Utils ;
2024-06-19 05:58:45 -04:00
using System.Diagnostics ;
2024-06-18 17:35:31 -04:00
2024-06-18 20:42:58 -04:00
namespace ReCodeIt.CrossCompiler ;
2024-06-18 17:35:31 -04:00
public class ReCodeItCrossCompiler
{
public ReCodeItCrossCompiler ( )
{
Remapper = new ( this ) ;
}
private ReCodeItRemapper Remapper { get ; }
2024-06-18 20:42:58 -04:00
public CrossCompilerSettings Settings = > DataProvider . Settings . CrossCompiler ;
public CrossCompilerProjectModel ActiveProject = > ProjectManager . ActiveProject ;
2024-06-18 17:35:31 -04:00
2024-06-19 09:20:57 -04:00
private int _identifiersChanged = 0 ;
2024-06-18 17:35:31 -04:00
public void StartRemap ( )
{
2024-06-19 05:58:45 -04:00
ActiveProject . ChangedTypes . Clear ( ) ;
2024-06-19 00:02:25 -04:00
2024-06-18 20:42:58 -04:00
if ( ActiveProject = = null )
2024-06-18 17:35:31 -04:00
{
Logger . Log ( "ERROR: No Cross Compiler Project is loaded, create or load one first." , ConsoleColor . Red ) ;
return ;
}
2024-06-20 13:58:39 -04:00
if ( ActiveProject . VisualStudioClonedSolutionDirectory = = string . Empty )
2024-06-18 17:35:31 -04:00
{
Logger . Log ( "ERROR: No ReCodeIt Project directory is set. (Project Creation Failed)" , ConsoleColor . Red ) ;
return ;
}
2024-06-19 06:27:30 -04:00
Remapper . InitializeRemap (
ActiveProject . RemapModels ,
ActiveProject . OriginalAssemblyPath ,
2024-06-20 14:23:11 -04:00
ActiveProject . VisualStudioDependencyPath ,
2024-06-19 06:27:30 -04:00
true ) ;
2024-06-19 09:20:57 -04:00
Logger . Log ( "-----------------------------------------------" , ConsoleColor . Green ) ;
Logger . Log ( $"Generated Cross Mapped DLL for project {ActiveProject.SolutionName}" , ConsoleColor . Green ) ;
2024-06-20 14:23:11 -04:00
Logger . Log ( $"Built to: {Path.Combine(ActiveProject.VisualStudioDependencyPath, ActiveProject.OriginalAssemblyDllName)}" , ConsoleColor . Green ) ;
2024-06-19 09:20:57 -04:00
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 ) ;
2024-06-20 14:23:11 -04:00
Logger . Log ( $"Original patched assembly path: {ActiveProject.VisualStudioDependencyPath}" , ConsoleColor . Green ) ;
2024-06-19 09:20:57 -04:00
//Logger.Log($"Original patched assembly hash: {ActiveProject.RemappedAssemblyHash}", ConsoleColor.Green);
Logger . Log ( "-----------------------------------------------" , ConsoleColor . Green ) ;
2024-06-18 17:35:31 -04:00
}
public void StartCrossCompile ( )
{
2024-06-20 14:44:21 -04:00
ProjectManager . LoadProjectCC ( ActiveProject ) ;
2024-06-19 09:20:57 -04:00
2024-06-19 04:10:46 -04:00
AnalyzeSourceFiles ( ) ;
2024-06-19 05:58:45 -04:00
StartBuild ( ) ;
MoveResult ( ) ;
2024-06-19 04:10:46 -04:00
}
private void AnalyzeSourceFiles ( )
{
foreach ( var file in ProjectManager . AllProjectSourceFiles )
{
AnalyzeSourcefile ( file ) ;
}
}
private void AnalyzeSourcefile ( string file )
{
2024-06-20 13:58:39 -04:00
_identifiersChanged = 0 ;
2024-06-19 05:58:45 -04:00
var source = File . ReadAllText ( file ) ;
2024-06-19 04:10:46 -04:00
var syntaxTree = CSharpSyntaxTree . ParseText ( source ) ;
var root = syntaxTree . GetCompilationUnitRoot ( ) ;
2024-06-19 05:58:45 -04:00
// Get the things we want to change
2024-06-19 04:10:46 -04:00
var identifiers = root . DescendantNodes ( )
. OfType < IdentifierNameSyntax > ( )
. Where ( id = > ActiveProject . ChangedTypes . ContainsKey ( id . Identifier . Text ) ) ;
if ( ! identifiers . Any ( ) ) { return ; }
2024-06-19 09:20:57 -04:00
_identifiersChanged + = identifiers . Count ( ) ;
Logger . Log ( $"changing {_identifiersChanged} identifiers in file {Path.GetFileName(file)}" , ConsoleColor . Green ) ;
2024-06-19 04:10:46 -04:00
2024-06-19 05:58:45 -04:00
// Do Black Voodoo Magic
2024-06-19 04:10:46 -04:00
var newRoot = root . ReplaceNodes ( identifiers , ( oldNode , newNode ) = >
SyntaxFactory . IdentifierName ( ActiveProject . ChangedTypes [ oldNode . Identifier . Text ] )
. WithLeadingTrivia ( oldNode . GetLeadingTrivia ( ) )
. WithTrailingTrivia ( oldNode . GetTrailingTrivia ( ) ) ) ;
2024-06-19 05:58:45 -04:00
File . WriteAllText ( file , newRoot . ToFullString ( ) ) ;
2024-06-19 04:10:46 -04:00
}
/// <summary>
2024-06-19 05:58:45 -04:00
/// Starts the build process for the active project.
2024-06-19 04:10:46 -04:00
/// </summary>
2024-06-19 05:58:45 -04:00
private void StartBuild ( )
{
2024-06-19 06:22:18 -04:00
var arguements = $"build {ActiveProject.VisualStudioClonedSolutionPath} " +
2024-06-19 05:58:45 -04:00
$"/p:Configuration=Debug " +
$"/p:Platform=\" Any CPU \ "" ;
2024-06-19 09:20:57 -04:00
var path = ActiveProject . VisualStudioClonedSolutionDirectory ;
2024-06-19 05:58:45 -04:00
// clean the project first
2024-06-19 09:20:57 -04:00
ExecuteDotnetCommand ( "clean" , path ) ;
2024-06-19 05:58:45 -04:00
// Restore packages
2024-06-19 09:20:57 -04:00
ExecuteDotnetCommand ( "restore" , path ) ;
2024-06-19 05:58:45 -04:00
// Then build the project
2024-06-19 09:20:57 -04:00
ExecuteDotnetCommand ( arguements , path ) ;
2024-06-19 05:58:45 -04:00
}
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 ( )
2024-06-19 04:10:46 -04:00
{
2024-06-20 15:03:17 -04:00
var builtDll = Directory
. GetFiles ( ActiveProject . VisualStudioClonedSolutionDirectory , "*.dll" , SearchOption . AllDirectories )
. FirstOrDefault ( file = > file . Contains ( ActiveProject . ProjectDllName ) ) ;
if ( builtDll = = null )
{
Logger . Log ( $"ERROR: No {ActiveProject.ProjectDllName} found at path {ActiveProject.VisualStudioClonedSolutionDirectory}, build failed." , ConsoleColor . Red ) ;
CleanUp ( ) ;
return ;
}
var dest = Path . Combine ( ActiveProject . BuildDirectory , ActiveProject . ProjectDllName ) ;
// Create it if it doesnt exist
if ( ! Directory . Exists ( ActiveProject . BuildDirectory ) )
{
Directory . CreateDirectory ( ActiveProject . BuildDirectory ) ;
}
File . Copy ( builtDll , dest , true ) ;
Logger . Log ( $"Copying {ActiveProject.ProjectDllName} to {dest}" , ConsoleColor . Yellow ) ;
2024-06-19 09:20:57 -04:00
Logger . Log ( $"Successfully Cross Compiled Project {ActiveProject.SolutionName}" , ConsoleColor . Green ) ;
2024-06-20 15:03:17 -04:00
CleanUp ( ) ;
}
private void CleanUp ( )
{
if ( Path . Exists ( ActiveProject . VisualStudioClonedSolutionDirectory ) )
{
Logger . Log ( "Cleaning up cloned project files" , ConsoleColor . Yellow ) ;
Directory . Delete ( ActiveProject . VisualStudioClonedSolutionDirectory , true ) ;
}
2024-06-18 17:35:31 -04:00
}
}