Merge pull request #6669 from livarcocc/resolver_with_path
Changing the resolver so that it will search for dotnet in the PATH
This commit is contained in:
commit
4501b01b00
5 changed files with 95 additions and 70 deletions
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.MSBuildSdkResolver
|
||||||
|
{
|
||||||
|
internal class EnvironmentProvider
|
||||||
|
{
|
||||||
|
private IEnumerable<string> _searchPaths;
|
||||||
|
|
||||||
|
private readonly Func<string, string> _getEnvironmentVariable;
|
||||||
|
|
||||||
|
public EnvironmentProvider(Func<string, string> getEnvironmentVariable)
|
||||||
|
{
|
||||||
|
_getEnvironmentVariable = getEnvironmentVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ExecutableExtension
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Interop.RunningOnWindows ? ".exe" : string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<string> SearchPaths
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_searchPaths == null)
|
||||||
|
{
|
||||||
|
var searchPaths = new List<string>();
|
||||||
|
|
||||||
|
searchPaths.AddRange(
|
||||||
|
_getEnvironmentVariable("PATH")
|
||||||
|
.Split(Path.PathSeparator)
|
||||||
|
.Select(p => p.Trim('"')));
|
||||||
|
|
||||||
|
_searchPaths = searchPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _searchPaths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetCommandPath(string commandName)
|
||||||
|
{
|
||||||
|
var commandNameWithExtension = commandName + ExecutableExtension;
|
||||||
|
var commandPath = SearchPaths
|
||||||
|
.Select(p => Path.Combine(p, commandNameWithExtension))
|
||||||
|
.FirstOrDefault(File.Exists);
|
||||||
|
|
||||||
|
return commandPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,8 @@ namespace Microsoft.DotNet.MSBuildSdkResolver
|
||||||
{
|
{
|
||||||
internal static partial class Interop
|
internal static partial class Interop
|
||||||
{
|
{
|
||||||
|
internal static readonly bool RunningOnWindows = true;
|
||||||
|
|
||||||
static Interop()
|
static Interop()
|
||||||
{
|
{
|
||||||
PreloadLibrary("hostfxr.dll");
|
PreloadLibrary("hostfxr.dll");
|
||||||
|
|
|
@ -14,13 +14,13 @@ namespace Microsoft.DotNet.MSBuildSdkResolver
|
||||||
{
|
{
|
||||||
internal static partial class Interop
|
internal static partial class Interop
|
||||||
{
|
{
|
||||||
internal static readonly bool s_runningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
internal static readonly bool RunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
|
|
||||||
private static int hostfxr_resolve_sdk(string exe_dir, string working_dir, [Out] StringBuilder buffer, int buffer_size)
|
private static int hostfxr_resolve_sdk(string exe_dir, string working_dir, [Out] StringBuilder buffer, int buffer_size)
|
||||||
{
|
{
|
||||||
// hostfxr string encoding is platform -specific so dispatch to the
|
// hostfxr string encoding is platform -specific so dispatch to the
|
||||||
// appropriately annotated P/Invoke for the current platform.
|
// appropriately annotated P/Invoke for the current platform.
|
||||||
return s_runningOnWindows
|
return RunningOnWindows
|
||||||
? windows_hostfxr_resolve_sdk(exe_dir, working_dir, buffer, buffer_size)
|
? windows_hostfxr_resolve_sdk(exe_dir, working_dir, buffer, buffer_size)
|
||||||
: unix_hostfxr_resolve_sdk(exe_dir, working_dir, buffer, buffer_size);
|
: unix_hostfxr_resolve_sdk(exe_dir, working_dir, buffer, buffer_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,71 +106,24 @@ namespace Microsoft.DotNet.MSBuildSdkResolver
|
||||||
|
|
||||||
private string ResolveNetcoreSdkDirectory(SdkResolverContext context)
|
private string ResolveNetcoreSdkDirectory(SdkResolverContext context)
|
||||||
{
|
{
|
||||||
foreach (string exeDir in GetDotnetExeDirectoryCandidates())
|
string exeDir = GetDotnetExeDirectory();
|
||||||
{
|
string workingDir = context.SolutionFilePath ?? context.ProjectFilePath;
|
||||||
string workingDir = context.SolutionFilePath ?? context.ProjectFilePath;
|
string netcoreSdkDir = Interop.hostfxr_resolve_sdk(exeDir, workingDir);
|
||||||
string netcoreSdkDir = Interop.hostfxr_resolve_sdk(exeDir, workingDir);
|
|
||||||
|
|
||||||
if (netcoreSdkDir != null)
|
return netcoreSdkDir;
|
||||||
{
|
|
||||||
return netcoreSdkDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for [ProgramFiles]\dotnet in this order.
|
private string GetDotnetExeDirectory()
|
||||||
private static readonly string[] s_programFiles = new[]
|
|
||||||
{
|
|
||||||
// "c:\Program Files" on x64 machine regardless process architecture.
|
|
||||||
// Undefined on x86 machines.
|
|
||||||
"ProgramW6432",
|
|
||||||
|
|
||||||
// "c:\Program Files (x86)" on x64 machine regardless of process architecture
|
|
||||||
// Undefined on x86 machines.
|
|
||||||
"ProgramFiles(x86)",
|
|
||||||
|
|
||||||
// "c:\Program Files" or "C:\Program Files (x86)" on x64 machine depending on process architecture.
|
|
||||||
// "c:\Program Files" on x86 machines (therefore not redundant with the two locations above in that case).
|
|
||||||
//
|
|
||||||
// NOTE: hostfxr will search this on its own if multilevel lookup is not disable, but we do it explicitly
|
|
||||||
// to prevent an environment with disabled multilevel lookup from crippling desktop msbuild and VS.
|
|
||||||
"ProgramFiles",
|
|
||||||
};
|
|
||||||
|
|
||||||
private List<string> GetDotnetExeDirectoryCandidates()
|
|
||||||
{
|
{
|
||||||
string environmentOverride = _getEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR");
|
string environmentOverride = _getEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR");
|
||||||
if (environmentOverride != null)
|
if (environmentOverride != null)
|
||||||
{
|
{
|
||||||
return new List<string>(capacity: 1) { environmentOverride };
|
return environmentOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial capacity is 2 because while there are 3 candidates, we expect at most 2 unique ones (x64 + x86)
|
var environmentProvider = new EnvironmentProvider(_getEnvironmentVariable);
|
||||||
// Also, N=3 here means that we needn't be concerned with the O(N^2) complexity of the foreach + contains.
|
|
||||||
var candidates = new List<string>(capacity: 2);
|
|
||||||
foreach (string variable in s_programFiles)
|
|
||||||
{
|
|
||||||
string directory = _getEnvironmentVariable(variable);
|
|
||||||
if (directory == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
directory = Path.Combine(directory, "dotnet");
|
return Path.GetDirectoryName(environmentProvider.GetCommandPath("dotnet"));
|
||||||
if (!candidates.Contains(directory))
|
|
||||||
{
|
|
||||||
candidates.Add(directory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (candidates.Count == 0)
|
|
||||||
{
|
|
||||||
candidates.Add(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return candidates;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ using Microsoft.DotNet.Tools.Test.Utilities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
using System;
|
using System;
|
||||||
|
@ -40,6 +41,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
var expected = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.98");
|
var expected = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.98");
|
||||||
environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.99");
|
environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.99");
|
||||||
environment.CreateGlobalJson(environment.TestDirectory, "99.99.98");
|
environment.CreateGlobalJson(environment.TestDirectory, "99.99.98");
|
||||||
|
environment.CreateMuxerAndAddToPath(ProgramFiles.X64);
|
||||||
|
|
||||||
var resolver = environment.CreateResolver();
|
var resolver = environment.CreateResolver();
|
||||||
var result = (MockResult)resolver.Resolve(
|
var result = (MockResult)resolver.Resolve(
|
||||||
|
@ -59,6 +61,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
{
|
{
|
||||||
var environment = new TestEnvironment();
|
var environment = new TestEnvironment();
|
||||||
environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.99");
|
environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.99");
|
||||||
|
environment.CreateMuxerAndAddToPath(ProgramFiles.X64);
|
||||||
|
|
||||||
var resolver = environment.CreateResolver();
|
var resolver = environment.CreateResolver();
|
||||||
var result = (MockResult)resolver.Resolve(
|
var result = (MockResult)resolver.Resolve(
|
||||||
|
@ -80,6 +83,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
{
|
{
|
||||||
var environment = new TestEnvironment();
|
var environment = new TestEnvironment();
|
||||||
var expected = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.99");
|
var expected = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.99");
|
||||||
|
environment.CreateMuxerAndAddToPath(ProgramFiles.X64);
|
||||||
|
|
||||||
var resolver = environment.CreateResolver();
|
var resolver = environment.CreateResolver();
|
||||||
var result = (MockResult)resolver.Resolve(
|
var result = (MockResult)resolver.Resolve(
|
||||||
|
@ -99,6 +103,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
{
|
{
|
||||||
var environment = new TestEnvironment();
|
var environment = new TestEnvironment();
|
||||||
var expected = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "999.99.99");
|
var expected = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "999.99.99");
|
||||||
|
environment.CreateMuxerAndAddToPath(ProgramFiles.X64);
|
||||||
|
|
||||||
var resolver = environment.CreateResolver();
|
var resolver = environment.CreateResolver();
|
||||||
var result = (MockResult)resolver.Resolve(
|
var result = (MockResult)resolver.Resolve(
|
||||||
|
@ -122,6 +127,10 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
|
|
||||||
private sealed class TestEnvironment : SdkResolverContext
|
private sealed class TestEnvironment : SdkResolverContext
|
||||||
{
|
{
|
||||||
|
public string Muxer => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet";
|
||||||
|
|
||||||
|
public string PathEnvironmentVariable { get; set; }
|
||||||
|
|
||||||
public DirectoryInfo TestDirectory { get; }
|
public DirectoryInfo TestDirectory { get; }
|
||||||
|
|
||||||
public TestEnvironment(string identifier = "", [CallerMemberName] string callingMethod = "")
|
public TestEnvironment(string identifier = "", [CallerMemberName] string callingMethod = "")
|
||||||
|
@ -130,6 +139,8 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
"temp",
|
"temp",
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
callingMethod: callingMethod);
|
callingMethod: callingMethod);
|
||||||
|
|
||||||
|
PathEnvironmentVariable = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SdkResolver CreateResolver()
|
public SdkResolver CreateResolver()
|
||||||
|
@ -148,30 +159,28 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateMuxerAndAddToPath(ProgramFiles programFiles)
|
||||||
|
{
|
||||||
|
var muxerDirectory = TestDirectory.GetDirectory(GetProgramFilesDirectory(programFiles).FullName, "dotnet");
|
||||||
|
|
||||||
|
new FileInfo(Path.Combine(muxerDirectory.FullName, Muxer)).Create();
|
||||||
|
|
||||||
|
PathEnvironmentVariable = $"{muxerDirectory}{Path.PathSeparator}{PathEnvironmentVariable}";
|
||||||
|
}
|
||||||
|
|
||||||
public void CreateGlobalJson(DirectoryInfo directory, string version)
|
public void CreateGlobalJson(DirectoryInfo directory, string version)
|
||||||
=> File.WriteAllText(directory.GetFile("global.json").FullName,
|
=> File.WriteAllText(directory.GetFile("global.json").FullName,
|
||||||
$@"{{ ""sdk"": {{ ""version"": ""{version}"" }} }}");
|
$@"{{ ""sdk"": {{ ""version"": ""{version}"" }} }}");
|
||||||
|
|
||||||
public string GetEnvironmentVariable(string variable)
|
public string GetEnvironmentVariable(string variable)
|
||||||
{
|
{
|
||||||
ProgramFiles programFiles;
|
|
||||||
|
|
||||||
switch (variable)
|
switch (variable)
|
||||||
{
|
{
|
||||||
case "ProgramW6432":
|
case "PATH":
|
||||||
programFiles = ProgramFiles.X64;
|
return PathEnvironmentVariable;
|
||||||
break;
|
|
||||||
case "ProgramFiles(x86)":
|
|
||||||
programFiles = ProgramFiles.X86;
|
|
||||||
break;
|
|
||||||
case "ProgramFiles":
|
|
||||||
programFiles = ProgramFiles.Default;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetProgramFilesDirectory(programFiles).FullName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue