| File: Commands\StartCommand.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.CommandLine; using System.Globalization; using Aspire.Cli.Backchannel; using Aspire.Cli.Profiling; using Aspire.Cli.Resources; using Aspire.Cli.Utils; using Aspire.Hosting; using Microsoft.Extensions.Configuration; namespace Aspire.Cli.Commands; internal sealed class StartCommand : BaseCommand { internal override HelpGroup HelpGroup => HelpGroup.AppCommands; protected override bool UpdateNotificationsEnabled => true; private readonly AppHostLauncher _appHostLauncher; private readonly IConfiguration _configuration; private readonly ProfileCaptureState _profileCaptureState; private static readonly Option<bool> s_noBuildOption = new("--no-build") { Description = RunCommandStrings.NoBuildArgumentDescription }; public StartCommand( AppHostLauncher appHostLauncher, IConfiguration configuration, ProfileCaptureState profileCaptureState, CommonCommandServices services) : base("start", StartCommandStrings.Description, services) { _appHostLauncher = appHostLauncher; _configuration = configuration; _profileCaptureState = profileCaptureState; Options.Add(s_noBuildOption); AppHostLauncher.AddLaunchOptions(this); TreatUnmatchedTokensAsErrors = false; } protected override async Task<CommandResult> ExecuteAsync(ParseResult parseResult, CancellationToken cancellationToken) { var passedAppHostProjectFile = parseResult.GetValue(AppHostLauncher.s_appHostOption); var format = parseResult.GetValue(AppHostLauncher.s_formatOption); var explicitIsolated = AppHostLauncher.GetExplicitIsolated(parseResult); var launchProfile = parseResult.GetValue(AppHostLauncher.s_launchProfileOption); var noBuild = parseResult.GetValue(s_noBuildOption); // The detached start path is always user-initiated. When invoked from the // Aspire terminal, it is delegated to VS Code below before reaching this // point, so keep detached summary output visible. var isExtensionHost = false; var waitForDebugger = parseResult.GetValue(RootCommand.WaitForDebuggerOption); var globalArgs = RootCommand.GetChildProcessArgs(parseResult); var appHostArgs = parseResult.UnmatchedTokens; var additionalArgs = new List<string>(); var captureProfile = parseResult.GetValue(RootCommand.CaptureProfileOption); var stopAfterLaunchDelay = captureProfile ? TimeSpan.FromSeconds(parseResult.GetValue(RootCommand.CaptureProfileDelayOption)) : (TimeSpan?)null; // When running in an extension host without an active debug session, delegate // to VS Code to start an interactive run session (non-debug) instead of launching // the AppHost detached. This preserves interactive console behavior and allows // the extension to manage the AppHost lifecycle. var nonInteractive = parseResult.GetValue(RootCommand.NonInteractiveOption); if (!nonInteractive && format != OutputFormat.Json && ExtensionHelper.IsExtensionHost(InteractionService, out var extensionInteractionService, out _) && string.IsNullOrEmpty(_configuration[KnownConfigNames.ExtensionDebugSessionId])) { var startDebugSession = parseResult.GetValue(RootCommand.StartDebugSessionOption); var debugSessionArguments = ParseResultHelper.GetForwardedArguments( parseResult, AppHostLauncher.s_appHostOption.InnerOption, AppHostLauncher.s_appHostOption.LegacyOption, AppHostLauncher.s_formatOption, RootCommand.StartDebugSessionOption, RootCommand.NonInteractiveOption); extensionInteractionService.DisplayConsolePlainText(string.Format(CultureInfo.CurrentCulture, startDebugSession ? RunCommandStrings.StartingDebugSessionInExtension : RunCommandStrings.StartingRunSessionInExtension, "start")); await extensionInteractionService.StartDebugSessionAsync( ExecutionContext.WorkingDirectory.FullName, passedAppHostProjectFile?.FullName, debug: startDebugSession, new DebugSessionOptions { Command = "run", Args = [.. debugSessionArguments.Tokens], AppHostSelectionOrigin = passedAppHostProjectFile is not null ? DebugSessionOptions.ExplicitCliAppHostSelectionOrigin : DebugSessionOptions.DefaultDiscoveryAppHostSelectionOrigin }); _profileCaptureState.MarkTransferred(); return CommandResult.Success(); } if (noBuild) { additionalArgs.Add("--no-build"); } if (!string.IsNullOrEmpty(launchProfile)) { additionalArgs.Add($"{AppHostLauncher.s_launchProfileOption.Name}={launchProfile}"); } if (appHostArgs.Count > 0) { additionalArgs.Add("--"); additionalArgs.AddRange(appHostArgs); } if (!AppHostStartupTimeout.TryGetTimeoutSeconds(_configuration, InteractionService, out var timeoutSeconds)) { return CommandResult.Failure(CliExitCodes.InvalidCommand); } return await _appHostLauncher.LaunchDetachedAsync( passedAppHostProjectFile, format, explicitIsolated, launchProfile, isExtensionHost, waitForDebugger, timeoutSeconds, globalArgs, additionalArgs, stopAfterLaunchDelay, cancellationToken); } }