Skip to content

Commit 3e29ba6

Browse files
authored
Add more methods to installer interface (#50475)
2 parents dd90109 + a559c31 commit 3e29ba6

File tree

3 files changed

+134
-56
lines changed

3 files changed

+134
-56
lines changed

src/Installer/dnup/Commands/Sdk/Install/SdkInstallCommand.cs

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -210,76 +210,36 @@ public override int Execute()
210210
}
211211

212212

213+
// TODO: Implement transaction / rollback?
214+
// TODO: Use Mutex to avoid concurrent installs?
215+
213216

214217
SpectreAnsiConsole.MarkupInterpolated($"Installing .NET SDK [blue]{resolvedChannelVersion}[/] to [blue]{resolvedInstallPath}[/]...");
215218

216-
string downloadLink = "https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.303/dotnet-sdk-9.0.303-win-x64.exe";
219+
SpectreAnsiConsole.Progress()
220+
.Start(ctx =>
221+
{
222+
_dotnetInstaller.InstallSdks(resolvedInstallPath, ctx, new[] { resolvedChannelVersion }.Concat(additionalVersionsToInstall));
223+
});
217224

218-
// Download the file to a temp path with progress
219-
using (var httpClient = new System.Net.Http.HttpClient())
225+
if (resolvedSetDefaultInstall == true)
220226
{
221-
SpectreAnsiConsole.Progress()
222-
.Start(ctx =>
223-
{
224-
var task = ctx.AddTask($"Downloading .NET SDK {resolvedChannelVersion}");
225-
226-
List<Action> additionalDownloads = additionalVersionsToInstall.Select(version =>
227-
{
228-
var additionalTask = ctx.AddTask($"Downloading .NET SDK {version}");
229-
return (Action)(() =>
230-
{
231-
Download(downloadLink, httpClient, additionalTask);
232-
});
233-
}).ToList();
227+
_dotnetInstaller.ConfigureInstallType(SdkInstallType.User, resolvedInstallPath);
228+
}
234229

235-
Download(downloadLink, httpClient, task);
230+
if (resolvedUpdateGlobalJson == true)
231+
{
232+
_dotnetInstaller.UpdateGlobalJson(globalJsonInfo!.GlobalJsonPath!, resolvedChannelVersion, globalJsonInfo.AllowPrerelease, globalJsonInfo.RollForward);
233+
}
236234

237235

238-
foreach (var additionalDownload in additionalDownloads)
239-
{
240-
additionalDownload();
241-
}
242-
});
243-
}
244236
SpectreAnsiConsole.WriteLine($"Complete!");
245237

246238

247239
return 0;
248240
}
249241

250-
void Download(string url, HttpClient httpClient, ProgressTask task)
251-
{
252-
//string tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(url));
253-
//using (var response = httpClient.GetAsync(url, System.Net.Http.HttpCompletionOption.ResponseHeadersRead).GetAwaiter().GetResult())
254-
//{
255-
// response.EnsureSuccessStatusCode();
256-
// var contentLength = response.Content.Headers.ContentLength ?? 0;
257-
// using (var stream = response.Content.ReadAsStream())
258-
// using (var fileStream = File.Create(tempFilePath))
259-
// {
260-
// var buffer = new byte[81920];
261-
// long totalRead = 0;
262-
// int read;
263-
// while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
264-
// {
265-
// fileStream.Write(buffer, 0, read);
266-
// totalRead += read;
267-
// if (contentLength > 0)
268-
// {
269-
// task.Value = (double)totalRead / contentLength * 100;
270-
// }
271-
// }
272-
// task.Value = 100;
273-
// }
274-
//}
275-
276-
for (int i = 0; i < 100; i++)
277-
{
278-
task.Increment(1);
279-
Thread.Sleep(20); // Simulate some work
280-
}
281-
task.Value = 100;
282-
}
242+
283243

284244
string? ResolveChannelFromGlobalJson(string globalJsonPath)
285245
{
@@ -330,6 +290,72 @@ public SdkInstallType GetConfiguredInstallType(out string? currentInstallPath)
330290
}
331291
return latestAdminVersion;
332292
}
293+
294+
public void InstallSdks(string dotnetRoot, ProgressContext progressContext, IEnumerable<string> sdkVersions)
295+
{
296+
//var task = progressContext.AddTask($"Downloading .NET SDK {resolvedChannelVersion}");
297+
using (var httpClient = new System.Net.Http.HttpClient())
298+
{
299+
List<Action> downloads = sdkVersions.Select(version =>
300+
{
301+
string downloadLink = "https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.303/dotnet-sdk-9.0.303-win-x64.exe";
302+
var task = progressContext.AddTask($"Downloading .NET SDK {version}");
303+
return (Action)(() =>
304+
{
305+
Download(downloadLink, httpClient, task);
306+
});
307+
}).ToList();
308+
309+
310+
foreach (var download in downloads)
311+
{
312+
download();
313+
}
314+
}
315+
}
316+
317+
void Download(string url, HttpClient httpClient, ProgressTask task)
318+
{
319+
//string tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(url));
320+
//using (var response = httpClient.GetAsync(url, System.Net.Http.HttpCompletionOption.ResponseHeadersRead).GetAwaiter().GetResult())
321+
//{
322+
// response.EnsureSuccessStatusCode();
323+
// var contentLength = response.Content.Headers.ContentLength ?? 0;
324+
// using (var stream = response.Content.ReadAsStream())
325+
// using (var fileStream = File.Create(tempFilePath))
326+
// {
327+
// var buffer = new byte[81920];
328+
// long totalRead = 0;
329+
// int read;
330+
// while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
331+
// {
332+
// fileStream.Write(buffer, 0, read);
333+
// totalRead += read;
334+
// if (contentLength > 0)
335+
// {
336+
// task.Value = (double)totalRead / contentLength * 100;
337+
// }
338+
// }
339+
// task.Value = 100;
340+
// }
341+
//}
342+
343+
for (int i = 0; i < 100; i++)
344+
{
345+
task.Increment(1);
346+
Thread.Sleep(20); // Simulate some work
347+
}
348+
task.Value = 100;
349+
}
350+
351+
public void UpdateGlobalJson(string globalJsonPath, string? sdkVersion = null, bool? allowPrerelease = null, string? rollForward = null)
352+
{
353+
SpectreAnsiConsole.WriteLine($"Updating {globalJsonPath} to SDK version {sdkVersion} (AllowPrerelease={allowPrerelease}, RollForward={rollForward})");
354+
}
355+
public void ConfigureInstallType(SdkInstallType installType, string? dotnetRoot = null)
356+
{
357+
SpectreAnsiConsole.WriteLine($"Configuring install type to {installType} (dotnetRoot={dotnetRoot})");
358+
}
333359
}
334360

