From da02e786fc2bd22928d81799b083b11c396a5fa5 Mon Sep 17 00:00:00 2001 From: Forgind Date: Thu, 3 Aug 2023 11:21:09 -0700 Subject: [PATCH 1/3] Respect DOTNET_ROOT --- src/MSBuildLocator/DotNetSdkLocationHelper.cs | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/MSBuildLocator/DotNetSdkLocationHelper.cs b/src/MSBuildLocator/DotNetSdkLocationHelper.cs index 3e6e86cc..88ec21d3 100644 --- a/src/MSBuildLocator/DotNetSdkLocationHelper.cs +++ b/src/MSBuildLocator/DotNetSdkLocationHelper.cs @@ -92,18 +92,37 @@ private static IEnumerable GetDotNetBasePaths(string workingDirectory) bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); string exeName = isWindows ? "dotnet.exe" : "dotnet"; - // We will generally find the dotnet exe on the path, but on linux, it is often just a 'dotnet' symlink (possibly even to more symlinks) that we have to resolve - // to the real dotnet executable. - // This will work as often as just invoking dotnet from the command line, but we can be more confident in finding a dotnet executable by following - // https://github.com/dotnet/designs/blob/main/accepted/2021/install-location-per-architecture.md - // This can be done using the nethost library. We didn't do this previously, so I did not implement this extension. - foreach (string dir in Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator)) - { - string filePath = Path.Combine(dir, exeName); - if (File.Exists(Path.Combine(dir, exeName))) + // First check for the DOTNET_ROOT environment variable, as it's often there as with, for example, dotnet format. + string dotnet_root = Environment.GetEnvironmentVariable("DOTNET_ROOT"); + if (!string.IsNullOrEmpty(dotnet_root)) + { + // DOTNET_ROOT can be a path to dotnet OR a path to the folder containing dotnet. + string fullPathToDotnetFromRoot = Path.Combine(dotnet_root, exeName); + if (File.Exists(fullPathToDotnetFromRoot)) + { + dotnetPath = fullPathToDotnetFromRoot; + } + else if (File.Exists(dotnet_root)) + { + dotnetPath = dotnet_root; + } + } + + if (dotnetPath is null) + { + // We will generally find the dotnet exe on the path, but on linux, it is often just a 'dotnet' symlink (possibly even to more symlinks) that we have to resolve + // to the real dotnet executable. + // This will work as often as just invoking dotnet from the command line, but we can be more confident in finding a dotnet executable by following + // https://github.com/dotnet/designs/blob/main/accepted/2021/install-location-per-architecture.md + // This can be done using the nethost library. We didn't do this previously, so I did not implement this extension. + foreach (string dir in Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator)) { - dotnetPath = filePath; - break; + string filePath = Path.Combine(dir, exeName); + if (File.Exists(Path.Combine(dir, exeName))) + { + dotnetPath = filePath; + break; + } } } From 59c2d52fca622e97cea9ca780aff1fffc2a59b95 Mon Sep 17 00:00:00 2001 From: Forgind Date: Wed, 9 Aug 2023 14:04:53 -0700 Subject: [PATCH 2/3] DOTNET_ROOT is a folder. Also, DOTNET_ROOT(x86) --- src/MSBuildLocator/DotNetSdkLocationHelper.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/MSBuildLocator/DotNetSdkLocationHelper.cs b/src/MSBuildLocator/DotNetSdkLocationHelper.cs index 7c6fd544..828be1d4 100644 --- a/src/MSBuildLocator/DotNetSdkLocationHelper.cs +++ b/src/MSBuildLocator/DotNetSdkLocationHelper.cs @@ -96,15 +96,24 @@ private static IEnumerable GetDotNetBasePaths(string workingDirectory) string dotnet_root = Environment.GetEnvironmentVariable("DOTNET_ROOT"); if (!string.IsNullOrEmpty(dotnet_root)) { - // DOTNET_ROOT can be a path to dotnet OR a path to the folder containing dotnet. string fullPathToDotnetFromRoot = Path.Combine(dotnet_root, exeName); if (File.Exists(fullPathToDotnetFromRoot)) { dotnetPath = fullPathToDotnetFromRoot; } - else if (File.Exists(dotnet_root)) + } + + // Second, check for the DOTNET_ROOT(x86) environment variable, as it can be there, too. + if (dotnetPath is null) + { + string dotnet_root_x86 = Environment.GetEnvironmentVariable("DOTNET_ROOT(x86)"); + if (!string.IsNullOrEmpty(dotnet_root_x86)) { - dotnetPath = dotnet_root; + string fullPathToDotnetFromRoot = Path.Combine(dotnet_root_x86, exeName); + if (File.Exists(fullPathToDotnetFromRoot)) + { + dotnetPath = fullPathToDotnetFromRoot; + } } } From 23d9b1c9dad990ff1ccdceddc1145c9aabb581a4 Mon Sep 17 00:00:00 2001 From: Forgind Date: Mon, 21 Aug 2023 18:00:00 -0700 Subject: [PATCH 3/3] PR Feedback --- src/MSBuildLocator/DotNetSdkLocationHelper.cs | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/MSBuildLocator/DotNetSdkLocationHelper.cs b/src/MSBuildLocator/DotNetSdkLocationHelper.cs index 828be1d4..12f65aad 100644 --- a/src/MSBuildLocator/DotNetSdkLocationHelper.cs +++ b/src/MSBuildLocator/DotNetSdkLocationHelper.cs @@ -78,6 +78,10 @@ public static IEnumerable GetInstances(string workingDirec } } + /// + /// This native method call determines the actual location of path, including + /// resolving symbolic links. + /// private static string realpath(string path) { IntPtr ptr = NativeMethods.realpath(path, IntPtr.Zero); @@ -86,35 +90,37 @@ private static string realpath(string path) return result; } - private static IEnumerable GetDotNetBasePaths(string workingDirectory) + private static string FindDotnetFromEnvironmentVariable(string environmentVariable, string exeName) { - string dotnetPath = null; - bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - string exeName = isWindows ? "dotnet.exe" : "dotnet"; - - // First check for the DOTNET_ROOT environment variable, as it's often there as with, for example, dotnet format. - string dotnet_root = Environment.GetEnvironmentVariable("DOTNET_ROOT"); + string dotnet_root = Environment.GetEnvironmentVariable(environmentVariable); if (!string.IsNullOrEmpty(dotnet_root)) { string fullPathToDotnetFromRoot = Path.Combine(dotnet_root, exeName); if (File.Exists(fullPathToDotnetFromRoot)) { - dotnetPath = fullPathToDotnetFromRoot; + return realpath(fullPathToDotnetFromRoot) ?? fullPathToDotnetFromRoot; } } - // Second, check for the DOTNET_ROOT(x86) environment variable, as it can be there, too. - if (dotnetPath is null) + return null; + } + + private static IEnumerable GetDotNetBasePaths(string workingDirectory) + { + string dotnetPath = null; + bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + string exeName = isWindows ? "dotnet.exe" : "dotnet"; + + // First check for the DOTNET_ROOT environment variable, as it's often there as with, for example, dotnet format. + if (IntPtr.Size == 4) { - string dotnet_root_x86 = Environment.GetEnvironmentVariable("DOTNET_ROOT(x86)"); - if (!string.IsNullOrEmpty(dotnet_root_x86)) - { - string fullPathToDotnetFromRoot = Path.Combine(dotnet_root_x86, exeName); - if (File.Exists(fullPathToDotnetFromRoot)) - { - dotnetPath = fullPathToDotnetFromRoot; - } - } + // 32-bit architecture + dotnetPath ??= FindDotnetFromEnvironmentVariable("DOTNET_ROOT(x86)", exeName); + } + else if (IntPtr.Size == 8) + { + // 64-bit architecture + dotnetPath ??= FindDotnetFromEnvironmentVariable("DOTNET_ROOT", exeName); } if (dotnetPath is null)