From d17fe1be76d2140e4b8de43fe7be60fcc23dbe18 Mon Sep 17 00:00:00 2001 From: Matt Galbraith Date: Thu, 9 Sep 2021 08:04:27 -0700 Subject: [PATCH] Use ProductVersion.txt where possible (#7837) (#7861) * Add ProductVersion.txt support where possible; get the version of the inner package from productVersion.txt, NOT from the specified version. Allows "non-stable" outer container with "stable" inner contents https://github.com/dotnet/arcade/issues/7836 --- .../Sdk/FindDotNetCliPackage.cs | 75 +++++++++++++++++-- .../Sdk/Microsoft.DotNet.Helix.Sdk.csproj | 1 + 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.DotNet.Helix/Sdk/FindDotNetCliPackage.cs b/src/Microsoft.DotNet.Helix/Sdk/FindDotNetCliPackage.cs index 5d82a45f509..1e00efe249b 100644 --- a/src/Microsoft.DotNet.Helix/Sdk/FindDotNetCliPackage.cs +++ b/src/Microsoft.DotNet.Helix/Sdk/FindDotNetCliPackage.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.Build.Framework; +using NuGet.Versioning; namespace Microsoft.DotNet.Helix.Sdk { @@ -30,7 +31,7 @@ public class FindDotNetCliPackage : BaseTask public string Runtime { get; set; } /// - /// 'sdk', 'runtime' or 'aspnetcore-runtime' + /// 'sdk', 'runtime' or 'aspnetcore-runtime' (default is runtime) /// [Required] public string PackageType { get; set; } @@ -49,7 +50,7 @@ private async Task ExecuteAsync() NormalizeParameters(); await ResolveVersionAsync(); - string downloadUrl = GetDownloadUrl(); + string downloadUrl = await GetDownloadUrlAsync(); Log.LogMessage($"Retrieved dotnet cli {PackageType} version {Version} package uri {downloadUrl}, testing..."); @@ -80,17 +81,75 @@ private async Task ExecuteAsync() } } - private string GetDownloadUrl() + private async Task GetDownloadUrlAsync() { string extension = Runtime.StartsWith("win") ? "zip" : "tar.gz"; + string effectiveVersion = await GetEffectiveVersion(); + return PackageType switch { - "sdk" => $"{DotNetCliAzureFeed}/Sdk/{Version}/dotnet-sdk-{Version}-{Runtime}.{extension}", - "aspnetcore-runtime" => $"{DotNetCliAzureFeed}/aspnetcore/Runtime/{Version}/aspnetcore-runtime-{Version}-{Runtime}.{extension}", - _ => $"{DotNetCliAzureFeed}/Runtime/{Version}/dotnet-runtime-{Version}-{Runtime}.{extension}" + "sdk" => $"{DotNetCliAzureFeed}/Sdk/{Version}/dotnet-sdk-{effectiveVersion}-{Runtime}.{extension}", + "aspnetcore-runtime" => $"{DotNetCliAzureFeed}/aspnetcore/Runtime/{Version}/aspnetcore-runtime-{effectiveVersion}-{Runtime}.{extension}", + _ => $"{DotNetCliAzureFeed}/Runtime/{Version}/dotnet-runtime-{effectiveVersion}-{Runtime}.{extension}" }; } + private async Task GetEffectiveVersion() + { + if (NuGetVersion.TryParse(Version, out NuGetVersion semanticVersion)) + { + // Pared down version of the logic from https://github.com/dotnet/install-scripts/blob/main/src/dotnet-install.ps1 + // If this functionality stops working, review changes made there. + // Current strategy is to start with a runtime-specific name then fall back to 'productVersion.txt' + string effectiveVersion = Version; + + // Do nothing for older runtimes; the file won't exist + if (semanticVersion >= new NuGetVersion("5.0.0")) + { + var productVersionText = PackageType switch + { + "sdk" => await GetMatchingProductVersionTxtContents($"{DotNetCliAzureFeed}/Sdk/{Version}", "sdk-productVersion.txt"), + "aspnetcore-runtime" => await GetMatchingProductVersionTxtContents($"{DotNetCliAzureFeed}/aspnetcore/Runtime/{Version}", "aspnetcore-productVersion.txt"), + _ => await GetMatchingProductVersionTxtContents($"{DotNetCliAzureFeed}/Runtime/{Version}", "runtime-productVersion.txt") + }; + + if (!productVersionText.Equals(Version)) + { + effectiveVersion = productVersionText; + Log.LogMessage($"Switched to effective .NET Core version '{productVersionText}' from matching productVersion.txt"); + } + } + return effectiveVersion; + } + else + { + throw new ArgumentException($"'{Version}' is not a valid semantic version."); + } + } + private async Task GetMatchingProductVersionTxtContents(string baseUri, string customVersionTextFileName) + { + using HttpResponseMessage specificResponse = await _client.GetAsync($"{baseUri}/{customVersionTextFileName}"); + if (specificResponse.StatusCode == HttpStatusCode.NotFound) + { + using HttpResponseMessage genericResponse = await _client.GetAsync($"{baseUri}/productVersion.txt"); + if (genericResponse.StatusCode != HttpStatusCode.NotFound) + { + genericResponse.EnsureSuccessStatusCode(); + return (await genericResponse.Content.ReadAsStringAsync()).Trim(); + } + else + { + Log.LogMessage(MessageImportance.Low, $"No *productVersion.txt files found for {Version} under {baseUri}"); + } + } + else + { + specificResponse.EnsureSuccessStatusCode(); + return (await specificResponse.Content.ReadAsStringAsync()).Trim(); + } + return Version; + } + private void NormalizeParameters() { if (string.Equals(Channel, "lts", StringComparison.OrdinalIgnoreCase)) @@ -136,9 +195,9 @@ private async Task ResolveVersionAsync() Log.LogMessage(MessageImportance.Low, "Resolving latest dotnet cli version."); string latestVersionUrl = PackageType switch { - "sdk" => $"{DotNetCliAzureFeed}/Sdk/{Channel}/latest.version", + "sdk" => $"{DotNetCliAzureFeed}/Sdk/{Channel}/latest.version", "aspnetcore-runtime" => $"{DotNetCliAzureFeed}/aspnetcore/Runtime/{Channel}/latest.version", - _ => $"{DotNetCliAzureFeed}/Runtime/{Channel}/latest.version" + _ => $"{DotNetCliAzureFeed}/Runtime/{Channel}/latest.version" }; Log.LogMessage(MessageImportance.Low, $"Resolving latest version from url {latestVersionUrl}"); diff --git a/src/Microsoft.DotNet.Helix/Sdk/Microsoft.DotNet.Helix.Sdk.csproj b/src/Microsoft.DotNet.Helix/Sdk/Microsoft.DotNet.Helix.Sdk.csproj index 2e510066ae4..7c4a029a946 100644 --- a/src/Microsoft.DotNet.Helix/Sdk/Microsoft.DotNet.Helix.Sdk.csproj +++ b/src/Microsoft.DotNet.Helix/Sdk/Microsoft.DotNet.Helix.Sdk.csproj @@ -12,6 +12,7 @@ +