Skip to content

Commit 2d9bd91

Browse files
author
Daniel Jacinto
authored
[TFM Display] Add service that generates compatible frameworks. (#8869)
* added framework compatibility service. * Added documentation on service interface. * Update properties to be static. * null frameworks return exception instead. * Use latest NuGet.Frameworks client package and list of supported frameworks updated. * nit. * nit. * Removed on demand computing for unknown supported frameworks.
1 parent 69a02d8 commit 2d9bd91

7 files changed

Lines changed: 298 additions & 1 deletion

File tree

src/NuGet.Services.Entities/NuGet.Services.Entities.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<Version>10.0.3</Version>
1616
</PackageReference>
1717
<PackageReference Include="NuGet.Frameworks">
18-
<Version>5.9.0</Version>
18+
<Version>6.0.0</Version>
1919
</PackageReference>
2020
</ItemGroup>
2121

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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 NuGet.Frameworks;
7+
8+
namespace NuGetGallery.Frameworks
9+
{
10+
public class FrameworkCompatibilityService : IFrameworkCompatibilityService
11+
{
12+
private static readonly IFrameworkCompatibilityProvider CompatibilityProvider = DefaultCompatibilityProvider.Instance;
13+
private static readonly IReadOnlyList<NuGetFramework> AllSupportedFrameworks = SupportedFrameworks.AllSupportedNuGetFrameworks;
14+
private static readonly IReadOnlyDictionary<NuGetFramework, ISet<NuGetFramework>> CompatibilityMatrix = GetCompatibilityMatrix();
15+
16+
public ISet<NuGetFramework> GetCompatibleFrameworks(IEnumerable<NuGetFramework> packageFrameworks)
17+
{
18+
if (packageFrameworks == null)
19+
{
20+
throw new ArgumentNullException(nameof(packageFrameworks));
21+
}
22+
23+
var allCompatibleFrameworks = new HashSet<NuGetFramework>();
24+
25+
foreach (var packageFramework in packageFrameworks)
26+
{
27+
if (packageFrameworks == null || packageFramework.IsUnsupported || packageFramework.IsPCL)
28+
{
29+
continue;
30+
}
31+
32+
if (CompatibilityMatrix.TryGetValue(packageFramework, out var compatibleFrameworks))
33+
{
34+
allCompatibleFrameworks.UnionWith(compatibleFrameworks);
35+
}
36+
}
37+
38+
return allCompatibleFrameworks;
39+
}
40+
41+
private static IReadOnlyDictionary<NuGetFramework, ISet<NuGetFramework>> GetCompatibilityMatrix()
42+
{
43+
var matrix = new Dictionary<NuGetFramework, ISet<NuGetFramework>>();
44+
45+
foreach (var packageFramework in AllSupportedFrameworks)
46+
{
47+
var compatibleFrameworks = new HashSet<NuGetFramework>();
48+
matrix.Add(packageFramework, compatibleFrameworks);
49+
50+
foreach (var projectFramework in AllSupportedFrameworks)
51+
{
52+
// This compatibility check is to know if the packageFramework can be installed on a certain projectFramework
53+
if (CompatibilityProvider.IsCompatible(projectFramework, packageFramework))
54+
{
55+
compatibleFrameworks.Add(projectFramework);
56+
}
57+
}
58+
}
59+
60+
return matrix;
61+
}
62+
}
63+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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.Collections.Generic;
5+
using NuGet.Frameworks;
6+
7+
namespace NuGetGallery.Frameworks
8+
{
9+
public interface IFrameworkCompatibilityService
10+
{
11+
/// <summary>
12+
/// Computes a set of compatible target frameworks from a list of target frameworks.
13+
/// </summary>
14+
/// <param name="frameworks">List of frameworks.</param>
15+
/// <returns>A set of computed compatible target frameworks.</returns>
16+
/// <remarks>
17+
/// Every element on the returned set is compatible with at least one of the target frameworks from the input.
18+
/// </remarks>
19+
ISet<NuGetFramework> GetCompatibleFrameworks(IEnumerable<NuGetFramework> frameworks);
20+
}
21+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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 NuGet.Frameworks;
7+
using static NuGet.Frameworks.FrameworkConstants;
8+
using static NuGet.Frameworks.FrameworkConstants.CommonFrameworks;
9+
10+
namespace NuGetGallery.Frameworks
11+
{
12+
/// <summary>
13+
/// This class contains documented supported frameworks.
14+
/// </summary>
15+
/// <remarks>
16+
/// All these frameworks were retrieved from the following sources:
17+
/// dotnet documentation: https://docs.microsoft.com/en-us/dotnet/standard/frameworks.
18+
/// nuget documentation: https://docs.microsoft.com/en-us/nuget/reference/target-frameworks.
19+
/// nuget client FrameworkConstants.CommonFrameworks: https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Frameworks/FrameworkConstants.cs.
20+
/// </remarks>
21+
public static class SupportedFrameworks
22+
{
23+
public static readonly NuGetFramework MonoAndroid = new NuGetFramework(FrameworkIdentifiers.MonoAndroid, EmptyVersion);
24+
public static readonly NuGetFramework MonoTouch = new NuGetFramework(FrameworkIdentifiers.MonoTouch, EmptyVersion);
25+
public static readonly NuGetFramework MonoMac = new NuGetFramework(FrameworkIdentifiers.MonoMac, EmptyVersion);
26+
public static readonly NuGetFramework Net48 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 8, 0, 0));
27+
public static readonly NuGetFramework Net50Windows = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version5, "windows");
28+
public static readonly NuGetFramework Net60Android = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "android");
29+
public static readonly NuGetFramework Net60Ios = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "ios");
30+
public static readonly NuGetFramework Net60MacOs = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "macos");
31+
public static readonly NuGetFramework Net60MacCatalyst = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "maccatalyst");
32+
public static readonly NuGetFramework Net60Tizen = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "tizen");
33+
public static readonly NuGetFramework Net60TvOs = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "tvos");
34+
public static readonly NuGetFramework Net60Windows = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version6, "windows");
35+
public static readonly NuGetFramework NetCore = new NuGetFramework(FrameworkIdentifiers.NetCore, EmptyVersion);
36+
public static readonly NuGetFramework NetMf = new NuGetFramework(FrameworkIdentifiers.NetMicro, EmptyVersion);
37+
public static readonly NuGetFramework UAP = new NuGetFramework(FrameworkIdentifiers.UAP, EmptyVersion);
38+
public static readonly NuGetFramework Win = new NuGetFramework(FrameworkIdentifiers.Windows, EmptyVersion);
39+
public static readonly NuGetFramework WinRt = new NuGetFramework(FrameworkIdentifiers.WinRT, EmptyVersion);
40+
public static readonly NuGetFramework WP = new NuGetFramework(FrameworkIdentifiers.WindowsPhone, EmptyVersion);
41+
public static readonly NuGetFramework XamarinIOs = new NuGetFramework(FrameworkIdentifiers.XamarinIOs, EmptyVersion);
42+
public static readonly NuGetFramework XamarinMac = new NuGetFramework(FrameworkIdentifiers.XamarinMac, EmptyVersion);
43+
public static readonly NuGetFramework XamarinPlaystation3 = new NuGetFramework(FrameworkIdentifiers.XamarinPlayStation3, EmptyVersion);
44+
public static readonly NuGetFramework XamarinPlayStation4 = new NuGetFramework(FrameworkIdentifiers.XamarinPlayStation4, EmptyVersion);
45+
public static readonly NuGetFramework XamarinPlayStationVita = new NuGetFramework(FrameworkIdentifiers.XamarinPlayStationVita, EmptyVersion);
46+
public static readonly NuGetFramework XamarinTvOs = new NuGetFramework(FrameworkIdentifiers.XamarinTVOS, EmptyVersion);
47+
public static readonly NuGetFramework XamarinWatchOs = new NuGetFramework(FrameworkIdentifiers.XamarinWatchOS, EmptyVersion);
48+
public static readonly NuGetFramework XamarinXbox360 = new NuGetFramework(FrameworkIdentifiers.XamarinXbox360, EmptyVersion);
49+
public static readonly NuGetFramework XamarinXboxOne = new NuGetFramework(FrameworkIdentifiers.XamarinXboxOne, EmptyVersion);
50+
51+
public static readonly IReadOnlyList<NuGetFramework> AllSupportedNuGetFrameworks;
52+
53+
static SupportedFrameworks()
54+
{
55+
AllSupportedNuGetFrameworks = new List<NuGetFramework>
56+
{
57+
AspNet, AspNet50, AspNetCore, AspNetCore50,
58+
Dnx, Dnx45, Dnx451, Dnx452, DnxCore, DnxCore50,
59+
DotNet, DotNet50, DotNet51, DotNet52, DotNet53, DotNet54, DotNet55, DotNet56,
60+
MonoAndroid, MonoMac, MonoTouch,
61+
Native,
62+
Net11, Net2, Net35, Net4, Net403, Net45, Net451, Net452, Net46, Net461, Net462, Net463, Net47, Net471, Net472, Net48,
63+
Net50, Net50Windows, Net60, Net60Android, Net60Ios, Net60MacCatalyst, Net60MacOs, Net60TvOs, Net60Windows,
64+
NetCore, NetCore45, NetCore451, NetCore50,
65+
NetCoreApp10, NetCoreApp11, NetCoreApp20, NetCoreApp21, NetCoreApp22, NetCoreApp30, NetCoreApp31,
66+
NetMf,
67+
NetStandard, NetStandard10, NetStandard11, NetStandard12, NetStandard13, NetStandard14, NetStandard15, NetStandard16, NetStandard17, NetStandard20, NetStandard21,
68+
NetStandardApp15,
69+
SL4, SL5,
70+
Tizen3, Tizen4, Tizen6,
71+
UAP, UAP10,
72+
Win, Win8, Win81, Win10,
73+
WinRt,
74+
WP, WP7, WP75, WP8, WP81, WPA81,
75+
XamarinIOs, XamarinMac, XamarinPlaystation3, XamarinPlayStation4, XamarinPlayStationVita, XamarinTvOs, XamarinWatchOs, XamarinXbox360, XamarinXboxOne
76+
};
77+
}
78+
}
79+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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.Linq;
7+
using NuGet.Frameworks;
8+
using Xunit;
9+
10+
namespace NuGetGallery.Frameworks
11+
{
12+
public class FrameworkCompatibilityServiceFacts
13+
{
14+
private readonly IFrameworkCompatibilityService _service;
15+
private readonly IFrameworkCompatibilityProvider CompatibilityProvider = DefaultCompatibilityProvider.Instance;
16+
17+
public FrameworkCompatibilityServiceFacts()
18+
{
19+
_service = new FrameworkCompatibilityService();
20+
}
21+
22+
[Fact]
23+
public void NullPackageFrameworksThrowsArgumentNullException()
24+
{
25+
Assert.Throws<ArgumentNullException>(() => _service.GetCompatibleFrameworks(null));
26+
}
27+
28+
[Fact]
29+
public void EmptyPackageFrameworksReturnsEmptySet()
30+
{
31+
var result = _service.GetCompatibleFrameworks(new List<NuGetFramework>());
32+
33+
Assert.Equal(expected: 0, actual: result.Count);
34+
}
35+
36+
[Fact]
37+
public void UnknownSupportedPackageReturnsEmptySet()
38+
{
39+
var framework = NuGetFramework.Parse("netstandard9.2");
40+
var frameworks = new List<NuGetFramework>() { framework };
41+
var compatible = _service.GetCompatibleFrameworks(frameworks);
42+
43+
Assert.False(framework.IsUnsupported);
44+
Assert.Equal(expected: 0, compatible.Count);
45+
}
46+
47+
[Theory]
48+
[InlineData("1000")]
49+
[InlineData("lib")]
50+
[InlineData("nuget")]
51+
public void UnsupportedPackageFrameworksReturnsEmptySet(string unsupportedFrameworkName)
52+
{
53+
var unsupportedFramework = NuGetFramework.Parse(unsupportedFrameworkName);
54+
55+
var result = _service.GetCompatibleFrameworks(new List<NuGetFramework>() { unsupportedFramework });
56+
57+
Assert.True(unsupportedFramework.IsUnsupported);
58+
Assert.Equal(expected: 0, actual: result.Count);
59+
}
60+
61+
[Theory]
62+
[InlineData("portable-net45+sl4+win8+wp7")]
63+
[InlineData("portable-net40+sl4")]
64+
[InlineData("portable-net45+sl5+win8+wpa81+wp8")]
65+
public void PCLPackageFrameworksReturnsEmptySet(string pclFrameworkName)
66+
{
67+
var portableFramework = NuGetFramework.Parse(pclFrameworkName);
68+
69+
var result = _service.GetCompatibleFrameworks(new List<NuGetFramework>() { portableFramework });
70+
71+
Assert.True(portableFramework.IsPCL);
72+
Assert.Equal(expected: 0, actual: result.Count);
73+
}
74+
75+
[Theory]
76+
[InlineData("net5.0", "netcoreapp2.0", "win81")]
77+
[InlineData("sl4", "netstandard1.2", "netmf")]
78+
public void ValidPackageFrameworksReturnsFrameworksCompatibleForAtLeastOne(params string[] frameworkNames)
79+
{
80+
var frameworks = new List<NuGetFramework>();
81+
82+
foreach (var frameworkName in frameworkNames)
83+
{
84+
frameworks.Add(NuGetFramework.Parse(frameworkName));
85+
}
86+
87+
var compatibleFrameworks = _service.GetCompatibleFrameworks(frameworks);
88+
89+
Assert.True(compatibleFrameworks.Count > 0);
90+
91+
foreach (var compatibleFramework in compatibleFrameworks)
92+
{
93+
var isCompatible = frameworks.Any(f => CompatibilityProvider.IsCompatible(compatibleFramework, f));
94+
95+
Assert.True(isCompatible);
96+
}
97+
}
98+
}
99+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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 NuGet.Frameworks;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using Xunit;
8+
9+
namespace NuGetGallery.Frameworks
10+
{
11+
public class SupportedFrameworksFacts
12+
{
13+
[Fact]
14+
public void SupportedFrameworksContainsAllNuGetClientCommonFrameworks()
15+
{
16+
var fields = typeof(FrameworkConstants.CommonFrameworks)
17+
.GetFields()
18+
.Where(f => f.FieldType == typeof(NuGetFramework))
19+
.ToList();
20+
21+
Assert.True(fields.Count > 0);
22+
23+
var supportedFrameworks = new HashSet<NuGetFramework>(SupportedFrameworks.AllSupportedNuGetFrameworks);
24+
25+
foreach (var field in fields)
26+
{
27+
var framework = (NuGetFramework)field.GetValue(null);
28+
29+
Assert.True(supportedFrameworks.Contains(framework), $"SupportedFrameworks is missing {field.Name} constant from CommonFrameworks.");
30+
}
31+
}
32+
}
33+
}

tests/NuGetGallery.Core.Facts/NuGetGallery.Core.Facts.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
<Compile Include="Cookies\CookieExpirationServiceFacts.cs" />
8383
<Compile Include="Features\FeatureFlagClientExtensionsFacts.cs" />
8484
<Compile Include="Features\EditableFeatureFlagFileStorageServiceFacts.cs" />
85+
<Compile Include="Frameworks\FrameworkCompatibilityServiceFacts.cs" />
86+
<Compile Include="Frameworks\SupportedFrameworksFacts.cs" />
8587
<Compile Include="GitHub\GitHubUsageConfigurationFacts.cs" />
8688
<Compile Include="Infrastructure\ElmahExceptionFacts.cs" />
8789
<Compile Include="Extensions\UserExtensionsCoreFacts.cs" />

0 commit comments

Comments
 (0)