@@ -19,7 +19,8 @@ internal class SdkInstallCommand(ParseResult result) : CommandBase(result)
1919 private readonly bool ? _updateGlobalJson = result . GetValue ( SdkInstallCommandParser . UpdateGlobalJsonOption ) ;
2020 private readonly bool _interactive = result . GetValue ( SdkInstallCommandParser . InteractiveOption ) ;
2121
22-
22+ private readonly IDotnetInstaller _dotnetInstaller = new EnvironmentVariableMockDotnetInstaller ( ) ;
23+ private readonly IReleaseInfoProvider _releaseInfoProvider = new EnvironmentVariableMockReleaseInfoProvider ( ) ;
2324
2425 public override int Execute ( )
2526 {
@@ -33,17 +34,17 @@ public override int Execute()
3334
3435 //Reporter.Output.WriteLine($"Update global.json: {_updateGlobalJson}");
3536
36- string ? globalJsonPath = FindGlobalJson ( ) ;
37+ var globalJsonInfo = _dotnetInstaller . GetGlobalJsonInfo ( Environment . CurrentDirectory ) ;
3738
3839 string ? currentInstallPath ;
39- DefaultInstall defaultInstallState = GetDefaultInstallState ( out currentInstallPath ) ;
40+ SdkInstallType defaultInstallState = _dotnetInstaller . GetConfiguredInstallType ( out currentInstallPath ) ;
4041
4142 string ? resolvedInstallPath = null ;
4243
4344 string ? installPathFromGlobalJson = null ;
44- if ( globalJsonPath != null )
45+ if ( globalJsonInfo ? . GlobalJsonPath != null )
4546 {
46- installPathFromGlobalJson = ResolveInstallPathFromGlobalJson ( globalJsonPath ) ;
47+ installPathFromGlobalJson = globalJsonInfo . SdkPath ;
4748
4849 if ( installPathFromGlobalJson != null && _installPath != null &&
4950 // TODO: Is there a better way to compare paths that takes into account whether the file system is case-sensitive?
@@ -62,7 +63,7 @@ public override int Execute()
6263 resolvedInstallPath = _installPath ;
6364 }
6465
65- if ( resolvedInstallPath == null && defaultInstallState == DefaultInstall . User )
66+ if ( resolvedInstallPath == null && defaultInstallState == SdkInstallType . User )
6667 {
6768 // If a user installation is already set up, we don't need to prompt for the install path
6869 resolvedInstallPath = currentInstallPath ;
@@ -74,19 +75,19 @@ public override int Execute()
7475 {
7576 resolvedInstallPath = SpectreAnsiConsole . Prompt (
7677 new TextPrompt < string > ( "Where should we install the .NET SDK to?)" )
77- . DefaultValue ( GetDefaultInstallPath ( ) ) ) ;
78+ . DefaultValue ( _dotnetInstaller . GetDefaultDotnetInstallPath ( ) ) ) ;
7879 }
7980 else
8081 {
8182 // If no install path is specified, use the default install path
82- resolvedInstallPath = GetDefaultInstallPath ( ) ;
83+ resolvedInstallPath = _dotnetInstaller . GetDefaultDotnetInstallPath ( ) ;
8384 }
8485 }
8586
8687 string ? channelFromGlobalJson = null ;
87- if ( globalJsonPath != null )
88+ if ( globalJsonInfo ? . GlobalJsonPath != null )
8889 {
89- channelFromGlobalJson = ResolveChannelFromGlobalJson ( globalJsonPath ) ;
90+ channelFromGlobalJson = ResolveChannelFromGlobalJson ( globalJsonInfo . GlobalJsonPath ) ;
9091 }
9192
9293 bool ? resolvedUpdateGlobalJson = null ;
@@ -107,7 +108,7 @@ public override int Execute()
107108
108109 if ( channelFromGlobalJson != null )
109110 {
110- SpectreAnsiConsole . WriteLine ( $ ".NET SDK { channelFromGlobalJson } will be installed since { globalJsonPath } specifies that version.") ;
111+ SpectreAnsiConsole . WriteLine ( $ ".NET SDK { channelFromGlobalJson } will be installed since { globalJsonInfo ? . GlobalJsonPath } specifies that version.") ;
111112
112113 resolvedChannel = channelFromGlobalJson ;
113114 }
@@ -120,7 +121,7 @@ public override int Execute()
120121 if ( _interactive )
121122 {
122123
123- SpectreAnsiConsole . WriteLine ( "Available supported channels: " + string . Join ( ' ' , GetAvailableChannels ( ) ) ) ;
124+ SpectreAnsiConsole . WriteLine ( "Available supported channels: " + string . Join ( ' ' , _releaseInfoProvider . GetAvailableChannels ( ) ) ) ;
124125 SpectreAnsiConsole . WriteLine ( "You can also specify a specific version (for example 9.0.304)." ) ;
125126
126127 resolvedChannel = SpectreAnsiConsole . Prompt (
@@ -140,13 +141,13 @@ public override int Execute()
140141 // If global.json specified an install path, we don't prompt for setting the default install path (since you probably don't want to do that for a repo-local path)
141142 if ( _interactive && installPathFromGlobalJson == null )
142143 {
143- if ( defaultInstallState == DefaultInstall . None )
144+ if ( defaultInstallState == SdkInstallType . None )
144145 {
145146 resolvedSetDefaultInstall = SpectreAnsiConsole . Confirm (
146147 $ "Do you want to set the install path ({ resolvedInstallPath } ) as the default dotnet install? This will update the PATH and DOTNET_ROOT environment variables.",
147148 defaultValue : true ) ;
148149 }
149- else if ( defaultInstallState == DefaultInstall . User )
150+ else if ( defaultInstallState == SdkInstallType . User )
150151 {
151152 // Another case where we need to compare paths and the comparison may or may not need to be case-sensitive
152153 if ( resolvedInstallPath . Equals ( currentInstallPath , StringComparison . OrdinalIgnoreCase ) )
@@ -160,7 +161,7 @@ public override int Execute()
160161 defaultValue : false ) ;
161162 }
162163 }
163- else if ( defaultInstallState == DefaultInstall . Admin )
164+ else if ( defaultInstallState == SdkInstallType . Admin )
164165 {
165166 SpectreAnsiConsole . WriteLine ( $ "You have an existing admin install of .NET in { currentInstallPath } . We can configure your system to use the new install of .NET " +
166167 $ "in { resolvedInstallPath } instead. This would mean that the admin install of .NET would no longer be accessible from the PATH or from Visual Studio.") ;
@@ -169,7 +170,7 @@ public override int Execute()
169170 $ "Do you want to set the user install path ({ resolvedInstallPath } ) as the default dotnet install? This will update the PATH and DOTNET_ROOT environment variables.",
170171 defaultValue : true ) ;
171172 }
172- else if ( defaultInstallState == DefaultInstall . Inconsistent )
173+ else if ( defaultInstallState == SdkInstallType . Inconsistent )
173174 {
174175 // TODO: Figure out what to do here
175176 resolvedSetDefaultInstall = false ;
@@ -183,14 +184,14 @@ public override int Execute()
183184
184185 List < string > additionalVersionsToInstall = new ( ) ;
185186
186- var resolvedChannelVersion = ResolveChannelVersion ( resolvedChannel ) ;
187+ var resolvedChannelVersion = _releaseInfoProvider . GetLatestVersion ( resolvedChannel ) ;
187188
188- if ( resolvedSetDefaultInstall == true && defaultInstallState == DefaultInstall . Admin )
189+ if ( resolvedSetDefaultInstall == true && defaultInstallState == SdkInstallType . Admin )
189190 {
190191 if ( _interactive )
191192 {
192- var latestAdminVersion = GetLatestInstalledAdminVersion ( ) ;
193- if ( new ReleaseVersion ( resolvedChannelVersion ) < new ReleaseVersion ( latestAdminVersion ) )
193+ var latestAdminVersion = _dotnetInstaller . GetLatestInstalledAdminVersion ( ) ;
194+ if ( latestAdminVersion != null && new ReleaseVersion ( resolvedChannelVersion ) < new ReleaseVersion ( latestAdminVersion ) )
194195 {
195196 SpectreAnsiConsole . WriteLine ( $ "Since the admin installs of the .NET SDK will no longer be accessible, we recommend installing the latest admin installed " +
196197 $ "version ({ latestAdminVersion } ) to the new user install location. This will make sure this version of the .NET SDK continues to be used for projects that don't specify a .NET SDK version in global.json.") ;
@@ -208,7 +209,7 @@ public override int Execute()
208209 }
209210 }
210211
211-
212+
212213
213214 SpectreAnsiConsole . MarkupInterpolated ( $ "Installing .NET SDK [blue]{ resolvedChannelVersion } [/] to [blue]{ resolvedInstallPath } [/]...") ;
214215
@@ -225,12 +226,12 @@ public override int Execute()
225226 List < Action > additionalDownloads = additionalVersionsToInstall . Select ( version =>
226227 {
227228 var additionalTask = ctx . AddTask ( $ "Downloading .NET SDK { version } ") ;
228- return ( Action ) ( ( ) =>
229+ return ( Action ) ( ( ) =>
229230 {
230231 Download ( downloadLink , httpClient , additionalTask ) ;
231232 } ) ;
232233 } ) . ToList ( ) ;
233-
234+
234235 Download ( downloadLink , httpClient , task ) ;
235236
236237
@@ -272,107 +273,108 @@ void Download(string url, HttpClient httpClient, ProgressTask task)
272273 // }
273274 //}
274275
275- for ( int i = 0 ; i < 100 ; i ++ )
276+ for ( int i = 0 ; i < 100 ; i ++ )
276277 {
277278 task . Increment ( 1 ) ;
278279 Thread . Sleep ( 20 ) ; // Simulate some work
279280 }
280281 task . Value = 100 ;
281282 }
282283
283-
284- string ? FindGlobalJson ( )
285- {
286- //return null;
287- return @"d:\git\dotnet-sdk\global.json" ;
288- }
289-
290- string ? ResolveInstallPathFromGlobalJson ( string globalJsonPath )
291- {
292- return Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_GLOBALJSON_SDK_INSTALL_PATH" ) ;
293- }
294-
295284 string ? ResolveChannelFromGlobalJson ( string globalJsonPath )
296285 {
297286 //return null;
298287 //return "9.0";
299288 return Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_GLOBALJSON_SDK_CHANNEL" ) ;
300289 }
301290
302- string GetDefaultInstallPath ( )
303- {
304- return Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , "dotnet" ) ;
305- }
306-
307- List < string > GetAvailableChannels ( )
291+ bool IsElevated ( )
308292 {
309- return [ "latest" , "preview" , "10" , "10.0.1xx" , "10.0.2xx" , "9" , "9.0.3xx" , "9.0.2xx" , "9.0.1xx" ] ;
293+ return false ;
310294 }
311295
312- string ResolveChannelVersion ( string channel )
296+ class EnvironmentVariableMockDotnetInstaller : IDotnetInstaller
313297 {
314- if ( channel == "preview" )
315- {
316- return "11.0.100-preview.1.42424" ;
317- }
318- else if ( channel == "latest" || channel == "10" || channel == "10.0.2xx" )
298+ public GlobalJsonInfo GetGlobalJsonInfo ( string initialDirectory )
319299 {
320- return "10.0.203" ;
321- }
322- else if ( channel == "10.0.1xx" )
323- {
324- return "10.0.106" ;
325- }
326- else if ( channel == "9" || channel == "9.0.3xx" )
327- {
328- return "9.0.309" ;
300+ return new GlobalJsonInfo
301+ {
302+ GlobalJsonPath = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_GLOBALJSON_PATH" ) ,
303+ SdkVersion = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_GLOBALJSON_SDK_VERSION" ) ,
304+ AllowPrerelease = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_GLOBALJSON_ALLOW_PRERELEASE" ) ,
305+ RollForward = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_GLOBALJSON_ROLLFORWARD" ) ,
306+ SdkPath = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_GLOBALJSON_SDK_INSTALL_PATH" )
307+ } ;
329308 }
330- else if ( channel == "9.0.2xx" )
309+
310+ public string GetDefaultDotnetInstallPath ( )
331311 {
332- return "9.0.212" ;
312+ return Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , "dotnet" ) ;
333313 }
334- else if ( channel == "9.0.1xx" )
314+
315+ public SdkInstallType GetConfiguredInstallType ( out string ? currentInstallPath )
335316 {
336- return "9.0.115" ;
317+ var testHookDefaultInstall = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_DEFAULT_INSTALL" ) ;
318+ SdkInstallType returnValue = SdkInstallType . None ;
319+ if ( ! Enum . TryParse < SdkInstallType > ( testHookDefaultInstall , out returnValue ) )
320+ {
321+ returnValue = SdkInstallType . None ;
322+ }
323+ currentInstallPath = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_CURRENT_INSTALL_PATH" ) ;
324+ return returnValue ;
337325 }
338326
339- return channel ;
340-
341- }
342-
343- enum DefaultInstall
344- {
345- None ,
346- // Inconsistent would be when the dotnet on the path doesn't match what DOTNET_ROOT is set to
347- Inconsistent ,
348- Admin ,
349- User
350- }
351327
352- DefaultInstall GetDefaultInstallState ( out string ? currentInstallPath )
353- {
354- var testHookDefaultInstall = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_DEFAULT_INSTALL" ) ;
355- DefaultInstall returnValue = DefaultInstall . None ;
356- if ( ! Enum . TryParse < DefaultInstall > ( testHookDefaultInstall , out returnValue ) )
328+ public string ? GetLatestInstalledAdminVersion ( )
357329 {
358- returnValue = DefaultInstall . None ;
330+ var latestAdminVersion = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_LATEST_ADMIN_VERSION" ) ;
331+ if ( string . IsNullOrEmpty ( latestAdminVersion ) )
332+ {
333+ latestAdminVersion = "10.0.203" ;
334+ }
335+ return latestAdminVersion ;
359336 }
360- currentInstallPath = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_CURRENT_INSTALL_PATH" ) ;
361- return returnValue ;
362337 }
363338
364- string GetLatestInstalledAdminVersion ( )
339+ class EnvironmentVariableMockReleaseInfoProvider : IReleaseInfoProvider
365340 {
366- var latestAdminVersion = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_LATEST_ADMIN_VERSION" ) ;
367- if ( string . IsNullOrEmpty ( latestAdminVersion ) )
341+ public List < string > GetAvailableChannels ( )
368342 {
369- latestAdminVersion = "10.0.203" ;
343+ var channels = Environment . GetEnvironmentVariable ( "DOTNET_TESTHOOK_AVAILABLE_CHANNELS" ) ;
344+ if ( string . IsNullOrEmpty ( channels ) )
345+ {
346+ return [ "latest" , "preview" , "10" , "10.0.1xx" , "10.0.2xx" , "9" , "9.0.3xx" , "9.0.2xx" , "9.0.1xx" ] ;
347+ }
348+ return channels . Split ( ',' ) . ToList ( ) ;
370349 }
371- return latestAdminVersion ;
372- }
350+ public string GetLatestVersion ( string channel )
351+ {
352+ if ( channel == "preview" )
353+ {
354+ return "11.0.100-preview.1.42424" ;
355+ }
356+ else if ( channel == "latest" || channel == "10" || channel == "10.0.2xx" )
357+ {
358+ return "10.0.203" ;
359+ }
360+ else if ( channel == "10.0.1xx" )
361+ {
362+ return "10.0.106" ;
363+ }
364+ else if ( channel == "9" || channel == "9.0.3xx" )
365+ {
366+ return "9.0.309" ;
367+ }
368+ else if ( channel == "9.0.2xx" )
369+ {
370+ return "9.0.212" ;
371+ }
372+ else if ( channel == "9.0.1xx" )
373+ {
374+ return "9.0.115" ;
375+ }
373376
374- bool IsElevated ( )
375- {
376- return false ;
377+ return channel ;
378+ }
377379 }
378380}
0 commit comments