Skip to content

Commit

Permalink
fix review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
YuliiaKovalova committed Aug 23, 2023
1 parent 06e4571 commit c8dccd1
Showing 1 changed file with 36 additions and 65 deletions.
101 changes: 36 additions & 65 deletions src/MSBuildLocator/DotNetSdkLocationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ namespace Microsoft.Build.Locator
internal static class DotNetSdkLocationHelper
{
private static readonly Regex VersionRegex = new Regex(@"^(\d+)\.(\d+)\.(\d+)", RegexOptions.Multiline);
private static readonly Regex SdkRegex = new Regex(@"(\S+) \[(.*?)]$", RegexOptions.Multiline);
private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
private static readonly string ExeName = IsWindows ? "dotnet.exe" : "dotnet";
private static readonly string DotnetPath = ResolveDotnetPath();

static DotNetSdkLocationHelper() => LoadHostFxr();

Expand Down Expand Up @@ -68,11 +69,7 @@ public static IEnumerable<VisualStudioInstance> GetInstances(string workingDirec
}
}

/// <summary>
/// This native method call determines the actual location of path, including
/// resolving symbolic links.
/// </summary>
private static string realpath(string path)
public static IEnumerable<string> GetDotNetBasePaths(string workingDirectory)
{
string? bestSDK = GetSdkFromGlobalSettings(workingDirectory);
if (!string.IsNullOrEmpty(bestSDK))
Expand All @@ -89,6 +86,7 @@ private static string realpath(string path)
yield return dotnetPaths[i];
}
}

private static void LoadHostFxr()
{
var isOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
Expand All @@ -100,9 +98,38 @@ private static void LoadHostFxr()
}
}

private static string FindDotnetFromEnvironmentVariable(string environmentVariable, string exeName)
private static IntPtr HostFxrResolver(Assembly assembly, string libraryName)
{
string dotnet_root = Environment.GetEnvironmentVariable(environmentVariable);
var hostFxrLibName = "libhostfxr.dylib";

if (string.Equals(hostFxrLibName, libraryName, StringComparison.Ordinal))
return IntPtr.Zero;

var hostFxrRoot = Path.Combine(DotnetPath, "host", "fxr");
if (Directory.Exists(hostFxrRoot))
{
// Agreed to load hostfxr from the highest version
var hostFxrAssemblyDirectory = Directory.GetDirectories(hostFxrRoot)
.OrderByDescending(d => d)
.FirstOrDefault();

if (hostFxrAssemblyDirectory != null)
{
var hostfxrAssembly = Directory.GetFiles(hostFxrAssemblyDirectory)
.Where(filePath => filePath.Contains(hostFxrLibName, StringComparison.Ordinal))
.FirstOrDefault();

if (hostfxrAssembly != null)
return NativeLibrary.TryLoad(hostfxrAssembly, out var handle) ? handle : IntPtr.Zero;
}
}

return IntPtr.Zero;
}

private static string? FindDotnetFromEnvironmentVariable(string environmentVariable, string exeName)
{
string? dotnet_root = Environment.GetEnvironmentVariable(environmentVariable);
if (!string.IsNullOrEmpty(dotnet_root))
{
string fullPathToDotnetFromRoot = Path.Combine(dotnet_root, exeName);
Expand All @@ -121,60 +148,6 @@ private static string FindDotnetFromEnvironmentVariable(string environmentVariab
return null;
}

private static IEnumerable<string> GetDotNetBasePaths(string workingDirectory)
{
string dotnetPath = null;
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)
{
// 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)
{
// 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(filePath))
{
if (!IsWindows)
{
filePath = realpath(filePath) ?? filePath;
if (File.Exists(filePath))
{
dotnetPath = Path.GetDirectoryName(filePath);
break;
}
else
{
continue;
}
}

dotnetPath = dir;
break;
}
}
}

if (dotnetPath is null)
{
throw new InvalidOperationException("Could not find the dotnet executable. Is it on the PATH?");
}

private static string SdkResolutionExceptionMessage(string methodName) => $"Failed to find all versions of .NET Core MSBuild. Call to {methodName}. There may be more details in stderr.";

/// <summary>
Expand All @@ -187,9 +160,7 @@ private static IEnumerable<string> GetDotNetBasePaths(string workingDirectory)
int rc = NativeMethods.hostfxr_resolve_sdk2(exe_dir: DotnetPath, working_dir: workingDirectory, flags: 0, result: (key, value) =>
{
if (key == NativeMethods.hostfxr_resolve_sdk2_result_key_t.resolved_sdk_dir)
{
resolvedSdk = value;
}
});

if (rc != 0)
Expand All @@ -207,9 +178,9 @@ private static string ResolveDotnetPath()
string? dotnetExePath = GetCurrentProcessPath();
var isRunFromDotnetExecutable = !string.IsNullOrEmpty(dotnetExePath)
&& Path.GetFileName(dotnetExePath).Equals(ExeName, StringComparison.InvariantCultureIgnoreCase);

if (isRunFromDotnetExecutable)
dotnetPath = Path.GetDirectoryName(dotnetExePath);

else
{
dotnetPath = FindDotnetPathFromEnvVariable("DOTNET_HOST_PATH")
Expand Down

0 comments on commit c8dccd1

Please sign in to comment.