packages/@aws-cdk/toolkit-lib/lib/api/cloud-assembly/private/stack-assembly.ts (90 lines of code) (raw):

import '../../../private/dispose-polyfill'; import { major } from 'semver'; import type { IoHelper } from '../../shared-private'; import { ToolkitError } from '../../shared-public'; import { BaseStackAssembly, ExtendedStackSelection as CliExtendedStackSelection } from '../stack-assembly'; import { StackCollection } from '../stack-collection'; import type { StackSelector } from '../stack-selector'; import { ExpandStackSelection, StackSelectionStrategy } from '../stack-selector'; import type { IReadableCloudAssembly } from '../types'; /** * A single Cloud Assembly wrapped to provide additional stack operations. */ export class StackAssembly extends BaseStackAssembly implements IReadableCloudAssembly { constructor(private readonly _asm: IReadableCloudAssembly, ioHelper: IoHelper) { super(_asm.cloudAssembly, ioHelper); } public get cloudAssembly() { return this._asm.cloudAssembly; } public async _unlock() { return this._asm._unlock(); } public async dispose() { return this._asm.dispose(); } public async [Symbol.asyncDispose]() { return this.dispose(); } /** * Improved stack selection interface with a single selector * @throws when the assembly does not contain any stacks, unless `selector.failOnEmpty` is `false` * @throws when individual selection strategies are not satisfied */ public async selectStacksV2(selector: StackSelector): Promise<StackCollection> { const asm = this.assembly; const topLevelStacks = asm.stacks; const allStacks = major(asm.version) < 10 ? asm.stacks : asm.stacksRecursively; if (allStacks.length === 0 && (selector.failOnEmpty ?? true)) { throw new ToolkitError('This app contains no stacks'); } const extend = expandToExtendEnum(selector.expand); const patterns = StackAssembly.sanitizePatterns(selector.patterns ?? []); switch (selector.strategy) { case StackSelectionStrategy.ALL_STACKS: return new StackCollection(this, allStacks); case StackSelectionStrategy.MAIN_ASSEMBLY: if (topLevelStacks.length < 1) { // @todo text should probably be handled in io host throw new ToolkitError('No stack found in the main cloud assembly. Use "list" to print manifest'); } return this.extendStacks(topLevelStacks, allStacks, extend); case StackSelectionStrategy.ONLY_SINGLE: if (topLevelStacks.length !== 1) { // @todo text should probably be handled in io host throw new ToolkitError('Since this app includes more than a single stack, specify which stacks to use (wildcards are supported) or specify `--all`\n' + `Stacks: ${allStacks.map(x => x.hierarchicalId).join(' · ')}`); } return new StackCollection(this, topLevelStacks); default: const matched = await this.selectMatchingStacks(allStacks, patterns, extend); if ( selector.strategy === StackSelectionStrategy.PATTERN_MUST_MATCH_SINGLE && matched.stackCount !== 1 ) { // @todo text should probably be handled in io host throw new ToolkitError( `Stack selection is ambiguous, please choose a specific stack for import [${allStacks.map(x => x.hierarchicalId).join(',')}]`, ); } if ( selector.strategy === StackSelectionStrategy.PATTERN_MUST_MATCH && matched.stackCount < 1 ) { // @todo text should probably be handled in io host throw new ToolkitError( `Stack selection is ambiguous, please choose a specific stack for import [${allStacks.map(x => x.hierarchicalId).join(',')}]`, ); } return matched; } } /** * Select all stacks. * * This method never throws and can safely be used as a basis for other calculations. * * @returns a `StackCollection` of all stacks */ public selectAllStacks() { const allStacks = major(this.assembly.version) < 10 ? this.assembly.stacks : this.assembly.stacksRecursively; return new StackCollection(this, allStacks); } /** * Select all stacks that have the validateOnSynth flag et. * * @returns a `StackCollection` of all stacks that needs to be validated */ public selectStacksForValidation() { const allStacks = this.selectAllStacks(); return allStacks.filter((art) => art.validateOnSynth ?? false); } } function expandToExtendEnum(extend?: ExpandStackSelection): CliExtendedStackSelection | undefined { switch (extend) { case ExpandStackSelection.DOWNSTREAM: return CliExtendedStackSelection.Downstream; case ExpandStackSelection.UPSTREAM: return CliExtendedStackSelection.Upstream; case ExpandStackSelection.NONE: return CliExtendedStackSelection.None; default: return undefined; } }