From 0fbc96c951f6eb00cbabcce2158050922e44a0a2 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 17 Jul 2026 15:57:37 -0400 Subject: [PATCH 1/4] Change return of GetCurrentPathConfiguration Specify whether the active path is the dotnetup managed hive rather than whether it is a system-installed path --- .../Commands/Dotnet/DotnetCommand.cs | 2 +- .../Commands/Init/InitWorkflows.cs | 5 ++- .../Commands/Shared/InstallWorkflow.cs | 2 +- .../Commands/Shared/UninstallWorkflow.cs | 6 ++- .../DotnetEnvironmentManager.cs | 14 ++++--- .../IDotnetEnvironmentManager.cs | 7 +++- test/dotnetup.Tests/DotnetCommandTests.cs | 15 +++---- test/dotnetup.Tests/UninstallWorkflowTests.cs | 41 +++++++++++++------ 8 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/Installer/dotnetup.Library/Commands/Dotnet/DotnetCommand.cs b/src/Installer/dotnetup.Library/Commands/Dotnet/DotnetCommand.cs index e1cf25e7c053..52d982141c04 100644 --- a/src/Installer/dotnetup.Library/Commands/Dotnet/DotnetCommand.cs +++ b/src/Installer/dotnetup.Library/Commands/Dotnet/DotnetCommand.cs @@ -65,7 +65,7 @@ protected override void ExecuteCore() private string ResolveDotnetPath() { var configuredRoot = _dotnetEnvironment.GetCurrentPathConfiguration(); - if (configuredRoot is not null && configuredRoot.InstallType == InstallType.User) + if (configuredRoot is { IsDotnetupHive: true }) { return configuredRoot.Path; } diff --git a/src/Installer/dotnetup.Library/Commands/Init/InitWorkflows.cs b/src/Installer/dotnetup.Library/Commands/Init/InitWorkflows.cs index 67bc5ee3b2f4..0f32ea6d2504 100644 --- a/src/Installer/dotnetup.Library/Commands/Init/InitWorkflows.cs +++ b/src/Installer/dotnetup.Library/Commands/Init/InitWorkflows.cs @@ -446,9 +446,10 @@ internal static List FormatMigrationDisplayItems(List /// Resolves the install path for uninstall using the same logic as the install command: - /// only use the configured path if it's a user install, otherwise fall back to default. + /// only use the configured path if it is a dotnetup-managed hive, otherwise fall back to + /// default. This prevents uninstall from targeting a dotnet that dotnetup does not own (e.g. + /// a system install or a hand-extracted dotnet that happens to win on PATH). /// internal static string ResolveInstallPath(string? explicitInstallPath, IDotnetEnvironmentManager dotnetEnvironment) { @@ -165,7 +167,7 @@ internal static string ResolveInstallPath(string? explicitInstallPath, IDotnetEn } var configuredInstall = dotnetEnvironment.GetCurrentPathConfiguration(); - if (configuredInstall is { InstallType: InstallType.User }) + if (configuredInstall is { IsDotnetupHive: true }) { return configuredInstall.Path; } diff --git a/src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs b/src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs index 7df86a37fa97..0d381a82111f 100644 --- a/src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs +++ b/src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs @@ -43,11 +43,15 @@ public DotnetEnvironmentManager() ResolveCurrentInstallRootPath(foundDotnet), InstallerUtilities.GetDefaultInstallArchitecture()); - // Classify the resolved dotnet by location. InstallPathClassifier.IsAdminInstallPath is the - // canonical "is this a system/admin-managed install?" check (Program Files on Windows; the - // standard /usr and /opt locations on Unix) used across dotnetup, so both platforms share it. - bool isAdminInstall = InstallPathClassifier.IsAdminInstallPath(currentInstallRoot.Path); - return new(currentInstallRoot, isAdminInstall ? InstallType.System : InstallType.User); + // Report whether the resolved dotnet is a dotnetup-managed hive — an install dotnetup owns + // and may run or uninstall from — rather than classifying it as "system vs user". A dotnet + // that merely lives in a user-writable location (e.g. a hand-extracted C:\dotnet on PATH) is + // NOT dotnetup's and must not be treated as such. Today the only supported hive is the + // default install path; configurable hives are tracked in + // https://github.com/dotnet/sdk/issues/55346, at which point this check would also consult + // the persisted root. + bool isDotnetupHive = DotnetupUtilities.PathsEqual(currentInstallRoot.Path, GetDefaultDotnetInstallPath()); + return new(currentInstallRoot, isDotnetupHive); } public string GetDefaultDotnetInstallPath() diff --git a/src/Installer/dotnetup.Library/IDotnetEnvironmentManager.cs b/src/Installer/dotnetup.Library/IDotnetEnvironmentManager.cs index 051daa11575e..bac21685a2f6 100644 --- a/src/Installer/dotnetup.Library/IDotnetEnvironmentManager.cs +++ b/src/Installer/dotnetup.Library/IDotnetEnvironmentManager.cs @@ -16,6 +16,11 @@ internal interface IDotnetEnvironmentManager { string GetDefaultDotnetInstallPath(); + /// + /// Resolves the dotnet that currently wins on PATH and reports whether it is a + /// dotnetup-managed hive (i.e. an install dotnetup owns and may run or uninstall from). + /// Returns null when no dotnet is found on PATH. + /// DotnetInstallRootConfiguration? GetCurrentPathConfiguration(); string? GetLatestInstalledSystemVersion(); @@ -75,7 +80,7 @@ public string? SdkPath public record DotnetInstallRootConfiguration( DotnetInstallRoot InstallRoot, - InstallType InstallType) + bool IsDotnetupHive) { public string Path => InstallRoot.Path; } diff --git a/test/dotnetup.Tests/DotnetCommandTests.cs b/test/dotnetup.Tests/DotnetCommandTests.cs index ac4c299cb10e..3fb74371e4bf 100644 --- a/test/dotnetup.Tests/DotnetCommandTests.cs +++ b/test/dotnetup.Tests/DotnetCommandTests.cs @@ -150,9 +150,9 @@ public void DotnetCommand_WhenDotnetFound_RunsProcess() } [TestMethod] - public void DotnetCommand_UsesConfiguredInstallType_WhenUserInstall() + public void DotnetCommand_UsesConfiguredPath_WhenDotnetupHive() { - // Arrange - two paths: a configured user install path and a default path + // Arrange - two paths: a configured dotnetup hive path and a default path var userDir = Directory.CreateTempSubdirectory("dotnetup-user-test"); var defaultDir = Directory.CreateTempSubdirectory("dotnetup-default-test"); try @@ -164,13 +164,13 @@ public void DotnetCommand_UsesConfiguredInstallType_WhenUserInstall() defaultInstallPath: defaultDir.FullName, configuredRoot: new DotnetInstallRootConfiguration( new DotnetInstallRoot(userDir.FullName, InstallArchitecture.x64), - InstallType.User)); + IsDotnetupHive: true)); var parseResult = Parser.Parse(["dotnet", "--version"]); var command = new TestableDotnetCommand(parseResult, mock); var exitCode = command.Execute(); - // Should succeed because it used the configured user path, not the default + // Should succeed because it used the configured hive path, not the default exitCode.Should().Be(0); } finally @@ -206,9 +206,10 @@ public void DotnetCommand_FallsBackToDefault_WhenNoConfiguredInstall() } [TestMethod] - public void DotnetCommand_FallsBackToDefault_WhenAdminInstall() + public void DotnetCommand_FallsBackToDefault_WhenNotDotnetupHive() { - // Arrange - configured install is Admin, not User; should fall back to default + // Arrange - configured install is not a dotnetup hive (e.g. an admin or loose install); + // should fall back to default var adminDir = Directory.CreateTempSubdirectory("dotnetup-admin-test"); var defaultDir = Directory.CreateTempSubdirectory("dotnetup-default-test"); try @@ -220,7 +221,7 @@ public void DotnetCommand_FallsBackToDefault_WhenAdminInstall() defaultInstallPath: defaultDir.FullName, configuredRoot: new DotnetInstallRootConfiguration( new DotnetInstallRoot(adminDir.FullName, InstallArchitecture.x64), - InstallType.System)); + IsDotnetupHive: false)); var parseResult = Parser.Parse(["dotnet", "--version"]); var command = new TestableDotnetCommand(parseResult, mock); diff --git a/test/dotnetup.Tests/UninstallWorkflowTests.cs b/test/dotnetup.Tests/UninstallWorkflowTests.cs index 5c2226247439..5e534a0f0a72 100644 --- a/test/dotnetup.Tests/UninstallWorkflowTests.cs +++ b/test/dotnetup.Tests/UninstallWorkflowTests.cs @@ -20,8 +20,8 @@ public class UninstallWorkflowTests /// /// When no explicit path is provided and dotnet on PATH resolves to an admin install, - /// the uninstall should fall back to the default user install path — not the admin path. - /// Regression test: previously, GetConfiguredInstallType().Path was used unconditionally, + /// the uninstall should fall back to the default hive — not the admin path. + /// Regression test: previously, the configured path was used unconditionally, /// causing uninstall to target "C:\Program Files\dotnet" when the user meant their user install. /// [TestMethod] @@ -29,27 +29,44 @@ public void ResolveInstallPath_AdminInstall_FallsBackToDefault() { var mock = new MockDotnetInstallManager( defaultInstallPath: DefaultUserPath, - configuredRoot: CreateConfig(AdminPath, InstallType.System)); + configuredRoot: CreateConfig(AdminPath, isDotnetupHive: false)); var result = UninstallWorkflow.ResolveInstallPath(null, mock); - result.Should().Be(DefaultUserPath, "system installs on PATH should not be used; default user path should be used instead"); + result.Should().Be(DefaultUserPath, "installs on PATH that dotnetup does not own should not be used; default hive should be used instead"); } /// - /// When dotnet on PATH resolves to a user install, the uninstall should use that path. + /// When dotnet on PATH resolves to the dotnetup-managed hive, the uninstall should use that path. /// [TestMethod] - public void ResolveInstallPath_UserInstall_UsesConfiguredPath() + public void ResolveInstallPath_DotnetupHive_UsesConfiguredPath() { - string userPath = "/home/user/custom-dotnet"; var mock = new MockDotnetInstallManager( defaultInstallPath: DefaultUserPath, - configuredRoot: CreateConfig(userPath, InstallType.User)); + configuredRoot: CreateConfig(DefaultUserPath, isDotnetupHive: true)); var result = UninstallWorkflow.ResolveInstallPath(null, mock); - result.Should().Be(userPath, "user install path from configuration should be used"); + result.Should().Be(DefaultUserPath, "the dotnetup hive on PATH should be used"); + } + + /// + /// A dotnet that lives in a user-writable location but is not a dotnetup hive (e.g. a + /// hand-extracted C:\dotnet that happens to win on PATH) must not be treated as dotnetup's; + /// uninstall should fall back to the default hive rather than target the unmanaged install. + /// + [TestMethod] + public void ResolveInstallPath_UnmanagedUserInstall_FallsBackToDefault() + { + string looseUserPath = "/home/user/custom-dotnet"; + var mock = new MockDotnetInstallManager( + defaultInstallPath: DefaultUserPath, + configuredRoot: CreateConfig(looseUserPath, isDotnetupHive: false)); + + var result = UninstallWorkflow.ResolveInstallPath(null, mock); + + result.Should().Be(DefaultUserPath, "a non-hive install on PATH should not be uninstalled; default hive should be used"); } /// @@ -60,7 +77,7 @@ public void ResolveInstallPath_ExplicitPath_TakesPrecedence() { var mock = new MockDotnetInstallManager( defaultInstallPath: DefaultUserPath, - configuredRoot: CreateConfig(AdminPath, InstallType.System)); + configuredRoot: CreateConfig(AdminPath, isDotnetupHive: false)); var result = UninstallWorkflow.ResolveInstallPath(ExplicitPath, mock); @@ -82,9 +99,9 @@ public void ResolveInstallPath_NoConfiguredInstall_UsesDefault() result.Should().Be(DefaultUserPath); } - private static DotnetInstallRootConfiguration CreateConfig(string path, InstallType installType) + private static DotnetInstallRootConfiguration CreateConfig(string path, bool isDotnetupHive) { var installRoot = new DotnetInstallRoot(path, InstallerUtilities.GetDefaultInstallArchitecture()); - return new DotnetInstallRootConfiguration(installRoot, installType); + return new DotnetInstallRootConfiguration(installRoot, isDotnetupHive); } } From 83503e1e6b2df3294047b29fec1fd3d9eec890ea Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 17 Jul 2026 16:01:39 -0400 Subject: [PATCH 2/4] Fix outdated doc --- documentation/general/dotnetup/designs/dotnetup-env.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/documentation/general/dotnetup/designs/dotnetup-env.md b/documentation/general/dotnetup/designs/dotnetup-env.md index d64e09808083..e06093507af9 100644 --- a/documentation/general/dotnetup/designs/dotnetup-env.md +++ b/documentation/general/dotnetup/designs/dotnetup-env.md @@ -154,9 +154,11 @@ DotnetAccessMode.Shell = old ShellProfile // shell profile file onl DotnetAccessMode.Everywhere = old FullPathReplacement // env-var PATH + shell profile ``` -The JSON serialization writes the new lowercase names (`none` / `shell` / `everywhere`). -On read, the converter also accepts the legacy spellings (`full`, `fullpathreplacement`, -etc.) so configs written by earlier internal builds keep their chosen mode. +The JSON serialization writes the new lowercase names (`none` / `shell` / `everywhere`) +via the built-in string-enum converter (camel-case, integer values rejected). Legacy +spellings from earlier internal builds (`full` / `fullpathreplacement`, and the old +`pathPreference` property) are **not** accepted: an unrecognized value is treated as a +corrupt config, which re-defaults on the next write rather than silently mapping to a mode. ## `dotnetup` on PATH: an orthogonal setting From 3134f0ec4c8192d7030ffbdb1f9a2e29997f3b59 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 17 Jul 2026 16:09:52 -0400 Subject: [PATCH 3/4] Improve EnvOpenNewTerminalForOtherSurfaces text --- src/Installer/dotnetup.Library/Strings.resx | 2 +- src/Installer/dotnetup.Library/xlf/Strings.cs.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.de.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.es.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.fr.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.it.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.ja.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.ko.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.pl.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.ru.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.tr.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Installer/dotnetup.Library/Strings.resx b/src/Installer/dotnetup.Library/Strings.resx index 03c4dc3a7deb..2ad92c96c971 100644 --- a/src/Installer/dotnetup.Library/Strings.resx +++ b/src/Installer/dotnetup.Library/Strings.resx @@ -283,7 +283,7 @@ Or open a new terminal. Open a new terminal for the change to take effect. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. Could not detect the current shell, which is required to update the dotnetup profile entry. Re-run with --shell <{0}> to specify it explicitly. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.cs.xlf b/src/Installer/dotnetup.Library/xlf/Strings.cs.xlf index 79e8e09b1273..9b76a269c8c3 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.cs.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.cs.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.de.xlf b/src/Installer/dotnetup.Library/xlf/Strings.de.xlf index 13b9d117311c..e234055d6ab0 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.de.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.de.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.es.xlf b/src/Installer/dotnetup.Library/xlf/Strings.es.xlf index d1a7bbb6ca1c..6643a6fb7948 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.es.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.es.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.fr.xlf b/src/Installer/dotnetup.Library/xlf/Strings.fr.xlf index 0977f5a1c853..fcfff0562bda 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.fr.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.fr.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.it.xlf b/src/Installer/dotnetup.Library/xlf/Strings.it.xlf index db404f6a3749..d9866cb020c5 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.it.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.it.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.ja.xlf b/src/Installer/dotnetup.Library/xlf/Strings.ja.xlf index 1ca8cec377e8..0fa110236297 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.ja.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.ja.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.ko.xlf b/src/Installer/dotnetup.Library/xlf/Strings.ko.xlf index a52c66b4bf08..fa8b7b098fe5 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.ko.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.ko.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.pl.xlf b/src/Installer/dotnetup.Library/xlf/Strings.pl.xlf index 21079e58d905..e168b9ad9c78 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.pl.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.pl.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf b/src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf index 82a89f2d4134..a04e081f849d 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.ru.xlf b/src/Installer/dotnetup.Library/xlf/Strings.ru.xlf index 7d4b8c53eb22..ac5d120955ad 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.ru.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.ru.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.tr.xlf b/src/Installer/dotnetup.Library/xlf/Strings.tr.xlf index 3ff70a4828b4..f9d57a97601f 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.tr.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.tr.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf b/src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf index bebd5d21e0db..1544fb2934b8 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf b/src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf index 611c6bf968df..a7f71a1f68cb 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf @@ -107,8 +107,8 @@ Or open a new terminal. {Locked="shell"} - Open a new terminal for the change to take effect in other terminals and applications. - Open a new terminal for the change to take effect in other terminals and applications. + Other open terminals and applications will pick up this change after they're restarted. + Other open terminals and applications will pick up this change after they're restarted. From 4d8f61a6c4f273def19f919b541996170dac9d13 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Mon, 20 Jul 2026 08:37:43 -0400 Subject: [PATCH 4/4] Fix test and style warning --- .../dotnetup.Library/DotnetEnvironmentManager.cs | 1 - src/Installer/dotnetup.Library/DotnetupPaths.cs | 11 +++++++++++ src/Installer/dotnetup.Library/Strings.resx | 2 +- src/Installer/dotnetup.Library/xlf/Strings.cs.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.de.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.es.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.fr.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.it.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.ja.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.ko.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.pl.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.ru.xlf | 4 ++-- src/Installer/dotnetup.Library/xlf/Strings.tr.xlf | 4 ++-- .../dotnetup.Library/xlf/Strings.zh-Hans.xlf | 4 ++-- .../dotnetup.Library/xlf/Strings.zh-Hant.xlf | 4 ++-- .../DotnetCommandStdinForwardingTests.cs | 8 +++++--- 17 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs b/src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs index 0d381a82111f..7cdcd0ac1bc8 100644 --- a/src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs +++ b/src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Dotnet.Installation.Internal; -using Microsoft.DotNet.Tools.Bootstrapper.Commands.Shared; using Microsoft.DotNet.Tools.Bootstrapper.Shell; using Microsoft.DotNet.Tools.Bootstrapper.Telemetry; using Spectre.Console; diff --git a/src/Installer/dotnetup.Library/DotnetupPaths.cs b/src/Installer/dotnetup.Library/DotnetupPaths.cs index 6024f3cadff6..b0190006d44c 100644 --- a/src/Installer/dotnetup.Library/DotnetupPaths.cs +++ b/src/Installer/dotnetup.Library/DotnetupPaths.cs @@ -121,10 +121,21 @@ public static string ManifestPath /// Gets the default dotnet install path managed by dotnetup. /// This is the user-local dotnet root (e.g. %LOCALAPPDATA%\dotnet on Windows). /// + /// + /// Can be overridden via DOTNET_TESTHOOK_DEFAULT_DOTNET_PATH environment variable. + /// public static string DefaultDotnetInstallPath { get { + // Allow override for testing — lets tests point the managed hive at a temp directory + // without touching the real user profile. + var overridePath = Environment.GetEnvironmentVariable("DOTNET_TESTHOOK_DEFAULT_DOTNET_PATH"); + if (!string.IsNullOrEmpty(overridePath)) + { + return overridePath; + } + var baseDir = GetBaseDirectory(); if (string.IsNullOrEmpty(baseDir)) { diff --git a/src/Installer/dotnetup.Library/Strings.resx b/src/Installer/dotnetup.Library/Strings.resx index 2ad92c96c971..ff89c905add8 100644 --- a/src/Installer/dotnetup.Library/Strings.resx +++ b/src/Installer/dotnetup.Library/Strings.resx @@ -163,7 +163,7 @@ Arguments to forward to dotnet. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. Run 'dotnetup install' to install a .NET SDK first. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.cs.xlf b/src/Installer/dotnetup.Library/xlf/Strings.cs.xlf index 9b76a269c8c3..f08d1f8a69eb 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.cs.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.cs.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.de.xlf b/src/Installer/dotnetup.Library/xlf/Strings.de.xlf index e234055d6ab0..5b1496df85b8 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.de.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.de.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.es.xlf b/src/Installer/dotnetup.Library/xlf/Strings.es.xlf index 6643a6fb7948..77aa652946de 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.es.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.es.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.fr.xlf b/src/Installer/dotnetup.Library/xlf/Strings.fr.xlf index fcfff0562bda..b94cbd115ce2 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.fr.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.fr.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.it.xlf b/src/Installer/dotnetup.Library/xlf/Strings.it.xlf index d9866cb020c5..6cdc3c7b7f6a 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.it.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.it.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.ja.xlf b/src/Installer/dotnetup.Library/xlf/Strings.ja.xlf index 0fa110236297..ca5e8215d4f6 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.ja.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.ja.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.ko.xlf b/src/Installer/dotnetup.Library/xlf/Strings.ko.xlf index fa8b7b098fe5..bab525c62c19 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.ko.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.ko.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.pl.xlf b/src/Installer/dotnetup.Library/xlf/Strings.pl.xlf index e168b9ad9c78..40b58ef7dcff 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.pl.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.pl.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf b/src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf index a04e081f849d..e2afcfb9976f 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.ru.xlf b/src/Installer/dotnetup.Library/xlf/Strings.ru.xlf index ac5d120955ad..50006ae89b60 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.ru.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.ru.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.tr.xlf b/src/Installer/dotnetup.Library/xlf/Strings.tr.xlf index f9d57a97601f..adf5b518ed4f 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.tr.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.tr.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf b/src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf index 1544fb2934b8..b8bbf1fb956d 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf b/src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf index a7f71a1f68cb..0d5e28854a18 100644 --- a/src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf +++ b/src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf @@ -28,8 +28,8 @@ - Error: dotnet executable not found at '{0}'. - Error: dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. + dotnet executable not found at '{0}'. diff --git a/test/dotnetup.Tests/DotnetCommandStdinForwardingTests.cs b/test/dotnetup.Tests/DotnetCommandStdinForwardingTests.cs index fbebd3227a8c..4b5c8fa1bd16 100644 --- a/test/dotnetup.Tests/DotnetCommandStdinForwardingTests.cs +++ b/test/dotnetup.Tests/DotnetCommandStdinForwardingTests.cs @@ -48,9 +48,11 @@ public void DotnetCommand_ForwardsStdinToChildProcess() process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; - // Prepend our temp dir to PATH so dotnetup resolves our fake dotnet - var currentPath = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; - process.StartInfo.Environment["PATH"] = tempDir.FullName + Path.PathSeparator + currentPath; + // Point dotnetup's managed hive at our temp dir so it resolves our fake dotnet. + // dotnetup resolves the dotnet to run from its managed hive (not from PATH), so the + // fake dotnet must live at /dotnet[.exe] — which is exactly where + // CreateStdinEchoFakeDotnet placed it. + process.StartInfo.Environment["DOTNET_TESTHOOK_DEFAULT_DOTNET_PATH"] = tempDir.FullName; process.StartInfo.Environment["DOTNET_NOLOGO"] = "1"; process.StartInfo.Environment["NO_COLOR"] = "1";