335361
class EnvironmentVariableMockReleaseInfoProvider : IReleaseInfoProvider

src/Installer/dnup/DotnetInstaller.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Linq;
77
using System.Text.Json;
88
using Microsoft.DotNet.Cli.Utils;
9+
using Spectre.Console;
910

1011
namespace Microsoft.DotNet.Tools.Bootstrapper;
1112

@@ -99,4 +100,46 @@ public GlobalJsonInfo GetGlobalJsonInfo(string initialDirectory)
99100
// TODO: Implement this
100101
return null;
101102
}
103+
104+
public void InstallSdks(string dotnetRoot, ProgressContext progressContext, IEnumerable<string> sdkVersions) => throw new NotImplementedException();
105+
public void UpdateGlobalJson(string globalJsonPath, string? sdkVersion = null, bool? allowPrerelease = null, string? rollForward = null) => throw new NotImplementedException();
106+
107+
public void ConfigureInstallType(SdkInstallType installType, string? dotnetRoot = null)
108+
{
109+
// Get current PATH
110+
var path = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User) ?? string.Empty;
111+
var pathEntries = path.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries).ToList();
112+
string exeName = OperatingSystem.IsWindows() ? "dotnet.exe" : "dotnet";
113+
// Remove only actual dotnet installation folders from PATH
114+
pathEntries = pathEntries.Where(p => !File.Exists(Path.Combine(p, exeName))).ToList();
115+
116+
switch (installType)
117+
{
118+
case SdkInstallType.User:
119+
if (string.IsNullOrEmpty(dotnetRoot))
120+
throw new ArgumentNullException(nameof(dotnetRoot));
121+
// Add dotnetRoot to PATH
122+
pathEntries.Insert(0, dotnetRoot);
123+
// Set DOTNET_ROOT
124+
Environment.SetEnvironmentVariable("DOTNET_ROOT", dotnetRoot, EnvironmentVariableTarget.User);
125+
break;
126+
case SdkInstallType.Admin:
127+
if (string.IsNullOrEmpty(dotnetRoot))
128+
throw new ArgumentNullException(nameof(dotnetRoot));
129+
// Add dotnetRoot to PATH
130+
pathEntries.Insert(0, dotnetRoot);
131+
// Unset DOTNET_ROOT
132+
Environment.SetEnvironmentVariable("DOTNET_ROOT", null, EnvironmentVariableTarget.User);
133+
break;
134+
case SdkInstallType.None:
135+
// Unset DOTNET_ROOT
136+
Environment.SetEnvironmentVariable("DOTNET_ROOT", null, EnvironmentVariableTarget.User);
137+
break;
138+
default:
139+
throw new ArgumentException($"Unknown install type: {installType}", nameof(installType));
140+
}
141+
// Update PATH
142+
var newPath = string.Join(Path.PathSeparator, pathEntries);
143+
Environment.SetEnvironmentVariable("PATH", newPath, EnvironmentVariableTarget.User);
144+
}
102145
}

src/Installer/dnup/IDotnetInstaller.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Text;
7+
using Spectre.Console;
78

89
namespace Microsoft.DotNet.Tools.Bootstrapper;
910

@@ -16,6 +17,14 @@ public interface IDotnetInstaller
1617
SdkInstallType GetConfiguredInstallType(out string? currentInstallPath);
1718

1819
string? GetLatestInstalledAdminVersion();
20+
21+
void InstallSdks(string dotnetRoot, ProgressContext progressContext, IEnumerable<string> sdkVersions);
22+
23+
void UpdateGlobalJson(string globalJsonPath, string? sdkVersion = null, bool? allowPrerelease = null, string? rollForward = null);
24+
25+
void ConfigureInstallType(SdkInstallType installType, string? dotnetRoot = null);
26+
27+
1928
}
2029

2130
public enum SdkInstallType

0 commit comments

Comments
 (0)