diff --git a/src/Cli/dotnet/NugetPackageInstaller/NuGetPackageInstaller.cs b/src/Cli/dotnet/NugetPackageInstaller/NuGetPackageInstaller.cs
index 74f1819dfff9..9b7aff5d4f89 100644
--- a/src/Cli/dotnet/NugetPackageInstaller/NuGetPackageInstaller.cs
+++ b/src/Cli/dotnet/NugetPackageInstaller/NuGetPackageInstaller.cs
@@ -218,7 +218,7 @@ await Task.WhenAll(
if (!accumulativeSearchResults.Any())
{
- _logger.LogWarning(
+ throw new Exception(
string.Format(
LocalizableStrings.FailedToLoadNuGetSourceSourceIsNotValid,
packageIdentifier,
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs
new file mode 100644
index 000000000000..044c6c1f6f31
--- /dev/null
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.DotNet.Workloads.Workload.Install.InstallRecord;
+
+namespace Microsoft.DotNet.Workloads.Workload.Install
+{
+ internal interface IWorkloadManifestUpdater
+ {
+ Task UpdateAdvertisingManifestsAsync(SdkFeatureBand featureBand, bool includePreviews);
+
+ IEnumerable<(ManifestId manifestId, ManifestVersion existingVersion, ManifestVersion newVersion)> CalculateManifestUpdates(SdkFeatureBand featureBand);
+ }
+}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx
index b9df77d85b2d..da357cf71a1f 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx
@@ -210,4 +210,22 @@
Rolling back pack {0} installation...
+
+ Updated advertising manifest {0}.
+
+
+ Failed to update the advertising manifest {0}: {1}
+
+
+ No manifest with id {0} exists.
+
+
+ Failed to install manifest {0} version {1}: {2}.
+
+
+ Installing workload manifest {0} version {1}.
+
+
+ Allow prerelease workload manifests.
+
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/ManifestVersion.cs b/src/Cli/dotnet/commands/dotnet-workload/install/ManifestVersion.cs
index 9f0e375c153f..2ef4e1c15e9e 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/ManifestVersion.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/ManifestVersion.cs
@@ -2,26 +2,30 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
+using Microsoft.DotNet.MSBuildSdkResolver;
namespace Microsoft.DotNet.Workloads.Workload.Install
{
- internal struct ManifestVersion : IEquatable, IComparable
+ internal class ManifestVersion : IEquatable, IComparable
{
- private string _version;
+ private FXVersion _version;
public ManifestVersion(string version)
{
- _version = version ?? throw new ArgumentNullException(nameof(version));
+ if (!FXVersion.TryParse(version, out _version))
+ {
+ throw new ArgumentNullException(nameof(version));
+ }
}
public bool Equals(ManifestVersion other)
{
- return ToString() == other.ToString();
+ return ToString().Equals(other.ToString());
}
public int CompareTo(ManifestVersion other)
{
- return string.Compare(ToString(), other.ToString(), StringComparison.Ordinal);
+ return FXVersion.Compare(_version, other._version);
}
public override bool Equals(object obj)
@@ -31,12 +35,12 @@ public override bool Equals(object obj)
public override int GetHashCode()
{
- return ToString().GetHashCode();
+ return _version.GetHashCode();
}
public override string ToString()
{
- return _version;
+ return _version.ToString();
}
}
}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkManagedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkManagedInstaller.cs
index 3b3a3c5f3d7b..877aa9173cbf 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkManagedInstaller.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkManagedInstaller.cs
@@ -11,11 +11,11 @@
using Microsoft.DotNet.ToolPackage;
using Microsoft.Extensions.EnvironmentAbstractions;
using Microsoft.NET.Sdk.WorkloadManifestReader;
+using NuGet.Common;
using NuGet.Versioning;
using static Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadResolver;
using EnvironmentProvider = Microsoft.DotNet.NativeWrapper.EnvironmentProvider;
using Microsoft.DotNet.Workloads.Workload.Install.InstallRecord;
-using NuGet.Common;
namespace Microsoft.DotNet.Workloads.Workload.Install
{
@@ -26,7 +26,7 @@ internal class NetSdkManagedInstaller : IWorkloadPackInstaller
private readonly string _installedPacksDir = "InstalledPacks";
protected readonly string _dotnetDir;
protected readonly DirectoryPath _tempPackagesDir;
- private readonly INuGetPackageDownloader _nugetPackageInstaller;
+ private readonly INuGetPackageDownloader _nugetPackageDownloader;
private readonly IWorkloadResolver _workloadResolver;
private readonly SdkFeatureBand _sdkFeatureBand;
private readonly NetSdkManagedInstallationRecordRepository _installationRecordRepository;
@@ -41,7 +41,7 @@ public NetSdkManagedInstaller(
{
_dotnetDir = dotnetDir ?? Path.GetDirectoryName(Environment.ProcessPath);
_tempPackagesDir = new DirectoryPath(Path.Combine(_dotnetDir, "metadata", "temp"));
- _nugetPackageInstaller = nugetPackageDownloader ??
+ _nugetPackageDownloader = nugetPackageDownloader ??
new NuGetPackageDownloader(_tempPackagesDir, verbosity.VerbosityIsDetailedOrDiagnostic() ? new NuGetConsoleLogger() : new NullLogger());
_workloadMetadataDir = Path.Combine(_dotnetDir, "metadata", "workloads");
_reporter = reporter;
@@ -87,7 +87,7 @@ public void InstallWorkloadPack(PackInfo packInfo, SdkFeatureBand sdkFeatureBand
{
if (!PackIsInstalled(packInfo))
{
- var packagePath = _nugetPackageInstaller.DownloadPackageAsync(new PackageId(packInfo.ResolvedPackageId), new NuGetVersion(packInfo.Version)).Result;
+ var packagePath = _nugetPackageDownloader.DownloadPackageAsync(new PackageId(packInfo.ResolvedPackageId), new NuGetVersion(packInfo.Version)).Result;
tempFilesToDelete.Add(packagePath);
if (!Directory.Exists(Path.GetDirectoryName(packInfo.Path)))
@@ -104,7 +104,7 @@ public void InstallWorkloadPack(PackInfo packInfo, SdkFeatureBand sdkFeatureBand
var tempExtractionDir = Path.Combine(_tempPackagesDir.Value, $"{packInfo.Id}-{packInfo.Version}-extracted");
tempDirsToDelete.Add(tempExtractionDir);
Directory.CreateDirectory(tempExtractionDir);
- var packFiles = _nugetPackageInstaller.ExtractPackageAsync(packagePath, tempExtractionDir).Result;
+ var packFiles = _nugetPackageDownloader.ExtractPackageAsync(packagePath, tempExtractionDir).Result;
FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(tempExtractionDir, packInfo.Path));
}
@@ -158,7 +158,77 @@ public void RollBackWorkloadPackInstall(PackInfo packInfo, SdkFeatureBand sdkFea
}
}
- public void InstallWorkloadManifest(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand) => throw new NotImplementedException();
+ public void InstallWorkloadManifest(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand)
+ {
+ string packagePath = null;
+ string tempExtractionDir = null;
+ string tempBackupDir = null;
+ var manifestPath = Path.Combine(_dotnetDir, "sdk-manifests", sdkFeatureBand.ToString(), manifestId.ToString());
+
+ _reporter.WriteLine(string.Format(LocalizableStrings.InstallingWorkloadManifest, manifestId, manifestVersion));
+
+ try
+ {
+ TransactionalAction.Run(
+ action: () =>
+ {
+ packagePath = _nugetPackageDownloader.DownloadPackageAsync(WorkloadManifestUpdater.GetManifestPackageId(sdkFeatureBand, manifestId), new NuGetVersion(manifestVersion.ToString())).Result;
+ tempExtractionDir = Path.Combine(_tempPackagesDir.Value, $"{manifestId}-{manifestVersion}-extracted");
+ Directory.CreateDirectory(tempExtractionDir);
+ var manifestFiles = _nugetPackageDownloader.ExtractPackageAsync(packagePath, tempExtractionDir).Result;
+
+ if (Directory.Exists(manifestPath) && Directory.GetFileSystemEntries(manifestPath).Any())
+ {
+ // Backup existing manifest data for roll back purposes
+ tempBackupDir = Path.Combine(_tempPackagesDir.Value, $"{manifestId}-{manifestVersion}-backup");
+ if (Directory.Exists(tempBackupDir))
+ {
+ Directory.Delete(tempBackupDir, true);
+ }
+ FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(manifestPath, tempBackupDir));
+ }
+ Directory.CreateDirectory(Path.GetDirectoryName(manifestPath));
+ FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(Path.Combine(tempExtractionDir, "data"), manifestPath));
+ },
+ rollback: () => {
+ if (!string.IsNullOrEmpty(tempBackupDir) && Directory.Exists(tempBackupDir))
+ {
+ FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(tempBackupDir, manifestPath));
+ }
+ });
+
+ // Delete leftover dirs and files
+ if (!string.IsNullOrEmpty(packagePath) && File.Exists(packagePath))
+ {
+ File.Delete(packagePath);
+ }
+
+ var versionDir = Path.GetDirectoryName(packagePath);
+ if (Directory.Exists(versionDir) && !Directory.GetFileSystemEntries(versionDir).Any())
+ {
+ Directory.Delete(versionDir);
+ var idDir = Path.GetDirectoryName(versionDir);
+ if (Directory.Exists(idDir) && !Directory.GetFileSystemEntries(idDir).Any())
+ {
+ Directory.Delete(idDir);
+ }
+ }
+
+ if (!string.IsNullOrEmpty(tempExtractionDir) && Directory.Exists(tempExtractionDir))
+ {
+ Directory.Delete(tempExtractionDir, true);
+ }
+
+ if (!string.IsNullOrEmpty(tempBackupDir) && Directory.Exists(tempBackupDir))
+ {
+ Directory.Delete(tempBackupDir, true);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception(string.Format(LocalizableStrings.FailedToInstallWorkloadManifest, manifestId, manifestVersion, e.Message));
+ }
+ }
public void DownloadToOfflineCache(IEnumerable manifests) => throw new NotImplementedException();
@@ -208,7 +278,7 @@ private IEnumerable GetExpectedPackInstallRecords(SdkFeatureBand sdkFeat
{
var installedWorkloads = _installationRecordRepository.GetInstalledWorkloads(sdkFeatureBand);
return installedWorkloads
- .SelectMany(workload => _workloadResolver.GetPacksInWorkload(workload))
+ .SelectMany(workload => _workloadResolver.GetPacksInWorkload(workload.ToString()))
.Select(pack => _workloadResolver.TryGetPackInfo(pack))
.Select(packInfo => GetPackInstallRecordPath(packInfo, sdkFeatureBand));
}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs
index 444a064fce82..950425894b29 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs
@@ -17,7 +17,11 @@
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;
+using Microsoft.DotNet.Cli.NuGetPackageDownloader;
+using Microsoft.Extensions.EnvironmentAbstractions;
+using NuGet.Common;
using Microsoft.DotNet.Workloads.Workload.Install.InstallRecord;
+using static Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadResolver;
namespace Microsoft.DotNet.Workloads.Workload.Install
{
@@ -27,10 +31,14 @@ internal class WorkloadInstallCommand : CommandBase
private readonly bool _skipManifestUpdate;
private readonly string _fromCacheOption;
private readonly bool _printDownloadLinkOnly;
+ private readonly bool _includePreviews;
private readonly VerbosityOptions _verbosity;
private readonly IReadOnlyCollection _workloadIds;
private readonly IInstaller _workloadInstaller;
private readonly IWorkloadResolver _workloadResolver;
+ private readonly IWorkloadManifestProvider _workloadManifestProvider;
+ private readonly INuGetPackageDownloader _nugetPackageDownloader;
+ private readonly IWorkloadManifestUpdater _workloadManifestUpdater;
private readonly ReleaseVersion _sdkVersion;
public readonly string MockInstallDirectory = Path.Combine(CliFolderPathCalculator.DotnetUserProfileFolderPath,
@@ -41,11 +49,15 @@ public WorkloadInstallCommand(
IReporter reporter = null,
IWorkloadResolver workloadResolver = null,
IInstaller workloadInstaller = null,
+ INuGetPackageDownloader nugetPackageDownloader = null,
+ IWorkloadManifestUpdater workloadManifestUpdater = null,
+ string userHome = null,
string version = null)
: base(parseResult)
{
_reporter = reporter ?? Reporter.Output;
_skipManifestUpdate = parseResult.ValueForOption(WorkloadInstallCommandParser.SkipManifestUpdateOption);
+ _includePreviews = parseResult.ValueForOption(WorkloadInstallCommandParser.IncludePreviewOption);
_printDownloadLinkOnly = parseResult.ValueForOption(WorkloadInstallCommandParser.PrintDownloadLinkOnlyOption);
_fromCacheOption = parseResult.ValueForOption(WorkloadInstallCommandParser.FromCacheOption);
_workloadIds = parseResult.ValueForArgument>(WorkloadInstallCommandParser.WorkloadIdArgument).ToList().AsReadOnly();
@@ -53,10 +65,14 @@ public WorkloadInstallCommand(
_sdkVersion = new ReleaseVersion(version ?? Product.Version);
var dotnetPath = Path.GetDirectoryName(Environment.ProcessPath);
- var workloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(dotnetPath, _sdkVersion.ToString());
- _workloadResolver = workloadResolver ?? WorkloadResolver.Create(workloadManifestProvider, dotnetPath, _sdkVersion.ToString());
+ _workloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(dotnetPath, _sdkVersion.ToString());
+ _workloadResolver = workloadResolver ?? WorkloadResolver.Create(_workloadManifestProvider, dotnetPath, _sdkVersion.ToString());
var sdkFeatureBand = new SdkFeatureBand(_sdkVersion);
_workloadInstaller = workloadInstaller ?? WorkloadInstallerFactory.GetWorkloadInstaller(_reporter, sdkFeatureBand, _workloadResolver, _verbosity);
+ userHome = userHome ?? CliFolderPathCalculator.DotnetHomePath;
+ var tempPackagesDir = new DirectoryPath(Path.Combine(userHome, ".dotnet", "sdk-advertising-temp"));
+ _nugetPackageDownloader = nugetPackageDownloader ?? new NuGetPackageDownloader(tempPackagesDir, new NullLogger());
+ _workloadManifestUpdater = workloadManifestUpdater ?? new WorkloadManifestUpdater(_reporter, _workloadManifestProvider, _nugetPackageDownloader, userHome);
}
public override int Execute()
@@ -122,9 +138,9 @@ public override int Execute()
{
try
{
- InstallWorkloads(_workloadIds.Select(id => new WorkloadId(id)), _skipManifestUpdate);
+ InstallWorkloads(_workloadIds.Select(id => new WorkloadId(id)), _skipManifestUpdate, _includePreviews);
}
- catch(Exception e)
+ catch (Exception e)
{
// Don't show entire stack trace
throw new GracefulException(string.Format(LocalizableStrings.WorkloadInstallationFailed, e.Message), e);
@@ -149,17 +165,23 @@ public string nupkgUrl(string baseUri, string id, NuGetVersion version) =>
"." +
version.ToNormalizedString() + ".nupkg";
- public void InstallWorkloads(IEnumerable workloadIds, bool skipManifestUpdate = false)
+ public void InstallWorkloads(IEnumerable workloadIds, bool skipManifestUpdate = false, bool includePreviews = false)
{
_reporter.WriteLine();
var featureBand = new SdkFeatureBand(string.Join('.', _sdkVersion.Major, _sdkVersion.Minor, _sdkVersion.SdkFeatureBand));
+ IEnumerable<(ManifestId, ManifestVersion, ManifestVersion)> manifestsToUpdate = new List<(ManifestId, ManifestVersion, ManifestVersion)>();
if (!skipManifestUpdate)
{
- throw new NotImplementedException();
+ // Update currently installed workloads
+ var installedWorkloads = _workloadInstaller.GetWorkloadInstallationRecordRepository().GetInstalledWorkloads(featureBand);
+ workloadIds = workloadIds.Concat(installedWorkloads).Distinct();
+
+ _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(featureBand, includePreviews).Wait();
+ manifestsToUpdate = _workloadManifestUpdater.CalculateManifestUpdates(featureBand);
}
- InstallWorkloadsWithInstallRecord(workloadIds, featureBand);
+ InstallWorkloadsWithInstallRecord(workloadIds, featureBand, manifestsToUpdate);
if (_workloadInstaller.GetInstallationUnit().Equals(InstallationUnit.Packs))
{
@@ -171,19 +193,31 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif
_reporter.WriteLine();
}
- private void InstallWorkloadsWithInstallRecord(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand)
+ private void InstallWorkloadsWithInstallRecord(
+ IEnumerable workloadIds,
+ SdkFeatureBand sdkFeatureBand,
+ IEnumerable<(ManifestId manifestId, ManifestVersion existingVersion, ManifestVersion newVersion)> manifestsToUpdate)
{
if (_workloadInstaller.GetInstallationUnit().Equals(InstallationUnit.Packs))
{
var installer = _workloadInstaller.GetPackInstaller();
+ IEnumerable workloadPackToInstall = new List();
- var workloadPackToInstall = workloadIds
- .SelectMany(workloadId => _workloadResolver.GetPacksInWorkload(workloadId.ToString()))
- .Distinct()
- .Select(packId => _workloadResolver.TryGetPackInfo(packId));
TransactionalAction.Run(
action: () =>
{
+ foreach (var manifest in manifestsToUpdate)
+ {
+ _workloadInstaller.InstallWorkloadManifest(manifest.manifestId, manifest.newVersion, sdkFeatureBand);
+ }
+
+ _workloadResolver.RefreshWorkloadManifests();
+
+ workloadPackToInstall = workloadIds
+ .SelectMany(workloadId => _workloadResolver.GetPacksInWorkload(workloadId.ToString()))
+ .Distinct()
+ .Select(packId => _workloadResolver.TryGetPackInfo(packId));
+
foreach (var packId in workloadPackToInstall)
{
installer.InstallWorkloadPack(packId, sdkFeatureBand);
@@ -194,12 +228,17 @@ private void InstallWorkloadsWithInstallRecord(IEnumerable workloadI
_workloadInstaller.GetWorkloadInstallationRecordRepository()
.WriteWorkloadInstallationRecord(workloadId, sdkFeatureBand);
}
-
},
rollback: () => {
try
{
_reporter.WriteLine(LocalizableStrings.RollingBackInstall);
+
+ foreach (var manifest in manifestsToUpdate)
+ {
+ _workloadInstaller.InstallWorkloadManifest(manifest.manifestId, manifest.existingVersion, sdkFeatureBand);
+ }
+
foreach (var packId in workloadPackToInstall)
{
installer.RollBackWorkloadPackInstall(packId, sdkFeatureBand);
@@ -216,7 +255,6 @@ private void InstallWorkloadsWithInstallRecord(IEnumerable workloadI
// Don't hide the original error if roll back fails
_reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, e.Message));
}
-
});
}
else
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommandParser.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommandParser.cs
index 34051eb58024..3f27fd17b44d 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommandParser.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommandParser.cs
@@ -39,6 +39,9 @@ internal static class WorkloadInstallCommandParser
IsHidden = true
};
+ public static readonly Option IncludePreviewOption =
+ new Option("--include-previews", LocalizableStrings.IncludePreviewOptionDescription);
+
public static readonly Option FromCacheOption =
new Option("--from-cache", LocalizableStrings.FromCacheOptionDescription) { };
@@ -57,6 +60,7 @@ public static Command GetCommand()
command.AddOption(SkipManifestUpdateOption);
command.AddOption(PrintDownloadLinkOnlyOption);
command.AddOption(FromCacheOption);
+ command.AddOption(IncludePreviewOption);
command.AddOption(WorkloadCommandRestorePassThroughOptions.DisableParallelOption);
command.AddOption(WorkloadCommandRestorePassThroughOptions.IgnoreFailedSourcesOption);
command.AddOption(WorkloadCommandRestorePassThroughOptions.NoCacheOption);
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallRecords/IWorkloadInstallationRecordRepository.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallRecords/IWorkloadInstallationRecordRepository.cs
index c122614cb103..f38602ed62ad 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallRecords/IWorkloadInstallationRecordRepository.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallRecords/IWorkloadInstallationRecordRepository.cs
@@ -7,7 +7,7 @@ namespace Microsoft.DotNet.Workloads.Workload.Install.InstallRecord
{
internal interface IWorkloadInstallationRecordRepository
{
- IEnumerable GetInstalledWorkloads(SdkFeatureBand sdkFeatureBand);
+ IEnumerable GetInstalledWorkloads(SdkFeatureBand sdkFeatureBand);
void WriteWorkloadInstallationRecord(WorkloadId workloadId, SdkFeatureBand sdkFeatureBand);
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallRecords/NetSdkManagedInstallationRecordInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallRecords/NetSdkManagedInstallationRecordInstaller.cs
index 3123112d5ba6..abe512208b58 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallRecords/NetSdkManagedInstallationRecordInstaller.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallRecords/NetSdkManagedInstallationRecordInstaller.cs
@@ -32,17 +32,17 @@ public IEnumerable GetFeatureBandsWithInstallationRecords()
}
}
- public IEnumerable GetInstalledWorkloads(SdkFeatureBand featureBand)
+ public IEnumerable GetInstalledWorkloads(SdkFeatureBand featureBand)
{
var path = Path.Combine(_workloadMetadataDir, featureBand.ToString(), _installedWorkloadDir);
if (Directory.Exists(path))
{
return Directory.EnumerateFiles(path)
- .Select(file => Path.GetFileName(file));
+ .Select(file => new WorkloadId(Path.GetFileName(file)));
}
else
{
- return new List();
+ return new List();
}
}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs
new file mode 100644
index 000000000000..7505d2d2be30
--- /dev/null
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs
@@ -0,0 +1,172 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using Microsoft.DotNet.Cli.Utils;
+using Microsoft.NET.Sdk.WorkloadManifestReader;
+using System.IO;
+using System.Linq;
+using Microsoft.DotNet.Cli.NuGetPackageDownloader;
+using Microsoft.DotNet.ToolPackage;
+using System.Threading.Tasks;
+using Microsoft.DotNet.Workloads.Workload.Install.InstallRecord;
+
+namespace Microsoft.DotNet.Workloads.Workload.Install
+{
+ internal class WorkloadManifestUpdater : IWorkloadManifestUpdater
+ {
+ private readonly IReporter _reporter;
+ private readonly IWorkloadManifestProvider _workloadManifestProvider;
+ private readonly INuGetPackageDownloader _nugetPackageDownloader;
+ private readonly string _userHome;
+
+ public WorkloadManifestUpdater(
+ IReporter reporter,
+ IWorkloadManifestProvider workloadManifestProvider,
+ INuGetPackageDownloader nugetPackageDownloader,
+ string userHome)
+ {
+ _reporter = reporter;
+ _workloadManifestProvider = workloadManifestProvider;
+ _userHome = userHome;
+ _nugetPackageDownloader = nugetPackageDownloader;
+ }
+
+ public async Task UpdateAdvertisingManifestsAsync(SdkFeatureBand featureBand, bool includePreviews)
+ {
+ var manifests = GetInstalledManifestIds();
+ foreach (var manifest in manifests)
+ {
+ await UpdateAdvertisingManifestAsync(manifest, featureBand, includePreviews);
+ }
+ }
+
+ public IEnumerable<(ManifestId manifestId, ManifestVersion existingVersion, ManifestVersion newVersion)> CalculateManifestUpdates(SdkFeatureBand featureBand)
+ {
+ var manifestUpdates = new List<(ManifestId, ManifestVersion, ManifestVersion)>();
+ var currentManifestIds = GetInstalledManifestIds();
+ foreach (var manifestId in currentManifestIds)
+ {
+ var currentManifestVersion = GetInstalledManifestVersion(manifestId);
+ var adManifestVersion = GetAdvertisingManifestVersion(featureBand, manifestId);
+ if (adManifestVersion == null)
+ {
+ continue;
+ }
+
+ if (adManifestVersion != null && adManifestVersion.CompareTo(currentManifestVersion) > 0)
+ {
+ manifestUpdates.Add((manifestId, currentManifestVersion, adManifestVersion));
+ }
+ }
+ return manifestUpdates;
+ }
+
+ private IEnumerable GetInstalledManifestIds()
+ {
+ var manifestDirs = _workloadManifestProvider.GetManifestDirectories();
+
+ var manifests = new List();
+ foreach (var manifestDir in manifestDirs)
+ {
+ var manifestId = Path.GetFileName(manifestDir);
+ manifests.Add(new ManifestId(manifestId));
+ }
+ return manifests;
+ }
+
+ private async Task UpdateAdvertisingManifestAsync(ManifestId manifestId, SdkFeatureBand featureBand, bool includePreviews)
+ {
+ string packagePath = null;
+ string extractionPath = null;
+ try
+ {
+ var adManifestPath = GetAdvertisingManifestPath(featureBand, manifestId);
+ packagePath = await _nugetPackageDownloader.DownloadPackageAsync(GetManifestPackageId(featureBand, manifestId), includePreview: includePreviews);
+ extractionPath = Path.Combine(_userHome, ".dotnet", "sdk-advertising-temp", $"{manifestId}-extracted");
+ Directory.CreateDirectory(extractionPath);
+ var resultingFiles = await _nugetPackageDownloader.ExtractPackageAsync(packagePath, extractionPath);
+
+ if (Directory.Exists(adManifestPath))
+ {
+ Directory.Delete(adManifestPath, true);
+ }
+ Directory.CreateDirectory(Path.GetDirectoryName(adManifestPath));
+ FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(Path.Combine(extractionPath, "data"), adManifestPath));
+
+ _reporter.WriteLine(string.Format(LocalizableStrings.AdManifestUpdated, manifestId));
+ }
+ catch (Exception e)
+ {
+ _reporter.WriteLine(string.Format(LocalizableStrings.FailedAdManifestUpdate, manifestId, e.Message));
+ }
+ finally
+ {
+ if (!string.IsNullOrEmpty(extractionPath) && Directory.Exists(extractionPath))
+ {
+ Directory.Delete(extractionPath, true);
+ }
+
+ if (!string.IsNullOrEmpty(packagePath) && File.Exists(packagePath))
+ {
+ File.Delete(packagePath);
+ }
+
+ var versionDir = Path.GetDirectoryName(packagePath);
+ if (Directory.Exists(versionDir) && !Directory.GetFileSystemEntries(versionDir).Any())
+ {
+ Directory.Delete(versionDir);
+ var idDir = Path.GetDirectoryName(versionDir);
+ if (Directory.Exists(idDir) && !Directory.GetFileSystemEntries(idDir).Any())
+ {
+ Directory.Delete(idDir);
+ }
+ }
+ }
+ }
+
+ private ManifestVersion GetAdvertisingManifestVersion(SdkFeatureBand featureBand, ManifestId manifestId)
+ {
+ var manifestPath = Path.Combine(GetAdvertisingManifestPath(featureBand, manifestId), "WorkloadManifest.json");
+ if (!File.Exists(manifestPath))
+ {
+ return null;
+ }
+
+ using (FileStream fsSource = new FileStream(manifestPath, FileMode.Open, FileAccess.Read))
+ {
+ var manifest = WorkloadManifestReader.ReadWorkloadManifest(manifestId.ToString(), fsSource);
+ return new ManifestVersion(manifest.Version);
+ }
+ }
+
+ private ManifestVersion GetInstalledManifestVersion(ManifestId manifestId)
+ {
+ var manifestDir = _workloadManifestProvider.GetManifestDirectories()
+ .FirstOrDefault(dir => Path.GetFileName(dir).ToLowerInvariant().Equals(manifestId.ToString()));
+ if (manifestDir == null)
+ {
+ throw new Exception(string.Format(LocalizableStrings.ManifestDoesNotExist, manifestId.ToString()));
+ }
+
+ var manifestPath = Path.Combine(manifestDir, "WorkloadManifest.json");
+ if (!File.Exists(manifestPath))
+ {
+ throw new Exception(string.Format(LocalizableStrings.ManifestDoesNotExist, manifestId.ToString()));
+ }
+
+ using (FileStream fsSource = new FileStream(manifestPath, FileMode.Open, FileAccess.Read))
+ {
+ var manifest = WorkloadManifestReader.ReadWorkloadManifest(manifestId.ToString(), fsSource);
+ return new ManifestVersion(manifest.Version);
+ }
+ }
+
+ private string GetAdvertisingManifestPath(SdkFeatureBand featureBand, ManifestId manifestId) =>
+ Path.Combine(_userHome, ".dotnet", "sdk-advertising", featureBand.ToString(), manifestId.ToString());
+
+ internal static PackageId GetManifestPackageId(SdkFeatureBand featureBand, ManifestId manifestId) =>
+ new PackageId($"{manifestId}.Manifest-{featureBand}");
+ }
+}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.cs.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.cs.xlf
index c51f4cbdf4bd..7b23ab94fb4c 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.cs.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.cs.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
Cílová architektura, pro kterou se má nástroj nainstalovat
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.de.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.de.xlf
index 83112c5a9745..7a06b5d1b702 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.de.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.de.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
Das Zielframework, für das das Tool installiert wird.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.es.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.es.xlf
index aaa4936958ac..f606f3b78c10 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.es.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.es.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
La plataforma de destino para la que se instala la herramienta.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.fr.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.fr.xlf
index ba82634ccb4d..1714f55b708d 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.fr.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.fr.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
Framework cible pour lequel l'outil doit être installé.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.it.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.it.xlf
index eb3a22a67bac..51ba90260af4 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.it.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.it.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
Framework di destinazione per cui installare lo strumento.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ja.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ja.xlf
index 04f0d6bdb6dd..a6147473a0f9 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ja.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ja.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
ツールをインストールするターゲット フレームワーク。
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ko.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ko.xlf
index ed91f8f0faa5..f8741db805d2 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ko.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ko.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
도구를 설치할 대상 프레임워크입니다.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.pl.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.pl.xlf
index 94ea5c2185b7..e478c43078b5 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.pl.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.pl.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
Docelowa platforma, dla której ma zostać zainstalowane narzędzie.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.pt-BR.xlf
index a5637484a7ca..b8dfd1e3819f 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.pt-BR.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.pt-BR.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
A estrutura de destino para a qual instalar a ferramenta.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ru.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ru.xlf
index b215d10b1ebc..87b96f903fd1 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ru.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.ru.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
Целевая платформа для установки инструмента.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.tr.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.tr.xlf
index bd665139337c..b1e8b69a4369 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.tr.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.tr.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
Aracın yükleneceği hedef çerçeve.
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.zh-Hans.xlf
index 925e0830e36f..a43362149251 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.zh-Hans.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.zh-Hans.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
要安装工具的目标框架。
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.zh-Hant.xlf
index 0d8b78c5bb2b..8573aefda02c 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.zh-Hant.xlf
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.zh-Hant.xlf
@@ -2,6 +2,21 @@
+
+ Updated advertising manifest {0}.
+ Updated advertising manifest {0}.
+
+
+
+ Failed to update the advertising manifest {0}: {1}
+ Failed to update the advertising manifest {0}: {1}
+
+
+
+ Failed to install manifest {0} version {1}: {2}.
+ Failed to install manifest {0} version {1}: {2}.
+
+
Complete the operation from cache (offline).
Complete the operation from cache (offline).
@@ -12,6 +27,11 @@
Garbage collecting for SDK feature bands {0}...
+
+ Allow prerelease workload manifests.
+ Allow prerelease workload manifests.
+
+
Successfully installed workload(s) {0}.
Successfully installed workload(s) {0}.
@@ -22,6 +42,11 @@
Installing pack {0} version {1}...
+
+ Installing workload manifest {0} version {1}.
+ Installing workload manifest {0} version {1}.
+
+
The settings file in the workload's NuGet package is invalid: {0}
The settings file in the workload's NuGet package is invalid: {0}
@@ -42,6 +67,11 @@
要為工具安裝的目標 Framework。
+
+ No manifest with id {0} exists.
+ No manifest with id {0} exists.
+
+
Installation roll back failed: {0}
Installation roll back failed: {0}
diff --git a/src/Cli/dotnet/dotnet.csproj b/src/Cli/dotnet/dotnet.csproj
index ef20e1cce97a..4df160046b8f 100644
--- a/src/Cli/dotnet/dotnet.csproj
+++ b/src/Cli/dotnet/dotnet.csproj
@@ -16,6 +16,7 @@
+
diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadResolver.cs
index e6f12be05d00..90c5cbf719a0 100644
--- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadResolver.cs
+++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadResolver.cs
@@ -21,5 +21,10 @@ public interface IWorkloadResolver
/// A workload pack ID
/// Information about the workload pack, or null if the specified pack ID isn't found in the manifests
WorkloadResolver.PackInfo? TryGetPackInfo(string packId);
+
+ ///
+ /// Refresh workload and pack information based on the current installed workload manifest files
+ ///
+ void RefreshWorkloadManifests();
}
}
diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs
index 37f5529f92a7..80f9a3ce52de 100644
--- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs
+++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs
@@ -7,7 +7,6 @@
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
-
using Microsoft.DotNet.MSBuildSdkResolver;
namespace Microsoft.NET.Sdk.WorkloadManifestReader
@@ -20,6 +19,7 @@ public class WorkloadResolver : IWorkloadResolver
{
private readonly Dictionary _workloads = new Dictionary();
private readonly Dictionary _packs = new Dictionary();
+ private readonly IWorkloadManifestProvider _manifestProvider;
private string[] _currentRuntimeIdentifiers;
private readonly string [] _dotnetRootPaths;
@@ -61,10 +61,20 @@ private WorkloadResolver(IWorkloadManifestProvider manifestProvider, string [] d
{
_dotnetRootPaths = dotnetRootPaths;
_currentRuntimeIdentifiers = currentRuntimeIdentifiers;
+ _manifestProvider = manifestProvider;
+
+ RefreshWorkloadManifests();
+ }
+
+ public void RefreshWorkloadManifests()
+ {
+ _workloads.Clear();
+ _packs.Clear();
var manifests = new Dictionary(StringComparer.OrdinalIgnoreCase);
- foreach ((string manifestId, Stream manifestStream) in manifestProvider.GetManifests())
+ foreach ((string manifestId, Stream manifestStream) in _manifestProvider.GetManifests())
+
{
using (manifestStream)
{
diff --git a/src/Tests/dotnet-workload-install.Tests/GivenDotnetWorkloadInstall.cs b/src/Tests/dotnet-workload-install.Tests/GivenDotnetWorkloadInstall.cs
index 3c5a43214dbb..3e84e99e5443 100644
--- a/src/Tests/dotnet-workload-install.Tests/GivenDotnetWorkloadInstall.cs
+++ b/src/Tests/dotnet-workload-install.Tests/GivenDotnetWorkloadInstall.cs
@@ -2,10 +2,14 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
+using System.Collections.Generic;
+using System.CommandLine.Parsing;
using System.IO;
using System.Linq;
+using System.Runtime.CompilerServices;
using FluentAssertions;
using ManifestReaderTests;
+using Microsoft.DotNet.Cli.NuGetPackageDownloader;
using Microsoft.DotNet.Workloads.Workload.Install;
using Microsoft.NET.Sdk.WorkloadManifestReader;
using Microsoft.NET.TestFramework;
@@ -48,12 +52,8 @@ public void GivenWorkloadInstallItErrorsOnFakeWorkloadName()
public void GivenWorkloadInstallItCanInstallPacks()
{
var mockWorkloadIds = new WorkloadId[] { new WorkloadId("xamarin-android") };
- var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
- var dotnetRoot = Path.Combine(testDirectory, "dotnet");
- var installer = new MockPackWorkloadInstaller();
- var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), new string[] { dotnetRoot });
var parseResult = Parser.GetWorkloadsInstance.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "--skip-manifest-update" });
- var installManager = new WorkloadInstallCommand(parseResult, reporter: _reporter, workloadResolver: workloadResolver, workloadInstaller: installer, version: "6.0.100");
+ (_, var installManager, var installer, _, _) = GetTestInstallers(parseResult);
installManager.InstallWorkloads(mockWorkloadIds, true);
@@ -61,19 +61,14 @@ public void GivenWorkloadInstallItCanInstallPacks()
installer.InstallationRecordRepository.WorkloadInstallRecord.Should().BeEquivalentTo(mockWorkloadIds);
installer.InstalledPacks.Count.Should().Be(8);
installer.InstalledPacks.Where(pack => pack.Id.Contains("Android")).Count().Should().Be(8);
- _reporter.Lines.Contains(string.Format(LocalizableStrings.InstallationSucceeded, "xamarin-android"));
}
[Fact]
public void GivenWorkloadInstallItCanRollBackPackInstallation()
{
var mockWorkloadIds = new WorkloadId[] { new WorkloadId("xamarin-android"), new WorkloadId("xamarin-android-build") };
- var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
- var dotnetRoot = Path.Combine(testDirectory, "dotnet");
- var installer = new MockPackWorkloadInstaller(failingWorkload: "xamarin-android-build");
- var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), new string[] { dotnetRoot });
var parseResult = Parser.GetWorkloadsInstance.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "xamarin-android-build", "--skip-manifest-update" });
- var installManager = new WorkloadInstallCommand(parseResult, reporter: _reporter, workloadResolver: workloadResolver, workloadInstaller: installer, version: "6.0.100");
+ (_, var installManager, var installer, var workloadResolver, _) = GetTestInstallers(parseResult, failingWorkload: "xamarin-android-build");
var exceptionThrown = Assert.Throws(() => installManager.InstallWorkloads(mockWorkloadIds, true));
exceptionThrown.Message.Should().Be("Failing workload: xamarin-android-build");
@@ -101,6 +96,53 @@ public void GivenWorkloadInstallOnFailingRollbackItDisplaysTopLevelError()
exceptionThrown.Message.Should().Be("Failing workload: xamarin-android-build");
string.Join(" ", _reporter.Lines).Should().Contain("Rollback failure");
+ }
+
+ [Fact]
+ public void GivenWorkloadInstallItCanUpdateAdvertisingManifests()
+ {
+ var parseResult = Parser.GetWorkloadsInstance.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android" });
+ (_, var installManager, var installer, _, var manifestUpdater) = GetTestInstallers(parseResult);
+
+ installManager.InstallWorkloads(new List(), false); // Don't actually do any installs, just update manifests
+
+ installer.InstalledManifests.Should().BeEmpty(); // Didn't try to alter any installed manifests
+ manifestUpdater.CalculateManifestUpdatesCallParams.Should().BeEquivalentTo(new SdkFeatureBand[] { new SdkFeatureBand("6.0.100") });
+ manifestUpdater.UpdateAdvertisingManifestsCallParams.Should().BeEquivalentTo(new SdkFeatureBand[] { new SdkFeatureBand("6.0.100") });
+ }
+
+ [Fact]
+ public void GivenWorkloadInstallItCanUpdateInstalledManifests()
+ {
+ var parseResult = Parser.GetWorkloadsInstance.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android" });
+ var manifestsToUpdate = new (ManifestId, ManifestVersion, ManifestVersion)[] { };
+ (_, var installManager, var installer, _, _) = GetTestInstallers(parseResult, manifestUpdates: manifestsToUpdate);
+
+ installManager.InstallWorkloads(new List(), false); // Don't actually do any installs, just update manifests
+
+ installer.InstalledManifests.Should().BeEquivalentTo(manifestsToUpdate);
+ }
+
+ private (string, WorkloadInstallCommand, MockPackWorkloadInstaller, IWorkloadResolver, MockWorkloadManifestUpdater) GetTestInstallers(
+ ParseResult parseResult, [CallerMemberName] string testName = "", string failingWorkload = null, IEnumerable<(ManifestId, ManifestVersion, ManifestVersion)> manifestUpdates = null)
+ {
+ var testDirectory = _testAssetsManager.CreateTestDirectory(testName: testName).Path;
+ var dotnetRoot = Path.Combine(testDirectory, "dotnet");
+ var installer = new MockPackWorkloadInstaller(failingWorkload);
+ var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), new string[] { dotnetRoot });
+ var nugetDownloader = new MockNuGetPackageDownloader(dotnetRoot);
+ var manifestUpdater = new MockWorkloadManifestUpdater(manifestUpdates);
+ var installManager = new WorkloadInstallCommand(
+ parseResult,
+ reporter: _reporter,
+ workloadResolver: workloadResolver,
+ workloadInstaller: installer,
+ nugetPackageDownloader: nugetDownloader,
+ workloadManifestUpdater: manifestUpdater,
+ userHome: testDirectory,
+ version: "6.0.100");
+
+ return (testDirectory, installManager, installer, workloadResolver, manifestUpdater);
}
}
}
diff --git a/src/Tests/dotnet-workload-install.Tests/GivenNetSdkManagedWorkloadInstall.cs b/src/Tests/dotnet-workload-install.Tests/GivenNetSdkManagedWorkloadInstall.cs
index 1fe1693731fa..abc30118bb47 100644
--- a/src/Tests/dotnet-workload-install.Tests/GivenNetSdkManagedWorkloadInstall.cs
+++ b/src/Tests/dotnet-workload-install.Tests/GivenNetSdkManagedWorkloadInstall.cs
@@ -39,34 +39,39 @@ public void GivenManagedInstallItsInsallationUnitIsPacks()
installer.GetInstallationUnit().Should().Be(InstallationUnit.Packs);
}
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public void GivenManagedInstallItCanGetFeatureBands(bool writeRecords)
+ [Fact]
+ public void GivenManagedInstallItCanGetFeatureBandsWhenFilesArePresent()
{
var versions = new string[] { "6.0.100", "6.0.300", "7.0.100" };
- var (dotnetRoot, installer, _) = GetTestInstaller(identifier: writeRecords.ToString());
+ var (dotnetRoot, installer, _) = GetTestInstaller();
// Write fake workloads
foreach (var version in versions)
{
var path = Path.Combine(dotnetRoot, "metadata", "workloads", version, "InstalledWorkloads");
Directory.CreateDirectory(path);
- if (writeRecords)
- {
- File.Create(Path.Combine(path, "6.0.100"));
- }
+ File.Create(Path.Combine(path, "6.0.100"));
}
var featureBands = installer.GetWorkloadInstallationRecordRepository().GetFeatureBandsWithInstallationRecords();
- if (writeRecords)
- {
- featureBands.ShouldBeEquivalentTo(versions);
- }
- else
+ featureBands.ShouldBeEquivalentTo(versions);
+ }
+
+ [Fact]
+ public void GivenManagedInstallItCanNotGetFeatureBandsWhenFilesAreNotPresent()
+ {
+ var versions = new string[] { "6.0.100", "6.0.300", "7.0.100" };
+ var (dotnetRoot, installer, _) = GetTestInstaller();
+
+ // Write fake workloads
+ foreach (var version in versions)
{
- featureBands.Should().BeEmpty();
+ var path = Path.Combine(dotnetRoot, "metadata", "workloads", version, "InstalledWorkloads");
+ Directory.CreateDirectory(path);
}
+
+ var featureBands = installer.GetWorkloadInstallationRecordRepository().GetFeatureBandsWithInstallationRecords();
+ featureBands.Should().BeEmpty();
}
[Fact]
@@ -111,10 +116,10 @@ public void GivenManagedInstallItCanInstallDirectoryPacks()
installer.InstallWorkloadPack(packInfo, new SdkFeatureBand(version));
var mockNugetInstaller = nugetInstaller as MockNuGetPackageDownloader;
- mockNugetInstaller.InstallCallParams.Count.Should().Be(1);
- mockNugetInstaller.InstallCallParams[0].ShouldBeEquivalentTo((new PackageId(packInfo.Id), new NuGetVersion(packInfo.Version)));
+ mockNugetInstaller.DownloadCallParams.Count.Should().Be(1);
+ mockNugetInstaller.DownloadCallParams[0].ShouldBeEquivalentTo((new PackageId(packInfo.Id), new NuGetVersion(packInfo.Version)));
mockNugetInstaller.ExtractCallParams.Count.Should().Be(1);
- mockNugetInstaller.ExtractCallParams[0].ShouldBeEquivalentTo((mockNugetInstaller.InstallCallResult[0], Path.Combine(dotnetRoot, "metadata", "temp", $"{packInfo.Id}-{packInfo.Version}-extracted")));
+ mockNugetInstaller.ExtractCallParams[0].ShouldBeEquivalentTo((mockNugetInstaller.DownloadCallResult[0], Path.Combine(dotnetRoot, "metadata", "temp", $"{packInfo.Id}-{packInfo.Version}-extracted")));
var installationRecordPath = Path.Combine(dotnetRoot, "metadata", "workloads", "InstalledPacks", "v1", packInfo.Id, packInfo.Version, version);
File.Exists(installationRecordPath).Should().BeTrue();
@@ -130,8 +135,8 @@ public void GivenManagedInstallItCanInstallSingleFilePacks()
var version = "6.0.100";
installer.InstallWorkloadPack(packInfo, new SdkFeatureBand(version));
- (nugetInstaller as MockNuGetPackageDownloader).InstallCallParams.Count.Should().Be(1);
- (nugetInstaller as MockNuGetPackageDownloader).InstallCallParams[0].ShouldBeEquivalentTo((new PackageId(packInfo.Id), new NuGetVersion(packInfo.Version)));
+ (nugetInstaller as MockNuGetPackageDownloader).DownloadCallParams.Count.Should().Be(1);
+ (nugetInstaller as MockNuGetPackageDownloader).DownloadCallParams[0].ShouldBeEquivalentTo((new PackageId(packInfo.Id), new NuGetVersion(packInfo.Version)));
(nugetInstaller as MockNuGetPackageDownloader).ExtractCallParams.Count.Should().Be(0);
var installationRecordPath = Path.Combine(dotnetRoot, "metadata", "workloads", "InstalledPacks", "v1", packInfo.Id, packInfo.Version, version);
@@ -149,8 +154,8 @@ public void GivenManagedInstallItCanInstallPacksWithAliases()
var version = "6.0.100";
installer.InstallWorkloadPack(packInfo, new SdkFeatureBand(version));
- (nugetInstaller as MockNuGetPackageDownloader).InstallCallParams.Count.Should().Be(1);
- (nugetInstaller as MockNuGetPackageDownloader).InstallCallParams[0].ShouldBeEquivalentTo((new PackageId(alias), new NuGetVersion(packInfo.Version)));
+ (nugetInstaller as MockNuGetPackageDownloader).DownloadCallParams.Count.Should().Be(1);
+ (nugetInstaller as MockNuGetPackageDownloader).DownloadCallParams[0].ShouldBeEquivalentTo((new PackageId(alias), new NuGetVersion(packInfo.Version)));
}
[Fact]
@@ -165,7 +170,7 @@ public void GivenManagedInstallItDetectsInstalledPacks()
installer.InstallWorkloadPack(packInfo, new SdkFeatureBand(version));
- (nugetInstaller as MockNuGetPackageDownloader).InstallCallParams.Count.Should().Be(0);
+ (nugetInstaller as MockNuGetPackageDownloader).DownloadCallParams.Count.Should().Be(0);
}
[Fact]
@@ -283,11 +288,26 @@ public void GivenManagedInstallItDoesNotRemovePacksWithInstallRecords()
}
}
- private (string, NetSdkManagedInstaller, INuGetPackageDownloader) GetTestInstaller([CallerMemberName] string testName = "", bool failingInstaller = false, string identifier = "")
+ [Fact]
+ public void GivenManagedInstallItCanInstallManifestVersion()
+ {
+ var (_, installer, nugetDownloader) = GetTestInstaller(manifestDownload: true);
+ var featureBand = new SdkFeatureBand("6.0.100");
+ var manifestId = new ManifestId("test-manifest-1");
+ var manifestVersion = new ManifestVersion("5.0.0");
+
+ installer.InstallWorkloadManifest(manifestId, manifestVersion, featureBand);
+
+ var mockNugetInstaller = nugetDownloader as MockNuGetPackageDownloader;
+ mockNugetInstaller.DownloadCallParams.Count.Should().Be(1);
+ mockNugetInstaller.DownloadCallParams[0].ShouldBeEquivalentTo((new PackageId($"{manifestId}.manifest-{featureBand}"), new NuGetVersion(manifestVersion.ToString())));
+ }
+
+ private (string, NetSdkManagedInstaller, INuGetPackageDownloader) GetTestInstaller([CallerMemberName] string testName = "", bool failingInstaller = false, string identifier = "", bool manifestDownload = false)
{
var testDirectory = _testAssetsManager.CreateTestDirectory(testName, identifier: identifier).Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
- INuGetPackageDownloader nugetInstaller = failingInstaller ? new FailingNuGetPackageDownloader(testDirectory) : new MockNuGetPackageDownloader(dotnetRoot);
+ INuGetPackageDownloader nugetInstaller = failingInstaller ? new FailingNuGetPackageDownloader(testDirectory) : new MockNuGetPackageDownloader(dotnetRoot, manifestDownload);
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), new string[] { dotnetRoot });
var sdkFeatureBand = new SdkFeatureBand("6.0.100");
return (dotnetRoot, new NetSdkManagedInstaller(_reporter, sdkFeatureBand, workloadResolver, nugetInstaller, dotnetRoot), nugetInstaller);
diff --git a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs
new file mode 100644
index 000000000000..5f2b4714662f
--- /dev/null
+++ b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs
@@ -0,0 +1,116 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.IO;
+using System.Linq;
+using FluentAssertions;
+using ManifestReaderTests;
+using Microsoft.DotNet.Cli.NuGetPackageDownloader;
+using Microsoft.DotNet.ToolPackage;
+using Microsoft.DotNet.Workloads.Workload.Install;
+using Microsoft.NET.TestFramework;
+using Microsoft.NET.TestFramework.Utilities;
+using NuGet.Versioning;
+using Xunit;
+using Xunit.Abstractions;
+using Microsoft.DotNet.Workloads.Workload.Install.InstallRecord;
+
+namespace Microsoft.DotNet.Cli.Workload.Install.Tests
+{
+ public class GivenWorkloadManifestUpdater : SdkTest
+ {
+ private readonly BufferedReporter _reporter;
+ private readonly string _manifestFileName = "WorkloadManifest.json";
+
+ public GivenWorkloadManifestUpdater(ITestOutputHelper log) : base(log)
+ {
+ _reporter = new BufferedReporter();
+ }
+
+ [Fact]
+ public void GivenWorkloadManifestUpdateItCanUpdateAdvertisingManifests()
+ {
+ var testDir = _testAssetsManager.CreateTestDirectory().Path;
+ var featureBand = "6.0.100";
+ var dotnetRoot = Path.Combine(testDir, "dotnet");
+ var installedManifests = new ManifestId[] { new ManifestId("test-manifest-1"), new ManifestId("test-manifest-2"), new ManifestId("test-manifest-3") };
+
+ // Write mock manifests
+ var installedManifestDir = Path.Combine(testDir, "dotnet", "sdk-manifests", featureBand);
+ var adManifestDir = Path.Combine(testDir, ".dotnet", "sdk-advertising", featureBand);
+ Directory.CreateDirectory(installedManifestDir);
+ Directory.CreateDirectory(adManifestDir);
+ foreach (var manifest in installedManifests)
+ {
+ Directory.CreateDirectory(Path.Combine(installedManifestDir, manifest.ToString()));
+ File.WriteAllText(Path.Combine(installedManifestDir, manifest.ToString(), _manifestFileName), GetManifestContent(new ManifestVersion("1.0.0")));
+ }
+
+ var manifestDirs = installedManifests
+ .Select(manifest => Path.Combine(installedManifestDir, manifest.ToString(), _manifestFileName))
+ .ToArray();
+ var workloadManifestProvider = new MockManifestProvider(manifestDirs);
+ var nugetDownloader = new MockNuGetPackageDownloader(dotnetRoot);
+ var manifestUpdater = new WorkloadManifestUpdater(_reporter, workloadManifestProvider, nugetDownloader, testDir);
+
+ manifestUpdater.UpdateAdvertisingManifestsAsync(new SdkFeatureBand(featureBand), true).Wait();
+ var expectedDownloadedPackages = installedManifests.Select(id => ((PackageId, NuGetVersion))(new PackageId($"{id}.manifest-{featureBand}"), null));
+ nugetDownloader.DownloadCallParams.Should().BeEquivalentTo(expectedDownloadedPackages);
+ }
+
+ [Fact]
+ public void GivenWorkloadManifestUpdateItCanCalculateUpdates()
+ {
+ var testDir = _testAssetsManager.CreateTestDirectory().Path;
+ var featureBand = "6.0.100";
+ var dotnetRoot = Path.Combine(testDir, "dotnet");
+ var expectedManifestUpdates = new (ManifestId, ManifestVersion, ManifestVersion)[] {
+ (new ManifestId("test-manifest-1"), new ManifestVersion("5.0.0"), new ManifestVersion("7.0.0")),
+ (new ManifestId("test-manifest-2"), new ManifestVersion("3.0.0"), new ManifestVersion("4.0.0")) };
+ var expectedManifestNotUpdated = new ManifestId[] { new ManifestId("test-manifest-3"), new ManifestId("test-manifest-4") };
+
+ // Write mock manifests
+ var installedManifestDir = Path.Combine(testDir, "dotnet", "sdk-manifests", featureBand);
+ var adManifestDir = Path.Combine(testDir, ".dotnet", "sdk-advertising", featureBand);
+ Directory.CreateDirectory(installedManifestDir);
+ Directory.CreateDirectory(adManifestDir);
+ foreach ((var manifestId, var existingVersion, var newVersion) in expectedManifestUpdates)
+ {
+ Directory.CreateDirectory(Path.Combine(installedManifestDir, manifestId.ToString()));
+ File.WriteAllText(Path.Combine(installedManifestDir, manifestId.ToString(), _manifestFileName), GetManifestContent(existingVersion));
+ Directory.CreateDirectory(Path.Combine(adManifestDir, manifestId.ToString()));
+ File.WriteAllText(Path.Combine(adManifestDir, manifestId.ToString(), _manifestFileName), GetManifestContent(newVersion));
+ }
+ foreach (var manifest in expectedManifestNotUpdated)
+ {
+ Directory.CreateDirectory(Path.Combine(installedManifestDir, manifest.ToString()));
+ File.WriteAllText(Path.Combine(installedManifestDir, manifest.ToString(), _manifestFileName), GetManifestContent(new ManifestVersion("5.0.0")));
+ Directory.CreateDirectory(Path.Combine(adManifestDir, manifest.ToString()));
+ File.WriteAllText(Path.Combine(adManifestDir, manifest.ToString(), _manifestFileName), GetManifestContent(new ManifestVersion("5.0.0")));
+ }
+
+ var manifestDirs = expectedManifestUpdates.Select(manifest => manifest.Item1)
+ .Concat(expectedManifestNotUpdated)
+ .Select(manifest => Path.Combine(installedManifestDir, manifest.ToString(), _manifestFileName))
+ .ToArray();
+ var workloadManifestProvider = new MockManifestProvider(manifestDirs);
+ var nugetDownloader = new MockNuGetPackageDownloader(dotnetRoot);
+ var manifestUpdater = new WorkloadManifestUpdater(_reporter, workloadManifestProvider, nugetDownloader, testDir);
+
+ var manifestUpdates = manifestUpdater.CalculateManifestUpdates(new SdkFeatureBand(featureBand));
+ manifestUpdates.Should().BeEquivalentTo(expectedManifestUpdates);
+ }
+
+ internal static string GetManifestContent(ManifestVersion version)
+ {
+ return $@"{{
+ ""version"": {version.ToString().Substring(0, 1)},
+ ""workloads"": {{
+ }}
+ }},
+ ""packs"": {{
+ }}
+}}";
+ }
+ }
+}
diff --git a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs
index ca35918539ef..ae369af4ecfb 100644
--- a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs
+++ b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs
@@ -16,7 +16,13 @@ public MockManifestProvider(params string[] filePaths)
_filePaths = filePaths;
}
- public IEnumerable GetManifestDirectories() => throw new System.NotImplementedException();
+ public IEnumerable GetManifestDirectories()
+ {
+ foreach (var filePath in _filePaths)
+ {
+ yield return Path.GetDirectoryName(filePath);
+ }
+ }
public IEnumerable<(string manifestId, Stream manifestStream)> GetManifests()
{
@@ -25,5 +31,5 @@ public MockManifestProvider(params string[] filePaths)
yield return (filePath, new FileStream(filePath, FileMode.Open, FileAccess.Read));
}
}
- }
+ }
}
diff --git a/src/Tests/dotnet-workload-install.Tests/MockNuGetPackageInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockNuGetPackageInstaller.cs
index f04efc9de89a..0a330c502ee9 100644
--- a/src/Tests/dotnet-workload-install.Tests/MockNuGetPackageInstaller.cs
+++ b/src/Tests/dotnet-workload-install.Tests/MockNuGetPackageInstaller.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
@@ -11,27 +12,30 @@ namespace Microsoft.DotNet.Cli.NuGetPackageDownloader
{
internal class MockNuGetPackageDownloader : INuGetPackageDownloader
{
- private readonly string _installPath;
+ private readonly string _downloadPath;
+ private readonly bool _manifestDownload;
- public List<(PackageId, NuGetVersion)> InstallCallParams = new List<(PackageId, NuGetVersion)>();
+ public List<(PackageId, NuGetVersion)> DownloadCallParams = new List<(PackageId, NuGetVersion)>();
- public List InstallCallResult = new List();
+ public List DownloadCallResult = new List();
public List<(string, string)> ExtractCallParams = new List<(string, string)>();
- public MockNuGetPackageDownloader(string dotnetRoot)
+ public MockNuGetPackageDownloader(string dotnetRoot, bool manifestDownload = false)
{
- _installPath = Path.Combine(dotnetRoot, "metadata", "temp");
- Directory.CreateDirectory(_installPath);
+ _manifestDownload = manifestDownload;
+ _downloadPath = Path.Combine(dotnetRoot, "metadata", "temp");
+ Directory.CreateDirectory(_downloadPath);
}
- public Task DownloadPackageAsync(PackageId packageId, NuGetVersion packageVersion,
+ public Task DownloadPackageAsync(PackageId packageId,
+ NuGetVersion packageVersion = null,
PackageSourceLocation packageSourceLocation = null,
bool includePreview = false)
{
- InstallCallParams.Add((packageId, packageVersion));
- var path = Path.Combine(_installPath, "mock.nupkg");
- InstallCallResult.Add(path);
+ DownloadCallParams.Add((packageId, packageVersion));
+ var path = Path.Combine(_downloadPath, "mock.nupkg");
+ DownloadCallResult.Add(path);
File.WriteAllText(path, string.Empty);
return Task.FromResult(path);
}
@@ -39,6 +43,10 @@ public Task DownloadPackageAsync(PackageId packageId, NuGetVersion packa
public Task> ExtractPackageAsync(string packagePath, string targetFolder)
{
ExtractCallParams.Add((packagePath, targetFolder));
+ if (_manifestDownload)
+ {
+ Directory.CreateDirectory(Path.Combine(targetFolder, "data"));
+ }
return Task.FromResult(new List() as IEnumerable);
}
}
diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs
index 419ef6fc3a45..3aba1c2a2675 100644
--- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs
+++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs
@@ -13,6 +13,8 @@ internal class MockPackWorkloadInstaller : IWorkloadPackInstaller
{
public IList InstalledPacks = new List();
public IList RolledBackPacks = new List();
+ public IList<(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand)> InstalledManifests =
+ new List<(ManifestId, ManifestVersion, SdkFeatureBand)>();
public bool GarbageCollectionCalled = false;
public MockInstallationRecordRepository InstallationRecordRepository;
public bool FailingRollback;
@@ -57,8 +59,12 @@ public IWorkloadInstallationRecordRepository GetWorkloadInstallationRecordReposi
return InstallationRecordRepository;
}
+ public void InstallWorkloadManifest(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand)
+ {
+ InstalledManifests.Add((manifestId, manifestVersion, sdkFeatureBand));
+ }
+
public void DownloadToOfflineCache(IEnumerable manifests) => throw new System.NotImplementedException();
- public void InstallWorkloadManifest(ManifestId manifestId, ManifestVersion manifestVersion, SdkFeatureBand sdkFeatureBand) => throw new System.NotImplementedException();
public IWorkloadInstaller GetWorkloadInstaller() => throw new NotImplementedException();
}
@@ -85,8 +91,11 @@ public void DeleteWorkloadInstallationRecord(WorkloadId workloadId, SdkFeatureBa
{
WorkloadInstallRecord.Remove(workloadId);
}
+ public IEnumerable GetInstalledWorkloads(SdkFeatureBand sdkFeatureBand)
+ {
+ return new List();
+ }
- public IEnumerable GetInstalledWorkloads(SdkFeatureBand sdkFeatureBand) => throw new NotImplementedException();
public IEnumerable GetFeatureBandsWithInstallationRecords() => throw new NotImplementedException();
}
}
diff --git a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs
new file mode 100644
index 000000000000..bc770f18ea1c
--- /dev/null
+++ b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs
@@ -0,0 +1,34 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.DotNet.Workloads.Workload.Install;
+using Microsoft.DotNet.Workloads.Workload.Install.InstallRecord;
+
+namespace Microsoft.DotNet.Cli.Workload.Install.Tests
+{
+ internal class MockWorkloadManifestUpdater : IWorkloadManifestUpdater
+ {
+ public List UpdateAdvertisingManifestsCallParams = new List();
+ public List CalculateManifestUpdatesCallParams = new List();
+ private IEnumerable<(ManifestId, ManifestVersion, ManifestVersion)> _manifestUpdates;
+
+ public MockWorkloadManifestUpdater(IEnumerable<(ManifestId, ManifestVersion, ManifestVersion)> manifestUpdates = null)
+ {
+ _manifestUpdates = manifestUpdates ?? new List<(ManifestId, ManifestVersion, ManifestVersion)>();
+ }
+
+ public Task UpdateAdvertisingManifestsAsync(SdkFeatureBand featureBand, bool includePreview)
+ {
+ UpdateAdvertisingManifestsCallParams.Add(featureBand);
+ return Task.CompletedTask;
+ }
+
+ public IEnumerable<(ManifestId, ManifestVersion, ManifestVersion)> CalculateManifestUpdates(SdkFeatureBand featureBand)
+ {
+ CalculateManifestUpdatesCallParams.Add(featureBand);
+ return _manifestUpdates;
+ }
+ }
+}