File: Commands\UpdateCommand.cs
Web Access
Project: src\src\Aspire.Cli\Aspire.Cli.Tool.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.CommandLine;
using Aspire.Cli.Configuration;
using Aspire.Cli.Interaction;
using Aspire.Cli.Packaging;
using Aspire.Cli.Projects;
using Aspire.Cli.Resources;
using Aspire.Cli.Utils;
using Spectre.Console;
 
namespace Aspire.Cli.Commands;
 
internal sealed class UpdateCommand : BaseCommand
{
    private readonly IProjectLocator _projectLocator;
    private readonly IInteractionService _interactionService;
    private readonly IPackagingService _packagingService;
    private readonly IProjectUpdater _projectUpdater;
 
    public UpdateCommand(IProjectLocator projectLocator, IPackagingService packagingService, IProjectUpdater projectUpdater, IInteractionService interactionService, IFeatures features, ICliUpdateNotifier updateNotifier) : base("update", UpdateCommandStrings.Description, features, updateNotifier)
    {
        ArgumentNullException.ThrowIfNull(projectLocator);
        ArgumentNullException.ThrowIfNull(interactionService);
        ArgumentNullException.ThrowIfNull(packagingService);
        ArgumentNullException.ThrowIfNull(projectUpdater);
 
        _projectLocator = projectLocator;
        _interactionService = interactionService;
        _packagingService = packagingService;
        _projectUpdater = projectUpdater;
    }
 
    protected override async Task<int> ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken)
    {
        try
        {
            var projectFile = await _projectLocator.UseOrFindAppHostProjectFileAsync(null, cancellationToken);
 
            // Fail fast if central package management is detected, before prompting for channels.
            if (projectFile is not null && UsesCentralPackageManagement(projectFile))
            {
                _interactionService.DisplayError(UpdateCommandStrings.CentralPackageManagementNotSupported);
                return ExitCodeConstants.CentralPackageManagementNotSupported;
            }
            var channels = await _packagingService.GetChannelsAsync(cancellationToken);
 
            var channel = await _interactionService.PromptForSelectionAsync(UpdateCommandStrings.SelectChannelPrompt, channels, (c) => c.Name, cancellationToken);
 
            await _projectUpdater.UpdateProjectAsync(projectFile!, channel, cancellationToken);
        }
        catch (ProjectUpdaterException ex)
        {
            var message = Markup.Escape(ex.Message);
            _interactionService.DisplayError(message);
            return ExitCodeConstants.FailedToUpgradeProject;
        }
        catch (ProjectLocatorException ex)
        {
            return HandleProjectLocatorException(ex, _interactionService);
        }
 
        return 0;
    }
 
    private static bool UsesCentralPackageManagement(FileInfo projectFile)
    {
        // Heuristic 1: Presence of Directory.Packages.props in directory tree.
        for (var current = projectFile.Directory; current is not null; current = current.Parent)
        {
            var directoryPackagesPropsPath = Path.Combine(current.FullName, "Directory.Packages.props");
            if (File.Exists(directoryPackagesPropsPath))
            {
                return true;
            }
        }
 
        // Heuristic 2: ManagePackageVersionsCentrally property inside project.
        try
        {
            var doc = new System.Xml.XmlDocument { PreserveWhitespace = true };
            doc.Load(projectFile.FullName);
            var manageNode = doc.SelectSingleNode("/Project/PropertyGroup/ManagePackageVersionsCentrally");
            if (manageNode?.InnerText.Trim().Equals("true", StringComparison.OrdinalIgnoreCase) == true)
            {
                return true;
            }
        }
        catch
        {
            // Ignore parse errors.
        }
 
        return false;
    }
}