| File: Package.cs | Web Access |
| Project: src\sdk\src\Compatibility\ApiCompat\Microsoft.DotNet.PackageValidation\Microsoft.DotNet.PackageValidation.csproj (Microsoft.DotNet.PackageValidation) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.ObjectModel; using NuGet.Client; using NuGet.ContentModel; using NuGet.Frameworks; using NuGet.Packaging; using NuGet.Packaging.Core; using NuGet.RuntimeModel; namespace Microsoft.DotNet.PackageValidation { /// <summary> /// This class represents a NuGet package. /// </summary> public class Package { private readonly ContentItemCollection _contentItemCollection; private readonly ManagedCodeConventions _conventions; private static RuntimeGraph? s_runtimeGraph; /// <summary> /// The name of the package /// </summary> public string PackageId { get; } /// <summary> /// The version of the package. /// </summary> public string Version { get; } /// <summary> /// Local path of the package. /// </summary> public string PackagePath { get; } /// <summary> /// List of assets in the package. /// </summary> public IEnumerable<ContentItem> PackageAssets { get; } /// <summary> /// List of compile assets in the package. /// </summary> public IEnumerable<ContentItem> CompileAssets { get; } /// <summary> /// List of assets under ref in the package. /// </summary> public IEnumerable<ContentItem> RefAssets { get; } /// <summary> /// List of assets under lib in the package. /// </summary> public IEnumerable<ContentItem> LibAssets { get; } /// <summary> /// List of all the runtime specific assets in the package. /// </summary> public IEnumerable<ContentItem> RuntimeSpecificAssets { get; } /// <summary> /// List of all the runtime assets in the package. /// </summary> public IEnumerable<ContentItem> RuntimeAssets { get; } /// <summary> /// List of rids in the package. /// </summary> public IEnumerable<string> Rids { get; } /// <summary> /// List of assembly references grouped by target framework. /// </summary> public IReadOnlyDictionary<NuGetFramework, IEnumerable<string>>? AssemblyReferences { get; } /// <summary> /// List of the frameworks in the package. /// </summary> public IReadOnlyList<NuGetFramework> FrameworksInPackage { get; } public Package(string packagePath, string packageId, string version, IEnumerable<string> packageAssets, IReadOnlyDictionary<NuGetFramework, IEnumerable<string>>? assemblyReferences = null) { PackagePath = packagePath; PackageId = packageId; Version = version; _conventions = new ManagedCodeConventions(s_runtimeGraph); _contentItemCollection = new ContentItemCollection(); _contentItemCollection.Load(packageAssets); PackageAssets = _contentItemCollection.FindItems(_conventions.Patterns.AnyTargettedFile); RefAssets = _contentItemCollection.FindItems(_conventions.Patterns.CompileRefAssemblies); LibAssets = _contentItemCollection.FindItems(_conventions.Patterns.CompileLibAssemblies); CompileAssets = RefAssets.Any() ? RefAssets : LibAssets; RuntimeAssets = _contentItemCollection.FindItems(_conventions.Patterns.RuntimeAssemblies); RuntimeSpecificAssets = RuntimeAssets.Where(t => t.Path.StartsWith("runtimes")).ToArray(); Rids = RuntimeSpecificAssets.Select(t => (string)t.Properties["rid"]) .Distinct() .ToArray(); FrameworksInPackage = CompileAssets.Select(t => (NuGetFramework)t.Properties["tfm"]) .Concat(RuntimeAssets.Select(t => (NuGetFramework)t.Properties["tfm"])) .Distinct() .ToArray(); AssemblyReferences = assemblyReferences; } public static void InitializeRuntimeGraph(string runtimeGraph) { s_runtimeGraph = JsonRuntimeFormat.ReadRuntimeGraph(runtimeGraph); } /// <summary> /// Creates a package object from a given package path and optional assembly references. /// </summary> /// <param name="packagePath">The path to the package path.</param> /// <param name="packageAssemblyReferences">Optional assembly references with target framework information.</param> public static Package Create(string? packagePath, IReadOnlyDictionary<NuGetFramework, IEnumerable<string>>? packageAssemblyReferences = null) { if (string.IsNullOrEmpty(packagePath)) { throw new ArgumentException(Resources.EmptyPackagePath); } if (!File.Exists(Path.GetFullPath(packagePath))) { throw new FileNotFoundException(string.Format(Resources.NonExistentPackagePath, packagePath)); } using PackageArchiveReader packageReader = new(packagePath); NuspecReader nuspecReader = packageReader.NuspecReader; string packageId = nuspecReader.GetId(); string version = nuspecReader.GetVersion().ToString(); IEnumerable<string> packageAssets = packageReader.GetFiles().Where(t => t.EndsWith(".dll")).ToArray(); return new Package(packagePath!, packageId, version, packageAssets, packageAssemblyReferences); } /// <summary> /// Finds the best runtime asset for for a specific framework. /// </summary> /// <param name="framework">The framework where the package needs to be installed.</param> /// <returns>A ContentItem representing the best runtime asset</returns> public IReadOnlyList<ContentItem>? FindBestRuntimeAssetForFramework(NuGetFramework framework) { SelectionCriteria managedCriteria = _conventions.Criteria.ForFramework(framework); IList<ContentItem>? items = _contentItemCollection.FindBestItemGroup(managedCriteria, _conventions.Patterns.RuntimeAssemblies)?.Items; return items != null ? new ReadOnlyCollection<ContentItem>(items.Where(t => !t.Path.StartsWith("runtimes")).ToArray()) : null; } /// <summary> /// Finds the best runtime specific asset for for a specific framework. /// </summary> /// <param name="framework">The framework where the package needs to be installed.</param> /// <returns>A ContentItem representing the best runtime specific asset.</returns> public IReadOnlyList<ContentItem>? FindBestRuntimeSpecificAssetForFramework(NuGetFramework framework) { SelectionCriteria managedCriteria = _conventions.Criteria.ForFramework(framework); IList<ContentItem>? items = _contentItemCollection.FindBestItemGroup(managedCriteria, _conventions.Patterns.RuntimeAssemblies)?.Items; return items != null ? new ReadOnlyCollection<ContentItem>(items.Where(t => t.Path.StartsWith("runtimes")).ToArray()) : null; } /// <summary> /// Finds the best runtime asset for a framework-rid pair. /// </summary> /// <param name="framework">The framework where the package needs to be installed.</param> /// <param name="rid">The rid where the package needs to be installed.</param> /// <returns>A ContentItem representing the best runtime asset</returns> public IReadOnlyList<ContentItem>? FindBestRuntimeAssetForFrameworkAndRuntime(NuGetFramework framework, string rid) { SelectionCriteria managedCriteria = _conventions.Criteria.ForFrameworkAndRuntime(framework, rid); IList<ContentItem>? items = _contentItemCollection.FindBestItemGroup(managedCriteria, _conventions.Patterns.RuntimeAssemblies)?.Items; return items != null ? new ReadOnlyCollection<ContentItem>(items) : null; } /// <summary> /// Finds the best compile time asset for a specific framework. /// </summary> /// <param name="framework">The framework where the package needs to be installed.</param> /// <returns>A ContentItem representing the best compile time asset.</returns> public IReadOnlyList<ContentItem>? FindBestCompileAssetForFramework(NuGetFramework framework) { SelectionCriteria managedCriteria = _conventions.Criteria.ForFramework(framework); PatternSet patternSet = RefAssets.Any() ? _conventions.Patterns.CompileRefAssemblies : _conventions.Patterns.CompileLibAssemblies; IList<ContentItem>? items = _contentItemCollection.FindBestItemGroup(managedCriteria, patternSet)?.Items; return items != null ? new ReadOnlyCollection<ContentItem>(items) : null; } /// <summary> /// Finds the best assembly references for a specific framework. /// </summary> /// <param name="framework">The framework where the package needs to be installed.</param> /// <returns>The assembly references for the specified framework.</returns> public IEnumerable<string>? FindBestAssemblyReferencesForFramework(NuGetFramework framework) { if (AssemblyReferences is null) return null; // Fast path: return for direct matches if (AssemblyReferences.TryGetValue(framework, out IEnumerable<string>? references)) { return references; } // Search for the nearest newer assembly references framework. Queue<NuGetFramework> tfmQueue = new(AssemblyReferences.Keys); while (tfmQueue.Count > 0) { NuGetFramework assemblyReferencesFramework = tfmQueue.Dequeue(); NuGetFramework? bestAssemblyReferencesFramework = NuGetFrameworkUtility.GetNearest(tfmQueue.Concat([framework]), assemblyReferencesFramework, (key) => key); if (bestAssemblyReferencesFramework == framework) { return AssemblyReferences[assemblyReferencesFramework]; } } return null; } } }