Created
August 2, 2022 06:56
-
-
Save rfvgyhn/35442b438289b22699b27f104f4de5cb to your computer and use it in GitHub Desktop.
MappingGenerator patcher for rider + linux (https://github.com/cezarypiatek/MappingGeneratorIssueTracker/issues/12)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net7.0</TargetFramework> | |
<ImplicitUsings>enable</ImplicitUsings> | |
<Nullable>enable</Nullable> | |
<LangVersion>preview</LangVersion> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="Mono.Cecil" Version="0.11.4" /> | |
</ItemGroup> | |
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Mono.Cecil; | |
using Mono.Cecil.Cil; | |
const string coreFileName = "MappingGenerator.Core.dll"; | |
const string installerFileName = "MappingGenerator.Installer.dll"; | |
var argv = Environment.GetCommandLineArgs(); | |
var exeName = Path.GetFileNameWithoutExtension(argv.First()); | |
var version = argv.ElementAtOrDefault(1); | |
if (version is null) | |
{ | |
Console.WriteLine($""" | |
Usage: {exeName} version | |
version - Nuget Package Version (e.g. 2022.7.45) | |
"""); | |
Environment.Exit(1); | |
} | |
var coreFilePath = GetAssemblyPath(coreFileName); | |
var installerFilePath = GetAssemblyPath(installerFileName); | |
ValidatePaths(coreFilePath, installerFilePath); | |
var newCorePath = Patch(coreFilePath, InitialSettingsProvider); | |
Console.WriteLine($"New assembly at {newCorePath}"); | |
var newInstallerPath = Patch(installerFilePath, FileLicenseStorage, Installer, MiniLogger); | |
Console.WriteLine($"New assembly at {newInstallerPath}"); | |
////////////////////// | |
string GetAssemblyPath(string fileName) => | |
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages", "mappinggenerator", version, "analyzers", "dotnet", "cs", fileName); | |
static void ValidatePaths(string corePath, string installerPath) | |
{ | |
if (!File.Exists(corePath)) | |
{ | |
Console.WriteLine($"Unable to find assembly at {corePath}"); | |
Environment.Exit(1); | |
} | |
if (!File.Exists(installerPath)) | |
{ | |
Console.WriteLine($"Unable to find assembly at {installerPath}"); | |
Environment.Exit(1); | |
} | |
} | |
static void InitialSettingsProvider(ModuleDefinition mainModule, MethodReference getEnvVarRef) => | |
PatchMethod(mainModule, getEnvVarRef, "InitialSettingsProvider`1", "GetSettingsPath"); | |
static void FileLicenseStorage(ModuleDefinition mainModule, MethodReference getEnvVarRef) => | |
PatchMethod(mainModule, getEnvVarRef, "FileLicenseStorage", "GetLicenseFilePath"); | |
static void Installer(ModuleDefinition mainModule, MethodReference getEnvVarRef) => | |
PatchStaticField(mainModule, getEnvVarRef, "Installer"); | |
static void MiniLogger(ModuleDefinition mainModule, MethodReference getEnvVarRef) => | |
PatchStaticField(mainModule, getEnvVarRef, "MiniLogger"); | |
static void PatchMethod(ModuleDefinition mainModule, MethodReference getEnvVarRef, string typeName, string methodName) | |
{ | |
var methodBody = mainModule | |
.Types.First(t => t.Name == typeName) | |
.Methods.First(m => m.Name == methodName) | |
.Body; | |
PatchIl(methodBody, getEnvVarRef); | |
} | |
static void PatchStaticField(ModuleDefinition mainModule, MethodReference getEnvVarRef, string typeName) | |
{ | |
var ctorBody = mainModule | |
.Types.First(t => t.Name == typeName) | |
.Methods.First(m => m.IsConstructor && m.IsStatic) | |
.Body; | |
PatchIl(ctorBody, getEnvVarRef); | |
} | |
static void PatchIl(MethodBody body, MethodReference getEnvVarRef) | |
{ | |
var target = body.Instructions.Single(i => i.OpCode == OpCodes.Ldstr && i.Operand as string == "MappingGenerator"); | |
var processor = body.GetILProcessor(); | |
processor.InsertBefore(target, Instruction.Create(OpCodes.Dup)); | |
processor.InsertBefore(target, Instruction.Create(OpCodes.Brtrue_S, target)); | |
processor.InsertBefore(target, Instruction.Create(OpCodes.Pop)); | |
processor.InsertBefore(target, Instruction.Create(OpCodes.Ldstr, "XDG_CONFIG_HOME")); | |
processor.InsertBefore(target, Instruction.Create(OpCodes.Call, getEnvVarRef)); | |
} | |
static string Patch(string assemblyPath, params Action<ModuleDefinition, MethodReference>[] actions) | |
{ | |
var original = $"{assemblyPath}.original"; | |
if (!File.Exists(original)) | |
File.Copy(assemblyPath, original); | |
var mainModule = AssemblyDefinition.ReadAssembly(original).MainModule; | |
var envType = mainModule.ImportReference(typeof(Environment)); | |
var getEnvVarRef = mainModule.ImportReference(envType.Resolve().Methods.Single(m => m.FullName == "System.String System.Environment::GetEnvironmentVariable(System.String)")); | |
foreach (var action in actions) | |
action(mainModule, getEnvVarRef); | |
mainModule.Write(assemblyPath); | |
return assemblyPath; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment