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;