-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide PrunePackageReference data for NuGet (#45874)
- Loading branch information
Showing
19 changed files
with
2,212 additions
and
1 deletion.
There are no files selected for viewing
182 changes: 182 additions & 0 deletions
182
src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
namespace Microsoft.ComponentDetection.Detectors.NuGet; | ||
|
||
using System; | ||
using System.Collections; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using global::NuGet.Frameworks; | ||
using global::NuGet.Versioning; | ||
|
||
/// <summary> | ||
/// Represents a set of packages that are provided by a specific framework. | ||
/// At the moment this only represents the packages that are provided by the Microsoft.NETCore.App framework. | ||
/// We could extend this to represent the packages provided by other frameworks like Microsoft.AspNetCore.App and Microsoft.WindowsDesktop.App. | ||
/// </summary> | ||
internal sealed partial class FrameworkPackages : IEnumerable<KeyValuePair<string, NuGetVersion>>, IEnumerable | ||
{ | ||
private const string DefaultFrameworkKey = ""; | ||
private static readonly ConcurrentDictionary<NuGetFramework, ConcurrentDictionary<string, FrameworkPackages>> FrameworkPackagesByFramework = []; | ||
|
||
static FrameworkPackages() | ||
{ | ||
NETStandard20.Register(); | ||
NETStandard21.Register(); | ||
NET461.Register(); | ||
NETCoreApp20.Register(); | ||
NETCoreApp21.Register(); | ||
NETCoreApp22.Register(); | ||
NETCoreApp30.Register(); | ||
NETCoreApp31.Register(); | ||
NETCoreApp50.Register(); | ||
NETCoreApp60.Register(); | ||
NETCoreApp70.Register(); | ||
NETCoreApp80.Register(); | ||
NETCoreApp90.Register(); | ||
} | ||
|
||
public FrameworkPackages(NuGetFramework framework, string frameworkName) | ||
{ | ||
this.Framework = framework; | ||
this.FrameworkName = frameworkName; | ||
} | ||
|
||
public FrameworkPackages(NuGetFramework framework, string frameworkName, FrameworkPackages frameworkPackages) | ||
: this(framework, frameworkName) => this.Packages = new(frameworkPackages.Packages); | ||
|
||
public NuGetFramework Framework { get; } | ||
|
||
public string FrameworkName { get; } | ||
|
||
public Dictionary<string, NuGetVersion> Packages { get; } = new Dictionary<string, NuGetVersion>(StringComparer.OrdinalIgnoreCase); | ||
|
||
private static string GetFrameworkKey(string frameworkName) => | ||
frameworkName switch | ||
{ | ||
FrameworkNames.NetStandardLibrary => DefaultFrameworkKey, | ||
FrameworkNames.NetCoreApp => DefaultFrameworkKey, | ||
_ => frameworkName, | ||
}; | ||
|
||
internal static void Register(params FrameworkPackages[] toRegister) | ||
{ | ||
foreach (var frameworkPackages in toRegister) | ||
{ | ||
if (!FrameworkPackagesByFramework.TryGetValue(frameworkPackages.Framework, out var frameworkPackagesForVersion)) | ||
{ | ||
FrameworkPackagesByFramework[frameworkPackages.Framework] = frameworkPackagesForVersion = []; | ||
} | ||
|
||
var frameworkKey = GetFrameworkKey(frameworkPackages.FrameworkName); | ||
frameworkPackagesForVersion[frameworkKey] = frameworkPackages; | ||
} | ||
} | ||
|
||
public static FrameworkPackages[] GetFrameworkPackages(NuGetFramework framework, string[] frameworkReferences, string targetingPackRoot) | ||
{ | ||
var frameworkPackages = new List<FrameworkPackages>(); | ||
|
||
if (frameworkReferences.Length == 0) | ||
{ | ||
frameworkReferences = [DefaultFrameworkKey]; | ||
} | ||
|
||
foreach (var frameworkReference in frameworkReferences) | ||
{ | ||
var frameworkKey = GetFrameworkKey(frameworkReference); | ||
if (FrameworkPackagesByFramework.TryGetValue(framework, out var frameworkPackagesForVersion) && | ||
frameworkPackagesForVersion.TryGetValue(frameworkKey, out var frameworkPackage)) | ||
{ | ||
frameworkPackages.Add(frameworkPackage); | ||
} | ||
else | ||
{ | ||
// if we didn't predefine the package overrides, load them from the targeting pack | ||
// we might just leave this out since in future frameworks we'll have this functionality built into NuGet.Frameworks | ||
var frameworkPackagesFromPack = LoadFrameworkPackagesFromPack(framework, frameworkReference, targetingPackRoot) ?? new FrameworkPackages(framework, frameworkReference); | ||
|
||
Register(frameworkPackagesFromPack); | ||
|
||
frameworkPackages.Add(frameworkPackagesFromPack); | ||
} | ||
} | ||
|
||
return frameworkPackages.ToArray(); | ||
} | ||
|
||
private static FrameworkPackages LoadFrameworkPackagesFromPack(NuGetFramework framework, string frameworkName, string targetingPackRoot) | ||
{ | ||
if (framework is null || framework.Framework != FrameworkConstants.FrameworkIdentifiers.NetCoreApp) | ||
{ | ||
return null; | ||
} | ||
|
||
var reducer = new FrameworkReducer(); | ||
var frameworkKey = GetFrameworkKey(frameworkName); | ||
var candidateFrameworks = FrameworkPackagesByFramework.Where(pair => pair.Value.ContainsKey(frameworkKey)).Select(pair => pair.Key); | ||
var nearestFramework = reducer.GetNearest(framework, candidateFrameworks); | ||
|
||
var frameworkPackages = nearestFramework is null ? | ||
new FrameworkPackages(framework, frameworkName) : | ||
new FrameworkPackages(framework, frameworkName, FrameworkPackagesByFramework[nearestFramework][frameworkKey]); | ||
|
||
if (!string.IsNullOrEmpty(targetingPackRoot)) | ||
{ | ||
var packsFolder = Path.Combine(targetingPackRoot, frameworkName + ".Ref"); | ||
if (Directory.Exists(packsFolder)) | ||
{ | ||
var packVersionPattern = $"{framework.Version.Major}.{framework.Version.Minor}.*"; | ||
var packDirectories = Directory.GetDirectories(packsFolder, packVersionPattern); | ||
var packageOverridesFile = packDirectories | ||
.Select(d => (Overrides: Path.Combine(d, "data", "PackageOverrides.txt"), Version: ParseVersion(Path.GetFileName(d)))) | ||
.Where(d => File.Exists(d.Overrides)) | ||
.OrderByDescending(d => d.Version) | ||
.FirstOrDefault().Overrides; | ||
|
||
if (packageOverridesFile is not null) | ||
{ | ||
// Adapted from https://github.com/dotnet/sdk/blob/c3a8f72c3a5491c693ff8e49e7406136a12c3040/src/Tasks/Common/ConflictResolution/PackageOverride.cs#L52-L68 | ||
var packageOverrides = File.ReadAllLines(packageOverridesFile); | ||
|
||
foreach (var packageOverride in packageOverrides) | ||
{ | ||
var packageOverrideParts = packageOverride.Trim().Split('|'); | ||
|
||
if (packageOverrideParts.Length == 2) | ||
{ | ||
var packageId = packageOverrideParts[0]; | ||
var packageVersion = ParseVersion(packageOverrideParts[1]); | ||
|
||
frameworkPackages.Packages[packageId] = packageVersion; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return frameworkPackages; | ||
|
||
static NuGetVersion ParseVersion(string versionString) => NuGetVersion.TryParse(versionString, out var version) ? version : null; | ||
} | ||
|
||
private void Add(string id, string version) | ||
{ | ||
// intentionally redirect to indexer to allow for overwrite | ||
this.Packages[id] = NuGetVersion.Parse(version); | ||
} | ||
|
||
public bool IsAFrameworkComponent(string id, NuGetVersion version) => this.Packages.TryGetValue(id, out var frameworkPackageVersion) && frameworkPackageVersion >= version; | ||
|
||
IEnumerator<KeyValuePair<string, NuGetVersion>> IEnumerable<KeyValuePair<string, NuGetVersion>>.GetEnumerator() => this.Packages.GetEnumerator(); | ||
|
||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); | ||
|
||
internal static class FrameworkNames | ||
{ | ||
public const string AspNetCoreApp = "Microsoft.AspNetCore.App"; | ||
public const string NetCoreApp = "Microsoft.NETCore.App"; | ||
public const string NetStandardLibrary = "NETStandard.Library"; | ||
public const string WindowsDesktopApp = "Microsoft.WindowsDesktop.App"; | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net461.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace Microsoft.ComponentDetection.Detectors.NuGet; | ||
|
||
using static global::NuGet.Frameworks.FrameworkConstants.CommonFrameworks; | ||
|
||
/// <summary> | ||
/// Framework packages for .NETFramework,Version=v4.6.1. | ||
/// </summary> | ||
internal partial class FrameworkPackages | ||
{ | ||
internal static class NET461 | ||
{ | ||
internal static FrameworkPackages Instance { get; } = new(Net461, DefaultFrameworkKey, NETStandard20.Instance); | ||
|
||
internal static void Register() => FrameworkPackages.Register(Instance); | ||
} | ||
} |
Oops, something went wrong.