packages/ros-cdk-cli/lib/api/cloud-executable.ts (57 lines of code) (raw):
import * as cxapi from '@alicloud/ros-cdk-cxapi';
import { debug } from '../logging';
import { Configuration } from '../settings';
import { CloudAssembly } from './cloud-assembly';
/**
* @returns output directory
*/
type Synthesizer = (config: Configuration) => Promise<cxapi.CloudAssembly>;
export interface CloudExecutableProps {
/**
* Application configuration (settings and context)
*/
configuration: Configuration;
/**
* Callback invoked to synthesize the actual stacks
*/
synthesizer: Synthesizer;
}
/**
* Represent the Cloud Executable and the synthesis we can do on it
*/
export class CloudExecutable {
private _cloudAssembly?: CloudAssembly;
constructor(private readonly props: CloudExecutableProps) {}
/**
* Return whether there is an app command from the configuration
*/
public get hasApp() {
return !!this.props.configuration.settings.get(['app']);
}
/**
* Synthesize a set of stacks
*/
public async synthesize(): Promise<CloudAssembly> {
if (!this._cloudAssembly) {
this._cloudAssembly = await this.doSynthesize();
}
return this._cloudAssembly;
}
private async doSynthesize(): Promise<CloudAssembly> {
// We may need to run the cloud executable multiple times in order to satisfy all missing context
// (When the executable runs, it will tell us about context it wants to use
// but it missing. We'll then look up the context and run the executable again, and
// again, until it doesn't complain anymore or we've stopped making progress).
let previouslyMissingKeys: Set<string> | undefined;
while (true) {
const assembly = await this.props.synthesizer(this.props.configuration);
if (assembly.manifest.missing) {
const missingKeys = missingContextKeys(assembly.manifest.missing);
let tryLookup = true;
if (previouslyMissingKeys && setsEqual(missingKeys, previouslyMissingKeys)) {
debug('Not making progress trying to resolve environmental context. Giving up.');
tryLookup = false;
}
previouslyMissingKeys = missingKeys;
if (tryLookup) {
debug('Some context information is missing. Fetching...');
// await contextproviders.provideContextValues(assembly.manifest.missing, this.props.configuration.context, this.props.sdkProvider);
// Cache the new context to disk
await this.props.configuration.saveContext();
// Execute again
continue;
}
}
return new CloudAssembly(assembly);
}
}
}
/**
* Return all keys of missing context items
*/
function missingContextKeys(missing?: cxapi.MissingContext[]): Set<string> {
return new Set((missing || []).map((m) => m.key));
}
function setsEqual<A>(a: Set<A>, b: Set<A>) {
if (a.size !== b.size) {
return false;
}
for (const x of a) {
if (!b.has(x)) {
return false;
}
}
return true;
}