| File: RuntimeSpec.cs | Web Access |
| Project: src\src\Aspire.TypeSystem\Aspire.TypeSystem.csproj (Aspire.TypeSystem) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Aspire.TypeSystem; /// <summary> /// Specifies the runtime execution configuration for a language. /// </summary> public sealed class RuntimeSpec { /// <summary> /// Gets the language identifier (e.g., "TypeScript", "Python"). /// </summary> public required string Language { get; init; } /// <summary> /// Gets the display name for the language (e.g., "TypeScript (Node.js)"). /// </summary> public required string DisplayName { get; init; } /// <summary> /// Gets the code generation language identifier for the generateCode RPC. /// </summary> public required string CodeGenLanguage { get; init; } /// <summary> /// Gets the file patterns used to detect this language (e.g., ["apphost.ts"]). /// </summary> public required string[] DetectionPatterns { get; init; } /// <summary> /// Gets the commands to initialize the project environment (e.g., create a virtual environment /// and install dependencies). Runs once during scaffolding. Null if no initialization is needed. /// </summary> public CommandSpec[]? Initialize { get; init; } /// <summary> /// Gets the command to install dependencies. Null if no dependencies to install. /// </summary> public CommandSpec? InstallDependencies { get; init; } /// <summary> /// Gets the commands to run before executing or publishing the AppHost. Null if no pre-execution validation is needed. /// Watch-mode validation should be part of <see cref="WatchExecute" /> when needed. /// </summary> public CommandSpec[]? PreExecute { get; init; } /// <summary> /// Gets the command to execute the AppHost for run. /// </summary> public required CommandSpec Execute { get; init; } /// <summary> /// Gets the command to execute the AppHost in watch mode. Null if watch mode not supported. /// </summary> public CommandSpec? WatchExecute { get; init; } /// <summary> /// Gets the command to execute the AppHost for publish. Null to use Execute with args appended. /// </summary> public CommandSpec? PublishExecute { get; init; } /// <summary> /// Gets the extension capability required to launch this language via the VS Code extension. /// When set (e.g., "node"), the CLI will use the extension launcher if the extension reports /// this capability. When null, the CLI always uses the default process-based launcher. /// </summary> public string? ExtensionLaunchCapability { get; init; } /// <summary> /// Gets the environment variable that accepts an additional PEM certificate bundle when running an AppHost for this language. /// </summary> /// <remarks> /// When set, the CLI assigns this environment variable a certificate bundle containing the /// ASP.NET Core development certificate before launching the AppHost in run mode. The variable /// is not set when publishing the AppHost. The runtime uses the bundle as additional trusted roots /// for the entire AppHost process, affecting all outbound TLS connections, including connections /// unrelated to Aspire-managed resources. For example: /// <code> /// CertificateBundleEnvironmentVariable = "NODE_EXTRA_CA_CERTS"; /// </code> /// </remarks> public string? CertificateBundleEnvironmentVariable { get; init; } /// <summary> /// Gets files that must exist in the project directory before execution. /// If a file in this dictionary is missing, the CLI will create it with the provided content. /// This supports upgrade scenarios where new runtime requirements are introduced. /// </summary> public Dictionary<string, string>? MigrationFiles { get; init; } } /// <summary> /// Specifies a command to execute. /// </summary> public sealed class CommandSpec { /// <summary> /// Gets the command to execute (e.g., "npm", "npx", "python"). /// </summary> public required string Command { get; init; } /// <summary> /// Gets the arguments for the command. /// Supports placeholders: {appHostFile}, {appHostDir}, {args} /// </summary> public required string[] Args { get; init; } /// <summary> /// Gets the environment variables to set when executing the command. /// These are merged with any environment variables provided by the caller. /// </summary> public Dictionary<string, string>? EnvironmentVariables { get; init; } /// <summary> /// Gets an optional incremental-build check. When set, the command is skipped if its stamp file /// is newer than every declared input. Null means the command always runs. /// </summary> public CommandUpToDateCheck? UpToDateCheck { get; init; } } /// <summary> /// Declares the inputs and stamp file that let the CLI skip a command whose work is already done. /// </summary> /// <remarks> /// This exists for compilers that have no incremental mode of their own. <c>javac</c> given an /// explicit list of source files recompiles all of them every time, so an AppHost that has not /// changed still pays a full compile of the generated SDK on every launch. Toolchains that are /// already incremental (<c>cargo</c>, for instance) do not need this. /// </remarks> public sealed class CommandUpToDateCheck { /// <summary> /// Gets the inputs to compare against the stamp file, relative to the working directory unless /// absolute. Supports the same placeholders as <see cref="CommandSpec.Args" />. /// </summary> /// <remarks> /// An entry is either a file, a directory, or a directory suffixed with <c>/**</c>. A plain /// directory is scanned one level deep; only the <c>/**</c> form recurses. That distinction is /// what keeps the check cheap: the AppHost directory can be declared as an input for the sources /// that sit beside the AppHost without walking sibling trees such as <c>node_modules</c>. /// Entries that do not exist are ignored, so a spec can name a path that only some layouts have. /// </remarks> public required string[] Inputs { get; init; } /// <summary> /// Gets the file extensions, including the leading dot, that identify input files. /// Null or empty means every file found under <see cref="Inputs" /> counts. /// </summary> /// <remarks> /// Restricting by extension is what keeps a command's own outputs from invalidating it when they /// land beside its inputs — <c>.class</c> files written next to the <c>.java</c> files they were /// compiled from, for example. /// </remarks> public string[]? FileExtensions { get; init; } /// <summary> /// Gets the file, relative to the working directory unless absolute, written after the command /// succeeds and compared against the inputs on the next launch. /// </summary> /// <remarks> /// Place this with the command's outputs so that deleting them — <c>mvn clean</c>, or removing the /// class output directory — also invalidates the check. /// </remarks> public required string StampFile { get; init; } }