diff --git a/Directory.Packages.props b/Directory.Packages.props
index 2fc29d442726..a6af2f4d1bbe 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -114,7 +114,7 @@
-
+
diff --git a/dnup.slnf b/dnup.slnf
index 8384b13f95f0..ba550e59653e 100644
--- a/dnup.slnf
+++ b/dnup.slnf
@@ -5,7 +5,7 @@
"src\\Installer\\dnup\\dnup.csproj",
"src\\Installer\\Microsoft.Dotnet.Installation\\Microsoft.Dotnet.Installation.csproj",
"test\\dnup.Tests\\dnup.Tests.csproj",
- "src\\Resolvers\\Microsoft.DotNet.NativeWrapper\\Microsoft.DotNet.NativeWrapper.csproj
+ "src\\Resolvers\\Microsoft.DotNet.NativeWrapper\\Microsoft.DotNet.NativeWrapper.csproj"
]
}
}
diff --git a/src/Installer/Microsoft.Dotnet.Installation/IDotnetReleaseInfoProvider.cs b/src/Installer/Microsoft.Dotnet.Installation/IDotnetReleaseInfoProvider.cs
index 92571c2e4c8f..ff48a53e5660 100644
--- a/src/Installer/Microsoft.Dotnet.Installation/IDotnetReleaseInfoProvider.cs
+++ b/src/Installer/Microsoft.Dotnet.Installation/IDotnetReleaseInfoProvider.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Dotnet.Installation;
public interface IDotnetReleaseInfoProvider
{
- IEnumerable GetAvailableChannels();
+ IEnumerable GetSupportedChannels();
ReleaseVersion? GetLatestVersion(InstallComponent component, string channel);
diff --git a/src/Installer/Microsoft.Dotnet.Installation/Internal/DotnetReleaseInfoProvider.cs b/src/Installer/Microsoft.Dotnet.Installation/Internal/DotnetReleaseInfoProvider.cs
index 168bcb95f063..17d444209285 100644
--- a/src/Installer/Microsoft.Dotnet.Installation/Internal/DotnetReleaseInfoProvider.cs
+++ b/src/Installer/Microsoft.Dotnet.Installation/Internal/DotnetReleaseInfoProvider.cs
@@ -10,7 +10,11 @@ namespace Microsoft.Dotnet.Installation.Internal;
internal class DotnetReleaseInfoProvider : IDotnetReleaseInfoProvider
{
- public IEnumerable GetAvailableChannels() => throw new NotImplementedException();
+ public IEnumerable GetSupportedChannels()
+ {
+ var releaseManifest = new ReleaseManifest();
+ return releaseManifest.GetSupportedChannels();
+ }
public ReleaseVersion? GetLatestVersion(InstallComponent component, string channel)
{
var releaseManifest = new ReleaseManifest();
diff --git a/src/Installer/Microsoft.Dotnet.Installation/Internal/ReleaseManifest.cs b/src/Installer/Microsoft.Dotnet.Installation/Internal/ReleaseManifest.cs
index 243e49da0766..85de5895bc2e 100644
--- a/src/Installer/Microsoft.Dotnet.Installation/Internal/ReleaseManifest.cs
+++ b/src/Installer/Microsoft.Dotnet.Installation/Internal/ReleaseManifest.cs
@@ -7,6 +7,7 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
+using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
@@ -53,6 +54,31 @@ internal class ReleaseManifest(HttpClient httpClient) : IDisposable
return (major, minor, featureBand, isFullySpecified);
}
+ public IEnumerable GetSupportedChannels()
+ {
+
+ return ["latest", "preview", "lts", "sts",
+ ..GetProductCollection()
+ .Where(p => p.IsSupported)
+ .OrderByDescending(p => p.LatestReleaseVersion)
+ .SelectMany(GetChannelsForProduct)
+ ];
+
+ static IEnumerable GetChannelsForProduct(Product product)
+ {
+ return [product.ProductVersion,
+ ..product.GetReleasesAsync().GetAwaiter().GetResult()
+ .SelectMany(r => r.Sdks)
+ .Select(sdk => sdk.Version)
+ .OrderByDescending(v => v)
+ .Select(v => $"{v.Major}.{v.Minor}.{(v.Patch / 100)}xx")
+ .Distinct()
+ .ToList()
+ ];
+ }
+
+ }
+
///
/// Finds the latest fully specified version for a given channel string (major, major.minor, or feature band).
///
@@ -64,17 +90,17 @@ internal class ReleaseManifest(HttpClient httpClient) : IDisposable
if (string.Equals(channel.Name, "lts", StringComparison.OrdinalIgnoreCase) || string.Equals(channel.Name, "sts", StringComparison.OrdinalIgnoreCase))
{
var releaseType = string.Equals(channel.Name, "lts", StringComparison.OrdinalIgnoreCase) ? ReleaseType.LTS : ReleaseType.STS;
- var productIndex = ProductCollection.GetAsync().GetAwaiter().GetResult();
+ var productIndex = GetProductCollection();
return GetLatestVersionByReleaseType(productIndex, releaseType, component);
}
else if (string.Equals(channel.Name, "preview", StringComparison.OrdinalIgnoreCase))
{
- var productIndex = ProductCollection.GetAsync().GetAwaiter().GetResult();
+ var productIndex = GetProductCollection();
return GetLatestPreviewVersion(productIndex, component);
}
else if (string.Equals(channel.Name, "latest", StringComparison.OrdinalIgnoreCase))
{
- var productIndex = ProductCollection.GetAsync().GetAwaiter().GetResult();
+ var productIndex = GetProductCollection();
return GetLatestActiveVersion(productIndex, component);
}
@@ -93,7 +119,7 @@ internal class ReleaseManifest(HttpClient httpClient) : IDisposable
}
// Load the index manifest
- var index = ProductCollection.GetAsync().GetAwaiter().GetResult();
+ var index = GetProductCollection();
if (minor < 0)
{
return GetLatestVersionForMajorOrMajorMinor(index, major, component); // Major Only (e.g., "9")
diff --git a/src/Installer/dnup/Commands/Sdk/Install/EnvironmentVariableMockDotnetInstaller.cs b/src/Installer/dnup/Commands/Sdk/Install/EnvironmentVariableMockDotnetInstaller.cs
deleted file mode 100644
index 37fc7435c741..000000000000
--- a/src/Installer/dnup/Commands/Sdk/Install/EnvironmentVariableMockDotnetInstaller.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net.Http;
-using System.Threading;
-using Microsoft.Dotnet.Installation.Internal;
-using Microsoft.DotNet.Tools.Bootstrapper.Commands.Sdk.Install;
-using Spectre.Console;
-
-using SpectreAnsiConsole = Spectre.Console.AnsiConsole;
-
-namespace Microsoft.DotNet.Tools.Bootstrapper.Commands.Sdk.Install
-{
- internal class EnvironmentVariableMockDotnetInstaller : IDotnetInstallManager
- {
- public GlobalJsonInfo GetGlobalJsonInfo(string initialDirectory)
- {
- return new GlobalJsonInfo
- {
- GlobalJsonPath = Environment.GetEnvironmentVariable("DOTNET_TESTHOOK_GLOBALJSON_PATH"),
- GlobalJsonContents = null // Set to null for test mock; update as needed for tests
- };
- }
-
- public string GetDefaultDotnetInstallPath()
- {
- return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "dotnet");
- }
-
- public DotnetInstallRootConfiguration? GetConfiguredInstallType()
- {
- var testHookDefaultInstall = Environment.GetEnvironmentVariable("DOTNET_TESTHOOK_DEFAULT_INSTALL");
- InstallType installtype;
- if (!Enum.TryParse(testHookDefaultInstall, out installtype))
- {
- return null;
- }
- var installPath = Environment.GetEnvironmentVariable("DOTNET_TESTHOOK_CURRENT_INSTALL_PATH") ?? GetDefaultDotnetInstallPath();
- return new(new(installPath, InstallerUtilities.GetDefaultInstallArchitecture()), installtype, true, true);
- }
-
- public string? GetLatestInstalledAdminVersion()
- {
- var latestAdminVersion = Environment.GetEnvironmentVariable("DOTNET_TESTHOOK_LATEST_ADMIN_VERSION");
- if (string.IsNullOrEmpty(latestAdminVersion))
- {
- latestAdminVersion = "10.0.0-preview.7";
- }
- return latestAdminVersion;
- }
-
- public void InstallSdks(DotnetInstallRoot dotnetRoot, ProgressContext progressContext, IEnumerable sdkVersions)
- {
- using (var httpClient = new HttpClient())
- {
- List downloads = sdkVersions.Select(version =>
- {
- string downloadLink = "https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.303/dotnet-sdk-9.0.303-win-x64.exe";
- var task = progressContext.AddTask($"Downloading .NET SDK {version}");
- return (Action)(() =>
- {
- Download(downloadLink, httpClient, task);
- });
- }).ToList();
-
- foreach (var download in downloads)
- {
- download();
- }
- }
- }
-
- void Download(string url, HttpClient httpClient, ProgressTask task)
- {
- for (int i = 0; i < 100; i++)
- {
- task.Increment(1);
- Thread.Sleep(20); // Simulate some work
- }
- task.Value = 100;
- }
-
- public void UpdateGlobalJson(string globalJsonPath, string? sdkVersion = null, bool? allowPrerelease = null, string? rollForward = null)
- {
- SpectreAnsiConsole.WriteLine($"Updating {globalJsonPath} to SDK version {sdkVersion} (AllowPrerelease={allowPrerelease}, RollForward={rollForward})");
- }
- public void ConfigureInstallType(InstallType installType, string? dotnetRoot = null)
- {
- SpectreAnsiConsole.WriteLine($"Configuring install type to {installType} (dotnetRoot={dotnetRoot})");
- }
- }
-}
diff --git a/src/Installer/dnup/Commands/Sdk/Install/EnvironmentVariableMockReleaseInfoProvider.cs b/src/Installer/dnup/Commands/Sdk/Install/EnvironmentVariableMockReleaseInfoProvider.cs
deleted file mode 100644
index 78a2b9a819dd..000000000000
--- a/src/Installer/dnup/Commands/Sdk/Install/EnvironmentVariableMockReleaseInfoProvider.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.Deployment.DotNet.Releases;
-using Microsoft.DotNet.Tools.Bootstrapper.Commands.Sdk.Install;
-
-namespace Microsoft.DotNet.Tools.Bootstrapper.Commands.Sdk.Install
-{
- internal class EnvironmentVariableMockReleaseInfoProvider : IDotnetReleaseInfoProvider
- {
- IEnumerable IDotnetReleaseInfoProvider.GetAvailableChannels()
- {
- var channels = Environment.GetEnvironmentVariable("DOTNET_TESTHOOK_AVAILABLE_CHANNELS");
- if (string.IsNullOrEmpty(channels))
- {
- return new List { "latest", "preview", "10", "10.0.1xx", "10.0.2xx", "9", "9.0.3xx", "9.0.2xx", "9.0.1xx" };
- }
- return channels.Split(',').ToList();
- }
- public ReleaseVersion GetLatestVersion(InstallComponent component, string channel)
- {
- if (component != InstallComponent.SDK)
- {
- throw new NotImplementedException("Only SDK component is supported in this mock provider");
- }
-
- string version;
- if (channel == "preview")
- {
- version = "11.0.100-preview.1.42424";
- }
- else if (channel == "latest" || channel == "10" || channel == "10.0.2xx")
- {
- version = "10.0.0-preview.7";
- }
- else if (channel == "10.0.1xx")
- {
- version = "10.0.106";
- }
- else if (channel == "9" || channel == "9.0.3xx")
- {
- version = "9.0.309";
- }
- else if (channel == "9.0.2xx")
- {
- version = "9.0.212";
- }
- else if (channel == "9.0.1xx")
- {
- version = "9.0.115";
- }
-
- version = channel;
-
- return new ReleaseVersion(version);
- }
-
- public SupportType GetSupportType(InstallComponent component, ReleaseVersion version) => throw new NotImplementedException();
-
- }
-}
diff --git a/src/Installer/dnup/Commands/Sdk/Install/SdkInstallCommand.cs b/src/Installer/dnup/Commands/Sdk/Install/SdkInstallCommand.cs
index 89957ad9106d..af4493136621 100644
--- a/src/Installer/dnup/Commands/Sdk/Install/SdkInstallCommand.cs
+++ b/src/Installer/dnup/Commands/Sdk/Install/SdkInstallCommand.cs
@@ -23,7 +23,7 @@ internal class SdkInstallCommand(ParseResult result) : CommandBase(result)
private readonly bool _noProgress = result.GetValue(SdkInstallCommandParser.NoProgressOption);
private readonly IDotnetInstallManager _dotnetInstaller = new DotnetInstallManager();
- private readonly IDotnetReleaseInfoProvider _releaseInfoProvider = new EnvironmentVariableMockReleaseInfoProvider();
+ private readonly IDotnetReleaseInfoProvider _releaseInfoProvider = new DotnetReleaseInfoProvider();
private readonly ManifestChannelVersionResolver _channelVersionResolver = new ManifestChannelVersionResolver();
public override int Execute()
@@ -113,7 +113,7 @@ public override int Execute()
if (_interactive)
{
- SpectreAnsiConsole.WriteLine("Available supported channels: " + string.Join(' ', _releaseInfoProvider.GetAvailableChannels()));
+ SpectreAnsiConsole.WriteLine("Available supported channels: " + string.Join(' ', _releaseInfoProvider.GetSupportedChannels()));
SpectreAnsiConsole.WriteLine("You can also specify a specific version (for example 9.0.304).");
resolvedChannel = SpectreAnsiConsole.Prompt(
diff --git a/src/Installer/dnup/IDotnetInstallManager.cs b/src/Installer/dnup/IDotnetInstallManager.cs
index 4b8c742dbb7c..b665d056d57f 100644
--- a/src/Installer/dnup/IDotnetInstallManager.cs
+++ b/src/Installer/dnup/IDotnetInstallManager.cs
@@ -43,7 +43,14 @@ public class GlobalJsonInfo
public string? SdkVersion => GlobalJsonContents?.Sdk?.Version;
public bool? AllowPrerelease => GlobalJsonContents?.Sdk?.AllowPrerelease;
public string? RollForward => GlobalJsonContents?.Sdk?.RollForward;
- public string? SdkPath => (GlobalJsonContents?.Sdk?.Paths is not null && GlobalJsonContents.Sdk.Paths.Length > 0) ? GlobalJsonContents.Sdk.Paths[0] : null;
+ public string? SdkPath
+ {
+ get
+ {
+ return (GlobalJsonContents?.Sdk?.Paths is not null && GlobalJsonContents.Sdk.Paths.Length > 0) ?
+ Path.GetFullPath(GlobalJsonContents.Sdk.Paths[0], GlobalJsonPath!) : null;
+ }
+ }
}
public record DotnetInstallRootConfiguration(
diff --git a/src/Installer/dnup/dnup.csproj b/src/Installer/dnup/dnup.csproj
index a272529118cb..52537eba9131 100644
--- a/src/Installer/dnup/dnup.csproj
+++ b/src/Installer/dnup/dnup.csproj
@@ -6,6 +6,7 @@
enable
enable
true
+ false
$(NoWarn);CS8002
diff --git a/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs b/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs
index 678577e9053f..6c900028af10 100644
--- a/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs
+++ b/src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs
@@ -33,7 +33,7 @@ static Interop()
// construction so that subsequent P/Invokes can find it.
private static void PreloadWindowsLibrary(string dllFileName)
{
- string? basePath = Path.GetDirectoryName(typeof(Interop).Assembly.Location);
+ string? basePath = AppContext.BaseDirectory;
string architecture = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant();
string dllPath = Path.Combine(basePath ?? string.Empty, architecture, $"{dllFileName}.dll");
diff --git a/src/Resolvers/Microsoft.DotNet.NativeWrapper/Microsoft.DotNet.NativeWrapper.csproj b/src/Resolvers/Microsoft.DotNet.NativeWrapper/Microsoft.DotNet.NativeWrapper.csproj
index f39d5b24e2c2..b700520b359b 100644
--- a/src/Resolvers/Microsoft.DotNet.NativeWrapper/Microsoft.DotNet.NativeWrapper.csproj
+++ b/src/Resolvers/Microsoft.DotNet.NativeWrapper/Microsoft.DotNet.NativeWrapper.csproj
@@ -2,6 +2,7 @@
$(ResolverTargetFramework);net472
+ true
diff --git a/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETEnvironmentInfo.cs b/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETEnvironmentInfo.cs
index e294a7d59b55..90045bdf6ab0 100644
--- a/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETEnvironmentInfo.cs
+++ b/src/Resolvers/Microsoft.DotNet.NativeWrapper/NETEnvironmentInfo.cs
@@ -66,7 +66,7 @@ internal void Initialize(IntPtr info, IntPtr resultContext)
var runtimes = new hostfxr_dotnet_environment_framework_info[infoStruct.framework_count];
for (var i = 0; i < (int)infoStruct.framework_count; i++)
{
- var pointer = new IntPtr(infoStruct.frameworks.ToInt64() + i * Marshal.SizeOf(typeof(hostfxr_dotnet_environment_framework_info)));
+ var pointer = new IntPtr(infoStruct.frameworks.ToInt64() + i * Marshal.SizeOf());
runtimes[i] = Marshal.PtrToStructure(pointer);
}
RuntimeInfo = runtimes.Select(runtime => new NetRuntimeInfo(runtime.name, runtime.version, runtime.path));
@@ -74,7 +74,7 @@ internal void Initialize(IntPtr info, IntPtr resultContext)
var sdks = new hostfxr_dotnet_environment_sdk_info[infoStruct.sdk_count];
for (var i = 0; i < (int)infoStruct.sdk_count; i++)
{
- var pointer = new IntPtr(infoStruct.sdks.ToInt64() + i * Marshal.SizeOf(typeof(hostfxr_dotnet_environment_sdk_info)));
+ var pointer = new IntPtr(infoStruct.sdks.ToInt64() + i * Marshal.SizeOf());
sdks[i] = Marshal.PtrToStructure(pointer);
}
SdkInfo = sdks.Select(sdk => new NetSdkInfo(sdk.version, sdk.path));
diff --git a/test/UnitTests.proj b/test/UnitTests.proj
index 6c396845af1d..e8e0f8969d56 100644
--- a/test/UnitTests.proj
+++ b/test/UnitTests.proj
@@ -16,7 +16,7 @@
-
+
net472
diff --git a/test/dnup.Tests/LibraryTests.cs b/test/dnup.Tests/LibraryTests.cs
index 217116c0c1eb..098df5619c4c 100644
--- a/test/dnup.Tests/LibraryTests.cs
+++ b/test/dnup.Tests/LibraryTests.cs
@@ -22,6 +22,9 @@ public LibraryTests(ITestOutputHelper log)
[Theory]
[InlineData("9")]
[InlineData("latest")]
+ [InlineData("sts")]
+ [InlineData("lts")]
+ [InlineData("preview")]
public void LatestVersionForChannelCanBeInstalled(string channel)
{
var releaseInfoProvider = InstallerFactory.CreateReleaseInfoProvider();
@@ -40,4 +43,21 @@ public void LatestVersionForChannelCanBeInstalled(string channel)
InstallComponent.SDK,
latestVersion!);
}
+
+ [Fact]
+ public void TestGetSupportedChannels()
+ {
+ var releaseInfoProvider = InstallerFactory.CreateReleaseInfoProvider();
+ var channels = releaseInfoProvider.GetSupportedChannels();
+
+ channels.Should().Contain(new[] { "latest", "lts", "sts", "preview" });
+
+ // This will need to be updated every few years as versions go out of support
+ channels.Should().Contain(new[] { "10.0", "10.0.1xx" });
+ channels.Should().NotContain("10");
+
+ channels.Should().NotContain("7.0");
+ channels.Should().NotContain("7.0.1xx");
+
+ }
}