From 3917a5e3c4b7784bf535eafb25e0a47662c0978a Mon Sep 17 00:00:00 2001 From: aszlig Date: Tue, 17 Jul 2018 02:59:32 +0200 Subject: monogame-patcher: Switch to MSBuild I really would have preferred a simple Makefile, but with that we can't use buildDotnetPackage and we also need to take care of butchering the dependencies manually. So I moved everything to src/ and added a csproj file to clean up most of the cruft and just use buildDotnetPackage with minimal attributes. In addition to that I also added assembly info, so that the command line help will show the proper author name, copyright, yaddayadda... Signed-off-by: aszlig --- .../build-support/monogame-patcher/default.nix | 47 +++--- .../build-support/monogame-patcher/patcher.cs | 168 --------------------- .../monogame-patcher/src/assembly-info.cs | 6 + .../build-support/monogame-patcher/src/patcher.cs | 168 +++++++++++++++++++++ .../monogame-patcher/src/patcher.csproj | 39 +++++ 5 files changed, 233 insertions(+), 195 deletions(-) delete mode 100644 pkgs/games/build-support/monogame-patcher/patcher.cs create mode 100644 pkgs/games/build-support/monogame-patcher/src/assembly-info.cs create mode 100644 pkgs/games/build-support/monogame-patcher/src/patcher.cs create mode 100644 pkgs/games/build-support/monogame-patcher/src/patcher.csproj (limited to 'pkgs/games') diff --git a/pkgs/games/build-support/monogame-patcher/default.nix b/pkgs/games/build-support/monogame-patcher/default.nix index fffa6825..1a06425e 100644 --- a/pkgs/games/build-support/monogame-patcher/default.nix +++ b/pkgs/games/build-support/monogame-patcher/default.nix @@ -1,31 +1,24 @@ -{ lib, runCommand, makeWrapper, fetchNuGet, mono, dotnetPackages }: +{ buildDotnetPackage, fetchNuGet }: -runCommand "monogame-patcher" { - nativeBuildInputs = [ mono makeWrapper ]; +buildDotnetPackage { + baseName = "monogame-patcher"; + version = "0.1.0"; - src = ./patcher.cs; + src = ./src; - cecil = "${fetchNuGet { - baseName = "Mono.Cecil"; - version = "0.10-beta7"; - sha256 = "03bina3llcnylrfrvp5psnwrfn757j7zch5r360rpdn7gmcjjcpl"; - outputFiles = [ "lib/net40/*" ]; - }}/lib/dotnet/Mono.Cecil"; + buildInputs = [ + (fetchNuGet { + baseName = "Mono.Cecil"; + version = "0.10-beta7"; + sha256 = "03bina3llcnylrfrvp5psnwrfn757j7zch5r360rpdn7gmcjjcpl"; + outputFiles = [ "lib/net40/*" ]; + }) - cliparser = "${fetchNuGet { - baseName = "CommandLineParser"; - version = "2.2.1"; - sha256 = "0wf8mzr16d2ni008m60rrk738v8ypk74llk6g8mlyx7rrlchnxaf"; - outputFiles = [ "lib/net45/*" ]; - }}/lib/dotnet/CommandLineParser"; - -} '' - mkdir -p "$out/bin" "$out/libexec/monogame-patcher" - mcs "$src" -out:"$out/libexec/monogame-patcher/patcher.exe" \ - -lib:"$cecil" -lib:"$cliparser" \ - -r:Mono.Cecil -r:Mono.Cecil.Rocks -r:CommandLine - - makeWrapper ${lib.escapeShellArg "${mono}/bin/mono"} "$out/bin/$name" \ - --set MONO_PATH "$cecil:$cliparser" \ - --add-flags "$out/libexec/monogame-patcher/patcher.exe" -'' + (fetchNuGet { + baseName = "CommandLineParser"; + version = "2.2.1"; + sha256 = "0wf8mzr16d2ni008m60rrk738v8ypk74llk6g8mlyx7rrlchnxaf"; + outputFiles = [ "lib/net45/*" ]; + }) + ]; +} diff --git a/pkgs/games/build-support/monogame-patcher/patcher.cs b/pkgs/games/build-support/monogame-patcher/patcher.cs deleted file mode 100644 index c1502ba1..00000000 --- a/pkgs/games/build-support/monogame-patcher/patcher.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System; - -using Mono.Cecil.Cil; -using Mono.Cecil.Rocks; -using Mono.Cecil; - -using CommandLine; - -class GenericOptions -{ - [Option('i', "infile", Required=true, HelpText="Input file to transform.")] - public string inputFile { get; set; } - [Option('o', "outfile", HelpText="File to write transformed data to.")] - public string outputFile { get; set; } -} - -class Command { - protected string infile; - protected string outfile; - protected ModuleDefinition module; - - public Command(GenericOptions options) { - if (options.outputFile == null) - this.outfile = options.inputFile; - else - this.outfile = options.outputFile; - this.infile = options.inputFile; - - var rp = new ReaderParameters { - ReadWrite = this.infile == this.outfile - }; - this.module = ModuleDefinition.ReadModule(this.infile, rp); - } - - public void save() { - if (this.outfile == this.infile) - this.module.Write(); - else - this.module.Write(this.outfile); - } -} - -[Verb("fix-filestreams", HelpText="Fix System.IO.FileStream constructors" - +" to open files read-only.")] -class FixFileStreamsCmd : GenericOptions { - [Value(0, Required=true, MetaName = "type", HelpText = "Types to patch.")] - public IEnumerable typesToPatch { get; set; } -}; - -class FixFileStreams : Command { - public FixFileStreams(FixFileStreamsCmd options) : base(options) { - var filtered = this.module.Types - .Where(p => options.typesToPatch.Contains(p.Name)); - - foreach (var toPatch in filtered) - patch_type(toPatch); - - this.save(); - } - - private void patch_method(MethodDefinition md) { - var il = md.Body.GetILProcessor(); - - var fileStreams = md.Body.Instructions - .Where(i => i.OpCode == OpCodes.Newobj) - .Where(i => (i.Operand as MethodReference).DeclaringType - .FullName == "System.IO.FileStream"); - - foreach (Instruction i in fileStreams.ToList()) { - var fileAccessRead = il.Create(OpCodes.Ldc_I4_1); - il.InsertBefore(i, fileAccessRead); - - var ctorType = this.module.AssemblyReferences.Select( - x => new { - type = this.module.AssemblyResolver.Resolve(x) - .MainModule.GetType("System.IO.FileStream") - } - ).Where(x => x.type != null).Select(x => x.type).First(); - - string wantedCtor = "System.Void System.IO.FileStream" - + "::.ctor(System.String," - + "System.IO.FileMode," - + "System.IO.FileAccess)"; - - var newCtor = ctorType.GetConstructors() - .Single(x => x.ToString() == wantedCtor); - - var refCtor = this.module.ImportReference(newCtor); - il.Replace(i, il.Create(OpCodes.Newobj, refCtor)); - } - } - - private void patch_type(TypeDefinition td) { - foreach (var nested in td.NestedTypes) patch_type(nested); - foreach (MethodDefinition md in td.Methods) patch_method(md); - } -} - -[Verb("replace-call", HelpText="Replace calls to types.")] -class ReplaceCallCmd : GenericOptions { - [Value(0, Min=2, Max=2, HelpText="Call to replace.")] - public IEnumerable replaceCall { get; set; } - - [Value(2, Required=true, MetaName = "type", HelpText = "Types to patch.")] - public IEnumerable typesToPatch { get; set; } - -}; - -class ReplaceCall : Command { - private string search; - private string replace; - - public ReplaceCall(ReplaceCallCmd options) : base(options) { - this.search = options.replaceCall.ToList()[0]; - this.replace = options.replaceCall.ToList()[1]; - - var filtered = this.module.Types - .Where(p => options.typesToPatch.Contains(p.Name)); - - foreach (var toPatch in filtered) - patch_type(toPatch); - - this.save(); - } - - private void patch_method(MethodDefinition md) { - var il = md.Body.GetILProcessor(); - - var found = md.Body.Instructions - .Where(i => i.OpCode == OpCodes.Call) - .Where(i => i.Operand.ToString() == this.search); - - var ctorType = this.module.AssemblyReferences.Select( - x => new { - // XXX: Don't hardcode UnityEngine.Application! - type = this.module.AssemblyResolver.Resolve(x) - .MainModule.GetType("UnityEngine.Application") - } - ).Where(x => x.type != null).Select(x => x.type).First(); - - var newMethod = ctorType.GetMethods() - .Single(x => x.ToString() == this.replace); - var refMethod = this.module.ImportReference(newMethod); - - foreach (Instruction i in found.ToList()) - il.Replace(i, il.Create(OpCodes.Call, refMethod)); - } - - private void patch_type(TypeDefinition td) { - foreach (var nested in td.NestedTypes) patch_type(nested); - foreach (MethodDefinition md in td.Methods) patch_method(md); - } -} - -public class patcher { - - public static int Main(string[] args) { - Parser.Default.ParseArguments< - GenericOptions, FixFileStreamsCmd, ReplaceCallCmd - >(args) - .WithParsed(opts => new FixFileStreams(opts)) - .WithParsed(opts => new ReplaceCall(opts)); - return 0; - } -} diff --git a/pkgs/games/build-support/monogame-patcher/src/assembly-info.cs b/pkgs/games/build-support/monogame-patcher/src/assembly-info.cs new file mode 100644 index 00000000..55c4c4d3 --- /dev/null +++ b/pkgs/games/build-support/monogame-patcher/src/assembly-info.cs @@ -0,0 +1,6 @@ +using System.Reflection; + +[assembly: AssemblyTitle("monogame-patcher")] +[assembly: AssemblyVersion("0.1.0")] +[assembly: AssemblyDescription("Patches common annoyances in Mono Assemblies")] +[assembly: AssemblyCopyright("(c) 2018 aszlig")] diff --git a/pkgs/games/build-support/monogame-patcher/src/patcher.cs b/pkgs/games/build-support/monogame-patcher/src/patcher.cs new file mode 100644 index 00000000..c1502ba1 --- /dev/null +++ b/pkgs/games/build-support/monogame-patcher/src/patcher.cs @@ -0,0 +1,168 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System; + +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using Mono.Cecil; + +using CommandLine; + +class GenericOptions +{ + [Option('i', "infile", Required=true, HelpText="Input file to transform.")] + public string inputFile { get; set; } + [Option('o', "outfile", HelpText="File to write transformed data to.")] + public string outputFile { get; set; } +} + +class Command { + protected string infile; + protected string outfile; + protected ModuleDefinition module; + + public Command(GenericOptions options) { + if (options.outputFile == null) + this.outfile = options.inputFile; + else + this.outfile = options.outputFile; + this.infile = options.inputFile; + + var rp = new ReaderParameters { + ReadWrite = this.infile == this.outfile + }; + this.module = ModuleDefinition.ReadModule(this.infile, rp); + } + + public void save() { + if (this.outfile == this.infile) + this.module.Write(); + else + this.module.Write(this.outfile); + } +} + +[Verb("fix-filestreams", HelpText="Fix System.IO.FileStream constructors" + +" to open files read-only.")] +class FixFileStreamsCmd : GenericOptions { + [Value(0, Required=true, MetaName = "type", HelpText = "Types to patch.")] + public IEnumerable typesToPatch { get; set; } +}; + +class FixFileStreams : Command { + public FixFileStreams(FixFileStreamsCmd options) : base(options) { + var filtered = this.module.Types + .Where(p => options.typesToPatch.Contains(p.Name)); + + foreach (var toPatch in filtered) + patch_type(toPatch); + + this.save(); + } + + private void patch_method(MethodDefinition md) { + var il = md.Body.GetILProcessor(); + + var fileStreams = md.Body.Instructions + .Where(i => i.OpCode == OpCodes.Newobj) + .Where(i => (i.Operand as MethodReference).DeclaringType + .FullName == "System.IO.FileStream"); + + foreach (Instruction i in fileStreams.ToList()) { + var fileAccessRead = il.Create(OpCodes.Ldc_I4_1); + il.InsertBefore(i, fileAccessRead); + + var ctorType = this.module.AssemblyReferences.Select( + x => new { + type = this.module.AssemblyResolver.Resolve(x) + .MainModule.GetType("System.IO.FileStream") + } + ).Where(x => x.type != null).Select(x => x.type).First(); + + string wantedCtor = "System.Void System.IO.FileStream" + + "::.ctor(System.String," + + "System.IO.FileMode," + + "System.IO.FileAccess)"; + + var newCtor = ctorType.GetConstructors() + .Single(x => x.ToString() == wantedCtor); + + var refCtor = this.module.ImportReference(newCtor); + il.Replace(i, il.Create(OpCodes.Newobj, refCtor)); + } + } + + private void patch_type(TypeDefinition td) { + foreach (var nested in td.NestedTypes) patch_type(nested); + foreach (MethodDefinition md in td.Methods) patch_method(md); + } +} + +[Verb("replace-call", HelpText="Replace calls to types.")] +class ReplaceCallCmd : GenericOptions { + [Value(0, Min=2, Max=2, HelpText="Call to replace.")] + public IEnumerable replaceCall { get; set; } + + [Value(2, Required=true, MetaName = "type", HelpText = "Types to patch.")] + public IEnumerable typesToPatch { get; set; } + +}; + +class ReplaceCall : Command { + private string search; + private string replace; + + public ReplaceCall(ReplaceCallCmd options) : base(options) { + this.search = options.replaceCall.ToList()[0]; + this.replace = options.replaceCall.ToList()[1]; + + var filtered = this.module.Types + .Where(p => options.typesToPatch.Contains(p.Name)); + + foreach (var toPatch in filtered) + patch_type(toPatch); + + this.save(); + } + + private void patch_method(MethodDefinition md) { + var il = md.Body.GetILProcessor(); + + var found = md.Body.Instructions + .Where(i => i.OpCode == OpCodes.Call) + .Where(i => i.Operand.ToString() == this.search); + + var ctorType = this.module.AssemblyReferences.Select( + x => new { + // XXX: Don't hardcode UnityEngine.Application! + type = this.module.AssemblyResolver.Resolve(x) + .MainModule.GetType("UnityEngine.Application") + } + ).Where(x => x.type != null).Select(x => x.type).First(); + + var newMethod = ctorType.GetMethods() + .Single(x => x.ToString() == this.replace); + var refMethod = this.module.ImportReference(newMethod); + + foreach (Instruction i in found.ToList()) + il.Replace(i, il.Create(OpCodes.Call, refMethod)); + } + + private void patch_type(TypeDefinition td) { + foreach (var nested in td.NestedTypes) patch_type(nested); + foreach (MethodDefinition md in td.Methods) patch_method(md); + } +} + +public class patcher { + + public static int Main(string[] args) { + Parser.Default.ParseArguments< + GenericOptions, FixFileStreamsCmd, ReplaceCallCmd + >(args) + .WithParsed(opts => new FixFileStreams(opts)) + .WithParsed(opts => new ReplaceCall(opts)); + return 0; + } +} diff --git a/pkgs/games/build-support/monogame-patcher/src/patcher.csproj b/pkgs/games/build-support/monogame-patcher/src/patcher.csproj new file mode 100644 index 00000000..cd8f1c19 --- /dev/null +++ b/pkgs/games/build-support/monogame-patcher/src/patcher.csproj @@ -0,0 +1,39 @@ + + + + + + + + + + + + , Culture=neutral, PublicKeyToken= + + Version=0.10.0.0$(Blurb)50cebf1cceb9d05e + Version=2.2.1.0$(Blurb)de6f01bd326f8c32 + + + + + False + True + + + + False + True + + + + + monogame-patcher + Exe + bin/Release/ + bin/Release + 4 + true + + -- cgit 1.4.1