| File: Commands\Workload\WorkloadInstallDetector.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 Microsoft.DotNet.Cli.Commands.Workload.Install.WorkloadInstallRecords; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Configurer; using Microsoft.NET.Sdk.WorkloadManifestReader; namespace Microsoft.DotNet.Cli.Commands.Workload; /// <summary> /// Read-only, dependency-light detection of whether any workloads are installed for the running /// SDK's feature band. /// /// <para> /// <see cref="WorkloadIntegrityChecker.RunFirstUseCheck"/> only performs an (expensive) repair when /// installed workloads exist; the resolver/installer plumbing it uses to discover that fact drags in /// the NuGet engine (and, on Windows, the MSI installer IPC). This type answers the same "are any /// workloads installed?" question by reading only the filesystem and registry, so it has no NuGet, /// MSBuild, cryptography, or installer-IPC dependencies and can run in-process under NativeAOT. The /// repair itself stays on the managed CLI. /// </para> /// </summary> internal static class WorkloadInstallDetector { /// <summary> /// Returns <see langword="true"/> if at least one workload is recorded as installed for the /// current SDK feature band. File-based installs are read from the workload metadata directory; /// MSI-based installs (Windows) are read from the machine registry. /// </summary> /// <param name="dotnetDir"> /// The dotnet root to inspect. Defaults to the directory of the running process. /// </param> public static bool HasInstalledWorkloadsForCurrentBand(string? dotnetDir = null) { dotnetDir = string.IsNullOrWhiteSpace(dotnetDir) ? Path.GetDirectoryName(Environment.ProcessPath) : dotnetDir; var sdkFeatureBand = new SdkFeatureBand(Product.Version); return WorkloadInstallType.GetWorkloadInstallType(sdkFeatureBand, dotnetDir) switch { InstallType.Msi => HasMsiWorkloadRecords(sdkFeatureBand), _ => HasFileBasedWorkloadRecords(dotnetDir, sdkFeatureBand), }; } private static bool HasFileBasedWorkloadRecords(string? dotnetDir, SdkFeatureBand sdkFeatureBand) { // Records live under {workloadRoot}/metadata/workloads, where workloadRoot is the user profile // for user-local installs and the dotnet root otherwise. This mirrors the layout used by // FileBasedInstaller / FileBasedInstallationRecordRepository. if (dotnetDir is null) { return false; } return FileBasedWorkloadInstallationRecordRepositoryFactory .Create(dotnetDir, sdkFeatureBand, CliFolderPathCalculator.DotnetUserProfileFolderPath) .GetInstalledWorkloads(sdkFeatureBand) .Any(); } private static bool HasMsiWorkloadRecords(SdkFeatureBand sdkFeatureBand) { if (!OperatingSystem.IsWindows()) { return false; } return new ReadOnlyWindowsWorkloadInstallationRecordRepository() .GetInstalledWorkloads(sdkFeatureBand) .Any(); } }