Skip to content
Merged
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
138 changes: 82 additions & 56 deletions src/Installer/dnup/Commands/Sdk/Install/SdkInstallCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,76 +210,36 @@ public override int Execute()
}


// TODO: Implement transaction / rollback?
// TODO: Use Mutex to avoid concurrent installs?


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

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

// Download the file to a temp path with progress
using (var httpClient = new System.Net.Http.HttpClient())
if (resolvedSetDefaultInstall == true)
{
SpectreAnsiConsole.Progress()
.Start(ctx =>
{
var task = ctx.AddTask($"Downloading .NET SDK {resolvedChannelVersion}");

List<Action> additionalDownloads = additionalVersionsToInstall.Select(version =>
{
var additionalTask = ctx.AddTask($"Downloading .NET SDK {version}");
return (Action)(() =>
{
Download(downloadLink, httpClient, additionalTask);
});
}).ToList();
_dotnetInstaller.ConfigureInstallType(SdkInstallType.User, resolvedInstallPath);
}

Download(downloadLink, httpClient, task);
if (resolvedUpdateGlobalJson == true)
{
_dotnetInstaller.UpdateGlobalJson(globalJsonInfo!.GlobalJsonPath!, resolvedChannelVersion, globalJsonInfo.AllowPrerelease, globalJsonInfo.RollForward);
}


foreach (var additionalDownload in additionalDownloads)
{
additionalDownload();
}
});
}
SpectreAnsiConsole.WriteLine($"Complete!");


return 0;
}

void Download(string url, HttpClient httpClient, ProgressTask task)
{
//string tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(url));
//using (var response = httpClient.GetAsync(url, System.Net.Http.HttpCompletionOption.ResponseHeadersRead).GetAwaiter().GetResult())
//{
// response.EnsureSuccessStatusCode();
// var contentLength = response.Content.Headers.ContentLength ?? 0;
// using (var stream = response.Content.ReadAsStream())
// using (var fileStream = File.Create(tempFilePath))
// {
// var buffer = new byte[81920];
// long totalRead = 0;
// int read;
// while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
// {
// fileStream.Write(buffer, 0, read);
// totalRead += read;
// if (contentLength > 0)
// {
// task.Value = (double)totalRead / contentLength * 100;
// }
// }
// task.Value = 100;
// }
//}

for (int i = 0; i < 100; i++)
{
task.Increment(1);
Thread.Sleep(20); // Simulate some work
}
task.Value = 100;
}


string? ResolveChannelFromGlobalJson(string globalJsonPath)
{
Expand Down Expand Up @@ -330,6 +290,72 @@ public SdkInstallType GetConfiguredInstallType(out string? currentInstallPath)
}
return latestAdminVersion;
}

public void InstallSdks(string dotnetRoot, ProgressContext progressContext, IEnumerable<string> sdkVersions)
{
//var task = progressContext.AddTask($"Downloading .NET SDK {resolvedChannelVersion}");
using (var httpClient = new System.Net.Http.HttpClient())
{
List<Action> downloads = sdkVersions.Select(version =>
{
string downloadLink = "https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.303/dotnet-sdk-9.0.303-win-x64.exe";
var task = progressContext.AddTask($"Downloading .NET SDK {version}");
return (Action)(() =>
{
Download(downloadLink, httpClient, task);
});
}).ToList();


foreach (var download in downloads)
{
download();
}
}
}

void Download(string url, HttpClient httpClient, ProgressTask task)
{
//string tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(url));
//using (var response = httpClient.GetAsync(url, System.Net.Http.HttpCompletionOption.ResponseHeadersRead).GetAwaiter().GetResult())
//{
// response.EnsureSuccessStatusCode();
// var contentLength = response.Content.Headers.ContentLength ?? 0;
// using (var stream = response.Content.ReadAsStream())
// using (var fileStream = File.Create(tempFilePath))
// {
// var buffer = new byte[81920];
// long totalRead = 0;
// int read;
// while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
// {
// fileStream.Write(buffer, 0, read);
// totalRead += read;
// if (contentLength > 0)
// {
// task.Value = (double)totalRead / contentLength * 100;
// }
// }
// task.Value = 100;
// }
//}

for (int i = 0; i < 100; i++)
{
task.Increment(1);
Thread.Sleep(20); // Simulate some work
}
task.Value = 100;
}

