RemoveSharedFrameworkDependencies.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.IO.Compression;
  7. using System.Linq;
  8. using System.Xml;
  9. using System.Xml.Linq;
  10. using Microsoft.Build.Framework;
  11. using Microsoft.Build.Utilities;
  12. using NuGet.Frameworks;
  13. using NuGet.Packaging;
  14. using NuGet.Packaging.Core;
  15. namespace RepoTasks;
  16. // This is temporary until we can use FrameworkReference to build our own packages
  17. public class RemoveSharedFrameworkDependencies : Microsoft.Build.Utilities.Task
  18. {
  19. [Required]
  20. public ITaskItem[] Files { get; set; }
  21. [Required]
  22. public ITaskItem[] FrameworkOnlyPackages { get; set; }
  23. [Required]
  24. public string SharedFrameworkTargetFramework { get; set; }
  25. public override bool Execute()
  26. {
  27. Log.LogMessage("NuGet version = " + typeof(PackageArchiveReader).Assembly.GetName().Version);
  28. var dependencyToRemove = new HashSet<string>(FrameworkOnlyPackages.Select(p => p.ItemSpec), StringComparer.OrdinalIgnoreCase);
  29. foreach (var file in Files)
  30. {
  31. FilterDependencies(file.ItemSpec, dependencyToRemove);
  32. }
  33. return !Log.HasLoggedErrors;
  34. }
  35. private void FilterDependencies(string targetPath, ISet<string> dependencyToRemove)
  36. {
  37. var fileName = Path.GetFileName(targetPath);
  38. Log.LogMessage($"Updating {fileName}");
  39. using (var fileStream = File.Open(targetPath, FileMode.Open))
  40. using (var package = new ZipArchive(fileStream, ZipArchiveMode.Update))
  41. using (var packageReader = new PackageArchiveReader(fileStream, leaveStreamOpen: true))
  42. {
  43. var referencesFrameworkOnlyAssembly = false;
  44. var nuspecFile = packageReader.GetNuspecFile();
  45. using (var stream = package.OpenFile(nuspecFile))
  46. {
  47. var reader = Manifest.ReadFrom(stream, validateSchema: true);
  48. stream.Position = 0;
  49. var packageBuilder = new PackageBuilder(stream, basePath: null);
  50. var updatedGroups = new List<PackageDependencyGroup>();
  51. foreach (var group in packageBuilder.DependencyGroups)
  52. {
  53. var packages = new List<PackageDependency>();
  54. var updatedGroup = new PackageDependencyGroup(group.TargetFramework, packages);
  55. foreach (var dependency in group.Packages)
  56. {
  57. if (dependencyToRemove.Contains(dependency.Id))
  58. {
  59. referencesFrameworkOnlyAssembly = true;
  60. Log.LogMessage($" Remove dependency on '{dependency.Id}'");
  61. continue;
  62. }
  63. packages.Add(dependency);
  64. }
  65. updatedGroups.Add(updatedGroup);
  66. }
  67. if (referencesFrameworkOnlyAssembly)
  68. {
  69. packageBuilder.DependencyGroups.Clear();
  70. packageBuilder.DependencyGroups.AddRange(updatedGroups);
  71. var updatedManifest = Manifest.Create(packageBuilder);
  72. var inMemory = new MemoryStream();
  73. updatedManifest.Save(inMemory);
  74. inMemory.Position = 0;
  75. // Hack the raw nuspec to add the <frameworkReference> dependency
  76. var rawNuspec = XDocument.Load(inMemory, LoadOptions.PreserveWhitespace);
  77. var ns = rawNuspec.Root.GetDefaultNamespace();
  78. var metadata = rawNuspec.Root.Descendants(ns + "metadata").Single();
  79. metadata.Add(
  80. new XElement(ns + "frameworkReferences",
  81. new XElement(ns + "group",
  82. new XAttribute("targetFramework", NuGetFramework.Parse(SharedFrameworkTargetFramework).GetFrameworkString()),
  83. new XElement(ns + "frameworkReference", new XAttribute("name", "Microsoft.AspNetCore.App")))));
  84. stream.Position = 0;
  85. stream.SetLength(0);
  86. rawNuspec.Save(stream);
  87. Log.LogMessage(MessageImportance.High, "Added <frameworkReference> to {0}", fileName);
  88. }
  89. else
  90. {
  91. Log.LogMessage($"No changes made to {fileName}");
  92. }
  93. }
  94. }
  95. }
  96. }