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
53 changes: 53 additions & 0 deletions src/Installer/Microsoft.Dotnet.Installation/IProgressTarget.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.Dotnet.Installation;

public interface IProgressTarget
{
public IProgressReporter CreateProgressReporter();
}

public interface IProgressReporter : IDisposable
{
public IProgressTask AddTask(string description, double maxValue);
}

public interface IProgressTask
{
string Description { get; set; }
double Value { get; set; }
double MaxValue { get; set; }


}

public class NullProgressTarget : IProgressTarget
{
public IProgressReporter CreateProgressReporter() => new NullProgressReporter();
class NullProgressReporter : IProgressReporter
{
public void Dispose()
{
}
public IProgressTask AddTask(string description, double maxValue)
{
return new NullProgressTask(description);
}
}
class NullProgressTask : IProgressTask
{
public NullProgressTask(string description)
{
Description = description;
}

public double Value { get; set; }
public string Description { get; set; }
public double MaxValue { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace Microsoft.Dotnet.Installation;

public static class InstallerFactory
{
public static IDotnetInstaller CreateInstaller()
public static IDotnetInstaller CreateInstaller(IProgressTarget progressTarget)
{
return new DotnetInstaller();
return new DotnetInstaller(progressTarget);
}

public static IDotnetReleaseInfoProvider CreateReleaseInfoProvider()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ internal class ArchiveDotnetExtractor : IDisposable
{
private readonly DotnetInstallRequest _request;
private readonly ReleaseVersion _resolvedVersion;
private readonly bool _noProgress;
private readonly IProgressTarget _progressTarget;
private string scratchDownloadDirectory;
private string? _archivePath;

public ArchiveDotnetExtractor(DotnetInstallRequest request, ReleaseVersion resolvedVersion, bool noProgress = false)
public ArchiveDotnetExtractor(DotnetInstallRequest request, ReleaseVersion resolvedVersion, IProgressTarget progressTarget)
{
_request = request;
_resolvedVersion = resolvedVersion;
_noProgress = noProgress;
_progressTarget = progressTarget;
scratchDownloadDirectory = Directory.CreateTempSubdirectory().FullName;
}

Expand All @@ -34,33 +34,17 @@ public void Prepare()
var archiveName = $"dotnet-{Guid.NewGuid()}";
_archivePath = Path.Combine(scratchDownloadDirectory, archiveName + DnupUtilities.GetArchiveFileExtensionForPlatform());

if (_noProgress)
using (var progressReporter = _progressTarget.CreateProgressReporter())
{
// When no-progress is enabled, download without progress display
Console.WriteLine($"Downloading .NET SDK {_resolvedVersion}...");
var downloadSuccess = releaseManifest.DownloadArchiveWithVerification(_request, _resolvedVersion, _archivePath, null);
var downloadTask = progressReporter.AddTask($"Downloading .NET SDK {_resolvedVersion}", 100);
var reporter = new DownloadProgressReporter(downloadTask, $"Downloading .NET SDK {_resolvedVersion}");
var downloadSuccess = releaseManifest.DownloadArchiveWithVerification(_request, _resolvedVersion, _archivePath, reporter);
if (!downloadSuccess)
{
throw new InvalidOperationException($"Failed to download .NET archive for version {_resolvedVersion}");
}
Console.WriteLine($"Download of .NET SDK {_resolvedVersion} complete.");
}
else
{
// Use progress display for normal operation
Spectre.Console.AnsiConsole.Progress()
.Start(ctx =>
{
var downloadTask = ctx.AddTask($"Downloading .NET SDK {_resolvedVersion}", autoStart: true);
var reporter = new SpectreDownloadProgressReporter(downloadTask, $"Downloading .NET SDK {_resolvedVersion}");
var downloadSuccess = releaseManifest.DownloadArchiveWithVerification(_request, _resolvedVersion, _archivePath, reporter);
if (!downloadSuccess)
{
throw new InvalidOperationException($"Failed to download .NET archive for version {_resolvedVersion}");
}

downloadTask.Value = 100;
});
downloadTask.Value = 100;
}
}

Expand Down Expand Up @@ -111,45 +95,26 @@ public void Commit(IEnumerable<ReleaseVersion> existingSdkVersions)
throw new InvalidOperationException("Archive not found. Make sure Prepare() was called successfully.");
}

if (_noProgress)
using (var progressReporter = _progressTarget.CreateProgressReporter())
{
// When no-progress is enabled, install without progress display
Console.WriteLine($"Installing .NET SDK {_resolvedVersion}...");
var installTask = progressReporter.AddTask($"Installing .NET SDK {_resolvedVersion}", maxValue: 100);

// Extract archive directly to target directory with special handling for muxer
var extractResult = ExtractArchiveDirectlyToTarget(_archivePath, _request.InstallRoot.Path!, existingSdkVersions, null);
var extractResult = ExtractArchiveDirectlyToTarget(_archivePath, _request.InstallRoot.Path!, existingSdkVersions, installTask);
if (extractResult is not null)
{
throw new InvalidOperationException($"Failed to install SDK: {extractResult}");
}

Console.WriteLine($"Installation of .NET SDK {_resolvedVersion} complete.");
}
else
{
// Use progress display for normal operation
Spectre.Console.AnsiConsole.Progress()
.Start(ctx =>
{
var installTask = ctx.AddTask($"Installing .NET SDK {_resolvedVersion}", autoStart: true);

// Extract archive directly to target directory with special handling for muxer
var extractResult = ExtractArchiveDirectlyToTarget(_archivePath, _request.InstallRoot.Path!, existingSdkVersions, installTask);
if (extractResult is not null)
{
throw new InvalidOperationException($"Failed to install SDK: {extractResult}");
}

installTask.Value = installTask.MaxValue;
});
installTask.Value = installTask.MaxValue;
}
}

/**
* Extracts the archive directly to the target directory with special handling for muxer.
* Combines extraction and installation into a single operation.
*/
private string? ExtractArchiveDirectlyToTarget(string archivePath, string targetDir, IEnumerable<ReleaseVersion> existingSdkVersions, Spectre.Console.ProgressTask? installTask)
private string? ExtractArchiveDirectlyToTarget(string archivePath, string targetDir, IEnumerable<ReleaseVersion> existingSdkVersions, IProgressTask? installTask)
{
try
{
Expand Down Expand Up @@ -194,7 +159,7 @@ private MuxerHandlingConfig ConfigureMuxerHandling(IEnumerable<ReleaseVersion> e
/**
* Extracts a tar or tar.gz archive to the target directory.
*/
private string? ExtractTarArchive(string archivePath, string targetDir, MuxerHandlingConfig muxerConfig, Spectre.Console.ProgressTask? installTask)
private string? ExtractTarArchive(string archivePath, string targetDir, MuxerHandlingConfig muxerConfig, IProgressTask? installTask)
{
string decompressedPath = DecompressTarGzIfNeeded(archivePath, out bool needsDecompression);

Expand Down Expand Up @@ -265,7 +230,7 @@ private long CountTarEntries(string tarPath)
/**
* Extracts the contents of a tar file to the target directory.
*/
private void ExtractTarContents(string tarPath, string targetDir, MuxerHandlingConfig muxerConfig, Spectre.Console.ProgressTask? installTask)
private void ExtractTarContents(string tarPath, string targetDir, MuxerHandlingConfig muxerConfig, IProgressTask? installTask)
{
using var tarStream = File.OpenRead(tarPath);
var tarReader = new TarReader(tarStream);
Expand All @@ -282,20 +247,20 @@ private void ExtractTarContents(string tarPath, string targetDir, MuxerHandlingC
// Create directory if it doesn't exist
var dirPath = Path.Combine(targetDir, entry.Name);
Directory.CreateDirectory(dirPath);
installTask?.Increment(1);
installTask?.Value += 1;
}
else
{
// Skip other entry types
installTask?.Increment(1);
installTask?.Value += 1;
}
}
}

/**
* Extracts a single file entry from a tar archive.
*/
private void ExtractTarFileEntry(TarEntry entry, string targetDir, MuxerHandlingConfig muxerConfig, Spectre.Console.ProgressTask? installTask)
private void ExtractTarFileEntry(TarEntry entry, string targetDir, MuxerHandlingConfig muxerConfig, IProgressTask? installTask)
{
var fileName = Path.GetFileName(entry.Name);
var destPath = Path.Combine(targetDir, entry.Name);
Expand All @@ -314,7 +279,7 @@ private void ExtractTarFileEntry(TarEntry entry, string targetDir, MuxerHandling
entry.DataStream?.CopyTo(outStream);
}

installTask?.Increment(1);
installTask?.Value += 1;
}

/**
Expand Down Expand Up @@ -346,7 +311,7 @@ private void HandleMuxerUpdateFromTar(TarEntry entry, string muxerTargetPath)
/**
* Extracts a zip archive to the target directory.
*/
private string? ExtractZipArchive(string archivePath, string targetDir, MuxerHandlingConfig muxerConfig, Spectre.Console.ProgressTask? installTask)
private string? ExtractZipArchive(string archivePath, string targetDir, MuxerHandlingConfig muxerConfig, IProgressTask? installTask)
{
long totalFiles = CountZipEntries(archivePath);

Expand All @@ -373,7 +338,7 @@ private long CountZipEntries(string zipPath)
/**
* Extracts a single entry from a zip archive.
*/
private void ExtractZipEntry(ZipArchiveEntry entry, string targetDir, MuxerHandlingConfig muxerConfig, Spectre.Console.ProgressTask? installTask)
private void ExtractZipEntry(ZipArchiveEntry entry, string targetDir, MuxerHandlingConfig muxerConfig, IProgressTask? installTask)
{
var fileName = Path.GetFileName(entry.FullName);
var destPath = Path.Combine(targetDir, entry.FullName);
Expand All @@ -382,7 +347,7 @@ private void ExtractZipEntry(ZipArchiveEntry entry, string targetDir, MuxerHandl
if (string.IsNullOrEmpty(fileName))
{
Directory.CreateDirectory(destPath);
installTask?.Increment(1);
installTask?.Value += 1;
return;
}

Expand All @@ -400,7 +365,7 @@ private void ExtractZipEntry(ZipArchiveEntry entry, string targetDir, MuxerHandl
entry.ExtractToFile(destPath, overwrite: true);
}

installTask?.Increment(1);
installTask?.Value += 1;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
using System.Collections.Generic;
using System.Text;
using Microsoft.Deployment.DotNet.Releases;
using Spectre.Console;

namespace Microsoft.Dotnet.Installation.Internal
{
internal class DotnetInstaller : IDotnetInstaller
{
IProgressTarget _progressTarget;

public DotnetInstaller(IProgressTarget progressTarget)
{
_progressTarget = progressTarget;
}

public void Install(DotnetInstallRoot dotnetRoot, InstallComponent component, ReleaseVersion version)
{
var installRequest = new DotnetInstallRequest(dotnetRoot, new UpdateChannel(version.ToString()), component, new InstallRequestOptions());

using ArchiveDotnetExtractor installer = new(installRequest, version, noProgress: true);
using ArchiveDotnetExtractor installer = new(installRequest, version, _progressTarget);
installer.Prepare();
installer.Commit();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using System;
using Spectre.Console;
using Microsoft.Dotnet.Installation;

namespace Microsoft.Dotnet.Installation.Internal
{
public class SpectreDownloadProgressReporter : IProgress<DownloadProgress>
public class DownloadProgressReporter : IProgress<DownloadProgress>
{
private readonly ProgressTask _task;
private readonly IProgressTask _task;
private readonly string _description;
private long? _totalBytes;

public SpectreDownloadProgressReporter(ProgressTask task, string description)
public DownloadProgressReporter(IProgressTask task, string description)
{
_task = task;
_description = description;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.Deployment.DotNet.Releases" />
<!-- TODO: Create logging / progress abstraction and remove this dependency from the library -->
<PackageReference Include="Spectre.Console" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public override int Execute()

// TODO: Implement transaction / rollback?

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

DotnetInstall? mainInstall;

Expand Down
4 changes: 3 additions & 1 deletion src/Installer/dnup/InstallerOrchestratorSingleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ private InstallerOrchestratorSingleton()
}
}

using ArchiveDotnetExtractor installer = new(installRequest, versionToInstall, noProgress);
IProgressTarget progressTarget = noProgress ? new NonUpdatingProgressTarget() : new SpectreProgressTarget();

using ArchiveDotnetExtractor installer = new(installRequest, versionToInstall, progressTarget);
installer.Prepare();

// Extract and commit the install to the directory
Expand Down
Loading