diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx
index 018bcfd494b5..b0783aff2301 100644
--- a/src/Cli/dotnet/Commands/CliCommandStrings.resx
+++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx
@@ -2691,4 +2691,7 @@ Proceed?
duration:
+
+ Successfully removed all workload sets, manifests, and installation state.
+
diff --git a/src/Cli/dotnet/Commands/Workload/Install/FileBasedInstaller.cs b/src/Cli/dotnet/Commands/Workload/Install/FileBasedInstaller.cs
index 933eeac911b5..9b4da76973f5 100644
--- a/src/Cli/dotnet/Commands/Workload/Install/FileBasedInstaller.cs
+++ b/src/Cli/dotnet/Commands/Workload/Install/FileBasedInstaller.cs
@@ -557,6 +557,7 @@ public void GarbageCollect(Func getResolverForWorkloa
if (cleanAllPacks)
{
DeleteAllWorkloadInstallationRecords();
+ DeleteAllWorkloadSetsAndManifests();
}
}
@@ -621,6 +622,96 @@ private void DeleteAllWorkloadInstallationRecords()
}
}
+ ///
+ /// Deletes all workload sets, manifests, and install state files across all feature bands.
+ /// This is used by 'dotnet workload clean --all' to completely reset workloads to a clean state.
+ ///
+ private void DeleteAllWorkloadSetsAndManifests()
+ {
+ Reporter.Verbose.WriteLine("Removing all workload sets and manifests...");
+
+ // Delete all workload sets and manifests from sdk-manifests directory
+ string sdkManifestsRoot = Path.Combine(_workloadRootDir, "sdk-manifests");
+ if (Directory.Exists(sdkManifestsRoot))
+ {
+ // Iterate through all feature band directories
+ foreach (var featureBandDir in Directory.GetDirectories(sdkManifestsRoot))
+ {
+ string featureBand = Path.GetFileName(featureBandDir);
+
+ // Delete workload sets directory for this feature band
+ string workloadSetsDir = Path.Combine(featureBandDir, SdkDirectoryWorkloadManifestProvider.WorkloadSetsFolderName);
+ if (Directory.Exists(workloadSetsDir))
+ {
+ Reporter.Verbose.WriteLine($"Deleting workload sets directory: {workloadSetsDir}");
+ Directory.Delete(workloadSetsDir, true);
+ }
+
+ // Delete all manifest directories for this feature band (except workloadsets folder)
+ foreach (var manifestDir in Directory.GetDirectories(featureBandDir))
+ {
+ string dirName = Path.GetFileName(manifestDir);
+ if (!string.Equals(dirName, SdkDirectoryWorkloadManifestProvider.WorkloadSetsFolderName, StringComparison.OrdinalIgnoreCase))
+ {
+ Reporter.Verbose.WriteLine($"Deleting manifest directory: {manifestDir}");
+ Directory.Delete(manifestDir, true);
+ }
+ }
+
+ // Delete the feature band directory if it's now empty
+ if (Directory.Exists(featureBandDir) && !Directory.GetFileSystemEntries(featureBandDir).Any())
+ {
+ Directory.Delete(featureBandDir);
+ }
+ }
+ }
+
+ // Delete all install state files
+ string metadataWorkloadsRoot = Path.Combine(_workloadRootDir, "metadata", "workloads");
+ if (Directory.Exists(metadataWorkloadsRoot))
+ {
+ foreach (var archDir in Directory.GetDirectories(metadataWorkloadsRoot))
+ {
+ foreach (var featureBandDir in Directory.GetDirectories(archDir))
+ {
+ string installStateDir = Path.Combine(featureBandDir, "InstallState");
+ if (Directory.Exists(installStateDir))
+ {
+ string defaultJsonPath = Path.Combine(installStateDir, "default.json");
+ if (File.Exists(defaultJsonPath))
+ {
+ Reporter.Verbose.WriteLine($"Deleting install state file: {defaultJsonPath}");
+ File.Delete(defaultJsonPath);
+ }
+
+ // Delete InstallState directory if it's now empty
+ if (Directory.Exists(installStateDir) && !Directory.GetFileSystemEntries(installStateDir).Any())
+ {
+ Directory.Delete(installStateDir);
+ }
+ }
+ }
+ }
+ }
+
+ // Also delete installation records for workload sets and manifests
+ string installedWorkloadSetsDir = Path.Combine(_workloadMetadataDir, InstalledWorkloadSetsDir);
+ if (Directory.Exists(installedWorkloadSetsDir))
+ {
+ Reporter.Verbose.WriteLine($"Deleting workload sets installation records: {installedWorkloadSetsDir}");
+ Directory.Delete(installedWorkloadSetsDir, true);
+ }
+
+ string installedManifestsDir = Path.Combine(_workloadMetadataDir, InstalledManifestsDir);
+ if (Directory.Exists(installedManifestsDir))
+ {
+ Reporter.Verbose.WriteLine($"Deleting manifest installation records: {installedManifestsDir}");
+ Directory.Delete(installedManifestsDir, true);
+ }
+
+ _reporter.WriteLine(CliCommandStrings.WorkloadCleanAllComplete);
+ }
+
string GetWorkloadHistoryDirectory()
{
return Path.Combine(_workloadMetadataDir, RuntimeInformation.ProcessArchitecture.ToString(), _sdkFeatureBand.ToString(), HistoryDir);
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
index 4971fb9bd45d..72f798c0fcd1 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
@@ -3778,6 +3778,11 @@ příkazu „dotnet tool list“.
{0} úlohy jsou už nainstalované.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Odebere součásti úloh, které mohly být pozůstatky z předchozích aktualizací a odinstalací.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
index 057029c7af1a..6306dccbf1f1 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
@@ -3778,6 +3778,11 @@ und die zugehörigen Paket-IDs für installierte Tools über den Befehl
Workloads '{0}' sind bereits installiert.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Entfernt Workloadkomponenten, die möglicherweise von vorherigen Updates und Deinstallationen zurückgelassen wurden.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
index e18effb56956..6c9949c1e6c3 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
@@ -3778,6 +3778,11 @@ y los identificadores de los paquetes correspondientes a las herramientas instal
Las cargas de trabajo "{0}" ya están instaladas.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Quita los componentes de carga de trabajo que pueden haberse dejado de las actualizaciones y desinstalaciones anteriores.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
index 6c9a04f60f09..cd59d6de4bc7 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
@@ -3778,6 +3778,11 @@ et les ID de package correspondants aux outils installés, utilisez la commande
La ou les charges de travail '{0}' sont déjà installées.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Supprime les composants de charge de travail qui ont peut-être été laissés en arrière des mises à jour et désinstallations précédentes.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
index 116c2ef17473..88dc56250b3f 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
@@ -3778,6 +3778,11 @@ e gli ID pacchetto corrispondenti per gli strumenti installati usando il comando
I carichi di lavoro '{0}' sono già installati.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Rimuove i componenti del carico di lavoro che potrebbero essere stati lasciati indietro da aggiornamenti e disinstallazioni precedenti.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
index 09e0b370a21d..ffbb70405a3a 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
@@ -3778,6 +3778,11 @@ and the corresponding package Ids for installed tools using the command
ワークロード '{0}' は既にインストールされています。
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.以前の更新プログラムとアンインストールで取り残された可能性のあるワークロード コンポーネントを削除します。
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
index d18f0a43e10d..f850d6e18185 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
@@ -3778,6 +3778,11 @@ and the corresponding package Ids for installed tools using the command
'{0}' 워크로드가 이미 설치되어 있습니다.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.이전 업데이트 및 제거에서 남아 있을 수 있는 워크로드 구성 요소를 제거합니다.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
index 59b0e6816f14..1b0f7b332a16 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
@@ -3778,6 +3778,11 @@ i odpowiednie identyfikatory pakietów zainstalowanych narzędzi można znaleź
Pakiety robocze „{0}” są już zainstalowane.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Usuwa składniki obciążenia, które mogły zostać pominięte w poprzednich aktualizacjach i dezinstalacjach.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
index 8a5ba6e0315d..86c39b381609 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
@@ -3778,6 +3778,11 @@ e as Ids de pacote correspondentes para as ferramentas instaladas usando o coman
A(s) carga(s) de trabalho '{0}' já está(ão) instalada(s).
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Remove componentes de carga de trabalho que podem ter sido deixados para trás em atualizações e desinstalações anteriores.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
index 544ec14a21f1..f1d08145e523 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
@@ -3779,6 +3779,11 @@ and the corresponding package Ids for installed tools using the command
Рабочие нагрузки "{0}" уже установлены.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Удаляет компоненты рабочей нагрузки, которые могли остаться после предыдущих обновлений и удалений.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
index 500968f42977..d5ef5d30ba98 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
@@ -3778,6 +3778,11 @@ karşılık gelen paket kimliklerini bulmak için
'{0}' iş yükleri zaten yüklü.
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.Önceki güncelleştirme ve kaldırma işlemlerinden kalmış olabilecek iş yükü bileşenlerini kaldırır.
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
index f2850c8dd0f2..ad092d725edb 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
@@ -3778,6 +3778,11 @@ and the corresponding package Ids for installed tools using the command
已安装工作负载“{0}”。
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.删除可能已从之前的更新和卸载中保留的工作负载组件。
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
index 17a521f0c546..68c0a0ab5e48 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
@@ -3778,6 +3778,11 @@ and the corresponding package Ids for installed tools using the command
已安裝工作負載 '{0}'。
+
+ Successfully removed all workload sets, manifests, and installation state.
+ Successfully removed all workload sets, manifests, and installation state.
+
+ Removes workload components that may have been left behind from previous updates and uninstallations.移除先前更新和解除安裝中可能遺漏的工作負載元件。
diff --git a/test/dotnet.Tests/CommandTests/Solution/List/GivenDotnetSlnList.cs b/test/dotnet.Tests/CommandTests/Solution/List/GivenDotnetSlnList.cs
index 663fd71efa83..22ae9d7059fe 100644
--- a/test/dotnet.Tests/CommandTests/Solution/List/GivenDotnetSlnList.cs
+++ b/test/dotnet.Tests/CommandTests/Solution/List/GivenDotnetSlnList.cs
@@ -308,7 +308,7 @@ public void WhenSolutionFilterWithTrailingCommaIsPassedItListsProjects(string so
$"{new string('-', CliCommandStrings.ProjectsHeader.Length)}",
$"{Path.Combine("App", "App.csproj")}",
$"{Path.Combine("Lib", "Lib.csproj")}" };
- var projectDirectory = _testAssetsManager
+ var projectDirectory = TestAssetsManager
.CopyTestAsset("TestAppWithTrailingCommaSlnf", identifier: "GivenDotnetSlnList-TrailingComma")
.WithSource()
.Path;
@@ -328,7 +328,7 @@ public void WhenSolutionFilterWithCommentsIsPassedItListsProjects(string solutio
string[] expectedOutput = { $"{CliCommandStrings.ProjectsHeader}",
$"{new string('-', CliCommandStrings.ProjectsHeader.Length)}",
$"{Path.Combine("App", "App.csproj")}" };
- var projectDirectory = _testAssetsManager
+ var projectDirectory = TestAssetsManager
.CopyTestAsset("TestAppWithTrailingCommaSlnf", identifier: "GivenDotnetSlnList-Comments")
.WithSource()
.Path;
diff --git a/test/dotnet.Tests/CommandTests/Workload/Clean/GivenDotnetWorkloadClean.cs b/test/dotnet.Tests/CommandTests/Workload/Clean/GivenDotnetWorkloadClean.cs
index f9110dbda964..382f4a8b594a 100644
--- a/test/dotnet.Tests/CommandTests/Workload/Clean/GivenDotnetWorkloadClean.cs
+++ b/test/dotnet.Tests/CommandTests/Workload/Clean/GivenDotnetWorkloadClean.cs
@@ -109,6 +109,56 @@ public void GivenWorkloadCleanAllFileBasedItCleansAllFeatureBands(bool userLocal
AssertValidPackCountsMatchExpected(installRoot, expectedPackCount: 0, expectedPackRecordCount: 0);
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void GivenWorkloadCleanAllFileBasedItRemovesWorkloadSetsAndManifests(bool userLocal)
+ {
+ var (testDirectory, dotnetRoot, userProfileDir, workloadResolver, nugetDownloader) = Setup(userLocal, true);
+
+ string installRoot = userLocal ? userProfileDir : dotnetRoot;
+ if (userLocal)
+ {
+ WorkloadFileBasedInstall.SetUserLocal(dotnetRoot, _sdkFeatureVersion);
+ }
+
+ // Create fake workload set directories
+ var workloadSetDir = Path.Combine(installRoot, "sdk-manifests", _sdkFeatureVersion, "workloadsets", "9.0.100");
+ Directory.CreateDirectory(workloadSetDir);
+ File.WriteAllText(Path.Combine(workloadSetDir, "9.0.100.workloadset.json"), "{}");
+
+ // Create fake manifest directories
+ var manifestDir = Path.Combine(installRoot, "sdk-manifests", _sdkFeatureVersion, "test.manifest", "1.0.0");
+ Directory.CreateDirectory(manifestDir);
+ File.WriteAllText(Path.Combine(manifestDir, "WorkloadManifest.json"), "{}");
+
+ // Create fake install state file
+ var installStateDir = Path.Combine(installRoot, "metadata", "workloads", RuntimeInformation.ProcessArchitecture.ToString(), _sdkFeatureVersion, "InstallState");
+ Directory.CreateDirectory(installStateDir);
+ var installStateFile = Path.Combine(installStateDir, "default.json");
+ File.WriteAllText(installStateFile, "{}");
+
+ // Create fake installation records for workload sets and manifests
+ var installedWorkloadSetsDir = Path.Combine(installRoot, "metadata", "workloads", "InstalledWorkloadSets");
+ Directory.CreateDirectory(installedWorkloadSetsDir);
+ File.WriteAllText(Path.Combine(installedWorkloadSetsDir, "test"), "");
+
+ var installedManifestsDir = Path.Combine(installRoot, "metadata", "workloads", "InstalledManifests");
+ Directory.CreateDirectory(installedManifestsDir);
+ File.WriteAllText(Path.Combine(installedManifestsDir, "test"), "");
+
+ // Execute clean --all
+ var cleanCommand = GenerateWorkloadCleanAllCommand(workloadResolver, userProfileDir, dotnetRoot);
+ cleanCommand.Execute();
+
+ // Verify all artifacts are removed
+ new DirectoryInfo(workloadSetDir).Should().NotExist("workload set directory should be removed");
+ new DirectoryInfo(manifestDir).Should().NotExist("manifest directory should be removed");
+ new FileInfo(installStateFile).Should().NotExist("install state file should be removed");
+ new DirectoryInfo(installedWorkloadSetsDir).Should().NotExist("workload set installation records should be removed");
+ new DirectoryInfo(installedManifestsDir).Should().NotExist("manifest installation records should be removed");
+ }
+
private void InstallWorkload(string userProfileDir, string dotnetRoot, string testDirectory, WorkloadResolver workloadResolver, MockNuGetPackageDownloader nugetDownloader, string sdkBand = null)
{
sdkBand ??= _sdkFeatureVersion;