diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs
index a565090b6e46..5fff0de94751 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 = "workloadVersion.txt";
}
}
diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs
index 75019c9e32e3..1957a49a1739 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs
+++ b/src/Cli/Microsoft.DotNet.Cli.Utils/PathUtility.cs
@@ -97,6 +97,30 @@ 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)
+ {
+ if (!File.Exists(path))
+ {
+ return false;
+ }
+
+ File.Delete(path);
+ var dir = Path.GetDirectoryName(path);
+
+ while (!Directory.EnumerateFileSystemEntries(dir).Any())
+ {
+ Directory.Delete(dir);
+ dir = Path.GetDirectoryName(dir);
+ }
+
+ return !File.Exists(path);
+ }
+
///
/// Returns childItem relative to directory, with Path.DirectorySeparatorChar as separator
///
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/InstallingWorkloadCommand.cs b/src/Cli/dotnet/commands/InstallingWorkloadCommand.cs
index 9e010dfb3632..d8ca6e0fc51d 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,6 +97,53 @@ 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 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 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
+ // an admin authorization popup for MSI-based installs.
+ if (!ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath))
+ {
+ _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, true);
+ }
+
+ _workloadManifestUpdater.DownloadWorkloadSet(_workloadSetVersion, offlineCache);
+ return InstallWorkloadSet(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)))
+ {
+ // 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");
+ return _workloadManifestUpdater.ParseRollbackDefinitionFiles(files);
+ }
+
+ 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)
{
List ret = new();
@@ -202,6 +250,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/InstallStateContents.cs b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs
index 3c30ce66ab73..b625067712d3 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/InstallStateContents.cs
@@ -4,6 +4,8 @@
using System.Text.Json;
using System.Text.Json.Serialization;
+#pragma warning disable CS8632
+
namespace Microsoft.DotNet.Workloads.Workload
{
internal class InstallStateContents
@@ -12,17 +14,21 @@ 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? WorkloadVersion { get; set; }
private static readonly JsonSerializerOptions s_options = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
+ AllowTrailingCommas = true,
};
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 +41,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/WorkloadInfoHelper.cs b/src/Cli/dotnet/commands/dotnet-workload/WorkloadInfoHelper.cs
index f686d494a53d..ec6a7641db54 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 string DotnetPath { get; }
public WorkloadInfoHelper(
bool isInteractive,
@@ -30,20 +31,20 @@ 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);
_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/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 6b4af4b5f2cb..170dda6cccd4 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
{
@@ -85,6 +85,31 @@ IEnumerable GetPacksInWorkloads(IEnumerable workloadIds)
return packs;
}
+ public string InstallWorkloadSet(ITransactionContext context, string advertisingPackagePath)
+ {
+ var workloadVersion = File.ReadAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName));
+ var workloadSetPath = Path.Combine(_dotnetDir, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadVersion);
+ context.Run(
+ action: () =>
+ {
+ Directory.CreateDirectory(workloadSetPath);
+
+ foreach (var file in Directory.EnumerateFiles(advertisingPackagePath))
+ {
+ File.Copy(file, Path.Combine(workloadSetPath, Path.GetFileName(file)), overwrite: true);
+ }
+ },
+ rollback: () =>
+ {
+ foreach (var file in Directory.EnumerateFiles(workloadSetPath))
+ {
+ PathUtility.DeleteFileAndEmptyParents(file);
+ }
+ });
+
+ return workloadSetPath;
+ }
+
public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null)
{
var packInfos = GetPacksInWorkloads(workloadIds);
@@ -452,6 +477,15 @@ public void GarbageCollect(Func getResolverForWorkloa
}
+ 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.WorkloadVersion = workloadVersion;
+ File.WriteAllText(path, installStateContents.ToString());
+ }
+
public void RemoveManifestsFromInstallState(SdkFeatureBand sdkFeatureBand)
{
string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkFeatureBand, _dotnetDir), "default.json");
@@ -509,7 +543,14 @@ public void Shutdown()
public PackageId GetManifestPackageId(ManifestId manifestId, SdkFeatureBand featureBand)
{
- return new PackageId($"{manifestId}.Manifest-{featureBand}");
+ if (manifestId.ToString().Equals("Microsoft.NET.Workloads", StringComparison.OrdinalIgnoreCase))
+ {
+ 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/IInstaller.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IInstaller.cs
index 5d388ef8bd21..275d5ecbcdce 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(ITransactionContext context, string advertisingPackagePath);
+
void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null);
void RepairWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, DirectoryPath? offlineCache = null);
@@ -25,6 +27,8 @@ internal interface IInstaller : IWorkloadManifestInstaller
IEnumerable GetDownloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, bool includeInstalledItems);
+ void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadVersion);
+
///
/// 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/IWorkloadManifestUpdater.cs b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs
index d9dec221ad29..49af91545c87 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/IWorkloadManifestUpdater.cs
@@ -8,19 +8,22 @@ 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();
IEnumerable CalculateManifestUpdates();
IEnumerable CalculateManifestRollbacks(string rollbackDefinitionFilePath);
+ IEnumerable ParseRollbackDefinitionFiles(IEnumerable files);
Task> GetManifestPackageDownloadsAsync(bool includePreviews, SdkFeatureBand providedSdkFeatureBand, SdkFeatureBand installedSdkFeatureBand);
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/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx
index b9cd5af6b5dd..6fddf990e564 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/LocalizableStrings.resx
@@ -346,4 +346,13 @@
Manifest MSI not found in NuGet package {0}
+
+ Update to the specified workload version.
+
+
+ Installing workload version {0}.
+
+
+ Updating workload version from {0} to {1}.
+
diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs b/src/Cli/dotnet/commands/dotnet-workload/install/MsiInstallerBase.cs
index ed4dfcbe35c8..8f3b0ca4d4e2 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)
{
@@ -228,6 +226,35 @@ protected void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode)
}
}
+ public void AdjustWorkloadSetInInstallState(SdkFeatureBand sdkFeatureBand, string workloadVersion)
+ {
+ string path = Path.Combine(WorkloadInstallType.GetInstallStateFolder(sdkFeatureBand, DotNetHome), "default.json");
+ var installStateContents = InstallStateContents.FromPath(path);
+ if ((installStateContents.WorkloadVersion == null && workloadVersion == null) ||
+ (installStateContents.WorkloadVersion != null && installStateContents.WorkloadVersion.Equals(workloadVersion)))
+ {
+ return;
+ }
+
+ Elevate();
+
+ if (IsElevated)
+ {
+ // Create the parent folder for the state file and set up all required ACLs
+ installStateContents.WorkloadVersion = workloadVersion;
+ CreateSecureFileInDirectory(path, installStateContents.ToString());
+ }
+ else if (IsClient)
+ {
+ InstallResponseMessage response = Dispatcher.SendUpdateWorkloadSetRequest(sdkFeatureBand, workloadVersion);
+ ExitOnFailure(response, "Failed to update install mode.");
+ }
+ else
+ {
+ throw new InvalidOperationException($"Invalid configuration: elevated: {IsElevated}, client: {IsClient}");
+ }
+ }
+
///
/// Installs the specified MSI.
///
@@ -506,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)
{
@@ -520,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 da42df3373d3..5e22f6bb329d 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;
@@ -257,6 +258,60 @@ public void GarbageCollect(Func getResolverForWorkloa
}
}
+ // advertisingPackagePath is the path to the workload set MSI nupkg in the advertising package.
+ public string InstallWorkloadSet(ITransactionContext context, string advertisingPackagePath)
+ {
+ var pathToReturn = string.Empty;
+ context.Run(
+ action: () =>
+ {
+ pathToReturn = ModifyWorkloadSet(advertisingPackagePath, InstallAction.Install);
+ },
+ rollback: () =>
+ {
+ ModifyWorkloadSet(advertisingPackagePath, InstallAction.Uninstall);
+ });
+
+ return pathToReturn;
+ }
+
+ private string ModifyWorkloadSet(string advertisingPackagePath, InstallAction requestedAction)
+ {
+ ReportPendingReboot();
+
+ // Resolve the package ID for the manifest payload package
+ var featureBand = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath));
+ 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(workloadSetVersion);
+
+ Log?.LogMessage($"Resolving Microsoft.NET.Workloads ({workloadSetVersion}) 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, requestedAction, installedVersion);
+
+ if (plannedAction != InstallAction.None)
+ {
+ Elevate();
+
+ ExecutePackage(msi, plannedAction, msiPackageId);
+
+ // Update the reference count against the MSI.
+ UpdateDependent(
+ plannedAction == InstallAction.Uninstall ?
+ InstallRequestType.RemoveDependent :
+ InstallRequestType.AddDependent,
+ msi.Manifest.ProviderKeyName,
+ _dependent);
+ }
+
+ return Path.Combine(DotNetHome, "sdk-manifests", _sdkFeatureBand.ToString(), "workloadsets", workloadSetVersion);
+ }
+
///
/// 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
@@ -587,7 +642,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", StringComparison.OrdinalIgnoreCase))
+ {
+ 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/NetSdkMsiInstallerServer.cs b/src/Cli/dotnet/commands/dotnet-workload/install/NetSdkMsiInstallerServer.cs
index 02c3bd3ead58..b2522e50e2d6 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/install/WorkloadGarbageCollector.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs
index cf25019d9994..8b75adb64743 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadGarbageCollector.cs
@@ -78,11 +78,11 @@ 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);
- if (!string.IsNullOrEmpty(installState.WorkloadSetVersion))
+ var installState = InstallStateContents.FromPath(installStateFilePath);
+ 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 b5aa34015e8c..7025e5a5bf2b 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallCommand.cs
@@ -43,6 +43,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.WorkloadVersion;
+ }
+
ValidateWorkloadIdsInput();
}
@@ -107,11 +115,24 @@ 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
+ {
+ RunInNewTransaction(context =>
+ {
+ var manifests = HandleWorkloadUpdateFromVersion(context, offlineCache);
+ InstallWorkloadsAndGarbageCollect(context, workloadIds, manifests, offlineCache, false);
+ });
+ }
}
catch (Exception e)
{
@@ -144,32 +165,46 @@ public void InstallWorkloads(IEnumerable workloadIds, bool skipManif
}
}
- if (!skipManifestUpdate)
+ RunInNewTransaction(context =>
{
- if (Verbosity != VerbosityOptions.quiet && Verbosity != VerbosityOptions.q)
+ if (!skipManifestUpdate)
{
- Reporter.WriteLine(LocalizableStrings.CheckForUpdatedWorkloadManifests);
- }
+ if (Verbosity != VerbosityOptions.quiet && Verbosity != VerbosityOptions.q)
+ {
+ Reporter.WriteLine(LocalizableStrings.CheckForUpdatedWorkloadManifests);
+ }
+ // Add workload Ids that already exist to our collection to later trigger an update in those 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();
- // Add workload Ids that already exist to our collection to later trigger an update in those 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());
- }
+ var useWorkloadSets = ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath);
+ useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition);
- workloadIds = workloadIds.Concat(installedWorkloads).Distinct();
+ _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait();
- useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition);
+ if (useWorkloadSets)
+ {
+ manifestsToUpdate = InstallWorkloadSet(context);
+ }
+ else
+ {
+ manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) :
+ _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate);
+ }
+ }
- _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, offlineCache).Wait();
- manifestsToUpdate = useRollback ?
- _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) :
- _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate);
- }
+ InstallWorkloadsAndGarbageCollect(context, workloadIds, manifestsToUpdate, offlineCache, useRollback);
+ });
+ }
- InstallWorkloadsWithInstallRecord(_workloadInstaller, workloadIds, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback);
+ private void InstallWorkloadsAndGarbageCollect(ITransactionContext context, IEnumerable workloadIds, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, bool useRollback)
+ {
+ InstallWorkloadsWithInstallRecord(context, _workloadInstaller, workloadIds, _sdkFeatureBand, manifestsToUpdate, offlineCache, useRollback);
TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache);
@@ -204,6 +239,7 @@ private void WriteSDKInstallRecordsForVSWorkloads()
}
private void InstallWorkloadsWithInstallRecord(
+ ITransactionContext context,
IInstaller installer,
IEnumerable workloadIds,
SdkFeatureBand sdkFeatureBand,
@@ -214,15 +250,8 @@ 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 =>
+ context.Run(
+ action: () =>
{
bool rollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition);
@@ -236,6 +265,8 @@ private void InstallWorkloadsWithInstallRecord(
installer.SaveInstallStateManifestVersions(sdkFeatureBand, GetInstallStateContents(manifestsToUpdate));
}
+ installer.AdjustWorkloadSetInInstallState(sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : _workloadSetVersion);
+
_workloadResolver.RefreshWorkloadManifests();
installer.InstallWorkloads(workloadIds, sdkFeatureBand, context, offlineCache);
@@ -246,13 +277,11 @@ private void InstallWorkloadsWithInstallRecord(
{
recordRepo.WriteWorkloadInstallationRecord(workloadId, sdkFeatureBand);
}
-
},
rollback: () =>
{
// 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()
@@ -282,5 +311,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/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 a7fe27c39f50..bb91d359cdab 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
@@ -72,12 +73,25 @@ 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 UpdateManifestWithVersionAsync("Microsoft.NET.Workloads", includePreviews, _sdkFeatureBand, null, 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 void DownloadWorkloadSet(string version, DirectoryPath? offlineCache = null)
+ {
+ var correctedVersion = WorkloadSetVersionToWorkloadSetPackageVersion(version);
+ await UpdateManifestWithVersionAsync("Microsoft.NET.Workloads", includePreviews: true, _sdkFeatureBand, new NuGetVersion(correctedVersion), offlineCache);
}
public async static Task BackgroundUpdateAdvertisingManifestsAsync(string userProfileDir)
@@ -99,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))
{
@@ -112,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);
@@ -134,6 +155,22 @@ public void DeleteUpdatableWorkloadsFile()
}
}
+ public static string WorkloadSetVersionToWorkloadSetPackageVersion(string setVersion)
+ {
+ 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(SdkFeatureBand sdkFeatureBand, string packageVersion)
+ {
+ 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()
{
try
@@ -196,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())
@@ -205,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);
@@ -261,64 +303,60 @@ 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);
try
{
- SdkFeatureBand? currentFeatureBand = null;
- 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) &&
+ (packageVersion == null || path.Contains(packageVersion.ToString())))
+ .Max() :
+ await _nugetPackageDownloader.DownloadPackageAsync(manifestPackageId, packageVersion: packageVersion, 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 (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();
+ var workloadSetVersion = WorkloadSetPackageVersionToWorkloadSetVersion(_sdkFeatureBand, downloadedPackageVersion.ToString());
+ File.WriteAllText(Path.Combine(adManifestPath, Constants.workloadSetVersionFileName), workloadSetVersion);
+ }
if (_displayManifestUpdates)
{
_reporter.WriteLine(LocalizableStrings.AdManifestUpdated, manifestId);
}
+ return true;
}
catch (Exception e)
{
_reporter.WriteLine(LocalizableStrings.FailedAdManifestUpdate, manifestId, e.Message);
+ return false;
}
finally
{
@@ -343,6 +381,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");
@@ -419,7 +473,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);
+ }
+
+ var reducedFullSet = fullSet.DistinctBy<(ManifestId, ManifestVersionWithBand), ManifestId>(update => update.Item1).ToList();
+ if (fullSet.Count != reducedFullSet.Count)
+ {
+ 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);
+ }
+
+ private static IEnumerable<(ManifestId Id, ManifestVersionWithBand ManifestWithBand)> ParseRollbackDefinitionFile(string rollbackDefinitionFilePath, SdkFeatureBand featureBand)
{
string fileContent;
@@ -439,7 +527,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/install/xlf/LocalizableStrings.cs.xlf b/src/Cli/dotnet/commands/dotnet-workload/install/xlf/LocalizableStrings.cs.xlf
index 720a2aefe836..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
@@ -182,6 +182,11 @@
Odebírání {0}.
+
+ Installing workload version {0}.
+ Installing workload 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,16 @@
Určete, jestli by budoucí operace úloh měly používat sady úloh nebo volné manifesty.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
{0} wird entfernt
+
+ Installing workload version {0}.
+ Installing workload 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,16 @@
Hiermit wird gesteuert, ob zukünftige Workloadvorgänge Workloadsätze oder lose Manifeste verwenden sollen.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
Quitando {0}
+
+ Installing workload version {0}.
+ Installing workload 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,16 @@
Controle si las operaciones de carga de trabajo futuras deben usar conjuntos de cargas de trabajo o manifiestos flexibles.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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 1462fa793077..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
@@ -182,6 +182,11 @@
Suppression de {0}
+
+ Installing workload version {0}.
+ Installing workload 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,16 @@
Contrôlez si les futures opérations de charge de travail doivent utiliser des ensembles de charges de travail ou des manifestes lâches.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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 2f9f807b9fa6..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
@@ -182,6 +182,11 @@
Rimozione di {0}
+
+ Installing workload version {0}.
+ Installing workload 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,16 @@
Controllare se le operazioni future del carico di lavoro devono usare set di carichi di lavoro o manifesti separati.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
{0} を削除しています
+
+ Installing workload version {0}.
+ Installing workload version {0}.
+
+ Failed to establish a trust relationship with parent process ({0}).親プロセス ({0}) との信頼関係を確立できませんでした。
@@ -367,6 +372,16 @@
将来のワークロード操作でワークロード セットを使用するか、ルーズ マニフェストを使用するかを制御します。
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
{0} 제거 중
+
+ Installing workload version {0}.
+ Installing workload version {0}.
+
+ Failed to establish a trust relationship with parent process ({0}).부모 프로세스({0})와 신뢰 관계를 설정하지 못했습니다.
@@ -367,6 +372,16 @@
향후 워크로드 작업에서 워크로드 집합을 사용할지, 매니페스트를 완화할지를 제어합니다.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
Usuwanie {0}
+
+ Installing workload version {0}.
+ Installing workload 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,16 @@
Określ, czy przyszłe operacje związane z obciążeniami powinny wykorzystywać zestawy obciążeń, czy luźne manifesty.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
Removendo {0}
+
+ Installing workload version {0}.
+ Installing workload 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,16 @@
Controle se as operações de carga de trabalho futuras devem usar conjuntos de carga de trabalho ou manifestos flexíveis.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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 b4940992ccc1..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
@@ -182,6 +182,11 @@
Идет удаление {0}
+
+ Installing workload version {0}.
+ Installing workload version {0}.
+
+ Failed to establish a trust relationship with parent process ({0}).Не удалось установить отношение доверия с родительским процессом ({0}).
@@ -367,6 +372,16 @@
Укажите, должны ли будущие операции рабочей нагрузки использовать наборы рабочей нагрузки или свободные манифесты.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
{0} kaldırılıyor
+
+ Installing workload version {0}.
+ Installing workload 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,16 @@
Gelecekteki iş yükü işlemlerinin iş yükü kümelerini mi yoksa gevşek bildirimleri mi kullanması gerektiğini kontrol edin.
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
正在删除 {0}
+
+ Installing workload version {0}.
+ Installing workload version {0}.
+
+ Failed to establish a trust relationship with parent process ({0}).未能建立与父进程({0})之间的信任关系。
@@ -367,6 +372,16 @@
控制未来的工作负载操作应该使用工作负载集还是松散清单。
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ 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..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
@@ -182,6 +182,11 @@
正在移除 {0}
+
+ Installing workload version {0}.
+ Installing workload version {0}.
+
+ Failed to establish a trust relationship with parent process ({0}).無法與父處理序 ({0}) 建立信任關係。
@@ -367,6 +372,16 @@
控制未來的工作負載作業應該使用工作負載集合還是鬆散資訊清單。
+
+ Updating workload version from {0} to {1}.
+ Updating workload version from {0} to {1}.
+
+
+
+ Update to the specified workload version.
+ Update to the specified workload version.
+
+ Workload updates are available. Run `dotnet workload list` for more information.有可用的工作負載更新。如需詳細資訊,請執行 `dotnet workload list`。
diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx b/src/Cli/dotnet/commands/dotnet-workload/list/LocalizableStrings.resx
index b7a929ae43e1..dbb30fdcd881 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 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 2a3d861b517e..93dcc18f90f3 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,13 @@ 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"));
+ if (installState.UseWorkloadSets == true)
+ {
+ Reporter.WriteLine();
+ Reporter.WriteLine(string.Format(LocalizableStrings.WorkloadSetVersion, _workloadListHelper.WorkloadResolver.GetWorkloadVersion() ?? "unknown"));
+ }
+
Reporter.WriteLine();
Reporter.WriteLine(LocalizableStrings.WorkloadListFooter);
Reporter.WriteLine();
@@ -110,6 +117,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.
_workloadManifestUpdater.UpdateAdvertisingManifestsAsync(_includePreviews).Wait();
var manifestsToUpdate = _workloadManifestUpdater.CalculateManifestUpdates();
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..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
@@ -12,6 +12,11 @@
Pokud chcete najít další úlohy, které se mají nainstalovat, použijte `dotnet workload search`.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
Verwenden Sie „dotnet workload search“, um zusätzliche zu installierende Workloads zu finden.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
Use "dotnet workload search" para buscar cargas de trabajo adicionales para instalar.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
Utilisez `dotnet workload search` pour rechercher d’autres charges de travail à installer.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
Utilizzare la `dotnet workload search` per trovare i carichi di lavoro aggiuntivi da installare.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
`dotnet workload search` を使用して追加ワークロードを検出し、インストールします。{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
`dotnet workload search`을 사용하여 설치할 추가 워크로드를 찾습니다.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
Użyj polecenia „dotnet workload search”, aby znaleźć dodatkowe obciążenia do zainstalowania.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
Use `dotnet workload search` para encontrar cargas de trabalho adicionais a serem instaladas.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
Используйте `dotnet workload search`, чтобы найти дополнительные рабочие нагрузки для установки.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
Yüklenecek ek iş yüklerini bulmak için `dotnet workload search` kullanın.{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
使用`dotnet workload search`查找要安装的其他工作负载。{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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..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
@@ -12,6 +12,11 @@
使用 `dotnet workload search` 尋找其他要安裝的工作負載。{Locked="dotnet workload search"}
+
+ Workload version: {0}
+ Workload 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/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 bf09bce1112b..0d14b1fc84f7 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommand.cs
@@ -37,6 +37,7 @@ public WorkloadUpdateCommand(
tempDirPath: tempDirPath)
{
+ _workloadSetVersion = parseResult.GetValue(InstallingWorkloadCommandParser.WorkloadSetVersionOption);
_fromPreviousSdk = parseResult.GetValue(WorkloadUpdateCommandParser.FromPreviousSdkOption);
_adManifestOnlyOption = parseResult.GetValue(WorkloadUpdateCommandParser.AdManifestOnlyOption);
_printRollbackDefinitionOnly = parseResult.GetValue(WorkloadUpdateCommandParser.PrintRollbackOption);
@@ -73,7 +74,13 @@ public override int Execute()
}
else if (_adManifestOnlyOption)
{
- _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(_includePreviews, string.IsNullOrWhiteSpace(_fromCacheOption) ? null : new DirectoryPath(_fromCacheOption)).Wait();
+ _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(
+ _includePreviews,
+ ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath),
+ string.IsNullOrWhiteSpace(_fromCacheOption) ?
+ null :
+ new DirectoryPath(_fromCacheOption))
+ .Wait();
Reporter.WriteLine();
Reporter.WriteLine(LocalizableStrings.WorkloadUpdateAdManifestsSucceeded);
}
@@ -105,7 +112,19 @@ 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))
+ {
+ CalculateManifestUpdatesAndUpdateWorkloads(_includePreviews, offlineCache);
+ }
+ else
+ {
+ RunInNewTransaction(context =>
+ {
+ var manifestUpdates = HandleWorkloadUpdateFromVersion(context, offlineCache);
+ UpdateWorkloads(false, manifestUpdates, offlineCache, context);
+ });
+ }
}
catch (Exception e)
{
@@ -118,29 +137,55 @@ public override int Execute()
return _workloadInstaller.ExitCode;
}
- public void UpdateWorkloads(bool includePreviews = false, DirectoryPath? offlineCache = null)
+ public void CalculateManifestUpdatesAndUpdateWorkloads(bool includePreviews = false, DirectoryPath? offlineCache = null)
{
Reporter.WriteLine();
+ var useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition);
+ var useWorkloadSets = ShouldUseWorkloadSetMode(_sdkFeatureBand, _dotnetPath);
+
+ if (useRollback && useWorkloadSets)
+ {
+ // Rollback files are only for loose manifests. Update the mode to be loose manifests.
+ Reporter.WriteLine(LocalizableStrings.UpdateFromRollbackSwitchesModeToLooseManifests);
+ _workloadInstaller.UpdateInstallMode(_sdkFeatureBand, false);
+ useWorkloadSets = false;
+ }
+
var workloadIds = GetUpdatableWorkloads();
WriteSDKInstallRecordsForVSWorkloads(workloadIds);
- _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, offlineCache).Wait();
+ _workloadManifestUpdater.UpdateAdvertisingManifestsAsync(includePreviews, useWorkloadSets, offlineCache).Wait();
- var useRollback = !string.IsNullOrWhiteSpace(_fromRollbackDefinition);
+ IEnumerable manifestsToUpdate;
+ RunInNewTransaction(context =>
+ {
+ if (useWorkloadSets)
+ {
+ manifestsToUpdate = InstallWorkloadSet(context);
+ }
+ else
+ {
+ manifestsToUpdate = useRollback ? _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) :
+ _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate);
+ }
- var manifestsToUpdate = useRollback ?
- _workloadManifestUpdater.CalculateManifestRollbacks(_fromRollbackDefinition) :
- _workloadManifestUpdater.CalculateManifestUpdates().Select(m => m.ManifestUpdate);
+ UpdateWorkloads(useRollback, manifestsToUpdate, offlineCache, context);
+
+ Reporter.WriteLine();
+ Reporter.WriteLine(string.Format(LocalizableStrings.UpdateSucceeded, string.Join(" ", workloadIds)));
+ Reporter.WriteLine();
+ });
+ }
- UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, useRollback, offlineCache);
+ private void UpdateWorkloads(bool useRollback, IEnumerable manifestsToUpdate, DirectoryPath? offlineCache, ITransactionContext context)
+ {
+ var workloadIds = GetUpdatableWorkloads();
+
+ UpdateWorkloadsWithInstallRecord(_sdkFeatureBand, manifestsToUpdate, useRollback, context, offlineCache);
WorkloadInstallCommand.TryRunGarbageCollection(_workloadInstaller, Reporter, Verbosity, workloadSetVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadSetVersion), offlineCache);
_workloadManifestUpdater.DeleteUpdatableWorkloadsFile();
-
- Reporter.WriteLine();
- Reporter.WriteLine(string.Format(LocalizableStrings.UpdateSucceeded, string.Join(" ", workloadIds)));
- Reporter.WriteLine();
}
private void WriteSDKInstallRecordsForVSWorkloads(IEnumerable updateableWorkloads)
@@ -157,23 +202,11 @@ private void UpdateWorkloadsWithInstallRecord(
SdkFeatureBand sdkFeatureBand,
IEnumerable manifestsToUpdate,
bool useRollback,
+ ITransactionContext context,
DirectoryPath? offlineCache = null)
{
-
- 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(
- action: context =>
+ context.Run(
+ action: () =>
{
foreach (var manifestUpdate in manifestsToUpdate)
{
@@ -189,6 +222,8 @@ private void UpdateWorkloadsWithInstallRecord(
_workloadInstaller.RemoveManifestsFromInstallState(sdkFeatureBand);
}
+ _workloadInstaller.AdjustWorkloadSetInInstallState(sdkFeatureBand, string.IsNullOrWhiteSpace(_workloadSetVersion) ? null : _workloadSetVersion);
+
_workloadResolver.RefreshWorkloadManifests();
var workloads = GetUpdatableWorkloads();
@@ -232,5 +267,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/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs
index fe068fc74b70..787189013bb4 100644
--- a/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs
+++ b/src/Cli/dotnet/commands/dotnet-workload/update/WorkloadUpdateCommandParser.cs
@@ -43,6 +43,7 @@ private static CliCommand ConstructCommand()
command.Options.Add(TempDirOption);
command.Options.Add(FromPreviousSdkOption);
command.Options.Add(AdManifestOnlyOption);
+ 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 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/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/IWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs
index a3acabf746e2..f6a5e9676624 100644
--- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs
+++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs
@@ -14,6 +14,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/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 95e51e8a6e6a..eeefd7dee1c7 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;
@@ -136,15 +131,15 @@ public void RefreshWorkloadManifests()
var installStateFilePath = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkVersionBand, _sdkRootPath), "default.json");
if (File.Exists(installStateFilePath))
{
- var installState = InstallStateReader.ReadInstallState(installStateFilePath);
- if (!string.IsNullOrEmpty(installState.WorkloadSetVersion))
+ var installState = InstallStateContents.FromPath(installStateFilePath);
+ 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;
+ _manifestsFromInstallState = installState.Manifests is null ? new WorkloadSet() : WorkloadSet.FromDictionaryForJson(installState.Manifests, _sdkVersionBand);
_installStateFilePath = installStateFilePath;
}
}
@@ -157,13 +152,18 @@ public void RefreshWorkloadManifests()
}
}
- 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/SdkFeatureBand.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkFeatureBand.cs
index e496e9d757d9..0ce6d4eed582 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);
diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs
index b45a463771b2..a764fb2d9fb5 100644
--- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs
+++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs
@@ -54,6 +54,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 040a0f7a1495..81fdae3f4c2d 100644
--- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs
+++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs
@@ -109,6 +109,8 @@ public void RefreshWorkloadManifests()
ComposeWorkloadManifests();
}
+ public string? GetWorkloadVersion() => _manifestProvider.GetWorkloadVersion();
+
private void LoadManifestsFromProvider(IWorkloadManifestProvider manifestProvider)
{
foreach (var readableManifest in manifestProvider.GetManifests())
@@ -741,6 +743,7 @@ public void RefreshWorkloadManifests() { }
public Dictionary GetAvailableWorkloadSets() => new();
public IEnumerable GetManifests() => Enumerable.Empty();
public string GetSdkFeatureBand() => _sdkFeatureBand;
+ public string? GetWorkloadVersion() => _sdkFeatureBand.ToString() + ".2";
}
}
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 1c16e13b948b..e1e67af18320 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
@@ -90,6 +90,7 @@
+
diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs
index 92ddb64a0829..7c8fa003a368 100644
--- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs
+++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs
@@ -40,6 +40,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)>
@@ -66,5 +67,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/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs
index 13a4f6d3570b..44bf3f961184 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""
}
");
}
@@ -494,7 +494,7 @@ public void ItUsesWorkloadSetFromGlobalJson()
{
"sdk": {
"version": "8.0.200",
- "workloadversion": "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",
- "workloadversion": "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": {
- "workloadversion": [ "8.0.202" ]
+ "workloadVersion": [ "8.0.202" ]
}
}
""");
@@ -862,7 +862,7 @@ public void ItFallsBackForManifestNotInInstallState()
"""
{
"manifests": {
- "ios": "12.0.1/8.0.200",
+ "ios": "12.0.1/8.0.200"
}
}
""");
@@ -885,7 +885,7 @@ public void GlobalJsonOverridesInstallState()
{
"sdk": {
"version": "8.0.200",
- "workloadversion": "8.0.201"
+ "workloadVersion": "8.0.201"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2",
diff --git a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs
index 029d28fd9ee6..1a12d4ccb8b9 100644
--- a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs
+++ b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs
@@ -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/MockManifestProvider.cs b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs
index f3298b0d654b..935fb9addfe8 100644
--- a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs
+++ b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs
@@ -48,5 +48,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 37a204706607..fb4b3924dea5 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
{
@@ -24,13 +25,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 +40,7 @@ public MockPackWorkloadInstaller(string dotnetDir, string failingWorkload = null
FailingPack = failingPack;
FailingGarbageCollection = failingGarbageCollection;
_dotnetDir = dotnetDir;
+ this.workloadSetContents = workloadSetContents;
}
IEnumerable GetPacksForWorkloads(IEnumerable workloadIds)
@@ -61,6 +64,17 @@ public void UpdateInstallMode(SdkFeatureBand sdkFeatureBand, bool newMode)
throw new NotImplementedException();
}
+ 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.WorkloadVersion = workloadVersion;
+ if (File.Exists(installStatePath))
+ {
+ File.WriteAllText(installStatePath, contents.ToString());
+ }
+ }
+
public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand sdkFeatureBand, ITransactionContext transactionContext, DirectoryPath? offlineCache = null)
{
List packs = new List();
@@ -91,6 +105,14 @@ public void InstallWorkloads(IEnumerable workloadIds, SdkFeatureBand
});
}
+ public string InstallWorkloadSet(ITransactionContext context, string advertisingPackagePath)
+ {
+ var version = Path.GetFileName(Path.GetDirectoryName(advertisingPackagePath ?? string.Empty));
+ Directory.CreateDirectory(advertisingPackagePath);
+ File.WriteAllText(Path.Combine(advertisingPackagePath, Constants.workloadSetVersionFileName), version);
+ return Path.GetDirectoryName(advertisingPackagePath ?? string.Empty);
+ }
+
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 6a3d90073c64..3b7a0275a2e6 100644
--- a/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs
+++ b/src/Tests/dotnet-workload-install.Tests/MockWorkloadManifestUpdater.cs
@@ -13,13 +13,15 @@ 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, DirectoryPath? cachePath = null)
+ public Task UpdateAdvertisingManifestsAsync(bool includePreview, bool useWorkloadSets = false, DirectoryPath? cachePath = null)
{
UpdateAdvertisingManifestsCallCount++;
return Task.CompletedTask;
@@ -42,11 +44,19 @@ 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);
}
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();
+ public IEnumerable ParseRollbackDefinitionFiles(IEnumerable files) => _manifestUpdates.Select(t => t.ManifestUpdate);
}
}
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"
}
}
""");
diff --git a/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs b/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs
index 0a769ee235ea..5a9bdd9cb706 100644
--- a/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs
+++ b/src/Tests/dotnet-workload-search.Tests/MockWorkloadResolver.cs
@@ -17,17 +17,18 @@ 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();
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();
diff --git a/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs b/src/Tests/dotnet-workload-update.Tests/GivenDotnetWorkloadUpdate.cs
index 896569702333..ef980e0ba4d4 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,64 @@ 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;
+ var versionFile = Path.Combine("userProfileDir", "sdk-advertising", "8.0.0", "microsoft.net.workloads", Constants.workloadSetVersionFileName);
+ try
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(installStatePath));
+ File.WriteAllText(installStatePath, contents.ToString());
+ updateCommand.Execute();
+ File.Exists(versionFile).Should().BeTrue();
+ File.ReadAllText(versionFile).Should().Be("8.0.0");
+ }
+ finally
+ {
+ if (File.Exists(versionFile))
+ {
+ File.Delete(versionFile);
+ }
+
+ if (File.Exists(installStatePath))
+ {
+ File.Delete(installStatePath);
+ }
+ }
+
+ workloadInstaller.InstalledManifests.Count.Should().Be(1);
+ workloadInstaller.InstalledManifests[0].manifestUpdate.NewVersion.ToString().Should().Be("2.3.4");
+ }
+
[Fact]
public void GivenWorkloadUpdateItRollsBackOnFailedUpdate()
{
@@ -332,7 +391,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);
@@ -362,7 +421,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);