Skip to content

Commit dd54f2a

Browse files
committed
Copilot implementation of new logic for stage 2 bundled versions
Copilot prompt #1: Replace the #class:'Microsoft.DotNet.Build.Tasks.OverrideAndCreateBundledNETCoreAppPackageVersion':1164-10242 Task. The new version should take as parameters the path to the stage 0 bundled versions file as well as the version from stage 2. It should copy some version numbers from items in the stage 0 version to the stage 2 version, and then save the updated stage 2 version. It should update items where the TargetFramework metadata is not the latest target framework supported. There are multiple item types that need to be updated, and they need to be matched on specific metadata. KnownFrameworkReference: match on Include, TargetFramework metadata. Update LatestRuntimeFrameworkVersion and TargetingPackVersion KnownAppHostPack: match on Include, TargetFramework metadata. Update AppHostPackVersion KnownCrossgen2Pack: match on Include, TargetFramework. Update Crossgen2PackVersion KnownILCompilerPack: match on Include, TargetFramework. Update ILCompilerPackVersion KnownRuntimePack: match on Include, TargetFramework, RuntimePackLabels. Update LatestRuntimeFrameworkVersion KnownILLinkPack: match on Include, TargetFramework. Update ILLinkPackVersion. If there is more than one match based on the specified metadata, generate an error. For the metadata which is not used to match and is not updated, if the value differs between the stage 0 and stage 2 versions, log a message. Copilot prompt #2: Don't look at just the first ItemGroup in each file, load items from all ItemGroups found. When looking for the latest target framework, use the NuGetFramework class to parse the TargetFramework values, and to compare them.
1 parent 0bf81da commit dd54f2a

File tree

1 file changed

+76
-171
lines changed

1 file changed

+76
-171
lines changed

src/Tasks/sdk-tasks/OverrideAndCreateBundledNETCoreAppPackageVersion.cs

Lines changed: 76 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -9,196 +9,101 @@
99
using System.Xml.Linq;
1010
using Microsoft.Build.Framework;
1111
using Microsoft.Build.Utilities;
12-
using NuGet.Versioning;
12+
using System.Collections.Generic;
13+
using NuGet.Frameworks;
1314

