Skip to content

Commit 43f7012

Browse files
committed
Refactor workload update and install commands
1 parent 7ecfc8a commit 43f7012

33 files changed

+633
-520
lines changed

src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public static bool TryDeleteDirectory(string directoryPath)
102102
/// and continues to its parent until it fails. Returns whether it succeeded
103103
/// in deleting the file it was intended to delete.
104104
/// </summary>
105-
public static bool DeleteFileAndEmptyParents(string path)
105+
public static bool DeleteFileAndEmptyParents(string path, int maxDirectoriesToDelete = int.MaxValue)
106106
{
107107
if (!File.Exists(path))
108108
{
@@ -112,9 +112,13 @@ public static bool DeleteFileAndEmptyParents(string path)
112112
File.Delete(path);
113113
var dir = Path.GetDirectoryName(path);
114114

115-
while (!Directory.EnumerateFileSystemEntries(dir).Any())
115+
int directoriesDeleted = 0;
116+
117+
while (!Directory.EnumerateFileSystemEntries(dir).Any() &&
118+
directoriesDeleted < maxDirectoriesToDelete)
116119
{
117120
Directory.Delete(dir);
121+
directoriesDeleted++;
118122
dir = Path.GetDirectoryName(dir);
119123
}
120124

src/Cli/dotnet/commands/InstallingWorkloadCommand.cs

Lines changed: 106 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.DotNet.Cli.Utils;
1515
using Microsoft.DotNet.ToolPackage;
1616
using Microsoft.DotNet.Workloads.Workload.Install;
17+
using Microsoft.DotNet.Workloads.Workload.Update;
1718
using Microsoft.Extensions.EnvironmentAbstractions;
1819
using Microsoft.NET.Sdk.WorkloadManifestReader;
1920
using NuGet.Versioning;
@@ -104,31 +105,107 @@ public static bool ShouldUseWorkloadSetMode(SdkFeatureBand sdkFeatureBand, strin
104105
return installStateContents.UseWorkloadSets ?? false;
105106
}
106107

107-
protected IEnumerable<ManifestVersionUpdate> HandleWorkloadUpdateFromVersion(ITransactionContext context, DirectoryPath? offlineCache)
108+
protected void UpdateWorkloads(ITransactionContext context, IEnumerable<WorkloadId> workloadsToUpdateOrInstall, DirectoryPath? offlineCache)
108109
{
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)
113114
{
114-
_workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true);
115+
throw new GracefulException(string.Format(Update.LocalizableStrings.CannotCombineOptions,
116+
InstallingWorkloadCommandParser.FromRollbackFileOption.Name,
117+
InstallingWorkloadCommandParser.WorkloadSetVersionOption.Name), isUserError: true);
115118
}
116119

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+
}
120128

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
125164
{
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);
128167
}
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);
132209
}
133210

134211
private void PrintWorkloadSetTransition(string newVersion)
@@ -240,6 +317,17 @@ protected IEnumerable<WorkloadId> GetInstalledWorkloads(bool fromPreviousSdk)
240317
return workloads ?? Enumerable.Empty<WorkloadId>();
241318
}
242319
}
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+
}
243331
}
244332

245333
internal static class InstallingWorkloadCommandParser

0 commit comments

Comments
 (0)