#nullable enable using System; using System.IO; using System.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace ShrinkSDK.CodeGen; public sealed class ShrinkWeaveTask : Task { [Required] public string AssemblyPath { get; set; } = string.Empty; public string? PdbPath { get; set; } public ITaskItem[] ReferencePaths { get; set; } = Array.Empty(); public string? StrongNameKeyFile { get; set; } [Output] public bool Changed { get; private set; } [Output] public int InstanceSubscriberCount { get; private set; } [Output] public int StaticSubscriberCount { get; private set; } [Output] public int RegistryEntryCount { get; private set; } public override bool Execute() { if (!File.Exists(AssemblyPath)) { Log.LogError($"[ShrinkSDK.CodeGen] Intermediate assembly does not exist: {AssemblyPath}"); return false; } var assemblyDirectory = Path.GetDirectoryName(Path.GetFullPath(AssemblyPath))!; var temporaryAssembly = Path.Combine(assemblyDirectory, $".{Path.GetFileName(AssemblyPath)}.{Guid.NewGuid():N}.tmp"); var hasPdb = !string.IsNullOrWhiteSpace(PdbPath) && File.Exists(PdbPath); var temporaryPdb = hasPdb ? Path.Combine(assemblyDirectory, $".{Path.GetFileName(PdbPath)}.{Guid.NewGuid():N}.tmp") : null; try { var result = ShrinkAssemblyWeaver.Weave( AssemblyPath, hasPdb ? PdbPath : null, ReferencePaths.Select(item => item.ItemSpec), temporaryAssembly, temporaryPdb, ShrinkCodeGenPlatform.EngineNeutral, StrongNameKeyFile); foreach (var diagnostic in result.Diagnostics) { switch (diagnostic.Severity) { case ShrinkCodeGenDiagnosticSeverity.Warning: Log.LogWarning($"[ShrinkSDK.CodeGen] {diagnostic.Message}"); break; case ShrinkCodeGenDiagnosticSeverity.Error: Log.LogError($"[ShrinkSDK.CodeGen] {diagnostic.Message}"); break; default: Log.LogMessage(MessageImportance.Low, $"[ShrinkSDK.CodeGen] {diagnostic.Message}"); break; } } if (!result.Succeeded) return false; Changed = result.Changed; InstanceSubscriberCount = result.InstanceSubscribers; StaticSubscriberCount = result.StaticSubscribers; RegistryEntryCount = result.RegistryEntries; if (Changed) { File.Move(temporaryAssembly, AssemblyPath, true); if (hasPdb && temporaryPdb != null) File.Move(temporaryPdb, PdbPath!, true); } Log.LogMessage(MessageImportance.High, $"[ShrinkSDK.CodeGen] {Path.GetFileName(AssemblyPath)} woven: instance={InstanceSubscriberCount}, static={StaticSubscriberCount}, registry={RegistryEntryCount}."); return true; } catch (Exception exception) { Log.LogErrorFromException(exception, true); return false; } finally { TryDelete(temporaryAssembly); if (temporaryPdb != null) TryDelete(temporaryPdb); } } private static void TryDelete(string path) { try { if (File.Exists(path)) File.Delete(path); } catch { } } }