Skip to content

Commit ea7eee9

Browse files
committed
use reflection to find capable API if present
1 parent 52f3db2 commit ea7eee9

File tree

4 files changed

+76
-44
lines changed

4 files changed

+76
-44
lines changed

eng/Versions.props

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,16 @@
132132
<SystemFormatsAsn1Version>10.0.0-preview.7.25377.103</SystemFormatsAsn1Version>
133133
<!-- These are minimum versions used for netfx-targeted components that run in Visual Studio because in those cases,
134134
Visual Studio is providing those assemblies, and we should work with whichever version it ships. -->
135-
<MicrosoftBclAsyncInterfacesToolsetPackageVersion>9.0.0</MicrosoftBclAsyncInterfacesToolsetPackageVersion>
135+
<MicrosoftBclAsyncInterfacesToolsetPackageVersion>8.0.0</MicrosoftBclAsyncInterfacesToolsetPackageVersion>
136136
<MicrosoftDeploymentDotNetReleasesToolsetPackageVersion>2.0.0-preview.1.24427.4</MicrosoftDeploymentDotNetReleasesToolsetPackageVersion>
137137
<SystemBuffersToolsetPackageVersion>4.5.1</SystemBuffersToolsetPackageVersion>
138-
<SystemCollectionsImmutableToolsetPackageVersion>9.0.0</SystemCollectionsImmutableToolsetPackageVersion>
138+
<SystemCollectionsImmutableToolsetPackageVersion>8.0.0</SystemCollectionsImmutableToolsetPackageVersion>
139139
<SystemMemoryToolsetPackageVersion>4.5.5</SystemMemoryToolsetPackageVersion>
140-
<SystemReflectionMetadataLoadContextToolsetPackageVersion>9.0.0</SystemReflectionMetadataLoadContextToolsetPackageVersion>
141-
<SystemReflectionMetadataToolsetPackageVersion>9.0.0</SystemReflectionMetadataToolsetPackageVersion>
142-
<SystemTextJsonToolsetPackageVersion>9.0.0</SystemTextJsonToolsetPackageVersion>
140+
<SystemReflectionMetadataLoadContextToolsetPackageVersion>8.0.0</SystemReflectionMetadataLoadContextToolsetPackageVersion>
141+
<SystemReflectionMetadataToolsetPackageVersion>8.0.0</SystemReflectionMetadataToolsetPackageVersion>
142+
<SystemTextJsonToolsetPackageVersion>8.0.5</SystemTextJsonToolsetPackageVersion>
143143
<SystemThreadingTasksExtensionsToolsetPackageVersion>4.5.4</SystemThreadingTasksExtensionsToolsetPackageVersion>
144-
<SystemResourcesExtensionsToolsetPackageVersion>9.0.0</SystemResourcesExtensionsToolsetPackageVersion>
144+
<SystemResourcesExtensionsToolsetPackageVersion>8.0.0</SystemResourcesExtensionsToolsetPackageVersion>
145145
</PropertyGroup>
146146
<PropertyGroup>
147147
<!-- Dependencies from https://github.com/nuget/nuget.client -->
@@ -189,8 +189,7 @@
189189
Additionally, set the MinimumVSVersion for the installer UI that's required for targeting NetCurrent -->
190190
<MicrosoftBuildVersion>17.15.0-preview-25377-103</MicrosoftBuildVersion>
191191
<MicrosoftBuildLocalizationVersion>17.15.0-preview-25377-103</MicrosoftBuildLocalizationVersion>
192-
<!-- TODO: ensure the right version actually gets inserted -->
193-
<MicrosoftBuildMinimumVersion Condition="'$(DotNetBuildSourceOnly)' != 'true'">$(MicrosoftBuildVersion)</MicrosoftBuildMinimumVersion>
192+
<MicrosoftBuildMinimumVersion Condition="'$(DotNetBuildSourceOnly)' != 'true'">17.11.4</MicrosoftBuildMinimumVersion>
194193
<MinimumVSVersion>17.13</MinimumVSVersion>
195194
</PropertyGroup>
196195
<PropertyGroup>

src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/MSBuildSdkResolver.cs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,47 @@ public sealed class DotNetMSBuildSdkResolver : SdkResolver
3939
private const string SdkResolverGlobalJsonPath = "SdkResolverGlobalJsonPath";
4040
private static CachingWorkloadResolver _staticWorkloadResolver = new();
4141

