diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx b/src/Cli/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx index f834f2498126..a4350e5facc3 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/LocalizableStrings.resx @@ -188,4 +188,13 @@ dotnet tool install --global {1} .NET workloads installed: + + Warning: Mixed-Mode Installation Detected + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf index 059c3cc90ea8..64715ee465d0 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.cs.xlf @@ -12,6 +12,21 @@ Nesprávně naformátovaný text příkazu {0} + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. Nebylo možné provést, protože zadaný příkaz nebo soubor nebyl nalezen. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf index b65426871939..a3d0036e06f6 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.de.xlf @@ -12,6 +12,21 @@ Fehlerhafter Befehlstext "{0}". + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. Die Ausführung war nicht möglich, da der angegebene Befehl oder die angegebene Datei nicht gefunden wurde. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf index ab310ba0919e..fdeabfb73270 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.es.xlf @@ -12,6 +12,21 @@ Texto de comando con formato incorrecto "{0}" + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. No se pudo ejecutar porque no se encontró el comando o archivo especificado. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf index 83aafec69438..4c9a020a0227 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.fr.xlf @@ -12,6 +12,21 @@ Texte de commande incorrect '{0}' + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. Exécution impossible, car la commande ou le fichier spécifié est introuvable. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf index d14e1840c5e8..d28d22ca7b20 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.it.xlf @@ -12,6 +12,21 @@ Il testo del comando '{0}' non è corretto + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. Non è stato possibile eseguire perché il comando o il file specificato non è stato trovato. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf index ac1e63ccf812..9e82946e0c76 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ja.xlf @@ -12,6 +12,21 @@ 無効な形式のコマンド テキスト '{0}' + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. 指定されたコマンドまたはファイルが見つからなかったため、実行できませんでした。 diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf index 4f2d0561d088..904fc2616383 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ko.xlf @@ -12,6 +12,21 @@ 형식이 잘못된 명령 텍스트 '{0}' + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. 지정한 명령 또는 파일을 찾을 수 없어 실행하지 못했습니다. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf index f6b356e4a6eb..a1fe920e8489 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pl.xlf @@ -12,6 +12,21 @@ Nieprawidłowo sformułowany tekst polecenia „{0}” + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. Nie można wykonać, ponieważ nie znaleziono określonego polecenia lub pliku. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf index b29d04bbe723..a52b2c53c408 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.pt-BR.xlf @@ -12,6 +12,21 @@ Texto do comando malformado '{0}' + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. Não foi possível executar porque o comando ou arquivo especificado não foi encontrado. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf index 0de8ace38958..2aaf3854d8ea 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.ru.xlf @@ -12,6 +12,21 @@ Неправильный формат текста команды "{0}" + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. Не удалось выполнить, поскольку указанная команда или файл не найдены. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf index effa36b8a0ee..0caf9cf9c976 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.tr.xlf @@ -12,6 +12,21 @@ Hatalı biçimlendirilmiş komut metni: '{0}' + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. Belirtilen komut veya dosya bulunamadığından yürütülemedi. diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf index 92d85374f55b..ce34244f776d 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hans.xlf @@ -12,6 +12,21 @@ 命令文本“{0}”格式错误 + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. 无法执行,因为找不到指定的命令或文件。 diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf index 2a19383fc1ce..d9b638d4b658 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/xlf/LocalizableStrings.zh-Hant.xlf @@ -12,6 +12,21 @@ 命令文字 '{0}' 格式錯誤 + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This can cause unexpected behavior. For more information, see: {2} + + + + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + The dotnet executable being used is from a global install location ({0}), but the DOTNET_ROOT environment variable is set to a different location ({1}). This indicates a PATH ordering problem. Please ensure that the directory containing the desired dotnet executable appears first in your PATH. + + + + Warning: Mixed-Mode Installation Detected + Warning: Mixed-Mode Installation Detected + + Could not execute because the specified command or file was not found. 無法執行,因為找不到指定的命令或檔案。 diff --git a/src/Cli/dotnet/CommandLineInfo.cs b/src/Cli/dotnet/CommandLineInfo.cs index 84f0b4ba1eff..885ed9c2a12a 100644 --- a/src/Cli/dotnet/CommandLineInfo.cs +++ b/src/Cli/dotnet/CommandLineInfo.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Runtime.InteropServices; using Microsoft.DotNet.Cli.Commands.Workload; using Microsoft.DotNet.Cli.Utils; using LocalizableStrings = Microsoft.DotNet.Cli.Utils.LocalizableStrings; @@ -33,9 +34,50 @@ public static void PrintInfo() Reporter.Output.WriteLine($" OS Platform: {RuntimeEnvironment.OperatingSystemPlatform}"); Reporter.Output.WriteLine($" RID: {GetDisplayRid(versionFile)}"); Reporter.Output.WriteLine($" Base Path: {AppContext.BaseDirectory}"); + PrintMixedInstallationWarning(); PrintWorkloadsInfo(); } + private static void PrintMixedInstallationWarning() + { + try + { + var muxer = new Muxer(); + string dotnetRoot = Environment.GetEnvironmentVariable("DOTNET_ROOT"); + + if (MixedInstallationDetector.IsMixedInstallation(muxer.MuxerPath, dotnetRoot)) + { + Reporter.Output.WriteLine(); + Reporter.Output.WriteLine(LocalizableStrings.MixedInstallWarningTitle); + + string docUrl = MixedInstallationDetector.GetDocumentationUrl(); + string warningMessage; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && docUrl != null) + { + warningMessage = string.Format( + LocalizableStrings.MixedInstallWarningMessageLinux, + Path.GetDirectoryName(muxer.MuxerPath), + dotnetRoot, + docUrl); + } + else + { + warningMessage = string.Format( + LocalizableStrings.MixedInstallWarningMessageOther, + Path.GetDirectoryName(muxer.MuxerPath), + dotnetRoot); + } + + Reporter.Output.WriteLine($" {warningMessage}"); + } + } + catch + { + // Silently ignore any errors in detection to avoid breaking dotnet --info + } + } + private static void PrintWorkloadsInfo() { Reporter.Output.WriteLine(); diff --git a/src/Cli/dotnet/MixedInstallationDetector.cs b/src/Cli/dotnet/MixedInstallationDetector.cs new file mode 100644 index 000000000000..e67e5a947fda --- /dev/null +++ b/src/Cli/dotnet/MixedInstallationDetector.cs @@ -0,0 +1,147 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; +using Microsoft.Win32; + +namespace Microsoft.DotNet.Cli; + +/// +/// Detects mixed installation scenarios where the dotnet muxer on PATH +/// is from a global install but DOTNET_ROOT points to a different location. +/// +internal static class MixedInstallationDetector +{ + /// + /// Gets the global installation root path for the current platform. + /// Based on https://github.com/dotnet/designs/blob/main/accepted/2020/install-locations.md + /// and https://github.com/dotnet/designs/blob/main/accepted/2021/install-location-per-architecture.md + /// + private static string? GetGlobalInstallRoot() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Windows: Read from registry HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation + // Use 32-bit registry view as specified in the spec + try + { + string arch = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); + using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) + using (var key = hklm.OpenSubKey($@"SOFTWARE\dotnet\Setup\InstalledVersions\{arch}")) + { + if (key != null) + { + var installLocation = key.GetValue("InstallLocation") as string; + if (!string.IsNullOrEmpty(installLocation)) + { + return installLocation; + } + } + } + } + catch + { + // If registry reading fails, return null + } + } + else + { + // Linux/macOS: Read from /etc/dotnet/install_location or /etc/dotnet/install_location_ + try + { + string arch = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); + string archSpecificPath = $"/etc/dotnet/install_location_{arch}"; + string defaultPath = "/etc/dotnet/install_location"; + + // Try arch-specific location first + if (File.Exists(archSpecificPath)) + { + string location = File.ReadAllText(archSpecificPath).Trim(); + if (!string.IsNullOrEmpty(location)) + { + return location; + } + } + + // Fall back to default location + if (File.Exists(defaultPath)) + { + string location = File.ReadAllText(defaultPath).Trim(); + if (!string.IsNullOrEmpty(location)) + { + return location; + } + } + } + catch + { + // If file reading fails, return null + } + } + + return null; + } + + /// + /// Detects if the current installation is a mixed installation scenario. + /// + /// The path to the current dotnet muxer executable + /// The value of the DOTNET_ROOT environment variable (can be null) + /// True if a mixed installation is detected, false otherwise + public static bool IsMixedInstallation(string muxerPath, string? dotnetRoot) + { + if (string.IsNullOrEmpty(muxerPath) || string.IsNullOrEmpty(dotnetRoot)) + { + return false; + } + + // Get the registered global install location + string? globalInstallRoot = GetGlobalInstallRoot(); + if (string.IsNullOrEmpty(globalInstallRoot)) + { + // No global install registered, cannot detect mixed installation + return false; + } + + // Normalize paths for comparison + string normalizedMuxerPath = Path.GetFullPath(muxerPath); + string normalizedDotnetRoot = Path.GetFullPath(dotnetRoot); + string normalizedGlobalRoot = Path.GetFullPath(globalInstallRoot); + + // Check if the muxer is in the global install root + if (!normalizedMuxerPath.StartsWith(normalizedGlobalRoot, GetStringComparison())) + { + // Muxer is not in the global install root, no mixed installation + return false; + } + + // Check if DOTNET_ROOT points to a different location than the global install root + bool isDifferentRoot = !normalizedDotnetRoot.StartsWith(normalizedGlobalRoot, GetStringComparison()); + + return isDifferentRoot; + } + + /// + /// Gets the appropriate string comparison for the current platform. + /// + private static StringComparison GetStringComparison() + { + // Windows is case-insensitive for paths + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + } + + /// + /// Gets the documentation URL for mixed installation issues. + /// + public static string? GetDocumentationUrl() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return "https://learn.microsoft.com/en-us/dotnet/core/install/linux-package-mixup"; + } + + return null; + } +} diff --git a/test/dotnet.Tests/MixedInstallationDetectorTests.cs b/test/dotnet.Tests/MixedInstallationDetectorTests.cs new file mode 100644 index 000000000000..ce70cd94ac36 --- /dev/null +++ b/test/dotnet.Tests/MixedInstallationDetectorTests.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; +using Microsoft.DotNet.Cli; + +namespace Microsoft.DotNet.Tests; + +public class MixedInstallationDetectorTests : SdkTest +{ + public MixedInstallationDetectorTests(ITestOutputHelper log) : base(log) + { + } + + [Fact] + public void IsMixedInstallation_ReturnsFalse_WhenMuxerPathIsNull() + { + bool result = MixedInstallationDetector.IsMixedInstallation(null!, "/some/path"); + Assert.False(result); + } + + [Fact] + public void IsMixedInstallation_ReturnsFalse_WhenMuxerPathIsEmpty() + { + bool result = MixedInstallationDetector.IsMixedInstallation("", "/some/path"); + Assert.False(result); + } + + [Fact] + public void IsMixedInstallation_ReturnsFalse_WhenDotnetRootIsNull() + { + bool result = MixedInstallationDetector.IsMixedInstallation("/usr/share/dotnet/dotnet", null); + Assert.False(result); + } + + [Fact] + public void IsMixedInstallation_ReturnsFalse_WhenDotnetRootIsEmpty() + { + bool result = MixedInstallationDetector.IsMixedInstallation("/usr/share/dotnet/dotnet", ""); + Assert.False(result); + } + + [Fact] + public void IsMixedInstallation_DoesNotThrow_WithValidInputs() + { + // This test verifies that the method doesn't throw exceptions + // The actual result depends on whether a global install is registered on the system + bool result = MixedInstallationDetector.IsMixedInstallation( + "/some/path/dotnet", + "/different/path"); + + // Result can be true or false depending on system configuration + // We just verify it doesn't throw + Assert.True(result == true || result == false); + } + + [Fact] + public void GetDocumentationUrl_ReturnsLinuxUrl_OnLinux() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + string? url = MixedInstallationDetector.GetDocumentationUrl(); + Assert.Equal("https://learn.microsoft.com/en-us/dotnet/core/install/linux-package-mixup", url); + } + } + + [Fact] + public void GetDocumentationUrl_ReturnsNull_OnNonLinux() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + string? url = MixedInstallationDetector.GetDocumentationUrl(); + Assert.Null(url); + } + } +}