Skip to content

Commit 3f689dd

Browse files
authored
Fix framework expansion and add .NET 10 moniker (#482)
1 parent a2a48cf commit 3f689dd

8 files changed

+118
-132
lines changed

PackageIndexer/CsvUtils.cs

+81-75
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ namespace PackageIndexer;
66

77
internal class CsvUtils
88
{
9+
Dictionary<string, IList<CsvEntry>> _csvDictionary = [];
10+
Dictionary<string, int> _packageCounter = []; // Used for "pac" number in CSV file.
11+
912
static readonly Dictionary<string, string> s_tfmToOpsMoniker = new()
1013
{
1114
{ "net462", "netframework-4.6.2-pp" },
@@ -18,32 +21,35 @@ internal class CsvUtils
1821
{ "net7.0", "net-7.0-pp" },
1922
{ "net8.0", "net-8.0-pp" },
2023
{ "net9.0", "net-9.0-pp" },
24+
{ "net10.0", "net-10.0-pp" },
2125
{ "netstandard2.0", "netstandard-2.0-pp" },
2226
{ "netstandard2.1", "netstandard-2.1-pp" }
2327
};
2428

25-
internal static void GenerateCSVFiles(string indexPackagesPath, string csvPath)
29+
internal CsvUtils()
30+
{
31+
// Initialize the two dictionaries.
32+
foreach (string moniker in s_tfmToOpsMoniker.Values)
33+
{
34+
_csvDictionary.Add(moniker, []);
35+
_packageCounter.Add(moniker, 1);
36+
}
37+
}
38+
39+
internal void GenerateCSVFiles(string indexPackagesPath, string csvPath)
2640
{
2741
Console.WriteLine("Generating CSV files from package index.");
2842

2943
// For each package XML file
3044
// For each framework
3145
// Map it to a known framework name
32-
// Generate a collection of that version + later versions of that framework
33-
// (e.g. add 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1 for net462; add 7.0, 8.0, 9.0 for net6.0)
46+
// Generate a collection of that version + compatible versions (e.g. also add to net9.0 moniker for net8.0 assets,
47+
// *if* net9.0 isn't already explicitly targeted).
3448
// Create a dictionary or add to an existing dictionary *for that version* that will become the CSV file -
3549
// pac<num>,[tfm=<tfm>;includeXml=false]<package name>,<package version>
3650
// Example: pac01,[tfm=net9.0;includeXml=false]Microsoft.Extensions.Caching.Abstractions,9.0.0-preview.2.24128.5
3751
// Generate a CSV file from each dictionary
3852

39-
Dictionary<string, IList<CsvEntry>> csvDictionary = [];
40-
Dictionary<string, int> packageCounter = []; // Used for "pac" number in CSV file.
41-
foreach (string moniker in s_tfmToOpsMoniker.Values)
42-
{
43-
csvDictionary.Add(moniker, []);
44-
packageCounter.Add(moniker, 1);
45-
}
46-
4753
// Get all XML files (ignores disabled indexes).
4854
IEnumerable<string> packageIndexFiles = Directory.EnumerateFiles(indexPackagesPath, "*.xml");
4955
foreach (string packageIndexFile in packageIndexFiles)
@@ -54,69 +60,69 @@ internal static void GenerateCSVFiles(string indexPackagesPath, string csvPath)
5460
Console.WriteLine($"Creating CSV entries for package {packageEntry.Name}.");
5561

5662
// Add to each applicable CSV file.
57-
foreach (FrameworkEntry frameworkEntry in packageEntry.FrameworkEntries)
63+
foreach (string targetFramework in packageEntry.Frameworks)
5864
{
59-
string framework = frameworkEntry.FrameworkName;
6065
string opsMoniker;
61-
switch (framework)
66+
string? fellThroughFromVersion = null;
67+
switch (targetFramework)
6268
{
69+
case "net6.0":
70+
opsMoniker = s_tfmToOpsMoniker["net6.0"];
71+
AddCsvEntryToDict(opsMoniker, packageEntry, "net6.0");
72+
if (!packageEntry.Frameworks.Contains("net7.0"))
73+
{
74+
// Add to net7.0 moniker since this is a compatible framework.
75+
fellThroughFromVersion = "net6.0";
76+
goto case "net7.0";
77+
}
78+
break;
79+
case "net7.0":
80+
opsMoniker = s_tfmToOpsMoniker["net7.0"];
81+
AddCsvEntryToDict(opsMoniker, packageEntry, fellThroughFromVersion ?? "net7.0");
82+
if (!packageEntry.Frameworks.Contains("net8.0"))
83+
{
84+
// Add to net8.0 moniker since this is a compatible framework.
85+
fellThroughFromVersion = fellThroughFromVersion ?? "net7.0";
86+
goto case "net8.0";
87+
}
88+
break;
89+
case "net8.0":
90+
opsMoniker = s_tfmToOpsMoniker["net8.0"];
91+
AddCsvEntryToDict(opsMoniker, packageEntry, fellThroughFromVersion ?? "net8.0");
92+
if (!packageEntry.Frameworks.Contains("net9.0"))
93+
{
94+
// Add to net9.0 moniker since this is a compatible framework.
95+
fellThroughFromVersion = fellThroughFromVersion ?? "net8.0";
96+
goto case "net9.0";
97+
}
98+
break;
99+
case "net9.0":
100+
opsMoniker = s_tfmToOpsMoniker["net9.0"];
101+
AddCsvEntryToDict(opsMoniker, packageEntry, fellThroughFromVersion ?? "net9.0");
102+
if (!packageEntry.Frameworks.Contains("net10.0"))
103+
{
104+
// Add to net10.0 moniker since this is a compatible framework.
105+
fellThroughFromVersion = fellThroughFromVersion ?? "net9.0";
106+
goto case "net10.0";
107+
}
108+
break;
109+
case "net10.0":
110+
opsMoniker = s_tfmToOpsMoniker["net10.0"];
111+
AddCsvEntryToDict(opsMoniker, packageEntry, fellThroughFromVersion ?? "net10.0");
112+
break;
63113
case "net462":
64-
framework = "net462";
65-
opsMoniker = s_tfmToOpsMoniker[framework];
66-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
67-
goto case "net47";
68114
case "net47":
69-
framework = "net47";
70-
opsMoniker = s_tfmToOpsMoniker[framework];
71-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
72-
goto case "net471";
73115
case "net471":
74-
framework = "net471";
75-
opsMoniker = s_tfmToOpsMoniker[framework];
76-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
77-
goto case "net472";
78116
case "net472":
79-
framework = "net472";
80-
opsMoniker = s_tfmToOpsMoniker[framework];
81-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
82-
goto case "net48";
83117
case "net48":
84-
framework = "net48";
85-
opsMoniker = s_tfmToOpsMoniker[framework];
86-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
87-
goto case "net481";
88118
case "net481":
89-
framework = "net481";
90-
opsMoniker = s_tfmToOpsMoniker[framework];
91-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
92-
break;
93-
case "net6.0":
94-
framework = "net6.0";
95-
opsMoniker = s_tfmToOpsMoniker[framework];
96-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
97-
goto case "net7.0";
98-
case "net7.0":
99-
framework = "net7.0";
100-
opsMoniker = s_tfmToOpsMoniker[framework];
101-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
102-
goto case "net8.0";
103-
case "net8.0":
104-
framework = "net8.0";
105-
opsMoniker = s_tfmToOpsMoniker[framework];
106-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
107-
goto case "net9.0";
108-
case "net9.0":
109-
framework = "net9.0";
110-
opsMoniker = s_tfmToOpsMoniker[framework];
111-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
112-
break;
113119
case "netstandard2.0":
114120
case "netstandard2.1":
115-
opsMoniker = s_tfmToOpsMoniker[framework];
116-
AddCsvEntryToDict(opsMoniker, csvDictionary, packageCounter, packageEntry, framework);
121+
opsMoniker = s_tfmToOpsMoniker[targetFramework];
122+
AddCsvEntryToDict(opsMoniker, packageEntry, targetFramework);
117123
break;
118124
default:
119-
Console.WriteLine($"Ignoring target framework {framework}.");
125+
Console.WriteLine($"Ignoring target framework {targetFramework}.");
120126
break;
121127
}
122128
}
@@ -125,7 +131,7 @@ internal static void GenerateCSVFiles(string indexPackagesPath, string csvPath)
125131
// Create the directory.
126132
Directory.CreateDirectory(csvPath);
127133

128-
foreach (KeyValuePair<string, IList<CsvEntry>> tfm in csvDictionary)
134+
foreach (KeyValuePair<string, IList<CsvEntry>> tfm in _csvDictionary)
129135
{
130136
// CSV file names must match the folder name in the "binaries" repo:
131137
// e.g. netframework-4.6.2-pp, netstandard-2.0-pp, net-8.0-pp.
@@ -148,12 +154,10 @@ internal static void GenerateCSVFiles(string indexPackagesPath, string csvPath)
148154
csv.WriteRecords(tfm.Value);
149155
}
150156

151-
static void AddCsvEntryToDict(
157+
void AddCsvEntryToDict(
152158
string opsMoniker,
153-
Dictionary<string, IList<CsvEntry>> csvDictionary,
154-
Dictionary<string, int> packageCounter,
155159
PackageEntry packageEntry,
156-
string frameworkName
160+
string targetFramework
157161
)
158162
{
159163
// Special case for packages from dotnet/extensions repo - include XML files.
@@ -166,29 +170,31 @@ string frameworkName
166170
bool includeXml = reposToIncludeXmlComments.Contains(packageEntry.Repository);
167171

168172
// Except don't include XML file for Microsoft.Extensions.Diagnostics.ResourceMonitoring
169-
// See https://github.com/dotnet/dotnet-api-docs/pull/10395#discussion_r1758128787.
170-
if (string.Equals(
171-
packageEntry.Name,
172-
"Microsoft.Extensions.Diagnostics.ResourceMonitoring",
173-
StringComparison.InvariantCultureIgnoreCase))
173+
// (see https://github.com/dotnet/dotnet-api-docs/pull/10395#discussion_r1758128787)
174+
// or Microsoft.Extensions.HttpClient.SocketHandling (deprecated package with docs that cause warnings).
175+
if (string.Equals(packageEntry.Name, "Microsoft.Extensions.Diagnostics.ResourceMonitoring", StringComparison.InvariantCultureIgnoreCase) ||
176+
string.Equals(packageEntry.Name, "Microsoft.Extensions.Diagnostics.ResourceMonitoring", StringComparison.InvariantCultureIgnoreCase))
177+
{
174178
includeXml = false;
179+
}
175180

176181
// Special case for newer assemblies - include XML documentation files.
177182
if (PlatformPackageDefinition.PackagesWithTruthDocs.Contains(packageEntry.Name))
178183
includeXml = true;
179184

180-
string squareBrackets = $"[tfm={frameworkName};includeXml={includeXml}]";
185+
string squareBrackets = $"[tfm={targetFramework};includeXml={includeXml}]";
181186

182187
// Special case for System.ServiceModel.Primitives - use reference assemblies.
183188
if (string.Equals(packageEntry.Name, "System.ServiceModel.Primitives", StringComparison.InvariantCultureIgnoreCase))
184-
squareBrackets = $"[tfm={frameworkName};includeXml={includeXml};libpath=ref]";
189+
squareBrackets = $"[tfm={targetFramework};includeXml={includeXml};libpath=ref]";
185190

186191
CsvEntry entry = CsvEntry.Create(
187-
string.Concat("pac", packageCounter[opsMoniker]++),
192+
string.Concat("pac", _packageCounter[opsMoniker]++),
188193
string.Concat(squareBrackets, packageEntry.Name),
189194
packageEntry.Version
190195
);
191-
csvDictionary[opsMoniker].Add(entry);
196+
197+
_csvDictionary[opsMoniker].Add(entry);
192198
}
193199
}
194200
}

PackageIndexer/DotnetPackageIndex.cs

+20-20
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ await Parallel.ForEachAsync(packageIds, async (packageId, _) =>
119119
return identities.ToArray();
120120
}
121121

122+
// Only includes the latest version
122123
private static IReadOnlyList<PackageIdentity> GetLatestVersions(
123124
IReadOnlyList<(PackageIdentity packageId, bool isDeprecated)> identities,
124125
bool usePreviewVersions
@@ -146,33 +147,32 @@ bool usePreviewVersions
146147
if (latestPrerelease.isDeprecated)
147148
latestPrerelease = default;
148149

149-
// If the latest stable version is newer than the latest
150-
// prerelease version, don't include the prerelease version.
151-
if (latestStable != default && latestPrerelease != default)
152-
{
153-
bool stableIsNewer = VersionComparer.VersionReleaseMetadata.Compare(
154-
latestPrerelease.packageId.Version,
155-
latestStable.packageId.Version
156-
) <= 0;
157-
if (stableIsNewer)
158-
latestPrerelease = default;
159-
}
160-
161-
// Comment this out for preview-only versions.
162-
if (latestStable != default)
150+
if (!usePreviewVersions && latestStable != default)
163151
{
164152
result.Add(latestStable.packageId);
153+
continue;
165154
}
166155

167156
if (usePreviewVersions)
168157
{
169-
// TODO - this seems clunky.
170-
// Make sure it's a .NET 10 preview version.
171-
if (latestPrerelease != default &&
172-
(latestPrerelease.packageId.Version.Major == 10 ||
173-
// Special case for major version (9) of Microsoft.Extensions.AI*.
174-
latestPrerelease.packageId.Id.StartsWith("Microsoft.Extensions.AI")))
158+
// Use whichever version (stable or prerelease) is newer.
159+
if (latestStable != default && latestPrerelease != default)
160+
{
161+
bool stableIsNewer = VersionComparer.VersionReleaseMetadata.Compare(
162+
latestPrerelease.packageId.Version,
163+
latestStable.packageId.Version
164+
) <= 0;
165+
166+
if (stableIsNewer)
167+
result.Add(latestStable.packageId);
168+
else
169+
result.Add(latestPrerelease.packageId);
170+
}
171+
else if (latestStable != default)
172+
result.Add(latestStable.packageId);
173+
else if (latestPrerelease != default)
175174
result.Add(latestPrerelease.packageId);
175+
// else don't add the package at all.
176176
}
177177
}
178178

PackageIndexer/FrameworkEntry.cs

-21
This file was deleted.

PackageIndexer/PackageEntry.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@
22

33
public sealed class PackageEntry
44
{
5-
public static PackageEntry Create(string id, string version, string repo, IList<FrameworkEntry> entries)
5+
public static PackageEntry Create(string id, string version, string repo, IList<string> frameworks)
66
{
7-
return new PackageEntry(id, version, repo, entries);
7+
return new PackageEntry(id, version, repo, frameworks);
88
}
99

10-
private PackageEntry(string id, string version, string repo, IList<FrameworkEntry> entries)
10+
private PackageEntry(string id, string version, string repo, IList<string> frameworks)
1111
{
1212
Name = id;
1313
Version = version;
1414
Repository = repo;
15-
FrameworkEntries = entries;
15+
Frameworks = frameworks;
1616
}
1717

1818
//public Guid Fingerprint { get; }
1919
public string Name { get; }
2020
public string Version { get; }
2121
public string Repository { get; }
22-
public IList<FrameworkEntry> FrameworkEntries { get; }
22+
public IList<string> Frameworks { get; }
2323

2424
public void Write(Stream stream)
2525
{

PackageIndexer/PackageIndexer.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public async Task<PackageEntry> Index(string id, string version)
1111
{
1212
string repo;
1313
var dependencies = new Dictionary<string, PackageArchiveReader>();
14-
var frameworkEntries = new List<FrameworkEntry>();
14+
var frameworkEntries = new List<string>();
1515
try
1616
{
1717
using (PackageArchiveReader root = await _store.GetPackageAsync(id, version))
@@ -30,7 +30,7 @@ public async Task<PackageEntry> Index(string id, string version)
3030

3131
foreach (NuGetFramework target in targets)
3232
{
33-
frameworkEntries.Add(FrameworkEntry.Create(target.GetShortFolderName()));
33+
frameworkEntries.Add(target.GetShortFolderName());
3434
}
3535
}
3636

PackageIndexer/PackageIndexer.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<OutputType>Exe</OutputType>
55
<TargetFramework>net8.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
7-
<Nullable>disable</Nullable>
7+
<Nullable>enable</Nullable>
88
</PropertyGroup>
99

1010
<ItemGroup>

0 commit comments

Comments
 (0)