Explorar o código

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

Nikita Tsukanov %!s(int64=2) %!d(string=hai) anos
pai
achega
a24e0185fc
Modificáronse 4 ficheiros con 129 adicións e 10 borrados
  1. 2 0
      nukebuild/Build.cs
  2. 24 0
      nukebuild/Helpers.cs
  3. 99 0
      nukebuild/RefAssemblyGenerator.cs
  4. 4 10
      nukebuild/_build.csproj

+ 2 - 0
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 - 0
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 - 0
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);
+                    }
+                }
+            }
+        }
+    }
+}

+ 4 - 10
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>