Files
cneicy 88ba3cdc48
Validate ShrinkSDK Workspace / unity (push) Failing after 3m18s
feat: add Godot C# compatibility and shared codegen weaving
2026-09-05 02:37:43 +08:00

164 lines
8.0 KiB
C#

#nullable enable
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Mono.Cecil;
using ShrinkSDK.CodeGen;
if (args.Length == 2 && args[0] == "--marker")
{
using var exported = AssemblyDefinition.ReadAssembly(args[1]);
var marker = exported.CustomAttributes.SingleOrDefault(attribute =>
attribute.AttributeType.FullName == "ShrinkSDK.Runtime.ShrinkCodeGenWovenAttribute");
Require(marker != null, "exported assembly has no ShrinkSDK CodeGen marker");
Require(exported.MainModule.Types.Any(type => type.FullName ==
"ShrinkEventBus.Generated.ShrinkGeneratedStaticBindings"),
"exported assembly has no static EventBus bootstrap");
Console.WriteLine($"PASS exported assembly woven by {marker!.ConstructorArguments[0].Value}");
return;
}
if ((args.Length == 3 || args.Length == 4) && args[0] == "--resign")
{
var signedAssembly = Path.GetFullPath(args[1]);
var keepOutput = args.Length == 4;
var output = keepOutput
? Path.GetFullPath(args[3])
: Path.Combine(Path.GetTempPath(), "ShrinkSDK.CodeGen.Resigned." + Guid.NewGuid().ToString("N") + ".dll");
var outputPdb = Path.ChangeExtension(output, ".pdb");
try
{
var result = ShrinkAssemblyWeaver.Weave(signedAssembly, Path.ChangeExtension(signedAssembly, ".pdb"),
BuildReferences(Path.GetDirectoryName(signedAssembly)!), output, outputPdb,
ShrinkCodeGenPlatform.EngineNeutral, args[2]);
Require(result.Succeeded && result.Changed,
"signed assembly re-weave failed: " + string.Join(" | ", result.Diagnostics.Select(item => item.Message)));
using var resigned = AssemblyDefinition.ReadAssembly(output);
Require(resigned.Name.HasPublicKey, "re-signed output has no public key");
Console.WriteLine("PASS signed assembly woven and re-signed with explicit key");
}
finally
{
if (!keepOutput)
{
if (File.Exists(output)) File.Delete(output);
if (File.Exists(outputPdb)) File.Delete(outputPdb);
}
}
return;
}
if (args.Length != 1 || !File.Exists(args[0]))
throw new ArgumentException("Pass the unwoven CodeGenFixture assembly path.");
var sourceAssembly = Path.GetFullPath(args[0]);
var sourceDirectory = Path.GetDirectoryName(sourceAssembly)!;
var sourcePdb = Path.ChangeExtension(sourceAssembly, ".pdb");
var references = BuildReferences(sourceDirectory);
var root = Path.Combine(Path.GetTempPath(), "ShrinkSDK.CodeGen.Validation", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(root);
try
{
var woven = Path.Combine(root, "fixture.woven.dll");
var wovenPdb = Path.Combine(root, "fixture.woven.pdb");
var first = ShrinkAssemblyWeaver.Weave(sourceAssembly, sourcePdb, references, woven, wovenPdb);
Require(first.Succeeded && first.Changed,
"single weave did not change the assembly: " + string.Join(" | ", first.Diagnostics.Select(item => item.Message)));
Require(first.InstanceSubscribers == 1 && first.StaticSubscribers == 1 && first.RegistryEntries == 5,
$"unexpected generated counts: {first.InstanceSubscribers}/{first.StaticSubscribers}/{first.RegistryEntries}");
VerifyStructure(woven);
var second = ShrinkAssemblyWeaver.Weave(woven, wovenPdb, references.Append(woven),
Path.Combine(root, "twice.dll"), Path.Combine(root, "twice.pdb"));
Require(second.Succeeded && !second.Changed, "repeated weave was not idempotent");
var corruptPdb = Path.Combine(root, "corrupt.pdb");
File.WriteAllText(corruptPdb, "not a portable pdb");
var corrupt = ShrinkAssemblyWeaver.Weave(sourceAssembly, corruptPdb, references,
Path.Combine(root, "corrupt.dll"), Path.Combine(root, "corrupt.out.pdb"));
Require(!corrupt.Succeeded && !File.Exists(Path.Combine(root, "corrupt.dll")),
"damaged PDB was not rejected atomically");
var missing = ShrinkAssemblyWeaver.Weave(sourceAssembly, null, Array.Empty<string>(),
Path.Combine(root, "missing.dll"), null);
Require(!missing.Succeeded, "missing dependencies were not rejected");
var signedInput = Path.Combine(root, "signed.dll");
using (var assembly = AssemblyDefinition.ReadAssembly(sourceAssembly))
{
assembly.Name.PublicKey = Enumerable.Range(0, 160).Select(value => (byte)(value + 1)).ToArray();
assembly.Name.Attributes |= AssemblyAttributes.PublicKey;
assembly.Write(signedInput);
}
var signed = ShrinkAssemblyWeaver.Weave(signedInput, null, references,
Path.Combine(root, "signed.out.dll"), null);
Require(!signed.Succeeded && signed.Diagnostics.Any(item => item.Message.Contains("Signed assemblies")),
"signed assembly was not rejected");
var parallel = Enumerable.Range(0, 4).Select(index => Task.Run(() =>
{
var output = Path.Combine(root, $"parallel-{index}.dll");
var outputPdb = Path.Combine(root, $"parallel-{index}.pdb");
return ShrinkAssemblyWeaver.Weave(sourceAssembly, sourcePdb, references, output, outputPdb);
})).ToArray();
await Task.WhenAll(parallel);
Require(parallel.All(task => task.Result.Succeeded && task.Result.Changed),
"parallel weaving of independent assemblies failed");
Console.WriteLine("PASS Cecil structure + single/repeat/parallel weave + corrupt PDB/signed/missing dependency guards");
}
finally
{
Directory.Delete(root, true);
}
static void VerifyStructure(string path)
{
using var assembly = AssemblyDefinition.ReadAssembly(path);
var module = assembly.MainModule;
var instance = module.Types.Single(type => type.Name == "InstanceSubscriber");
Require(instance.Interfaces.Any(item => item.InterfaceType.FullName == "ShrinkEventBus.IShrinkGeneratedSubscriber"),
"generated subscriber interface is missing");
Require(instance.Methods.Any(method => method.Name == "ShrinkEventBus.IShrinkGeneratedSubscriber.AttachGenerated"),
"AttachGenerated is missing");
Require(module.Types.Any(type => type.FullName == "ShrinkEventBus.Generated.ShrinkGeneratedStaticBindings"),
"static binding bootstrap is missing");
Require(module.Types.Any(type => type.FullName ==
"ShrinkNetwork.Integration.Generated.ShrinkGeneratedNetworkEventBindings"),
"Network/EventBus generated bootstrap is missing");
var moduleInitializer = module.Types.Single(type => type.Name == "<Module>").Methods.Single(method => method.Name == ".cctor");
Require(moduleInitializer.Body.Instructions.Any(instruction => instruction.Operand is MethodReference method && method.Name == "Register"),
"module initializer does not call static registration");
var attributes = assembly.CustomAttributes.Select(attribute => attribute.AttributeType.FullName).ToArray();
foreach (var expected in new[]
{
"ShrinkSDK.Runtime.ShrinkCodeGenWovenAttribute",
"ShrinkCommand.ShrinkCommandStaticRegistryAttribute",
"ShrinkNetwork.ShrinkNetworkMessageRegistryAttribute",
"ShrinkNetwork.ShrinkNetworkStaticSubscriberRegistryAttribute"
})
Require(attributes.Contains(expected), $"assembly registry is missing: {expected}");
}
static void Require(bool condition, string message)
{
if (!condition) throw new InvalidOperationException(message);
}
static string[] BuildReferences(string sourceDirectory)
{
var referencePackRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".nuget", "packages", "microsoft.netcore.app.ref");
var referencePack = Directory.GetDirectories(referencePackRoot)
.Select(path => Path.Combine(path, "ref", "net8.0"))
.Where(Directory.Exists)
.OrderByDescending(path => path, StringComparer.OrdinalIgnoreCase)
.First();
return Directory.GetFiles(sourceDirectory, "*.dll")
.Concat(Directory.GetFiles(referencePack, "*.dll"))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
}