From cdba4ac273ff022abb0af5538e316944eee00db9 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 28 Dec 2023 15:30:14 -0800 Subject: [PATCH 01/43] Support accessing install mode Causes the dotnet workload update/install/repair commands to use a new GetWorkloadInstallMode method to decide whether to use workload sets or not. If they decide to use workload sets, they calculate manifest updates by reading from a dictionary that is not implemented. --- .../install/FileBasedInstaller.cs | 7 +++++ .../dotnet-workload/install/IInstaller.cs | 2 ++ .../install/IWorkloadManifestUpdater.cs | 2 +- .../install/MsiInstallerBase.cs | 7 +++++ .../install/NetSdkMsiInstallerClient.cs | 2 ++ .../install/WorkloadInstallCommand.cs | 2 +- .../install/WorkloadManifestUpdater.cs | 31 +++++++++++++++++-- .../update/WorkloadUpdateCommand.cs | 2 +- .../MockPackWorkloadInstaller.cs | 2 ++ .../MockWorkloadManifestUpdater.cs | 2 +- 10 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 08cd93199320..5af12dadc6eb 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -702,5 +702,12 @@ private bool PackHasInstallRecords(PackInfo packInfo) } private bool IsSingleFilePack(PackInfo packInfo) => packInfo.Kind.Equals(WorkloadPackKind.Library) || packInfo.Kind.Equals(WorkloadPackKind.Template); + + public bool GetWorkloadInstallMode(SdkFeatureBand sdkFeatureBand) + { + string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, _dotnetDir), "default.json"); + var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + return installStateContents.UseWorkloadSets ?? false; + } } } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index 5d388ef8bd21..7549c56923cb 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -48,6 +48,8 @@ internal interface IInstaller : IWorkloadManifestInstaller void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dictionary manifestContents); void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode); + + bool GetWorkloadInstallMode(SdkFeatureBand sdkFeatureBand); } // Interface to pass to workload manifest updater diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs index d9dec221ad29..01a5bcfeb74a 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs @@ -12,7 +12,7 @@ internal interface IWorkloadManifestUpdater Task BackgroundUpdateAdvertisingManifestsWhenRequiredAsync(); - IEnumerable CalculateManifestUpdates(); + IEnumerable CalculateManifestUpdates(bool useWorkloadSets); IEnumerable CalculateManifestRollbacks(string rollbackDefinitionFilePath); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs index 5cf0b2ab0eb5..c08adfc11578 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs @@ -309,6 +309,13 @@ protected void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) } } + protected bool GetInstallMode(SdkFeatureBand sdkFeatureBand) + { + string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); + var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + return installStateContents.UseWorkloadSets ?? false; + } + /// /// Installs the specified MSI. /// diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 566beb0cedfc..02573cb7954e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -1076,5 +1076,7 @@ private void OnProcessExit(object sender, EventArgs e) } void IInstaller.UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) => UpdateInstallMode(sdkFeatureBand, newMode); + + public bool GetWorkloadInstallMode(SdkFeatureBand sdkFeatureBand) => GetInstallMode(sdkFeatureBand); } } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 586c8b87fd74..ec48db716798 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -162,7 +162,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, offlineCache).Wait(); manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); + _workloadManifestUpdater.CalculateManifestUpdates(_workloadInstaller.GetWorkloadInstallMode(_sdkFeatureBand)).Select(m => m.ManifestUpdate); } InstallWorkloadsWithInstallRecord(_workloadInstaller, workloadIds, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index a7fe27c39f50..7f44f2ecb0a1 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -157,12 +157,39 @@ public static void AdvertiseWorkloadUpdates() } } - public IEnumerable CalculateManifestUpdates() + private Dictionary GetManifestVersionsFromWorkloadSet() + { + return null; + } + + public IEnumerable CalculateManifestUpdates(bool useWorkloadSets) { var currentManifestIds = GetInstalledManifestIds(); + Dictionary manifestsFromSet = null; + if (useWorkloadSets) + { + manifestsFromSet = GetManifestVersionsFromWorkloadSet(); + if (manifestsFromSet is null) + { + // Fall back to loose manifests? Consult with team. + useWorkloadSets = false; + } + } + foreach (var manifestId in currentManifestIds) { - var advertisingInfo = GetAdvertisingManifestVersionAndWorkloads(manifestId); + (ManifestVersionWithBand, WorkloadCollection)? advertisingInfo = null; + if (useWorkloadSets) + { + // This out parameter only takes the non-nullable type, but as a value type, it has to be nullable if it may be null, as it is if it is absent. + manifestsFromSet.TryGetValue(manifestId, out var advertInfo); + advertisingInfo = advertInfo; + } + else + { + advertisingInfo = GetAdvertisingManifestVersionAndWorkloads(manifestId); + } + if (advertisingInfo == null) { continue; diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index a14ad7e4d00b..45363422be7d 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -126,7 +126,7 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline var manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); + _workloadManifestUpdater.CalculateManifestUpdates(_workloadInstaller.GetWorkloadInstallMode(_sdkFeatureBand)).Select(m => m.ManifestUpdate); UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, useRollback, offlineCache); diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 61d6dc6f24d8..9ae762e2d296 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -184,6 +184,8 @@ public void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dict installStateContents.Manifests = manifestContents; File.WriteAllText(path, installStateContents.ToString()); } + + public bool GetWorkloadInstallMode(SdkFeatureBand sdkFeatureBand) => throw new NotImplementedException(); } internal class MockInstallationRecordRepository : IWorkloadInstallationRecordRepository diff --git a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs index 6a3d90073c64..799214f970c7 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs @@ -25,7 +25,7 @@ public Task UpdateAdvertisingManifestsAsync(bool includePreview, DirectoryPath? return Task.CompletedTask; } - public IEnumerable CalculateManifestUpdates() + public IEnumerable CalculateManifestUpdates(bool useWorkloadSets) { CalculateManifestUpdatesCallCount++; return _manifestUpdates; From 3a54940d85962a18c8ea97b2300f24a8c54d286b Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:56:59 -0800 Subject: [PATCH 02/43] Simplify getting install mode --- src/Cli/dotnet/commands/InstallingWorkloadCommand.cs | 7 +++++++ .../commands/dotnet-workload/install/FileBasedInstaller.cs | 7 ------- .../dotnet/commands/dotnet-workload/install/IInstaller.cs | 2 -- .../commands/dotnet-workload/install/MsiInstallerBase.cs | 7 ------- .../dotnet-workload/install/NetSdkMsiInstallerClient.cs | 2 -- .../dotnet-workload/install/WorkloadInstallCommand.cs | 2 +- .../dotnet-workload/update/WorkloadUpdateCommand.cs | 2 +- .../MockPackWorkloadInstaller.cs | 2 -- 8 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index 9e010dfb3632..345438429123 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -96,6 +96,13 @@ protected static Dictionary GetInstallStateContents(IEnumerable< manifestVersionUpdates.Select(update => new WorkloadManifestInfo(update.ManifestId.ToString(), update.NewVersion.ToString(), /* We don't actually use the directory here */ string.Empty, update.NewFeatureBand)) ).ToDictionaryForJson(); + public static bool GetInstallStateMode(SdkFeatureBand sdkFeatureBand, string dotnetDir) + { + string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, dotnetDir), "default.json"); + var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + return installStateContents.UseWorkloadSets ?? false; + } + protected async Task> GetDownloads(IEnumerable workloadIds, bool skipManifestUpdate, bool includePreview, string downloadFolder = null) { List ret = new(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 5af12dadc6eb..08cd93199320 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -702,12 +702,5 @@ private bool PackHasInstallRecords(PackInfo packInfo) } private bool IsSingleFilePack(PackInfo packInfo) => packInfo.Kind.Equals(WorkloadPackKind.Library) || packInfo.Kind.Equals(WorkloadPackKind.Template); - - public bool GetWorkloadInstallMode(SdkFeatureBand sdkFeatureBand) - { - string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, _dotnetDir), "default.json"); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); - return installStateContents.UseWorkloadSets ?? false; - } } } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index 7549c56923cb..5d388ef8bd21 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -48,8 +48,6 @@ internal interface IInstaller : IWorkloadManifestInstaller void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dictionary manifestContents); void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode); - - bool GetWorkloadInstallMode(SdkFeatureBand sdkFeatureBand); } // Interface to pass to workload manifest updater diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs index c08adfc11578..5cf0b2ab0eb5 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs @@ -309,13 +309,6 @@ protected void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) } } - protected bool GetInstallMode(SdkFeatureBand sdkFeatureBand) - { - string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); - return installStateContents.UseWorkloadSets ?? false; - } - /// /// Installs the specified MSI. /// diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 02573cb7954e..566beb0cedfc 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -1076,7 +1076,5 @@ private void OnProcessExit(object sender, EventArgs e) } void IInstaller.UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) => UpdateInstallMode(sdkFeatureBand, newMode); - - public bool GetWorkloadInstallMode(SdkFeatureBand sdkFeatureBand) => GetInstallMode(sdkFeatureBand); } } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index ec48db716798..16cc52171490 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -162,7 +162,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, offlineCache).Wait(); manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates(_workloadInstaller.GetWorkloadInstallMode(_sdkFeatureBand)).Select(m => m.ManifestUpdate); + _workloadManifestUpdater.CalculateManifestUpdates(GetInstallStateMode(_sdkFeatureBand, _dotnetPath)).Select(m => m.ManifestUpdate); } InstallWorkloadsWithInstallRecord(_workloadInstaller, workloadIds, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 45363422be7d..32da72aacded 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -126,7 +126,7 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline var manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates(_workloadInstaller.GetWorkloadInstallMode(_sdkFeatureBand)).Select(m => m.ManifestUpdate); + _workloadManifestUpdater.CalculateManifestUpdates(GetInstallStateMode(_sdkFeatureBand, _dotnetPath)).Select(m => m.ManifestUpdate); UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, useRollback, offlineCache); diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 9ae762e2d296..61d6dc6f24d8 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -184,8 +184,6 @@ public void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dict installStateContents.Manifests = manifestContents; File.WriteAllText(path, installStateContents.ToString()); } - - public bool GetWorkloadInstallMode(SdkFeatureBand sdkFeatureBand) => throw new NotImplementedException(); } internal class MockInstallationRecordRepository : IWorkloadInstallationRecordRepository From 65ea81a22e8354e4614ca922065c17a39e444ff2 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:46:11 -0800 Subject: [PATCH 03/43] Update to use workload sets --- .../install/FileBasedInstaller.cs | 9 ++++++++- .../install/IWorkloadManifestUpdater.cs | 2 +- .../install/NetSdkMsiInstallerClient.cs | 9 ++++++++- .../install/WorkloadInstallCommand.cs | 5 +++-- .../install/WorkloadManifestUpdater.cs | 17 ++++++++++++----- .../dotnet-workload/list/WorkloadListCommand.cs | 5 ++++- .../update/WorkloadUpdateCommand.cs | 13 ++++++++++--- .../GivenWorkloadManifestUpdater.cs | 6 +++--- .../MockWorkloadManifestUpdater.cs | 2 +- 9 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 08cd93199320..c75d25e78068 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -509,7 +509,14 @@ public void Shutdown() public PackageId GetManifestPackageId(ManifestId manifestId, SdkFeatureBand featureBand) { - return new PackageId($"{manifestId}.Manifest-{featureBand}"); + if (manifestId.ToString().Equals("Microsoft.NET.Workloads")) + { + return new PackageId($"{manifestId}.{featureBand}"); + } + else + { + return new PackageId($"{manifestId}.Manifest-{featureBand}"); + } } public async Task ExtractManifestAsync(string nupkgPath, string targetPath) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs index 01a5bcfeb74a..b9948a3266ca 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs @@ -8,7 +8,7 @@ namespace Microsoft.DotNet.Workloads.Workload.Install { internal interface IWorkloadManifestUpdater { - Task UpdateAdvertisingManifestsAsync(bool includePreviews, DirectoryPath? offlineCache = null); + Task UpdateAdvertisingManifestsAsync(bool includePreviews, bool useWorkloadSets = false, DirectoryPath? offlineCache = null); Task BackgroundUpdateAdvertisingManifestsWhenRequiredAsync(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 566beb0cedfc..5fd9849d135d 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -555,7 +555,14 @@ public void Shutdown() public PackageId GetManifestPackageId(ManifestId manifestId, SdkFeatureBand featureBand) { - return new PackageId($"{manifestId}.Manifest-{featureBand}.Msi.{RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant()}"); + if (manifestId.ToString().Equals("Microsoft.NET.Workloads")) + { + return new PackageId($"{manifestId}.{featureBand}.Msi.{RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant()}"); + } + else + { + return new PackageId($"{manifestId}.Manifest-{featureBand}.Msi.{RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant()}"); + } } private static object _msiAdminInstallLock = new(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 16cc52171490..49ffd413ce4b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -157,12 +157,13 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif } workloadIds = workloadIds.Concat(installedWorkloads).Distinct(); + var useWorkloadSets = GetInstallStateMode(_sdkFeatureBand, _dotnetPath); useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); - _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, offlineCache).Wait(); + _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates(GetInstallStateMode(_sdkFeatureBand, _dotnetPath)).Select(m => m.ManifestUpdate); + _workloadManifestUpdater.CalculateManifestUpdates(useWorkloadSets).Select(m => m.ManifestUpdate); } InstallWorkloadsWithInstallRecord(_workloadInstaller, workloadIds, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 7f44f2ecb0a1..3f00a585fe57 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -72,12 +72,19 @@ private static WorkloadManifestUpdater GetInstance(string userProfileDir) return new WorkloadManifestUpdater(reporter, workloadResolver, nugetPackageDownloader, userProfileDir, workloadRecordRepo, installer); } - public async Task UpdateAdvertisingManifestsAsync(bool includePreviews, DirectoryPath? offlineCache = null) + public async Task UpdateAdvertisingManifestsAsync(bool includePreviews, bool useWorkloadSets = false, DirectoryPath? offlineCache = null) { - // this updates all the manifests - var manifests = _workloadResolver.GetInstalledManifests(); - await Task.WhenAll(manifests.Select(manifest => UpdateAdvertisingManifestAsync(manifest, includePreviews, offlineCache))).ConfigureAwait(false); - WriteUpdatableWorkloadsFile(); + if (useWorkloadSets) + { + await UpdateAdvertisingManifestAsync(new WorkloadManifestInfo("Microsoft.NET.Workloads", null, null, _sdkFeatureBand.ToString()), includePreviews, offlineCache); + } + else + { + // this updates all the manifests + var manifests = _workloadResolver.GetInstalledManifests(); + await Task.WhenAll(manifests.Select(manifest => UpdateAdvertisingManifestAsync(manifest, includePreviews, offlineCache))).ConfigureAwait(false); + WriteUpdatableWorkloadsFile(); + } } public async static Task BackgroundUpdateAdvertisingManifestsAsync(string userProfileDir) diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs index 2a3d861b517e..d98de3fc5621 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs @@ -3,6 +3,7 @@ using System.CommandLine; using System.Text.Json; +using Microsoft.Deployment.DotNet.Releases; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.NuGetPackageDownloader; using Microsoft.DotNet.Cli.Utils; @@ -12,6 +13,7 @@ using Microsoft.NET.Sdk.WorkloadManifestReader; using Microsoft.TemplateEngine.Cli.Commands; using InformationStrings = Microsoft.DotNet.Workloads.Workload.LocalizableStrings; +using Product = Microsoft.DotNet.Cli.Utils.Product; namespace Microsoft.DotNet.Workloads.Workload.List { @@ -110,8 +112,9 @@ public override int Execute() internal IEnumerable GetUpdateAvailable(IEnumerable installedList) { + // This was an internal partner ask, and they do not need to support workload sets. + var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestUpdates(useWorkloadSets: false); _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(_includePreviews).Wait(); - var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestUpdates(); foreach ((ManifestVersionUpdate manifestUpdate, WorkloadCollection workloads) in manifestsToUpdate) { diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 32da72aacded..1380ec9ba102 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -70,7 +70,13 @@ public override int Execute() } else if (_adManifestOnlyOption) { - _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(_includePreviews, string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption)).Wait(); + _workloadManifestUpdater.UpdateAdvertisingManifestsAsync( + _includePreviews, + GetInstallStateMode(_sdkFeatureBand, _dotnetPath), + string.IsNullOrWhiteSpace(_fromCacheOption) ? + null : + new DirectoryPath(_fromCacheOption)) + .Wait(); Reporter.WriteLine(); Reporter.WriteLine(LocalizableStrings.WorkloadUpdateAdManifestsSucceeded); } @@ -120,13 +126,14 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline Reporter.WriteLine(); var workloadIds = GetUpdatableWorkloads(); - _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, offlineCache).Wait(); + var useWorkloadSets = GetInstallStateMode(_sdkFeatureBand, _dotnetPath); + _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); var useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); var manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates(GetInstallStateMode(_sdkFeatureBand, _dotnetPath)).Select(m => m.ManifestUpdate); + _workloadManifestUpdater.CalculateManifestUpdates(useWorkloadSets).Select(m => m.ManifestUpdate); UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, useRollback, offlineCache); diff --git a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs index 029d28fd9ee6..ec6e2dd1bfe3 100644 --- a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs @@ -126,7 +126,7 @@ public void GivenWorkloadManifestUpdateItCanCalculateUpdates() var installationRepo = new MockInstallationRecordRepository(); var manifestUpdater = new WorkloadManifestUpdater(_reporter, workloadResolver, nugetDownloader, userProfileDir: Path.Combine(testDir, ".dotnet"), installationRepo, new MockPackWorkloadInstaller(dotnetRoot)); - var manifestUpdates = manifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); + var manifestUpdates = manifestUpdater.CalculateManifestUpdates(false).Select(m => m.ManifestUpdate); manifestUpdates.Should().BeEquivalentTo(expectedManifestUpdates); } @@ -193,7 +193,7 @@ public void GivenAdvertisedManifestsItCalculatesCorrectUpdates() var installationRepo = new MockInstallationRecordRepository(); var manifestUpdater = new WorkloadManifestUpdater(_reporter, workloadResolver, nugetDownloader, userProfileDir: Path.Combine(testDir, ".dotnet"), installationRepo, new MockPackWorkloadInstaller(dotnetRoot)); - var manifestUpdates = manifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); + var manifestUpdates = manifestUpdater.CalculateManifestUpdates(false).Select(m => m.ManifestUpdate); manifestUpdates.Should().BeEquivalentTo(expectedManifestUpdates); } @@ -558,7 +558,7 @@ public void GivenWorkloadManifestUpdateItChoosesHighestManifestVersionInCache() var installationRepo = new MockInstallationRecordRepository(); var installer = new MockPackWorkloadInstaller(dotnetRoot); var manifestUpdater = new WorkloadManifestUpdater(_reporter, workloadResolver, nugetDownloader, testDir, installationRepo, installer); - manifestUpdater.UpdateAdvertisingManifestsAsync(false, new DirectoryPath(offlineCache)).Wait(); + manifestUpdater.UpdateAdvertisingManifestsAsync(false, false, new DirectoryPath(offlineCache)).Wait(); // We should have chosen the higher version manifest package to install/ extract installer.ExtractCallParams.Count().Should().Be(1); diff --git a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs index 799214f970c7..d3ff5c400dcb 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs @@ -19,7 +19,7 @@ public MockWorkloadManifestUpdater(IEnumerable mani _manifestUpdates = manifestUpdates ?? new List(); } - public Task UpdateAdvertisingManifestsAsync(bool includePreview, DirectoryPath? cachePath = null) + public Task UpdateAdvertisingManifestsAsync(bool includePreview, bool useWorkloadSets = false, DirectoryPath? cachePath = null) { UpdateAdvertisingManifestsCallCount++; return Task.CompletedTask; From 02253d6de9c6bba04495063e90ec15539cca79dd Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 5 Jan 2024 15:22:03 -0800 Subject: [PATCH 04/43] Update to properly install via workload set --- .../commands/InstallingWorkloadCommand.cs | 5 +++ .../install/FileBasedInstaller.cs | 10 +++++- .../dotnet-workload/install/IInstaller.cs | 2 ++ .../install/IWorkloadManifestUpdater.cs | 2 +- .../install/NetSdkMsiInstallerClient.cs | 2 ++ .../install/WorkloadInstallCommand.cs | 12 +++++-- .../install/WorkloadManifestUpdater.cs | 31 ++----------------- .../list/WorkloadListCommand.cs | 2 +- .../update/WorkloadUpdateCommand.cs | 15 ++++++--- .../GivenWorkloadManifestUpdater.cs | 4 +-- .../MockPackWorkloadInstaller.cs | 2 ++ .../MockWorkloadManifestUpdater.cs | 2 +- 12 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index 345438429123..aa7d269e5e27 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -103,6 +103,11 @@ public static bool GetInstallStateMode(SdkFeatureBand sdkFeatureBand, string dot return installStateContents.UseWorkloadSets ?? false; } + public string InstallWorkloadSet() + { + return _workloadInstaller.InstallWorkloadSet(Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads")); + } + protected async Task> GetDownloads(IEnumerable workloadIds, bool skipManifestUpdate, bool includePreview, string downloadFolder = null) { List ret = new(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index c75d25e78068..7b21e62da781 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -85,6 +85,14 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds) return packs; } + public string InstallWorkloadSet(string path) + { + string workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", "version", ".workloadset.json"); + Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); + File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath); + return workloadSetPath; + } + public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) { var packInfos = GetPacksInWorkloads(workloadIds); @@ -509,7 +517,7 @@ public void Shutdown() public PackageId GetManifestPackageId(ManifestId manifestId, SdkFeatureBand featureBand) { - if (manifestId.ToString().Equals("Microsoft.NET.Workloads")) + if (manifestId.ToString().Equals("Microsoft.NET.Workloads", StringComparison.OrdinalIgnoreCase)) { return new PackageId($"{manifestId}.{featureBand}"); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index 5d388ef8bd21..8826a6d6ccc9 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -13,6 +13,8 @@ internal interface IInstaller : IWorkloadManifestInstaller { int ExitCode { get; } + string InstallWorkloadSet(string path); + void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null); void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs index b9948a3266ca..a4612935e226 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs @@ -12,7 +12,7 @@ internal interface IWorkloadManifestUpdater Task BackgroundUpdateAdvertisingManifestsWhenRequiredAsync(); - IEnumerable CalculateManifestUpdates(bool useWorkloadSets); + IEnumerable CalculateManifestUpdates(); IEnumerable CalculateManifestRollbacks(string rollbackDefinitionFilePath); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 5fd9849d135d..6fc969efc814 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -182,6 +182,8 @@ public void GarbageCollect(Func getResolverForWorkloa } } + public string InstallWorkloadSet(string path) => throw new NotImplementedException(); + /// /// Find all the dependents that look like they belong to SDKs. We only care /// about dependents that match the SDK host we're running under. For example, an x86 SDK should not be diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 49ffd413ce4b..36477e36c901 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -160,10 +160,16 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif var useWorkloadSets = GetInstallStateMode(_sdkFeatureBand, _dotnetPath); useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); + string workloadSetLocation = null; + if (useWorkloadSets) + { + workloadSetLocation = InstallWorkloadSet(); + } + _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); - manifestsToUpdate = useRollback ? - _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates(useWorkloadSets).Select(m => m.ManifestUpdate); + manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : + useWorkloadSets ? _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation) : + _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); } InstallWorkloadsWithInstallRecord(_workloadInstaller, workloadIds, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 3f00a585fe57..7d8bfb222002 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -164,39 +164,12 @@ public static void AdvertiseWorkloadUpdates() } } - private Dictionary GetManifestVersionsFromWorkloadSet() - { - return null; - } - - public IEnumerable CalculateManifestUpdates(bool useWorkloadSets) + public IEnumerable CalculateManifestUpdates() { var currentManifestIds = GetInstalledManifestIds(); - Dictionary manifestsFromSet = null; - if (useWorkloadSets) - { - manifestsFromSet = GetManifestVersionsFromWorkloadSet(); - if (manifestsFromSet is null) - { - // Fall back to loose manifests? Consult with team. - useWorkloadSets = false; - } - } - foreach (var manifestId in currentManifestIds) { - (ManifestVersionWithBand, WorkloadCollection)? advertisingInfo = null; - if (useWorkloadSets) - { - // This out parameter only takes the non-nullable type, but as a value type, it has to be nullable if it may be null, as it is if it is absent. - manifestsFromSet.TryGetValue(manifestId, out var advertInfo); - advertisingInfo = advertInfo; - } - else - { - advertisingInfo = GetAdvertisingManifestVersionAndWorkloads(manifestId); - } - + var advertisingInfo = GetAdvertisingManifestVersionAndWorkloads(manifestId); if (advertisingInfo == null) { continue; diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs index d98de3fc5621..1d797fb2101c 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs @@ -113,7 +113,7 @@ public override int Execute() internal IEnumerable GetUpdateAvailable(IEnumerable installedList) { // This was an internal partner ask, and they do not need to support workload sets. - var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestUpdates(useWorkloadSets: false); + var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestUpdates(); _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(_includePreviews).Wait(); foreach ((ManifestVersionUpdate manifestUpdate, WorkloadCollection workloads) in manifestsToUpdate) diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 1380ec9ba102..37dad227a4b1 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -126,14 +126,19 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline Reporter.WriteLine(); var workloadIds = GetUpdatableWorkloads(); - var useWorkloadSets = GetInstallStateMode(_sdkFeatureBand, _dotnetPath); + var useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); + var useWorkloadSets = !useRollback && GetInstallStateMode(_sdkFeatureBand, _dotnetPath); _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); - var useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); + string workloadSetLocation = null; + if (useWorkloadSets) + { + workloadSetLocation = InstallWorkloadSet(); + } - var manifestsToUpdate = useRollback ? - _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates(useWorkloadSets).Select(m => m.ManifestUpdate); + var manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : + useWorkloadSets ? _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation) : + _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, useRollback, offlineCache); diff --git a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs index ec6e2dd1bfe3..1a12d4ccb8b9 100644 --- a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs @@ -126,7 +126,7 @@ public void GivenWorkloadManifestUpdateItCanCalculateUpdates() var installationRepo = new MockInstallationRecordRepository(); var manifestUpdater = new WorkloadManifestUpdater(_reporter, workloadResolver, nugetDownloader, userProfileDir: Path.Combine(testDir, ".dotnet"), installationRepo, new MockPackWorkloadInstaller(dotnetRoot)); - var manifestUpdates = manifestUpdater.CalculateManifestUpdates(false).Select(m => m.ManifestUpdate); + var manifestUpdates = manifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); manifestUpdates.Should().BeEquivalentTo(expectedManifestUpdates); } @@ -193,7 +193,7 @@ public void GivenAdvertisedManifestsItCalculatesCorrectUpdates() var installationRepo = new MockInstallationRecordRepository(); var manifestUpdater = new WorkloadManifestUpdater(_reporter, workloadResolver, nugetDownloader, userProfileDir: Path.Combine(testDir, ".dotnet"), installationRepo, new MockPackWorkloadInstaller(dotnetRoot)); - var manifestUpdates = manifestUpdater.CalculateManifestUpdates(false).Select(m => m.ManifestUpdate); + var manifestUpdates = manifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); manifestUpdates.Should().BeEquivalentTo(expectedManifestUpdates); } diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 61d6dc6f24d8..6cc9613819a6 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -91,6 +91,8 @@ public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand }); } + public string InstallWorkloadSet(string path) => throw new NotImplementedException(); + public void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null) => throw new NotImplementedException(); public void GarbageCollect(Func getResolverForWorkloadSet, DirectoryPath? offlineCache = null, bool cleanAllPacks = false) diff --git a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs index d3ff5c400dcb..6202ee6efc3e 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs @@ -25,7 +25,7 @@ public Task UpdateAdvertisingManifestsAsync(bool includePreview, bool useWorkloa return Task.CompletedTask; } - public IEnumerable CalculateManifestUpdates(bool useWorkloadSets) + public IEnumerable CalculateManifestUpdates() { CalculateManifestUpdatesCallCount++; return _manifestUpdates; From 63647b242e980e73e7f724e96411dad0f3df62cf Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:32:29 -0800 Subject: [PATCH 05/43] Undo List changes --- .../commands/dotnet-workload/list/WorkloadListCommand.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs index 1d797fb2101c..03901a528200 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs @@ -3,7 +3,6 @@ using System.CommandLine; using System.Text.Json; -using Microsoft.Deployment.DotNet.Releases; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.NuGetPackageDownloader; using Microsoft.DotNet.Cli.Utils; @@ -13,7 +12,6 @@ using Microsoft.NET.Sdk.WorkloadManifestReader; using Microsoft.TemplateEngine.Cli.Commands; using InformationStrings = Microsoft.DotNet.Workloads.Workload.LocalizableStrings; -using Product = Microsoft.DotNet.Cli.Utils.Product; namespace Microsoft.DotNet.Workloads.Workload.List { @@ -113,8 +111,8 @@ public override int Execute() internal IEnumerable GetUpdateAvailable(IEnumerable installedList) { // This was an internal partner ask, and they do not need to support workload sets. - var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestUpdates(); _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(_includePreviews).Wait(); + var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestUpdates(); foreach ((ManifestVersionUpdate manifestUpdate, WorkloadCollection workloads) in manifestsToUpdate) { From 347d0c9698d22721588583e4bb870d9891c98048 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:58:42 -0800 Subject: [PATCH 06/43] Get real version --- .../dotnet-workload/install/FileBasedInstaller.cs | 2 +- .../install/WorkloadManifestUpdater.cs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 7b21e62da781..69bd7ab9ac2b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -87,7 +87,7 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds) public string InstallWorkloadSet(string path) { - string workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", "version", ".workloadset.json"); + string workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), ".workloadset.json"); Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath); return workloadSetPath; diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 7d8bfb222002..14ea7255ecb5 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -272,9 +272,9 @@ private async Task UpdateAdvertisingManifestAsync(WorkloadManifestInfo manifest, { string packagePath = null; var manifestId = new ManifestId(manifest.Id); + SdkFeatureBand? currentFeatureBand = null; try { - SdkFeatureBand? currentFeatureBand = null; var fallbackFeatureBand = new SdkFeatureBand(manifest.ManifestFeatureBand); // The bands should be checked in the order defined here. SdkFeatureBand[] bands = [_sdkFeatureBand, fallbackFeatureBand]; @@ -317,6 +317,16 @@ private async Task UpdateAdvertisingManifestAsync(WorkloadManifestInfo manifest, // add file that contains the advertised manifest feature band so GetAdvertisingManifestVersionAndWorkloads will use correct feature band, regardless of if rollback occurred or not File.WriteAllText(Path.Combine(adManifestPath, "AdvertisedManifestFeatureBand.txt"), currentFeatureBand.ToString()); + if (manifest.Id.Equals("Microsoft.NET.Workloads")) + { + var fileName = Path.GetFileNameWithoutExtension(packagePath); + var band = _sdkFeatureBand.ToString(); + + // The format is Microsoft.NET.Workloads.featureBand.version, so this skips past the band and the '.' afterwards to get the version + var version = fileName.Substring(fileName.IndexOf(band) + band.Length + 1); + File.WriteAllText(Path.Combine(adManifestPath, "version.txt"), version); + } + if (_displayManifestUpdates) { _reporter.WriteLine(LocalizableStrings.AdManifestUpdated, manifestId); From 39f0ec734ccffcbfeaeb713565aeb1a859e5b813 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:18:44 -0800 Subject: [PATCH 07/43] Implement workload update --version --- .../install/IWorkloadManifestUpdater.cs | 2 + .../install/WorkloadManifestUpdater.cs | 79 ++++++++++--------- .../update/LocalizableStrings.resx | 3 + .../update/WorkloadUpdateCommand.cs | 39 ++++++++- .../update/WorkloadUpdateCommandParser.cs | 5 ++ .../update/xlf/LocalizableStrings.cs.xlf | 5 ++ .../update/xlf/LocalizableStrings.de.xlf | 5 ++ .../update/xlf/LocalizableStrings.es.xlf | 5 ++ .../update/xlf/LocalizableStrings.fr.xlf | 5 ++ .../update/xlf/LocalizableStrings.it.xlf | 5 ++ .../update/xlf/LocalizableStrings.ja.xlf | 5 ++ .../update/xlf/LocalizableStrings.ko.xlf | 5 ++ .../update/xlf/LocalizableStrings.pl.xlf | 5 ++ .../update/xlf/LocalizableStrings.pt-BR.xlf | 5 ++ .../update/xlf/LocalizableStrings.ru.xlf | 5 ++ .../update/xlf/LocalizableStrings.tr.xlf | 5 ++ .../update/xlf/LocalizableStrings.zh-Hans.xlf | 5 ++ .../update/xlf/LocalizableStrings.zh-Hant.xlf | 5 ++ .../MockWorkloadManifestUpdater.cs | 2 + 19 files changed, 155 insertions(+), 40 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs index a4612935e226..269bae40989b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs @@ -21,6 +21,8 @@ internal interface IWorkloadManifestUpdater IEnumerable GetUpdatableWorkloadsToAdvertise(IEnumerable installedWorkloads); void DeleteUpdatableWorkloadsFile(); + + void DownloadWorkloadSet(string version, DirectoryPath? offlineCache); } internal record ManifestUpdateWithWorkloads(ManifestVersionUpdate ManifestUpdate, WorkloadCollection Workloads); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 14ea7255ecb5..f3343ab68c83 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -87,6 +87,11 @@ public async Task UpdateAdvertisingManifestsAsync(bool includePreviews, bool use } } + public async void DownloadWorkloadSet(string version, DirectoryPath? offlineCache = null) + { + await UpdateManifestWithVersionAsync("Microsoft.NET.Workloads", includePreviews: true, _sdkFeatureBand, new NuGetVersion(version), offlineCache); + } + public async static Task BackgroundUpdateAdvertisingManifestsAsync(string userProfileDir) { try @@ -268,62 +273,44 @@ public async Task> GetManifestPackageDownloadsAsyn private IEnumerable GetInstalledManifestIds() => _workloadResolver.GetInstalledManifests().Select(manifest => new ManifestId(manifest.Id)); - private async Task UpdateAdvertisingManifestAsync(WorkloadManifestInfo manifest, bool includePreviews, DirectoryPath? offlineCache = null) + private async Task UpdateManifestWithVersionAsync(string id, bool includePreviews, SdkFeatureBand band, NuGetVersion packageVersion = null, DirectoryPath? offlineCache = null) { + var manifestId = new ManifestId(id); string packagePath = null; - var manifestId = new ManifestId(manifest.Id); - SdkFeatureBand? currentFeatureBand = null; try { - var fallbackFeatureBand = new SdkFeatureBand(manifest.ManifestFeatureBand); - // The bands should be checked in the order defined here. - SdkFeatureBand[] bands = [_sdkFeatureBand, fallbackFeatureBand]; - var success = false; - // Use Distinct to eliminate bands that are the same. - foreach (var band in bands.Distinct()) + var manifestPackageId = _workloadManifestInstaller.GetManifestPackageId(manifestId, band); + try + { + // If an offline cache is present, use that. Otherwise, try to acquire the package online. + packagePath = offlineCache != null ? + Directory.GetFiles(offlineCache.Value.Value) + .Where(path => path.EndsWith(".nupkg") && Path.GetFileName(path).StartsWith(manifestPackageId.ToString(), StringComparison.OrdinalIgnoreCase)) + .Max() : + await _nugetPackageDownloader.DownloadPackageAsync(manifestPackageId, packageSourceLocation: _packageSourceLocation, includePreview: includePreviews); + } + catch (NuGetPackageNotFoundException) { - var manifestPackageId = _workloadManifestInstaller.GetManifestPackageId(manifestId, band); - currentFeatureBand = band; - - try - { - // If an offline cache is present, use that. Otherwise, try to acquire the package online. - packagePath = offlineCache != null ? - Directory.GetFiles(offlineCache.Value.Value) - .Where(path => path.EndsWith(".nupkg") && Path.GetFileName(path).StartsWith(manifestPackageId.ToString(), StringComparison.OrdinalIgnoreCase)) - .Max() : - await _nugetPackageDownloader.DownloadPackageAsync(manifestPackageId, packageSourceLocation: _packageSourceLocation, includePreview: includePreviews); - - if (packagePath != null) - { - success = true; - break; - } - } - catch (NuGetPackageNotFoundException) - { - } } - if (!success) + if (packagePath is null) { - _reporter.WriteLine(LocalizableStrings.AdManifestPackageDoesNotExist, manifestId); - return; + return false; } var adManifestPath = GetAdvertisingManifestPath(_sdkFeatureBand, manifestId); await _workloadManifestInstaller.ExtractManifestAsync(packagePath, adManifestPath); // add file that contains the advertised manifest feature band so GetAdvertisingManifestVersionAndWorkloads will use correct feature band, regardless of if rollback occurred or not - File.WriteAllText(Path.Combine(adManifestPath, "AdvertisedManifestFeatureBand.txt"), currentFeatureBand.ToString()); + File.WriteAllText(Path.Combine(adManifestPath, "AdvertisedManifestFeatureBand.txt"), band.ToString()); - if (manifest.Id.Equals("Microsoft.NET.Workloads")) + if (id.Equals("Microsoft.NET.Workloads")) { var fileName = Path.GetFileNameWithoutExtension(packagePath); - var band = _sdkFeatureBand.ToString(); + var featureBand = _sdkFeatureBand.ToString(); // The format is Microsoft.NET.Workloads.featureBand.version, so this skips past the band and the '.' afterwards to get the version - var version = fileName.Substring(fileName.IndexOf(band) + band.Length + 1); + var version = fileName.Substring(fileName.IndexOf(featureBand) + featureBand.Length + 1); File.WriteAllText(Path.Combine(adManifestPath, "version.txt"), version); } @@ -332,10 +319,12 @@ private async Task UpdateAdvertisingManifestAsync(WorkloadManifestInfo manifest, _reporter.WriteLine(LocalizableStrings.AdManifestUpdated, manifestId); } + return true; } catch (Exception e) { _reporter.WriteLine(LocalizableStrings.FailedAdManifestUpdate, manifestId, e.Message); + return false; } finally { @@ -360,6 +349,22 @@ private async Task UpdateAdvertisingManifestAsync(WorkloadManifestInfo manifest, } } + private async Task UpdateAdvertisingManifestAsync(WorkloadManifestInfo manifest, bool includePreviews, DirectoryPath? offlineCache = null) + { + var fallbackFeatureBand = new SdkFeatureBand(manifest.ManifestFeatureBand); + // The bands should be checked in the order defined here. + SdkFeatureBand[] bands = [_sdkFeatureBand, fallbackFeatureBand]; + foreach (var band in bands.Distinct()) + { + if (await UpdateManifestWithVersionAsync(manifest.Id, includePreviews, band, null, offlineCache)) + { + return; + } + } + + _reporter.WriteLine(LocalizableStrings.AdManifestPackageDoesNotExist, manifest.Id); + } + private (ManifestVersionWithBand ManifestWithBand, WorkloadCollection Workloads)? GetAdvertisingManifestVersionAndWorkloads(ManifestId manifestId) { var manifestPath = Path.Combine(GetAdvertisingManifestPath(_sdkFeatureBand, manifestId), "WorkloadManifest.json"); diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx index 77709f82d798..3742cfc702ea 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx +++ b/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx @@ -144,6 +144,9 @@ Include workloads installed with earlier SDK versions in update. + + Update to the specified workload set. + No workloads installed for this feature band. To update workloads installed with earlier SDK versions, include the --from-previous-sdk option. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 37dad227a4b1..e92c1a417545 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -20,6 +20,7 @@ internal class WorkloadUpdateCommand : InstallingWorkloadCommand private readonly bool _printRollbackDefinitionOnly; private readonly bool _fromPreviousSdk; private readonly string _workloadSetMode; + private readonly string _workloadSetVersion; public WorkloadUpdateCommand( ParseResult parseResult, @@ -34,6 +35,7 @@ public WorkloadUpdateCommand( tempDirPath: tempDirPath) { + _workloadSetVersion = parseResult.GetValue(WorkloadUpdateCommandParser.WorkloadSetVersionOption); _fromPreviousSdk = parseResult.GetValue(WorkloadUpdateCommandParser.FromPreviousSdkOption); _adManifestOnlyOption = parseResult.GetValue(WorkloadUpdateCommandParser.AdManifestOnlyOption); _printRollbackDefinitionOnly = parseResult.GetValue(WorkloadUpdateCommandParser.PrintRollbackOption); @@ -108,7 +110,25 @@ public override int Execute() { try { - UpdateWorkloads(_includePreviews, string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption)); + DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); + if (string.IsNullOrWhiteSpace(_workloadSetVersion)) + { + UpdateWorkloads(_includePreviews, offlineCache); + } + else + { + // Ensure workload set mode is set to 'workloadset' + // Do not skip checking the mode first, as setting it triggers + // an admin authorization popup for MSI-based installs. + if (!GetInstallStateMode(_sdkFeatureBand, _dotnetPath)) + { + _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true); + } + + _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache); + var workloadSetLocation = InstallWorkloadSet(); + CalculateManifestUpdatesAndUpdateWorkloads(false, true, workloadSetLocation, offlineCache); + } } catch (Exception e) { @@ -125,9 +145,16 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline { Reporter.WriteLine(); - var workloadIds = GetUpdatableWorkloads(); var useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); - var useWorkloadSets = !useRollback && GetInstallStateMode(_sdkFeatureBand, _dotnetPath); + var useWorkloadSets = GetInstallStateMode(_sdkFeatureBand, _dotnetPath); + + if (useRollback && useWorkloadSets) + { + // Rollback files are only for loose manifests. Update the mode to be loose manifests. + _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, false); + useWorkloadSets = false; + } + _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); string workloadSetLocation = null; @@ -136,6 +163,12 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline workloadSetLocation = InstallWorkloadSet(); } + CalculateManifestUpdatesAndUpdateWorkloads(useRollback, useWorkloadSets, workloadSetLocation, offlineCache); + } + + private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool useWorkloadSets, string workloadSetLocation, DirectoryPath? offlineCache) + { + var workloadIds = GetUpdatableWorkloads(); var manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : useWorkloadSets ? _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation) : _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs index fe068fc74b70..bb405817d5c6 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs @@ -12,6 +12,11 @@ internal static class WorkloadUpdateCommandParser { public static readonly CliOption TempDirOption = WorkloadInstallCommandParser.TempDirOption; + public static readonly CliOption WorkloadSetVersionOption = new("--version") + { + Description = LocalizableStrings.WorkloadSetVersionOptionDescription + }; + public static readonly CliOption FromPreviousSdkOption = new("--from-previous-sdk") { Description = LocalizableStrings.FromPreviousSdkOptionDescription diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf index 9549325a870b..8bf8996e1e56 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf @@ -57,6 +57,11 @@ Invalid argument "{0}" to the --mode argument for dotnet workload update. Only supported modes are "workloadset", "loosemanifest", and "auto". + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. Manifesty reklamy se úspěšně aktualizovaly. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf index 7fe3755912f5..3e8dcf4c5220 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf @@ -57,6 +57,11 @@ Ungültiges Argument "{0}" zum Argument --mode für das Dotnet Workload-Update. Es werden nur die Modi "workloadset", "loosemanifest" und "auto" unterstützt. + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. Werbemanifeste wurden erfolgreich aktualisiert. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf index 61eacfcb2be0..b72e964ca5f8 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf @@ -57,6 +57,11 @@ Argumento "{0}" no válido para el argumento --mode para la actualización de la carga de trabajo de dotnet. Solo los modos admitidos son "workloadset", "loosemanifest" y "auto". + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. Los manifiestos de publicidad se han actualizado correctamente. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf index 617881842505..88662c3487f5 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf @@ -57,6 +57,11 @@ Invalid argument "{0}" to the --mode argument for dotnet workload update. Only supported modes are "workloadset", "loosemanifest", and "auto". + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. Les manifestes de publicité ont été mis à jour. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf index 3e242f66ba13..40b44113feda 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf @@ -57,6 +57,11 @@ Invalid argument "{0}" to the --mode argument for dotnet workload update. Only supported modes are "workloadset", "loosemanifest", and "auto". + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. I manifesti pubblicitari sono stati aggiornati. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf index a3555167d604..058657142fcd 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf @@ -57,6 +57,11 @@ .NET ワークロード更新の --mode 引数に対する引数 "{0}" が無効です。サポートされているモードは、"workloadset"、"loosemanifest"、および "auto" のみです。 + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. 広告マニフェストを正常に更新しました。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf index 1f9d499812c4..0d1ec7111278 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf @@ -57,6 +57,11 @@ dotnet 워크로드 업데이트의 --mode 인수에 대한 "{0}" 인수가 잘못되었습니다. "workloadset", "loosemanifest", "auto" 모드만 지원됩니다. + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. 알림 매니페스트를 업데이트했습니다. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf index 222d233a4c10..7c768a6f1a11 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf @@ -57,6 +57,11 @@ Nieprawidłowy argument „{0}” argumentu --mode dla aktualizacji obciążenia dotnet. Obsługiwane tryby to „workloadset”, „loosemanifest” i „auto”. + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. Pomyślnie zaktualizowano manifesty reklam. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf index c5db7d56ba3e..34d3d5747d60 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf @@ -57,6 +57,11 @@ Argumento "{0}" inválido para o argumento --mode para atualização de carga de trabalho dotnet. Os únicos modos com suporte são "workloadset", "loosemanifest" e "auto". + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. Manifestos de anúncio atualizados com êxito. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf index 2ff37fb49329..cef528bd2c11 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf @@ -57,6 +57,11 @@ Invalid argument "{0}" to the --mode argument for dotnet workload update. Only supported modes are "workloadset", "loosemanifest", and "auto". + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. Манифесты рекламы успешно обновлены. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf index 6c7f77da9566..e5e22d06a42e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf @@ -57,6 +57,11 @@ Dotnet iş yükü güncelleştirmesi için --mod bağımsız değişkeninde geçersiz "{0}" bağımsız değişkeni. Yalnızca "workloadset", "loosemanifest" ve "auto" modları desteklenir. + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. Reklam bildirimleri başarıyla güncelleştirildi. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf index 3c981c1c23c4..12bb960578d9 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf @@ -57,6 +57,11 @@ dotnet 工作负载更新的 --mode 参数的参数“{0}”无效。仅支持“workloadset”、“loosemanifest”和“auto”模式。 + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. 成功更新广告清单。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf index 20dab178f25e..a457e2327a96 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf @@ -57,6 +57,11 @@ dotnet 工作負載更新的 --mode 引數之引數 "{0}" 無效。僅支援 "workloadset"、"loosemanifest" 和 "auto" 模式。 + + Update to the specified workload set. + Update to the specified workload set. + + Successfully updated advertising manifests. 已成功更新廣告資訊清單。 diff --git a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs index 6202ee6efc3e..78557f03b2bb 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs @@ -48,5 +48,7 @@ public IEnumerable CalculateManifestRollbacks(string roll public Task BackgroundUpdateAdvertisingManifestsWhenRequiredAsync() => throw new NotImplementedException(); public IEnumerable GetUpdatableWorkloadsToAdvertise(IEnumerable installedWorkloads) => throw new NotImplementedException(); public void DeleteUpdatableWorkloadsFile() { } + + public void DownloadWorkloadSet(string version, DirectoryPath? offlineCache) => throw new NotImplementedException(); } } From 52af35d34fa74f981ab6ff40f74e5885fd45d315 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:02:08 -0800 Subject: [PATCH 08/43] Support rolling back workload set installation --- .../install/FileBasedInstaller.cs | 20 +++++++++++++++++++ .../dotnet-workload/install/IInstaller.cs | 2 ++ .../install/NetSdkMsiInstallerClient.cs | 1 + .../update/WorkloadUpdateCommand.cs | 3 ++- .../MockPackWorkloadInstaller.cs | 1 + 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 69bd7ab9ac2b..3ad372989f4a 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.IO; using System.Text.Json; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.NuGetPackageDownloader; @@ -32,6 +33,7 @@ internal class FileBasedInstaller : IInstaller private readonly FileBasedInstallationRecordRepository _installationRecordRepository; private readonly PackageSourceLocation _packageSourceLocation; private readonly RestoreActionConfig _restoreActionConfig; + private string workloadSetRollbackContents; public int ExitCode => 0; @@ -89,10 +91,28 @@ public string InstallWorkloadSet(string path) { string workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), ".workloadset.json"); Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); + if (File.Exists(workloadSetPath)) + { + workloadSetRollbackContents = File.ReadAllText(workloadSetPath); + } + File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath); return workloadSetPath; } + public void RollBackWorkloadSetInstallation() + { + string workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), ".workloadset.json"); + if (workloadSetRollbackContents is null) + { + File.Delete(workloadSetPath); + } + else + { + File.WriteAllText(workloadSetPath, workloadSetRollbackContents); + } + } + public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) { var packInfos = GetPacksInWorkloads(workloadIds); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index 8826a6d6ccc9..a9346f336c47 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -15,6 +15,8 @@ internal interface IInstaller : IWorkloadManifestInstaller string InstallWorkloadSet(string path); + void RollBackWorkloadSetInstallation(); + void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null); void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 6fc969efc814..d64b39310be7 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -183,6 +183,7 @@ public void GarbageCollect(Func getResolverForWorkloa } public string InstallWorkloadSet(string path) => throw new NotImplementedException(); + public void RollBackWorkloadSetInstallation() => throw new NotImplementedException(); /// /// Find all the dependents that look like they belong to SDKs. We only care diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index e92c1a417545..a794cf0935a8 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -228,7 +228,8 @@ private void UpdateWorkloadsWithInstallRecord( }, rollback: () => { - // Nothing to roll back at this level, InstallWorkloadManifest and InstallWorkloadPacks handle the transaction rollback + // InstallWorkloadManifest and InstallWorkloadPacks handle the transaction rollback + _workloadInstaller.RollBackWorkloadSetInstallation(); }); } diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 6cc9613819a6..80cf0c743864 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -92,6 +92,7 @@ public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand } public string InstallWorkloadSet(string path) => throw new NotImplementedException(); + public void RollBackWorkloadSetInstallation() => throw new NotImplementedException(); public void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null) => throw new NotImplementedException(); From 26256495158fed47d734f7f9c56036759488cb7b Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:59:07 -0800 Subject: [PATCH 09/43] Don't roll back for file-based --- .../dotnet-workload/install/FileBasedInstaller.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 3ad372989f4a..fcc2894e8be8 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.IO; using System.Text.Json; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.NuGetPackageDownloader; @@ -102,15 +101,7 @@ public string InstallWorkloadSet(string path) public void RollBackWorkloadSetInstallation() { - string workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), ".workloadset.json"); - if (workloadSetRollbackContents is null) - { - File.Delete(workloadSetPath); - } - else - { - File.WriteAllText(workloadSetPath, workloadSetRollbackContents); - } + // We don't really need to worry about uninstalling workload sets for file-based installations, since they're side-by-side. } public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) From 198e3970af26e9bee7753c4874b9153e028cff79 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:55:05 -0800 Subject: [PATCH 10/43] Small touchup --- .../commands/dotnet-workload/install/WorkloadManifestUpdater.cs | 2 +- .../commands/dotnet-workload/update/WorkloadUpdateCommand.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index f3343ab68c83..fb1c3b32395b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -76,7 +76,7 @@ public async Task UpdateAdvertisingManifestsAsync(bool includePreviews, bool use { if (useWorkloadSets) { - await UpdateAdvertisingManifestAsync(new WorkloadManifestInfo("Microsoft.NET.Workloads", null, null, _sdkFeatureBand.ToString()), includePreviews, offlineCache); + await UpdateManifestWithVersionAsync("Microsoft.NET.Workloads", includePreviews, _sdkFeatureBand, null, offlineCache); } else { diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index a794cf0935a8..c82b014efa0b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -151,6 +151,7 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline if (useRollback && useWorkloadSets) { // Rollback files are only for loose manifests. Update the mode to be loose manifests. + // TODO: add message explaining this (to Reporter) _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, false); useWorkloadSets = false; } From 2a4a9f9764dfed053a1640945853f647b9496ba1 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:55:13 -0800 Subject: [PATCH 11/43] First stab at MSI-based install --- .../install/NetSdkMsiInstallerClient.cs | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index d64b39310be7..e9d1cd2a054f 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -182,7 +182,83 @@ public void GarbageCollect(Func getResolverForWorkloa } } - public string InstallWorkloadSet(string path) => throw new NotImplementedException(); + public string InstallWorkloadSet(string path) + { + ReportPendingReboot(); + + // Rolling back a manifest update after a successful install is essentially a downgrade, which is blocked so we have to + // treat it as a special case and is different from the install failing and rolling that back, though depending where the install + // failed, it may have removed the old product already. + // Resolve the package ID for the manifest payload package + var featureBand = Path.GetFileName(Path.GetDirectoryName(path)); + var version = File.ReadAllText(Path.Combine(path, "version.txt")); + string msiPackageId = GetManifestPackageId(new ManifestId("Microsoft.NET.Workloads"), new SdkFeatureBand(featureBand)).ToString(); + string msiPackageVersion = version; + + Log?.LogMessage($"Resolving Microsoft.NET.Workloads ({version}) to {msiPackageId} ({msiPackageVersion})."); + + // Retrieve the payload from the MSI package cache. + MsiPayload msi = GetCachedMsiPayload(msiPackageId, msiPackageVersion, null); + VerifyPackage(msi); + DetectState state = DetectPackage(msi.ProductCode, out Version installedVersion); + InstallAction plannedAction = PlanPackage(msi, state, InstallAction.Install, installedVersion, out IEnumerable relatedProducts); + + // If we've detected a downgrade, it's possible we might be doing a rollback after the manifests were updated, + // but another error occurred. In this case we need to try and uninstall the upgrade and then install the lower + // version of the MSI. The downgrade can also be a deliberate rollback. + if (plannedAction == InstallAction.Downgrade && state == DetectState.Absent) + { + // The provider keys for manifest packages are stable across feature bands so we retain dependents during upgrades. + DependencyProvider depProvider = new DependencyProvider(msi.Manifest.ProviderKeyName); + + // Try and remove the SDK dependency, but ignore any remaining dependencies since + // we want to force the removal of the old version. The remaining dependencies and the provider + // key won't be removed. + UpdateDependent(InstallRequestType.RemoveDependent, msi.Manifest.ProviderKeyName, _dependent); + + // Since we don't have records for manifests, we need to try and retrieve the ProductCode of + // the newer MSI that's installed that we want to remove using its dependency provider. + string productCode = depProvider.ProductCode; + + if (string.IsNullOrWhiteSpace(productCode)) + { + // We don't know the MSI package that wrote this provider key, so if the ProductCode is missing + // we can't do anything else. + Log?.LogMessage($"Failed to retrieve the ProductCode for provider: {depProvider.ProviderKeyName}."); + return null; + } + + Log?.LogMessage($"Found ProductCode {productCode} registered against provider, {depProvider.ProviderKeyName}."); + + // This is a best effort. If for some reason the manifest installers were fixed, for example, manually + // adding additional upgrade paths to work around previous faulty authoring, we may have multiple related + // products. The best we can do is to check for at least one match and remove it and then try the rollback. + if (!relatedProducts.Contains(productCode, StringComparer.OrdinalIgnoreCase)) + { + Log?.LogMessage($"Cannot rollback manifest. ProductCode does not match any detected related products."); + return null; + } + + string logFile = GetMsiLogName(productCode, InstallAction.Uninstall); + uint error = UninstallMsi(productCode, logFile, ignoreDependencies: true); + + ExitOnError(error, "Failed to uninstall manifest package."); + + // Detect the package again and fall through to the original execution. If that fails, then there's nothing + // we could have done. + Log?.LogMessage("Replanning manifest package."); + state = DetectPackage(msi, out Version _); + plannedAction = PlanPackage(msi, state, InstallAction.Install, installedVersion, out IEnumerable _); + } + + ExecutePackage(msi, plannedAction, msiPackageId); + + // Update the reference count against the MSI. + UpdateDependent(InstallRequestType.AddDependent, msi.Manifest.ProviderKeyName, _dependent); + + return null; + } + public void RollBackWorkloadSetInstallation() => throw new NotImplementedException(); /// From b28ca3830b8cd84925ffa9f46ddf3477a4c8e4fe Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:46:15 -0800 Subject: [PATCH 12/43] Reimplement rolling back Plus more correct MSI-based workload set installation --- .../Microsoft.DotNet.Cli.Utils/PathUtility.cs | 26 +++++++ .../install/FileBasedInstaller.cs | 11 +-- .../install/NetSdkMsiInstallerClient.cs | 77 +++++++------------ 3 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs index 75019c9e32e3..556294ea27bf 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs @@ -97,6 +97,32 @@ public static bool TryDeleteDirectory(string directoryPath) } } + /// + /// Deletes the provided file. Then deletes the parent directory if empty + /// and continues to its parent until it fails. Returns whether it succeeded + /// in deleting the file it was intended to delete. + /// + public static bool DeleteFileAndEmptyParents(string path) + { + try + { + File.Delete(path); + var dir = Path.GetDirectoryName(path); + + // Directory.Delete throws an exception when it fails to delete + // a directory, as, for instance, if it isn't empty. This is + // intended to run until it throws an exception, then return. + while (true) + { + Directory.Delete(dir); + dir = Path.GetDirectoryName(dir); + } + } + catch (Exception) { } + + return !File.Exists(path); + } + /// /// Returns childItem relative to directory, with Path.DirectorySeparatorChar as separator /// diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index fcc2894e8be8..0ce9409f0c67 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -13,7 +13,7 @@ using NuGet.Common; using NuGet.Versioning; using static Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadResolver; - +using PathUtility = Microsoft.DotNet.Tools.Common.PathUtility; namespace Microsoft.DotNet.Workloads.Workload.Install { @@ -32,7 +32,7 @@ internal class FileBasedInstaller : IInstaller private readonly FileBasedInstallationRecordRepository _installationRecordRepository; private readonly PackageSourceLocation _packageSourceLocation; private readonly RestoreActionConfig _restoreActionConfig; - private string workloadSetRollbackContents; + private string workloadSetPath; public int ExitCode => 0; @@ -88,12 +88,8 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds) public string InstallWorkloadSet(string path) { - string workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), ".workloadset.json"); + workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), "workloadset.json"); Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); - if (File.Exists(workloadSetPath)) - { - workloadSetRollbackContents = File.ReadAllText(workloadSetPath); - } File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath); return workloadSetPath; @@ -102,6 +98,7 @@ public string InstallWorkloadSet(string path) public void RollBackWorkloadSetInstallation() { // We don't really need to worry about uninstalling workload sets for file-based installations, since they're side-by-side. + PathUtility.DeleteFileAndEmptyParents(workloadSetPath); } public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index e9d1cd2a054f..7b6e9db26ce5 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -34,6 +34,9 @@ internal partial class NetSdkMsiInstallerClient : MsiInstallerBase, IInstaller public int ExitCode => Restart ? unchecked((int)Error.SUCCESS_REBOOT_REQUIRED) : unchecked((int)Error.SUCCESS); + private string _newWorkloadSetPath; + private string _previousWorkloadSetVersion; + public NetSdkMsiInstallerClient(InstallElevationContextBase elevationContext, ISetupLogger logger, bool verifySignatures, @@ -183,6 +186,24 @@ public void GarbageCollect(Func getResolverForWorkloa } public string InstallWorkloadSet(string path) + { + return ModifyWorkloadSet(path, InstallAction.Install); + } + + public void RollBackWorkloadSetInstallation() + { + if (_newWorkloadSetPath is not null) + { + ModifyWorkloadSet(_newWorkloadSetPath, InstallAction.Uninstall); + if (_previousWorkloadSetVersion is not null) + { + File.WriteAllText(Path.Combine(_newWorkloadSetPath, "version.txt"), _previousWorkloadSetVersion); + ModifyWorkloadSet(_newWorkloadSetPath, InstallAction.Repair); + } + } + } + + private string ModifyWorkloadSet(string path, InstallAction installAction) { ReportPendingReboot(); @@ -201,66 +222,24 @@ public string InstallWorkloadSet(string path) MsiPayload msi = GetCachedMsiPayload(msiPackageId, msiPackageVersion, null); VerifyPackage(msi); DetectState state = DetectPackage(msi.ProductCode, out Version installedVersion); - InstallAction plannedAction = PlanPackage(msi, state, InstallAction.Install, installedVersion, out IEnumerable relatedProducts); - // If we've detected a downgrade, it's possible we might be doing a rollback after the manifests were updated, - // but another error occurred. In this case we need to try and uninstall the upgrade and then install the lower - // version of the MSI. The downgrade can also be a deliberate rollback. - if (plannedAction == InstallAction.Downgrade && state == DetectState.Absent) + if (installAction == InstallAction.Install) { - // The provider keys for manifest packages are stable across feature bands so we retain dependents during upgrades. - DependencyProvider depProvider = new DependencyProvider(msi.Manifest.ProviderKeyName); - - // Try and remove the SDK dependency, but ignore any remaining dependencies since - // we want to force the removal of the old version. The remaining dependencies and the provider - // key won't be removed. - UpdateDependent(InstallRequestType.RemoveDependent, msi.Manifest.ProviderKeyName, _dependent); - - // Since we don't have records for manifests, we need to try and retrieve the ProductCode of - // the newer MSI that's installed that we want to remove using its dependency provider. - string productCode = depProvider.ProductCode; - - if (string.IsNullOrWhiteSpace(productCode)) - { - // We don't know the MSI package that wrote this provider key, so if the ProductCode is missing - // we can't do anything else. - Log?.LogMessage($"Failed to retrieve the ProductCode for provider: {depProvider.ProviderKeyName}."); - return null; - } - - Log?.LogMessage($"Found ProductCode {productCode} registered against provider, {depProvider.ProviderKeyName}."); - - // This is a best effort. If for some reason the manifest installers were fixed, for example, manually - // adding additional upgrade paths to work around previous faulty authoring, we may have multiple related - // products. The best we can do is to check for at least one match and remove it and then try the rollback. - if (!relatedProducts.Contains(productCode, StringComparer.OrdinalIgnoreCase)) - { - Log?.LogMessage($"Cannot rollback manifest. ProductCode does not match any detected related products."); - return null; - } - - string logFile = GetMsiLogName(productCode, InstallAction.Uninstall); - uint error = UninstallMsi(productCode, logFile, ignoreDependencies: true); - - ExitOnError(error, "Failed to uninstall manifest package."); - - // Detect the package again and fall through to the original execution. If that fails, then there's nothing - // we could have done. - Log?.LogMessage("Replanning manifest package."); - state = DetectPackage(msi, out Version _); - plannedAction = PlanPackage(msi, state, InstallAction.Install, installedVersion, out IEnumerable _); + // If we are installing the workload set, record its version and the previous version so that we can roll back if necessary. + _newWorkloadSetPath = path; + _previousWorkloadSetVersion = installedVersion.ToString(); } + InstallAction plannedAction = PlanPackage(msi, state, installAction, installedVersion, out IEnumerable relatedProducts); + ExecutePackage(msi, plannedAction, msiPackageId); // Update the reference count against the MSI. UpdateDependent(InstallRequestType.AddDependent, msi.Manifest.ProviderKeyName, _dependent); - return null; + return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", version, "workloadset.json"); } - public void RollBackWorkloadSetInstallation() => throw new NotImplementedException(); - /// /// Find all the dependents that look like they belong to SDKs. We only care /// about dependents that match the SDK host we're running under. For example, an x86 SDK should not be From 0aca30e7479e6a2c8b392b6df77565ca0c3da2dc Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:01:12 -0800 Subject: [PATCH 13/43] Little fixups --- .../commands/dotnet-workload/install/FileBasedInstaller.cs | 5 ++++- .../dotnet-workload/install/WorkloadInstallCommand.cs | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 0ce9409f0c67..7b5a2b522fe3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -98,7 +98,10 @@ public string InstallWorkloadSet(string path) public void RollBackWorkloadSetInstallation() { // We don't really need to worry about uninstalling workload sets for file-based installations, since they're side-by-side. - PathUtility.DeleteFileAndEmptyParents(workloadSetPath); + if (workloadSetPath is not null) + { + PathUtility.DeleteFileAndEmptyParents(workloadSetPath); + } } public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 36477e36c901..edcc5518f2a6 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -249,6 +249,8 @@ private void InstallWorkloadsWithInstallRecord( installer.GetWorkloadInstallationRecordRepository() .DeleteWorkloadInstallationRecord(workloadId, sdkFeatureBand); } + + installer.RollBackWorkloadSetInstallation(); }); } From 4d1b0fc123b74cd9f0d8e1468ad1ffda20b02d40 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 18 Jan 2024 16:51:41 -0800 Subject: [PATCH 14/43] Overwrite workload set if present --- .../commands/dotnet-workload/install/FileBasedInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 7b5a2b522fe3..53bc6ecc3bc3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -91,7 +91,7 @@ public string InstallWorkloadSet(string path) workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), "workloadset.json"); Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); - File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath); + File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath, overwrite: true); return workloadSetPath; } From 65e6c7388cdbdcf597368cd150dd23aed0bb3cb5 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 18 Jan 2024 16:51:59 -0800 Subject: [PATCH 15/43] Fix garbage collecting workload sets --- .../SdkDirectoryWorkloadManifestProvider.cs | 3 +- ...kDirectoryWorkloadManifestProviderTests.cs | 69 +------------------ 2 files changed, 3 insertions(+), 69 deletions(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index 286a858bdebf..b49180179e61 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -410,7 +410,8 @@ public Dictionary GetAvailableWorkloadSets() foreach (var workloadSetDirectory in Directory.GetDirectories(workloadSetsRoot)) { WorkloadSet? workloadSet = null; - foreach (var jsonFile in Directory.GetFiles(workloadSetDirectory, "*.workloadset.json")) + var jsonFile = Path.Combine(workloadSetDirectory, "workloadset.json"); + if (File.Exists(jsonFile)) { var newWorkloadSet = WorkloadSet.FromJson(File.ReadAllText(jsonFile), _sdkVersionBand); if (workloadSet == null) diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 13a4f6d3570b..b74d87bcf0fa 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -417,73 +417,6 @@ var sdkDirectoryWorkloadManifestProvider Assert.Throws(() => GetManifestContents(sdkDirectoryWorkloadManifestProvider).ToList()); } - [Fact] - public void WorkloadSetCanIncludeMultipleJsonFiles() - { - Initialize("8.0.200"); - - CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); - CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); - CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); - - CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.1", true); - CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true); - CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2", true); - - - var workloadSetDirectory = Path.Combine(_manifestRoot, "8.0.200", "workloadsets", "8.0.200"); - Directory.CreateDirectory(workloadSetDirectory); - File.WriteAllText(Path.Combine(workloadSetDirectory, "1.workloadset.json"), """ - { - "ios": "11.0.2/8.0.100" - } - """); - File.WriteAllText(Path.Combine(workloadSetDirectory, "2.workloadset.json"), """ - { - "android": "33.0.2-rc.1/8.0.200" - } - """); - - var sdkDirectoryWorkloadManifestProvider - = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); - - GetManifestContents(sdkDirectoryWorkloadManifestProvider) - .Should() - .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2-rc.1/8.0.200"); - } - - [Fact] - public void ItThrowsExceptionIfWorkloadSetJsonFilesHaveDuplicateManifests() - { - Initialize("8.0.200"); - - CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); - CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); - CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); - - CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.1", true); - CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true); - CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2", true); - - - var workloadSetDirectory = Path.Combine(_manifestRoot, "8.0.200", "workloadsets", "8.0.200"); - Directory.CreateDirectory(workloadSetDirectory); - File.WriteAllText(Path.Combine(workloadSetDirectory, "1.workloadset.json"), """ - { - "ios": "11.0.2/8.0.100" - } - """); - File.WriteAllText(Path.Combine(workloadSetDirectory, "2.workloadset.json"), """ - { - "android": "33.0.2-rc.1/8.0.200", - "ios": "11.0.2/8.0.100" - } - """); - - Assert.Throws(() => - new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null)); - } - [Fact] public void ItUsesWorkloadSetFromGlobalJson() { @@ -1270,7 +1203,7 @@ private void CreateMockWorkloadSet(string manifestRoot, string featureBand, stri { Directory.CreateDirectory(workloadSetDirectory); } - File.WriteAllText(Path.Combine(workloadSetDirectory, "workloadset.workloadset.json"), workloadSetContents); + File.WriteAllText(Path.Combine(workloadSetDirectory, "workloadset.json"), workloadSetContents); } private string CreateMockInstallState(string featureBand, string installStateContents) From 197b7f99c0f0fe1fdf4475a5adbb750034cd5bc7 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:02:36 -0800 Subject: [PATCH 16/43] Find workload set before installing it --- .../commands/dotnet-workload/install/WorkloadInstallCommand.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index edcc5518f2a6..68417d9cdfb8 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -160,13 +160,14 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif var useWorkloadSets = GetInstallStateMode(_sdkFeatureBand, _dotnetPath); useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); + _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); + string workloadSetLocation = null; if (useWorkloadSets) { workloadSetLocation = InstallWorkloadSet(); } - _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : useWorkloadSets ? _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation) : _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); From 324d5e0390d1cf28f5376aa04405b61c42153a21 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:21:06 -0800 Subject: [PATCH 17/43] Support workload sets in list --- .../dotnet-workload/WorkloadInfoHelper.cs | 3 ++- .../list/LocalizableStrings.resx | 3 +++ .../list/WorkloadListCommand.cs | 20 ++++++++++++++++++- .../list/xlf/LocalizableStrings.cs.xlf | 5 +++++ .../list/xlf/LocalizableStrings.de.xlf | 5 +++++ .../list/xlf/LocalizableStrings.es.xlf | 5 +++++ .../list/xlf/LocalizableStrings.fr.xlf | 5 +++++ .../list/xlf/LocalizableStrings.it.xlf | 5 +++++ .../list/xlf/LocalizableStrings.ja.xlf | 5 +++++ .../list/xlf/LocalizableStrings.ko.xlf | 5 +++++ .../list/xlf/LocalizableStrings.pl.xlf | 5 +++++ .../list/xlf/LocalizableStrings.pt-BR.xlf | 5 +++++ .../list/xlf/LocalizableStrings.ru.xlf | 5 +++++ .../list/xlf/LocalizableStrings.tr.xlf | 5 +++++ .../list/xlf/LocalizableStrings.zh-Hans.xlf | 5 +++++ .../list/xlf/LocalizableStrings.zh-Hant.xlf | 5 +++++ .../SdkDirectoryWorkloadManifestProvider.cs | 1 + 17 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs b/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs index f686d494a53d..ed9b0be85188 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs @@ -17,6 +17,7 @@ internal class WorkloadInfoHelper : IWorkloadInfoHelper { public readonly SdkFeatureBand _currentSdkFeatureBand; private readonly string _targetSdkVersion; + public readonly string dotnetPath; public WorkloadInfoHelper( bool isInteractive, @@ -30,7 +31,7 @@ public WorkloadInfoHelper( string userProfileDir = null, IWorkloadResolver workloadResolver = null) { - string dotnetPath = dotnetDir ?? Path.GetDirectoryName(Environment.ProcessPath); + dotnetPath = dotnetDir ?? Path.GetDirectoryName(Environment.ProcessPath); ReleaseVersion currentSdkReleaseVersion = new(currentSdkVersion ?? Product.Version); _currentSdkFeatureBand = new SdkFeatureBand(currentSdkReleaseVersion); diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx index b7a929ae43e1..ef35ac109171 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx +++ b/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx @@ -128,4 +128,7 @@ Use `dotnet workload search` to find additional workloads to install. {Locked="dotnet workload search"} + + Workload set version: {0} + \ No newline at end of file diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs index 03901a528200..e13ec31ec84b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs @@ -20,7 +20,7 @@ internal class WorkloadListCommand : WorkloadCommandBase private readonly bool _includePreviews; private readonly bool _machineReadableOption; private readonly IWorkloadManifestUpdater _workloadManifestUpdater; - private readonly IWorkloadInfoHelper _workloadListHelper; + private readonly WorkloadInfoHelper _workloadListHelper; public WorkloadListCommand( ParseResult parseResult, @@ -93,6 +93,24 @@ public override int Execute() table.PrintRows(installedWorkloads.AsEnumerable(), l => Reporter.WriteLine(l)); + if (InstallingWorkloadCommand.GetInstallStateMode(_workloadListHelper._currentSdkFeatureBand, _workloadListHelper.dotnetPath)) + { + var workloadSetVersion = "unknown"; + try + { + var workloadSetPath = Path.Combine(_workloadListHelper.dotnetPath, "sdk-manifests", _workloadListHelper._currentSdkFeatureBand.ToString(), "workloadsets"); + var workloadSetDirectory = new DirectoryInfo(workloadSetPath); + workloadSetVersion = workloadSetDirectory.EnumerateDirectories().Where(d => d.EnumerateFiles("workloadset.json").Count() == 1).Max().Name; + } + catch (Exception) + { + // Don't throw just because we couldn't find a workload set! The user may have changed the mode to workload sets but not yet run update/install. + } + + Reporter.WriteLine(); + Reporter.WriteLine(string.Format(LocalizableStrings.WorkloadSetVersion, workloadSetVersion)); + } + Reporter.WriteLine(); Reporter.WriteLine(LocalizableStrings.WorkloadListFooter); Reporter.WriteLine(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.cs.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.cs.xlf index dbc5c5d7eb39..ddc9d461f8bb 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.cs.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.cs.xlf @@ -12,6 +12,11 @@ Pokud chcete najít další úlohy, které se mají nainstalovat, použijte `dotnet workload search`. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. Aktualizace jsou k dispozici pro následující úlohy: {0}. Pokud chcete získat nejnovější verzi, spusťte aktualizaci úlohy dotnet (`dotnet workload update`). diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.de.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.de.xlf index 63bfadefbaed..c9ad93904c25 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.de.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.de.xlf @@ -12,6 +12,11 @@ Verwenden Sie „dotnet workload search“, um zusätzliche zu installierende Workloads zu finden. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. Updates sind für die folgenden Workloads verfügbar: {0}. Führen Sie „dotnet workload update“ aus, um die neueste Updates zu erhalten. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.es.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.es.xlf index 6a235d3dceb3..672ef0ae3f1f 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.es.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.es.xlf @@ -12,6 +12,11 @@ Use "dotnet workload search" para buscar cargas de trabajo adicionales para instalar. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. Hay actualizaciones disponibles para las siguientes cargas de trabajo: {0}. Ejecute "dotnet workload update" para obtener la versión más reciente. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.fr.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.fr.xlf index 7bb2a04f586e..810d740328c6 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.fr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.fr.xlf @@ -12,6 +12,11 @@ Utilisez `dotnet workload search` pour rechercher d’autres charges de travail à installer. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. Des mises à jour sont disponibles pour les charges de travail suivantes : {0}. Exécutez `dotnet workload update` pour obtenir la dernière version. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.it.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.it.xlf index 1cbcf50e4808..48cce199abd3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.it.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.it.xlf @@ -12,6 +12,11 @@ Utilizzare la `dotnet workload search` per trovare i carichi di lavoro aggiuntivi da installare. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. Gli aggiornamenti sono disponibili per i carichi di lavoro seguenti: {0}. Per ottenere la versione più recente, eseguire 'dotnet workload update'. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ja.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ja.xlf index 2b121428078f..b1f40a8699b8 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ja.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ja.xlf @@ -12,6 +12,11 @@ `dotnet workload search` を使用して追加ワークロードを検出し、インストールします。 {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. 次のワークロードについて更新プログラムを入手可能です: {0}。最新版を取得するには、`dotnet workload update` を実行します。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ko.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ko.xlf index bc25fba551b4..4841ed758843 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ko.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ko.xlf @@ -12,6 +12,11 @@ `dotnet workload search`을 사용하여 설치할 추가 워크로드를 찾습니다. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. 다음 워크로드에 대한 업데이트를 사용할 수 있습니다. {0}. 최신 버전을 받으려면 `dotnet workload update`를 실행하세요. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pl.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pl.xlf index d831a98b9807..ed0ffb6d830a 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pl.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pl.xlf @@ -12,6 +12,11 @@ Użyj polecenia „dotnet workload search”, aby znaleźć dodatkowe obciążenia do zainstalowania. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. Aktualizacje są dostępne dla następujących obciążeń: {0}. Uruchom polecenie `dotnet workload update`, aby uzyskać najnowszą wersję. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pt-BR.xlf index b9246e9d8a9b..246d445a773f 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pt-BR.xlf @@ -12,6 +12,11 @@ Use `dotnet workload search` para encontrar cargas de trabalho adicionais a serem instaladas. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. As atualizações estão disponíveis para as seguintes cargas de trabalho(s): {0}. Execute `dotnet workload update` para obter o mais recente. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ru.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ru.xlf index 7ddcbf47db14..de6232292d2c 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ru.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ru.xlf @@ -12,6 +12,11 @@ Используйте `dotnet workload search`, чтобы найти дополнительные рабочие нагрузки для установки. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. Обновления доступны для следующих рабочих нагрузок: {0}. Чтобы получить последнюю версию, запустите `dotnet workload update`. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.tr.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.tr.xlf index 9ea3ecc06a29..35fd7c55f6e8 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.tr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.tr.xlf @@ -12,6 +12,11 @@ Yüklenecek ek iş yüklerini bulmak için `dotnet workload search` kullanın. {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. Şu iş yükleri için güncelleştirmeler var: {0}. En son sürümü almak için `dotnet workload update` çalıştırın. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hans.xlf index ae6dab8c46d0..4830270120db 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hans.xlf @@ -12,6 +12,11 @@ 使用`dotnet workload search`查找要安装的其他工作负载。 {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. 以下工作负载有可用的更新: {0}。请运行 `dotnet workload update` 以获取最新版本。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hant.xlf index 8365be692fe5..6087c813702f 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hant.xlf @@ -12,6 +12,11 @@ 使用 `dotnet workload search` 尋找其他要安裝的工作負載。 {Locked="dotnet workload search"} + + Workload set version: {0} + Workload set version: {0} + + Updates are available for the following workload(s): {0}. Run `dotnet workload update` to get the latest. 以下工作負載有可用的更新: {0}。執行 `dotnet workload update` 以取得最新更新。 diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index b49180179e61..f89ae89400d3 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -427,6 +427,7 @@ public Dictionary GetAvailableWorkloadSets() } } } + if (workloadSet != null) { if (File.Exists(Path.Combine(workloadSetDirectory, "baseline.workloadset.json"))) From d44a33d5852dfcc936e4470d2f1f3aab01a1c358 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:35:37 -0800 Subject: [PATCH 18/43] Partial progress --- .../Windows/InstallMessageDispatcher.cs | 16 ++++++++++ .../Windows/InstallRequestMessage.cs | 8 +++++ .../Installer/Windows/InstallRequestType.cs | 5 +++ .../dotnet-workload/InstallStateContents.cs | 3 ++ .../install/FileBasedInstaller.cs | 9 ++++++ .../dotnet-workload/install/IInstaller.cs | 2 ++ .../install/MsiInstallerBase.cs | 31 +++++++++++++++++++ .../install/NetSdkMsiInstallerServer.cs | 5 +++ .../update/WorkloadUpdateCommand.cs | 7 ++++- .../MockPackWorkloadInstaller.cs | 5 +++ 10 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/Installer/Windows/InstallMessageDispatcher.cs b/src/Cli/dotnet/Installer/Windows/InstallMessageDispatcher.cs index 7d446db4944d..538bae6d1a46 100644 --- a/src/Cli/dotnet/Installer/Windows/InstallMessageDispatcher.cs +++ b/src/Cli/dotnet/Installer/Windows/InstallMessageDispatcher.cs @@ -192,5 +192,21 @@ public InstallResponseMessage SendUpdateWorkloadModeRequest(SdkFeatureBand sdkFe UseWorkloadSets = newMode, }); } + + /// + /// Send an to adjust the workload set version used for installing and updating workloads + /// + /// The SDK feature band of the install state file to write + /// The workload set version + /// + public InstallResponseMessage SendUpdateWorkloadSetRequest(SdkFeatureBand sdkFeatureBand, string newVersion) + { + return Send(new InstallRequestMessage + { + RequestType = InstallRequestType.AdjustWorkloadSetVersion, + SdkFeatureBand = sdkFeatureBand.ToString(), + WorkloadSetVersion = newVersion, + }); + } } } diff --git a/src/Cli/dotnet/Installer/Windows/InstallRequestMessage.cs b/src/Cli/dotnet/Installer/Windows/InstallRequestMessage.cs index 5ab6430bcbf4..962bdd90dd9f 100644 --- a/src/Cli/dotnet/Installer/Windows/InstallRequestMessage.cs +++ b/src/Cli/dotnet/Installer/Windows/InstallRequestMessage.cs @@ -128,6 +128,14 @@ public bool UseWorkloadSets get; set; } + /// + /// The workload set version + /// + public string WorkloadSetVersion + { + get; set; + } + /// /// Converts a deserialized array of bytes into an . /// diff --git a/src/Cli/dotnet/Installer/Windows/InstallRequestType.cs b/src/Cli/dotnet/Installer/Windows/InstallRequestType.cs index 2d90d3f2f68f..b734531d1b53 100644 --- a/src/Cli/dotnet/Installer/Windows/InstallRequestType.cs +++ b/src/Cli/dotnet/Installer/Windows/InstallRequestType.cs @@ -69,5 +69,10 @@ public enum InstallRequestType /// Changes the workload mode /// AdjustWorkloadMode, + + /// + /// Changes the workload set version + /// + AdjustWorkloadSetVersion, } } diff --git a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs index f8afd9fa3943..2fc80aeec699 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs @@ -11,6 +11,9 @@ internal class InstallStateContents [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public Dictionary Manifests { get; set; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string WorkloadSetVersion { get; set; } + private static readonly JsonSerializerOptions s_options = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 53bc6ecc3bc3..d3924e7d5c90 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -471,6 +471,15 @@ public void GarbageCollect(Func getResolverForWorkloa } + public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion) + { + string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, _dotnetDir), "default.json"); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + installStateContents.WorkloadSetVersion = workloadSetVersion; + File.WriteAllText(path, installStateContents.ToString()); + } + public void RemoveManifestsFromInstallState(SdkFeatureBand sdkFeatureBand) { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, _dotnetDir), "default.json"); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index a9346f336c47..8b2e62d6735e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -29,6 +29,8 @@ internal interface IInstaller : IWorkloadManifestInstaller IEnumerable GetDownloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, bool includeInstalledItems); + void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion); + /// /// Replace the workload resolver used by this installer. Typically used to call /// for a set of workload manifests that isn't currently installed diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs index 5cf0b2ab0eb5..7b8123ffcbb3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs @@ -309,6 +309,37 @@ protected void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) } } + public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion) + { + string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); + var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + if ((installStateContents.WorkloadSetVersion == null && workloadSetVersion == null) || + (installStateContents.WorkloadSetVersion != null && installStateContents.WorkloadSetVersion.Equals(workloadSetVersion)) { + return; + } + + Elevate(); + + if (IsElevated) + { + // Create the parent folder for the state file and set up all required ACLs + SecurityUtils.CreateSecureDirectory(Path.GetDirectoryName(path)); + installStateContents.WorkloadSetVersion = workloadSetVersion; + File.WriteAllText(path, installStateContents.ToString()); + + SecurityUtils.SecureFile(path); + } + else if (IsClient) + { + InstallResponseMessage response = Dispatcher.SendUpdateWorkloadSetRequest(sdkFeatureBand, workloadSetVersion); + ExitOnFailure(response, "Failed to update install mode."); + } + else + { + throw new InvalidOperationException($"Invalid configuration: elevated: {IsElevated}, client: {IsClient}"); + } + } + /// /// Installs the specified MSI. /// diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerServer.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerServer.cs index c62dd4b36096..f563bcbb56b2 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerServer.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerServer.cs @@ -109,6 +109,11 @@ public void Run() Dispatcher.ReplySuccess($"Updated install mode to use {newMode}."); break; + case InstallRequestType.AdjustWorkloadSetVersion: + AdjustWorkloadSetInInstallState(new SdkFeatureBand(request.SdkFeatureBand), request.WorkloadSetVersion); + Dispatcher.ReplySuccess($"Updated workload set version in install state to {request.WorkloadSetVersion}."); + break; + default: throw new InvalidOperationException($"Unknown message request: {(int)request.RequestType}"); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index c82b014efa0b..58b74bd1366e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -174,7 +174,9 @@ private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool u useWorkloadSets ? _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation) : _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); - UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, useRollback, offlineCache); + var workloadSetVersion = workloadSetLocation is null ? null : Path.GetDirectoryName(workloadSetLocation); + + UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadSetVersion, useRollback, offlineCache); WorkloadInstallCommand.TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); @@ -188,6 +190,7 @@ private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool u private void UpdateWorkloadsWithInstallRecord( SdkFeatureBand sdkFeatureBand, IEnumerable manifestsToUpdate, + string workloadSetVersion, bool useRollback, DirectoryPath? offlineCache = null) { @@ -226,6 +229,8 @@ private void UpdateWorkloadsWithInstallRecord( { _workloadInstaller.RemoveManifestsFromInstallState(sdkFeatureBand); } + + _workloadInstaller.AdjustWorkloadSetInInstallState(sdkFeatureBand, workloadSetVersion); }, rollback: () => { diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 80cf0c743864..355b211bd988 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -61,6 +61,11 @@ public void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) throw new NotImplementedException(); } + public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion) + { + + } + public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) { List packs = new List(); From 60a387f87225f4b13bb96a053160c26004c0098b Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:30:33 -0800 Subject: [PATCH 19/43] Avoid elevation if we will noop in MSI-based operations to adjust the install state (#38117) --- .../dotnet-workload/InstallStateContents.cs | 5 ++++ .../install/FileBasedInstaller.cs | 6 ++--- .../install/MsiInstallerBase.cs | 26 +++++++++++++++---- .../MockPackWorkloadInstaller.cs | 4 +-- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs index 2fc80aeec699..356a82a26502 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs @@ -25,6 +25,11 @@ public static InstallStateContents FromString(string contents) return JsonSerializer.Deserialize(contents, s_options); } + public static InstallStateContents FromPath(string path) + { + return File.Exists(path) ? FromString(File.ReadAllText(path)) : new InstallStateContents(); + } + public override string ToString() { return JsonSerializer.Serialize(this, s_options); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index d3924e7d5c90..3f97cfc155a7 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -486,7 +486,7 @@ public void RemoveManifestsFromInstallState(SdkFeatureBand sdkFeatureBand) if (File.Exists(path)) { - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + var installStateContents = InstallStateContents.FromString(File.ReadAllText(path)); installStateContents.Manifests = null; File.WriteAllText(path, installStateContents.ToString()); } @@ -496,7 +496,7 @@ public void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dict { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, _dotnetDir), "default.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + var installStateContents = InstallStateContents.FromPath(path); installStateContents.Manifests = manifestContents; File.WriteAllText(path, installStateContents.ToString()); } @@ -505,7 +505,7 @@ public void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, _dotnetDir), "default.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + var installStateContents = InstallStateContents.FromPath(path); installStateContents.UseWorkloadSets = newMode; File.WriteAllText(path, installStateContents.ToString()); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs index 7b8123ffcbb3..f1bf17a541c9 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs @@ -285,17 +285,21 @@ protected uint RepairMsi(string productCode, string logFile) /// protected void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) { + string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); + var installStateContents = InstallStateContents.FromPath(path); + if (installStateContents.UseWorkloadSets == newMode) + { + return; + } + Elevate(); if (IsElevated) { - string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); // Create the parent folder for the state file and set up all required ACLs SecurityUtils.CreateSecureDirectory(Path.GetDirectoryName(path)); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); installStateContents.UseWorkloadSets = newMode; File.WriteAllText(path, installStateContents.ToString()); - SecurityUtils.SecureFile(path); } else if (IsClient) @@ -568,6 +572,11 @@ protected void UpdateDependent(InstallRequestType requestType, string providerKe public void RemoveManifestsFromInstallState(SdkFeatureBand sdkFeatureBand) { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); + var installStateContents = InstallStateContents.FromPath(path); + if (installStateContents.Manifests == null) + { + return; + } if (!File.Exists(path)) { @@ -581,7 +590,6 @@ public void RemoveManifestsFromInstallState(SdkFeatureBand sdkFeatureBand) { if (File.Exists(path)) { - var installStateContents = InstallStateContents.FromString(File.ReadAllText(path)); installStateContents.Manifests = null; File.WriteAllText(path, installStateContents.ToString()); } @@ -601,6 +609,14 @@ public void RemoveManifestsFromInstallState(SdkFeatureBand sdkFeatureBand) public void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dictionary manifestContents) { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); + var installStateContents = InstallStateContents.FromPath(path); + if (installStateContents.Manifests != null && // manifestContents should not be null here + installStateContents.Manifests.Count == manifestContents.Count && + installStateContents.Manifests.All(m => manifestContents.TryGetValue(m.Key, out var val) && val.Equals(m.Value))) + { + return; + } + Elevate(); if (IsElevated) @@ -608,7 +624,7 @@ public void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dict // Create the parent folder for the state file and set up all required ACLs SecurityUtils.CreateSecureDirectory(Path.GetDirectoryName(path)); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + installStateContents.Manifests = manifestContents; File.WriteAllText(path, installStateContents.ToString()); diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 355b211bd988..a974f5f25d40 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -178,7 +178,7 @@ public void RemoveManifestsFromInstallState(SdkFeatureBand sdkFeatureBand) string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, _dotnetDir), "default.json"); if (File.Exists(path)) { - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + var installStateContents = InstallStateContents.FromPath(path); installStateContents.Manifests = null; File.WriteAllText(path, installStateContents.ToString()); } @@ -188,7 +188,7 @@ public void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dict { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, _dotnetDir), "default.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + var installStateContents = InstallStateContents.FromPath(path); installStateContents.Manifests = manifestContents; File.WriteAllText(path, installStateContents.ToString()); } From 402ff34f912395f59ce00e36c5337aca9145ec4b Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:41:41 -0800 Subject: [PATCH 20/43] Finish adding to install state --- .../dotnet-workload/install/FileBasedInstaller.cs | 2 +- .../commands/dotnet-workload/install/MsiInstallerBase.cs | 5 +++-- .../dotnet-workload/install/WorkloadInstallCommand.cs | 9 +++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 3f97cfc155a7..93622c50f531 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -475,7 +475,7 @@ public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, strin { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, _dotnetDir), "default.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + var installStateContents = InstallStateContents.FromPath(path); installStateContents.WorkloadSetVersion = workloadSetVersion; File.WriteAllText(path, installStateContents.ToString()); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs index f1bf17a541c9..9ebd321abac9 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs @@ -316,9 +316,10 @@ protected void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion) { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); - var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + var installStateContents = InstallStateContents.FromPath(path); if ((installStateContents.WorkloadSetVersion == null && workloadSetVersion == null) || - (installStateContents.WorkloadSetVersion != null && installStateContents.WorkloadSetVersion.Equals(workloadSetVersion)) { + (installStateContents.WorkloadSetVersion != null && installStateContents.WorkloadSetVersion.Equals(workloadSetVersion))) + { return; } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 68417d9cdfb8..cff8e5bc8b76 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -130,6 +130,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif var manifestsToUpdate = Enumerable.Empty(); var useRollback = false; + string workloadSetLocation = null; if (!skipManifestUpdate) { @@ -162,7 +163,6 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); - string workloadSetLocation = null; if (useWorkloadSets) { workloadSetLocation = InstallWorkloadSet(); @@ -173,7 +173,9 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); } - InstallWorkloadsWithInstallRecord(_workloadInstaller, workloadIds, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); + var workloadSetVersion = workloadSetLocation is null ? null : Path.GetDirectoryName(workloadSetLocation); + + InstallWorkloadsWithInstallRecord(_workloadInstaller, workloadIds, workloadSetVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); @@ -199,6 +201,7 @@ internal static void TryRunGarbageCollection(IInstaller workloadInstaller, IRepo private void InstallWorkloadsWithInstallRecord( IInstaller installer, IEnumerable workloadIds, + string workloadSetVersion, SdkFeatureBand sdkFeatureBand, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, @@ -239,6 +242,8 @@ private void InstallWorkloadsWithInstallRecord( { installer.SaveInstallStateManifestVersions(sdkFeatureBand, GetInstallStateContents(manifestsToUpdate)); } + + installer.AdjustWorkloadSetInInstallState(sdkFeatureBand, workloadSetVersion); }, rollback: () => { From 5796ee522ce3dab13f50d15646cd3cd03d51046b Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Tue, 23 Jan 2024 15:59:19 -0800 Subject: [PATCH 21/43] Remove InstallStateReader --- .../dotnet-workload/InstallStateContents.cs | 12 +- .../install/WorkloadGarbageCollector.cs | 2 +- .../update/WorkloadUpdateCommand.cs | 2 +- .../Microsoft.DotNet.TemplateLocator.csproj | 1 + ...Microsoft.DotNet.MSBuildSdkResolver.csproj | 1 + ...soft.NET.Sdk.WorkloadManifestReader.csproj | 1 + ...loadManifestProvider.InstallStateReader.cs | 104 ------------------ .../SdkDirectoryWorkloadManifestProvider.cs | 18 +-- .../Microsoft.NET.Build.Tasks.csproj | 1 + 9 files changed, 17 insertions(+), 125 deletions(-) delete mode 100644 src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs diff --git a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs index 356a82a26502..77b4cc932c6c 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs @@ -1,6 +1,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#pragma warning disable CS8632 + namespace Microsoft.DotNet.Workloads.Workload { internal class InstallStateContents @@ -9,10 +11,10 @@ internal class InstallStateContents public bool? UseWorkloadSets { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public Dictionary Manifests { get; set; } + public Dictionary? Manifests { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string WorkloadSetVersion { get; set; } + public string? WorkloadSetVersion { get; set; } private static readonly JsonSerializerOptions s_options = new() { @@ -22,7 +24,7 @@ internal class InstallStateContents public static InstallStateContents FromString(string contents) { - return JsonSerializer.Deserialize(contents, s_options); + return JsonSerializer.Deserialize(contents, s_options) ?? new InstallStateContents(); } public static InstallStateContents FromPath(string path) @@ -35,4 +37,6 @@ public override string ToString() return JsonSerializer.Serialize(this, s_options); } } -} \ No newline at end of file +} + +#pragma warning restore CS8632 \ No newline at end of file diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs index 9273cb8e0cef..d5dcb1527187 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs @@ -71,7 +71,7 @@ void GarbageCollectWorkloadSets() if (File.Exists(installStateFilePath)) { // If there is a rollback state file (default.json) in the workload install state folder, don't garbage collect the workload set it specifies. - var installState = SdkDirectoryWorkloadManifestProvider.InstallStateReader.ReadInstallState(installStateFilePath); + var installState = InstallStateContents.FromPath(installStateFilePath); if (!string.IsNullOrEmpty(installState.WorkloadSetVersion)) { WorkloadSetsToKeep.Add(installState.WorkloadSetVersion); diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 58b74bd1366e..244c1bf2bf1c 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -174,7 +174,7 @@ private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool u useWorkloadSets ? _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation) : _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); - var workloadSetVersion = workloadSetLocation is null ? null : Path.GetDirectoryName(workloadSetLocation); + var workloadSetVersion = workloadSetLocation is null ? null : Path.GetFileName(Path.GetDirectoryName(workloadSetLocation)); UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadSetVersion, useRollback, offlineCache); diff --git a/src/Microsoft.DotNet.TemplateLocator/Microsoft.DotNet.TemplateLocator.csproj b/src/Microsoft.DotNet.TemplateLocator/Microsoft.DotNet.TemplateLocator.csproj index 20f6d73e1473..84bd3a16954c 100644 --- a/src/Microsoft.DotNet.TemplateLocator/Microsoft.DotNet.TemplateLocator.csproj +++ b/src/Microsoft.DotNet.TemplateLocator/Microsoft.DotNet.TemplateLocator.csproj @@ -51,6 +51,7 @@ + diff --git a/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj b/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj index 77a9cf79660b..600d5decb5e7 100644 --- a/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj +++ b/src/Resolvers/Microsoft.DotNet.MSBuildSdkResolver/Microsoft.DotNet.MSBuildSdkResolver.csproj @@ -72,6 +72,7 @@ + diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Microsoft.NET.Sdk.WorkloadManifestReader.csproj b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Microsoft.NET.Sdk.WorkloadManifestReader.csproj index bfeb093643bd..afc2aa64034c 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Microsoft.NET.Sdk.WorkloadManifestReader.csproj +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Microsoft.NET.Sdk.WorkloadManifestReader.csproj @@ -21,6 +21,7 @@ + diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs deleted file mode 100644 index 7579778f6a46..000000000000 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs +++ /dev/null @@ -1,104 +0,0 @@ -// 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 Microsoft.NET.Sdk.Localization; -using static Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadManifestReader; -using Microsoft.Deployment.DotNet.Releases; - -#if USE_SYSTEM_TEXT_JSON -using System.Text.Json; -#else -using Newtonsoft.Json; -using JsonTokenType = Newtonsoft.Json.JsonToken; -#endif - -namespace Microsoft.NET.Sdk.WorkloadManifestReader -{ - public partial class SdkDirectoryWorkloadManifestProvider - { - public class InstallState - { - public string? WorkloadSetVersion { get; set; } - public WorkloadSet? Manifests { get; set; } - } - - public static class InstallStateReader - { - public static InstallState ReadInstallState(string installStatePath) - { - using var fileStream = File.OpenRead(installStatePath); - -#if USE_SYSTEM_TEXT_JSON - var readerOptions = new JsonReaderOptions - { - AllowTrailingCommas = true, - CommentHandling = JsonCommentHandling.Skip - }; - var reader = new Utf8JsonStreamReader(fileStream, readerOptions); -#else - using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - - var reader = new Utf8JsonStreamReader(jsonReader); -#endif - - InstallState installState = new(); - - JsonReader.ConsumeToken(ref reader, JsonTokenType.StartObject); - while (reader.Read()) - { - switch (reader.TokenType) - { - case JsonTokenType.PropertyName: - var propName = reader.GetString(); - if (string.Equals("workloadVersion", propName, StringComparison.OrdinalIgnoreCase)) - { - installState.WorkloadSetVersion = JsonReader.ReadString(ref reader); - } - else if (string.Equals("manifests", propName, StringComparison.OrdinalIgnoreCase)) - { - installState.Manifests = ReadManifests(ref reader); - } - else - { - JsonReader.ConsumeValue(ref reader); - } - break; - - case JsonTokenType.EndObject: - return installState; - default: - throw new JsonFormatException(Strings.UnexpectedTokenAtOffset, reader.TokenType, reader.TokenStartIndex); - } - } - - throw new JsonFormatException(Strings.IncompleteDocument); - } - - static WorkloadSet ReadManifests(ref Utf8JsonStreamReader reader) - { - JsonReader.ConsumeToken(ref reader, JsonTokenType.StartObject); - Dictionary workloadSetDict = new(); - - while (reader.Read()) - { - switch (reader.TokenType) - { - case JsonTokenType.PropertyName: - var propName = reader.GetString(); - var propValue = JsonReader.ReadString(ref reader); - workloadSetDict[propName] = propValue; - break; - case JsonTokenType.EndObject: - return WorkloadSet.FromDictionaryForJson(workloadSetDict, new SdkFeatureBand(new ReleaseVersion(0,0,0))); - default: - throw new JsonFormatException(Strings.UnexpectedTokenAtOffset, reader.TokenType, reader.TokenStartIndex); - } - } - throw new JsonFormatException(Strings.IncompleteDocument); - } - } - } -} - diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index f89ae89400d3..32e76bbf3735 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -126,7 +126,7 @@ internal SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVers var installStateFilePath = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkVersionBand, _sdkRootPath), "default.json"); if (File.Exists(installStateFilePath)) { - var installState = InstallStateReader.ReadInstallState(installStateFilePath); + var installState = InstallStateContents.FromPath(installStateFilePath); if (!string.IsNullOrEmpty(installState.WorkloadSetVersion)) { if (!availableWorkloadSets.TryGetValue(installState.WorkloadSetVersion!, out _workloadSet)) @@ -134,7 +134,7 @@ internal SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVers throw new FileNotFoundException(string.Format(Strings.WorkloadVersionFromInstallStateNotFound, installState.WorkloadSetVersion, installStateFilePath)); } } - _manifestsFromInstallState = installState.Manifests; + _manifestsFromInstallState = installState.Manifests is null ? new WorkloadSet() : WorkloadSet.FromDictionaryForJson(installState.Manifests, _sdkVersionBand); _installStateFilePath = installStateFilePath; } } @@ -413,19 +413,7 @@ public Dictionary GetAvailableWorkloadSets() var jsonFile = Path.Combine(workloadSetDirectory, "workloadset.json"); if (File.Exists(jsonFile)) { - var newWorkloadSet = WorkloadSet.FromJson(File.ReadAllText(jsonFile), _sdkVersionBand); - if (workloadSet == null) - { - workloadSet = newWorkloadSet; - } - else - { - // If there are multiple workloadset.json files, merge them - foreach (var kvp in newWorkloadSet.ManifestVersions) - { - workloadSet.ManifestVersions.Add(kvp.Key, kvp.Value); - } - } + workloadSet = WorkloadSet.FromJson(File.ReadAllText(jsonFile), _sdkVersionBand); } if (workloadSet != null) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj b/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj index 18c60cc15bde..da284b7bd196 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj +++ b/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj @@ -89,6 +89,7 @@ + From 4b8ab179c31c33b37754ff9c3434b0220e96a7f4 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Wed, 24 Jan 2024 15:18:03 -0800 Subject: [PATCH 22/43] Small fixes --- .../dotnet-workload/install/NetSdkMsiInstallerClient.cs | 7 ++++++- .../dotnet-workload/install/WorkloadManifestUpdater.cs | 7 ++++++- .../dotnet-workload/update/WorkloadUpdateCommandParser.cs | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 7b6e9db26ce5..c32a3595a324 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -232,6 +232,11 @@ private string ModifyWorkloadSet(string path, InstallAction installAction) InstallAction plannedAction = PlanPackage(msi, state, installAction, installedVersion, out IEnumerable relatedProducts); + if (plannedAction != InstallAction.None) + { + Elevate(); + } + ExecutePackage(msi, plannedAction, msiPackageId); // Update the reference count against the MSI. @@ -613,7 +618,7 @@ public void Shutdown() public PackageId GetManifestPackageId(ManifestId manifestId, SdkFeatureBand featureBand) { - if (manifestId.ToString().Equals("Microsoft.NET.Workloads")) + if (manifestId.ToString().Equals("Microsoft.NET.Workloads", StringComparison.OrdinalIgnoreCase)) { return new PackageId($"{manifestId}.{featureBand}.Msi.{RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant()}"); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index fb1c3b32395b..8525293f0961 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -287,7 +287,7 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP Directory.GetFiles(offlineCache.Value.Value) .Where(path => path.EndsWith(".nupkg") && Path.GetFileName(path).StartsWith(manifestPackageId.ToString(), StringComparison.OrdinalIgnoreCase)) .Max() : - await _nugetPackageDownloader.DownloadPackageAsync(manifestPackageId, packageSourceLocation: _packageSourceLocation, includePreview: includePreviews); + await _nugetPackageDownloader.DownloadPackageAsync(manifestPackageId, packageVersion: packageVersion, packageSourceLocation: _packageSourceLocation, includePreview: includePreviews); } catch (NuGetPackageNotFoundException) { @@ -311,6 +311,11 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP // The format is Microsoft.NET.Workloads.featureBand.version, so this skips past the band and the '.' afterwards to get the version var version = fileName.Substring(fileName.IndexOf(featureBand) + featureBand.Length + 1); + if (version.StartsWith("msi", StringComparison.OrdinalIgnoreCase)) + { + // version starts with msi.. Remove that part. + version = version.Substring(version.IndexOf('.', 5)); + } File.WriteAllText(Path.Combine(adManifestPath, "version.txt"), version); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs index bb405817d5c6..365578935567 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs @@ -48,6 +48,7 @@ private static CliCommand ConstructCommand() command.Options.Add(TempDirOption); command.Options.Add(FromPreviousSdkOption); command.Options.Add(AdManifestOnlyOption); + command.Options.Add(WorkloadSetVersionOption); command.AddWorkloadCommandNuGetRestoreActionConfigOptions(); command.Options.Add(CommonOptions.VerbosityOption); command.Options.Add(PrintRollbackOption); From 2e0d6e5ccb4fa382c43e6367d491aeaf40a8d39e Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:25:59 -0800 Subject: [PATCH 23/43] More small fixes --- .../dotnet-workload/install/NetSdkMsiInstallerClient.cs | 2 +- .../commands/dotnet-workload/install/WorkloadManifestUpdater.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index c32a3595a324..01ad4e4f676d 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -227,7 +227,7 @@ private string ModifyWorkloadSet(string path, InstallAction installAction) { // If we are installing the workload set, record its version and the previous version so that we can roll back if necessary. _newWorkloadSetPath = path; - _previousWorkloadSetVersion = installedVersion.ToString(); + _previousWorkloadSetVersion = installedVersion?.ToString(); } InstallAction plannedAction = PlanPackage(msi, state, installAction, installedVersion, out IEnumerable relatedProducts); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 8525293f0961..09c2b0b3d069 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -314,7 +314,7 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP if (version.StartsWith("msi", StringComparison.OrdinalIgnoreCase)) { // version starts with msi.. Remove that part. - version = version.Substring(version.IndexOf('.', 5)); + version = version.Substring(version.IndexOf('.', 5) + 1); } File.WriteAllText(Path.Combine(adManifestPath, "version.txt"), version); } From 0e4c5f1a96c97caa06aff3da4b06593117b2479b Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 25 Jan 2024 13:26:20 -0800 Subject: [PATCH 24/43] Fix rollback behavior --- .../dotnet-workload/install/NetSdkMsiInstallerClient.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 01ad4e4f676d..622af807df47 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -227,7 +227,8 @@ private string ModifyWorkloadSet(string path, InstallAction installAction) { // If we are installing the workload set, record its version and the previous version so that we can roll back if necessary. _newWorkloadSetPath = path; - _previousWorkloadSetVersion = installedVersion?.ToString(); + var parentDirectory = new DirectoryInfo(Path.GetDirectoryName(Path.GetDirectoryName(msi.MsiPath))); + _previousWorkloadSetVersion = parentDirectory.EnumerateDirectories().Select(d => d.Name).Where(n => !n.Equals(version))?.Max(); } InstallAction plannedAction = PlanPackage(msi, state, installAction, installedVersion, out IEnumerable relatedProducts); From 3a60e0c1b926eb510f32983aa80475bc8a122aa2 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:02:07 -0800 Subject: [PATCH 25/43] Update some tests --- .../dotnet-workload/InstallStateContents.cs | 1 + ...rkloadManifestProvider.GlobalJsonReader.cs | 2 +- ...kDirectoryWorkloadManifestProviderTests.cs | 26 +++++++++---------- .../WorkloadGarbageCollectionTests.cs | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs index 77b4cc932c6c..5b0a2c5816d0 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs @@ -20,6 +20,7 @@ internal class InstallStateContents { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true, + AllowTrailingCommas = true, }; public static InstallStateContents FromString(string contents) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs index 43dd03f24073..19ec03b462aa 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs @@ -61,7 +61,7 @@ static class GlobalJsonReader { case JsonTokenType.PropertyName: var sdkPropName = reader.GetString(); - if (string.Equals("workloadVersion", sdkPropName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("workloadSetVersion", sdkPropName, StringComparison.OrdinalIgnoreCase)) { workloadVersion = JsonReader.ReadString(ref reader); } diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index b74d87bcf0fa..3da88ddad152 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -48,7 +48,7 @@ public void ItShouldReturnTheWorkloadVersion(bool useWorkloadSet) { ""ios"": ""11.0.2/8.0.100"", ""android"": ""33.0.2-rc.1/8.0.200"", - ""maui"": ""15.0.1-rc.456/8.0.200-rc.2"", + ""maui"": ""15.0.1-rc.456/8.0.200-rc.2"" } "); } @@ -427,7 +427,7 @@ public void ItUsesWorkloadSetFromGlobalJson() { "sdk": { "version": "8.0.200", - "workloadversion": "8.0.201" + "workloadSetVersion": "8.0.201" }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2", @@ -469,7 +469,7 @@ public void ItFailsIfWorkloadSetFromGlobalJsonIsNotInstalled() { "sdk": { "version": "8.0.200", - "workloadversion": "8.0.201" + "workloadSetVersion": "8.0.201" }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2", @@ -498,7 +498,7 @@ public void ItFailsIfGlobalJsonIsMalformed() File.WriteAllText(globalJsonPath, """ { "sdk": { - "workloadversion": [ "8.0.202" ] + "workloadSetVersion": [ "8.0.202" ] } } """); @@ -538,7 +538,7 @@ public void ItUsesWorkloadSetFromInstallState() CreateMockInstallState("8.0.200", """ { - "workloadVersion": "8.0.201" + "workloadSetVersion": "8.0.201" } """); @@ -574,7 +574,7 @@ public void ItFailsIfWorkloadSetFromInstallStateIsNotInstalled() var installStatePath = CreateMockInstallState("8.0.200", """ { - "workloadVersion": "8.0.203" + "workloadSetVersion": "8.0.203" } """); @@ -606,7 +606,7 @@ public void ItFailsIfManifestFromWorkloadSetFromInstallStateIsNotInstalled() var installStatePath = CreateMockInstallState("8.0.200", """ { - "workloadVersion": "8.0.201" + "workloadSetVersion": "8.0.201" } """); @@ -719,7 +719,7 @@ public void ItUsesWorkloadSetAndManifestFromInstallState() CreateMockInstallState("8.0.200", """ { - "workloadVersion": "8.0.201", + "workloadSetVersion": "8.0.201", "manifests": { "tizen": "8.0.0/8.0.200", } @@ -758,7 +758,7 @@ public void WorkloadManifestFromInstallStateOverridesWorkloadSetFromInstallState CreateMockInstallState("8.0.200", """ { - "workloadVersion": "8.0.201", + "workloadSetVersion": "8.0.201", "manifests": { "ios": "11.0.1/8.0.100", } @@ -795,7 +795,7 @@ public void ItFallsBackForManifestNotInInstallState() """ { "manifests": { - "ios": "12.0.1/8.0.200", + "ios": "12.0.1/8.0.200" } } """); @@ -818,7 +818,7 @@ public void GlobalJsonOverridesInstallState() { "sdk": { "version": "8.0.200", - "workloadversion": "8.0.201" + "workloadSetVersion": "8.0.201" }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2", @@ -829,7 +829,7 @@ public void GlobalJsonOverridesInstallState() CreateMockInstallState("8.0.200", """ { - "workloadVersion": "8.0.202", + "workloadSetVersion": "8.0.202", } """); @@ -868,7 +868,7 @@ public void GlobalJsonWithoutWorkloadVersionDoesNotOverrideInstallState() CreateMockInstallState("8.0.200", """ { - "workloadVersion": "8.0.200", + "workloadSetVersion": "8.0.200", } """); diff --git a/src/Tests/dotnet-workload-install.Tests/WorkloadGarbageCollectionTests.cs b/src/Tests/dotnet-workload-install.Tests/WorkloadGarbageCollectionTests.cs index 7946e7e3ce5a..0cd4e2a2fe21 100644 --- a/src/Tests/dotnet-workload-install.Tests/WorkloadGarbageCollectionTests.cs +++ b/src/Tests/dotnet-workload-install.Tests/WorkloadGarbageCollectionTests.cs @@ -200,7 +200,7 @@ public void GarbageCollectManifestsWithInstallState() """ { "manifests": { - "testmanifest": "2.0.0/6.0.300", + "testmanifest": "2.0.0/6.0.300" } } """); From d47e4045aa315f0d759cc0e37f1c1134a96b003b Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 26 Jan 2024 15:16:44 -0800 Subject: [PATCH 26/43] Add test --- .../MockPackWorkloadInstaller.cs | 18 +++++-- .../MockWorkloadManifestUpdater.cs | 9 +++- .../MockWorkloadResolver.cs | 4 +- .../GivenDotnetWorkloadUpdate.cs | 50 +++++++++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index a974f5f25d40..13151200e0a2 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -24,13 +24,14 @@ internal class MockPackWorkloadInstaller : IInstaller public bool FailingGarbageCollection; private readonly string FailingPack; private readonly string _dotnetDir; + private string workloadSetContents; public IWorkloadResolver WorkloadResolver { get; set; } public int ExitCode => 0; public MockPackWorkloadInstaller(string dotnetDir, string failingWorkload = null, string failingPack = null, bool failingRollback = false, IList installedWorkloads = null, - IList installedPacks = null, bool failingGarbageCollection = false) + IList installedPacks = null, bool failingGarbageCollection = false, string workloadSetContents = "") { InstallationRecordRepository = new MockInstallationRecordRepository(failingWorkload, installedWorkloads); FailingRollback = failingRollback; @@ -38,6 +39,7 @@ public MockPackWorkloadInstaller(string dotnetDir, string failingWorkload = null FailingPack = failingPack; FailingGarbageCollection = failingGarbageCollection; _dotnetDir = dotnetDir; + this.workloadSetContents = workloadSetContents; } IEnumerable GetPacksForWorkloads(IEnumerable workloadIds) @@ -63,7 +65,13 @@ public void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion) { - + var installStatePath = Path.Combine(Path.GetTempPath(), "dotnetTestPath", "metadata", "workloads", sdkFeatureBand.ToString(), "InstallState", "default.json"); + var contents = InstallStateContents.FromPath(installStatePath); + contents.WorkloadSetVersion = workloadSetVersion; + if (File.Exists(installStatePath)) + { + File.WriteAllText(installStatePath, contents.ToString()); + } } public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) @@ -96,7 +104,11 @@ public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand }); } - public string InstallWorkloadSet(string path) => throw new NotImplementedException(); + public string InstallWorkloadSet(string path) + { + return (path ?? string.Empty) + "installed.workloadset.json"; + } + public void RollBackWorkloadSetInstallation() => throw new NotImplementedException(); public void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null) => throw new NotImplementedException(); diff --git a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs index 78557f03b2bb..ecb7dc64d68d 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs @@ -13,10 +13,12 @@ internal class MockWorkloadManifestUpdater : IWorkloadManifestUpdater public int CalculateManifestUpdatesCallCount = 0; public int GetManifestPackageDownloadsCallCount = 0; private readonly IEnumerable _manifestUpdates; + private bool _fromWorkloadSet; - public MockWorkloadManifestUpdater(IEnumerable manifestUpdates = null) + public MockWorkloadManifestUpdater(IEnumerable manifestUpdates = null, bool fromWorkloadSet = false) { _manifestUpdates = manifestUpdates ?? new List(); + _fromWorkloadSet = fromWorkloadSet; } public Task UpdateAdvertisingManifestsAsync(bool includePreview, bool useWorkloadSets = false, DirectoryPath? cachePath = null) @@ -42,6 +44,11 @@ public Task> GetManifestPackageDownloadsAsync(bool public IEnumerable CalculateManifestRollbacks(string rollbackDefinitionFilePath) { + if (_fromWorkloadSet && !rollbackDefinitionFilePath.EndsWith("installed.workloadset.json")) + { + throw new Exception("Should be updating or installing via workload set."); + } + return _manifestUpdates.Select(t => t.ManifestUpdate); } diff --git a/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs b/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs index 0a769ee235ea..8063b14fb986 100644 --- a/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs +++ b/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs @@ -17,11 +17,11 @@ public MockWorkloadResolver(IEnumerable available public IEnumerable GetAvailableWorkloads() => _availableWorkloads; public IEnumerable GetInstalledWorkloadPacksOfKind(WorkloadPackKind kind) => throw new NotImplementedException(); - public IEnumerable GetPacksInWorkload(WorkloadId workloadId) => throw new NotImplementedException(); + public IEnumerable GetPacksInWorkload(WorkloadId workloadId) => Array.Empty(); public IEnumerable GetExtendedWorkloads(IEnumerable workloadIds) => throw new NotImplementedException(); public ISet GetWorkloadSuggestionForMissingPacks(IList packId, out ISet unsatisfiablePacks) => throw new NotImplementedException(); - public void RefreshWorkloadManifests() => throw new NotImplementedException(); + public void RefreshWorkloadManifests() { } public WorkloadResolver.PackInfo TryGetPackInfo(WorkloadPackId packId) => throw new NotImplementedException(); public bool IsPlatformIncompatibleWorkload(WorkloadId workloadId) => throw new NotImplementedException(); public string GetManifestVersion(string manifestId) => throw new NotImplementedException(); diff --git a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs index 896569702333..3caeb9a6df23 100644 --- a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs +++ b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs @@ -13,6 +13,7 @@ using Microsoft.DotNet.Cli.Utils; using static Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadResolver; using System.Text.Json; +using Microsoft.DotNet.Cli.Workload.Search.Tests; namespace Microsoft.DotNet.Cli.Workload.Update.Tests { @@ -190,6 +191,55 @@ public void GivenWorkloadUpdateItUpdatesOutOfDatePacks() installer.InstalledPacks.Where(pack => pack.Id.ToString().Contains("Android")).Count().Should().Be(8); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void UpdateViaWorkloadSet(bool upgrade) + { + var versionNumber = "8.0.0"; + var workloadSetContents = @" +{ +""android"": ""2.3.4/8.0.200"" +} +"; + var nugetPackageDownloader = new MockNuGetPackageDownloader(); + var workloadResolver = new MockWorkloadResolver(new WorkloadInfo[] { new WorkloadInfo(new WorkloadId("android"), string.Empty) }); + var workloadInstaller = new MockPackWorkloadInstaller( + Path.Combine(Path.GetTempPath(), "dotnetTestPat", "userProfileDir"), + installedWorkloads: new List() { new WorkloadId("android")}, + workloadSetContents: workloadSetContents) + { + WorkloadResolver = workloadResolver + }; + var oldVersion = upgrade ? "2.3.2" : "2.3.6"; + var workloadManifestUpdater = new MockWorkloadManifestUpdater( + manifestUpdates: new ManifestUpdateWithWorkloads[] { + new ManifestUpdateWithWorkloads(new ManifestVersionUpdate(new ManifestId("android"), new ManifestVersion(oldVersion), "8.0.200", new ManifestVersion("2.3.4"), "8.0.200"), Enumerable.Empty>().ToDictionary()) + }, + fromWorkloadSet: true); + var resolverFactory = new MockWorkloadResolverFactory(Path.Combine(Path.GetTempPath(), "dotnetTestPath"), versionNumber, workloadResolver, "userProfileDir"); + var updateCommand = new WorkloadUpdateCommand(Parser.Instance.Parse("dotnet workload update"), Reporter.Output, resolverFactory, workloadInstaller, nugetPackageDownloader, workloadManifestUpdater); + + var installStatePath = Path.Combine(Path.GetTempPath(), "dotnetTestPath", "metadata", "workloads", versionNumber, "InstallState", "default.json"); + var contents = new InstallStateContents(); + contents.UseWorkloadSets = true; + try + { + Directory.CreateDirectory(Path.GetDirectoryName(installStatePath)); + File.WriteAllText(installStatePath, contents.ToString()); + updateCommand.Execute(); + var newContents = InstallStateContents.FromPath(installStatePath); + newContents.WorkloadSetVersion.Should().Be("8.0.0"); + } + finally + { + File.Delete(installStatePath); + } + + workloadInstaller.InstalledManifests.Count.Should().Be(1); + workloadInstaller.InstalledManifests[0].manifestUpdate.NewVersion.ToString().Should().Be("2.3.4"); + } + [Fact] public void GivenWorkloadUpdateItRollsBackOnFailedUpdate() { From ea939c708cde057f1a6602eb80324b1135436080 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 5 Feb 2024 13:26:42 -0800 Subject: [PATCH 27/43] Simplify workload set version finding in list --- .../dotnet-workload/list/WorkloadListCommand.cs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs index e13ec31ec84b..b58d4c15a2b3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs @@ -93,22 +93,11 @@ public override int Execute() table.PrintRows(installedWorkloads.AsEnumerable(), l => Reporter.WriteLine(l)); - if (InstallingWorkloadCommand.GetInstallStateMode(_workloadListHelper._currentSdkFeatureBand, _workloadListHelper.dotnetPath)) + var installState = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_workloadListHelper._currentSdkFeatureBand, _workloadListHelper.dotnetPath), "default.json")); + if (installState.UseWorkloadSets == true) { - var workloadSetVersion = "unknown"; - try - { - var workloadSetPath = Path.Combine(_workloadListHelper.dotnetPath, "sdk-manifests", _workloadListHelper._currentSdkFeatureBand.ToString(), "workloadsets"); - var workloadSetDirectory = new DirectoryInfo(workloadSetPath); - workloadSetVersion = workloadSetDirectory.EnumerateDirectories().Where(d => d.EnumerateFiles("workloadset.json").Count() == 1).Max().Name; - } - catch (Exception) - { - // Don't throw just because we couldn't find a workload set! The user may have changed the mode to workload sets but not yet run update/install. - } - Reporter.WriteLine(); - Reporter.WriteLine(string.Format(LocalizableStrings.WorkloadSetVersion, workloadSetVersion)); + Reporter.WriteLine(string.Format(LocalizableStrings.WorkloadSetVersion, installState.WorkloadSetVersion ?? "unknown")); } Reporter.WriteLine(); From 21a33a5b7fe8893600753b64c13c2744cbc3b180 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 5 Feb 2024 16:47:22 -0800 Subject: [PATCH 28/43] Couple comments --- .../install/NetSdkMsiInstallerClient.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 622af807df47..123a845878fc 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -203,7 +203,7 @@ public void RollBackWorkloadSetInstallation() } } - private string ModifyWorkloadSet(string path, InstallAction installAction) + private string ModifyWorkloadSet(string path, InstallAction requestedAction) { ReportPendingReboot(); @@ -223,25 +223,24 @@ private string ModifyWorkloadSet(string path, InstallAction installAction) VerifyPackage(msi); DetectState state = DetectPackage(msi.ProductCode, out Version installedVersion); - if (installAction == InstallAction.Install) + if (requestedAction == InstallAction.Install) { // If we are installing the workload set, record its version and the previous version so that we can roll back if necessary. _newWorkloadSetPath = path; - var parentDirectory = new DirectoryInfo(Path.GetDirectoryName(Path.GetDirectoryName(msi.MsiPath))); - _previousWorkloadSetVersion = parentDirectory.EnumerateDirectories().Select(d => d.Name).Where(n => !n.Equals(version))?.Max(); + _previousWorkloadSetVersion = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, DotNetHome), "default.json")).WorkloadSetVersion; } - InstallAction plannedAction = PlanPackage(msi, state, installAction, installedVersion, out IEnumerable relatedProducts); + InstallAction plannedAction = PlanPackage(msi, state, requestedAction, installedVersion, out IEnumerable relatedProducts); if (plannedAction != InstallAction.None) { Elevate(); - } - ExecutePackage(msi, plannedAction, msiPackageId); + ExecutePackage(msi, plannedAction, msiPackageId); - // Update the reference count against the MSI. - UpdateDependent(InstallRequestType.AddDependent, msi.Manifest.ProviderKeyName, _dependent); + // Update the reference count against the MSI. + UpdateDependent(InstallRequestType.AddDependent, msi.Manifest.ProviderKeyName, _dependent); + } return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", version, "workloadset.json"); } From 925239dc65b71119b1ab4759abcaacf8440a12f0 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 5 Feb 2024 20:52:36 -0800 Subject: [PATCH 29/43] PR comments --- .../Microsoft.DotNet.Cli.Utils/PathUtility.cs | 22 +++++----- .../commands/InstallingWorkloadCommand.cs | 4 +- .../install/FileBasedInstaller.cs | 30 ++++++------- .../dotnet-workload/install/IInstaller.cs | 4 +- .../install/NetSdkMsiInstallerClient.cs | 42 +++++++------------ .../install/WorkloadInstallCommand.cs | 21 +++++----- .../update/WorkloadUpdateCommand.cs | 19 ++++----- .../MockPackWorkloadInstaller.cs | 4 +- 8 files changed, 64 insertions(+), 82 deletions(-) diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs index 556294ea27bf..1957a49a1739 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs @@ -104,21 +104,19 @@ public static bool TryDeleteDirectory(string directoryPath) /// public static bool DeleteFileAndEmptyParents(string path) { - try + if (!File.Exists(path)) { - File.Delete(path); - var dir = Path.GetDirectoryName(path); + return false; + } - // Directory.Delete throws an exception when it fails to delete - // a directory, as, for instance, if it isn't empty. This is - // intended to run until it throws an exception, then return. - while (true) - { - Directory.Delete(dir); - dir = Path.GetDirectoryName(dir); - } + File.Delete(path); + var dir = Path.GetDirectoryName(path); + + while (!Directory.EnumerateFileSystemEntries(dir).Any()) + { + Directory.Delete(dir); + dir = Path.GetDirectoryName(dir); } - catch (Exception) { } return !File.Exists(path); } diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index aa7d269e5e27..4d96cd870476 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -103,9 +103,9 @@ public static bool GetInstallStateMode(SdkFeatureBand sdkFeatureBand, string dot return installStateContents.UseWorkloadSets ?? false; } - public string InstallWorkloadSet() + public string InstallWorkloadSet(CliTransaction transaction) { - return _workloadInstaller.InstallWorkloadSet(Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads")); + return _workloadInstaller.InstallWorkloadSet(transaction, Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads")); } protected async Task> GetDownloads(IEnumerable workloadIds, bool skipManifestUpdate, bool includePreview, string downloadFolder = null) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 93622c50f531..72ba8419fc91 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -32,7 +32,6 @@ internal class FileBasedInstaller : IInstaller private readonly FileBasedInstallationRecordRepository _installationRecordRepository; private readonly PackageSourceLocation _packageSourceLocation; private readonly RestoreActionConfig _restoreActionConfig; - private string workloadSetPath; public int ExitCode => 0; @@ -86,24 +85,27 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds) return packs; } - public string InstallWorkloadSet(string path) + public string InstallWorkloadSet(CliTransaction transaction, string path) { - workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), "workloadset.json"); - Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); + var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), "workloadset.json"); + transaction.Run( + action: context => + { + Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); - File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath, overwrite: true); + File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath, overwrite: true); + }, + rollback: () => + { + if (path is not null) + { + PathUtility.DeleteFileAndEmptyParents(path); + } + }); + return workloadSetPath; } - public void RollBackWorkloadSetInstallation() - { - // We don't really need to worry about uninstalling workload sets for file-based installations, since they're side-by-side. - if (workloadSetPath is not null) - { - PathUtility.DeleteFileAndEmptyParents(workloadSetPath); - } - } - public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) { var packInfos = GetPacksInWorkloads(workloadIds); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index 8b2e62d6735e..94f2d4e61f07 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -13,9 +13,7 @@ internal interface IInstaller : IWorkloadManifestInstaller { int ExitCode { get; } - string InstallWorkloadSet(string path); - - void RollBackWorkloadSetInstallation(); + string InstallWorkloadSet(CliTransaction transaction, string path); void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 123a845878fc..002e1b36c721 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -34,9 +34,6 @@ internal partial class NetSdkMsiInstallerClient : MsiInstallerBase, IInstaller public int ExitCode => Restart ? unchecked((int)Error.SUCCESS_REBOOT_REQUIRED) : unchecked((int)Error.SUCCESS); - private string _newWorkloadSetPath; - private string _previousWorkloadSetVersion; - public NetSdkMsiInstallerClient(InstallElevationContextBase elevationContext, ISetupLogger logger, bool verifySignatures, @@ -185,31 +182,29 @@ public void GarbageCollect(Func getResolverForWorkloa } } - public string InstallWorkloadSet(string path) + public string InstallWorkloadSet(CliTransaction transaction, string path) { - return ModifyWorkloadSet(path, InstallAction.Install); - } - - public void RollBackWorkloadSetInstallation() - { - if (_newWorkloadSetPath is not null) - { - ModifyWorkloadSet(_newWorkloadSetPath, InstallAction.Uninstall); - if (_previousWorkloadSetVersion is not null) + var pathToReturn = string.Empty; + var previousVersion = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, DotNetHome), "default.json")).WorkloadSetVersion; + transaction.Run( + action: context => { - File.WriteAllText(Path.Combine(_newWorkloadSetPath, "version.txt"), _previousWorkloadSetVersion); - ModifyWorkloadSet(_newWorkloadSetPath, InstallAction.Repair); - } - } + pathToReturn = ModifyWorkloadSet(path, InstallAction.Install); + }, + rollback: () => + { + ModifyWorkloadSet(path, InstallAction.Uninstall); + File.WriteAllText(Path.Combine(path, "version.txt"), previousVersion); + ModifyWorkloadSet(path, InstallAction.Repair); + }); + + return pathToReturn; } private string ModifyWorkloadSet(string path, InstallAction requestedAction) { ReportPendingReboot(); - // Rolling back a manifest update after a successful install is essentially a downgrade, which is blocked so we have to - // treat it as a special case and is different from the install failing and rolling that back, though depending where the install - // failed, it may have removed the old product already. // Resolve the package ID for the manifest payload package var featureBand = Path.GetFileName(Path.GetDirectoryName(path)); var version = File.ReadAllText(Path.Combine(path, "version.txt")); @@ -223,13 +218,6 @@ private string ModifyWorkloadSet(string path, InstallAction requestedAction) VerifyPackage(msi); DetectState state = DetectPackage(msi.ProductCode, out Version installedVersion); - if (requestedAction == InstallAction.Install) - { - // If we are installing the workload set, record its version and the previous version so that we can roll back if necessary. - _newWorkloadSetPath = path; - _previousWorkloadSetVersion = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, DotNetHome), "default.json")).WorkloadSetVersion; - } - InstallAction plannedAction = PlanPackage(msi, state, requestedAction, installedVersion, out IEnumerable relatedProducts); if (plannedAction != InstallAction.None) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index cff8e5bc8b76..7f6c8858d804 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -143,6 +143,13 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif } } + var transaction = new CliTransaction + { + RollbackStarted = () => Reporter.WriteLine(LocalizableStrings.RollingBackInstall), + // Don't hide the original error if roll back fails, but do log the rollback failure + RollbackFailed = ex => Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)) + }; + if (!skipManifestUpdate) { if (Verbosity != VerbosityOptions.quiet && Verbosity != VerbosityOptions.q) @@ -165,7 +172,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif if (useWorkloadSets) { - workloadSetLocation = InstallWorkloadSet(); + workloadSetLocation = InstallWorkloadSet(transaction); } manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : @@ -175,7 +182,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif var workloadSetVersion = workloadSetLocation is null ? null : Path.GetDirectoryName(workloadSetLocation); - InstallWorkloadsWithInstallRecord(_workloadInstaller, workloadIds, workloadSetVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); + InstallWorkloadsWithInstallRecord(transaction, _workloadInstaller, workloadIds, workloadSetVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); @@ -199,6 +206,7 @@ internal static void TryRunGarbageCollection(IInstaller workloadInstaller, IRepo } private void InstallWorkloadsWithInstallRecord( + CliTransaction transaction, IInstaller installer, IEnumerable workloadIds, string workloadSetVersion, @@ -210,13 +218,6 @@ private void InstallWorkloadsWithInstallRecord( IEnumerable workloadPackToInstall = new List(); IEnumerable newWorkloadInstallRecords = new List(); - var transaction = new CliTransaction - { - RollbackStarted = () => Reporter.WriteLine(LocalizableStrings.RollingBackInstall), - // Don't hide the original error if roll back fails, but do log the rollback failure - RollbackFailed = ex => Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)) - }; - transaction.Run( action: context => { @@ -255,8 +256,6 @@ private void InstallWorkloadsWithInstallRecord( installer.GetWorkloadInstallationRecordRepository() .DeleteWorkloadInstallationRecord(workloadId, sdkFeatureBand); } - - installer.RollBackWorkloadSetInstallation(); }); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 244c1bf2bf1c..3ce712c3f815 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -126,8 +126,9 @@ public override int Execute() } _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache); - var workloadSetLocation = InstallWorkloadSet(); - CalculateManifestUpdatesAndUpdateWorkloads(false, true, workloadSetLocation, offlineCache); + var transaction = new CliTransaction(); + var workloadSetLocation = InstallWorkloadSet(transaction); + CalculateManifestUpdatesAndUpdateWorkloads(false, true, workloadSetLocation, offlineCache, transaction); } } catch (Exception e) @@ -159,15 +160,16 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); string workloadSetLocation = null; + var transaction = new CliTransaction(); if (useWorkloadSets) { - workloadSetLocation = InstallWorkloadSet(); + workloadSetLocation = InstallWorkloadSet(transaction); } - CalculateManifestUpdatesAndUpdateWorkloads(useRollback, useWorkloadSets, workloadSetLocation, offlineCache); + CalculateManifestUpdatesAndUpdateWorkloads(useRollback, useWorkloadSets, workloadSetLocation, offlineCache, transaction); } - private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool useWorkloadSets, string workloadSetLocation, DirectoryPath? offlineCache) + private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool useWorkloadSets, string workloadSetLocation, DirectoryPath? offlineCache, CliTransaction transaction) { var workloadIds = GetUpdatableWorkloads(); var manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : @@ -176,7 +178,7 @@ private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool u var workloadSetVersion = workloadSetLocation is null ? null : Path.GetFileName(Path.GetDirectoryName(workloadSetLocation)); - UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadSetVersion, useRollback, offlineCache); + UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadSetVersion, useRollback, transaction, offlineCache); WorkloadInstallCommand.TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); @@ -192,11 +194,9 @@ private void UpdateWorkloadsWithInstallRecord( IEnumerable manifestsToUpdate, string workloadSetVersion, bool useRollback, + CliTransaction transaction, DirectoryPath? offlineCache = null) { - - var transaction = new CliTransaction(); - transaction.RollbackStarted = () => { Reporter.WriteLine(LocalizableStrings.RollingBackInstall); @@ -235,7 +235,6 @@ private void UpdateWorkloadsWithInstallRecord( rollback: () => { // InstallWorkloadManifest and InstallWorkloadPacks handle the transaction rollback - _workloadInstaller.RollBackWorkloadSetInstallation(); }); } diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 13151200e0a2..15bbb088529d 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -104,13 +104,11 @@ public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand }); } - public string InstallWorkloadSet(string path) + public string InstallWorkloadSet(CliTransaction transaction, string path) { return (path ?? string.Empty) + "installed.workloadset.json"; } - public void RollBackWorkloadSetInstallation() => throw new NotImplementedException(); - public void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null) => throw new NotImplementedException(); public void GarbageCollect(Func getResolverForWorkloadSet, DirectoryPath? offlineCache = null, bool cleanAllPacks = false) From 1c69272bf233be78c44de4c4723fdd9f7afef909 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:42:52 -0800 Subject: [PATCH 30/43] Address feedback --- .../commands/InstallingWorkloadCommand.cs | 5 ++ .../install/FileBasedInstaller.cs | 10 ++-- .../dotnet-workload/install/IInstaller.cs | 2 +- .../install/LocalizableStrings.resx | 3 ++ .../install/NetSdkMsiInstallerClient.cs | 21 ++++----- .../install/WorkloadInstallCommand.cs | 47 ++++++++++++++++--- .../install/WorkloadInstallCommandParser.cs | 1 + .../install/WorkloadManifestUpdater.cs | 15 ++---- .../install/xlf/LocalizableStrings.cs.xlf | 5 ++ .../install/xlf/LocalizableStrings.de.xlf | 5 ++ .../install/xlf/LocalizableStrings.es.xlf | 5 ++ .../install/xlf/LocalizableStrings.fr.xlf | 5 ++ .../install/xlf/LocalizableStrings.it.xlf | 5 ++ .../install/xlf/LocalizableStrings.ja.xlf | 5 ++ .../install/xlf/LocalizableStrings.ko.xlf | 5 ++ .../install/xlf/LocalizableStrings.pl.xlf | 5 ++ .../install/xlf/LocalizableStrings.pt-BR.xlf | 5 ++ .../install/xlf/LocalizableStrings.ru.xlf | 5 ++ .../install/xlf/LocalizableStrings.tr.xlf | 5 ++ .../xlf/LocalizableStrings.zh-Hans.xlf | 5 ++ .../xlf/LocalizableStrings.zh-Hant.xlf | 5 ++ .../list/WorkloadListCommand.cs | 2 +- .../update/LocalizableStrings.resx | 3 -- .../update/WorkloadUpdateCommand.cs | 4 +- .../update/WorkloadUpdateCommandParser.cs | 7 +-- .../update/xlf/LocalizableStrings.cs.xlf | 5 -- .../update/xlf/LocalizableStrings.de.xlf | 5 -- .../update/xlf/LocalizableStrings.es.xlf | 5 -- .../update/xlf/LocalizableStrings.fr.xlf | 5 -- .../update/xlf/LocalizableStrings.it.xlf | 5 -- .../update/xlf/LocalizableStrings.ja.xlf | 5 -- .../update/xlf/LocalizableStrings.ko.xlf | 5 -- .../update/xlf/LocalizableStrings.pl.xlf | 5 -- .../update/xlf/LocalizableStrings.pt-BR.xlf | 5 -- .../update/xlf/LocalizableStrings.ru.xlf | 5 -- .../update/xlf/LocalizableStrings.tr.xlf | 5 -- .../update/xlf/LocalizableStrings.zh-Hans.xlf | 5 -- .../update/xlf/LocalizableStrings.zh-Hant.xlf | 5 -- .../IWorkloadManifestProvider.cs | 2 + .../IWorkloadResolver.cs | 1 + .../SdkDirectoryWorkloadManifestProvider.cs | 7 ++- .../TempDirectoryWorkloadManifestProvider.cs | 1 + .../WorkloadResolver.cs | 3 ++ .../FakeManifestProvider.cs | 2 + .../MockManifestProvider.cs | 1 + .../MockPackWorkloadInstaller.cs | 4 +- .../MockWorkloadResolver.cs | 1 + 47 files changed, 157 insertions(+), 115 deletions(-) diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index 4d96cd870476..e7821228ea15 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -214,6 +214,11 @@ internal static class InstallingWorkloadCommandParser Hidden = true }; + public static readonly CliOption WorkloadSetVersionOption = new("--version") + { + Description = Strings.WorkloadSetVersionOptionDescription + }; + public static readonly CliOption PrintDownloadLinkOnlyOption = new("--print-download-link-only") { Description = Strings.PrintDownloadLinkOnlyDescription, diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 72ba8419fc91..ff6843c46dc5 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -85,21 +85,21 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds) return packs; } - public string InstallWorkloadSet(CliTransaction transaction, string path) + public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) { - var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(path, "version.txt")), "workloadset.json"); + var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(advertisingPackagePath, "packageVersion.txt")), "workloadset.json"); transaction.Run( action: context => { Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); - File.Copy(Path.Combine(path, "workloadset.json"), workloadSetPath, overwrite: true); + File.Copy(Path.Combine(advertisingPackagePath, "workloadset.json"), workloadSetPath, overwrite: true); }, rollback: () => { - if (path is not null) + if (advertisingPackagePath is not null) { - PathUtility.DeleteFileAndEmptyParents(path); + PathUtility.DeleteFileAndEmptyParents(advertisingPackagePath); } }); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index 94f2d4e61f07..e3dcd989c104 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -13,7 +13,7 @@ internal interface IInstaller : IWorkloadManifestInstaller { int ExitCode { get; } - string InstallWorkloadSet(CliTransaction transaction, string path); + string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath); void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx index b9cd5af6b5dd..2041190b6960 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx +++ b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx @@ -346,4 +346,7 @@ Manifest MSI not found in NuGet package {0} + + Update to the specified workload set. + diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 002e1b36c721..2155ce804e92 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -182,36 +182,33 @@ public void GarbageCollect(Func getResolverForWorkloa } } - public string InstallWorkloadSet(CliTransaction transaction, string path) + public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) { var pathToReturn = string.Empty; - var previousVersion = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, DotNetHome), "default.json")).WorkloadSetVersion; transaction.Run( action: context => { - pathToReturn = ModifyWorkloadSet(path, InstallAction.Install); + pathToReturn = ModifyWorkloadSet(advertisingPackagePath, InstallAction.Install); }, rollback: () => { - ModifyWorkloadSet(path, InstallAction.Uninstall); - File.WriteAllText(Path.Combine(path, "version.txt"), previousVersion); - ModifyWorkloadSet(path, InstallAction.Repair); + ModifyWorkloadSet(advertisingPackagePath, InstallAction.Uninstall); }); return pathToReturn; } - private string ModifyWorkloadSet(string path, InstallAction requestedAction) + private string ModifyWorkloadSet(string advertisingPackagePath, InstallAction requestedAction) { ReportPendingReboot(); // Resolve the package ID for the manifest payload package - var featureBand = Path.GetFileName(Path.GetDirectoryName(path)); - var version = File.ReadAllText(Path.Combine(path, "version.txt")); + var featureBand = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath)); + var packageVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, "packageVersion.txt")); string msiPackageId = GetManifestPackageId(new ManifestId("Microsoft.NET.Workloads"), new SdkFeatureBand(featureBand)).ToString(); - string msiPackageVersion = version; + string msiPackageVersion = packageVersion; - Log?.LogMessage($"Resolving Microsoft.NET.Workloads ({version}) to {msiPackageId} ({msiPackageVersion})."); + Log?.LogMessage($"Resolving Microsoft.NET.Workloads ({packageVersion}) to {msiPackageId} ({msiPackageVersion})."); // Retrieve the payload from the MSI package cache. MsiPayload msi = GetCachedMsiPayload(msiPackageId, msiPackageVersion, null); @@ -230,7 +227,7 @@ private string ModifyWorkloadSet(string path, InstallAction requestedAction) UpdateDependent(InstallRequestType.AddDependent, msi.Manifest.ProviderKeyName, _dependent); } - return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", version, "workloadset.json"); + return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", packageVersion, "workloadset.json"); } /// diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 7f6c8858d804..95b922c27e84 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -18,6 +18,7 @@ internal class WorkloadInstallCommand : InstallingWorkloadCommand { private readonly bool _skipManifestUpdate; private readonly IReadOnlyCollection _workloadIds; + private readonly string _workloadSetVersion; public WorkloadInstallCommand( ParseResult parseResult, @@ -43,6 +44,14 @@ public WorkloadInstallCommand( _workloadManifestUpdater = _workloadManifestUpdaterFromConstructor ?? new WorkloadManifestUpdater(Reporter, _workloadResolver, PackageDownloader, _userProfileDir, _workloadInstaller.GetWorkloadInstallationRecordRepository(), _workloadInstaller, _packageSourceLocation, displayManifestUpdates: Verbosity.IsDetailedOrDiagnostic()); + _workloadSetVersion = parseResult.GetValue(InstallingWorkloadCommandParser.WorkloadSetVersionOption); + if (string.IsNullOrWhiteSpace(_workloadSetVersion)) + { + // If the version of the workload set is currently pinned, treat it as if it were freshly pinned. + var installStateContents = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, _dotnetPath), "default.json")); + _workloadSetVersion = installStateContents.WorkloadSetVersion; + } + ValidateWorkloadIdsInput(); } @@ -107,11 +116,32 @@ public override int Execute() { try { - InstallWorkloads( - _workloadIds.Select(id => new WorkloadId(id)), - _skipManifestUpdate, - _includePreviews, - string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption)); + DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); + var workloadIds = _workloadIds.Select(id => new WorkloadId(id)); + if (string.IsNullOrWhiteSpace(_workloadSetVersion)) + { + InstallWorkloads( + workloadIds, + _skipManifestUpdate, + _includePreviews, + offlineCache); + } + else + { + // Ensure workload set mode is set to 'workloadset' + // Do not skip checking the mode first, as setting it triggers + // an admin authorization popup for MSI-based installs. + if (!GetInstallStateMode(_sdkFeatureBand, _dotnetPath)) + { + _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true); + } + + _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache); + var transaction = new CliTransaction(); + var workloadSetLocation = InstallWorkloadSet(transaction); + var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation); + InstallWorkloadsAndGarbageCollect(workloadSetLocation, transaction, workloadIds, manifestsToUpdate, offlineCache, false); + } } catch (Exception e) { @@ -180,6 +210,11 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); } + InstallWorkloadsAndGarbageCollect(workloadSetLocation, transaction, workloadIds, manifestsToUpdate, offlineCache, useRollback); + } + + private void InstallWorkloadsAndGarbageCollect(string workloadSetLocation, CliTransaction transaction, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback) + { var workloadSetVersion = workloadSetLocation is null ? null : Path.GetDirectoryName(workloadSetLocation); InstallWorkloadsWithInstallRecord(transaction, _workloadInstaller, workloadIds, workloadSetVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); @@ -244,7 +279,7 @@ private void InstallWorkloadsWithInstallRecord( installer.SaveInstallStateManifestVersions(sdkFeatureBand, GetInstallStateContents(manifestsToUpdate)); } - installer.AdjustWorkloadSetInInstallState(sdkFeatureBand, workloadSetVersion); + installer.AdjustWorkloadSetInInstallState(sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : workloadSetVersion); }, rollback: () => { diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommandParser.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommandParser.cs index a7bbd03af121..f0323853dd79 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommandParser.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommandParser.cs @@ -61,6 +61,7 @@ internal static void AddWorkloadInstallCommandOptions(CliCommand command) command.AddWorkloadCommandNuGetRestoreActionConfigOptions(); command.Options.Add(CommonOptions.VerbosityOption); command.Options.Add(SkipSignCheckOption); + command.Options.Add(InstallingWorkloadCommandParser.WorkloadSetVersionOption); } } } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 09c2b0b3d069..c444884a3acc 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.EnvironmentAbstractions; using Microsoft.NET.Sdk.WorkloadManifestReader; using NuGet.Common; +using NuGet.Packaging; using NuGet.Versioning; namespace Microsoft.DotNet.Workloads.Workload.Install @@ -306,17 +307,9 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP if (id.Equals("Microsoft.NET.Workloads")) { - var fileName = Path.GetFileNameWithoutExtension(packagePath); - var featureBand = _sdkFeatureBand.ToString(); - - // The format is Microsoft.NET.Workloads.featureBand.version, so this skips past the band and the '.' afterwards to get the version - var version = fileName.Substring(fileName.IndexOf(featureBand) + featureBand.Length + 1); - if (version.StartsWith("msi", StringComparison.OrdinalIgnoreCase)) - { - // version starts with msi.. Remove that part. - version = version.Substring(version.IndexOf('.', 5) + 1); - } - File.WriteAllText(Path.Combine(adManifestPath, "version.txt"), version); + using PackageArchiveReader packageReader = new(packagePath); + var downloadedPackageVersion = packageReader.NuspecReader.GetVersion(); + File.WriteAllText(Path.Combine(adManifestPath, "packageVersion.txt"), downloadedPackageVersion.ToString()); } if (_displayManifestUpdates) 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 c3ed03c91b61..e158aa9774b3 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 @@ -367,6 +367,11 @@ Control whether future workload operations should use workload sets or loose manifests. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. Jsou k dispozici aktualizace úloh. Pokud chcete získat další informace, spusťte `dotnet workload list`. 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 f412e4e21584..bd5321571227 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 @@ -367,6 +367,11 @@ Hiermit wird gesteuert, ob zukünftige Workloadvorgänge Workloadsätze oder lose Manifeste verwenden sollen. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. Es sind Workloadupdates verfügbar. Um weitere Informationen zu erhalten, führen Sie `dotnet workload list` aus. 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 661379832a29..367b74d2930c 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 @@ -367,6 +367,11 @@ Controle si las operaciones de carga de trabajo futuras deben usar conjuntos de cargas de trabajo o manifiestos flexibles. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. Hay actualizaciones de carga de trabajo disponibles. Ejecute "dotnet workload list" para obtener más información. 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 51bcf45d03b5..91519b98afc8 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 @@ -367,6 +367,11 @@ Control whether future workload operations should use workload sets or loose manifests. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. Des mises à jour de la charge de travail sont disponibles. Exécutez `dotnet workload list` pour plus d’informations. 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 a4b0ff121dd0..15c09ffb0a8f 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 @@ -367,6 +367,11 @@ Control whether future workload operations should use workload sets or loose manifests. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. Sono disponibili aggiornamenti del carico di lavoro. Per altre informazioni, eseguire `dotnet workload list`. 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 93aa4172e61b..b162b1018a6f 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 @@ -367,6 +367,11 @@ 将来のワークロード操作でワークロード セットを使用するか、ルーズ マニフェストを使用するかを制御します。 + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. ワークロードの更新が利用可能です。詳細については、`dotnet workload list` を実行してください。 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 dcfa49035630..e85b15848465 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 @@ -367,6 +367,11 @@ 향후 워크로드 작업에서 워크로드 집합을 사용할지, 매니페스트를 완화할지를 제어합니다. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. 워크로드 업데이트를 사용할 수 있습니다. 자세한 내용을 보려면 `dotnet workload list`을 실행하세요. 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 6325acdc4b93..be5693957dc6 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 @@ -367,6 +367,11 @@ Określ, czy przyszłe operacje związane z obciążeniami powinny wykorzystywać zestawy obciążeń, czy luźne manifesty. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. Dostępne są aktualizacje obciążenia. Uruchom polecenie `dotnet workload list`, aby uzyskać więcej informacji. 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 8c03cca867d1..7c3fe86f5dde 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 @@ -367,6 +367,11 @@ Controle se as operações de carga de trabalho futuras devem usar conjuntos de carga de trabalho ou manifestos flexíveis. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. As atualizações de carga de trabalho estão disponíveis. Execute `dotnet workload list` para obter mais informações. 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 ae04b48008d0..124714a87ccf 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 @@ -367,6 +367,11 @@ Control whether future workload operations should use workload sets or loose manifests. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. Доступны обновления рабочей нагрузки. Для получения дополнительных сведений запустите `dotnet workload list`. 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 3691d8eb871c..225ea92db262 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 @@ -367,6 +367,11 @@ Gelecekteki iş yükü işlemlerinin iş yükü kümelerini mi yoksa gevşek bildirimleri mi kullanması gerektiğini kontrol edin. + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. İş yükü güncelleştirmeleri var. Daha fazla bilgi için `dotnet workload list` çalıştırın. 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 60dce47d2925..fc2112a1759c 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 @@ -367,6 +367,11 @@ 控制未来的工作负载操作应该使用工作负载集还是松散清单。 + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. 有可用的工作负载更新。有关详细信息,请运行 `dotnet workload list`。 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 4921d99e1aab..1f65afb8847f 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 @@ -367,6 +367,11 @@ 控制未來的工作負載作業應該使用工作負載集合還是鬆散資訊清單。 + + Update to the specified workload set. + Update to the specified workload set. + + Workload updates are available. Run `dotnet workload list` for more information. 有可用的工作負載更新。如需詳細資訊,請執行 `dotnet workload list`。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs index b58d4c15a2b3..dd91aad3ad75 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs @@ -97,7 +97,7 @@ public override int Execute() if (installState.UseWorkloadSets == true) { Reporter.WriteLine(); - Reporter.WriteLine(string.Format(LocalizableStrings.WorkloadSetVersion, installState.WorkloadSetVersion ?? "unknown")); + Reporter.WriteLine(string.Format(LocalizableStrings.WorkloadSetVersion, _workloadListHelper.WorkloadResolver.GetWorkloadVersion() ?? "unknown")); } Reporter.WriteLine(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx index 3742cfc702ea..77709f82d798 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx +++ b/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx @@ -144,9 +144,6 @@ Include workloads installed with earlier SDK versions in update. - - Update to the specified workload set. - No workloads installed for this feature band. To update workloads installed with earlier SDK versions, include the --from-previous-sdk option. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 3ce712c3f815..dfa738afd662 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -35,7 +35,7 @@ public WorkloadUpdateCommand( tempDirPath: tempDirPath) { - _workloadSetVersion = parseResult.GetValue(WorkloadUpdateCommandParser.WorkloadSetVersionOption); + _workloadSetVersion = parseResult.GetValue(InstallingWorkloadCommandParser.WorkloadSetVersionOption); _fromPreviousSdk = parseResult.GetValue(WorkloadUpdateCommandParser.FromPreviousSdkOption); _adManifestOnlyOption = parseResult.GetValue(WorkloadUpdateCommandParser.AdManifestOnlyOption); _printRollbackDefinitionOnly = parseResult.GetValue(WorkloadUpdateCommandParser.PrintRollbackOption); @@ -230,7 +230,7 @@ private void UpdateWorkloadsWithInstallRecord( _workloadInstaller.RemoveManifestsFromInstallState(sdkFeatureBand); } - _workloadInstaller.AdjustWorkloadSetInInstallState(sdkFeatureBand, workloadSetVersion); + _workloadInstaller.AdjustWorkloadSetInInstallState(sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : workloadSetVersion); }, rollback: () => { diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs index 365578935567..787189013bb4 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs @@ -12,11 +12,6 @@ internal static class WorkloadUpdateCommandParser { public static readonly CliOption TempDirOption = WorkloadInstallCommandParser.TempDirOption; - public static readonly CliOption WorkloadSetVersionOption = new("--version") - { - Description = LocalizableStrings.WorkloadSetVersionOptionDescription - }; - public static readonly CliOption FromPreviousSdkOption = new("--from-previous-sdk") { Description = LocalizableStrings.FromPreviousSdkOptionDescription @@ -48,7 +43,7 @@ private static CliCommand ConstructCommand() command.Options.Add(TempDirOption); command.Options.Add(FromPreviousSdkOption); command.Options.Add(AdManifestOnlyOption); - command.Options.Add(WorkloadSetVersionOption); + command.Options.Add(InstallingWorkloadCommandParser.WorkloadSetVersionOption); command.AddWorkloadCommandNuGetRestoreActionConfigOptions(); command.Options.Add(CommonOptions.VerbosityOption); command.Options.Add(PrintRollbackOption); diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf index 8bf8996e1e56..9549325a870b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf @@ -57,11 +57,6 @@ Invalid argument "{0}" to the --mode argument for dotnet workload update. Only supported modes are "workloadset", "loosemanifest", and "auto". - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. Manifesty reklamy se úspěšně aktualizovaly. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf index 3e8dcf4c5220..7fe3755912f5 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf @@ -57,11 +57,6 @@ Ungültiges Argument "{0}" zum Argument --mode für das Dotnet Workload-Update. Es werden nur die Modi "workloadset", "loosemanifest" und "auto" unterstützt. - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. Werbemanifeste wurden erfolgreich aktualisiert. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf index b72e964ca5f8..61eacfcb2be0 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf @@ -57,11 +57,6 @@ Argumento "{0}" no válido para el argumento --mode para la actualización de la carga de trabajo de dotnet. Solo los modos admitidos son "workloadset", "loosemanifest" y "auto". - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. Los manifiestos de publicidad se han actualizado correctamente. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf index 88662c3487f5..617881842505 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf @@ -57,11 +57,6 @@ Invalid argument "{0}" to the --mode argument for dotnet workload update. Only supported modes are "workloadset", "loosemanifest", and "auto". - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. Les manifestes de publicité ont été mis à jour. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf index 40b44113feda..3e242f66ba13 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf @@ -57,11 +57,6 @@ Invalid argument "{0}" to the --mode argument for dotnet workload update. Only supported modes are "workloadset", "loosemanifest", and "auto". - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. I manifesti pubblicitari sono stati aggiornati. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf index 058657142fcd..a3555167d604 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf @@ -57,11 +57,6 @@ .NET ワークロード更新の --mode 引数に対する引数 "{0}" が無効です。サポートされているモードは、"workloadset"、"loosemanifest"、および "auto" のみです。 - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. 広告マニフェストを正常に更新しました。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf index 0d1ec7111278..1f9d499812c4 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf @@ -57,11 +57,6 @@ dotnet 워크로드 업데이트의 --mode 인수에 대한 "{0}" 인수가 잘못되었습니다. "workloadset", "loosemanifest", "auto" 모드만 지원됩니다. - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. 알림 매니페스트를 업데이트했습니다. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf index 7c768a6f1a11..222d233a4c10 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf @@ -57,11 +57,6 @@ Nieprawidłowy argument „{0}” argumentu --mode dla aktualizacji obciążenia dotnet. Obsługiwane tryby to „workloadset”, „loosemanifest” i „auto”. - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. Pomyślnie zaktualizowano manifesty reklam. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf index 34d3d5747d60..c5db7d56ba3e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf @@ -57,11 +57,6 @@ Argumento "{0}" inválido para o argumento --mode para atualização de carga de trabalho dotnet. Os únicos modos com suporte são "workloadset", "loosemanifest" e "auto". - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. Manifestos de anúncio atualizados com êxito. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf index cef528bd2c11..2ff37fb49329 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf @@ -57,11 +57,6 @@ Invalid argument "{0}" to the --mode argument for dotnet workload update. Only supported modes are "workloadset", "loosemanifest", and "auto". - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. Манифесты рекламы успешно обновлены. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf index e5e22d06a42e..6c7f77da9566 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf @@ -57,11 +57,6 @@ Dotnet iş yükü güncelleştirmesi için --mod bağımsız değişkeninde geçersiz "{0}" bağımsız değişkeni. Yalnızca "workloadset", "loosemanifest" ve "auto" modları desteklenir. - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. Reklam bildirimleri başarıyla güncelleştirildi. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf index 12bb960578d9..3c981c1c23c4 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf @@ -57,11 +57,6 @@ dotnet 工作负载更新的 --mode 参数的参数“{0}”无效。仅支持“workloadset”、“loosemanifest”和“auto”模式。 - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. 成功更新广告清单。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf index a457e2327a96..20dab178f25e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf @@ -57,11 +57,6 @@ dotnet 工作負載更新的 --mode 引數之引數 "{0}" 無效。僅支援 "workloadset"、"loosemanifest" 和 "auto" 模式。 - - Update to the specified workload set. - Update to the specified workload set. - - Successfully updated advertising manifests. 已成功更新廣告資訊清單。 diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs index 28b2862b979b..1ec61dea611e 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs @@ -13,6 +13,8 @@ public interface IWorkloadManifestProvider string GetSdkFeatureBand(); + string? GetWorkloadVersion(); + Dictionary GetAvailableWorkloadSets(); } } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadResolver.cs index 283aaffd387f..05a86f60d3b5 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadResolver.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadResolver.cs @@ -19,6 +19,7 @@ public interface IWorkloadResolver string GetManifestVersion(string manifestId); IEnumerable GetInstalledManifests(); string GetSdkFeatureBand(); + string? GetWorkloadVersion(); IEnumerable GetUpdatedWorkloads(WorkloadResolver advertisingManifestResolver, IEnumerable installedWorkloads); WorkloadManifest GetManifestFromWorkload(WorkloadId workloadId); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index 32e76bbf3735..c545f0ea6b80 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -147,13 +147,18 @@ internal SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVers } } - public string GetWorkloadVersion() + public string? GetWorkloadVersion() { if (_workloadSet?.Version is not null) { return _workloadSet?.Version!; } + if (InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkVersionBand, _sdkRootPath), "default.json")).UseWorkloadSets == true) + { + return null; + } + using (SHA256 sha256Hash = SHA256.Create()) { byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(string.Join(";", diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs index 950d99753bd7..dbff0f3c2a43 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs @@ -52,6 +52,7 @@ public IEnumerable GetManifestDirectories() } public string GetSdkFeatureBand() => _sdkVersionBand; + public string? GetWorkloadVersion() => _sdkVersionBand.ToString() + ".2"; public Dictionary GetAvailableWorkloadSets() => new(); } } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs index 5e5e28cab079..c1edd700d042 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs @@ -107,6 +107,8 @@ public void RefreshWorkloadManifests() ComposeWorkloadManifests(); } + public string? GetWorkloadVersion() => _manifestProvider.GetWorkloadVersion(); + private void LoadManifestsFromProvider(IWorkloadManifestProvider manifestProvider) { foreach (var readableManifest in manifestProvider.GetManifests()) @@ -738,6 +740,7 @@ public EmptyWorkloadManifestProvider(string sdkFeatureBand) public Dictionary GetAvailableWorkloadSets() => new(); public IEnumerable GetManifests() => Enumerable.Empty(); public string GetSdkFeatureBand() => _sdkFeatureBand; + public string? GetWorkloadVersion() => _sdkFeatureBand.ToString() + ".2"; } } diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs index 8f53b3051420..7699f420c12b 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs @@ -38,6 +38,7 @@ public IEnumerable GetManifests() public string GetSdkFeatureBand() => "8.0.100"; public Dictionary GetAvailableWorkloadSets() => throw new NotImplementedException(); + public string? GetWorkloadVersion() => "8.0.100.2"; } internal class InMemoryFakeManifestProvider : IWorkloadManifestProvider, IEnumerable<(string id, string content)> @@ -62,5 +63,6 @@ public IEnumerable GetManifests() IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); public string GetSdkFeatureBand() => "8.0.100"; public Dictionary GetAvailableWorkloadSets() => throw new NotImplementedException(); + public string? GetWorkloadVersion() => "8.0.100.2"; } } diff --git a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs index fb94af52d370..7390c6d5c87d 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs @@ -46,5 +46,6 @@ public IEnumerable GetManifests() } public string GetSdkFeatureBand() => SdkFeatureBand.ToString(); + public string GetWorkloadVersion() => SdkFeatureBand.ToString() + ".2"; } } diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 15bbb088529d..e82789ca3851 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -104,9 +104,9 @@ public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand }); } - public string InstallWorkloadSet(CliTransaction transaction, string path) + public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) { - return (path ?? string.Empty) + "installed.workloadset.json"; + return (advertisingPackagePath ?? string.Empty) + "installed.workloadset.json"; } public void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null) => throw new NotImplementedException(); diff --git a/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs b/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs index 8063b14fb986..5a9bdd9cb706 100644 --- a/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs +++ b/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs @@ -28,6 +28,7 @@ public void RefreshWorkloadManifests() { } public IEnumerable GetInstalledManifests() => throw new NotImplementedException(); public IWorkloadResolver CreateOverlayResolver(IWorkloadManifestProvider overlayManifestProvider) => throw new NotImplementedException(); public string GetSdkFeatureBand() => "12.0.400"; + public string GetWorkloadVersion() => "12.0.400.2"; public IEnumerable GetUpdatedWorkloads(WorkloadResolver advertisingManifestResolver, IEnumerable installedWorkloads) => throw new NotImplementedException(); WorkloadResolver IWorkloadResolver.CreateOverlayResolver(IWorkloadManifestProvider overlayManifestProvider) => throw new NotImplementedException(); WorkloadManifest IWorkloadResolver.GetManifestFromWorkload(WorkloadId workloadId) => throw new NotImplementedException(); From cb06526f0d4b3ae0626c1549f4d7786a5a860724 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 1 Mar 2024 10:26:53 -0800 Subject: [PATCH 31/43] Convert to and from package version --- .../install/NetSdkMsiInstallerClient.cs | 4 +++- .../install/WorkloadManifestUpdater.cs | 20 +++++++++++++++++-- .../SdkDirectoryWorkloadManifestProvider.cs | 12 ++++++----- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 2155ce804e92..861d752892b9 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Linq; using System.Runtime.Versioning; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.NuGetPackageDownloader; @@ -182,6 +183,7 @@ public void GarbageCollect(Func getResolverForWorkloa } } + // advertisingPackagePath is the path to the workload set MSI nupkg in the advertising package. public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) { var pathToReturn = string.Empty; @@ -206,7 +208,7 @@ private string ModifyWorkloadSet(string advertisingPackagePath, InstallAction re var featureBand = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath)); var packageVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, "packageVersion.txt")); string msiPackageId = GetManifestPackageId(new ManifestId("Microsoft.NET.Workloads"), new SdkFeatureBand(featureBand)).ToString(); - string msiPackageVersion = packageVersion; + string msiPackageVersion = WorkloadManifestUpdater.WorkloadSetVersionToWorkloadSetPackageVersion(packageVersion); Log?.LogMessage($"Resolving Microsoft.NET.Workloads ({packageVersion}) to {msiPackageId} ({msiPackageVersion})."); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index c444884a3acc..5ae869e4b7e9 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -90,7 +90,8 @@ public async Task UpdateAdvertisingManifestsAsync(bool includePreviews, bool use public async void DownloadWorkloadSet(string version, DirectoryPath? offlineCache = null) { - await UpdateManifestWithVersionAsync("Microsoft.NET.Workloads", includePreviews: true, _sdkFeatureBand, new NuGetVersion(version), offlineCache); + var correctedVersion = WorkloadSetVersionToWorkloadSetPackageVersion(version); + await UpdateManifestWithVersionAsync("Microsoft.NET.Workloads", includePreviews: true, _sdkFeatureBand, new NuGetVersion(correctedVersion), offlineCache); } public async static Task BackgroundUpdateAdvertisingManifestsAsync(string userProfileDir) @@ -147,6 +148,18 @@ public void DeleteUpdatableWorkloadsFile() } } + public static string WorkloadSetVersionToWorkloadSetPackageVersion(string setVersion) + { + var splitVersion = setVersion.Split('.'); + return string.Join('.', splitVersion.Skip(2).Prepend(splitVersion[0])); + } + + public static string WorkloadSetPackageVersionToWorkloadSetVersion(string packageVersion) + { + var splitVersion = packageVersion.Split('.'); + return string.Join('.', splitVersion.Skip(1).Prepend("0").Prepend(splitVersion[0])); + } + public static void AdvertiseWorkloadUpdates() { try @@ -307,9 +320,12 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP if (id.Equals("Microsoft.NET.Workloads")) { + // Create version file later used as part of installing the workload set in the file-based installer and in the msi-based installer using PackageArchiveReader packageReader = new(packagePath); var downloadedPackageVersion = packageReader.NuspecReader.GetVersion(); - File.WriteAllText(Path.Combine(adManifestPath, "packageVersion.txt"), downloadedPackageVersion.ToString()); + var correctedPackageVersion = WorkloadSetPackageVersionToWorkloadSetVersion(downloadedPackageVersion.ToString()); // $"{downloadedPackageVersion.Major}.0.{downloadedPackageVersion.Minor}.{downloadedPackageVersion.Patch}" + // + (string.IsNullOrWhiteSpace(downloadedPackageVersion.Release) ? string.Empty : '-' + downloadedPackageVersion.Release); + File.WriteAllText(Path.Combine(adManifestPath, "packageVersion.txt"), correctedPackageVersion); } if (_displayManifestUpdates) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index c545f0ea6b80..8e1b10f08e84 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -421,13 +421,15 @@ public Dictionary GetAvailableWorkloadSets() workloadSet = WorkloadSet.FromJson(File.ReadAllText(jsonFile), _sdkVersionBand); } - if (workloadSet != null) + var baselineWorkloadSet = Path.Combine(workloadSetDirectory, "baseline.workloadset.json"); + if (File.Exists(baselineWorkloadSet)) { - if (File.Exists(Path.Combine(workloadSetDirectory, "baseline.workloadset.json"))) - { - workloadSet.IsBaselineWorkloadSet = true; - } + workloadSet = WorkloadSet.FromJson(File.ReadAllText(baselineWorkloadSet), _sdkVersionBand); + workloadSet.IsBaselineWorkloadSet = true; + } + if (workloadSet != null) + { workloadSet.Version = Path.GetFileName(workloadSetDirectory); availableWorkloadSets[workloadSet.Version] = workloadSet; } From f21016db6a70e07d982a1a305c8c996e3352b1c6 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 1 Mar 2024 11:59:19 -0800 Subject: [PATCH 32/43] Update version conversion logic To align with joeloff's version (https://github.com/dotnet/arcade/pull/14526) --- .../install/WorkloadManifestUpdater.cs | 16 ++++++++++------ .../SdkFeatureBand.cs | 3 +++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 5ae869e4b7e9..e1f7b1f1f445 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -150,14 +150,18 @@ public void DeleteUpdatableWorkloadsFile() public static string WorkloadSetVersionToWorkloadSetPackageVersion(string setVersion) { - var splitVersion = setVersion.Split('.'); - return string.Join('.', splitVersion.Skip(2).Prepend(splitVersion[0])); + var nugetVersion = new NuGetVersion(setVersion); + var patch = nugetVersion.Revision; + var release = string.IsNullOrWhiteSpace(nugetVersion.Release) ? string.Empty : $"-{nugetVersion.Release}"; + return $"{nugetVersion.Major}.{nugetVersion.Patch}.{patch}{release}"; } - public static string WorkloadSetPackageVersionToWorkloadSetVersion(string packageVersion) + public static string WorkloadSetPackageVersionToWorkloadSetVersion(SdkFeatureBand sdkFeatureBand, string packageVersion) { - var splitVersion = packageVersion.Split('.'); - return string.Join('.', splitVersion.Skip(1).Prepend("0").Prepend(splitVersion[0])); + var nugetVersion = new NuGetVersion(packageVersion); + var patch = nugetVersion.Patch > 0 ? $".{nugetVersion.Patch}" : string.Empty; + var release = string.IsNullOrWhiteSpace(nugetVersion.Release) ? string.Empty : $"-{nugetVersion.Release}"; + return $"{sdkFeatureBand.Major}.{sdkFeatureBand.Minor}.{nugetVersion.Minor}{patch}{release}"; } public static void AdvertiseWorkloadUpdates() @@ -323,7 +327,7 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP // Create version file later used as part of installing the workload set in the file-based installer and in the msi-based installer using PackageArchiveReader packageReader = new(packagePath); var downloadedPackageVersion = packageReader.NuspecReader.GetVersion(); - var correctedPackageVersion = WorkloadSetPackageVersionToWorkloadSetVersion(downloadedPackageVersion.ToString()); // $"{downloadedPackageVersion.Major}.0.{downloadedPackageVersion.Minor}.{downloadedPackageVersion.Patch}" + var correctedPackageVersion = WorkloadSetPackageVersionToWorkloadSetVersion(_sdkFeatureBand, downloadedPackageVersion.ToString()); // $"{downloadedPackageVersion.Major}.0.{downloadedPackageVersion.Minor}.{downloadedPackageVersion.Patch}" // + (string.IsNullOrWhiteSpace(downloadedPackageVersion.Release) ? string.Empty : '-' + downloadedPackageVersion.Release); File.WriteAllText(Path.Combine(adManifestPath, "packageVersion.txt"), correctedPackageVersion); } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkFeatureBand.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkFeatureBand.cs index ac23e482e83d..af88ae8b931e 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkFeatureBand.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkFeatureBand.cs @@ -30,6 +30,9 @@ public SdkFeatureBand(ReleaseVersion version) } } + public int Major => _featureBand.Major; + public int Minor => _featureBand.Minor; + public bool Equals(SdkFeatureBand other) { return _featureBand.Equals(other._featureBand); From 4155948483e58d2ccea038417e3b1fbf21e4c5b8 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 1 Mar 2024 12:44:09 -0800 Subject: [PATCH 33/43] Add workload set update message --- .../install/LocalizableStrings.resx | 6 ++++++ .../install/WorkloadManifestUpdater.cs | 17 +++++++++++++++-- .../install/xlf/LocalizableStrings.cs.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.de.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.es.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.fr.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.it.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.ja.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.ko.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.pl.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.pt-BR.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.ru.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.tr.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.zh-Hans.xlf | 10 ++++++++++ .../install/xlf/LocalizableStrings.zh-Hant.xlf | 10 ++++++++++ 15 files changed, 151 insertions(+), 2 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx index 2041190b6960..0187de5fc260 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx +++ b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx @@ -349,4 +349,10 @@ Update to the specified workload set. + + Installing new workload set with version {0}. + + + Updating workload set version from {0} to {1}. + diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index e1f7b1f1f445..9b8c4b3b1282 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -94,6 +94,19 @@ public async void DownloadWorkloadSet(string version, DirectoryPath? offlineCach await UpdateManifestWithVersionAsync("Microsoft.NET.Workloads", includePreviews: true, _sdkFeatureBand, new NuGetVersion(correctedVersion), offlineCache); } + private void PrintWorkloadSetTransition(string newVersion) + { + var currentVersion = _workloadResolver.GetWorkloadVersion(); + if (currentVersion == null) + { + _reporter.WriteLine(string.Format(LocalizableStrings.NewWorkloadSet, newVersion)); + } + else + { + _reporter.WriteLine(string.Format(LocalizableStrings.WorkloadSetUpgrade, currentVersion, newVersion)); + } + } + public async static Task BackgroundUpdateAdvertisingManifestsAsync(string userProfileDir) { try @@ -327,9 +340,9 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP // Create version file later used as part of installing the workload set in the file-based installer and in the msi-based installer using PackageArchiveReader packageReader = new(packagePath); var downloadedPackageVersion = packageReader.NuspecReader.GetVersion(); - var correctedPackageVersion = WorkloadSetPackageVersionToWorkloadSetVersion(_sdkFeatureBand, downloadedPackageVersion.ToString()); // $"{downloadedPackageVersion.Major}.0.{downloadedPackageVersion.Minor}.{downloadedPackageVersion.Patch}" - // + (string.IsNullOrWhiteSpace(downloadedPackageVersion.Release) ? string.Empty : '-' + downloadedPackageVersion.Release); + var correctedPackageVersion = WorkloadSetPackageVersionToWorkloadSetVersion(_sdkFeatureBand, downloadedPackageVersion.ToString()); File.WriteAllText(Path.Combine(adManifestPath, "packageVersion.txt"), correctedPackageVersion); + PrintWorkloadSetTransition(correctedPackageVersion); } if (_displayManifestUpdates) 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 e158aa9774b3..56aea7d5e8ad 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 @@ -182,6 +182,11 @@ Odebírání {0}. + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). Nepovedlo se navázat vztah důvěryhodnosti s nadřazeným procesem ({0}). @@ -367,6 +372,11 @@ Control whether future workload operations should use workload sets or loose manifests. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 bd5321571227..9dad9682c1a1 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 @@ -182,6 +182,11 @@ {0} wird entfernt + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). Fehler beim Einrichten einer Vertrauensbeziehung mit dem übergeordneten Prozess ({0}). @@ -367,6 +372,11 @@ Hiermit wird gesteuert, ob zukünftige Workloadvorgänge Workloadsätze oder lose Manifeste verwenden sollen. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 367b74d2930c..99c31cd2bf2b 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 @@ -182,6 +182,11 @@ Quitando {0} + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). No se ha podido establecer una relación de confianza con el proceso primario ({0}). @@ -367,6 +372,11 @@ Controle si las operaciones de carga de trabajo futuras deben usar conjuntos de cargas de trabajo o manifiestos flexibles. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 91519b98afc8..78b638fffba8 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 @@ -182,6 +182,11 @@ Suppression de {0} + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). Impossible d’établir une relation de confiance avec le processus parent ({0}). @@ -367,6 +372,11 @@ Control whether future workload operations should use workload sets or loose manifests. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 15c09ffb0a8f..7ece409b918c 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 @@ -182,6 +182,11 @@ Rimozione di {0} + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). Impossibile stabilire una relazione di attendibilità con il processo padre ({0}). @@ -367,6 +372,11 @@ Control whether future workload operations should use workload sets or loose manifests. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 b162b1018a6f..9bb6af02d1bb 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 @@ -182,6 +182,11 @@ {0} を削除しています + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). 親プロセス ({0}) との信頼関係を確立できませんでした。 @@ -367,6 +372,11 @@ 将来のワークロード操作でワークロード セットを使用するか、ルーズ マニフェストを使用するかを制御します。 + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 e85b15848465..da4fde058721 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 @@ -182,6 +182,11 @@ {0} 제거 중 + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). 부모 프로세스({0})와 신뢰 관계를 설정하지 못했습니다. @@ -367,6 +372,11 @@ 향후 워크로드 작업에서 워크로드 집합을 사용할지, 매니페스트를 완화할지를 제어합니다. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 be5693957dc6..4b191835ea4f 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 @@ -182,6 +182,11 @@ Usuwanie {0} + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). Nie można ustanowić relacji zaufania z procesem nadrzędnym ({0}). @@ -367,6 +372,11 @@ Określ, czy przyszłe operacje związane z obciążeniami powinny wykorzystywać zestawy obciążeń, czy luźne manifesty. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 7c3fe86f5dde..34119f7cd3c7 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 @@ -182,6 +182,11 @@ Removendo {0} + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). Falha ao estabelecer uma relação de confiança com o processo pai ({0}). @@ -367,6 +372,11 @@ Controle se as operações de carga de trabalho futuras devem usar conjuntos de carga de trabalho ou manifestos flexíveis. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 124714a87ccf..d97ea3f87962 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 @@ -182,6 +182,11 @@ Идет удаление {0} + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). Не удалось установить отношение доверия с родительским процессом ({0}). @@ -367,6 +372,11 @@ Control whether future workload operations should use workload sets or loose manifests. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 225ea92db262..1880d6c5db18 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 @@ -182,6 +182,11 @@ {0} kaldırılıyor + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). Üst işlemle ({0}) bir güven ilişkisi kurulamadı. @@ -367,6 +372,11 @@ Gelecekteki iş yükü işlemlerinin iş yükü kümelerini mi yoksa gevşek bildirimleri mi kullanması gerektiğini kontrol edin. + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 fc2112a1759c..df1eb9e9867b 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 @@ -182,6 +182,11 @@ 正在删除 {0} + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). 未能建立与父进程({0})之间的信任关系。 @@ -367,6 +372,11 @@ 控制未来的工作负载操作应该使用工作负载集还是松散清单。 + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. 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 1f65afb8847f..6700d644f856 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 @@ -182,6 +182,11 @@ 正在移除 {0} + + Installing new workload set with version {0}. + Installing new workload set with version {0}. + + Failed to establish a trust relationship with parent process ({0}). 無法與父處理序 ({0}) 建立信任關係。 @@ -367,6 +372,11 @@ 控制未來的工作負載作業應該使用工作負載集合還是鬆散資訊清單。 + + Updating workload set version from {0} to {1}. + Updating workload set version from {0} to {1}. + + Update to the specified workload set. Update to the specified workload set. From 8c8ce54f71d470b267cb57ebad64ef97e892e526 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:51:41 -0800 Subject: [PATCH 34/43] Delete duplicate method (?) --- .../dotnet/commands/dotnet-workload/InstallStateContents.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs index afaabf155702..94712d4284ed 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs @@ -36,11 +36,6 @@ public static InstallStateContents FromPath(string path) return File.Exists(path) ? FromString(File.ReadAllText(path)) : new InstallStateContents(); } - public static InstallStateContents FromPath(string path) - { - return File.Exists(path) ? FromString(File.ReadAllText(path)) : new InstallStateContents(); - } - public override string ToString() { return JsonSerializer.Serialize(this, s_options); From 5bbcb0d3c6c2309177a3a2a76d96facf022c484c Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 1 Mar 2024 14:05:15 -0800 Subject: [PATCH 35/43] Fix method signature (and this time, build to make sure that's it) --- .../dotnet-workload/install/NetSdkMsiInstallerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 93679d62558d..c3cfb66177f5 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -292,7 +292,7 @@ private string ModifyWorkloadSet(string advertisingPackagePath, InstallAction re VerifyPackage(msi); DetectState state = DetectPackage(msi.ProductCode, out Version installedVersion); - InstallAction plannedAction = PlanPackage(msi, state, requestedAction, installedVersion, out IEnumerable relatedProducts); + InstallAction plannedAction = PlanPackage(msi, state, requestedAction, installedVersion); if (plannedAction != InstallAction.None) { From 5c09c2c1f12ebde9bd8a74bebabb24b395aa0081 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 1 Mar 2024 15:54:29 -0800 Subject: [PATCH 36/43] Fix test Version is not written into the install state by default anymore, so this writes it into a temporary "versionFile" (analogous to packageVersion.txt) and verifies that it's updated to the right workload set version. --- .../MockPackWorkloadInstaller.cs | 5 ++++- .../GivenDotnetWorkloadUpdate.cs | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index e82789ca3851..29573110f7e3 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -106,7 +106,10 @@ public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) { - return (advertisingPackagePath ?? string.Empty) + "installed.workloadset.json"; + var version = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath ?? string.Empty)); + Directory.CreateDirectory(advertisingPackagePath); + File.WriteAllText(Path.Combine(advertisingPackagePath, "packageVersion.txt"), version); + return Path.Combine(Path.GetDirectoryName(advertisingPackagePath ?? string.Empty), "installed.workloadset.json"); } public void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null) => throw new NotImplementedException(); diff --git a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs index 3caeb9a6df23..175008cc6866 100644 --- a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs +++ b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs @@ -223,16 +223,18 @@ public void UpdateViaWorkloadSet(bool upgrade) var installStatePath = Path.Combine(Path.GetTempPath(), "dotnetTestPath", "metadata", "workloads", versionNumber, "InstallState", "default.json"); var contents = new InstallStateContents(); contents.UseWorkloadSets = true; + var versionFile = "userProfileDir\\sdk-advertising\\8.0.0\\microsoft.net.workloads\\packageVersion.txt"; try { Directory.CreateDirectory(Path.GetDirectoryName(installStatePath)); File.WriteAllText(installStatePath, contents.ToString()); updateCommand.Execute(); - var newContents = InstallStateContents.FromPath(installStatePath); - newContents.WorkloadSetVersion.Should().Be("8.0.0"); + File.Exists(versionFile).Should().BeTrue(); + File.ReadAllText(versionFile).Should().Be("8.0.0"); } finally { + File.Delete(versionFile); File.Delete(installStatePath); } From b9f79ac7cc59b899513cb9b4c3de131f0e10d688 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 4 Mar 2024 10:00:58 -0800 Subject: [PATCH 37/43] I'm dumb sometimes --- .../dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs index 175008cc6866..67daf392cb5f 100644 --- a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs +++ b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs @@ -223,7 +223,7 @@ public void UpdateViaWorkloadSet(bool upgrade) var installStatePath = Path.Combine(Path.GetTempPath(), "dotnetTestPath", "metadata", "workloads", versionNumber, "InstallState", "default.json"); var contents = new InstallStateContents(); contents.UseWorkloadSets = true; - var versionFile = "userProfileDir\\sdk-advertising\\8.0.0\\microsoft.net.workloads\\packageVersion.txt"; + var versionFile = Path.Combine("userProfileDir", "sdk-advertising", "8.0.0", "microsoft.net.workloads", "packageVersion.txt"); try { Directory.CreateDirectory(Path.GetDirectoryName(installStatePath)); From e38c25aece92ff5ace58661553c235d2ea387c83 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:22:21 -0800 Subject: [PATCH 38/43] Most PR comments --- .../Microsoft.DotNet.Cli.Utils/Constants.cs | 1 + .../commands/InstallingWorkloadCommand.cs | 34 +++++++++++++++++-- .../dotnet-workload/WorkloadInfoHelper.cs | 8 ++--- .../install/FileBasedInstaller.cs | 16 +++++---- .../install/MsiInstallerBase.cs | 22 ++++++------ .../install/NetSdkMsiInstallerClient.cs | 15 +++++--- .../install/WorkloadInstallCommand.cs | 14 ++------ .../install/WorkloadManifestUpdater.cs | 27 ++++++--------- .../list/WorkloadListCommand.cs | 2 +- .../update/LocalizableStrings.resx | 3 ++ .../update/WorkloadUpdateCommand.cs | 18 +++------- .../update/xlf/LocalizableStrings.cs.xlf | 5 +++ .../update/xlf/LocalizableStrings.de.xlf | 5 +++ .../update/xlf/LocalizableStrings.es.xlf | 5 +++ .../update/xlf/LocalizableStrings.fr.xlf | 5 +++ .../update/xlf/LocalizableStrings.it.xlf | 5 +++ .../update/xlf/LocalizableStrings.ja.xlf | 5 +++ .../update/xlf/LocalizableStrings.ko.xlf | 5 +++ .../update/xlf/LocalizableStrings.pl.xlf | 5 +++ .../update/xlf/LocalizableStrings.pt-BR.xlf | 5 +++ .../update/xlf/LocalizableStrings.ru.xlf | 5 +++ .../update/xlf/LocalizableStrings.tr.xlf | 5 +++ .../update/xlf/LocalizableStrings.zh-Hans.xlf | 5 +++ .../update/xlf/LocalizableStrings.zh-Hant.xlf | 5 +++ ...rkloadManifestProvider.GlobalJsonReader.cs | 2 +- .../MockPackWorkloadInstaller.cs | 3 +- .../GivenDotnetWorkloadUpdate.cs | 2 +- 27 files changed, 156 insertions(+), 76 deletions(-) diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs index a565090b6e46..7e3261799d92 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs @@ -28,5 +28,6 @@ public static class Constants public static readonly string AnyRid = "any"; public static readonly string RestoreInteractiveOption = "--interactive"; + public static readonly string workloadSetVersionFileName = "workloadSetVersion.txt"; } } diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index e7821228ea15..00a192008206 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -34,6 +34,7 @@ internal abstract class InstallingWorkloadCommand : WorkloadCommandBase protected readonly SdkFeatureBand _sdkFeatureBand; protected readonly ReleaseVersion _targetSdkVersion; protected readonly string _fromRollbackDefinition; + protected string _workloadSetVersion; protected readonly PackageSourceLocation _packageSourceLocation; protected readonly IWorkloadResolverFactory _workloadResolverFactory; protected IWorkloadResolver _workloadResolver; @@ -96,16 +97,45 @@ protected static Dictionary GetInstallStateContents(IEnumerable< manifestVersionUpdates.Select(update => new WorkloadManifestInfo(update.ManifestId.ToString(), update.NewVersion.ToString(), /* We don't actually use the directory here */ string.Empty, update.NewFeatureBand)) ).ToDictionaryForJson(); - public static bool GetInstallStateMode(SdkFeatureBand sdkFeatureBand, string dotnetDir) + public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, string dotnetDir) { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, dotnetDir), "default.json"); var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); return installStateContents.UseWorkloadSets ?? false; } + protected string HandleWorkloadUpdateFromVersion(CliTransaction transaction, DirectoryPath? offlineCache) + { + // Ensure workload set mode is set to 'workloadset' + // Do not skip checking the mode first, as setting it triggers + // an admin authorization popup for MSI-based installs. + if (!ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath)) + { + _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true); + } + + _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache); + return InstallWorkloadSet(transaction); + } + public string InstallWorkloadSet(CliTransaction transaction) { - return _workloadInstaller.InstallWorkloadSet(transaction, Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads")); + var advertisingPackagePath = Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads"); + PrintWorkloadSetTransition(File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))); + return _workloadInstaller.InstallWorkloadSet(transaction, advertisingPackagePath); + } + + private void PrintWorkloadSetTransition(string newVersion) + { + var currentVersion = _workloadResolver.GetWorkloadVersion(); + if (currentVersion == null) + { + Reporter.WriteLine(string.Format(Strings.NewWorkloadSet, newVersion)); + } + else + { + Reporter.WriteLine(string.Format(Strings.WorkloadSetUpgrade, currentVersion, newVersion)); + } } protected async Task> GetDownloads(IEnumerable workloadIds, bool skipManifestUpdate, bool includePreview, string downloadFolder = null) diff --git a/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs b/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs index ed9b0be85188..ec6a7641db54 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs @@ -17,7 +17,7 @@ internal class WorkloadInfoHelper : IWorkloadInfoHelper { public readonly SdkFeatureBand _currentSdkFeatureBand; private readonly string _targetSdkVersion; - public readonly string dotnetPath; + public string DotnetPath { get; } public WorkloadInfoHelper( bool isInteractive, @@ -31,20 +31,20 @@ public WorkloadInfoHelper( string userProfileDir = null, IWorkloadResolver workloadResolver = null) { - dotnetPath = dotnetDir ?? Path.GetDirectoryName(Environment.ProcessPath); + DotnetPath = dotnetDir ?? Path.GetDirectoryName(Environment.ProcessPath); ReleaseVersion currentSdkReleaseVersion = new(currentSdkVersion ?? Product.Version); _currentSdkFeatureBand = new SdkFeatureBand(currentSdkReleaseVersion); _targetSdkVersion = targetSdkVersion; userProfileDir ??= CliFolderPathCalculator.DotnetUserProfileFolderPath; ManifestProvider = - new SdkDirectoryWorkloadManifestProvider(dotnetPath, + new SdkDirectoryWorkloadManifestProvider(DotnetPath, string.IsNullOrWhiteSpace(_targetSdkVersion) ? currentSdkReleaseVersion.ToString() : _targetSdkVersion, userProfileDir, SdkDirectoryWorkloadManifestProvider.GetGlobalJsonPath(Environment.CurrentDirectory)); WorkloadResolver = workloadResolver ?? NET.Sdk.WorkloadManifestReader.WorkloadResolver.Create( - ManifestProvider, dotnetPath, + ManifestProvider, DotnetPath, currentSdkReleaseVersion.ToString(), userProfileDir); var restoreConfig = new RestoreActionConfig(Interactive: isInteractive); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 39c28517f0df..d4822caae562 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -87,23 +87,27 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds) public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) { - var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", File.ReadAllText(Path.Combine(advertisingPackagePath, "packageVersion.txt")), "workloadset.json"); + var workloadSetVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName)); + var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadSetVersion); transaction.Run( action: context => { - Directory.CreateDirectory(Path.GetDirectoryName(workloadSetPath)); + Directory.CreateDirectory(workloadSetPath); - File.Copy(Path.Combine(advertisingPackagePath, "workloadset.json"), workloadSetPath, overwrite: true); + foreach (var file in Directory.EnumerateFiles(advertisingPackagePath)) + { + File.Copy(file, Path.Combine(workloadSetPath, Path.GetFileName(file)), overwrite: true); + } }, rollback: () => { - if (advertisingPackagePath is not null) + foreach (var file in Directory.EnumerateFiles(workloadSetPath)) { - PathUtility.DeleteFileAndEmptyParents(advertisingPackagePath); + PathUtility.DeleteFileAndEmptyParents(file); } }); - return workloadSetPath; + return Path.Combine(workloadSetPath, "workloadset.json"); } public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs index 9d0ec42cb52e..d0f827eeefc9 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs @@ -212,10 +212,8 @@ protected void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) if (IsElevated) { // Create the parent folder for the state file and set up all required ACLs - SecurityUtils.CreateSecureDirectory(Path.GetDirectoryName(path)); installStateContents.UseWorkloadSets = newMode; - File.WriteAllText(path, installStateContents.ToString()); - SecurityUtils.SecureFile(path); + CreateSecureFileInDirectory(path, installStateContents.ToString()); } else if (IsClient) { @@ -243,10 +241,8 @@ public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, strin if (IsElevated) { // Create the parent folder for the state file and set up all required ACLs - SecurityUtils.CreateSecureDirectory(Path.GetDirectoryName(path)); installStateContents.WorkloadSetVersion = workloadSetVersion; - File.WriteAllText(path, installStateContents.ToString()); - SecurityUtils.SecureFile(path); + CreateSecureFileInDirectory(path, installStateContents.ToString()); } else if (IsClient) { @@ -537,13 +533,8 @@ public void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dict if (IsElevated) { // Create the parent folder for the state file and set up all required ACLs - SecurityUtils.CreateSecureDirectory(Path.GetDirectoryName(path)); - - installStateContents.Manifests = manifestContents; - File.WriteAllText(path, installStateContents.ToString()); - - SecurityUtils.SecureFile(path); + CreateSecureFileInDirectory(path, installStateContents.ToString()); } else if (IsClient) { @@ -551,5 +542,12 @@ public void SaveInstallStateManifestVersions(SdkFeatureBand sdkFeatureBand, Dict ExitOnFailure(respone, $"Failed to write install state file: {path}"); } } + + private void CreateSecureFileInDirectory(string path, string contents) + { + SecurityUtils.CreateSecureDirectory(Path.GetDirectoryName(path)); + File.WriteAllText(path, contents); + SecurityUtils.SecureFile(path); + } } } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index c3cfb66177f5..587ac53141e0 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -281,11 +281,11 @@ private string ModifyWorkloadSet(string advertisingPackagePath, InstallAction re // Resolve the package ID for the manifest payload package var featureBand = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath)); - var packageVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, "packageVersion.txt")); + var workloadSetVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName)); string msiPackageId = GetManifestPackageId(new ManifestId("Microsoft.NET.Workloads"), new SdkFeatureBand(featureBand)).ToString(); - string msiPackageVersion = WorkloadManifestUpdater.WorkloadSetVersionToWorkloadSetPackageVersion(packageVersion); + string msiPackageVersion = WorkloadManifestUpdater.WorkloadSetVersionToWorkloadSetPackageVersion(workloadSetVersion); - Log?.LogMessage($"Resolving Microsoft.NET.Workloads ({packageVersion}) to {msiPackageId} ({msiPackageVersion})."); + Log?.LogMessage($"Resolving Microsoft.NET.Workloads ({workloadSetVersion}) to {msiPackageId} ({msiPackageVersion})."); // Retrieve the payload from the MSI package cache. MsiPayload msi = GetCachedMsiPayload(msiPackageId, msiPackageVersion, null); @@ -301,10 +301,15 @@ private string ModifyWorkloadSet(string advertisingPackagePath, InstallAction re ExecutePackage(msi, plannedAction, msiPackageId); // Update the reference count against the MSI. - UpdateDependent(InstallRequestType.AddDependent, msi.Manifest.ProviderKeyName, _dependent); + UpdateDependent( + plannedAction == InstallAction.Uninstall ? + InstallRequestType.RemoveDependent : + InstallRequestType.AddDependent, + msi.Manifest.ProviderKeyName, + _dependent); } - return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", packageVersion, "workloadset.json"); + return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadSetVersion, "workloadset.json"); } /// diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 60b7ddf78e34..3bf83984827b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -18,7 +18,6 @@ internal class WorkloadInstallCommand : InstallingWorkloadCommand { private readonly bool _skipManifestUpdate; private readonly IReadOnlyCollection _workloadIds; - private readonly string _workloadSetVersion; public WorkloadInstallCommand( ParseResult parseResult, @@ -128,17 +127,8 @@ public override int Execute() } else { - // Ensure workload set mode is set to 'workloadset' - // Do not skip checking the mode first, as setting it triggers - // an admin authorization popup for MSI-based installs. - if (!GetInstallStateMode(_sdkFeatureBand, _dotnetPath)) - { - _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true); - } - - _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache); var transaction = new CliTransaction(); - var workloadSetLocation = InstallWorkloadSet(transaction); + var workloadSetLocation = HandleWorkloadUpdateFromVersion(transaction, offlineCache); var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation); InstallWorkloadsAndGarbageCollect(workloadSetLocation, transaction, workloadIds, manifestsToUpdate, offlineCache, false); } @@ -195,7 +185,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif } workloadIds = workloadIds.Concat(installedWorkloads).Distinct(); - var useWorkloadSets = GetInstallStateMode(_sdkFeatureBand, _dotnetPath); + var useWorkloadSets = ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath); useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 9b8c4b3b1282..598cbc98008a 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -94,19 +94,6 @@ public async void DownloadWorkloadSet(string version, DirectoryPath? offlineCach await UpdateManifestWithVersionAsync("Microsoft.NET.Workloads", includePreviews: true, _sdkFeatureBand, new NuGetVersion(correctedVersion), offlineCache); } - private void PrintWorkloadSetTransition(string newVersion) - { - var currentVersion = _workloadResolver.GetWorkloadVersion(); - if (currentVersion == null) - { - _reporter.WriteLine(string.Format(LocalizableStrings.NewWorkloadSet, newVersion)); - } - else - { - _reporter.WriteLine(string.Format(LocalizableStrings.WorkloadSetUpgrade, currentVersion, newVersion)); - } - } - public async static Task BackgroundUpdateAdvertisingManifestsAsync(string userProfileDir) { try @@ -126,7 +113,7 @@ public async Task BackgroundUpdateAdvertisingManifestsWhenRequiredAsync() AdManifestSentinelIsDueForUpdate() && UpdatedAdManifestPackagesExistAsync().GetAwaiter().GetResult()) { - await UpdateAdvertisingManifestsAsync(false); + await UpdateAdvertisingManifestsAsync(false, ShouldUseWorkloadSetMode(_sdkFeatureBand, _userProfileDir)); var sentinelPath = GetAdvertisingManifestSentinelPath(_sdkFeatureBand); if (File.Exists(sentinelPath)) { @@ -139,6 +126,13 @@ public async Task BackgroundUpdateAdvertisingManifestsWhenRequiredAsync() } } + public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, string dotnetDir) + { + string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, dotnetDir), "default.json"); + var installStateContents = File.Exists(path) ? InstallStateContents.FromString(File.ReadAllText(path)) : new InstallStateContents(); + return installStateContents.UseWorkloadSets ?? false; + } + private void WriteUpdatableWorkloadsFile() { var installedWorkloads = _workloadRecordRepo.GetInstalledWorkloads(_sdkFeatureBand); @@ -340,9 +334,8 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP // Create version file later used as part of installing the workload set in the file-based installer and in the msi-based installer using PackageArchiveReader packageReader = new(packagePath); var downloadedPackageVersion = packageReader.NuspecReader.GetVersion(); - var correctedPackageVersion = WorkloadSetPackageVersionToWorkloadSetVersion(_sdkFeatureBand, downloadedPackageVersion.ToString()); - File.WriteAllText(Path.Combine(adManifestPath, "packageVersion.txt"), correctedPackageVersion); - PrintWorkloadSetTransition(correctedPackageVersion); + var workloadSetVersion = WorkloadSetPackageVersionToWorkloadSetVersion(_sdkFeatureBand, downloadedPackageVersion.ToString()); + File.WriteAllText(Path.Combine(adManifestPath, Constants.workloadSetVersionFileName), workloadSetVersion); } if (_displayManifestUpdates) diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs index dd91aad3ad75..93dcc18f90f3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs @@ -93,7 +93,7 @@ public override int Execute() table.PrintRows(installedWorkloads.AsEnumerable(), l => Reporter.WriteLine(l)); - var installState = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_workloadListHelper._currentSdkFeatureBand, _workloadListHelper.dotnetPath), "default.json")); + var installState = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_workloadListHelper._currentSdkFeatureBand, _workloadListHelper.DotnetPath), "default.json")); if (installState.UseWorkloadSets == true) { Reporter.WriteLine(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx index 77709f82d798..58a400e6ede6 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx +++ b/src/Cli/dotnet/commands/dotnet-workload/update/LocalizableStrings.resx @@ -156,4 +156,7 @@ Update workloads based on specified rollback definition file. + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + \ No newline at end of file diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index afedb53a78bb..5c674829ea39 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -20,7 +20,6 @@ internal class WorkloadUpdateCommand : InstallingWorkloadCommand private readonly bool _printRollbackDefinitionOnly; private readonly bool _fromPreviousSdk; private readonly string _workloadSetMode; - private readonly string _workloadSetVersion; public WorkloadUpdateCommand( ParseResult parseResult, @@ -74,7 +73,7 @@ public override int Execute() { _workloadManifestUpdater.UpdateAdvertisingManifestsAsync( _includePreviews, - GetInstallStateMode(_sdkFeatureBand, _dotnetPath), + ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath), string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption)) @@ -117,17 +116,8 @@ public override int Execute() } else { - // Ensure workload set mode is set to 'workloadset' - // Do not skip checking the mode first, as setting it triggers - // an admin authorization popup for MSI-based installs. - if (!GetInstallStateMode(_sdkFeatureBand, _dotnetPath)) - { - _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true); - } - - _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache); var transaction = new CliTransaction(); - var workloadSetLocation = InstallWorkloadSet(transaction); + var workloadSetLocation = HandleWorkloadUpdateFromVersion(transaction, offlineCache); CalculateManifestUpdatesAndUpdateWorkloads(false, true, workloadSetLocation, offlineCache, transaction); } } @@ -147,12 +137,12 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline Reporter.WriteLine(); var useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); - var useWorkloadSets = GetInstallStateMode(_sdkFeatureBand, _dotnetPath); + var useWorkloadSets = ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath); if (useRollback && useWorkloadSets) { // Rollback files are only for loose manifests. Update the mode to be loose manifests. - // TODO: add message explaining this (to Reporter) + Reporter.WriteLine(LocalizableStrings.UpdateFromRollbackSwitchesModeToLooseManifests); _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, false); useWorkloadSets = false; } diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf index 0d57937d6b65..0cc940248598 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.cs.xlf @@ -42,6 +42,11 @@ Aktualizace úlohy {0} neproběhla úspěšně z následujícího důvodu: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. Úlohy se úspěšně aktualizovaly: {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf index 7fe3755912f5..eec11ddc74e8 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.de.xlf @@ -42,6 +42,11 @@ Fehler beim Update der Workload "{0}". Ursache: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. Workload(s) erfolgreich aktualisiert: {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf index 61eacfcb2be0..5fd3c603769c 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.es.xlf @@ -42,6 +42,11 @@ La carga de trabajo "{0}" no se pudo actualizar debido a lo siguiente: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. La(s) carga(s) de trabajo se ha(n) actualizado correctamente: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf index ffa504cef235..767a9f67a439 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.fr.xlf @@ -42,6 +42,11 @@ Échec de la mise à jour de la charge de travail '{0}' pour la ou les raisons suivantes : + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. Mise à jour réussie du charge de travail : {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf index 0d9403d54fe4..f3d40db0dc9b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.it.xlf @@ -42,6 +42,11 @@ L'aggiornamento del carico di lavoro '{0}' non è riuscito. Motivi: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. I carichi di lavoro sono stati aggiornati: {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf index a3555167d604..27a35287eee3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ja.xlf @@ -42,6 +42,11 @@ ワークロード '{0}' を更新できませんでした。原因: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. ワークロード {0} が正常に更新されました。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf index 1f9d499812c4..2dcea44b5860 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ko.xlf @@ -42,6 +42,11 @@ 다음으로 인해 워크로드 '{0}'을(를) 업데이트하지 못했습니다. + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. 워크로드를 업데이트했습니다. {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf index 222d233a4c10..96c9a3f67371 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pl.xlf @@ -42,6 +42,11 @@ Aktualizacja obciążenia „{0}” nie powiodła się z następującego powodu: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. Pomyślnie zaktualizowano pakiety robocze: {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf index c5db7d56ba3e..235954d94f87 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.pt-BR.xlf @@ -42,6 +42,11 @@ Falha ao atualizar a carga de trabalho '{0}' devido ao seguinte motivo: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. Carga(s) de trabalho atualizada(s) com êxito: {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf index f65de634659b..b3b7e621533e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.ru.xlf @@ -42,6 +42,11 @@ Не удалось обновить рабочую нагрузку "{0}" по следующей причине: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. Рабочие нагрузки успешно обновлены: {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf index 6c7f77da9566..670f5d690df9 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.tr.xlf @@ -42,6 +42,11 @@ Aşağıdaki nedenlerle '{0}' iş yükü güncelleştirilemedi: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. İş yükleri başarıyla güncelleştirildi: {0}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf index 3c981c1c23c4..3beaaebc1acf 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hans.xlf @@ -42,6 +42,11 @@ 工作负载“{0}”因以下原因而未能更新: + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. 已成功更新工作负载: {0}。 diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf index 20dab178f25e..914b6a666c8a 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/update/xlf/LocalizableStrings.zh-Hant.xlf @@ -42,6 +42,11 @@ 因為下列原因,所以無法更新工作負載 '{0}': + + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + Updating to a rollback file is not compatible with workload sets. Install and Update will now use loose manifests. To update to a specific workload version, use --version. + + Successfully updated workload(s): {0}. 已成功更新工作負載: {0}。 diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs index 19ec03b462aa..43dd03f24073 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs @@ -61,7 +61,7 @@ static class GlobalJsonReader { case JsonTokenType.PropertyName: var sdkPropName = reader.GetString(); - if (string.Equals("workloadSetVersion", sdkPropName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals("workloadVersion", sdkPropName, StringComparison.OrdinalIgnoreCase)) { workloadVersion = JsonReader.ReadString(ref reader); } diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 29573110f7e3..8f261c637efa 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -8,6 +8,7 @@ using Microsoft.NET.Sdk.WorkloadManifestReader; using Microsoft.DotNet.ToolPackage; using Microsoft.DotNet.Workloads.Workload; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Cli.Workload.Install.Tests { @@ -108,7 +109,7 @@ public string InstallWorkloadSet(CliTransaction transaction, string advertisingP { var version = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath ?? string.Empty)); Directory.CreateDirectory(advertisingPackagePath); - File.WriteAllText(Path.Combine(advertisingPackagePath, "packageVersion.txt"), version); + File.WriteAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName), version); return Path.Combine(Path.GetDirectoryName(advertisingPackagePath ?? string.Empty), "installed.workloadset.json"); } diff --git a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs index 67daf392cb5f..9ef484db3bf4 100644 --- a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs +++ b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs @@ -223,7 +223,7 @@ public void UpdateViaWorkloadSet(bool upgrade) var installStatePath = Path.Combine(Path.GetTempPath(), "dotnetTestPath", "metadata", "workloads", versionNumber, "InstallState", "default.json"); var contents = new InstallStateContents(); contents.UseWorkloadSets = true; - var versionFile = Path.Combine("userProfileDir", "sdk-advertising", "8.0.0", "microsoft.net.workloads", "packageVersion.txt"); + var versionFile = Path.Combine("userProfileDir", "sdk-advertising", "8.0.0", "microsoft.net.workloads", Constants.workloadSetVersionFileName); try { Directory.CreateDirectory(Path.GetDirectoryName(installStatePath)); From d0e0bcf31fe23927e0f4fdb025380a0914e740f2 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 8 Mar 2024 13:11:48 -0800 Subject: [PATCH 39/43] Fix transactions and other little things --- .../commands/InstallingWorkloadCommand.cs | 8 +-- .../install/FileBasedInstaller.cs | 6 +- .../dotnet-workload/install/IInstaller.cs | 2 +- .../install/LocalizableStrings.resx | 6 +- .../install/NetSdkMsiInstallerClient.cs | 6 +- .../install/WorkloadInstallCommand.cs | 59 ++++++++++--------- .../install/xlf/LocalizableStrings.cs.xlf | 12 ++-- .../install/xlf/LocalizableStrings.de.xlf | 12 ++-- .../install/xlf/LocalizableStrings.es.xlf | 12 ++-- .../install/xlf/LocalizableStrings.fr.xlf | 12 ++-- .../install/xlf/LocalizableStrings.it.xlf | 12 ++-- .../install/xlf/LocalizableStrings.ja.xlf | 12 ++-- .../install/xlf/LocalizableStrings.ko.xlf | 12 ++-- .../install/xlf/LocalizableStrings.pl.xlf | 12 ++-- .../install/xlf/LocalizableStrings.pt-BR.xlf | 12 ++-- .../install/xlf/LocalizableStrings.ru.xlf | 12 ++-- .../install/xlf/LocalizableStrings.tr.xlf | 12 ++-- .../xlf/LocalizableStrings.zh-Hans.xlf | 12 ++-- .../xlf/LocalizableStrings.zh-Hant.xlf | 12 ++-- .../list/LocalizableStrings.resx | 2 +- .../list/xlf/LocalizableStrings.cs.xlf | 4 +- .../list/xlf/LocalizableStrings.de.xlf | 4 +- .../list/xlf/LocalizableStrings.es.xlf | 4 +- .../list/xlf/LocalizableStrings.fr.xlf | 4 +- .../list/xlf/LocalizableStrings.it.xlf | 4 +- .../list/xlf/LocalizableStrings.ja.xlf | 4 +- .../list/xlf/LocalizableStrings.ko.xlf | 4 +- .../list/xlf/LocalizableStrings.pl.xlf | 4 +- .../list/xlf/LocalizableStrings.pt-BR.xlf | 4 +- .../list/xlf/LocalizableStrings.ru.xlf | 4 +- .../list/xlf/LocalizableStrings.tr.xlf | 4 +- .../list/xlf/LocalizableStrings.zh-Hans.xlf | 4 +- .../list/xlf/LocalizableStrings.zh-Hant.xlf | 4 +- .../update/WorkloadUpdateCommand.cs | 59 ++++++++++--------- .../MockPackWorkloadInstaller.cs | 2 +- 35 files changed, 181 insertions(+), 177 deletions(-) diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index 00a192008206..b289c44339cd 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -104,7 +104,7 @@ public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, strin return installStateContents.UseWorkloadSets ?? false; } - protected string HandleWorkloadUpdateFromVersion(CliTransaction transaction, DirectoryPath? offlineCache) + protected string HandleWorkloadUpdateFromVersion(ITransactionContext context, DirectoryPath? offlineCache) { // Ensure workload set mode is set to 'workloadset' // Do not skip checking the mode first, as setting it triggers @@ -115,14 +115,14 @@ protected string HandleWorkloadUpdateFromVersion(CliTransaction transaction, Dir } _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache); - return InstallWorkloadSet(transaction); + return InstallWorkloadSet(context); } - public string InstallWorkloadSet(CliTransaction transaction) + public string InstallWorkloadSet(ITransactionContext context) { var advertisingPackagePath = Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads"); PrintWorkloadSetTransition(File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))); - return _workloadInstaller.InstallWorkloadSet(transaction, advertisingPackagePath); + return _workloadInstaller.InstallWorkloadSet(context, advertisingPackagePath); } private void PrintWorkloadSetTransition(string newVersion) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index d4822caae562..8a184df07420 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -85,12 +85,12 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds) return packs; } - public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) + public string InstallWorkloadSet(ITransactionContext context, string advertisingPackagePath) { var workloadSetVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName)); var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadSetVersion); - transaction.Run( - action: context => + context.Run( + action: () => { Directory.CreateDirectory(workloadSetPath); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index e3dcd989c104..3e93d71fc8ec 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -13,7 +13,7 @@ internal interface IInstaller : IWorkloadManifestInstaller { int ExitCode { get; } - string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath); + string InstallWorkloadSet(ITransactionContext context, string advertisingPackagePath); void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx index 0187de5fc260..6fddf990e564 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx +++ b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx @@ -347,12 +347,12 @@ Manifest MSI not found in NuGet package {0} - Update to the specified workload set. + Update to the specified workload version. - Installing new workload set with version {0}. + Installing workload version {0}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 587ac53141e0..2c2fc726cd79 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -259,11 +259,11 @@ public void GarbageCollect(Func getResolverForWorkloa } // advertisingPackagePath is the path to the workload set MSI nupkg in the advertising package. - public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) + public string InstallWorkloadSet(ITransactionContext context, string advertisingPackagePath) { var pathToReturn = string.Empty; - transaction.Run( - action: context => + context.Run( + action: () => { pathToReturn = ModifyWorkloadSet(advertisingPackagePath, InstallAction.Install); }, diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 3bf83984827b..6091d4ab5e10 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -117,21 +117,30 @@ public override int Execute() { DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); var workloadIds = _workloadIds.Select(id => new WorkloadId(id)); - if (string.IsNullOrWhiteSpace(_workloadSetVersion)) + var transaction = new CliTransaction() { - InstallWorkloads( - workloadIds, - _skipManifestUpdate, - _includePreviews, - offlineCache); - } - else + RollbackStarted = () => Reporter.WriteLine(LocalizableStrings.RollingBackInstall), + // Don't hide the original error if roll back fails, but do log the rollback failure + RollbackFailed = ex => Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)) + }; + transaction.Run(context => { - var transaction = new CliTransaction(); - var workloadSetLocation = HandleWorkloadUpdateFromVersion(transaction, offlineCache); - var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation); - InstallWorkloadsAndGarbageCollect(workloadSetLocation, transaction, workloadIds, manifestsToUpdate, offlineCache, false); - } + if (string.IsNullOrWhiteSpace(_workloadSetVersion)) + { + InstallWorkloads( + workloadIds, + _skipManifestUpdate, + _includePreviews, + offlineCache, + context); + } + else + { + var workloadSetLocation = HandleWorkloadUpdateFromVersion(context, offlineCache); + var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation); + InstallWorkloadsAndGarbageCollect(workloadSetLocation, context, workloadIds, manifestsToUpdate, offlineCache, false); + } + }); } catch (Exception e) { @@ -144,7 +153,7 @@ public override int Execute() return _workloadInstaller.ExitCode; } - public void InstallWorkloads(IEnumerable workloadIds, bool skipManifestUpdate = false, bool includePreviews = false, DirectoryPath? offlineCache = null) + public void InstallWorkloads(IEnumerable workloadIds, bool skipManifestUpdate = false, bool includePreviews = false, DirectoryPath? offlineCache = null, ITransactionContext context = null) { Reporter.WriteLine(); @@ -163,13 +172,6 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif } } - var transaction = new CliTransaction - { - RollbackStarted = () => Reporter.WriteLine(LocalizableStrings.RollingBackInstall), - // Don't hide the original error if roll back fails, but do log the rollback failure - RollbackFailed = ex => Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)) - }; - if (!skipManifestUpdate) { if (Verbosity != VerbosityOptions.quiet && Verbosity != VerbosityOptions.q) @@ -192,7 +194,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif if (useWorkloadSets) { - workloadSetLocation = InstallWorkloadSet(transaction); + workloadSetLocation = InstallWorkloadSet(context); } manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : @@ -200,14 +202,14 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); } - InstallWorkloadsAndGarbageCollect(workloadSetLocation, transaction, workloadIds, manifestsToUpdate, offlineCache, useRollback); + InstallWorkloadsAndGarbageCollect(workloadSetLocation, context, workloadIds, manifestsToUpdate, offlineCache, useRollback); } - private void InstallWorkloadsAndGarbageCollect(string workloadSetLocation, CliTransaction transaction, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback) + private void InstallWorkloadsAndGarbageCollect(string workloadSetLocation, ITransactionContext context, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback) { var workloadSetVersion = workloadSetLocation is null ? null : Path.GetDirectoryName(workloadSetLocation); - InstallWorkloadsWithInstallRecord(transaction, _workloadInstaller, workloadIds, workloadSetVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); + InstallWorkloadsWithInstallRecord(context, _workloadInstaller, workloadIds, workloadSetVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); @@ -231,7 +233,7 @@ internal static void TryRunGarbageCollection(IInstaller workloadInstaller, IRepo } private void InstallWorkloadsWithInstallRecord( - CliTransaction transaction, + ITransactionContext context, IInstaller installer, IEnumerable workloadIds, string workloadSetVersion, @@ -243,8 +245,8 @@ private void InstallWorkloadsWithInstallRecord( IEnumerable workloadPackToInstall = new List(); IEnumerable newWorkloadInstallRecords = new List(); - transaction.Run( - action: context => + context.Run( + action: () => { bool rollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); @@ -275,7 +277,6 @@ private void InstallWorkloadsWithInstallRecord( { // InstallWorkloadManifest and InstallWorkloadPacks already handle rolling back their actions, so here we only // need to delete the installation records - foreach (var workloadId in newWorkloadInstallRecords) { installer.GetWorkloadInstallationRecordRepository() 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 642613c163f5..16d19acff6fe 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 9dad9682c1a1..3684392e233f 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 99c31cd2bf2b..b85299b2a989 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 84ab3634e619..22f5c5ee64e0 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 7f7e5d1a53b1..0f2b45bf6774 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 9bb6af02d1bb..029a1695d244 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 da4fde058721..928954891bfd 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 4b191835ea4f..b2fc232366d5 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 34119f7cd3c7..f28bacbe2588 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 706d055773e1..ed236e9b4434 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 1880d6c5db18..8bfc444dd456 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 df1eb9e9867b..afc5f7b4f3d7 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. 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 6700d644f856..b1c547749558 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 @@ -183,8 +183,8 @@ - Installing new workload set with version {0}. - Installing new workload set with version {0}. + Installing workload version {0}. + Installing workload version {0}. @@ -373,13 +373,13 @@ - Updating workload set version from {0} to {1}. - Updating workload set version from {0} to {1}. + Updating workload version from {0} to {1}. + Updating workload version from {0} to {1}. - Update to the specified workload set. - Update to the specified workload set. + Update to the specified workload version. + Update to the specified workload version. diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx index ef35ac109171..dbb30fdcd881 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx +++ b/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx @@ -129,6 +129,6 @@ {Locked="dotnet workload search"} - Workload set version: {0} + Workload version: {0} \ No newline at end of file diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.cs.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.cs.xlf index ddc9d461f8bb..66284edd36c8 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.cs.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.cs.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.de.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.de.xlf index c9ad93904c25..df59aa34bd89 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.de.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.de.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.es.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.es.xlf index 672ef0ae3f1f..80f0a9398d5e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.es.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.es.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.fr.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.fr.xlf index 810d740328c6..3f4c46ae97ca 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.fr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.fr.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.it.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.it.xlf index 48cce199abd3..caa33f6a522b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.it.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.it.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ja.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ja.xlf index b1f40a8699b8..58eaa7887ce4 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ja.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ja.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ko.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ko.xlf index 4841ed758843..7b93e295c32c 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ko.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ko.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pl.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pl.xlf index ed0ffb6d830a..6dab03cac48a 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pl.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pl.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pt-BR.xlf index 246d445a773f..bfd92a1420d3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.pt-BR.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ru.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ru.xlf index de6232292d2c..8001bc04e0f0 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ru.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.ru.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.tr.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.tr.xlf index 35fd7c55f6e8..3b0ac98ba2d2 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.tr.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.tr.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hans.xlf index 4830270120db..35e9756641e4 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hans.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hant.xlf index 6087c813702f..424fdf614a55 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/commands/dotnet-workload/list/xlf/LocalizableStrings.zh-Hant.xlf @@ -13,8 +13,8 @@ {Locked="dotnet workload search"} - Workload set version: {0} - Workload set version: {0} + Workload version: {0} + Workload version: {0} diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 5c674829ea39..530970c329b7 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -109,17 +109,31 @@ public override int Execute() { try { - DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); - if (string.IsNullOrWhiteSpace(_workloadSetVersion)) + var transaction = new CliTransaction(); + transaction.RollbackStarted = () => { - UpdateWorkloads(_includePreviews, offlineCache); - } - else + Reporter.WriteLine(LocalizableStrings.RollingBackInstall); + }; + // Don't hide the original error if roll back fails, but do log the rollback failure + transaction.RollbackFailed = ex => { - var transaction = new CliTransaction(); - var workloadSetLocation = HandleWorkloadUpdateFromVersion(transaction, offlineCache); - CalculateManifestUpdatesAndUpdateWorkloads(false, true, workloadSetLocation, offlineCache, transaction); - } + Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)); + }; + + transaction.Run( + action: context => + { + DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); + if (string.IsNullOrWhiteSpace(_workloadSetVersion)) + { + UpdateWorkloads(_includePreviews, offlineCache, context); + } + else + { + var workloadSetLocation = HandleWorkloadUpdateFromVersion(context, offlineCache); + CalculateManifestUpdatesAndUpdateWorkloads(false, true, workloadSetLocation, offlineCache, context); + } + }); } catch (Exception e) { @@ -132,7 +146,7 @@ public override int Execute() return _workloadInstaller.ExitCode; } - public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offlineCache = null) + public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offlineCache = null, ITransactionContext context = null) { Reporter.WriteLine(); @@ -150,16 +164,15 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); string workloadSetLocation = null; - var transaction = new CliTransaction(); if (useWorkloadSets) { - workloadSetLocation = InstallWorkloadSet(transaction); + workloadSetLocation = InstallWorkloadSet(context); } - CalculateManifestUpdatesAndUpdateWorkloads(useRollback, useWorkloadSets, workloadSetLocation, offlineCache, transaction); + CalculateManifestUpdatesAndUpdateWorkloads(useRollback, useWorkloadSets, workloadSetLocation, offlineCache, context); } - private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool useWorkloadSets, string workloadSetLocation, DirectoryPath? offlineCache, CliTransaction transaction) + private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool useWorkloadSets, string workloadSetLocation, DirectoryPath? offlineCache, ITransactionContext context) { var workloadIds = GetUpdatableWorkloads(); var manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : @@ -168,7 +181,7 @@ private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool u var workloadSetVersion = workloadSetLocation is null ? null : Path.GetFileName(Path.GetDirectoryName(workloadSetLocation)); - UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadSetVersion, useRollback, transaction, offlineCache); + UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadSetVersion, useRollback, context, offlineCache); WorkloadInstallCommand.TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); @@ -184,21 +197,11 @@ private void UpdateWorkloadsWithInstallRecord( IEnumerable manifestsToUpdate, string workloadSetVersion, bool useRollback, - CliTransaction transaction, + ITransactionContext context, DirectoryPath? offlineCache = null) { - transaction.RollbackStarted = () => - { - Reporter.WriteLine(LocalizableStrings.RollingBackInstall); - }; - // Don't hide the original error if roll back fails, but do log the rollback failure - transaction.RollbackFailed = ex => - { - Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)); - }; - - transaction.Run( - action: context => + context.Run( + action: () => { foreach (var manifestUpdate in manifestsToUpdate) { diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 8f261c637efa..361ca2bfa36e 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -105,7 +105,7 @@ public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand }); } - public string InstallWorkloadSet(CliTransaction transaction, string advertisingPackagePath) + public string InstallWorkloadSet(ITransactionContext context, string advertisingPackagePath) { var version = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath ?? string.Empty)); Directory.CreateDirectory(advertisingPackagePath); From 9a34b4bc8a118b5948d06281e9451cf4cd160488 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:45:23 -0800 Subject: [PATCH 40/43] Permit multiple *.workloadset.json files --- .../commands/InstallingWorkloadCommand.cs | 9 ++- .../install/FileBasedInstaller.cs | 4 +- .../install/IWorkloadManifestUpdater.cs | 1 + .../install/NetSdkMsiInstallerClient.cs | 2 +- .../install/WorkloadInstallCommand.cs | 26 ++++--- .../install/WorkloadManifestUpdater.cs | 47 +++++++++++-- .../update/WorkloadUpdateCommand.cs | 29 ++++---- .../SdkDirectoryWorkloadManifestProvider.cs | 35 +++++----- ...kDirectoryWorkloadManifestProviderTests.cs | 69 ++++++++++++++++++- .../MockWorkloadManifestUpdater.cs | 1 + .../GivenDotnetWorkloadUpdate.cs | 4 +- 11 files changed, 170 insertions(+), 57 deletions(-) diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index b289c44339cd..c5536b6b0900 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -104,7 +104,7 @@ public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, strin return installStateContents.UseWorkloadSets ?? false; } - protected string HandleWorkloadUpdateFromVersion(ITransactionContext context, DirectoryPath? offlineCache) + protected (string version, IEnumerable) HandleWorkloadUpdateFromVersion(ITransactionContext context, DirectoryPath? offlineCache) { // Ensure workload set mode is set to 'workloadset' // Do not skip checking the mode first, as setting it triggers @@ -118,11 +118,14 @@ protected string HandleWorkloadUpdateFromVersion(ITransactionContext context, Di return InstallWorkloadSet(context); } - public string InstallWorkloadSet(ITransactionContext context) + public (string version, IEnumerable updates) InstallWorkloadSet(ITransactionContext context) { var advertisingPackagePath = Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads"); PrintWorkloadSetTransition(File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))); - return _workloadInstaller.InstallWorkloadSet(context, advertisingPackagePath); + var workloadSetPath = _workloadInstaller.InstallWorkloadSet(context, advertisingPackagePath); + var files = Directory.EnumerateFiles(workloadSetPath, "*.workloadset.json"); + var version = Path.GetFileName(workloadSetPath); + return (version, _workloadManifestUpdater.ParseRollbackDefinitionFiles(files)); } private void PrintWorkloadSetTransition(string newVersion) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 8a184df07420..44d68214ec33 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -106,8 +106,8 @@ public string InstallWorkloadSet(ITransactionContext context, string advertising PathUtility.DeleteFileAndEmptyParents(file); } }); - - return Path.Combine(workloadSetPath, "workloadset.json"); + + return workloadSetPath; } public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs index 269bae40989b..49af91545c87 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs @@ -15,6 +15,7 @@ internal interface IWorkloadManifestUpdater IEnumerable CalculateManifestUpdates(); IEnumerable CalculateManifestRollbacks(string rollbackDefinitionFilePath); + IEnumerable ParseRollbackDefinitionFiles(IEnumerable files); Task> GetManifestPackageDownloadsAsync(bool includePreviews, SdkFeatureBand providedSdkFeatureBand, SdkFeatureBand installedSdkFeatureBand); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs index 2c2fc726cd79..d43d64766d67 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerClient.cs @@ -309,7 +309,7 @@ private string ModifyWorkloadSet(string advertisingPackagePath, InstallAction re _dependent); } - return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadSetVersion, "workloadset.json"); + return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadSetVersion); } /// diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 6091d4ab5e10..27fceed3e2ed 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -136,9 +136,8 @@ public override int Execute() } else { - var workloadSetLocation = HandleWorkloadUpdateFromVersion(context, offlineCache); - var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation); - InstallWorkloadsAndGarbageCollect(workloadSetLocation, context, workloadIds, manifestsToUpdate, offlineCache, false); + (var workloadVersion, var manifests) = HandleWorkloadUpdateFromVersion(context, offlineCache); + InstallWorkloadsAndGarbageCollect(workloadVersion, context, workloadIds, manifests, offlineCache, false); } }); } @@ -159,7 +158,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif var manifestsToUpdate = Enumerable.Empty(); var useRollback = false; - string workloadSetLocation = null; + string workloadVersion = null; if (!skipManifestUpdate) { @@ -194,22 +193,21 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif if (useWorkloadSets) { - workloadSetLocation = InstallWorkloadSet(context); + (workloadVersion, manifestsToUpdate) = InstallWorkloadSet(context); + } + else + { + manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : + _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); } - - manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - useWorkloadSets ? _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation) : - _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); } - InstallWorkloadsAndGarbageCollect(workloadSetLocation, context, workloadIds, manifestsToUpdate, offlineCache, useRollback); + InstallWorkloadsAndGarbageCollect(workloadVersion, context, workloadIds, manifestsToUpdate, offlineCache, useRollback); } - private void InstallWorkloadsAndGarbageCollect(string workloadSetLocation, ITransactionContext context, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback) + private void InstallWorkloadsAndGarbageCollect(string workloadVersion, ITransactionContext context, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback) { - var workloadSetVersion = workloadSetLocation is null ? null : Path.GetDirectoryName(workloadSetLocation); - - InstallWorkloadsWithInstallRecord(context, _workloadInstaller, workloadIds, workloadSetVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); + InstallWorkloadsWithInstallRecord(context, _workloadInstaller, workloadIds, workloadVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 598cbc98008a..0db82677b166 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -233,7 +233,7 @@ public IEnumerable GetUpdatableWorkloadsToAdvertise(IEnumerable CalculateManifestRollbacks(string rollbackDefinitionFilePath) { var currentManifestIds = GetInstalledManifestIds(); - var manifestRollbacks = ParseRollbackDefinitionFile(rollbackDefinitionFilePath); + var manifestRollbacks = ParseRollbackDefinitionFile(rollbackDefinitionFilePath, _sdkFeatureBand); var unrecognizedManifestIds = manifestRollbacks.Where(rollbackManifest => !currentManifestIds.Contains(rollbackManifest.Id)); if (unrecognizedManifestIds.Any()) @@ -242,7 +242,12 @@ public IEnumerable CalculateManifestRollbacks(string roll manifestRollbacks = manifestRollbacks.Where(rollbackManifest => currentManifestIds.Contains(rollbackManifest.Id)); } - var manifestUpdates = manifestRollbacks.Select(manifest => + return CalculateManifestRollbacks(manifestRollbacks); + } + + private IEnumerable CalculateManifestRollbacks(IEnumerable<(ManifestId Id, ManifestVersionWithBand ManifestWithBand)> versionUpdates) + { + var manifestUpdates = versionUpdates.Select(manifest => { var (id, (version, band)) = manifest; var (installedVersion, installedBand) = GetInstalledManifestVersion(id); @@ -465,7 +470,41 @@ private async Task NewerManifestPackageExists(ManifestId manifest) } } - private IEnumerable<(ManifestId Id, ManifestVersionWithBand ManifestWithBand)> ParseRollbackDefinitionFile(string rollbackDefinitionFilePath) + public IEnumerable ParseRollbackDefinitionFiles(IEnumerable rollbackFilePaths) + { + if (rollbackFilePaths.Count() == 1) + { + return CalculateManifestRollbacks(rollbackFilePaths.Single()); + } + + var currentManifestIds = GetInstalledManifestIds(); + // Create a single workload set that includes all the others + List<(ManifestId, ManifestVersionWithBand)> fullSet = new(); + foreach (var rollbackFile in rollbackFilePaths) + { + var rollbacks = ParseRollbackDefinitionFile(rollbackFile, _sdkFeatureBand); + + var unrecognizedManifestIds = rollbacks.Where(rollbackManifest => !currentManifestIds.Contains(rollbackManifest.Id)); + if (unrecognizedManifestIds.Any()) + { + _reporter.WriteLine(string.Format(LocalizableStrings.RollbackDefinitionContainsExtraneousManifestIds, rollbackFile, string.Join(" ", unrecognizedManifestIds)).Yellow()); + rollbacks = rollbacks.Where(rollbackManifest => currentManifestIds.Contains(rollbackManifest.Id)); + } + + fullSet.AddRange(rollbacks); + } + + int size = fullSet.Count; + fullSet = fullSet.DistinctBy<(ManifestId, ManifestVersionWithBand), ManifestId>(update => update.Item1).ToList(); + if (size != fullSet.Count) + { + throw new Exception(); + } + + return CalculateManifestRollbacks(fullSet); + } + + private static IEnumerable<(ManifestId Id, ManifestVersionWithBand ManifestWithBand)> ParseRollbackDefinitionFile(string rollbackDefinitionFilePath, SdkFeatureBand featureBand) { string fileContent; @@ -485,7 +524,7 @@ private async Task NewerManifestPackageExists(ManifestId manifest) } } - var versions = WorkloadSet.FromJson(fileContent, _sdkFeatureBand).ManifestVersions; + var versions = WorkloadSet.FromJson(fileContent, featureBand).ManifestVersions; return versions.Select(kvp => (kvp.Key, new ManifestVersionWithBand(kvp.Value.Version, kvp.Value.FeatureBand))); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 530970c329b7..51af73814489 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -126,12 +126,12 @@ public override int Execute() DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); if (string.IsNullOrWhiteSpace(_workloadSetVersion)) { - UpdateWorkloads(_includePreviews, offlineCache, context); + CalculateManifestUpdatesAndUpdateWorkloads(_includePreviews, offlineCache, context); } else { - var workloadSetLocation = HandleWorkloadUpdateFromVersion(context, offlineCache); - CalculateManifestUpdatesAndUpdateWorkloads(false, true, workloadSetLocation, offlineCache, context); + (var workloadVersion, var manifestUpdates) = HandleWorkloadUpdateFromVersion(context, offlineCache); + UpdateWorkloads(false, manifestUpdates, workloadVersion, offlineCache, context); } }); } @@ -146,7 +146,7 @@ public override int Execute() return _workloadInstaller.ExitCode; } - public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offlineCache = null, ITransactionContext context = null) + public void CalculateManifestUpdatesAndUpdateWorkloads(bool includePreviews = false, DirectoryPath? offlineCache = null, ITransactionContext context = null) { Reporter.WriteLine(); @@ -163,25 +163,26 @@ public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offline _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); - string workloadSetLocation = null; + string workloadVersion = null; + IEnumerable manifestsToUpdate; if (useWorkloadSets) { - workloadSetLocation = InstallWorkloadSet(context); + (workloadVersion, manifestsToUpdate) = InstallWorkloadSet(context); + } + else + { + manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : + _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); } - CalculateManifestUpdatesAndUpdateWorkloads(useRollback, useWorkloadSets, workloadSetLocation, offlineCache, context); + UpdateWorkloads(useRollback, manifestsToUpdate, workloadVersion, offlineCache, context); } - private void CalculateManifestUpdatesAndUpdateWorkloads(bool useRollback, bool useWorkloadSets, string workloadSetLocation, DirectoryPath? offlineCache, ITransactionContext context) + private void UpdateWorkloads(bool useRollback, IEnumerable manifestsToUpdate, string workloadVersion, DirectoryPath? offlineCache, ITransactionContext context) { var workloadIds = GetUpdatableWorkloads(); - var manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - useWorkloadSets ? _workloadManifestUpdater.CalculateManifestRollbacks(workloadSetLocation) : - _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); - - var workloadSetVersion = workloadSetLocation is null ? null : Path.GetFileName(Path.GetDirectoryName(workloadSetLocation)); - UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadSetVersion, useRollback, context, offlineCache); + UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadVersion, useRollback, context, offlineCache); WorkloadInstallCommand.TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index 9c46e7b58f0a..7200cda9dd75 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -1,12 +1,7 @@ // 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.IO; -using System.Linq; using System.Security.Cryptography; -using System.Text; using Microsoft.Deployment.DotNet.Releases; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Workloads.Workload; @@ -425,21 +420,29 @@ public Dictionary GetAvailableWorkloadSets() foreach (var workloadSetDirectory in Directory.GetDirectories(workloadSetsRoot)) { WorkloadSet? workloadSet = null; - var jsonFile = Path.Combine(workloadSetDirectory, "workloadset.json"); - if (File.Exists(jsonFile)) + foreach (var jsonFile in Directory.GetFiles(workloadSetDirectory, "*.workloadset.json")) { - workloadSet = WorkloadSet.FromJson(File.ReadAllText(jsonFile), _sdkVersionBand); - } - - var baselineWorkloadSet = Path.Combine(workloadSetDirectory, "baseline.workloadset.json"); - if (File.Exists(baselineWorkloadSet)) - { - workloadSet = WorkloadSet.FromJson(File.ReadAllText(baselineWorkloadSet), _sdkVersionBand); - workloadSet.IsBaselineWorkloadSet = true; + var newWorkloadSet = WorkloadSet.FromJson(File.ReadAllText(jsonFile), _sdkVersionBand); + if (workloadSet == null) + { + workloadSet = newWorkloadSet; + } + else + { + // If there are multiple workloadset.json files, merge them + foreach (var kvp in newWorkloadSet.ManifestVersions) + { + workloadSet.ManifestVersions.Add(kvp.Key, kvp.Value); + } + } } - if (workloadSet != null) { + if (File.Exists(Path.Combine(workloadSetDirectory, "baseline.workloadset.json"))) + { + workloadSet.IsBaselineWorkloadSet = true; + } + workloadSet.Version = Path.GetFileName(workloadSetDirectory); availableWorkloadSets[workloadSet.Version] = workloadSet; } diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 3da88ddad152..9b51d4dd6a0d 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -417,6 +417,73 @@ var sdkDirectoryWorkloadManifestProvider Assert.Throws(() => GetManifestContents(sdkDirectoryWorkloadManifestProvider).ToList()); } + [Fact] + public void WorkloadSetCanIncludeMultipleJsonFiles() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true); + CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2", true); + + + var workloadSetDirectory = Path.Combine(_manifestRoot, "8.0.200", "workloadsets", "8.0.200"); + Directory.CreateDirectory(workloadSetDirectory); + File.WriteAllText(Path.Combine(workloadSetDirectory, "1.workloadset.json"), """ + { + "ios": "11.0.2/8.0.100" + } + """); + File.WriteAllText(Path.Combine(workloadSetDirectory, "2.workloadset.json"), """ + { + "android": "33.0.2-rc.1/8.0.200" + } + """); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2-rc.1/8.0.200"); + } + + [Fact] + public void ItThrowsExceptionIfWorkloadSetJsonFilesHaveDuplicateManifests() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true); + CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2", true); + + + var workloadSetDirectory = Path.Combine(_manifestRoot, "8.0.200", "workloadsets", "8.0.200"); + Directory.CreateDirectory(workloadSetDirectory); + File.WriteAllText(Path.Combine(workloadSetDirectory, "1.workloadset.json"), """ + { + "ios": "11.0.2/8.0.100" + } + """); + File.WriteAllText(Path.Combine(workloadSetDirectory, "2.workloadset.json"), """ + { + "android": "33.0.2-rc.1/8.0.200", + "ios": "11.0.2/8.0.100" + } + """); + + Assert.Throws(() => + new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null)); + } + [Fact] public void ItUsesWorkloadSetFromGlobalJson() { @@ -1203,7 +1270,7 @@ private void CreateMockWorkloadSet(string manifestRoot, string featureBand, stri { Directory.CreateDirectory(workloadSetDirectory); } - File.WriteAllText(Path.Combine(workloadSetDirectory, "workloadset.json"), workloadSetContents); + File.WriteAllText(Path.Combine(workloadSetDirectory, "workloadset.workloadset.json"), workloadSetContents); } private string CreateMockInstallState(string featureBand, string installStateContents) diff --git a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs index ecb7dc64d68d..3b7a0275a2e6 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs @@ -57,5 +57,6 @@ public IEnumerable CalculateManifestRollbacks(string roll public void DeleteUpdatableWorkloadsFile() { } public void DownloadWorkloadSet(string version, DirectoryPath? offlineCache) => throw new NotImplementedException(); + public IEnumerable ParseRollbackDefinitionFiles(IEnumerable files) => _manifestUpdates.Select(t => t.ManifestUpdate); } } diff --git a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs index 9ef484db3bf4..a1061fe1c3f2 100644 --- a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs +++ b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs @@ -384,7 +384,7 @@ public void ApplyRollbackAcrossFeatureBand(string existingSdkFeatureBand, string }; (var dotnetPath, var updateCommand, var packInstaller, _, _, _) = GetTestInstallers(parseResult, manifestUpdates: manifestsToUpdate, sdkVersion: "6.0.300", identifier: existingSdkFeatureBand + newSdkFeatureBand, installedFeatureBand: existingSdkFeatureBand); - updateCommand.UpdateWorkloads(); + updateCommand.CalculateManifestUpdatesAndUpdateWorkloads(); packInstaller.InstalledManifests[0].manifestUpdate.ManifestId.Should().Be(manifestsToUpdate[0].ManifestUpdate.ManifestId); packInstaller.InstalledManifests[0].manifestUpdate.NewVersion.Should().Be(manifestsToUpdate[0].ManifestUpdate.NewVersion); @@ -414,7 +414,7 @@ public void ApplyRollbackWithMultipleManifestsAcrossFeatureBand() }; (_, var updateCommand, var packInstaller, _, _, _) = GetTestInstallers(parseResult, manifestUpdates: manifestsToUpdate, sdkVersion: "6.0.300", installedFeatureBand: "6.0.300"); - updateCommand.UpdateWorkloads(); + updateCommand.CalculateManifestUpdatesAndUpdateWorkloads(); packInstaller.InstalledManifests[0].manifestUpdate.ManifestId.Should().Be(manifestsToUpdate[0].ManifestUpdate.ManifestId); packInstaller.InstalledManifests[0].manifestUpdate.NewVersion.Should().Be(manifestsToUpdate[0].ManifestUpdate.NewVersion); From 11c0d447af3046fcbac6cc345fb288714d36a123 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 11 Mar 2024 12:11:13 -0700 Subject: [PATCH 41/43] Fix transaction usage + update some tests --- .../install/WorkloadInstallCommand.cs | 95 ++++++++++--------- .../update/WorkloadUpdateCommand.cs | 69 ++++++++------ ...kDirectoryWorkloadManifestProviderTests.cs | 8 +- 3 files changed, 93 insertions(+), 79 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 27fceed3e2ed..acb6f6470127 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -117,29 +117,22 @@ public override int Execute() { DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); var workloadIds = _workloadIds.Select(id => new WorkloadId(id)); - var transaction = new CliTransaction() + if (string.IsNullOrWhiteSpace(_workloadSetVersion)) { - RollbackStarted = () => Reporter.WriteLine(LocalizableStrings.RollingBackInstall), - // Don't hide the original error if roll back fails, but do log the rollback failure - RollbackFailed = ex => Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)) - }; - transaction.Run(context => + InstallWorkloads( + workloadIds, + _skipManifestUpdate, + _includePreviews, + offlineCache); + } + else { - if (string.IsNullOrWhiteSpace(_workloadSetVersion)) - { - InstallWorkloads( - workloadIds, - _skipManifestUpdate, - _includePreviews, - offlineCache, - context); - } - else + RunInNewTransaction(context => { (var workloadVersion, var manifests) = HandleWorkloadUpdateFromVersion(context, offlineCache); InstallWorkloadsAndGarbageCollect(workloadVersion, context, workloadIds, manifests, offlineCache, false); - } - }); + }); + } } catch (Exception e) { @@ -152,7 +145,7 @@ public override int Execute() return _workloadInstaller.ExitCode; } - public void InstallWorkloads(IEnumerable workloadIds, bool skipManifestUpdate = false, bool includePreviews = false, DirectoryPath? offlineCache = null, ITransactionContext context = null) + public void InstallWorkloads(IEnumerable workloadIds, bool skipManifestUpdate = false, bool includePreviews = false, DirectoryPath? offlineCache = null) { Reporter.WriteLine(); @@ -171,38 +164,41 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif } } - if (!skipManifestUpdate) + RunInNewTransaction(context => { - if (Verbosity != VerbosityOptions.quiet && Verbosity != VerbosityOptions.q) - { - Reporter.WriteLine(LocalizableStrings.CheckForUpdatedWorkloadManifests); - } - // Update currently installed workloads - var installedWorkloads = _workloadInstaller.GetWorkloadInstallationRecordRepository().GetInstalledWorkloads(_sdkFeatureBand); - var previouslyInstalledWorkloads = installedWorkloads.Intersect(workloadIds); - if (previouslyInstalledWorkloads.Any()) + if (!skipManifestUpdate) { - Reporter.WriteLine(string.Format(LocalizableStrings.WorkloadAlreadyInstalled, string.Join(" ", previouslyInstalledWorkloads)).Yellow()); - } - workloadIds = workloadIds.Concat(installedWorkloads).Distinct(); + if (Verbosity != VerbosityOptions.quiet && Verbosity != VerbosityOptions.q) + { + Reporter.WriteLine(LocalizableStrings.CheckForUpdatedWorkloadManifests); + } + // Update currently installed workloads + var installedWorkloads = _workloadInstaller.GetWorkloadInstallationRecordRepository().GetInstalledWorkloads(_sdkFeatureBand); + var previouslyInstalledWorkloads = installedWorkloads.Intersect(workloadIds); + if (previouslyInstalledWorkloads.Any()) + { + Reporter.WriteLine(string.Format(LocalizableStrings.WorkloadAlreadyInstalled, string.Join(" ", previouslyInstalledWorkloads)).Yellow()); + } + workloadIds = workloadIds.Concat(installedWorkloads).Distinct(); - var useWorkloadSets = ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath); - useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); + var useWorkloadSets = ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath); + useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); - _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); + _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); - if (useWorkloadSets) - { - (workloadVersion, manifestsToUpdate) = InstallWorkloadSet(context); - } - else - { - manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); + if (useWorkloadSets) + { + (workloadVersion, manifestsToUpdate) = InstallWorkloadSet(context); + } + else + { + manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : + _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); + } } - } - InstallWorkloadsAndGarbageCollect(workloadVersion, context, workloadIds, manifestsToUpdate, offlineCache, useRollback); + InstallWorkloadsAndGarbageCollect(workloadVersion, context, workloadIds, manifestsToUpdate, offlineCache, useRollback); + }); } private void InstallWorkloadsAndGarbageCollect(string workloadVersion, ITransactionContext context, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback) @@ -304,5 +300,16 @@ private Task DownloadToOfflineCacheAsync(IEnumerable workloadIds, Di { return GetDownloads(workloadIds, skipManifestUpdate, includePreviews, offlineCache.Value); } + + private void RunInNewTransaction(Action a) + { + var transaction = new CliTransaction() + { + RollbackStarted = () => Reporter.WriteLine(LocalizableStrings.RollingBackInstall), + // Don't hide the original error if roll back fails, but do log the rollback failure + RollbackFailed = ex => Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)) + }; + transaction.Run(context => a(context)); + } } } diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 51af73814489..3450b8e77414 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -109,31 +109,19 @@ public override int Execute() { try { - var transaction = new CliTransaction(); - transaction.RollbackStarted = () => + DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); + if (string.IsNullOrWhiteSpace(_workloadSetVersion)) { - Reporter.WriteLine(LocalizableStrings.RollingBackInstall); - }; - // Don't hide the original error if roll back fails, but do log the rollback failure - transaction.RollbackFailed = ex => + CalculateManifestUpdatesAndUpdateWorkloads(_includePreviews, offlineCache); + } + else { - Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)); - }; - - transaction.Run( - action: context => + RunInNewTransaction(context => { - DirectoryPath? offlineCache = string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption); - if (string.IsNullOrWhiteSpace(_workloadSetVersion)) - { - CalculateManifestUpdatesAndUpdateWorkloads(_includePreviews, offlineCache, context); - } - else - { - (var workloadVersion, var manifestUpdates) = HandleWorkloadUpdateFromVersion(context, offlineCache); - UpdateWorkloads(false, manifestUpdates, workloadVersion, offlineCache, context); - } + (var workloadVersion, var manifestUpdates) = HandleWorkloadUpdateFromVersion(context, offlineCache); + UpdateWorkloads(false, manifestUpdates, workloadVersion, offlineCache, context); }); + } } catch (Exception e) { @@ -146,7 +134,7 @@ public override int Execute() return _workloadInstaller.ExitCode; } - public void CalculateManifestUpdatesAndUpdateWorkloads(bool includePreviews = false, DirectoryPath? offlineCache = null, ITransactionContext context = null) + public void CalculateManifestUpdatesAndUpdateWorkloads(bool includePreviews = false, DirectoryPath? offlineCache = null) { Reporter.WriteLine(); @@ -165,17 +153,20 @@ public void CalculateManifestUpdatesAndUpdateWorkloads(bool includePreviews = fa string workloadVersion = null; IEnumerable manifestsToUpdate; - if (useWorkloadSets) - { - (workloadVersion, manifestsToUpdate) = InstallWorkloadSet(context); - } - else + RunInNewTransaction(context => { - manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : - _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); - } + if (useWorkloadSets) + { + (workloadVersion, manifestsToUpdate) = InstallWorkloadSet(context); + } + else + { + manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : + _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); + } - UpdateWorkloads(useRollback, manifestsToUpdate, workloadVersion, offlineCache, context); + UpdateWorkloads(useRollback, manifestsToUpdate, workloadVersion, offlineCache, context); + }); } private void UpdateWorkloads(bool useRollback, IEnumerable manifestsToUpdate, string workloadVersion, DirectoryPath? offlineCache, ITransactionContext context) @@ -263,5 +254,21 @@ private IEnumerable GetUpdatableWorkloads() return workloads; } + + private void RunInNewTransaction(Action a) + { + var transaction = new CliTransaction(); + transaction.RollbackStarted = () => + { + Reporter.WriteLine(LocalizableStrings.RollingBackInstall); + }; + // Don't hide the original error if roll back fails, but do log the rollback failure + transaction.RollbackFailed = ex => + { + Reporter.WriteLine(string.Format(LocalizableStrings.RollBackFailedMessage, ex.Message)); + }; + + transaction.Run(context => a(context)); + } } } diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 9b51d4dd6a0d..9b14cd7e7776 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -494,7 +494,7 @@ public void ItUsesWorkloadSetFromGlobalJson() { "sdk": { "version": "8.0.200", - "workloadSetVersion": "8.0.201" + "workloadVersion": "8.0.201" }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2", @@ -536,7 +536,7 @@ public void ItFailsIfWorkloadSetFromGlobalJsonIsNotInstalled() { "sdk": { "version": "8.0.200", - "workloadSetVersion": "8.0.201" + "workloadVersion": "8.0.201" }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2", @@ -565,7 +565,7 @@ public void ItFailsIfGlobalJsonIsMalformed() File.WriteAllText(globalJsonPath, """ { "sdk": { - "workloadSetVersion": [ "8.0.202" ] + "workloadVersion": [ "8.0.202" ] } } """); @@ -885,7 +885,7 @@ public void GlobalJsonOverridesInstallState() { "sdk": { "version": "8.0.200", - "workloadSetVersion": "8.0.201" + "workloadVersion": "8.0.201" }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2", From c7ec231955cf3da9f36443477bcc3515fed970c6 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Mon, 11 Mar 2024 14:10:34 -0700 Subject: [PATCH 42/43] Correct my test --- src/Cli/dotnet/commands/InstallingWorkloadCommand.cs | 6 +++++- .../MockPackWorkloadInstaller.cs | 2 +- .../GivenDotnetWorkloadUpdate.cs | 11 +++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index c5536b6b0900..19364a65c72e 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -121,7 +121,11 @@ public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, strin public (string version, IEnumerable updates) InstallWorkloadSet(ITransactionContext context) { var advertisingPackagePath = Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads"); - PrintWorkloadSetTransition(File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))); + if (File.Exists(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))) + { + // This file isn't created in tests. + PrintWorkloadSetTransition(File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))); + } var workloadSetPath = _workloadInstaller.InstallWorkloadSet(context, advertisingPackagePath); var files = Directory.EnumerateFiles(workloadSetPath, "*.workloadset.json"); var version = Path.GetFileName(workloadSetPath); diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 361ca2bfa36e..2a4c3435aee9 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -110,7 +110,7 @@ public string InstallWorkloadSet(ITransactionContext context, string advertising var version = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath ?? string.Empty)); Directory.CreateDirectory(advertisingPackagePath); File.WriteAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName), version); - return Path.Combine(Path.GetDirectoryName(advertisingPackagePath ?? string.Empty), "installed.workloadset.json"); + return Path.GetDirectoryName(advertisingPackagePath ?? string.Empty); } public void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null) => throw new NotImplementedException(); diff --git a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs index a1061fe1c3f2..ef980e0ba4d4 100644 --- a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs +++ b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs @@ -234,8 +234,15 @@ public void UpdateViaWorkloadSet(bool upgrade) } finally { - File.Delete(versionFile); - File.Delete(installStatePath); + if (File.Exists(versionFile)) + { + File.Delete(versionFile); + } + + if (File.Exists(installStatePath)) + { + File.Delete(installStatePath); + } } workloadInstaller.InstalledManifests.Count.Should().Be(1); From 5944045213dfcdbdd2f0a2f37442c37587e6b8b8 Mon Sep 17 00:00:00 2001 From: Forgind <12969783+Forgind@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:46:24 -0700 Subject: [PATCH 43/43] More feedback --- .../Microsoft.DotNet.Cli.Utils/Constants.cs | 2 +- .../commands/InstallingWorkloadCommand.cs | 7 +++---- .../dotnet-workload/InstallStateContents.cs | 2 +- .../clean/WorkloadCleanCommand.cs | 2 +- .../install/FileBasedInstaller.cs | 8 ++++---- .../dotnet-workload/install/IInstaller.cs | 2 +- .../install/MsiInstallerBase.cs | 10 +++++----- .../install/WorkloadGarbageCollector.cs | 6 +++--- .../install/WorkloadInstallCommand.cs | 18 ++++++++---------- .../install/WorkloadManifestUpdater.cs | 13 ++++++++----- .../update/WorkloadUpdateCommand.cs | 16 +++++++--------- .../SdkDirectoryWorkloadManifestProvider.cs | 6 +++--- ...dkDirectoryWorkloadManifestProviderTests.cs | 14 +++++++------- .../MockPackWorkloadInstaller.cs | 4 ++-- 14 files changed, 54 insertions(+), 56 deletions(-) diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs index 7e3261799d92..5fff0de94751 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs @@ -28,6 +28,6 @@ public static class Constants public static readonly string AnyRid = "any"; public static readonly string RestoreInteractiveOption = "--interactive"; - public static readonly string workloadSetVersionFileName = "workloadSetVersion.txt"; + public static readonly string workloadSetVersionFileName = "workloadVersion.txt"; } } diff --git a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs index 19364a65c72e..d8ca6e0fc51d 100644 --- a/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs +++ b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs @@ -104,7 +104,7 @@ public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, strin return installStateContents.UseWorkloadSets ?? false; } - protected (string version, IEnumerable) HandleWorkloadUpdateFromVersion(ITransactionContext context, DirectoryPath? offlineCache) + protected IEnumerable HandleWorkloadUpdateFromVersion(ITransactionContext context, DirectoryPath? offlineCache) { // Ensure workload set mode is set to 'workloadset' // Do not skip checking the mode first, as setting it triggers @@ -118,7 +118,7 @@ public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, strin return InstallWorkloadSet(context); } - public (string version, IEnumerable updates) InstallWorkloadSet(ITransactionContext context) + public IEnumerable InstallWorkloadSet(ITransactionContext context) { var advertisingPackagePath = Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads"); if (File.Exists(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))) @@ -128,8 +128,7 @@ public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, strin } var workloadSetPath = _workloadInstaller.InstallWorkloadSet(context, advertisingPackagePath); var files = Directory.EnumerateFiles(workloadSetPath, "*.workloadset.json"); - var version = Path.GetFileName(workloadSetPath); - return (version, _workloadManifestUpdater.ParseRollbackDefinitionFiles(files)); + return _workloadManifestUpdater.ParseRollbackDefinitionFiles(files); } private void PrintWorkloadSetTransition(string newVersion) diff --git a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs index 94712d4284ed..b625067712d3 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs @@ -17,7 +17,7 @@ internal class InstallStateContents public Dictionary? Manifests { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? WorkloadSetVersion { get; set; } + public string? WorkloadVersion { get; set; } private static readonly JsonSerializerOptions s_options = new() { diff --git a/src/Cli/dotnet/commands/dotnet-workload/clean/WorkloadCleanCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/clean/WorkloadCleanCommand.cs index 5ccc9998f91f..ef0b679607b0 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/clean/WorkloadCleanCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/clean/WorkloadCleanCommand.cs @@ -59,7 +59,7 @@ public override int Execute() private void ExecuteGarbageCollection() { - _workloadInstaller.GarbageCollect(workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), + _workloadInstaller.GarbageCollect(workloadVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadVersion), cleanAllPacks: _cleanAll); DisplayUninstallableVSWorkloads(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs index 44d68214ec33..170dda6cccd4 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/FileBasedInstaller.cs @@ -87,8 +87,8 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds) public string InstallWorkloadSet(ITransactionContext context, string advertisingPackagePath) { - var workloadSetVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName)); - var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadSetVersion); + var workloadVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName)); + var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadVersion); context.Run( action: () => { @@ -477,12 +477,12 @@ public void GarbageCollect(Func getResolverForWorkloa } - public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion) + public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadVersion) { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, _dotnetDir), "default.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); var installStateContents = InstallStateContents.FromPath(path); - installStateContents.WorkloadSetVersion = workloadSetVersion; + installStateContents.WorkloadVersion = workloadVersion; File.WriteAllText(path, installStateContents.ToString()); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs index 3e93d71fc8ec..275d5ecbcdce 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs @@ -27,7 +27,7 @@ internal interface IInstaller : IWorkloadManifestInstaller IEnumerable GetDownloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, bool includeInstalledItems); - void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion); + void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadVersion); /// /// Replace the workload resolver used by this installer. Typically used to call diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs index d0f827eeefc9..8f3b0ca4d4e2 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs @@ -226,12 +226,12 @@ protected void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) } } - public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion) + public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadVersion) { string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json"); var installStateContents = InstallStateContents.FromPath(path); - if ((installStateContents.WorkloadSetVersion == null && workloadSetVersion == null) || - (installStateContents.WorkloadSetVersion != null && installStateContents.WorkloadSetVersion.Equals(workloadSetVersion))) + if ((installStateContents.WorkloadVersion == null && workloadVersion == null) || + (installStateContents.WorkloadVersion != null && installStateContents.WorkloadVersion.Equals(workloadVersion))) { return; } @@ -241,12 +241,12 @@ public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, strin if (IsElevated) { // Create the parent folder for the state file and set up all required ACLs - installStateContents.WorkloadSetVersion = workloadSetVersion; + installStateContents.WorkloadVersion = workloadVersion; CreateSecureFileInDirectory(path, installStateContents.ToString()); } else if (IsClient) { - InstallResponseMessage response = Dispatcher.SendUpdateWorkloadSetRequest(sdkFeatureBand, workloadSetVersion); + InstallResponseMessage response = Dispatcher.SendUpdateWorkloadSetRequest(sdkFeatureBand, workloadVersion); ExitOnFailure(response, "Failed to update install mode."); } else diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs index b67eca82a2a8..8b75adb64743 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs @@ -79,10 +79,10 @@ void GarbageCollectWorkloadSets() { // If there is a rollback state file (default.json) in the workload install state folder, don't garbage collect the workload set it specifies. var installState = InstallStateContents.FromPath(installStateFilePath); - if (!string.IsNullOrEmpty(installState.WorkloadSetVersion)) + if (!string.IsNullOrEmpty(installState.WorkloadVersion)) { - WorkloadSetsToKeep.Add(installState.WorkloadSetVersion); - _verboseReporter.WriteLine($"GC: Keeping workload set version {installState.WorkloadSetVersion} because it is specified in the install state file {installStateFilePath}"); + WorkloadSetsToKeep.Add(installState.WorkloadVersion); + _verboseReporter.WriteLine($"GC: Keeping workload set version {installState.WorkloadVersion} because it is specified in the install state file {installStateFilePath}"); } } else diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs index 6f9ea1929064..7025e5a5bf2b 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs @@ -48,7 +48,7 @@ public WorkloadInstallCommand( { // If the version of the workload set is currently pinned, treat it as if it were freshly pinned. var installStateContents = InstallStateContents.FromPath(Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, _dotnetPath), "default.json")); - _workloadSetVersion = installStateContents.WorkloadSetVersion; + _workloadSetVersion = installStateContents.WorkloadVersion; } ValidateWorkloadIdsInput(); @@ -129,8 +129,8 @@ public override int Execute() { RunInNewTransaction(context => { - (var workloadVersion, var manifests) = HandleWorkloadUpdateFromVersion(context, offlineCache); - InstallWorkloadsAndGarbageCollect(workloadVersion, context, workloadIds, manifests, offlineCache, false); + var manifests = HandleWorkloadUpdateFromVersion(context, offlineCache); + InstallWorkloadsAndGarbageCollect(context, workloadIds, manifests, offlineCache, false); }); } } @@ -151,7 +151,6 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif var manifestsToUpdate = Enumerable.Empty(); var useRollback = false; - string workloadVersion = null; WriteSDKInstallRecordsForVSWorkloads(); @@ -190,7 +189,7 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif if (useWorkloadSets) { - (workloadVersion, manifestsToUpdate) = InstallWorkloadSet(context); + manifestsToUpdate = InstallWorkloadSet(context); } else { @@ -199,13 +198,13 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif } } - InstallWorkloadsAndGarbageCollect(workloadVersion, context, workloadIds, manifestsToUpdate, offlineCache, useRollback); + InstallWorkloadsAndGarbageCollect(context, workloadIds, manifestsToUpdate, offlineCache, useRollback); }); } - private void InstallWorkloadsAndGarbageCollect(string workloadVersion, ITransactionContext context, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback) + private void InstallWorkloadsAndGarbageCollect(ITransactionContext context, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback) { - InstallWorkloadsWithInstallRecord(context, _workloadInstaller, workloadIds, workloadVersion, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); + InstallWorkloadsWithInstallRecord(context, _workloadInstaller, workloadIds, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback); TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); @@ -243,7 +242,6 @@ private void InstallWorkloadsWithInstallRecord( ITransactionContext context, IInstaller installer, IEnumerable workloadIds, - string workloadSetVersion, SdkFeatureBand sdkFeatureBand, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, @@ -267,7 +265,7 @@ private void InstallWorkloadsWithInstallRecord( installer.SaveInstallStateManifestVersions(sdkFeatureBand, GetInstallStateContents(manifestsToUpdate)); } - installer.AdjustWorkloadSetInInstallState(sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : workloadSetVersion); + installer.AdjustWorkloadSetInInstallState(sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : _workloadSetVersion); _workloadResolver.RefreshWorkloadManifests(); diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs index 0db82677b166..bb91d359cdab 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadManifestUpdater.cs @@ -315,7 +315,10 @@ private async Task UpdateManifestWithVersionAsync(string id, bool includeP // If an offline cache is present, use that. Otherwise, try to acquire the package online. packagePath = offlineCache != null ? Directory.GetFiles(offlineCache.Value.Value) - .Where(path => path.EndsWith(".nupkg") && Path.GetFileName(path).StartsWith(manifestPackageId.ToString(), StringComparison.OrdinalIgnoreCase)) + .Where(path => + path.EndsWith(".nupkg") && + Path.GetFileName(path).StartsWith(manifestPackageId.ToString(), StringComparison.OrdinalIgnoreCase) && + (packageVersion == null || path.Contains(packageVersion.ToString()))) .Max() : await _nugetPackageDownloader.DownloadPackageAsync(manifestPackageId, packageVersion: packageVersion, packageSourceLocation: _packageSourceLocation, includePreview: includePreviews); } @@ -494,11 +497,11 @@ public IEnumerable ParseRollbackDefinitionFiles(IEnumerab fullSet.AddRange(rollbacks); } - int size = fullSet.Count; - fullSet = fullSet.DistinctBy<(ManifestId, ManifestVersionWithBand), ManifestId>(update => update.Item1).ToList(); - if (size != fullSet.Count) + var reducedFullSet = fullSet.DistinctBy<(ManifestId, ManifestVersionWithBand), ManifestId>(update => update.Item1).ToList(); + if (fullSet.Count != reducedFullSet.Count) { - throw new Exception(); + var duplicates = reducedFullSet.Where(manifest => fullSet.Where(m => m.Item1.Equals(manifest.Item1)).Count() > 1); + throw new ArgumentException("There were duplicates of the following manifests between the workload set files: " + string.Join(", ", duplicates)); } return CalculateManifestRollbacks(fullSet); diff --git a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs index 09b8686e73b2..0d14b1fc84f7 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs @@ -121,8 +121,8 @@ public override int Execute() { RunInNewTransaction(context => { - (var workloadVersion, var manifestUpdates) = HandleWorkloadUpdateFromVersion(context, offlineCache); - UpdateWorkloads(false, manifestUpdates, workloadVersion, offlineCache, context); + var manifestUpdates = HandleWorkloadUpdateFromVersion(context, offlineCache); + UpdateWorkloads(false, manifestUpdates, offlineCache, context); }); } } @@ -156,13 +156,12 @@ public void CalculateManifestUpdatesAndUpdateWorkloads(bool includePreviews = fa WriteSDKInstallRecordsForVSWorkloads(workloadIds); _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait(); - string workloadVersion = null; IEnumerable manifestsToUpdate; RunInNewTransaction(context => { if (useWorkloadSets) { - (workloadVersion, manifestsToUpdate) = InstallWorkloadSet(context); + manifestsToUpdate = InstallWorkloadSet(context); } else { @@ -170,7 +169,7 @@ public void CalculateManifestUpdatesAndUpdateWorkloads(bool includePreviews = fa _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); } - UpdateWorkloads(useRollback, manifestsToUpdate, workloadVersion, offlineCache, context); + UpdateWorkloads(useRollback, manifestsToUpdate, offlineCache, context); Reporter.WriteLine(); Reporter.WriteLine(string.Format(LocalizableStrings.UpdateSucceeded, string.Join(" ", workloadIds))); @@ -178,11 +177,11 @@ public void CalculateManifestUpdatesAndUpdateWorkloads(bool includePreviews = fa }); } - private void UpdateWorkloads(bool useRollback, IEnumerable manifestsToUpdate, string workloadVersion, DirectoryPath? offlineCache, ITransactionContext context) + private void UpdateWorkloads(bool useRollback, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, ITransactionContext context) { var workloadIds = GetUpdatableWorkloads(); - UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, workloadVersion, useRollback, context, offlineCache); + UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, useRollback, context, offlineCache); WorkloadInstallCommand.TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache); @@ -202,7 +201,6 @@ private void WriteSDKInstallRecordsForVSWorkloads(IEnumerable update private void UpdateWorkloadsWithInstallRecord( SdkFeatureBand sdkFeatureBand, IEnumerable manifestsToUpdate, - string workloadSetVersion, bool useRollback, ITransactionContext context, DirectoryPath? offlineCache = null) @@ -224,7 +222,7 @@ private void UpdateWorkloadsWithInstallRecord( _workloadInstaller.RemoveManifestsFromInstallState(sdkFeatureBand); } - _workloadInstaller.AdjustWorkloadSetInInstallState(sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : workloadSetVersion); + _workloadInstaller.AdjustWorkloadSetInInstallState(sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : _workloadSetVersion); _workloadResolver.RefreshWorkloadManifests(); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index 7200cda9dd75..eeefd7dee1c7 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -132,11 +132,11 @@ public void RefreshWorkloadManifests() if (File.Exists(installStateFilePath)) { var installState = InstallStateContents.FromPath(installStateFilePath); - if (!string.IsNullOrEmpty(installState.WorkloadSetVersion)) + if (!string.IsNullOrEmpty(installState.WorkloadVersion)) { - if (!availableWorkloadSets.TryGetValue(installState.WorkloadSetVersion!, out _workloadSet)) + if (!availableWorkloadSets.TryGetValue(installState.WorkloadVersion!, out _workloadSet)) { - throw new FileNotFoundException(string.Format(Strings.WorkloadVersionFromInstallStateNotFound, installState.WorkloadSetVersion, installStateFilePath)); + throw new FileNotFoundException(string.Format(Strings.WorkloadVersionFromInstallStateNotFound, installState.WorkloadVersion, installStateFilePath)); } } _manifestsFromInstallState = installState.Manifests is null ? new WorkloadSet() : WorkloadSet.FromDictionaryForJson(installState.Manifests, _sdkVersionBand); diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 9b14cd7e7776..44bf3f961184 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -605,7 +605,7 @@ public void ItUsesWorkloadSetFromInstallState() CreateMockInstallState("8.0.200", """ { - "workloadSetVersion": "8.0.201" + "workloadVersion": "8.0.201" } """); @@ -641,7 +641,7 @@ public void ItFailsIfWorkloadSetFromInstallStateIsNotInstalled() var installStatePath = CreateMockInstallState("8.0.200", """ { - "workloadSetVersion": "8.0.203" + "workloadVersion": "8.0.203" } """); @@ -673,7 +673,7 @@ public void ItFailsIfManifestFromWorkloadSetFromInstallStateIsNotInstalled() var installStatePath = CreateMockInstallState("8.0.200", """ { - "workloadSetVersion": "8.0.201" + "workloadVersion": "8.0.201" } """); @@ -786,7 +786,7 @@ public void ItUsesWorkloadSetAndManifestFromInstallState() CreateMockInstallState("8.0.200", """ { - "workloadSetVersion": "8.0.201", + "workloadVersion": "8.0.201", "manifests": { "tizen": "8.0.0/8.0.200", } @@ -825,7 +825,7 @@ public void WorkloadManifestFromInstallStateOverridesWorkloadSetFromInstallState CreateMockInstallState("8.0.200", """ { - "workloadSetVersion": "8.0.201", + "workloadVersion": "8.0.201", "manifests": { "ios": "11.0.1/8.0.100", } @@ -896,7 +896,7 @@ public void GlobalJsonOverridesInstallState() CreateMockInstallState("8.0.200", """ { - "workloadSetVersion": "8.0.202", + "workloadVersion": "8.0.202", } """); @@ -935,7 +935,7 @@ public void GlobalJsonWithoutWorkloadVersionDoesNotOverrideInstallState() CreateMockInstallState("8.0.200", """ { - "workloadSetVersion": "8.0.200", + "workloadVersion": "8.0.200", } """); diff --git a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs index 2a4c3435aee9..fb4b3924dea5 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockPackWorkloadInstaller.cs @@ -64,11 +64,11 @@ public void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode) throw new NotImplementedException(); } - public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadSetVersion) + public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadVersion) { var installStatePath = Path.Combine(Path.GetTempPath(), "dotnetTestPath", "metadata", "workloads", sdkFeatureBand.ToString(), "InstallState", "default.json"); var contents = InstallStateContents.FromPath(installStatePath); - contents.WorkloadSetVersion = workloadSetVersion; + contents.WorkloadVersion = workloadVersion; if (File.Exists(installStatePath)) { File.WriteAllText(installStatePath, contents.ToString());