42+
/// <summary>
43+
/// This is a workaround for MSBuild API compatibility in older VS hosts.
44+
/// To allow for working with the MSBuild 17.15 APIs while not blowing up our ability to build the SdkResolver in
45+
/// VS-driven CI pipelines, we probe and invoke only if the expected method is present.
46+
/// Once we can update our MSBuild API dependency this can go away.
47+
/// </summary>
48+
private static Func<
49+
SdkResultFactory,
50+
// path to sdk
51+
string,
52+
// sdk version
53+
string?,
54+
// properties to add
55+
IDictionary<string, string?>?,
56+
// items to add
57+
IDictionary<string, SdkResultItem>?,
58+
// warnings
59+
List<string>?,
60+
// environment variables to add
61+
IDictionary<string, string?>?,
62+
SdkResult>? _factorySuccessFunc = TryLocateNewMSBuildFactory();
63+
64+
private static Func<SdkResultFactory, string, string?, IDictionary<string, string?>?, IDictionary<string, SdkResultItem>?, List<string>?, IDictionary<string, string?>?, SdkResult>? TryLocateNewMSBuildFactory()
65+
{
66+
if (typeof(SdkResultFactory).GetMethod("IndicateSuccess", [
67+
typeof(string), // path to sdk
68+
typeof(string), // sdk version
69+
typeof(IDictionary<string, string>), // properties to add
70+
typeof(IDictionary<string, SdkResultItem>), // items to add
71+
typeof(List<string>), // warnings
72+
typeof(IDictionary<string, string>) // environment variables to add
73+
]) is MethodInfo m)
74+
{
75+
return (factory, path, version, properties, items, warnings, environmentVariables) =>
76+
{
77+
return (SdkResult)m.Invoke(factory, [path, version, properties, items, warnings, environmentVariables]);
78+
};
79+
}
80+
return null;
81+
}
82+
4283
private bool _shouldLog = false;
4384

4485
public DotNetMSBuildSdkResolver()
@@ -293,8 +334,14 @@ private sealed class CachedState
293334
Strings.MSBuildSDKDirectoryNotFound,
294335
msbuildSdkDir);
295336
}
296-
297-
return factory.IndicateSuccess(msbuildSdkDir, netcoreSdkVersion, propertiesToAdd, itemsToAdd, warnings, environmentVariablesToAdd: environmentVariablesToAdd);
337+
if (_factorySuccessFunc != null)
338+
{
339+
return _factorySuccessFunc.Invoke(factory, msbuildSdkDir, netcoreSdkVersion, propertiesToAdd, itemsToAdd, warnings, environmentVariablesToAdd);
340+
}
341+
else
342+
{
343+
return factory.IndicateSuccess(msbuildSdkDir, netcoreSdkVersion, propertiesToAdd, itemsToAdd, warnings);
344+
}
298345
}
299346

300347
/// <summary>

src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,18 @@
105105
</ResolveAssemblyReference>
106106

107107
<ItemGroup>
108-
<ExpectedDependencies Include="Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
109-
<ExpectedDependencies Include="Microsoft.Build.Framework, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
110108
<ExpectedDependencies Include="Microsoft.Deployment.DotNet.Releases, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
111-
<ExpectedDependencies Include="System.Buffers, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
112-
<ExpectedDependencies Include="System.Collections.Immutable, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
113-
<!-- <ExpectedDependencies Include="System.Diagnostics.DiagnosticSource, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" /> -->
114-
<ExpectedDependencies Include="System.IO.Pipelines, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
115-
<ExpectedDependencies Include="System.Memory, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
116-
<ExpectedDependencies Include="System.Numerics.Vectors, Version=4.1.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
117-
<ExpectedDependencies Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
118-
<ExpectedDependencies Include="System.Text.Encodings.Web, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
119-
<ExpectedDependencies Include="System.Text.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
109+
<ExpectedDependencies Include="System.Text.Json, Version=8.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
110+
<ExpectedDependencies Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
111+
<ExpectedDependencies Include="Microsoft.Build.Framework, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
112+
<ExpectedDependencies Include="System.Collections.Immutable, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
113+
<ExpectedDependencies Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
114+
<ExpectedDependencies Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
115+
<ExpectedDependencies Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
116+
<ExpectedDependencies Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
117+
<ExpectedDependencies Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
120118
<ExpectedDependencies Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
119+
<ExpectedDependencies Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
121120
</ItemGroup>
122121

