Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BuiltInTools/Watch/Context/EnvironmentOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public TimeSpan GetProcessCleanupTimeout(bool isHotReloadEnabled)

private static string ValidateMuxerPath(string path)
{
Debug.Assert(Path.GetFileNameWithoutExtension(path) == "dotnet");
Debug.Assert(Path.GetFileName(path).Equals("dotnet" + PathUtilities.ExecutableExtension, StringComparison.OrdinalIgnoreCase));
return path;
}

Expand Down
11 changes: 7 additions & 4 deletions src/Cli/Microsoft.DotNet.Cli.Utils/Muxer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ public string MuxerPath

public Muxer()
{
string muxerFileName = MuxerName + Constants.ExeSuffix;

// Most scenarios are running dotnet.dll as the app
// Root directory with muxer should be two above app base: <root>/sdk/<version>
string? rootPath = Path.GetDirectoryName(Path.GetDirectoryName(AppContext.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar)));
if (rootPath is not null)
{
string muxerPathMaybe = Path.Combine(rootPath, $"{MuxerName}{FileNameSuffixes.CurrentPlatform.Exe}");
string muxerPathMaybe = Path.Combine(rootPath, muxerFileName);
if (File.Exists(muxerPathMaybe))
{
_muxerPath = muxerPathMaybe;
Expand All @@ -58,8 +60,9 @@ public Muxer()
string processPath = Process.GetCurrentProcess().MainModule.FileName;
#endif

// The current process should be dotnet in most normal scenarios except when dotnet.dll is loaded in a custom host like the testhost
if (processPath is not null && !Path.GetFileNameWithoutExtension(processPath).Equals("dotnet", StringComparison.OrdinalIgnoreCase))
// The current process should be dotnet in most normal scenarios except when dotnet.dll is loaded in a custom host like the testhost.
// Use GetFileName (not GetFileNameWithoutExtension) to avoid false matches with dotnet-prefixed names like "dotnet.Tests".
if (processPath is not null && !Path.GetFileName(processPath).Equals(muxerFileName, StringComparison.OrdinalIgnoreCase))
{
// SDK sets DOTNET_HOST_PATH as absolute path to current dotnet executable
processPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH");
Expand All @@ -69,7 +72,7 @@ public Muxer()
var root = Environment.GetEnvironmentVariable("DOTNET_ROOT");
if (root is not null)
{
processPath = Path.Combine(root, $"dotnet{Constants.ExeSuffix}");
processPath = Path.Combine(root, muxerFileName);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/RazorSdk/Tool/ServerProtocol/ServerConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,15 @@ private static string FindDotNetExecutable()
expectedPath = Process.GetCurrentProcess().MainModule.FileName;
#endif

if ("dotnet".Equals(Path.GetFileNameWithoutExtension(expectedPath), StringComparison.Ordinal))
// Use GetFileName (not GetFileNameWithoutExtension) to avoid false matches with dotnet-prefixed names like "dotnet.Tests".
var exeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet";
if (exeName.Equals(Path.GetFileName(expectedPath), StringComparison.Ordinal))
Comment thread
MichaelSimons marked this conversation as resolved.
{
return expectedPath;
}

// We were probably running from Visual Studio or Build Tools and found MSBuild instead of dotnet. Use the PATH...
var paths = Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator);
var exeName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet";
foreach (string path in paths)
{
var dotnetPath = Path.Combine(path, exeName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,7 @@ private sealed class CachedState
minimumVSDefinedSDKVersion);
}

string? fullPathToMuxer =
TryResolveMuxerFromSdkResolution(dotnetSdkDir)
?? Path.Combine(dotnetRoot, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Constants.DotNetExe : Constants.DotNet);
string? fullPathToMuxer = TryResolveMuxerFromSdkResolution(dotnetSdkDir) ?? Path.Combine(dotnetRoot, Constants.DotNetFileName);
if (File.Exists(fullPathToMuxer))
{
// keeping this in until this component no longer needs to handle 17.14.
Expand Down Expand Up @@ -349,10 +347,9 @@ private sealed class CachedState
/// </remarks>
private static string? TryResolveMuxerFromSdkResolution(string resolvedSdkDirectory)
{
var expectedFileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Constants.DotNetExe : Constants.DotNet;
var currentDir = resolvedSdkDirectory;
var expectedDotnetRoot = Path.GetDirectoryName(Path.GetDirectoryName(currentDir));
var expectedMuxerPath = Path.Combine(expectedDotnetRoot, expectedFileName);
var expectedMuxerPath = Path.Combine(expectedDotnetRoot, Constants.DotNetFileName);
if (File.Exists(expectedMuxerPath))
{
return expectedMuxerPath;
Expand Down
3 changes: 2 additions & 1 deletion src/Resolvers/Microsoft.DotNet.NativeWrapper/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ internal static class Constants
{
public const string HostFxr = "hostfxr";
public const string DotNet = "dotnet";
public const string DotNetExe = "dotnet.exe";
public const string PATH = "PATH";
public const string DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR = "DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR";

public static readonly string DotNetFileName = DotNet + ExeSuffix;

public static readonly string ExeSuffix =
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty;

Comment thread
MichaelSimons marked this conversation as resolved.
Outdated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ private IEnumerable<string> SearchPaths
// the current process path on .NET Framework. We are expected to find dotnet on PATH.
dotnetExe = _getCurrentProcessPath();

if (string.IsNullOrEmpty(dotnetExe) || !Path.GetFileNameWithoutExtension(dotnetExe)
.Equals(Constants.DotNet, StringComparison.InvariantCultureIgnoreCase))
if (string.IsNullOrEmpty(dotnetExe) || !Path.GetFileName(dotnetExe)
.Equals(Constants.DotNetFileName, StringComparison.InvariantCultureIgnoreCase))
#endif
{
string? dotnetExeFromPath = GetCommandPath(Constants.DotNet);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@

namespace Microsoft.DotNet.Cli.Utils.Tests
{
public class GivenAnEnvironmentForResolution
public class GivenAnEnvironmentForResolution : SdkTest
{
public GivenAnEnvironmentForResolution(ITestOutputHelper log) : base(log)
{
}

[Fact]
public void ItIgnoresInvalidPath()
{
Expand All @@ -22,5 +26,26 @@ public void ItDoesNotReturnNullDotnetRootOnExtraPathSeparator()
var result = NativeWrapper.EnvironmentProvider.GetDotnetExeDirectory(getPathEnvVarFunc);
result.Should().NotBeNullOrWhiteSpace();
}

[Fact]
public void ItDoesNotMistakeDotnetPrefixedProcessForDotnetHost()
{
// Use separate directories for the dotnet host and the dotnet-prefixed process
// to verify the resolver finds dotnet via PATH, not from the process path.
var dotnetDir = TestAssetsManager.CreateTestDirectory(identifier: "dotnetHost").Path;
var processDir = TestAssetsManager.CreateTestDirectory(identifier: "processDir").Path;

var dotnetFileName = "dotnet" + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty);
File.Create(Path.Combine(dotnetDir, dotnetFileName)).Close();

// Simulate a dotnet-prefixed process (e.g. dotnet.Tests from xunit v3)
Func<string, string?> getEnvVar = (input) => input.Equals("PATH") ? dotnetDir : null;
Func<string?> getProcessPath = () => Path.Combine(processDir, "dotnet.Tests");

var result = NativeWrapper.EnvironmentProvider.GetDotnetExeDirectory(getEnvVar, getProcessPath);

// Should resolve via PATH to the real dotnet directory, not the process directory
result.Should().Be(dotnetDir);
}
}
}
Loading