2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
4
using System . Reflection ;
5
+ using System . Text . Json ;
5
6
using Microsoft . Build . Framework ;
6
7
using Microsoft . DotNet . Cli ;
7
8
using Microsoft . DotNet . Configurer ;
@@ -28,23 +29,28 @@ public sealed class DotNetMSBuildSdkResolver : SdkResolver
28
29
29
30
private readonly Func < string , string ? > _getEnvironmentVariable ;
30
31
private readonly Func < string > ? _getCurrentProcessPath ;
32
+ private readonly Func < string , string , string ? > _getMsbuildRuntime ;
31
33
private readonly NETCoreSdkResolver _netCoreSdkResolver ;
32
34
35
+ private const string DotnetHost = "DOTNET_HOST_PATH" ;
36
+ private const string MSBuildTaskHostRuntimeVersion = "SdkResolverMSBuildTaskHostRuntimeVersion" ;
37
+
33
38
private static CachingWorkloadResolver _staticWorkloadResolver = new ( ) ;
34
39
35
40
private bool _shouldLog = false ;
36
41
37
42
public DotNetMSBuildSdkResolver ( )
38
- : this ( Environment . GetEnvironmentVariable , null , VSSettings . Ambient )
43
+ : this ( Environment . GetEnvironmentVariable , null , GetMSbuildRuntimeVersion , VSSettings . Ambient )
39
44
{
40
45
}
41
46
42
47
// Test constructor
43
- public DotNetMSBuildSdkResolver ( Func < string , string ? > getEnvironmentVariable , Func < string > ? getCurrentProcessPath , VSSettings vsSettings )
48
+ public DotNetMSBuildSdkResolver ( Func < string , string ? > getEnvironmentVariable , Func < string > ? getCurrentProcessPath , Func < string , string , string ? > getMsbuildRuntime , VSSettings vsSettings )
44
49
{
45
50
_getEnvironmentVariable = getEnvironmentVariable ;
46
51
_getCurrentProcessPath = getCurrentProcessPath ;
47
52
_netCoreSdkResolver = new NETCoreSdkResolver ( getEnvironmentVariable , vsSettings ) ;
53
+ _getMsbuildRuntime = getMsbuildRuntime ;
48
54
49
55
if ( _getEnvironmentVariable ( EnvironmentVariableNames . DOTNET_MSBUILD_SDK_RESOLVER_ENABLE_LOG ) is string val &&
50
56
( string . Equals ( val , "true" , StringComparison . OrdinalIgnoreCase ) ||
@@ -190,6 +196,30 @@ private sealed class CachedState
190
196
minimumVSDefinedSDKVersion ) ;
191
197
}
192
198
199
+ string dotnetExe = Path . Combine ( dotnetRoot , Constants . DotNetExe ) ;
200
+ if ( File . Exists ( dotnetExe ) )
201
+ {
202
+ propertiesToAdd ??= new Dictionary < string , string ? > ( ) ;
203
+ propertiesToAdd . Add ( DotnetHost , dotnetExe ) ;
204
+ }
205
+ else
206
+ {
207
+ logger ? . LogMessage ( $ "Could not set '{ DotnetHost } ' because dotnet executable '{ dotnetExe } ' does not exist.") ;
208
+ }
209
+
210
+ string ? runtimeVersion = dotnetRoot != null ?
211
+ _getMsbuildRuntime ( resolverResult . ResolvedSdkDirectory , dotnetRoot ) :
212
+ null ;
213
+ if ( ! string . IsNullOrEmpty ( runtimeVersion ) )
214
+ {
215
+ propertiesToAdd ??= new Dictionary < string , string ? > ( ) ;
216
+ propertiesToAdd . Add ( MSBuildTaskHostRuntimeVersion , runtimeVersion ) ;
217
+ }
218
+ else
219
+ {
220
+ logger ? . LogMessage ( $ "Could not set '{ MSBuildTaskHostRuntimeVersion } ' because runtime version could not be determined.") ;
221
+ }
222
+
193
223
if ( resolverResult . FailedToResolveSDKSpecifiedInGlobalJson )
194
224
{
195
225
logger ? . LogMessage ( $ "Could not resolve SDK specified in '{ resolverResult . GlobalJsonPath } '. Ignoring global.json for this resolution.") ;
@@ -208,10 +238,7 @@ private sealed class CachedState
208
238
warnings . Add ( Strings . GlobalJsonResolutionFailed ) ;
209
239
}
210
240
211
- if ( propertiesToAdd == null )
212
- {
213
- propertiesToAdd = new Dictionary < string , string ? > ( ) ;
214
- }
241
+ propertiesToAdd ??= new Dictionary < string , string ? > ( ) ;
215
242
propertiesToAdd . Add ( "SdkResolverHonoredGlobalJson" , "false" ) ;
216
243
propertiesToAdd . Add ( "SdkResolverGlobalJsonPath" , resolverResult . GlobalJsonPath ) ;
217
244
@@ -259,6 +286,28 @@ private sealed class CachedState
259
286
return factory . IndicateSuccess ( msbuildSdkDir , netcoreSdkVersion , propertiesToAdd , itemsToAdd , warnings ) ;
260
287
}
261
288
289
+ private static string ? GetMSbuildRuntimeVersion ( string sdkDirectory , string dotnetRoot )
290
+ {
291
+ // 1. Get the runtime version from the MSBuild.runtimeconfig.json file
292
+ string runtimeConfigPath = Path . Combine ( sdkDirectory , "MSBuild.runtimeconfig.json" ) ;
293
+ if ( ! File . Exists ( runtimeConfigPath ) ) return null ;
294
+
295
+ using var stream = File . OpenRead ( runtimeConfigPath ) ;
296
+ using var jsonDoc = JsonDocument . Parse ( stream ) ;
297
+
298
+ JsonElement root = jsonDoc . RootElement ;
299
+ if ( ! root . TryGetProperty ( "runtimeOptions" , out JsonElement runtimeOptions ) ||
300
+ ! runtimeOptions . TryGetProperty ( "framework" , out JsonElement framework ) ) return null ;
301
+
302
+ string ? runtimeName = framework . GetProperty ( "name" ) . GetString ( ) ;
303
+ string ? runtimeVersion = framework . GetProperty ( "version" ) . GetString ( ) ;
304
+
305
+ // 2. Check that the runtime version is installed (in shared folder)
306
+ return ( ! string . IsNullOrEmpty ( runtimeName ) && ! string . IsNullOrEmpty ( runtimeVersion ) &&
307
+ Directory . Exists ( Path . Combine ( dotnetRoot , "shared" , runtimeName , runtimeVersion ) ) )
308
+ ? runtimeVersion : null ;
309
+ }
310
+
262
311
private static SdkResult Failure ( SdkResultFactory factory , ResolverLogger ? logger , SdkLogger sdkLogger , string format , params object ? [ ] args )
263
312
{
264
313
string error = string . Format ( format , args ) ;
0 commit comments