| File: Commands\Workload\Clean\WorkloadCleanCommand.cs | Web Access |
| Project: src\sdk\src\Cli\dotnet\dotnet.csproj (dotnet) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.CommandLine; using Microsoft.Deployment.DotNet.Releases; using Microsoft.DotNet.Cli.Commands.Workload.Install; using Microsoft.DotNet.Cli.Commands.Workload.List; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils.Extensions; using Microsoft.NET.Sdk.WorkloadManifestReader; namespace Microsoft.DotNet.Cli.Commands.Workload.Clean; internal sealed class WorkloadCleanCommand : WorkloadCommandBase<WorkloadCleanCommandDefinition> { private readonly bool _cleanAll; private readonly string _dotnetPath; private readonly string _userProfileDir; private readonly ReleaseVersion _sdkVersion; private readonly IInstaller _workloadInstaller; private readonly IWorkloadResolverFactory _workloadResolverFactory; public WorkloadCleanCommand( ParseResult parseResult, IReporter? reporter = null, IWorkloadResolverFactory? workloadResolverFactory = null) : base(parseResult, reporter: reporter) { _cleanAll = parseResult.GetValue(Definition.CleanAllOption); _workloadResolverFactory = workloadResolverFactory ?? new WorkloadResolverFactory(); if (!string.IsNullOrEmpty(parseResult.GetValue(Definition.SdkVersionOption))) { throw new GracefulException(CliCommandStrings.SdkVersionOptionNotSupported); } var creationResult = _workloadResolverFactory.Create(); _dotnetPath = creationResult.DotnetPath; _userProfileDir = creationResult.UserProfileDir; _sdkVersion = creationResult.SdkVersion; var sdkFeatureBand = new SdkFeatureBand(_sdkVersion); _workloadInstaller = WorkloadInstallerFactory.GetWorkloadInstaller(Reporter, sdkFeatureBand, creationResult.WorkloadResolver, Verbosity, creationResult.UserProfileDir, VerifySignatures, PackageDownloader, creationResult.DotnetPath); } public override int Execute() { ExecuteGarbageCollection(); return 0; } private void ExecuteGarbageCollection() { _workloadInstaller.GarbageCollect(workloadVersion => _workloadResolverFactory.CreateForWorkloadSet(_dotnetPath, _sdkVersion.ToString(), _userProfileDir, workloadVersion), cleanAllPacks: _cleanAll); DisplayUninstallableVSWorkloads(); } /// <summary> /// Print VS Workloads with the same machine arch which can't be uninstalled through the SDK CLI to increase user awareness that they must uninstall via VS. /// </summary> private void DisplayUninstallableVSWorkloads() { #if TARGET_WINDOWS // We don't want to print MSI related content in a file-based installation. if (!(_workloadInstaller.GetType() == typeof(NetSdkMsiInstallerClient))) { return; } if (OperatingSystem.IsWindows()) { // All VS Workloads should have a corresponding MSI based SDK. This means we can pull all of the VS SDK feature bands using MSI/VS related registry keys. var installedSDKVersionsWithPotentialVSRecords = MsiInstallerBase.GetInstalledSdkVersions(); HashSet<string> vsWorkloadUninstallWarnings = []; string defaultDotnetWinPath = MsiInstallerBase.GetDotNetHome(); foreach (string sdkVersion in installedSDKVersionsWithPotentialVSRecords) { try { #pragma warning disable CS8604 // We error in the constructor if the dotnet path is null. // We don't know if the dotnet installation for the other bands is in a different directory than the current dotnet; check the default directory if it isn't. var bandedDotnetPath = Path.Exists(Path.Combine(_dotnetPath, "sdk", sdkVersion)) ? _dotnetPath : defaultDotnetWinPath; if (!Path.Exists(bandedDotnetPath)) { Reporter.WriteLine(string.Format(CliCommandStrings.CannotAnalyzeVSWorkloadBand, sdkVersion, _dotnetPath, defaultDotnetWinPath).Yellow()); continue; } var workloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(bandedDotnetPath, sdkVersion, _userProfileDir, SdkDirectoryWorkloadManifestProvider.GetGlobalJsonPath(Environment.CurrentDirectory)); var bandedResolver = WorkloadResolver.Create(workloadManifestProvider, bandedDotnetPath, sdkVersion.ToString(), _userProfileDir); #pragma warning restore CS8604 InstalledWorkloadsCollection vsWorkloads = new(); VisualStudioWorkloads.GetInstalledWorkloads(bandedResolver, vsWorkloads, _cleanAll ? null : new SdkFeatureBand(sdkVersion)); foreach (var vsWorkload in vsWorkloads.AsEnumerable()) { vsWorkloadUninstallWarnings.Add(string.Format(CliCommandStrings.VSWorkloadNotRemoved, $"{vsWorkload.Key}", $"{vsWorkload.Value}")); } } catch (WorkloadManifestException ex) { // Limitation: We don't know the dotnetPath of the other feature bands when making the manifestProvider and resolvers. // This can cause the manifest resolver to fail as it may look for manifests in an invalid path. // It can theoretically be customized, but that is not currently supported for workloads with VS. Reporter.WriteLine(string.Format(CliCommandStrings.CannotAnalyzeVSWorkloadBand, sdkVersion, _dotnetPath, defaultDotnetWinPath).Yellow()); Utils.Reporter.Verbose.WriteLine(ex.Message); } } foreach (string warning in vsWorkloadUninstallWarnings) { Reporter.WriteLine(warning.Yellow()); } } #endif } }