File: Utils\SdkInstallHelper.cs
Web Access
Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Globalization;
using Aspire.Cli.Configuration;
using Aspire.Cli.DotNet;
using Aspire.Cli.Interaction;
using Aspire.Cli.Resources;
 
namespace Aspire.Cli.Utils;
 
/// <summary>
/// Helper class for managing SDK installation UX and user interaction.
/// </summary>
internal static class SdkInstallHelper
{
    /// <summary>
    /// Ensures that the .NET SDK is installed and available, displaying an error message if it's not.
    /// If the SDK is missing, prompts the user to install it automatically (if in interactive mode and feature is enabled).
    /// </summary>
    /// <param name="sdkInstaller">The SDK installer service.</param>
    /// <param name="interactionService">The interaction service for user communication.</param>
    /// <param name="features">The features service for checking if SDK installation is enabled.</param>
    /// <param name="hostEnvironment">The CLI host environment for detecting interactive capabilities.</param>
    /// <param name="cancellationToken">Cancellation token.</param>
    /// <returns>True if the SDK is available, false if it's missing.</returns>
    public static async Task<bool> EnsureSdkInstalledAsync(
        IDotNetSdkInstaller sdkInstaller,
        IInteractionService interactionService,
        IFeatures features,
        ICliHostEnvironment? hostEnvironment = null,
        CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(sdkInstaller);
        ArgumentNullException.ThrowIfNull(interactionService);
        ArgumentNullException.ThrowIfNull(features);
 
        var (success, highestVersion, minimumRequiredVersion, forceInstall) = await sdkInstaller.CheckAsync(cancellationToken);
 
        if (!success || forceInstall)
        {
            var detectedVersion = highestVersion ?? "(not found)";
            
            // Only display error if SDK is actually missing
            if (!success)
            {
                var sdkErrorMessage = string.Format(CultureInfo.InvariantCulture, 
                    ErrorStrings.MinimumSdkVersionNotMet, 
                    minimumRequiredVersion, 
                    detectedVersion);
                interactionService.DisplayError(sdkErrorMessage);
            }
 
            // Only offer to install if:
            // 1. The feature is enabled (default: false)
            // 2. We support interactive input OR forceInstall is true (for testing)
            if (features.IsFeatureEnabled(KnownFeatures.DotNetSdkInstallationEnabled, defaultValue: false) &&
                (hostEnvironment?.SupportsInteractiveInput == true || forceInstall))
            {
                bool shouldInstall;
                
                if (forceInstall)
                {
                    // When alwaysInstallSdk is true, skip the prompt and install directly
                    shouldInstall = true;
                    interactionService.DisplayMessage("information", 
                        "alwaysInstallSdk is enabled - forcing SDK installation for testing purposes.");
                }
                else
                {
                    // Offer to install the SDK automatically
                    shouldInstall = await interactionService.ConfirmAsync(
                        string.Format(CultureInfo.InvariantCulture,
                            "Would you like to install .NET SDK {0} automatically?",
                            minimumRequiredVersion),
                        defaultValue: true,
                        cancellationToken: cancellationToken);
                }
 
                if (shouldInstall)
                {
                    try
                    {
                        await interactionService.ShowStatusAsync(
                            string.Format(CultureInfo.InvariantCulture,
                                "Downloading and installing .NET SDK {0}... This may take a few minutes.",
                                minimumRequiredVersion),
                            async () =>
                            {
                                await sdkInstaller.InstallAsync(cancellationToken);
                                return 0; // Return dummy value for ShowStatusAsync
                            });
 
                        interactionService.DisplaySuccess(
                            string.Format(CultureInfo.InvariantCulture,
                                ".NET SDK {0} has been installed successfully.",
                                minimumRequiredVersion));
 
                        return true;
                    }
                    catch (Exception ex)
                    {
                        interactionService.DisplayError(
                            string.Format(CultureInfo.InvariantCulture,
                                "Failed to install .NET SDK: {0}",
                                ex.Message));
                        return false;
                    }
                }
            }
 
            // If we didn't install and SDK check failed, return false
            return success;
        }
 
        return true;
    }
}