| File: OverrideAndCreateBundledNETCoreAppPackageVersion.cs | Web Access |
| Project: src\sdk\src\Tasks\sdk-tasks\sdk-tasks.csproj (sdk-tasks) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable using NuGet.Frameworks; using NuGet.Versioning; namespace Microsoft.DotNet.Build.Tasks { /// <summary> /// For stage 2, we want use the version numbers from stage 0 for the downlevel .NET versions. This is because /// the latest patches of different major versions are built entirely separately, and we want to have tests /// on downlevel versions but we can't depend on the latest patches being available in test environments. /// /// So we copy the version numbers from stage 0 for those downlevel versions. /// /// However, if the stage 2 version is a preview version, we don't overwrite it. This is because in this case /// the version of .NET hasn't been released yet, so we want to use the later preview version. The preview /// versions should all be on the same NuGet feeds anyway. /// </summary> public sealed class OverrideAndCreateBundledNETCoreAppPackageVersion : Task { [Required] public string Stage0BundledVersionsPath { get; set; } [Required] public string Stage2BundledVersionsPath { get; set; } public override bool Execute() { try { var stage0Doc = XDocument.Load(Stage0BundledVersionsPath); var stage2Doc = XDocument.Load(Stage2BundledVersionsPath); var ns = stage2Doc.Root.Name.Namespace; // Load all items from all ItemGroups var items2 = stage2Doc.Root.Elements(ns + "ItemGroup").SelectMany(ig => ig.Elements()).ToList(); var items0 = stage0Doc.Root.Elements(ns + "ItemGroup").SelectMany(ig => ig.Elements()).ToList(); // Find latest TargetFramework using NuGetFramework var allTargetFrameworks = items2 .Select(e => e.Attribute("TargetFramework")?.Value) .Where(v => !string.IsNullOrEmpty(v)) .Distinct() .Select(tf => new { Raw = tf, Parsed = NuGetFramework.Parse(tf) }) .ToList(); var latest = allTargetFrameworks .OrderByDescending(tf => tf.Parsed.Version) .FirstOrDefault(); var latestTargetFramework = latest?.Raw; // Helper for matching and updating void UpdateItems(string elementName, string[] matchAttrs, string[] updateAttrs) { var items2Filtered = items2 .Where(e => e.Name.LocalName == elementName && e.Attribute("TargetFramework")?.Value != latestTargetFramework) .ToList(); foreach (var item2 in items2Filtered) { var matches0 = items0 .Where(e => e.Name.LocalName == elementName && matchAttrs.All(attr => (e.Attribute(attr)?.Value ?? "") == (item2.Attribute(attr)?.Value ?? ""))) .ToList(); if (matches0.Count == 0) { Log.LogError($"No matching {elementName} in stage 0 for: {string.Join(", ", matchAttrs.Select(a => $"{a}={item2.Attribute(a)?.Value}"))}"); continue; } if (matches0.Count > 1) { Log.LogError($"Multiple matches for {elementName} in stage 0 for: {string.Join(", ", matchAttrs.Select(a => $"{a}={item2.Attribute(a)?.Value}"))}"); continue; } var item0 = matches0[0]; foreach (var updateAttr in updateAttrs) { var v0 = item0.Attribute(updateAttr)?.Value; var v2 = item2.Attribute(updateAttr)?.Value; if (v0 != null && v2 != v0) { bool isPreview = false; if (!string.IsNullOrEmpty(v2)) { try { var nugetVersion = NuGetVersion.Parse(v2); isPreview = nugetVersion.IsPrerelease; } catch { // If parsing fails, treat as non-preview isPreview = false; } } if (!isPreview) { item2.SetAttributeValue(updateAttr, v0); } } } // Log if other metadata differs foreach (var attr in item2.Attributes()) { if (matchAttrs.Contains(attr.Name.LocalName) || updateAttrs.Contains(attr.Name.LocalName)) continue; var v0 = item0.Attribute(attr.Name)?.Value; if (v0 != null && v0 != attr.Value) Log.LogMessage(MessageImportance.Low, $"{elementName} {string.Join(", ", matchAttrs.Select(a => $"{a}={item2.Attribute(a)?.Value}"))}: Metadata '{attr.Name}' differs: stage0='{v0}', stage2='{attr.Value}'"); } } } UpdateItems("KnownFrameworkReference", new[] { "Include", "TargetFramework" }, new[] { "LatestRuntimeFrameworkVersion", "TargetingPackVersion" }); UpdateItems("KnownAppHostPack", new[] { "Include", "TargetFramework" }, new[] { "AppHostPackVersion" }); UpdateItems("KnownCrossgen2Pack", new[] { "Include", "TargetFramework" }, new[] { "Crossgen2PackVersion" }); UpdateItems("KnownILCompilerPack", new[] { "Include", "TargetFramework" }, new[] { "ILCompilerPackVersion" }); UpdateItems("KnownRuntimePack", new[] { "Include", "TargetFramework", "RuntimePackLabels" }, new[] { "LatestRuntimeFrameworkVersion" }); UpdateItems("KnownILLinkPack", new[] { "Include", "TargetFramework" }, new[] { "ILLinkPackVersion" }); stage2Doc.Save(Stage2BundledVersionsPath); return !Log.HasLoggedErrors; } catch (Exception ex) { Log.LogErrorFromException(ex, true); return false; } } } }