Skip to content

Commit 63edbe4

Browse files
committed
Fix dotnet path for RoslynCodeTaskFactory
1 parent 0974273 commit 63edbe4

File tree

3 files changed

+85
-2
lines changed

3 files changed

+85
-2
lines changed

src/Tasks.UnitTests/RoslynCodeTaskFactory_Tests.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,61 @@ public override bool Execute()
10681068
}
10691069
}
10701070

1071+
[Fact]
1072+
public void RoslynCodeTaskFactory_UsingAPI()
1073+
{
1074+
string text = $@"
1075+
<Project>
1076+
1077+
<UsingTask
1078+
TaskName=""Custom1""
1079+
TaskFactory=""RoslynCodeTaskFactory""
1080+
AssemblyFile=""$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"" >
1081+
<ParameterGroup>
1082+
<SayHi ParameterType=""System.String"" Required=""true"" />
1083+
</ParameterGroup>
1084+
<Task>
1085+
<Reference Include=""{typeof(Enumerable).Assembly.Location}"" />
1086+
<Code Type=""Fragment"" Language=""cs"">
1087+
<![CDATA[
1088+
string sayHi = ""Hello "" + SayHi;
1089+
Log.LogMessage(sayHi);
1090+
]]>
1091+
</Code>
1092+
</Task>
1093+
</UsingTask>
1094+
1095+
<Target Name=""Build"">
1096+
<Custom1 SayHi=""World"" />
1097+
</Target>
1098+
1099+
</Project>";
1100+
1101+
using var env = TestEnvironment.Create();
1102+
#if !FEATURE_RUN_EXE_IN_TESTS
1103+
RunnerUtilities.ApplyDotnetHostPathEnvironmentVariable(env);
1104+
#endif
1105+
1106+
var project = env.CreateTestProjectWithFiles("p1.proj", text);
1107+
1108+
var logger = project.BuildProjectExpectSuccess();
1109+
#if !FEATURE_RUN_EXE_IN_TESTS
1110+
var filter = "dotnet path is ";
1111+
#else
1112+
var filter = "Compiling task source code";
1113+
1114+
#endif
1115+
var logLines = logger.AllBuildEvents.Select(a => a.Message);
1116+
var log = string.Join("\n", logLines);
1117+
var messages = logLines.Where(l => l.Contains(filter)).ToList();
1118+
messages.Count.ShouldBe(1, log);
1119+
#if !FEATURE_RUN_EXE_IN_TESTS
1120+
var dotnetPath = messages[0].Replace(filter, string.Empty);
1121+
bool isFilePath = File.Exists(dotnetPath);
1122+
isFilePath.ShouldBeTrue(dotnetPath);
1123+
#endif
1124+
}
1125+
10711126
private void TryLoadTaskBodyAndExpectFailure(string taskBody, string expectedErrorMessage)
10721127
{
10731128
if (expectedErrorMessage == null)

src/Tasks/RoslynCodeTaskFactory/RoslynCodeTaskFactoryCompilers.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.IO;
66
using System.Linq;
7+
using System.Runtime.InteropServices;
78
using Microsoft.Build.Framework;
89
using Microsoft.Build.Utilities;
910

@@ -14,7 +15,7 @@ namespace Microsoft.Build.Tasks
1415
internal abstract class RoslynCodeTaskFactoryCompilerBase : ToolTaskExtension
1516
{
1617
#if RUNTIME_TYPE_NETCORE
17-
private static readonly string DotnetCliPath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
18+
private readonly string dotnetCliPath;
1819
#endif
1920

2021
private readonly Lazy<string> _executablePath;
@@ -43,6 +44,26 @@ protected RoslynCodeTaskFactoryCompilerBase()
4344
}, isThreadSafe: true);
4445

4546
StandardOutputImportance = MessageImportance.Low.ToString("G");
47+
48+
#if RUNTIME_TYPE_NETCORE
49+
// Tools and MSBuild Tasks within the SDK that invoke binaries via the dotnet host are expected
50+
// to honor the environment variable DOTNET_HOST_PATH to ensure a consistent experience.
51+
dotnetCliPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH");
52+
if (string.IsNullOrEmpty(dotnetCliPath))
53+
{
54+
// Fallback to get dotnet path from current process which might be dotnet executable.
55+
dotnetCliPath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
56+
}
57+
58+
// If dotnet path is not found, rely on dotnet via the system's PATH
59+
bool runningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
60+
string exeSuffix = runningOnWindows ? ".exe" : string.Empty;
61+
var dotnetFileName = $"dotnet{exeSuffix}";
62+
if (!dotnetCliPath.EndsWith(dotnetFileName, StringComparison.OrdinalIgnoreCase))
63+
{
64+
dotnetCliPath = "dotnet";
65+
}
66+
#endif
4667
}
4768

4869
public bool? Deterministic { get; set; }
@@ -99,7 +120,8 @@ protected override string GenerateFullPathToTool()
99120
}
100121

101122
#if RUNTIME_TYPE_NETCORE
102-
return DotnetCliPath;
123+
Log.LogMessageFromText($"dotnet path is {dotnetCliPath}", StandardOutputImportanceToUse);
124+
return dotnetCliPath;
103125
#else
104126
return _executablePath.Value;
105127
#endif

src/UnitTests.Shared/RunnerUtilities.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ public static class RunnerUtilities
1515
public static string PathToCurrentlyRunningMsBuildExe => BuildEnvironmentHelper.Instance.CurrentMSBuildExePath;
1616
#if !FEATURE_RUN_EXE_IN_TESTS
1717
private static readonly string s_dotnetExePath = EnvironmentProvider.GetDotnetExePath();
18+
19+
public static void ApplyDotnetHostPathEnvironmentVariable(TestEnvironment testEnvironment)
20+
{
21+
// Built msbuild.dll executed by dotnet.exe needs this environment variable for msbuild tasks such as RoslynCodeTaskFactory.
22+
testEnvironment.SetEnvironmentVariable("DOTNET_HOST_PATH", s_dotnetExePath);
23+
}
1824
#endif
1925

2026
/// <summary>

0 commit comments

Comments
 (0)