Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions extension/src/views/AspireAppHostTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ export class AspireAppHostTreeProvider implements vscode.TreeDataProvider<TreeEl
});

if (selected) {
this._terminalProvider.sendAspireCommandToAspireTerminal(`command "${element.resource.name}" "${selected.label}" --apphost "${appHost.appHostPath}"`);
this._terminalProvider.sendAspireCommandToAspireTerminal(`resource "${element.resource.name}" "${selected.label}" --apphost "${appHost.appHostPath}"`);
}
}

Expand All @@ -324,7 +324,7 @@ export class AspireAppHostTreeProvider implements vscode.TreeDataProvider<TreeEl
return;
}
const suffix = extraArgs.length > 0 ? ` ${extraArgs.join(' ')}` : '';
this._terminalProvider.sendAspireCommandToAspireTerminal(`${command} "${element.resource.name}" --apphost "${appHost.appHostPath}"${suffix}`);
this._terminalProvider.sendAspireCommandToAspireTerminal(`resource "${element.resource.name}" ${command} --apphost "${appHost.appHostPath}"${suffix}`);
}

private _findAppHostForResource(element: ResourceItem): AppHostDisplayInfo | undefined {
Expand Down
28 changes: 27 additions & 1 deletion src/Aspire.Cli/Commands/ResourceCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Aspire.Cli.Resources;
using Aspire.Cli.Telemetry;
using Aspire.Cli.Utils;
using Aspire.Hosting.ApplicationModel;
using Microsoft.Extensions.Logging;

namespace Aspire.Cli.Commands;
Expand All @@ -33,6 +34,16 @@ internal sealed class ResourceCommand : BaseCommand

private static readonly OptionWithLegacy<FileInfo?> s_appHostOption = new("--apphost", "--project", SharedCommandStrings.AppHostOptionDescription);

/// <summary>
/// Maps friendly command names to their backchannel equivalents with display metadata.
/// </summary>
private static readonly Dictionary<string, (string BackchannelCommand, string ProgressVerb, string BaseVerb, string PastTenseVerb)> s_wellKnownCommands = new(StringComparer.OrdinalIgnoreCase)
{
["start"] = (KnownResourceCommands.StartCommand, "Starting", "start", "started"),
["stop"] = (KnownResourceCommands.StopCommand, "Stopping", "stop", "stopped"),
["restart"] = (KnownResourceCommands.RestartCommand, "Restarting", "restart", "restarted"),
};

public ResourceCommand(
IInteractionService interactionService,
IAuxiliaryBackchannelMonitor backchannelMonitor,
Expand All @@ -41,7 +52,7 @@ public ResourceCommand(
CliExecutionContext executionContext,
ILogger<ResourceCommand> logger,
AspireCliTelemetry telemetry)
: base("command", ResourceCommandStrings.CommandDescription, features, updateNotifier, executionContext, interactionService, telemetry)
: base("resource", ResourceCommandStrings.CommandDescription, features, updateNotifier, executionContext, interactionService, telemetry)
{
_interactionService = interactionService;
_connectionResolver = new AppHostConnectionResolver(backchannelMonitor, interactionService, executionContext, logger);
Expand Down Expand Up @@ -71,6 +82,21 @@ protected override async Task<int> ExecuteAsync(ParseResult parseResult, Cancell
return ExitCodeConstants.FailedToFindProject;
}

// Map well-known friendly names (start/stop/restart) to their backchannel equivalents
if (s_wellKnownCommands.TryGetValue(commandName, out var knownCommand))
{
return await ResourceCommandHelper.ExecuteResourceCommandAsync(
result.Connection!,
_interactionService,
_logger,
resourceName,
knownCommand.BackchannelCommand,
knownCommand.ProgressVerb,
knownCommand.BaseVerb,
knownCommand.PastTenseVerb,
cancellationToken);
}

return await ResourceCommandHelper.ExecuteGenericCommandAsync(
result.Connection!,
_interactionService,
Expand Down
106 changes: 0 additions & 106 deletions src/Aspire.Cli/Commands/ResourceCommandBase.cs

This file was deleted.

38 changes: 0 additions & 38 deletions src/Aspire.Cli/Commands/RestartCommand.cs

This file was deleted.

2 changes: 0 additions & 2 deletions src/Aspire.Cli/Commands/RootCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ public RootCommand(
RunCommand runCommand,
StopCommand stopCommand,
StartCommand startCommand,
RestartCommand restartCommand,
WaitCommand waitCommand,
ResourceCommand commandCommand,
PsCommand psCommand,
Expand Down Expand Up @@ -200,7 +199,6 @@ public RootCommand(
Subcommands.Add(runCommand);
Subcommands.Add(stopCommand);
Subcommands.Add(startCommand);
Subcommands.Add(restartCommand);
Subcommands.Add(waitCommand);
Subcommands.Add(commandCommand);
Subcommands.Add(psCommand);
Expand Down
70 changes: 3 additions & 67 deletions src/Aspire.Cli/Commands/StartCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,20 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.CommandLine;
using System.Globalization;
using Aspire.Cli.Backchannel;
using Aspire.Cli.Configuration;
using Aspire.Cli.Interaction;
using Aspire.Cli.Resources;
using Aspire.Cli.Telemetry;
using Aspire.Cli.Utils;
using Aspire.Hosting.ApplicationModel;
using Microsoft.Extensions.Logging;

namespace Aspire.Cli.Commands;

internal sealed class StartCommand : BaseCommand
{
internal override HelpGroup HelpGroup => HelpGroup.ResourceManagement;
internal override HelpGroup HelpGroup => HelpGroup.AppCommands;

private readonly IInteractionService _interactionService;
private readonly AppHostConnectionResolver _connectionResolver;
private readonly AppHostLauncher _appHostLauncher;
private readonly ILogger<StartCommand> _logger;

private static readonly Argument<string?> s_resourceArgument = new("resource")
{
Description = ResourceCommandStrings.StartResourceArgumentDescription,
Arity = ArgumentArity.ZeroOrOne
};
private readonly IInteractionService _interactionService;

private static readonly Option<bool> s_noBuildOption = new("--no-build")
{
Expand All @@ -36,22 +24,17 @@ internal sealed class StartCommand : BaseCommand

public StartCommand(
IInteractionService interactionService,
IAuxiliaryBackchannelMonitor backchannelMonitor,
IFeatures features,
ICliUpdateNotifier updateNotifier,
CliExecutionContext executionContext,
ILogger<StartCommand> logger,
AspireCliTelemetry telemetry,
AppHostLauncher appHostLauncher)
: base("start", ResourceCommandStrings.StartDescription,
: base("start", StartCommandStrings.Description,
features, updateNotifier, executionContext, interactionService, telemetry)
{
_interactionService = interactionService;
_connectionResolver = new AppHostConnectionResolver(backchannelMonitor, interactionService, executionContext, logger);
_appHostLauncher = appHostLauncher;
_logger = logger;

Arguments.Add(s_resourceArgument);
Options.Add(s_noBuildOption);
AppHostLauncher.AddLaunchOptions(this);

Expand All @@ -60,30 +43,10 @@ public StartCommand(

protected override async Task<int> ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken)
{
var resourceName = parseResult.GetValue(s_resourceArgument);
var passedAppHostProjectFile = parseResult.GetValue(AppHostLauncher.s_appHostOption);
var format = parseResult.GetValue(AppHostLauncher.s_formatOption);
var isolated = parseResult.GetValue(AppHostLauncher.s_isolatedOption);

// If a resource name is provided, start that specific resource
if (!string.IsNullOrEmpty(resourceName))
{
if (format == OutputFormat.Json)
{
_interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, ResourceCommandStrings.OptionNotValidWithResource, "--format"));
return ExitCodeConstants.InvalidCommand;
}

if (isolated)
{
_interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, ResourceCommandStrings.OptionNotValidWithResource, "--isolated"));
return ExitCodeConstants.InvalidCommand;
}

return await StartResourceAsync(passedAppHostProjectFile, resourceName, cancellationToken);
}

// No resource specified — start the AppHost in detached mode
var noBuild = parseResult.GetValue(s_noBuildOption);
var isExtensionHost = ExtensionHelper.IsExtensionHost(_interactionService, out _, out _);
var globalArgs = RootCommand.GetChildProcessArgs(parseResult);
Expand All @@ -103,31 +66,4 @@ protected override async Task<int> ExecuteAsync(ParseResult parseResult, Cancell
additionalArgs,
cancellationToken);
}

private async Task<int> StartResourceAsync(FileInfo? passedAppHostProjectFile, string resourceName, CancellationToken cancellationToken)
{
var result = await _connectionResolver.ResolveConnectionAsync(
passedAppHostProjectFile,
SharedCommandStrings.ScanningForRunningAppHosts,
string.Format(CultureInfo.CurrentCulture, SharedCommandStrings.SelectAppHost, ResourceCommandStrings.SelectAppHostAction),
SharedCommandStrings.AppHostNotRunning,
cancellationToken);

if (!result.Success)
{
_interactionService.DisplayError(result.ErrorMessage);
return ExitCodeConstants.FailedToFindProject;
}

return await ResourceCommandHelper.ExecuteResourceCommandAsync(
result.Connection!,
_interactionService,
_logger,
resourceName,
KnownResourceCommands.StartCommand,
"Starting",
"start",
"started",
cancellationToken);
}
}
Loading
Loading