1415
namespace Microsoft.DotNet.Build.Tasks
1516
{
1617
/// <summary>
17-
/// Use the runtime in dotnet/sdk instead of in the stage 0 to avoid circular dependency.
18-
/// If there is a change depended on the latest runtime. Without override the runtime version in BundledNETCoreAppPackageVersion
19-
/// we would need to somehow get this change in without the test, and then insertion dotnet/installer
20-
/// and then update the stage 0 back.
21-
///
22-
/// Override NETCoreSdkVersion to stage 0 sdk version like 6.0.100-dev
23-
/// Override NETCoreSdkRuntimeIdentifier and NETCoreSdkPortableRuntimeIdentifier to match the target RID
24-
///
25-
/// Use a task to override since it was generated as a string literal replace anyway.
26-
/// And using C# can have better error when anything goes wrong.
18+
/// Updates version numbers in the stage 2 bundled versions file by copying values from the stage 0 file
19+
/// for items where the TargetFramework is not the latest supported. Matches and updates multiple item types.
2720
/// </summary>
2821
public sealed class OverrideAndCreateBundledNETCoreAppPackageVersion : Task
2922
{
30-
private static string _messageWhenMismatch =
31-
"{0} version {1} does not match BundledNETCoreAppPackageVersion {2}. " +
32-
"The schema of https://github.com/dotnet/installer/blob/main/src/redist/targets/GenerateBundledVersions.targets might change. " +
33-
"We need to ensure we can swap the runtime version from what's in stage0 to what dotnet/sdk used successfully";
34-
35-
[Required] public string Stage0MicrosoftNETCoreAppRefPackageVersionPath { get; set; }
36-
37-
[Required] public string MicrosoftNETCoreAppRefPackageVersion { get; set; }
38-
39-
[Required] public string NewSDKVersion { get; set; }
40-
41-
[Required] public string TargetRid { get; set; }
42-
23+
[Required] public string Stage0BundledVersionsPath { get; set; }
24+
[Required] public string Stage2BundledVersionsPath { get; set; }
4325
[Required] public string OutputPath { get; set; }
4426

4527
public override bool Execute()
4628
{
47-
File.WriteAllText(OutputPath,
48-
ExecuteInternal(
49-
File.ReadAllText(Stage0MicrosoftNETCoreAppRefPackageVersionPath),
50-
MicrosoftNETCoreAppRefPackageVersion,
51-
NewSDKVersion,
52-
TargetRid,
53-
Log));
54-
return true;
55-
}
56-
57-
public static string ExecuteInternal(
58-
string stage0MicrosoftNETCoreAppRefPackageVersionContent,
59-
string microsoftNETCoreAppRefPackageVersion,
60-
string newSDKVersion,
61-
string targetRid,
62-
TaskLoggingHelper log)
63-
{
64-
var projectXml = XDocument.Parse(stage0MicrosoftNETCoreAppRefPackageVersionContent);
65-
66-
var ns = projectXml.Root.Name.Namespace;
67-
68-
var propertyGroup = projectXml.Root.Elements(ns + "PropertyGroup").First();
69-
70-
propertyGroup.Element(ns + "NETCoreSdkVersion").Value = newSDKVersion;
71-
propertyGroup.Element(ns + "NETCoreSdkRuntimeIdentifier").Value = targetRid;
72-
propertyGroup.Element(ns + "NETCoreSdkPortableRuntimeIdentifier").Value = targetRid;
73-
74-
75-
var originalBundledNETCoreAppPackageVersion = propertyGroup.Element(ns + "BundledNETCoreAppPackageVersion").Value;
76-
var parsedOriginalBundledPackageVersion = SemanticVersion.Parse(originalBundledNETCoreAppPackageVersion);
77-
var parsedMicrosoftNETCoreAppRefPackageVersion =
78-
SemanticVersion.Parse(microsoftNETCoreAppRefPackageVersion);
79-
80-
// In the case where we have a new major version, it'll come in first through the dotnet/runtime flow of the
81-
// SDK's own package references. The Stage0 SDK's bundled version props file will still be on the older major version
82-
// (and the older TFM that goes along with that). If we just replaced the bundled version with the new major version,
83-
// apps that target the 'older' TFM would fail to build. So we need to keep the bundled version from the existing
84-
// bundledversions.props in this one specific case.
85-
86-
var newBundledPackageVersion =
87-
parsedOriginalBundledPackageVersion.Major == parsedMicrosoftNETCoreAppRefPackageVersion.Major
88-
? microsoftNETCoreAppRefPackageVersion
89-
: originalBundledNETCoreAppPackageVersion;
90-
91-
propertyGroup.Element(ns + "BundledNETCoreAppPackageVersion").Value = newBundledPackageVersion;
92-
93-
var isNETServicing = IsNETServicing(originalBundledNETCoreAppPackageVersion);
94-
var currentTargetFramework = $"net{parsedMicrosoftNETCoreAppRefPackageVersion.Major}.0";
95-
96-
void CheckAndReplaceElement(XElement element)
29+
try
9730
{
98-
if (element.Value != originalBundledNETCoreAppPackageVersion)
31+
var stage0Doc = XDocument.Load(Stage0BundledVersionsPath);
32+
var stage2Doc = XDocument.Load(Stage2BundledVersionsPath);
33+
var ns = stage2Doc.Root.Name.Namespace;
34+
35+
// Load all items from all ItemGroups
36+
var items2 = stage2Doc.Root.Elements(ns + "ItemGroup").SelectMany(ig => ig.Elements()).ToList();
37+
var items0 = stage0Doc.Root.Elements(ns + "ItemGroup").SelectMany(ig => ig.Elements()).ToList();
38+
39+
// Find latest TargetFramework using NuGetFramework
40+
var allTargetFrameworks = items2
41+
.Select(e => e.Attribute("TargetFramework")?.Value)
42+
.Where(v => !string.IsNullOrEmpty(v))
43+
.Distinct()
44+
.Select(tf => new { Raw = tf, Parsed = NuGetFramework.Parse(tf) })
45+
.ToList();
46+
var latest = allTargetFrameworks
47+
.OrderByDescending(tf => tf.Parsed, NuGetFramework.Comparer)
48+
.FirstOrDefault();
49+
var latestTargetFramework = latest?.Raw;
50+
51+
// Helper for matching and updating
52+
void UpdateItems(string elementName, string[] matchAttrs, string[] updateAttrs)
9953
{
100-
throw new InvalidOperationException(string.Format(
101-
_messageWhenMismatch,
102-
element.ToString(), element.Value, originalBundledNETCoreAppPackageVersion));
54+
var items2Filtered = items2
55+
.Where(e => e.Name.LocalName == elementName && e.Attribute("TargetFramework")?.Value != latestTargetFramework)
56+
.ToList();
57+
foreach (var item2 in items2Filtered)
58+
{
59+
var matches0 = items0
60+
.Where(e => e.Name.LocalName == elementName && matchAttrs.All(attr => (e.Attribute(attr)?.Value ?? "") == (item2.Attribute(attr)?.Value ?? "")))
61+
.ToList();
62+
if (matches0.Count == 0)
63+
{
64+
Log.LogError($"No matching {elementName} in stage 0 for: {string.Join(", ", matchAttrs.Select(a => $"{a}={item2.Attribute(a)?.Value}"))}");
65+
continue;
66+
}
67+
if (matches0.Count > 1)
68+
{
69+
Log.LogError($"Multiple matches for {elementName} in stage 0 for: {string.Join(", ", matchAttrs.Select(a => $"{a}={item2.Attribute(a)?.Value}"))}");
70+
continue;
71+
}
72+
var item0 = matches0[0];
73+
foreach (var updateAttr in updateAttrs)
74+
{
75+
var v0 = item0.Attribute(updateAttr)?.Value;
76+
var v2 = item2.Attribute(updateAttr)?.Value;
77+
if (v0 != null && v2 != v0)
78+
item2.SetAttributeValue(updateAttr, v0);
79+
}
80+
// Log if other metadata differs
81+
foreach (var attr in item2.Attributes())
82+
{
83+
if (matchAttrs.Contains(attr.Name.LocalName) || updateAttrs.Contains(attr.Name.LocalName))
84+
continue;
85+
var v0 = item0.Attribute(attr.Name)?.Value;
86+
if (v0 != null && v0 != attr.Value)
87+
Log.LogMessage(MessageImportance.Low, $"{elementName} {string.Join(", ", matchAttrs.Select(a => $"{a}={item2.Attribute(a)?.Value}"))}: Metadata '{attr.Name}' differs: stage0='{v0}', stage2='{attr.Value}'");
88+
}
89+
}
10390
}
10491

105-
log.LogMessage(MessageImportance.High,
106-
$"Replacing element {element.Name} value '{element.Value}' with '{newBundledPackageVersion}'");
107-
element.Value = newBundledPackageVersion;
108-
}
92+
UpdateItems("KnownFrameworkReference", new[] { "Include", "TargetFramework" }, new[] { "LatestRuntimeFrameworkVersion", "TargetingPackVersion" });
93+
UpdateItems("KnownAppHostPack", new[] { "Include", "TargetFramework" }, new[] { "AppHostPackVersion" });
94+
UpdateItems("KnownCrossgen2Pack", new[] { "Include", "TargetFramework" }, new[] { "Crossgen2PackVersion" });
95+
UpdateItems("KnownILCompilerPack", new[] { "Include", "TargetFramework" }, new[] { "ILCompilerPackVersion" });
96+
UpdateItems("KnownRuntimePack", new[] { "Include", "TargetFramework", "RuntimePackLabels" }, new[] { "LatestRuntimeFrameworkVersion" });
97+
UpdateItems("KnownILLinkPack", new[] { "Include", "TargetFramework" }, new[] { "ILLinkPackVersion" });
10998

110-
void CheckAndReplaceAttribute(XAttribute attribute)
111-
{
112-
if (attribute.Value != originalBundledNETCoreAppPackageVersion)
113-
{
114-
throw new InvalidOperationException(string.Format(
115-
_messageWhenMismatch,
116-
attribute.Parent.ToString() + " --- " + attribute.ToString(), attribute.Value,
117-
originalBundledNETCoreAppPackageVersion));
118-
}
119-
120-
log.LogMessage(MessageImportance.High,
121-
$"Replacing attribute {attribute.Name} value '{attribute.Value}' with '{newBundledPackageVersion}' in element {attribute.Parent.Name}");
122-
attribute.Value = newBundledPackageVersion;
99+
stage2Doc.Save(OutputPath);
100+
return !Log.HasLoggedErrors;
123101
}
124-
125-
if (!isNETServicing)
102+
catch (Exception ex)
126103
{
127-
CheckAndReplaceElement(propertyGroup.Element(ns + "BundledNETCorePlatformsPackageVersion"));
104+
Log.LogErrorFromException(ex, true);
105+
return false;
128106
}
129-
130-
var itemGroup = projectXml.Root.Elements(ns + "ItemGroup").First();
131-
132-
if (!isNETServicing)
133-
{
134-
foreach (var element in itemGroup.Elements(ns + "KnownFrameworkReference")
135-
.Where(e => e.Attribute("TargetFramework")?.Value == currentTargetFramework))
136-
{
137-
CheckAndReplaceAttribute(element.Attribute("DefaultRuntimeFrameworkVersion"));
138-
CheckAndReplaceAttribute(element.Attribute("TargetingPackVersion"));
139-
}
140-
}
141-
142-
foreach (var element in itemGroup.Elements(ns + "KnownFrameworkReference")
143-
.Where(e => e.Attribute("TargetFramework")?.Value == currentTargetFramework))
144-
{
145-
CheckAndReplaceAttribute(element.Attribute("LatestRuntimeFrameworkVersion"));
146-
}
147-
foreach (var element in itemGroup.Elements(ns + "KnownAppHostPack")
148-
.Where(e => e.Attribute("TargetFramework")?.Value == currentTargetFramework))
149-
{
150-
CheckAndReplaceAttribute(element.Attribute("AppHostPackVersion"));
151-
}
152-
153-
foreach (var element in itemGroup.Elements(ns + "KnownCrossgen2Pack")
154-
.Where(e => e.Attribute("TargetFramework")?.Value == currentTargetFramework))
155-
{
156-
CheckAndReplaceAttribute(element.Attribute("Crossgen2PackVersion"));
157-
}
158-
159-
foreach (var element in itemGroup.Elements(ns + "KnownILCompilerPack")
160-
.Where(e => e.Attribute("TargetFramework")?.Value == currentTargetFramework))
161-
{
162-
CheckAndReplaceAttribute(element.Attribute("ILCompilerPackVersion"));
163-
}
164-
165-
foreach (var element in itemGroup.Elements(ns + "KnownILLinkPack")
166-
.Where(e => e.Attribute("TargetFramework")?.Value == currentTargetFramework))
167-
{
168-
CheckAndReplaceAttribute(element.Attribute("ILLinkPackVersion"));
169-
}
170-
171-
// web assembly packs always use the latest regardless of the TFM
172-
foreach (var element in itemGroup.Elements(ns + "KnownWebAssemblySdkPack"))
173-
{
174-
CheckAndReplaceAttribute(element.Attribute("WebAssemblySdkPackVersion"));
175-
}
176-
177-
foreach (var element in itemGroup.Elements(ns + "KnownAspNetCorePack")
178-
.Where(e => e.Attribute("TargetFramework")?.Value == currentTargetFramework))
179-
{
180-
CheckAndReplaceAttribute(element.Attribute("AspNetCorePackVersion"));
181-
}
182-
183-
foreach (var element in itemGroup.Elements(ns + "KnownRuntimePack")
184-
.Where(e => e.Attribute("TargetFramework")?.Value == currentTargetFramework))
185-
{
186-
CheckAndReplaceAttribute(element.Attribute("LatestRuntimeFrameworkVersion"));
187-
}
188-
189-
return projectXml.ToString();
190-
}
191-
192-
/// <summary>
193-
/// For SDK servicing, few Attributes like "DefaultRuntimeFrameworkVersion" does not use the latest flowed version
194-
/// so there is no need to replace them.
195-
/// </summary>
196-
/// <returns></returns>
197-
private static bool IsNETServicing(string netVersion)
198-
{
199-
var parsedSdkVersion = NuGet.Versioning.NuGetVersion.Parse(netVersion);
200-
201-
return !parsedSdkVersion.IsPrerelease;
202107
}
203108
}
204109
}

0 commit comments

Comments
 (0)