Skip to content

Instantly share code, notes, and snippets.

@rfvgyhn
Created August 2, 2022 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rfvgyhn/35442b438289b22699b27f104f4de5cb to your computer and use it in GitHub Desktop.
Save rfvgyhn/35442b438289b22699b27f104f4de5cb to your computer and use it in GitHub Desktop.
MappingGenerator patcher for rider + linux (https://github.com/cezarypiatek/MappingGeneratorIssueTracker/issues/12)
<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>
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