Browse Source

Generate fake ref assemblies with patched *Impl and [NotClientImplementable] interfaces

pull/11062/head
Nikita Tsukanov 3 years ago
parent
commit
a24e0185fc
  1. 2
      nukebuild/Build.cs
  2. 24
      nukebuild/Helpers.cs
  3. 99
      nukebuild/RefAssemblyGenerator.cs
  4. 14
      nukebuild/_build.csproj

2
nukebuild/Build.cs

@ -273,6 +273,8 @@ partial class Build : NukeBuild
if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,
new NumergeNukeLogger()))
throw new Exception("Package merge failed");
RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." +
Parameters.Version + ".nupkg");
});
Target RunTests => _ => _

24
nukebuild/Helpers.cs

@ -0,0 +1,24 @@
using System;
using System.IO;
using Nuke.Common.Utilities;
class Helpers
{
public static IDisposable UseTempDir(out string dir)
{
var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(path);
dir = path;
return DelegateDisposable.CreateBracket(null, () =>
{
try
{
Directory.Delete(path, true);
}
catch
{
// ignore
}
});
}
}

99
nukebuild/RefAssemblyGenerator.cs

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.Writer;
public class RefAssemblyGenerator
{
static void PatchRefAssembly(string file)
{
var reader = typeof(RefAssemblyGenerator).Assembly.GetManifestResourceStream("avalonia.snk");
var snk = new byte[reader.Length];
reader.Read(snk, 0, snk.Length);
var def = AssemblyDef.Load(new MemoryStream(File.ReadAllBytes(file)));
foreach(var t in def.ManifestModule.Types)
ProcessType(t);
def.Write(file, new ModuleWriterOptions(def.ManifestModule)
{
StrongNameKey = new StrongNameKey(snk),
});
}
static void ProcessType(TypeDef type)
{
foreach (var nested in type.NestedTypes)
ProcessType(nested);
if (type.IsInterface)
{
var hideMethods = type.Name.EndsWith("Impl");
var injectMethod = hideMethods
|| type.CustomAttributes.Any(a =>
a.AttributeType.FullName.EndsWith("NotClientImplementableAttribute"));
if (hideMethods)
{
foreach (var m in type.Methods)
{
m.Attributes |= MethodAttributes.Public | MethodAttributes.Assembly;
m.Attributes ^= MethodAttributes.Public;
}
}
if(injectMethod)
{
type.Methods.Add(new MethodDefUser("NotClientImplementable",
new MethodSig(CallingConvention.Default, 0, type.Module.CorLibTypes.Void),
MethodAttributes.Assembly
| MethodAttributes.Abstract
| MethodAttributes.NewSlot
| MethodAttributes.HideBySig));
}
}
}
public static void GenerateRefAsmsInPackage(string packagePath)
{
using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
ZipArchiveMode.Update))
{
foreach (var entry in archive.Entries.ToList())
{
if (entry.FullName.StartsWith("ref/"))
entry.Delete();
}
foreach (var entry in archive.Entries.ToList())
{
if (entry.FullName.StartsWith("lib/"))
{
if (entry.Name.EndsWith(".dll"))
{
using (Helpers.UseTempDir(out var temp))
{
var file = Path.Combine(temp, entry.Name);
entry.ExtractToFile(file);
PatchRefAssembly(file);
archive.CreateEntryFromFile(file, "ref/" + entry.FullName.Substring(4));
}
}
else if (entry.Name.EndsWith(".xml"))
{
var newEntry = archive.CreateEntry("ref/" + entry.FullName.Substring(4),
CompressionLevel.Optimal);
using (var src = entry.Open())
using (var dst = newEntry.Open())
src.CopyTo(dst);
}
}
}
}
}
}

14
nukebuild/_build.csproj

@ -18,6 +18,7 @@
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="SourceLink" Version="1.1.0" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" PrivateAssets="All" />
<PackageReference Include="dnlib" Version="3.6.0" />
<PackageReference Include="xunit.runner.console" Version="2.4.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@ -31,18 +32,11 @@
<!-- Common build related files -->
<Compile Remove="Numerge/**/*.*" />
<Compile Include="Numerge/Numerge/**/*.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
<EmbeddedResource Include="../build/avalonia.snk"></EmbeddedResource>
<Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Numerge\Numerge.Console\" />
</ItemGroup>
</Project>

Loading…
Cancel
Save