123122
<!-- Check that the dependencies of the output assembly match our expectations -->

test/Microsoft.DotNet.MSBuildSdkResolver.Tests/GivenAnMSBuildSdkResolver.cs

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -205,14 +205,8 @@ public void ItReturnsHighestSdkAvailableThatIsCompatibleWithMSBuild(bool disallo
205205
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
206206
{
207207
// DotnetHost is the path to dotnet.exe. Can be only on Windows.
208-
result.PropertiesToAdd.Should().NotBeNull()
209-
.And.HaveCount(1)
210-
.And.NotContainKey(DotnetHostExperimentalKey);
211-
result.EnvironmentVariablesToAdd.Should().NotBeNull()
212-
.And.BeEquivalentTo(new Dictionary<string, string?>
213-
{
214-
["DOTNET_HOST"] = Path.Combine(environment.GetProgramFilesDirectory(ProgramFiles.X64).FullName, "dotnet", "dotnet.exe")
215-
});
208+
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(2);
209+
result.PropertiesToAdd.Should().ContainKey(DotnetHostExperimentalKey);
216210
}
217211
else
218212
{
@@ -237,9 +231,9 @@ public void WhenALocalSdkIsResolvedItReturnsHostFromThatSDKInsteadOfAmbientGloba
237231
var localSdkRoot = Path.Combine("some", "local", "dir");
238232
var localSdkDotnetRoot = Path.Combine(environment.TestDirectory.FullName, localSdkRoot, "dotnet");
239233
var ambientSdkDotnetRoot = Path.Combine(environment.GetProgramFilesDirectory(ProgramFiles.X64).FullName, "dotnet");
240-
var _ambientMSBuildSkRoot = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "1.2.3");
241-
var _localPathMSBuildSdkRoot = environment.CreateSdkDirectory(localSdkRoot, "Some.Test.Sdk", "1.2.4");
242-
var _ambientDotnetBinary = environment.CreateMuxerAndAddToPath(ProgramFiles.X64);
234+
var ambientMSBuildSkRoot = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "1.2.3");
235+
var localPathMSBuildSdkRoot = environment.CreateSdkDirectory(localSdkRoot, "Some.Test.Sdk", "1.2.4");
236+
var ambientDotnetBinary = environment.CreateMuxerAndAddToPath(ProgramFiles.X64);
243237
var localDotnetBinary = environment.CreateMuxer(localSdkRoot);
244238
environment.CreateGlobalJson(environment.TestDirectory, "1.2.3", [localSdkDotnetRoot, ambientSdkDotnetRoot]);
245239

@@ -255,11 +249,9 @@ public void WhenALocalSdkIsResolvedItReturnsHostFromThatSDKInsteadOfAmbientGloba
255249
context,
256250
new MockFactory());
257251
result.Success.Should().BeTrue();
258-
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(1).And.ContainKey(MSBuildTaskHostRuntimeVersion);
259-
result.EnvironmentVariablesToAdd.Should().NotBeNull().And.BeEquivalentTo(new Dictionary<string, string?>
260-
{
261-
[DotnetHostExperimentalKey] = localDotnetBinary
262-
});
252+
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(2);
253+
result.PropertiesToAdd.Should().ContainKey(DotnetHostExperimentalKey);
254+
result.PropertiesToAdd[DotnetHostExperimentalKey].Should().Be(localDotnetBinary);
263255
}
264256

265257
[Theory]
@@ -333,13 +325,8 @@ public void ItReturnsHighestSdkAvailableThatIsCompatibleWithMSBuildWhenVersionIn
333325
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
334326
{
335327
// DotnetHost is the path to dotnet.exe. Can be only on Windows.
336-
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(3);
337-
result.PropertiesToAdd.Should().NotContainKey(DotnetHostExperimentalKey);
338-
result.EnvironmentVariablesToAdd.Should().NotBeNull()
339-
.And.BeEquivalentTo(new Dictionary<string, string?>
340-
{
341-
["DOTNET_HOST"] = Path.Combine(environment.GetProgramFilesDirectory(ProgramFiles.X64).FullName, "dotnet", "dotnet.exe")
342-
});
328+
result.PropertiesToAdd.Should().NotBeNull().And.HaveCount(4);
329+
result.PropertiesToAdd.Should().ContainKey(DotnetHostExperimentalKey);
343330
}
344331
else
345332
{

0 commit comments

Comments
 (0)