packages/@aws-cdk/integ-runner/lib/utils.ts (68 lines of code) (raw):
// Helper functions for CDK Exec
import { spawnSync } from 'child_process';
/**
* Our own execute function which doesn't use shells and strings.
*/
export function exec(commandLine: string[], options: { cwd?: string; verbose?: boolean; env?: any } = { }): any {
const proc = spawnSync(commandLine[0], commandLine.slice(1), {
stdio: ['ignore', 'pipe', options.verbose ? 'inherit' : 'pipe'], // inherit STDERR in verbose mode
env: {
...process.env,
...options.env,
},
cwd: options.cwd,
});
if (proc.error) {
throw proc.error;
}
if (proc.status !== 0) {
if (process.stderr) { // will be 'null' in verbose mode
process.stderr.write(proc.stderr);
}
throw new Error(`Command exited with ${proc.status ? `status ${proc.status}` : `signal ${proc.signal}`}`);
}
const output = proc.stdout.toString('utf-8').trim();
return output;
}
/**
* Flatten a list of lists into a list of elements
*/
export function flatten<T>(xs: T[][]): T[] {
return Array.prototype.concat.apply([], xs);
}
/**
* Chain commands
*/
export function chain(commands: string[]): string {
return commands.filter(c => !!c).join(' && ');
}
/**
* Split command to chunks by space
*/
export function chunks(command: string): string[] {
const result = command.match(/(?:[^\s"]+|"[^"]*")+/g);
return result ?? [];
}
/**
* A class holding a set of items which are being crossed off in time
*
* If it takes too long to cross off a new item, print the list.
*/
export class WorkList<A> {
private readonly remaining = new Set(this.items);
private readonly timeout: number;
private timer?: NodeJS.Timeout;
constructor(private readonly items: A[], private readonly options: WorkListOptions<A> = {}) {
this.timeout = options.timeout ?? 60_000;
this.scheduleTimer();
}
public crossOff(item: A) {
this.remaining.delete(item);
this.stopTimer();
if (this.remaining.size > 0) {
this.scheduleTimer();
}
}
public done() {
this.remaining.clear();
this.stopTimer();
}
private stopTimer() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = undefined;
}
}
private scheduleTimer() {
this.timer = setTimeout(() => this.report(), this.timeout);
}
private report() {
this.options.onTimeout?.(this.remaining);
}
}
export interface WorkListOptions<A> {
/**
* When to reply with remaining items
*
* @default 60000
*/
readonly timeout?: number;
/**
* Function to call when timeout hits
*/
readonly onTimeout?: (x: Set<A>) => void;
}