Skip to content

Use SdkResolver APIs for reporting environment variables #49866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: darc-main-7628065e-94f2-4f11-a6d5-3ab587167c53
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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 build.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ if %errorlevel%==0 (
set skipFlags="/p:SkipUsingCrossgen=true /p:SkipBuildingInstallers=true"
)
set DOTNET_SYSTEM_NET_SECURITY_NOREVOCATIONCHECKBYDEFAULT=true
powershell -NoLogo -NoProfile -ExecutionPolicy ByPass -command "& """%~dp0eng\common\build.ps1""" -restore -build -msbuildEngine dotnet %skipFlags% %*"
powershell -NoLogo -NoProfile -ExecutionPolicy ByPass -command "& """%~dp0eng\common\build.ps1""" -restore -build -msbuildEngine dotnet %skipFlags% /tlp:summary %*"
exit /b %ErrorLevel%
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ if [[ "$@" != *"-pack"* ]]; then
fi

export DOTNET_SYSTEM_NET_SECURITY_NOREVOCATIONCHECKBYDEFAULT="true"
. "$ScriptRoot/eng/common/build.sh" --build --restore $skipFlags "$@"
. "$ScriptRoot/eng/common/build.sh" --build --restore $skipFlags /tlp:summary "$@"
15 changes: 8 additions & 7 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,16 @@
<SystemFormatsAsn1Version>10.0.0-preview.7.25367.101</SystemFormatsAsn1Version>
<!-- These are minimum versions used for netfx-targeted components that run in Visual Studio because in those cases,
Visual Studio is providing those assemblies, and we should work with whichever version it ships. -->
<MicrosoftBclAsyncInterfacesToolsetPackageVersion>8.0.0</MicrosoftBclAsyncInterfacesToolsetPackageVersion>
<MicrosoftBclAsyncInterfacesToolsetPackageVersion>9.0.0</MicrosoftBclAsyncInterfacesToolsetPackageVersion>
<MicrosoftDeploymentDotNetReleasesToolsetPackageVersion>2.0.0-preview.1.24427.4</MicrosoftDeploymentDotNetReleasesToolsetPackageVersion>
<SystemBuffersToolsetPackageVersion>4.5.1</SystemBuffersToolsetPackageVersion>
<SystemCollectionsImmutableToolsetPackageVersion>8.0.0</SystemCollectionsImmutableToolsetPackageVersion>
<SystemCollectionsImmutableToolsetPackageVersion>9.0.0</SystemCollectionsImmutableToolsetPackageVersion>
<SystemMemoryToolsetPackageVersion>4.5.5</SystemMemoryToolsetPackageVersion>
<SystemReflectionMetadataLoadContextToolsetPackageVersion>8.0.0</SystemReflectionMetadataLoadContextToolsetPackageVersion>
<SystemReflectionMetadataToolsetPackageVersion>8.0.0</SystemReflectionMetadataToolsetPackageVersion>
<SystemTextJsonToolsetPackageVersion>8.0.5</SystemTextJsonToolsetPackageVersion>
<SystemReflectionMetadataLoadContextToolsetPackageVersion>9.0.0</SystemReflectionMetadataLoadContextToolsetPackageVersion>
<SystemReflectionMetadataToolsetPackageVersion>9.0.0</SystemReflectionMetadataToolsetPackageVersion>
<SystemTextJsonToolsetPackageVersion>9.0.0</SystemTextJsonToolsetPackageVersion>
<SystemThreadingTasksExtensionsToolsetPackageVersion>4.5.4</SystemThreadingTasksExtensionsToolsetPackageVersion>
<SystemResourcesExtensionsToolsetPackageVersion>8.0.0</SystemResourcesExtensionsToolsetPackageVersion>
<SystemResourcesExtensionsToolsetPackageVersion>9.0.0</SystemResourcesExtensionsToolsetPackageVersion>
Comment on lines -136 to +145
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is the scary stuff @rainersigwald @YuliiaKovalova @marcpopMSFT @jaredpar

How do we usually navigate/negotiate bumps to these shared dependencies between MSBuild/Roslyn/SDK/VS?

</PropertyGroup>
<PropertyGroup>
<!-- Dependencies from https://github.com/nuget/nuget.client -->
Expand Down Expand Up @@ -190,7 +190,8 @@
Additionally, set the MinimumVSVersion for the installer UI that's required for targeting NetCurrent -->
<MicrosoftBuildVersion>17.15.0-preview-25368-01</MicrosoftBuildVersion>
<MicrosoftBuildLocalizationVersion>17.15.0-preview-25368-01</MicrosoftBuildLocalizationVersion>
<MicrosoftBuildMinimumVersion Condition="'$(DotNetBuildSourceOnly)' != 'true'">17.11.4</MicrosoftBuildMinimumVersion>
<!-- TODO: ensure the right version actually gets inserted -->
<MicrosoftBuildMinimumVersion Condition="'$(DotNetBuildSourceOnly)' != 'true'">$(MicrosoftBuildVersion)</MicrosoftBuildMinimumVersion>
<MinimumVSVersion>17.13</MinimumVSVersion>
</PropertyGroup>
<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ public sealed class DotNetMSBuildSdkResolver : SdkResolver
private readonly Func<string, string, string?> _getMsbuildRuntime;
private readonly NETCoreSdkResolver _netCoreSdkResolver;

private const string DOTNET_HOST = nameof(DOTNET_HOST);
private const string DotnetHostExperimentalKey = "DOTNET_EXPERIMENTAL_HOST_PATH";
private const string MSBuildTaskHostRuntimeVersion = "SdkResolverMSBuildTaskHostRuntimeVersion";

private const string SdkResolverHonoredGlobalJson = "SdkResolverHonoredGlobalJson";
private const string SdkResolverGlobalJsonPath = "SdkResolverGlobalJsonPath";
private static CachingWorkloadResolver _staticWorkloadResolver = new();

private bool _shouldLog = false;
Expand Down Expand Up @@ -68,6 +70,7 @@ private sealed class CachedState
public string? GlobalJsonPath;
public IDictionary<string, string?>? PropertiesToAdd;
public CachingWorkloadResolver? WorkloadResolver;
public IDictionary<string, string?>? EnvironmentVariablesToAdd;
}

public override SdkResult? Resolve(SdkReference sdkReference, SdkResolverContext context, SdkResultFactory factory)
Expand All @@ -78,6 +81,7 @@ private sealed class CachedState
string? globalJsonPath = null;
IDictionary<string, string?>? propertiesToAdd = null;
IDictionary<string, SdkResultItem>? itemsToAdd = null;
IDictionary<string, string?>? environmentVariablesToAdd = null;
List<string>? warnings = null;
CachingWorkloadResolver? workloadResolver = null;

Expand All @@ -99,6 +103,7 @@ private sealed class CachedState
globalJsonPath = priorResult.GlobalJsonPath;
propertiesToAdd = priorResult.PropertiesToAdd;
workloadResolver = priorResult.WorkloadResolver;
environmentVariablesToAdd = priorResult.EnvironmentVariablesToAdd;

logger?.LogMessage($"\tDotnet root: {dotnetRoot}");
logger?.LogMessage($"\tMSBuild SDKs Dir: {msbuildSdksDir}");
Expand Down Expand Up @@ -139,9 +144,9 @@ private sealed class CachedState
logger?.LogMessage($"\tResolved SDK directory: {resolverResult.ResolvedSdkDirectory}");
logger?.LogMessage($"\tglobal.json path: {resolverResult.GlobalJsonPath}");
logger?.LogMessage($"\tFailed to resolve SDK from global.json: {resolverResult.FailedToResolveSDKSpecifiedInGlobalJson}");

msbuildSdksDir = Path.Combine(resolverResult.ResolvedSdkDirectory, "Sdks");
netcoreSdkVersion = new DirectoryInfo(resolverResult.ResolvedSdkDirectory).Name;
string dotnetSdkDir = resolverResult.ResolvedSdkDirectory;
msbuildSdksDir = Path.Combine(dotnetSdkDir, "Sdks");
netcoreSdkVersion = new DirectoryInfo(dotnetSdkDir).Name;
globalJsonPath = resolverResult.GlobalJsonPath;

// These are overrides that are used to force the resolved SDK tasks and targets to come from a given
Expand Down Expand Up @@ -197,20 +202,22 @@ private sealed class CachedState
}

string? fullPathToMuxer =
TryResolveMuxerFromSdkResolution(resolverResult)
TryResolveMuxerFromSdkResolution(dotnetSdkDir)
?? Path.Combine(dotnetRoot, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Constants.DotNetExe : Constants.DotNet);
if (File.Exists(fullPathToMuxer))
{
propertiesToAdd ??= new Dictionary<string, string?>();
propertiesToAdd.Add(DotnetHostExperimentalKey, fullPathToMuxer);
environmentVariablesToAdd ??= new Dictionary<string, string?>(1)
{
[DOTNET_HOST] = fullPathToMuxer
};
}
else
{
logger?.LogMessage($"Could not set '{DotnetHostExperimentalKey}' because dotnet executable '{fullPathToMuxer}' does not exist.");
logger?.LogMessage($"Could not set '{DOTNET_HOST}' environment variable because dotnet executable '{fullPathToMuxer}' does not exist.");
}

string? runtimeVersion = dotnetRoot != null ?
_getMsbuildRuntime(resolverResult.ResolvedSdkDirectory, dotnetRoot) :
_getMsbuildRuntime(dotnetSdkDir, dotnetRoot) :
null;
if (!string.IsNullOrEmpty(runtimeVersion))
{
Expand All @@ -224,7 +231,7 @@ private sealed class CachedState

if (resolverResult.FailedToResolveSDKSpecifiedInGlobalJson)
{
logger?.LogMessage($"Could not resolve SDK specified in '{resolverResult.GlobalJsonPath}'. Ignoring global.json for this resolution.");
logger?.LogMessage($"Could not resolve SDK specified in '{globalJsonPath}'. Ignoring global.json for this resolution.");

if (warnings == null)
{
Expand All @@ -241,8 +248,9 @@ private sealed class CachedState
}

propertiesToAdd ??= new Dictionary<string, string?>();
propertiesToAdd.Add("SdkResolverHonoredGlobalJson", "false");
propertiesToAdd.Add("SdkResolverGlobalJsonPath", resolverResult.GlobalJsonPath);
propertiesToAdd.Add(SdkResolverHonoredGlobalJson, "false");
// TODO: this would ideally be reported anytime it was non-null - that may cause more imports though?
propertiesToAdd.Add(SdkResolverGlobalJsonPath, globalJsonPath);

if (logger != null)
{
Expand All @@ -258,7 +266,8 @@ private sealed class CachedState
NETCoreSdkVersion = netcoreSdkVersion,
GlobalJsonPath = globalJsonPath,
PropertiesToAdd = propertiesToAdd,
WorkloadResolver = workloadResolver
WorkloadResolver = workloadResolver,
EnvironmentVariablesToAdd = environmentVariablesToAdd
};

// First check if requested SDK resolves to a workload SDK pack
Expand All @@ -285,7 +294,7 @@ private sealed class CachedState
msbuildSdkDir);
}

return factory.IndicateSuccess(msbuildSdkDir, netcoreSdkVersion, propertiesToAdd, itemsToAdd, warnings);
return factory.IndicateSuccess(msbuildSdkDir, netcoreSdkVersion, propertiesToAdd, itemsToAdd, warnings, environmentVariablesToAdd: environmentVariablesToAdd);
}

/// <summary>
Expand All @@ -295,10 +304,10 @@ private sealed class CachedState
/// SDK layouts always have a defined relationship to the location of the muxer -
/// the muxer binary should be exactly two directories above the SDK directory.
/// </remarks>
private static string? TryResolveMuxerFromSdkResolution(SdkResolutionResult resolverResult)
private static string? TryResolveMuxerFromSdkResolution(string resolvedSdkDirectory)
{
var expectedFileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Constants.DotNetExe : Constants.DotNet;
var currentDir = resolverResult.ResolvedSdkDirectory;
var currentDir = resolvedSdkDirectory;
var expectedDotnetRoot = Path.GetDirectoryName(Path.GetDirectoryName(currentDir));
var expectedMuxerPath = Path.Combine(expectedDotnetRoot, expectedFileName);
if (File.Exists(expectedMuxerPath))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,18 +105,19 @@
</ResolveAssemblyReference>

<ItemGroup>
<ExpectedDependencies Include="Microsoft.Deployment.DotNet.Releases, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<ExpectedDependencies Include="System.Text.Json, Version=8.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="Microsoft.Build.Framework, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<ExpectedDependencies Include="System.Collections.Immutable, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<ExpectedDependencies Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<ExpectedDependencies Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<ExpectedDependencies Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="Microsoft.Deployment.DotNet.Releases, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<ExpectedDependencies Include="System.Buffers, Version=4.0.4.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.Collections.Immutable, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<ExpectedDependencies Include="System.Diagnostics.DiagnosticSource, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.IO.Pipelines, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.Memory, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.Numerics.Vectors, Version=4.1.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<ExpectedDependencies Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<ExpectedDependencies Include="System.Text.Encodings.Web, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.Text.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<ExpectedDependencies Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
</ItemGroup>

<!-- Check that the dependencies of the output assembly match our expectations -->
Expand All @@ -127,9 +128,11 @@
</PropertyGroup>

<Error Text="$(AssemblyName) is expected to depend on %(ExpectedDependencies.Identity). $(DependencyMismatchErrorText)"
Condition="!($([System.String]::Copy('$(ResolvedDependenciesList)').Contains('%(ExpectedDependencies.Identity)')))" />
Condition="!($([System.String]::Copy('$(ResolvedDependenciesList)').Contains('%(ExpectedDependencies.Identity)')))"
ContinueOnError="true" />
<Error Text="$(AssemblyName) is not expected to depend on %(ResolvedDependencies.FusionName). $(DependencyMismatchErrorText)"
Condition="!($([System.String]::Copy('$(ExpectedDependenciesList)').Contains('%(ResolvedDependencies.FusionName)')))" />
Condition="!($([System.String]::Copy('$(ExpectedDependenciesList)').Contains('%(ResolvedDependencies.FusionName)')))"
ContinueOnError="true" />
</Target>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,14 @@ public void ItReturnsHighestSdkAvailableThatIsCompatibleWithMSBuild(bool disallo
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// DotnetHost is the path to dotnet.exe. Can be only on Windows.
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(2);
result.PropertiesToAdd.Should().ContainKey(DotnetHostExperimentalKey);
result.PropertiesToAdd.Should().NotBeNull()
.And.HaveCount(1)
.And.NotContainKey(DotnetHostExperimentalKey);
result.EnvironmentVariablesToAdd.Should().NotBeNull()
.And.BeEquivalentTo(new Dictionary<string, string?>
{
["DOTNET_HOST"] = Path.Combine(environment.GetProgramFilesDirectory(ProgramFiles.X64).FullName, "dotnet", "dotnet.exe")
});
}
else
{
Expand All @@ -231,9 +237,9 @@ public void WhenALocalSdkIsResolvedItReturnsHostFromThatSDKInsteadOfAmbientGloba
var localSdkRoot = Path.Combine("some", "local", "dir");
var localSdkDotnetRoot = Path.Combine(environment.TestDirectory.FullName, localSdkRoot, "dotnet");
var ambientSdkDotnetRoot = Path.Combine(environment.GetProgramFilesDirectory(ProgramFiles.X64).FullName, "dotnet");
var ambientMSBuildSkRoot = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "1.2.3");
var localPathMSBuildSdkRoot = environment.CreateSdkDirectory(localSdkRoot, "Some.Test.Sdk", "1.2.4");
var ambientDotnetBinary = environment.CreateMuxerAndAddToPath(ProgramFiles.X64);
var _ambientMSBuildSkRoot = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "1.2.3");
var _localPathMSBuildSdkRoot = environment.CreateSdkDirectory(localSdkRoot, "Some.Test.Sdk", "1.2.4");
var _ambientDotnetBinary = environment.CreateMuxerAndAddToPath(ProgramFiles.X64);
var localDotnetBinary = environment.CreateMuxer(localSdkRoot);
environment.CreateGlobalJson(environment.TestDirectory, "1.2.3", [localSdkDotnetRoot, ambientSdkDotnetRoot]);

Expand All @@ -249,9 +255,11 @@ public void WhenALocalSdkIsResolvedItReturnsHostFromThatSDKInsteadOfAmbientGloba
context,
new MockFactory());
result.Success.Should().BeTrue();
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(2);
result.PropertiesToAdd.Should().ContainKey(DotnetHostExperimentalKey);
result.PropertiesToAdd[DotnetHostExperimentalKey].Should().Be(localDotnetBinary);
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(1).And.ContainKey(MSBuildTaskHostRuntimeVersion);
result.EnvironmentVariablesToAdd.Should().NotBeNull().And.BeEquivalentTo(new Dictionary<string, string?>
{
[DotnetHostExperimentalKey] = localDotnetBinary
});
}

[Theory]
Expand Down Expand Up @@ -325,8 +333,13 @@ public void ItReturnsHighestSdkAvailableThatIsCompatibleWithMSBuildWhenVersionIn
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// DotnetHost is the path to dotnet.exe. Can be only on Windows.
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(4);
result.PropertiesToAdd.Should().ContainKey(DotnetHostExperimentalKey);
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(3);
result.PropertiesToAdd.Should().NotContainKey(DotnetHostExperimentalKey);
result.EnvironmentVariablesToAdd.Should().NotBeNull()
.And.BeEquivalentTo(new Dictionary<string, string?>
{
["DOTNET_HOST"] = Path.Combine(environment.GetProgramFilesDirectory(ProgramFiles.X64).FullName, "dotnet", "dotnet.exe")
});
}
else
{
Expand Down