|
14 | 14 | using Microsoft.DotNet.Cli.Utils;
|
15 | 15 | using Microsoft.DotNet.ToolPackage;
|
16 | 16 | using Microsoft.DotNet.Workloads.Workload.Install;
|
| 17 | +using Microsoft.DotNet.Workloads.Workload.Update; |
17 | 18 | using Microsoft.Extensions.EnvironmentAbstractions;
|
18 | 19 | using Microsoft.NET.Sdk.WorkloadManifestReader;
|
19 | 20 | using NuGet.Versioning;
|
@@ -104,31 +105,107 @@ public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, strin
|
104 | 105 | return installStateContents.UseWorkloadSets ?? false;
|
105 | 106 | }
|
106 | 107 |
|
107 |
| - protected IEnumerable<ManifestVersionUpdate> HandleWorkloadUpdateFromVersion(ITransactionContext context, DirectoryPath? offlineCache) |
| 108 | + protected void UpdateWorkloads(ITransactionContext context, IEnumerable<WorkloadId> workloadsToUpdateOrInstall, DirectoryPath? offlineCache) |
108 | 109 | {
|
109 |
| - // Ensure workload set mode is set to 'workloadset' |
110 |
| - // Do not skip checking the mode first, as setting it triggers |
111 |
| - // an admin authorization popup for MSI-based installs. |
112 |
| - if (!ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath)) |
| 110 | + var useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition); |
| 111 | + |
| 112 | + bool specifiedWorkloadSetVersion = !string.IsNullOrEmpty(_workloadSetVersion); |
| 113 | + if (specifiedWorkloadSetVersion && useRollback) |
113 | 114 | {
|
114 |
| - _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true); |
| 115 | + throw new GracefulException(string.Format(Update.LocalizableStrings.CannotCombineOptions, |
| 116 | + InstallingWorkloadCommandParser.FromRollbackFileOption.Name, |
| 117 | + InstallingWorkloadCommandParser.WorkloadSetVersionOption.Name), isUserError: true); |
115 | 118 | }
|
116 | 119 |
|
117 |
| - _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache); |
118 |
| - return InstallWorkloadSet(context); |
119 |
| - } |
| 120 | + var useWorkloadSets = ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath); |
| 121 | + if (useRollback && useWorkloadSets) |
| 122 | + { |
| 123 | + // Rollback files are only for loose manifests. Update the mode to be loose manifests. |
| 124 | + Reporter.WriteLine(Update.LocalizableStrings.UpdateFromRollbackSwitchesModeToLooseManifests); |
| 125 | + _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, false); |
| 126 | + useWorkloadSets = false; |
| 127 | + } |
120 | 128 |
|
121 |
| - public IEnumerable<ManifestVersionUpdate> InstallWorkloadSet(ITransactionContext context) |
122 |
| - { |
123 |
| - var advertisingPackagePath = Path.Combine(_userProfileDir, "sdk-advertising", _sdkFeatureBand.ToString(), "microsoft.net.workloads"); |
124 |
| - if (File.Exists(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))) |
| 129 | + if (specifiedWorkloadSetVersion) |
| 130 | + { |
| 131 | + useWorkloadSets = true; |
| 132 | + |
| 133 | + // If a workload set version is specified, then switch to workload set update mode |
| 134 | + // Check to make sure the value needs to be changed, as updating triggers a UAC prompt |
| 135 | + // for MSI-based installs. |
| 136 | + if (!ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath)) |
| 137 | + { |
| 138 | + _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true); |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + string resolvedWorkloadSetVersion = _workloadSetVersion; |
| 143 | + if (string.IsNullOrWhiteSpace(_workloadSetVersion)) |
| 144 | + { |
| 145 | + _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(_includePreviews, useWorkloadSets, offlineCache).Wait(); |
| 146 | + if (useWorkloadSets) |
| 147 | + { |
| 148 | + resolvedWorkloadSetVersion = _workloadManifestUpdater.GetAdvertisedWorkloadSetVersion(); |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + if (useWorkloadSets && resolvedWorkloadSetVersion == null) |
| 153 | + { |
| 154 | + Reporter.WriteLine(Update.LocalizableStrings.NoWorkloadUpdateFound); |
| 155 | + return; |
| 156 | + } |
| 157 | + |
| 158 | + IEnumerable<ManifestVersionUpdate> manifestsToUpdate; |
| 159 | + if (useWorkloadSets) |
| 160 | + { |
| 161 | + manifestsToUpdate = InstallWorkloadSet(context, resolvedWorkloadSetVersion); |
| 162 | + } |
| 163 | + else |
125 | 164 | {
|
126 |
| - // This file isn't created in tests. |
127 |
| - PrintWorkloadSetTransition(File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName))); |
| 165 | + manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) : |
| 166 | + _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate); |
128 | 167 | }
|
129 |
| - var workloadSetPath = _workloadInstaller.InstallWorkloadSet(context, advertisingPackagePath); |
130 |
| - var files = Directory.EnumerateFiles(workloadSetPath, "*.workloadset.json"); |
131 |
| - return _workloadManifestUpdater.ParseRollbackDefinitionFiles(files); |
| 168 | + |
| 169 | + context.Run( |
| 170 | + action: () => |
| 171 | + { |
| 172 | + foreach (var manifestUpdate in manifestsToUpdate) |
| 173 | + { |
| 174 | + _workloadInstaller.InstallWorkloadManifest(manifestUpdate, context, offlineCache, useRollback); |
| 175 | + } |
| 176 | + |
| 177 | + if (useRollback) |
| 178 | + { |
| 179 | + _workloadInstaller.SaveInstallStateManifestVersions(_sdkFeatureBand, GetInstallStateContents(manifestsToUpdate)); |
| 180 | + } |
| 181 | + else if (this is WorkloadUpdateCommand) |
| 182 | + { |
| 183 | + // For workload updates, if you don't specify a rollback file, then we should update to a new version of the manifests or workload set, and |
| 184 | + // should remove the install state that pins to the other version |
| 185 | + // TODO: Do we need to do something similar if the workload set version is pinned in the install state? |
| 186 | + _workloadInstaller.RemoveManifestsFromInstallState(_sdkFeatureBand); |
| 187 | + } |
| 188 | + |
| 189 | + _workloadInstaller.AdjustWorkloadSetInInstallState(_sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : _workloadSetVersion); |
| 190 | + |
| 191 | + _workloadResolver.RefreshWorkloadManifests(); |
| 192 | + |
| 193 | + _workloadInstaller.InstallWorkloads(workloadsToUpdateOrInstall, _sdkFeatureBand, context, offlineCache); |
| 194 | + }, |
| 195 | + rollback: () => |
| 196 | + { |
| 197 | + // Nothing to roll back at this level, InstallWorkloadManifest and InstallWorkloadPacks handle the transaction rollback |
| 198 | + // We will refresh the workload manifests to make sure that the resolver has the updated state after the rollback |
| 199 | + _workloadResolver.RefreshWorkloadManifests(); |
| 200 | + }); |
| 201 | + } |
| 202 | + |
| 203 | + private IEnumerable<ManifestVersionUpdate> InstallWorkloadSet(ITransactionContext context, string workloadSetVersion) |
| 204 | + { |
| 205 | + PrintWorkloadSetTransition(workloadSetVersion); |
| 206 | + var workloadSet = _workloadInstaller.InstallWorkloadSet(context, workloadSetVersion); |
| 207 | + |
| 208 | + return _workloadManifestUpdater.CalculateManifestUpdatesForWorkloadSet(workloadSet); |
132 | 209 | }
|
133 | 210 |
|
134 | 211 | private void PrintWorkloadSetTransition(string newVersion)
|
@@ -240,6 +317,17 @@ protected IEnumerable<WorkloadId> GetInstalledWorkloads(bool fromPreviousSdk)
|
240 | 317 | return workloads ?? Enumerable.Empty<WorkloadId>();
|
241 | 318 | }
|
242 | 319 | }
|
| 320 | + |
| 321 | + protected IEnumerable<WorkloadId> WriteSDKInstallRecordsForVSWorkloads(IEnumerable<WorkloadId> workloadsWithExistingInstallRecords) |
| 322 | + { |
| 323 | +#if !DOT_NET_BUILD_FROM_SOURCE |
| 324 | + if (OperatingSystem.IsWindows()) |
| 325 | + { |
| 326 | + return VisualStudioWorkloads.WriteSDKInstallRecordsForVSWorkloads(_workloadInstaller, _workloadResolver, workloadsWithExistingInstallRecords, Reporter); |
| 327 | + } |
| 328 | +#endif |
| 329 | + return workloadsWithExistingInstallRecords; |
| 330 | + } |
243 | 331 | }
|
244 | 332 |
|
245 | 333 | internal static class InstallingWorkloadCommandParser
|
|
0 commit comments