Skip to content

Commit 55adfe0

Browse files
authored
Refactored PackageService code for use by Search-by-TFM (#9261)
* Refactored PackageService code, created AssetFrameworkService * Added .NET foundation header to new file * renamed the new file/class * renamed reference too
1 parent 8337efe commit 55adfe0

2 files changed

Lines changed: 119 additions & 93 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Linq;
8+
using NuGet.Client;
9+
using NuGet.ContentModel;
10+
using NuGet.Frameworks;
11+
using NuGet.Packaging.Core;
12+
using NuGet.RuntimeModel;
13+
14+
namespace NuGetGallery
15+
{
16+
public static class AssetFrameworkHelper
17+
{
18+
/// <summary>
19+
/// This method combines the logic used in restore operations to make a determination about the TFM supported by the package.
20+
/// We have curated a set of compatibility requirements for our needs in NuGet.org. The client logic can be found here:
21+
/// https://github.com/NuGet/NuGet.Client/blob/63255047fe7052cc33b763356ff995d9166f719e/src/NuGet.Core/NuGet.Commands/RestoreCommand/CompatibilityChecker.cs#L252-L294
22+
/// https://github.com/NuGet/NuGet.Client/blob/63255047fe7052cc33b763356ff995d9166f719e/src/NuGet.Core/NuGet.Commands/RestoreCommand/CompatibilityChecker.cs#L439-L442
23+
/// ...and our combination of these elements is below.
24+
/// The logic is essentially this:
25+
/// - Determine whether we're looking at a tools package. In this case we will use tools "pattern sets" (collections of file patterns
26+
/// defined in <see cref="ManagedCodeConventions" />) to assess which frameworks are targeted by the package.
27+
/// - If this isn't a tools package, we look for build-time, runtime, content and resource file patterns
28+
/// For added details on the various cases, see unit tests targeting this method.
29+
/// </summary>
30+
public static IEnumerable<NuGetFramework> GetAssetFrameworks(string packageId, IReadOnlyList<PackageType> packageTypes, IList<string> packageFiles)
31+
{
32+
var supportedTFMs = Enumerable.Empty<NuGetFramework>();
33+
if (packageFiles != null && packageFiles.Any())
34+
{
35+
// Setup content items for analysis
36+
var items = new ContentItemCollection();
37+
items.Load(packageFiles);
38+
var runtimeGraph = new RuntimeGraph();
39+
var conventions = new ManagedCodeConventions(runtimeGraph);
40+
41+
// Let's test for tools packages first--they're a special case
42+
var groups = Enumerable.Empty<ContentItemGroup>();
43+
if (packageTypes.Count == 1 && (packageTypes[0] == PackageType.DotnetTool ||
44+
packageTypes[0] == PackageType.DotnetCliTool))
45+
{
46+
// Only a package that is a tool package (and nothing else) will be matched against tools pattern set
47+
groups = items.FindItemGroups(conventions.Patterns.ToolsAssemblies);
48+
}
49+
else
50+
{
51+
// Gather together a list of pattern sets indicating the kinds of packages we wish to evaluate
52+
var patterns = new[]
53+
{
54+
conventions.Patterns.CompileRefAssemblies,
55+
conventions.Patterns.CompileLibAssemblies,
56+
conventions.Patterns.RuntimeAssemblies,
57+
conventions.Patterns.ContentFiles,
58+
conventions.Patterns.ResourceAssemblies,
59+
};
60+
61+
// Add MSBuild to this list, but we need to ensure we have package assets before they make the cut.
62+
// A series of files in the right places won't matter if there's no {id}.props|targets.
63+
var msbuildPatterns = new[]
64+
{
65+
conventions.Patterns.MSBuildFiles,
66+
conventions.Patterns.MSBuildMultiTargetingFiles,
67+
};
68+
69+
// We'll create a set of "groups" --these are content items which satisfy file pattern sets
70+
var standardGroups = patterns
71+
.SelectMany(p => items.FindItemGroups(p));
72+
73+
// Filter out MSBuild assets that don't match the package ID and append to groups we already have
74+
var msbuildGroups = msbuildPatterns
75+
.SelectMany(p => items.FindItemGroups(p))
76+
.Where(g => HasBuildItemsForPackageId(g.Items, packageId));
77+
groups = standardGroups.Concat(msbuildGroups);
78+
}
79+
80+
// Now that we have a collection of groups which have made it through the pattern set filter, let's transform them into TFMs
81+
supportedTFMs = groups
82+
.SelectMany(p => p.Properties)
83+
.Where(pair => pair.Key == ManagedCodeConventions.PropertyNames.TargetFrameworkMoniker)
84+
.Select(pair => pair.Value)
85+
.Cast<NuGetFramework>()
86+
.Distinct();
87+
}
88+
89+
return supportedTFMs;
90+
}
91+
92+
private static bool HasBuildItemsForPackageId(IEnumerable<ContentItem> items, string packageId)
93+
{
94+
foreach (var item in items)
95+
{
96+
var fileName = Path.GetFileName(item.Path);
97+
if (fileName == PackagingCoreConstants.EmptyFolder)
98+
{
99+
return true;
100+
}
101+
102+
if ($"{packageId}.props".Equals(fileName, StringComparison.OrdinalIgnoreCase))
103+
{
104+
return true;
105+
}
106+
107+
if ($"{packageId}.targets".Equals(fileName, StringComparison.OrdinalIgnoreCase))
108+
{
109+
return true;
110+
}
111+
}
112+
113+
return false;
114+
}
115+
}
116+
}

src/NuGetGallery.Services/PackageManagement/PackageService.cs

Lines changed: 3 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -712,104 +712,14 @@ public virtual IEnumerable<NuGetFramework> GetSupportedFrameworks(PackageArchive
712712
return package.GetSupportedFrameworks();
713713
}
714714

715-
/// <summary>
716-
/// This method combines the logic used in restore operations to make a determination about the TFM supported by the package.
717-
/// We have curated a set of compatibility requirements for our needs in NuGet.org. The client logic can be found here:
718-
/// https://github.com/NuGet/NuGet.Client/blob/63255047fe7052cc33b763356ff995d9166f719e/src/NuGet.Core/NuGet.Commands/RestoreCommand/CompatibilityChecker.cs#L252-L294
719-
/// https://github.com/NuGet/NuGet.Client/blob/63255047fe7052cc33b763356ff995d9166f719e/src/NuGet.Core/NuGet.Commands/RestoreCommand/CompatibilityChecker.cs#L439-L442
720-
/// ...and our combination of these elements is below.
721-
/// The logic is essentially this:
722-
/// - Determine whether we're looking at a tools package. In this case we will use tools "pattern sets" (collections of file patterns
723-
/// defined in <see cref="ManagedCodeConventions" />) to assess which frameworks are targeted by the package.
724-
/// - If this isn't a tools package, we look for build-time, runtime, content and resource file patterns
725-
/// For added details on the various cases, see unit tests targeting this method.
726-
/// </summary>
727715
public virtual IEnumerable<NuGetFramework> GetSupportedFrameworks(NuspecReader nuspecReader, IList<string> packageFiles)
728716
{
729-
var supportedTFMs = Enumerable.Empty<NuGetFramework>();
730-
if (packageFiles != null && packageFiles.Any() && nuspecReader != null)
731-
{
732-
// Setup content items for analysis
733-
var items = new ContentItemCollection();
734-
items.Load(packageFiles);
735-
var runtimeGraph = new RuntimeGraph();
736-
var conventions = new ManagedCodeConventions(runtimeGraph);
737-
738-
// Let's test for tools packages first--they're a special case
739-
var groups = Enumerable.Empty<ContentItemGroup>();
740-
var packageTypes = nuspecReader.GetPackageTypes();
741-
if (packageTypes.Count == 1 && (packageTypes[0] == PackageType.DotnetTool ||
742-
packageTypes[0] == PackageType.DotnetCliTool))
743-
{
744-
// Only a package that is a tool package (and nothing else) will be matched against tools pattern set
745-
groups = items.FindItemGroups(conventions.Patterns.ToolsAssemblies);
746-
}
747-
else
748-
{
749-
// Gather together a list of pattern sets indicating the kinds of packages we wish to evaluate
750-
var patterns = new[]
751-
{
752-
conventions.Patterns.CompileRefAssemblies,
753-
conventions.Patterns.CompileLibAssemblies,
754-
conventions.Patterns.RuntimeAssemblies,
755-
conventions.Patterns.ContentFiles,
756-
conventions.Patterns.ResourceAssemblies,
757-
};
758-
759-
// Add MSBuild to this list, but we need to ensure we have package assets before they make the cut.
760-
// A series of files in the right places won't matter if there's no {id}.props|targets.
761-
var msbuildPatterns = new[]
762-
{
763-
conventions.Patterns.MSBuildFiles,
764-
conventions.Patterns.MSBuildMultiTargetingFiles,
765-
};
766-
767-
// We'll create a set of "groups" --these are content items which satisfy file pattern sets
768-
var standardGroups = patterns
769-
.SelectMany(p => items.FindItemGroups(p));
770-
771-
// Filter out MSBuild assets that don't match the package ID and append to groups we already have
772-
var packageId = nuspecReader.GetId();
773-
var msbuildGroups = msbuildPatterns
774-
.SelectMany(p => items.FindItemGroups(p))
775-
.Where(g => HasBuildItemsForPackageId(g.Items, packageId));
776-
groups = standardGroups.Concat(msbuildGroups);
777-
}
778-
779-
// Now that we have a collection of groups which have made it through the pattern set filter, let's transform them into TFMs
780-
supportedTFMs = groups
781-
.SelectMany(p => p.Properties)
782-
.Where(pair => pair.Key == ManagedCodeConventions.PropertyNames.TargetFrameworkMoniker)
783-
.Select(pair => pair.Value)
784-
.Cast<NuGetFramework>()
785-
.Distinct();
786-
}
787-
788-
return supportedTFMs;
789-
}
790-
791-
private static bool HasBuildItemsForPackageId(IEnumerable<ContentItem> items, string packageId)
792-
{
793-
foreach (var item in items)
717+
if (nuspecReader != null)
794718
{
795-
var fileName = Path.GetFileName(item.Path);
796-
if (fileName == PackagingCoreConstants.EmptyFolder)
797-
{
798-
return true;
799-
}
800-
801-
if ($"{packageId}.props".Equals(fileName, StringComparison.OrdinalIgnoreCase))
802-
{
803-
return true;
804-
}
805-
806-
if ($"{packageId}.targets".Equals(fileName, StringComparison.OrdinalIgnoreCase))
807-
{
808-
return true;
809-
}
719+
return AssetFrameworkHelper.GetAssetFrameworks(nuspecReader.GetId(), nuspecReader.GetPackageTypes(), packageFiles);
810720
}
811721

812-
return false;
722+
return Enumerable.Empty<NuGetFramework>();
813723
}
814724

815725
private static EmbeddedLicenseFileType GetEmbeddedLicenseType(PackageMetadata packageMetadata)

0 commit comments

Comments
 (0)