projen
Version:
CDK for software projects
293 lines โข 38.3 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaskRuntime = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const path_1 = require("path");
const path = require("path");
const util_1 = require("util");
const chalk_1 = require("chalk");
const common_1 = require("./common");
const logging = require("./logging");
const tasks_1 = require("./util/tasks");
// avoids a (false positive) esbuild warning about incorrect imports
// eslint-disable-next-line @typescript-eslint/no-require-imports
const parseConflictJSON = require("parse-conflict-json");
const ENV_TRIM_LEN = 20;
const ARGS_MARKER = "$@";
const QUOTED_ARGS_MARKER = `"${ARGS_MARKER}"`;
/**
* The runtime component of the tasks engine.
*/
class TaskRuntime {
constructor(workdir) {
this.workdir = (0, path_1.resolve)(workdir);
const manifestPath = (0, path_1.join)(this.workdir, TaskRuntime.MANIFEST_FILE);
this.manifest = (0, fs_1.existsSync)(manifestPath)
? parseConflictJSON((0, fs_1.readFileSync)(manifestPath, "utf-8"), undefined, "theirs")
: { tasks: {} };
}
/**
* The tasks in this project.
*/
get tasks() {
return Object.values(this.manifest.tasks ?? {});
}
/**
* Find a task by name, or `undefined` if not found.
*/
tryFindTask(name) {
if (!this.manifest.tasks) {
return undefined;
}
return this.manifest.tasks[name];
}
/**
* Runs the task.
* @param name The task name.
*/
runTask(name, parents = [], args = [], env = {}) {
const task = this.tryFindTask(name);
if (!task) {
throw new Error(`cannot find command ${task}`);
}
new RunTask(this, task, parents, args, env);
}
}
exports.TaskRuntime = TaskRuntime;
_a = JSII_RTTI_SYMBOL_1;
TaskRuntime[_a] = { fqn: "projen.TaskRuntime", version: "0.98.32" };
/**
* The project-relative path of the tasks manifest file.
*/
TaskRuntime.MANIFEST_FILE = path.posix.join(common_1.PROJEN_DIR, "tasks.json");
class RunTask {
constructor(runtime, task, parents = [], args = [], envParam = {}) {
this.runtime = runtime;
this.task = task;
this.env = {};
this.workdir = task.cwd ?? this.runtime.workdir;
this.parents = parents;
if (!task.steps || task.steps.length === 0) {
this.logDebug((0, chalk_1.gray)("No actions have been specified for this task."));
return;
}
this.env = this.resolveEnvironment(envParam, parents);
const envlogs = [];
for (const [k, v] of Object.entries(this.env)) {
const vv = v ?? "";
const trimmed = vv.length > ENV_TRIM_LEN ? vv.substr(0, ENV_TRIM_LEN) + "..." : vv;
envlogs.push(`${k}=${trimmed}`);
}
if (envlogs.length) {
this.logDebug((0, chalk_1.gray)(`${(0, chalk_1.underline)("env")}: ${envlogs.join(" ")}`));
}
// evaluate condition
if (!this.evalCondition(task)) {
this.log("condition exited with non-zero - skipping");
return;
}
// verify we required environment variables are defined
const merged = { ...process.env, ...this.env };
const missing = new Array();
for (const name of task.requiredEnv ?? []) {
if (!(name in merged)) {
missing.push(name);
}
}
if (missing.length > 0) {
throw new Error(`missing required environment variables: ${missing.join(",")}`);
}
for (const step of task.steps) {
// evaluate step condition
if (!this.evalCondition(step)) {
this.log("condition exited with non-zero - skipping");
continue;
}
const argsList = [
...(step.args || []),
...(step.receiveArgs ? args : []),
].map((a) => a.toString());
if (step.say) {
logging.info(this.fmtLog(step.say));
}
if (step.spawn) {
this.runtime.runTask(step.spawn, [...this.parents, this.task.name], argsList, step.env);
}
const execs = step.exec ? [step.exec] : [];
// Parse step-specific environment variables
const env = this.evalEnvironment(step.env ?? {});
if (step.builtin) {
execs.push(this.renderBuiltin(step.builtin));
}
for (const exec of execs) {
let hasError = false;
let command = (0, tasks_1.makeCrossPlatform)(exec);
if (command.includes(QUOTED_ARGS_MARKER)) {
// Poorly imitate bash quoted variable expansion. If "$@" is encountered in bash, elements of the arg array
// that contain whitespace will be single quoted ('arg'). This preserves whitespace in things like filenames.
// Imitate that behavior here by single quoting every element of the arg array when a quoted arg marker ("$@")
// is encountered.
command = command.replace(QUOTED_ARGS_MARKER, argsList.map((arg) => `'${arg}'`).join(" "));
}
else if (command.includes(ARGS_MARKER)) {
command = command.replace(ARGS_MARKER, argsList.join(" "));
}
else {
command = [command, ...argsList].join(" ");
}
const cwd = step.cwd;
try {
const result = this.shell({
command,
cwd,
extraEnv: env,
});
hasError = result.status !== 0;
}
catch (e) {
// This is the error 'shx' will throw
if (e?.message?.startsWith("non-zero exit code:")) {
hasError = true;
}
throw e;
}
if (hasError) {
throw new Error(`Task "${this.fullname}" failed when executing "${command}" (cwd: ${(0, path_1.resolve)(cwd ?? this.workdir)})`);
}
}
}
}
/**
* Determines if a task should be executed based on "condition".
*
* @returns true if the task should be executed or false if the condition
* evaluates to false (exits with non-zero), indicating that the task should
* be skipped.
*/
evalCondition(taskOrStep) {
// no condition, carry on
if (!taskOrStep.condition) {
return true;
}
this.log((0, chalk_1.gray)(`${(0, chalk_1.underline)("condition")}: ${taskOrStep.condition}`));
const result = this.shell({
command: taskOrStep.condition,
logprefix: "condition: ",
quiet: true,
});
if (result.status === 0) {
return true;
}
else {
return false;
}
}
/**
* Evaluates environment variables from shell commands (e.g. `$(xx)`)
*/
evalEnvironment(env) {
const output = {};
for (const [key, value] of Object.entries(env ?? {})) {
if (String(value).startsWith("$(") && String(value).endsWith(")")) {
const query = value.substring(2, value.length - 1);
const result = this.shellEval({ command: query });
if (result.status !== 0) {
const error = result.error
? result.error.stack
: result.stderr?.toString() ?? "unknown error";
throw new Error(`unable to evaluate environment variable ${key}=${value}: ${error}`);
}
output[key] = result.stdout.toString("utf-8").trim();
}
else {
output[key] = value;
}
}
return output;
}
/**
* Renders the runtime environment for a task. Namely, it supports this syntax
* `$(xx)` for allowing environment to be evaluated by executing a shell
* command and obtaining its result.
*/
resolveEnvironment(envParam, parents) {
let env = this.runtime.manifest.env ?? {};
// add env from all parent tasks one by one
for (const parent of parents) {
env = {
...env,
...(this.runtime.tryFindTask(parent)?.env ?? {}),
};
}
// apply task environment, then the specific env last
env = {
...env,
...(this.task.env ?? {}),
...envParam,
};
return this.evalEnvironment(env ?? {});
}
/**
* Returns the "full name" of the task which includes all it's parent task names concatenated by chevrons.
*/
get fullname() {
return [...this.parents, this.task.name].join(" ยป ");
}
log(...args) {
logging.verbose(this.fmtLog(...args));
}
logDebug(...args) {
logging.debug(this.fmtLog(...args));
}
fmtLog(...args) {
return (0, util_1.format)(`${(0, chalk_1.underline)(this.fullname)} |`, ...args);
}
shell(options) {
const quiet = options.quiet ?? false;
if (!quiet) {
const log = new Array();
if (options.logprefix) {
log.push(options.logprefix);
}
log.push(options.command);
if (options.cwd) {
log.push(`(cwd: ${options.cwd})`);
}
this.log(log.join(" "));
}
const cwd = options.cwd ?? this.workdir;
if (!(0, fs_1.existsSync)(cwd) || !(0, fs_1.statSync)(cwd).isDirectory()) {
throw new Error(`invalid workdir (cwd): ${cwd} must be an existing directory`);
}
return (0, child_process_1.spawnSync)(options.command, {
...options,
cwd,
shell: true,
stdio: "inherit",
env: {
...process.env,
...this.env,
...options.extraEnv,
},
...options.spawnOptions,
});
}
shellEval(options) {
return this.shell({
quiet: true,
...options,
spawnOptions: {
stdio: ["inherit", "pipe", "inherit"],
},
});
}
renderBuiltin(builtin) {
const moduleRoot = (0, path_1.dirname)(require.resolve("../package.json"));
const program = require.resolve((0, path_1.join)(moduleRoot, "lib", `${builtin}.task.js`));
return `"${process.execPath}" "${program}"`;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFzay1ydW50aW1lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Rhc2stcnVudGltZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLGlEQUF3RDtBQUN4RCwyQkFBd0Q7QUFDeEQsK0JBQThDO0FBQzlDLDZCQUE2QjtBQUM3QiwrQkFBOEI7QUFDOUIsaUNBQXdDO0FBQ3hDLHFDQUFzQztBQUN0QyxxQ0FBcUM7QUFFckMsd0NBQWlEO0FBRWpELG9FQUFvRTtBQUNwRSxpRUFBaUU7QUFDakUsTUFBTSxpQkFBaUIsR0FBRyxPQUFPLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUV6RCxNQUFNLFlBQVksR0FBRyxFQUFFLENBQUM7QUFDeEIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDO0FBQ3pCLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxXQUFXLEdBQUcsQ0FBQztBQUU5Qzs7R0FFRztBQUNILE1BQWEsV0FBVztJQW1CdEIsWUFBWSxPQUFlO1FBQ3pCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBQSxjQUFPLEVBQUMsT0FBTyxDQUFDLENBQUM7UUFDaEMsTUFBTSxZQUFZLEdBQUcsSUFBQSxXQUFJLEVBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDbkUsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFBLGVBQVUsRUFBQyxZQUFZLENBQUM7WUFDdEMsQ0FBQyxDQUFDLGlCQUFpQixDQUNmLElBQUEsaUJBQVksRUFBQyxZQUFZLEVBQUUsT0FBTyxDQUFDLEVBQ25DLFNBQVMsRUFDVCxRQUFRLENBQ1Q7WUFDSCxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDcEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBVyxLQUFLO1FBQ2QsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ2xE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LFVBQVUsR0FBRyxJQUFBLGNBQU8sRUFBQyxPQUFPLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQztRQUMvRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUM3QixJQUFBLFdBQUksRUFBQyxVQUFVLEVBQUUsS0FBSyxFQUFFLEdBQUcsT0FBTyxVQUFVLENBQUMsQ0FDOUMsQ0FBQztRQUNGLE9BQU8sSUFBSSxPQUFPLENBQUMsUUFBUSxNQUFNLE9BQU8sR0FBRyxDQUFDO0lBQzlDLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFNwYXduT3B0aW9ucywgc3Bhd25TeW5jIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgc3RhdFN5bmMgfSBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IGRpcm5hbWUsIGpvaW4sIHJlc29sdmUgfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgZm9ybWF0IH0gZnJvbSBcInV0aWxcIjtcbmltcG9ydCB7IGdyYXksIHVuZGVybGluZSB9IGZyb20gXCJjaGFsa1wiO1xuaW1wb3J0IHsgUFJPSkVOX0RJUiB9IGZyb20gXCIuL2NvbW1vblwiO1xuaW1wb3J0ICogYXMgbG9nZ2luZyBmcm9tIFwiLi9sb2dnaW5nXCI7XG5pbXBvcnQgeyBUYXNrc01hbmlmZXN0LCBUYXNrU3BlYywgVGFza1N0ZXAgfSBmcm9tIFwiLi90YXNrLW1vZGVsXCI7XG5pbXBvcnQgeyBtYWtlQ3Jvc3NQbGF0Zm9ybSB9IGZyb20gXCIuL3V0aWwvdGFza3NcIjtcblxuLy8gYXZvaWRzIGEgKGZhbHNlIHBvc2l0aXZlKSBlc2J1aWxkIHdhcm5pbmcgYWJvdXQgaW5jb3JyZWN0IGltcG9ydHNcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG5jb25zdCBwYXJzZUNvbmZsaWN0SlNPTiA9IHJlcXVpcmUoXCJwYXJzZS1jb25mbGljdC1qc29uXCIpO1xuXG5jb25zdCBFTlZfVFJJTV9MRU4gPSAyMDtcbmNvbnN0IEFSR1NfTUFSS0VSID0gXCIkQFwiO1xuY29uc3QgUVVPVEVEX0FSR1NfTUFSS0VSID0gYFwiJHtBUkdTX01BUktFUn1cImA7XG5cbi8qKlxuICogVGhlIHJ1bnRpbWUgY29tcG9uZW50IG9mIHRoZSB0YXNrcyBlbmdpbmUuXG4gKi9cbmV4cG9ydCBjbGFzcyBUYXNrUnVudGltZSB7XG4gIC8qKlxuICAgKiBUaGUgcHJvamVjdC1yZWxhdGl2ZSBwYXRoIG9mIHRoZSB0YXNrcyBtYW5pZmVzdCBmaWxlLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBNQU5JRkVTVF9GSUxFID0gcGF0aC5wb3NpeC5qb2luKFxuICAgIFBST0pFTl9ESVIsXG4gICAgXCJ0YXNrcy5qc29uXCJcbiAgKTtcblxuICAvKipcbiAgICogVGhlIGNvbnRlbnRzIG9mIHRhc2tzLmpzb25cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBtYW5pZmVzdDogVGFza3NNYW5pZmVzdDtcblxuICAvKipcbiAgICogVGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoZSBwcm9qZWN0IGFuZCB0aGUgY3dkIGZvciBleGVjdXRpbmcgdGFza3MuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgd29ya2Rpcjogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHdvcmtkaXI6IHN0cmluZykge1xuICAgIHRoaXMud29ya2RpciA9IHJlc29sdmUod29ya2Rpcik7XG4gICAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbih0aGlzLndvcmtkaXIsIFRhc2tSdW50aW1lLk1BTklGRVNUX0ZJTEUpO1xuICAgIHRoaXMubWFuaWZlc3QgPSBleGlzdHNTeW5jKG1hbmlmZXN0UGF0aClcbiAgICAgID8gcGFyc2VDb25mbGljdEpTT04oXG4gICAgICAgICAgcmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCwgXCJ1dGYtOFwiKSxcbiAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgXCJ0aGVpcnNcIlxuICAgICAgICApXG4gICAgICA6IHsgdGFza3M6IHt9IH07XG4gIH1cblxuICAvKipcbiAgICogVGhlIHRhc2tzIGluIHRoaXMgcHJvamVjdC5cbiAgICovXG4gIHB1YmxpYyBnZXQgdGFza3MoKTogVGFza1NwZWNbXSB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5tYW5pZmVzdC50YXNrcyA/PyB7fSk7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBhIHRhc2sgYnkgbmFtZSwgb3IgYHVuZGVmaW5lZGAgaWYgbm90IGZvdW5kLlxuICAgKi9cbiAgcHVibGljIHRyeUZpbmRUYXNrKG5hbWU6IHN0cmluZyk6IFRhc2tTcGVjIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXRoaXMubWFuaWZlc3QudGFza3MpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLm1hbmlmZXN0LnRhc2tzW25hbWVdO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgdGhlIHRhc2suXG4gICAqIEBwYXJhbSBuYW1lIFRoZSB0YXNrIG5hbWUuXG4gICAqL1xuICBwdWJsaWMgcnVuVGFzayhcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgcGFyZW50czogc3RyaW5nW10gPSBbXSxcbiAgICBhcmdzOiBBcnJheTxzdHJpbmcgfCBudW1iZXI+ID0gW10sXG4gICAgZW52OiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfSA9IHt9XG4gICkge1xuICAgIGNvbnN0IHRhc2sgPSB0aGlzLnRyeUZpbmRUYXNrKG5hbWUpO1xuICAgIGlmICghdGFzaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBjYW5ub3QgZmluZCBjb21tYW5kICR7dGFza31gKTtcbiAgICB9XG5cbiAgICBuZXcgUnVuVGFzayh0aGlzLCB0YXNrLCBwYXJlbnRzLCBhcmdzLCBlbnYpO1xuICB9XG59XG5cbmNsYXNzIFJ1blRhc2sge1xuICBwcml2YXRlIHJlYWRvbmx5IGVudjogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH0gPSB7fTtcbiAgcHJpdmF0ZSByZWFkb25seSBwYXJlbnRzOiBzdHJpbmdbXTtcblxuICBwcml2YXRlIHJlYWRvbmx5IHdvcmtkaXI6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJ1bnRpbWU6IFRhc2tSdW50aW1lLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgdGFzazogVGFza1NwZWMsXG4gICAgcGFyZW50czogc3RyaW5nW10gPSBbXSxcbiAgICBhcmdzOiBBcnJheTxzdHJpbmcgfCBudW1iZXI+ID0gW10sXG4gICAgZW52UGFyYW06IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB9ID0ge31cbiAgKSB7XG4gICAgdGhpcy53b3JrZGlyID0gdGFzay5jd2QgPz8gdGhpcy5ydW50aW1lLndvcmtkaXI7XG5cbiAgICB0aGlzLnBhcmVudHMgPSBwYXJlbnRzO1xuXG4gICAgaWYgKCF0YXNrLnN0ZXBzIHx8IHRhc2suc3RlcHMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aGlzLmxvZ0RlYnVnKGdyYXkoXCJObyBhY3Rpb25zIGhhdmUgYmVlbiBzcGVjaWZpZWQgZm9yIHRoaXMgdGFzay5cIikpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuZW52ID0gdGhpcy5yZXNvbHZlRW52aXJvbm1lbnQoZW52UGFyYW0sIHBhcmVudHMpO1xuXG4gICAgY29uc3QgZW52bG9ncyA9IFtdO1xuICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuZW52KSkge1xuICAgICAgY29uc3QgdnYgPSB2ID8/IFwiXCI7XG4gICAgICBjb25zdCB0cmltbWVkID1cbiAgICAgICAgdnYubGVuZ3RoID4gRU5WX1RSSU1fTEVOID8gdnYuc3Vic3RyKDAsIEVOVl9UUklNX0xFTikgKyBcIi4uLlwiIDogdnY7XG4gICAgICBlbnZsb2dzLnB1c2goYCR7a309JHt0cmltbWVkfWApO1xuICAgIH1cblxuICAgIGlmIChlbnZsb2dzLmxlbmd0aCkge1xuICAgICAgdGhpcy5sb2dEZWJ1ZyhncmF5KGAke3VuZGVybGluZShcImVudlwiKX06ICR7ZW52bG9ncy5qb2luKFwiIFwiKX1gKSk7XG4gICAgfVxuXG4gICAgLy8gZXZhbHVhdGUgY29uZGl0aW9uXG4gICAgaWYgKCF0aGlzLmV2YWxDb25kaXRpb24odGFzaykpIHtcbiAgICAgIHRoaXMubG9nKFwiY29uZGl0aW9uIGV4aXRlZCB3aXRoIG5vbi16ZXJvIC0gc2tpcHBpbmdcIik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gdmVyaWZ5IHdlIHJlcXVpcmVkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgZGVmaW5lZFxuICAgIGNvbnN0IG1lcmdlZCA9IHsgLi4ucHJvY2Vzcy5lbnYsIC4uLnRoaXMuZW52IH07XG4gICAgY29uc3QgbWlzc2luZyA9IG5ldyBBcnJheTxzdHJpbmc+KCk7XG4gICAgZm9yIChjb25zdCBuYW1lIG9mIHRhc2sucmVxdWlyZWRFbnYgPz8gW10pIHtcbiAgICAgIGlmICghKG5hbWUgaW4gbWVyZ2VkKSkge1xuICAgICAgICBtaXNzaW5nLnB1c2gobmFtZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG1pc3NpbmcubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgbWlzc2luZyByZXF1aXJlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXM6ICR7bWlzc2luZy5qb2luKFwiLFwiKX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qgc3RlcCBvZiB0YXNrLnN0ZXBzKSB7XG4gICAgICAvLyBldmFsdWF0ZSBzdGVwIGNvbmRpdGlvblxuICAgICAgaWYgKCF0aGlzLmV2YWxDb25kaXRpb24oc3RlcCkpIHtcbiAgICAgICAgdGhpcy5sb2coXCJjb25kaXRpb24gZXhpdGVkIHdpdGggbm9uLXplcm8gLSBza2lwcGluZ1wiKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGFyZ3NMaXN0OiBzdHJpbmdbXSA9IFtcbiAgICAgICAgLi4uKHN0ZXAuYXJncyB8fCBbXSksXG4gICAgICAgIC4uLihzdGVwLnJlY2VpdmVBcmdzID8gYXJncyA6IFtdKSxcbiAgICAgIF0ubWFwKChhKSA9PiBhLnRvU3RyaW5nKCkpO1xuXG4gICAgICBpZiAoc3RlcC5zYXkpIHtcbiAgICAgICAgbG9nZ2luZy5pbmZvKHRoaXMuZm10TG9nKHN0ZXAuc2F5KSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzdGVwLnNwYXduKSB7XG4gICAgICAgIHRoaXMucnVudGltZS5ydW5UYXNrKFxuICAgICAgICAgIHN0ZXAuc3Bhd24sXG4gICAgICAgICAgWy4uLnRoaXMucGFyZW50cywgdGhpcy50YXNrLm5hbWVdLFxuICAgICAgICAgIGFyZ3NMaXN0LFxuICAgICAgICAgIHN0ZXAuZW52XG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGV4ZWNzID0gc3RlcC5leGVjID8gW3N0ZXAuZXhlY10gOiBbXTtcblxuICAgICAgLy8gUGFyc2Ugc3RlcC1zcGVjaWZpYyBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbiAgICAgIGNvbnN0IGVudiA9IHRoaXMuZXZhbEVudmlyb25tZW50KHN0ZXAuZW52ID8/IHt9KTtcblxuICAgICAgaWYgKHN0ZXAuYnVpbHRpbikge1xuICAgICAgICBleGVjcy5wdXNoKHRoaXMucmVuZGVyQnVpbHRpbihzdGVwLmJ1aWx0aW4pKTtcbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBleGVjIG9mIGV4ZWNzKSB7XG4gICAgICAgIGxldCBoYXNFcnJvciA9IGZhbHNlO1xuXG4gICAgICAgIGxldCBjb21tYW5kID0gbWFrZUNyb3NzUGxhdGZvcm0oZXhlYyk7XG5cbiAgICAgICAgaWYgKGNvbW1hbmQuaW5jbHVkZXMoUVVPVEVEX0FSR1NfTUFSS0VSKSkge1xuICAgICAgICAgIC8vIFBvb3JseSBpbWl0YXRlIGJhc2ggcXVvdGVkIHZhcmlhYmxlIGV4cGFuc2lvbi4gSWYgXCIkQFwiIGlzIGVuY291bnRlcmVkIGluIGJhc2gsIGVsZW1lbnRzIG9mIHRoZSBhcmcgYXJyYXlcbiAgICAgICAgICAvLyB0aGF0IGNvbnRhaW4gd2hpdGVzcGFjZSB3aWxsIGJlIHNpbmdsZSBxdW90ZWQgKCdhcmcnKS4gVGhpcyBwcmVzZXJ2ZXMgd2hpdGVzcGFjZSBpbiB0aGluZ3MgbGlrZSBmaWxlbmFtZXMuXG4gICAgICAgICAgLy8gSW1pdGF0ZSB0aGF0IGJlaGF2aW9yIGhlcmUgYnkgc2luZ2xlIHF1b3RpbmcgZXZlcnkgZWxlbWVudCBvZiB0aGUgYXJnIGFycmF5IHdoZW4gYSBxdW90ZWQgYXJnIG1hcmtlciAoXCIkQFwiKVxuICAgICAgICAgIC8vIGlzIGVuY291bnRlcmVkLlxuICAgICAgICAgIGNvbW1hbmQgPSBjb21tYW5kLnJlcGxhY2UoXG4gICAgICAgICAgICBRVU9URURfQVJHU19NQVJLRVIsXG4gICAgICAgICAgICBhcmdzTGlzdC5tYXAoKGFyZykgPT4gYCcke2FyZ30nYCkuam9pbihcIiBcIilcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2UgaWYgKGNvbW1hbmQuaW5jbHVkZXMoQVJHU19NQVJLRVIpKSB7XG4gICAgICAgICAgY29tbWFuZCA9IGNvbW1hbmQucmVwbGFjZShBUkdTX01BUktFUiwgYXJnc0xpc3Quam9pbihcIiBcIikpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbW1hbmQgPSBbY29tbWFuZCwgLi4uYXJnc0xpc3RdLmpvaW4oXCIgXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY3dkID0gc3RlcC5jd2Q7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5zaGVsbCh7XG4gICAgICAgICAgICBjb21tYW5kLFxuICAgICAgICAgICAgY3dkLFxuICAgICAgICAgICAgZXh0cmFFbnY6IGVudixcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBoYXNFcnJvciA9IHJlc3VsdC5zdGF0dXMgIT09IDA7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAvLyBUaGlzIGlzIHRoZSBlcnJvciAnc2h4JyB3aWxsIHRocm93XG4gICAgICAgICAgaWYgKChlIGFzIGFueSk/Lm1lc3NhZ2U/LnN0YXJ0c1dpdGgoXCJub24temVybyBleGl0IGNvZGU6XCIpKSB7XG4gICAgICAgICAgICBoYXNFcnJvciA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGhhc0Vycm9yKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYFRhc2sgXCIke1xuICAgICAgICAgICAgICB0aGlzLmZ1bGxuYW1lXG4gICAgICAgICAgICB9XCIgZmFpbGVkIHdoZW4gZXhlY3V0aW5nIFwiJHtjb21tYW5kfVwiIChjd2Q6ICR7cmVzb2x2ZShcbiAgICAgICAgICAgICAgY3dkID8/IHRoaXMud29ya2RpclxuICAgICAgICAgICAgKX0pYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyBpZiBhIHRhc2sgc2hvdWxkIGJlIGV4ZWN1dGVkIGJhc2VkIG9uIFwiY29uZGl0aW9uXCIuXG4gICAqXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIHRhc2sgc2hvdWxkIGJlIGV4ZWN1dGVkIG9yIGZhbHNlIGlmIHRoZSBjb25kaXRpb25cbiAgICogZXZhbHVhdGVzIHRvIGZhbHNlIChleGl0cyB3aXRoIG5vbi16ZXJvKSwgaW5kaWNhdGluZyB0aGF0IHRoZSB0YXNrIHNob3VsZFxuICAgKiBiZSBza2lwcGVkLlxuICAgKi9cbiAgcHJpdmF0ZSBldmFsQ29uZGl0aW9uKHRhc2tPclN0ZXA6IFRhc2tTcGVjIHwgVGFza1N0ZXApIHtcbiAgICAvLyBubyBjb25kaXRpb24sIGNhcnJ5IG9uXG4gICAgaWYgKCF0YXNrT3JTdGVwLmNvbmRpdGlvbikge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgdGhpcy5sb2coZ3JheShgJHt1bmRlcmxpbmUoXCJjb25kaXRpb25cIil9OiAke3Rhc2tPclN0ZXAuY29uZGl0aW9ufWApKTtcbiAgICBjb25zdCByZXN1bHQgPSB0aGlzLnNoZWxsKHtcbiAgICAgIGNvbW1hbmQ6IHRhc2tPclN0ZXAuY29uZGl0aW9uLFxuICAgICAgbG9ncHJlZml4OiBcImNvbmRpdGlvbjogXCIsXG4gICAgICBxdWlldDogdHJ1ZSxcbiAgICB9KTtcbiAgICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gMCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXZhbHVhdGVzIGVudmlyb25tZW50IHZhcmlhYmxlcyBmcm9tIHNoZWxsIGNvbW1hbmRzIChlLmcuIGAkKHh4KWApXG4gICAqL1xuICBwcml2YXRlIGV2YWxFbnZpcm9ubWVudChlbnY6IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB9KSB7XG4gICAgY29uc3Qgb3V0cHV0OiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfCB1bmRlZmluZWQgfSA9IHt9O1xuXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoZW52ID8/IHt9KSkge1xuICAgICAgaWYgKFN0cmluZyh2YWx1ZSkuc3RhcnRzV2l0aChcIiQoXCIpICYmIFN0cmluZyh2YWx1ZSkuZW5kc1dpdGgoXCIpXCIpKSB7XG4gICAgICAgIGNvbnN0IHF1ZXJ5ID0gdmFsdWUuc3Vic3RyaW5nKDIsIHZhbHVlLmxlbmd0aCAtIDEpO1xuICAgICAgICBjb25zdCByZXN1bHQgPSB0aGlzLnNoZWxsRXZhbCh7IGNvbW1hbmQ6IHF1ZXJ5IH0pO1xuICAgICAgICBpZiAocmVzdWx0LnN0YXR1cyAhPT0gMCkge1xuICAgICAgICAgIGNvbnN0IGVycm9yID0gcmVzdWx0LmVycm9yXG4gICAgICAgICAgICA/IHJlc3VsdC5lcnJvci5zdGFja1xuICAgICAgICAgICAgOiByZXN1bHQuc3RkZXJyPy50b1N0cmluZygpID8/IFwidW5rbm93biBlcnJvclwiO1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGB1bmFibGUgdG8gZXZhbHVhdGUgZW52aXJvbm1lbnQgdmFyaWFibGUgJHtrZXl9PSR7dmFsdWV9OiAke2Vycm9yfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIG91dHB1dFtrZXldID0gcmVzdWx0LnN0ZG91dC50b1N0cmluZyhcInV0Zi04XCIpLnRyaW0oKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG91dHB1dFtrZXldID0gdmFsdWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvdXRwdXQ7XG4gIH1cblxuICAvKipcbiAgICogUmVuZGVycyB0aGUgcnVudGltZSBlbnZpcm9ubWVudCBmb3IgYSB0YXNrLiBOYW1lbHksIGl0IHN1cHBvcnRzIHRoaXMgc3ludGF4XG4gICAqIGAkKHh4KWAgZm9yIGFsbG93aW5nIGVudmlyb25tZW50IHRvIGJlIGV2YWx1YXRlZCBieSBleGVjdXRpbmcgYSBzaGVsbFxuICAgKiBjb21tYW5kIGFuZCBvYnRhaW5pbmcgaXRzIHJlc3VsdC5cbiAgICovXG4gIHByaXZhdGUgcmVzb2x2ZUVudmlyb25tZW50KFxuICAgIGVudlBhcmFtOiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfSxcbiAgICBwYXJlbnRzOiBzdHJpbmdbXVxuICApIHtcbiAgICBsZXQgZW52ID0gdGhpcy5ydW50aW1lLm1hbmlmZXN0LmVudiA/PyB7fTtcblxuICAgIC8vIGFkZCBlbnYgZnJvbSBhbGwgcGFyZW50IHRhc2tzIG9uZSBieSBvbmVcbiAgICBmb3IgKGNvbnN0IHBhcmVudCBvZiBwYXJlbnRzKSB7XG4gICAgICBlbnYgPSB7XG4gICAgICAgIC4uLmVudixcbiAgICAgICAgLi4uKHRoaXMucnVudGltZS50cnlGaW5kVGFzayhwYXJlbnQpPy5lbnYgPz8ge30pLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBhcHBseSB0YXNrIGVudmlyb25tZW50LCB0aGVuIHRoZSBzcGVjaWZpYyBlbnYgbGFzdFxuICAgIGVudiA9IHtcbiAgICAgIC4uLmVudixcbiAgICAgIC4uLih0aGlzLnRhc2suZW52ID8/IHt9KSxcbiAgICAgIC4uLmVudlBhcmFtLFxuICAgIH07XG5cbiAgICByZXR1cm4gdGhpcy5ldmFsRW52aXJvbm1lbnQoZW52ID8/IHt9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBcImZ1bGwgbmFtZVwiIG9mIHRoZSB0YXNrIHdoaWNoIGluY2x1ZGVzIGFsbCBpdCdzIHBhcmVudCB0YXNrIG5hbWVzIGNvbmNhdGVuYXRlZCBieSBjaGV2cm9ucy5cbiAgICovXG4gIHByaXZhdGUgZ2V0IGZ1bGxuYW1lKCkge1xuICAgIHJldHVybiBbLi4udGhpcy5wYXJlbnRzLCB0aGlzLnRhc2submFtZV0uam9pbihcIiDCuyBcIik7XG4gIH1cblxuICBwcml2YXRlIGxvZyguLi5hcmdzOiBhbnlbXSkge1xuICAgIGxvZ2dpbmcudmVyYm9zZSh0aGlzLmZtdExvZyguLi5hcmdzKSk7XG4gIH1cblxuICBwcml2YXRlIGxvZ0RlYnVnKC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgbG9nZ2luZy5kZWJ1Zyh0aGlzLmZtdExvZyguLi5hcmdzKSk7XG4gIH1cblxuICBwcml2YXRlIGZtdExvZyguLi5hcmdzOiBhbnlbXSkge1xuICAgIHJldHVybiBmb3JtYXQoYCR7dW5kZXJsaW5lKHRoaXMuZnVsbG5hbWUpfSB8YCwgLi4uYXJncyk7XG4gIH1cblxuICBwcml2YXRlIHNoZWxsKG9wdGlvbnM6IFNoZWxsT3B0aW9ucykge1xuICAgIGNvbnN0IHF1aWV0ID0gb3B0aW9ucy5xdWlldCA/PyBmYWxzZTtcbiAgICBpZiAoIXF1aWV0KSB7XG4gICAgICBjb25zdCBsb2cgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuXG4gICAgICBpZiAob3B0aW9ucy5sb2dwcmVmaXgpIHtcbiAgICAgICAgbG9nLnB1c2gob3B0aW9ucy5sb2dwcmVmaXgpO1xuICAgICAgfVxuXG4gICAgICBsb2cucHVzaChvcHRpb25zLmNvbW1hbmQpO1xuXG4gICAgICBpZiAob3B0aW9ucy5jd2QpIHtcbiAgICAgICAgbG9nLnB1c2goYChjd2Q6ICR7b3B0aW9ucy5jd2R9KWApO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmxvZyhsb2cuam9pbihcIiBcIikpO1xuICAgIH1cblxuICAgIGNvbnN0IGN3ZCA9IG9wdGlvbnMuY3dkID8/IHRoaXMud29ya2RpcjtcbiAgICBpZiAoIWV4aXN0c1N5bmMoY3dkKSB8fCAhc3RhdFN5bmMoY3dkKS5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBpbnZhbGlkIHdvcmtkaXIgKGN3ZCk6ICR7Y3dkfSBtdXN0IGJlIGFuIGV4aXN0aW5nIGRpcmVjdG9yeWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNwYXduU3luYyhvcHRpb25zLmNvbW1hbmQsIHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICBjd2QsXG4gICAgICBzaGVsbDogdHJ1ZSxcbiAgICAgIHN0ZGlvOiBcImluaGVyaXRcIixcbiAgICAgIGVudjoge1xuICAgICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgICAgLi4udGhpcy5lbnYsXG4gICAgICAgIC4uLm9wdGlvbnMuZXh0cmFFbnYsXG4gICAgICB9LFxuICAgICAgLi4ub3B0aW9ucy5zcGF3bk9wdGlvbnMsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHNoZWxsRXZhbChvcHRpb25zOiBTaGVsbE9wdGlvbnMpIHtcbiAgICByZXR1cm4gdGhpcy5zaGVsbCh7XG4gICAgICBxdWlldDogdHJ1ZSxcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICBzcGF3bk9wdGlvbnM6IHtcbiAgICAgICAgc3RkaW86IFtcImluaGVyaXRcIiwgXCJwaXBlXCIsIFwiaW5oZXJpdFwiXSxcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHJlbmRlckJ1aWx0aW4oYnVpbHRpbjogc3RyaW5nKSB7XG4gICAgY29uc3QgbW9kdWxlUm9vdCA9IGRpcm5hbWUocmVxdWlyZS5yZXNvbHZlKFwiLi4vcGFja2FnZS5qc29uXCIpKTtcbiAgICBjb25zdCBwcm9ncmFtID0gcmVxdWlyZS5yZXNvbHZlKFxuICAgICAgam9pbihtb2R1bGVSb290LCBcImxpYlwiLCBgJHtidWlsdGlufS50YXNrLmpzYClcbiAgICApO1xuICAgIHJldHVybiBgXCIke3Byb2Nlc3MuZXhlY1BhdGh9XCIgXCIke3Byb2dyYW19XCJgO1xuICB9XG59XG5cbmludGVyZmFjZSBTaGVsbE9wdGlvbnMge1xuICByZWFkb25seSBjb21tYW5kOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBAZGVmYXVsdCAtIHByb2plY3QgZGlyXG4gICAqL1xuICByZWFkb25seSBjd2Q/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGxvZ3ByZWZpeD86IHN0cmluZztcbiAgcmVhZG9ubHkgc3Bhd25PcHRpb25zPzogU3Bhd25PcHRpb25zO1xuICAvKiogQGRlZmF1bHQgZmFsc2UgKi9cbiAgcmVhZG9ubHkgcXVpZXQ/OiBib29sZWFuO1xuICByZWFkb25seSBleHRyYUVudj86IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9O1xufVxuIl19