public void UpdateGlobalJson(string globalJsonPath, string? sdkVersion = null, bool? allowPrerelease = null, string? rollForward = null)
{
SpectreAnsiConsole.WriteLine($"Updating {globalJsonPath} to SDK version {sdkVersion} (AllowPrerelease={allowPrerelease}, RollForward={rollForward})");
}
public void ConfigureInstallType(SdkInstallType installType, string? dotnetRoot = null)
{
SpectreAnsiConsole.WriteLine($"Configuring install type to {installType} (dotnetRoot={dotnetRoot})");
}
}

class EnvironmentVariableMockReleaseInfoProvider : IReleaseInfoProvider
Expand Down
43 changes: 43 additions & 0 deletions src/Installer/dnup/DotnetInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using System.Text.Json;
using Microsoft.DotNet.Cli.Utils;
using Spectre.Console;

namespace Microsoft.DotNet.Tools.Bootstrapper;

Expand Down Expand Up @@ -99,4 +100,46 @@ public GlobalJsonInfo GetGlobalJsonInfo(string initialDirectory)
// TODO: Implement this
return null;
}

public void InstallSdks(string dotnetRoot, ProgressContext progressContext, IEnumerable<string> sdkVersions) => throw new NotImplementedException();
public void UpdateGlobalJson(string globalJsonPath, string? sdkVersion = null, bool? allowPrerelease = null, string? rollForward = null) => throw new NotImplementedException();

public void ConfigureInstallType(SdkInstallType installType, string? dotnetRoot = null)
{
// Get current PATH
var path = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User) ?? string.Empty;
var pathEntries = path.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries).ToList();
string exeName = OperatingSystem.IsWindows() ? "dotnet.exe" : "dotnet";
// Remove only actual dotnet installation folders from PATH
pathEntries = pathEntries.Where(p => !File.Exists(Path.Combine(p, exeName))).ToList();

switch (installType)
{
case SdkInstallType.User:
if (string.IsNullOrEmpty(dotnetRoot))
throw new ArgumentNullException(nameof(dotnetRoot));
// Add dotnetRoot to PATH
pathEntries.Insert(0, dotnetRoot);
// Set DOTNET_ROOT
Environment.SetEnvironmentVariable("DOTNET_ROOT", dotnetRoot, EnvironmentVariableTarget.User);
break;
case SdkInstallType.Admin:
if (string.IsNullOrEmpty(dotnetRoot))
throw new ArgumentNullException(nameof(dotnetRoot));
// Add dotnetRoot to PATH
pathEntries.Insert(0, dotnetRoot);
// Unset DOTNET_ROOT
Environment.SetEnvironmentVariable("DOTNET_ROOT", null, EnvironmentVariableTarget.User);
break;
case SdkInstallType.None:
// Unset DOTNET_ROOT
Environment.SetEnvironmentVariable("DOTNET_ROOT", null, EnvironmentVariableTarget.User);
break;
default:
throw new ArgumentException($"Unknown install type: {installType}", nameof(installType));
}
// Update PATH
var newPath = string.Join(Path.PathSeparator, pathEntries);
Environment.SetEnvironmentVariable("PATH", newPath, EnvironmentVariableTarget.User);
}
}
9 changes: 9 additions & 0 deletions src/Installer/dnup/IDotnetInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using Spectre.Console;

namespace Microsoft.DotNet.Tools.Bootstrapper;

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

string? GetLatestInstalledAdminVersion();

void InstallSdks(string dotnetRoot, ProgressContext progressContext, IEnumerable<string> sdkVersions);

void UpdateGlobalJson(string globalJsonPath, string? sdkVersion = null, bool? allowPrerelease = null, string? rollForward = null);

void ConfigureInstallType(SdkInstallType installType, string? dotnetRoot = null);


}

public enum SdkInstallType
Expand Down