gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
339 lines • 63.2 kB
JavaScript
import { Utils } from "./utils.js";
import fs from "fs-extra";
import assert, { AssertionError } from "assert";
import chalk from "chalk";
import { Parser } from "./parser.js";
import axios from "axios";
import path from "path";
import semver from "semver";
import { RE2JS } from "re2js";
export class ParserIncludes {
static count = 0;
static resetCount() {
this.count = 0;
}
static normalizeTriggerInclude(gitlabData, opts) {
const { writeStreams } = opts;
for (const [jobName, jobData] of Object.entries(gitlabData ?? {})) {
if (typeof jobData.trigger?.include === "string") {
jobData.trigger.include = [{
local: jobData.trigger.include,
}];
}
else if (jobData.trigger?.project) {
writeStreams.memoStdout(chalk `{bgYellowBright WARN } The job: \`{blueBright ${jobName}}\` will be no-op. Multi-project pipeline is not supported by gitlab-ci-local\n`);
}
}
}
static async init(gitlabData, opts) {
const { argv } = opts;
this.count++;
assert(this.count <= opts.maximumIncludes + 1, // 1st init call is not counted
chalk `This GitLab CI configuration is invalid: Maximum of {blueBright ${opts.maximumIncludes}} nested includes are allowed!. This limit can be increased with the --maximum-includes cli flags.`);
let includeDatas = [];
const promises = [];
const { stateDir, cwd, fetchIncludes, gitData, expandVariables } = opts;
const include = this.expandInclude(gitlabData?.include, opts.variables);
this.normalizeTriggerInclude(gitlabData, opts);
// Find files to fetch from remote and place in .gitlab-ci-local/includes
for (const value of include) {
if (value["rules"]) {
const include_rules = value["rules"];
const rulesResult = Utils.getRulesResult({ argv, cwd, rules: include_rules, variables: opts.variables }, gitData);
if (rulesResult.when === "never") {
continue;
}
}
if (value["file"]) {
for (const fileValue of Array.isArray(value["file"]) ? value["file"] : [value["file"]]) {
promises.push(this.downloadIncludeProjectFile(cwd, stateDir, value["project"], value["ref"] || "HEAD", fileValue, gitData, fetchIncludes));
}
}
else if (value["template"]) {
const { project, ref, file, domain } = this.covertTemplateToProjectFile(value["template"]);
const url = `https://${domain}/${project}/-/raw/${ref}/${file}`;
promises.push(this.downloadIncludeRemote(cwd, stateDir, url, fetchIncludes));
}
else if (value["remote"]) {
promises.push(this.downloadIncludeRemote(cwd, stateDir, value["remote"], fetchIncludes));
}
}
await Promise.all(promises);
for (const value of include) {
if (value["rules"]) {
const include_rules = value["rules"];
const rulesResult = Utils.getRulesResult({ argv, cwd, rules: include_rules, variables: opts.variables }, gitData);
if (rulesResult.when === "never") {
continue;
}
}
if (value["local"]) {
validateIncludeLocal(value["local"]);
const files = await resolveIncludeLocal(value["local"], cwd);
if (files.length == 0) {
throw new AssertionError({ message: `Local include file cannot be found ${value["local"]}` });
}
for (const localFile of files) {
const content = await Parser.loadYaml(localFile, { inputs: value.inputs ?? {} }, expandVariables);
includeDatas = includeDatas.concat(await this.init(content, opts));
}
}
else if (value["project"]) {
for (const fileValue of Array.isArray(value["file"]) ? value["file"] : [value["file"]]) {
const fileDoc = await Parser.loadYaml(`${cwd}/${stateDir}/includes/${gitData.remote.host}/${value["project"]}/${value["ref"] || "HEAD"}/${fileValue}`, { inputs: value.inputs || {} }, expandVariables);
// Expand local includes inside a "project"-like include
fileDoc["include"] = this.expandInclude(fileDoc["include"], opts.variables);
fileDoc["include"].forEach((inner, i) => {
if (!inner["local"])
return;
if (inner["rules"]) {
const rulesResult = Utils.getRulesResult({ argv, cwd: opts.cwd, variables: opts.variables, rules: inner["rules"] }, gitData);
if (rulesResult.when === "never") {
return;
}
}
fileDoc["include"][i] = {
project: value["project"],
file: inner["local"].replace(/^\//, ""),
ref: value["ref"],
inputs: inner.inputs || {},
};
});
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
}
}
else if (value["component"]) {
const { domain, port, projectPath, componentName, ref, isLocalComponent } = this.parseIncludeComponent(value["component"], gitData);
// converts component to project. gitlab allows two different file path ways to include a component
let files = [`${componentName}.yml`, `${componentName}/template.yml`, null];
// If a file is present locally, keep only that one in the files array to avoid downloading the other one that never exists
if (!argv.fetchIncludes) {
for (const f of files) {
const localFileName = `${cwd}/${stateDir}/includes/${gitData.remote.host}/${projectPath}/${ref}/${f}`;
if (fs.existsSync(localFileName)) {
files = [f];
break;
}
}
}
for (const f of files) {
assert(f !== null, `This GitLab CI configuration is invalid: component: \`${value["component"]}\`. One of the files [${files}] must exist in \`${domain}` +
(port ? `:${port}` : "") + `/${projectPath}\``);
if (isLocalComponent) {
const localComponentInclude = `${cwd}/${f}`;
if (!(await fs.pathExists(localComponentInclude))) {
continue;
}
const content = await Parser.loadYaml(localComponentInclude, { inputs: value.inputs || {} }, expandVariables);
includeDatas = includeDatas.concat(await this.init(content, opts));
break;
}
else {
const localFileName = `${cwd}/${stateDir}/includes/${gitData.remote.host}/${projectPath}/${ref}/${f}`;
// Check remotely only if the file does not exist locally
if (!fs.existsSync(localFileName) && !(await Utils.remoteFileExist(cwd, f, ref, domain, projectPath, gitData.remote.schema, gitData.remote.port))) {
continue;
}
const fileDoc = {
include: {
project: projectPath,
file: f,
ref: ref,
inputs: value.inputs || {},
},
};
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
break;
}
}
}
else if (value["template"]) {
const { project, ref, file, domain } = this.covertTemplateToProjectFile(value["template"]);
const fsUrl = Utils.fsUrl(`https://${domain}/${project}/-/raw/${ref}/${file}`);
const fileDoc = await Parser.loadYaml(`${cwd}/${stateDir}/includes/${fsUrl}`, { inputs: value.inputs || {} }, expandVariables);
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
}
else if (value["remote"]) {
const fsUrl = Utils.fsUrl(value["remote"]);
const fileDoc = await Parser.loadYaml(`${cwd}/${stateDir}/includes/${fsUrl}`, { inputs: value.inputs || {} }, expandVariables);
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
}
else {
throw new AssertionError({ message: `Didn't understand include ${JSON.stringify(value)}` });
}
}
includeDatas.push(gitlabData);
return includeDatas;
}
static expandInclude(i, variables) {
let include = i || [];
if (include && include.length == null) {
include = [i];
}
if (typeof include === "string") {
include = [include];
}
for (const [index, entry] of Object.entries(include)) {
if (typeof entry === "string" && (entry.startsWith("https:") || entry.startsWith("http:"))) {
include[index] = { "remote": entry };
}
else if (typeof entry === "string") {
include[index] = { "local": entry };
}
else {
include[index] = entry;
}
}
for (const entry of include) {
for (const [key, value] of Object.entries(entry)) {
if (Array.isArray(value)) {
entry[key] = value.map((v) => Utils.expandText(v, variables));
}
else {
entry[key] = Utils.expandText(value, variables);
}
}
}
return include;
}
static covertTemplateToProjectFile(template) {
return {
domain: "gitlab.com",
project: "gitlab-org/gitlab",
ref: "HEAD",
file: `lib/gitlab/ci/templates/${template}`,
};
}
static parseIncludeComponent(component, gitData) {
assert(!component.includes("://"), `This GitLab CI configuration is invalid: component: \`${component}\` should not contain protocol`);
const pattern = /(?<domain>[^/:\s]+)(:(?<port>\d+))?\/(?<projectPath>.+)\/(?<componentName>[^@]+)@(?<ref>.+)/; // https://regexr.com/7v7hm
const gitRemoteMatch = pattern.exec(component);
if (gitRemoteMatch?.groups == null)
throw new Error(`This is a bug, please create a github issue if this is something you're expecting to work. input: ${component}`);
const { domain, projectPath, port } = gitRemoteMatch.groups;
let ref = gitRemoteMatch.groups["ref"];
const isLocalComponent = projectPath === `${gitData.remote.group}/${gitData.remote.project}` && ref === gitData.commit.SHA;
if (!isLocalComponent) {
const semanticVersionRangesPattern = /^\d+(\.\d+)?$/;
if (ref == "~latest" || semanticVersionRangesPattern.test(ref)) {
// https://docs.gitlab.com/ci/components/#semantic-version-ranges
let stdout;
try {
stdout = Utils.syncSpawn(["git", "ls-remote", "--tags", `git@${domain}:${projectPath}`]).stdout;
}
catch {
stdout = Utils.syncSpawn(["git", "ls-remote", "--tags", `https://${domain}:${port ?? 443}/${projectPath}.git`]).stdout;
}
assert(stdout);
const tags = stdout
.split("\n")
.map((line) => {
return line
.split("\t")[1]
.split("/")[2];
});
const _ref = resolveSemanticVersionRange(ref, tags);
assert(_ref, `This GitLab CI configuration is invalid: component: \`${component}\` - The ref (${ref}) is invalid`);
ref = _ref;
}
}
return {
domain: domain,
port: port,
projectPath: projectPath,
componentName: `templates/${gitRemoteMatch.groups["componentName"]}`,
ref: ref,
isLocalComponent: isLocalComponent,
};
}
static async downloadIncludeRemote(cwd, stateDir, url, fetchIncludes) {
const fsUrl = Utils.fsUrl(url);
try {
const target = `${cwd}/${stateDir}/includes/${fsUrl}`;
if (await fs.pathExists(target) && !fetchIncludes)
return;
const res = await axios.get(url, { headers: { "User-Agent": "gitlab-ci-local" } });
await fs.outputFile(target, res.data);
}
catch (e) {
throw new AssertionError({ message: `Remote include could not be fetched ${url}\n${e}` });
}
}
static async downloadIncludeProjectFile(cwd, stateDir, project, ref, file, gitData, fetchIncludes) {
const remote = gitData.remote;
const normalizedFile = file.replace(/^\/+/, "");
try {
const target = `${stateDir}/includes/${remote.host}/${project}/${ref}`;
if (await fs.pathExists(`${cwd}/${target}/${normalizedFile}`) && !fetchIncludes)
return;
if (remote.schema.startsWith("http")) {
const ext = "tmp-" + Math.random();
await fs.mkdirp(path.dirname(`${cwd}/${target}/${normalizedFile}`));
const gitCloneBranch = (ref === "HEAD") ? "" : `--branch ${ref}`;
await Utils.bashMulti([
`cd ${cwd}/${stateDir}`,
`git clone ${gitCloneBranch} -n --depth=1 --filter=tree:0 ${remote.schema}://${remote.host}:${remote.port}/${project}.git ${cwd}/${target}.${ext}`,
`cd ${cwd}/${target}.${ext}`,
`git sparse-checkout set --no-cone ${normalizedFile}`,
"git checkout",
`cd ${cwd}/${stateDir}`,
`cp ${cwd}/${target}.${ext}/${normalizedFile} ${cwd}/${target}/${normalizedFile}`,
], cwd);
}
else {
await fs.mkdirp(`${cwd}/${target}`);
await Utils.bash(`set -eou pipefail; git archive --remote=ssh://git@${remote.host}:${remote.port}/${project}.git ${ref} ${normalizedFile} | tar -f - -xC ${target}/`, cwd);
}
}
catch (e) {
throw new AssertionError({ message: `Project include could not be fetched { project: ${project}, ref: ${ref}, file: ${normalizedFile} }\n${e}` });
}
}
static memoLocalRepoFiles = (() => {
const cache = new Map();
return async (path) => {
let result = cache.get(path);
if (typeof result !== "undefined")
return result;
result = (await Utils.getTrackedFiles(path)).map(p => `${path}/${p}`);
cache.set(path, result);
return result;
};
})();
}
export function validateIncludeLocal(filePath) {
assert(!filePath.startsWith("./"), `\`${filePath}\` for include:local is invalid. Gitlab does not support relative path (ie. cannot start with \`./\`).`);
assert(!filePath.includes(".."), `\`${filePath}\` for include:local is invalid. Gitlab does not support directory traversal.`);
}
export function resolveSemanticVersionRange(range, gitTags) {
/** sorted list of tags thats compliant to semantic version where index 0 is the latest */
const sanitizedSemverTags = semver.rsort(gitTags.filter(s => semver.valid(s)));
const found = sanitizedSemverTags.find(t => {
if (range == "~latest") {
const semverParsed = semver.parse(t);
assert(semverParsed);
return (semverParsed.prerelease.length == 0 && semverParsed.build.length == 0);
}
else {
return semver.satisfies(t, range);
}
});
return found;
}
export async function resolveIncludeLocal(pattern, cwd) {
const repoFiles = await ParserIncludes.memoLocalRepoFiles(cwd);
if (!pattern.startsWith("/"))
pattern = `/${pattern}`; // Ensure pattern starts with `/`
pattern = `${cwd}${pattern}`;
// escape all special regex metacharacters
pattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// `**` matches anything
const anything = ".*?";
pattern = pattern.replace(/\\\*\\\*/g, anything);
// `*` matches anything except for `/`
const anything_but_not_slash = "([^/])*?";
pattern = pattern.replace(/\\\*/g, anything_but_not_slash);
const re2js = RE2JS.compile(`^${pattern}`);
return repoFiles.filter((f) => re2js.matches(f));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2VyLWluY2x1ZGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicGFyc2VyLWluY2x1ZGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBQyxLQUFLLEVBQUMsTUFBTSxZQUFZLENBQUM7QUFDakMsT0FBTyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRzFCLE9BQU8sTUFBTSxFQUFFLEVBQUMsY0FBYyxFQUFDLE1BQU0sUUFBUSxDQUFDO0FBQzlDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sYUFBYSxDQUFDO0FBQ25DLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQzVCLE9BQU8sRUFBQyxLQUFLLEVBQUMsTUFBTSxPQUFPLENBQUM7QUFjNUIsTUFBTSxPQUFPLGNBQWM7SUFDZixNQUFNLENBQUMsS0FBSyxHQUFXLENBQUMsQ0FBQztJQUVqQyxNQUFNLENBQUMsVUFBVTtRQUNiLElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ25CLENBQUM7SUFFTyxNQUFNLENBQUMsdUJBQXVCLENBQUUsVUFBZSxFQUFFLElBQStCO1FBQ3BGLE1BQU0sRUFBQyxZQUFZLEVBQUMsR0FBRyxJQUFJLENBQUM7UUFDNUIsS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQU0sVUFBVSxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDckUsSUFBSSxPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsT0FBTyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUMvQyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sR0FBRyxDQUFDO3dCQUN2QixLQUFLLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPO3FCQUNqQyxDQUFF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QyxDQUFDO0lBQzNDLE9BQU8sU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzFELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FyZ3Z9IGZyb20gXCIuL2FyZ3YuanNcIjtcbmltcG9ydCB7VXRpbHN9IGZyb20gXCIuL3V0aWxzLmpzXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzLWV4dHJhXCI7XG5pbXBvcnQge1dyaXRlU3RyZWFtc30gZnJvbSBcIi4vd3JpdGUtc3RyZWFtcy5qc1wiO1xuaW1wb3J0IHtHaXREYXRhfSBmcm9tIFwiLi9naXQtZGF0YS5qc1wiO1xuaW1wb3J0IGFzc2VydCwge0Fzc2VydGlvbkVycm9yfSBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQge1BhcnNlcn0gZnJvbSBcIi4vcGFyc2VyLmpzXCI7XG5pbXBvcnQgYXhpb3MgZnJvbSBcImF4aW9zXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHNlbXZlciBmcm9tIFwic2VtdmVyXCI7XG5pbXBvcnQge1JFMkpTfSBmcm9tIFwicmUyanNcIjtcblxudHlwZSBQYXJzZXJJbmNsdWRlc0luaXRPcHRpb25zID0ge1xuICAgIGFyZ3Y6IEFyZ3Y7XG4gICAgY3dkOiBzdHJpbmc7XG4gICAgc3RhdGVEaXI6IHN0cmluZztcbiAgICB3cml0ZVN0cmVhbXM6IFdyaXRlU3RyZWFtcztcbiAgICBnaXREYXRhOiBHaXREYXRhO1xuICAgIGZldGNoSW5jbHVkZXM6IGJvb2xlYW47XG4gICAgdmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfTtcbiAgICBleHBhbmRWYXJpYWJsZXM6IGJvb2xlYW47XG4gICAgbWF4aW11bUluY2x1ZGVzOiBudW1iZXI7XG59O1xuXG5leHBvcnQgY2xhc3MgUGFyc2VySW5jbHVkZXMge1xuICAgIHByaXZhdGUgc3RhdGljIGNvdW50OiBudW1iZXIgPSAwO1xuXG4gICAgc3RhdGljIHJlc2V0Q291bnQgKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmNvdW50ID0gMDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBub3JtYWxpemVUcmlnZ2VySW5jbHVkZSAoZ2l0bGFiRGF0YTogYW55LCBvcHRzOiBQYXJzZXJJbmNsdWRlc0luaXRPcHRpb25zKSB7XG4gICAgICAgIGNvbnN0IHt3cml0ZVN0cmVhbXN9ID0gb3B0cztcbiAgICAgICAgZm9yIChjb25zdCBbam9iTmFtZSwgam9iRGF0YV0gb2YgT2JqZWN0LmVudHJpZXM8YW55PihnaXRsYWJEYXRhID8/IHt9KSkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBqb2JEYXRhLnRyaWdnZXI/LmluY2x1ZGUgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgICBqb2JEYXRhLnRyaWdnZXIuaW5jbHVkZSA9IFt7XG4gICAgICAgICAgICAgICAgICAgIGxvY2FsOiBqb2JEYXRhLnRyaWdnZXIuaW5jbHVkZSxcbiAgICAgICAgICAgICAgICB9IF07XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGpvYkRhdGEudHJpZ2dlcj8ucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIHdyaXRlU3RyZWFtcy5tZW1vU3Rkb3V0KGNoYWxrYHtiZ1llbGxvd0JyaWdodCAgV0FSTiB9IFRoZSBqb2I6IFxcYHtibHVlQnJpZ2h0ICR7am9iTmFtZX19XFxgIHdpbGwgYmUgbm8tb3AuIE11bHRpLXByb2plY3QgcGlwZWxpbmUgaXMgbm90IHN1cHBvcnRlZCBieSBnaXRsYWItY2ktbG9jYWxcXG5gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHN0YXRpYyBhc3luYyBpbml0IChnaXRsYWJEYXRhOiBhbnksIG9wdHM6IFBhcnNlckluY2x1ZGVzSW5pdE9wdGlvbnMpOiBQcm9taXNlPGFueVtdPiB7XG4gICAgICAgIGNvbnN0IHthcmd2fSA9IG9wdHM7XG4gICAgICAgIHRoaXMuY291bnQrKztcbiAgICAgICAgYXNzZXJ0KFxuICAgICAgICAgICAgdGhpcy5jb3VudCA8PSBvcHRzLm1heGltdW1JbmNsdWRlcyArIDEsIC8vIDFzdCBpbml0IGNhbGwgaXMgbm90IGNvdW50ZWRcbiAgICAgICAgICAgIGNoYWxrYFRoaXMgR2l0TGFiIENJIGNvbmZpZ3VyYXRpb24gaXMgaW52YWxpZDogTWF4aW11bSBvZiB7Ymx1ZUJyaWdodCAke29wdHMubWF4aW11bUluY2x1ZGVzfX0gbmVzdGVkIGluY2x1ZGVzIGFyZSBhbGxvd2VkIS4gVGhpcyBsaW1pdCBjYW4gYmUgaW5jcmVhc2VkIHdpdGggdGhlIC0tbWF4aW11bS1pbmNsdWRlcyBjbGkgZmxhZ3MuYCxcbiAgICAgICAgKTtcbiAgICAgICAgbGV0IGluY2x1ZGVEYXRhczogYW55W10gPSBbXTtcbiAgICAgICAgY29uc3QgcHJvbWlzZXMgPSBbXTtcbiAgICAgICAgY29uc3Qge3N0YXRlRGlyLCBjd2QsIGZldGNoSW5jbHVkZXMsIGdpdERhdGEsIGV4cGFuZFZhcmlhYmxlc30gPSBvcHRzO1xuXG4gICAgICAgIGNvbnN0IGluY2x1ZGUgPSB0aGlzLmV4cGFuZEluY2x1ZGUoZ2l0bGFiRGF0YT8uaW5jbHVkZSwgb3B0cy52YXJpYWJsZXMpO1xuXG4gICAgICAgIHRoaXMubm9ybWFsaXplVHJpZ2dlckluY2x1ZGUoZ2l0bGFiRGF0YSwgb3B0cyk7XG4gICAgICAgIC8vIEZpbmQgZmlsZXMgdG8gZmV0Y2ggZnJvbSByZW1vdGUgYW5kIHBsYWNlIGluIC5naXRsYWItY2ktbG9jYWwvaW5jbHVkZXNcbiAgICAgICAgZm9yIChjb25zdCB2YWx1ZSBvZiBpbmNsdWRlKSB7XG4gICAgICAgICAgICBpZiAodmFsdWVbXCJydWxlc1wiXSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGluY2x1ZGVfcnVsZXMgPSB2YWx1ZVtcInJ1bGVzXCJdO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJ1bGVzUmVzdWx0ID0gVXRpbHMuZ2V0UnVsZXNSZXN1bHQoe2FyZ3YsIGN3ZCwgcnVsZXM6IGluY2x1ZGVfcnVsZXMsIHZhcmlhYmxlczogb3B0cy52YXJpYWJsZXN9LCBnaXREYXRhKTtcbiAgICAgICAgICAgICAgICBpZiAocnVsZXNSZXN1bHQud2hlbiA9PT0gXCJuZXZlclwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh2YWx1ZVtcImZpbGVcIl0pIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGZpbGVWYWx1ZSBvZiBBcnJheS5pc0FycmF5KHZhbHVlW1wiZmlsZVwiXSkgPyB2YWx1ZVtcImZpbGVcIl0gOiBbdmFsdWVbXCJmaWxlXCJdXSkge1xuICAgICAgICAgICAgICAgICAgICBwcm9taXNlcy5wdXNoKHRoaXMuZG93bmxvYWRJbmNsdWRlUHJvamVjdEZpbGUoY3dkLCBzdGF0ZURpciwgdmFsdWVbXCJwcm9qZWN0XCJdLCB2YWx1ZVtcInJlZlwiXSB8fCBcIkhFQURcIiwgZmlsZVZhbHVlLCBnaXREYXRhLCBmZXRjaEluY2x1ZGVzKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZVtcInRlbXBsYXRlXCJdKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qge3Byb2plY3QsIHJlZiwgZmlsZSwgZG9tYWlufSA9IHRoaXMuY292ZXJ0VGVtcGxhdGVUb1Byb2plY3RGaWxlKHZhbHVlW1widGVtcGxhdGVcIl0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IHVybCA9IGBodHRwczovLyR7ZG9tYWlufS8ke3Byb2plY3R9Ly0vcmF3LyR7cmVmfS8ke2ZpbGV9YDtcbiAgICAgICAgICAgICAgICBwcm9taXNlcy5wdXNoKHRoaXMuZG93bmxvYWRJbmNsdWRlUmVtb3RlKGN3ZCwgc3RhdGVEaXIsIHVybCwgZmV0Y2hJbmNsdWRlcykpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZVtcInJlbW90ZVwiXSkge1xuICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2godGhpcy5kb3dubG9hZEluY2x1ZGVSZW1vdGUoY3dkLCBzdGF0ZURpciwgdmFsdWVbXCJyZW1vdGVcIl0sIGZldGNoSW5jbHVkZXMpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuXG4gICAgICAgIGZvciAoY29uc3QgdmFsdWUgb2YgaW5jbHVkZSkge1xuICAgICAgICAgICAgaWYgKHZhbHVlW1wicnVsZXNcIl0pIHtcbiAgICAgICAgICAgICAgICBjb25zdCBpbmNsdWRlX3J1bGVzID0gdmFsdWVbXCJydWxlc1wiXTtcbiAgICAgICAgICAgICAgICBjb25zdCBydWxlc1Jlc3VsdCA9IFV0aWxzLmdldFJ1bGVzUmVzdWx0KHthcmd2LCBjd2QsIHJ1bGVzOiBpbmNsdWRlX3J1bGVzLCB2YXJpYWJsZXM6IG9wdHMudmFyaWFibGVzfSwgZ2l0RGF0YSk7XG4gICAgICAgICAgICAgICAgaWYgKHJ1bGVzUmVzdWx0LndoZW4gPT09IFwibmV2ZXJcIikge1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodmFsdWVbXCJsb2NhbFwiXSkge1xuICAgICAgICAgICAgICAgIHZhbGlkYXRlSW5jbHVkZUxvY2FsKHZhbHVlW1wibG9jYWxcIl0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgcmVzb2x2ZUluY2x1ZGVMb2NhbCh2YWx1ZVtcImxvY2FsXCJdLCBjd2QpO1xuICAgICAgICAgICAgICAgIGlmIChmaWxlcy5sZW5ndGggPT0gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgQXNzZXJ0aW9uRXJyb3Ioe21lc3NhZ2U6IGBMb2NhbCBpbmNsdWRlIGZpbGUgY2Fubm90IGJlIGZvdW5kICR7dmFsdWVbXCJsb2NhbFwiXX1gfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgbG9jYWxGaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBQYXJzZXIubG9hZFlhbWwobG9jYWxGaWxlLCB7aW5wdXRzOiB2YWx1ZS5pbnB1dHMgPz8ge319LCBleHBhbmRWYXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICBpbmNsdWRlRGF0YXMgPSBpbmNsdWRlRGF0YXMuY29uY2F0KGF3YWl0IHRoaXMuaW5pdChjb250ZW50LCBvcHRzKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZVtcInByb2plY3RcIl0pIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGZpbGVWYWx1ZSBvZiBBcnJheS5pc0FycmF5KHZhbHVlW1wiZmlsZVwiXSkgPyB2YWx1ZVtcImZpbGVcIl0gOiBbdmFsdWVbXCJmaWxlXCJdXSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBmaWxlRG9jID0gYXdhaXQgUGFyc2VyLmxvYWRZYW1sKFxuICAgICAgICAgICAgICAgICAgICAgICAgYCR7Y3dkfS8ke3N0YXRlRGlyfS9pbmNsdWRlcy8ke2dpdERhdGEucmVtb3RlLmhvc3R9LyR7dmFsdWVbXCJwcm9qZWN0XCJdfS8ke3ZhbHVlW1wicmVmXCJdIHx8IFwiSEVBRFwifS8ke2ZpbGVWYWx1ZX1gXG4gICAgICAgICAgICAgICAgICAgICAgICAsIHtpbnB1dHM6IHZhbHVlLmlucHV0cyB8fCB7fX1cbiAgICAgICAgICAgICAgICAgICAgICAgICwgZXhwYW5kVmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gRXhwYW5kIGxvY2FsIGluY2x1ZGVzIGluc2lkZSBhIFwicHJvamVjdFwiLWxpa2UgaW5jbHVkZVxuICAgICAgICAgICAgICAgICAgICBmaWxlRG9jW1wiaW5jbHVkZVwiXSA9IHRoaXMuZXhwYW5kSW5jbHVkZShmaWxlRG9jW1wiaW5jbHVkZVwiXSwgb3B0cy52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICBmaWxlRG9jW1wiaW5jbHVkZVwiXS5mb3JFYWNoKChpbm5lcjogYW55LCBpOiBudW1iZXIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaW5uZXJbXCJsb2NhbFwiXSkgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlubmVyW1wicnVsZXNcIl0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBydWxlc1Jlc3VsdCA9IFV0aWxzLmdldFJ1bGVzUmVzdWx0KHthcmd2LCBjd2Q6IG9wdHMuY3dkLCB2YXJpYWJsZXM6IG9wdHMudmFyaWFibGVzLCBydWxlczogaW5uZXJbXCJydWxlc1wiXX0sIGdpdERhdGEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChydWxlc1Jlc3VsdC53aGVuID09PSBcIm5ldmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVEb2NbXCJpbmNsdWRlXCJdW2ldID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2plY3Q6IHZhbHVlW1wicHJvamVjdFwiXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlOiBpbm5lcltcImxvY2FsXCJdLnJlcGxhY2UoL15cXC8vLCBcIlwiKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWY6IHZhbHVlW1wicmVmXCJdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0czogaW5uZXIuaW5wdXRzIHx8IHt9LFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaW5jbHVkZURhdGFzID0gaW5jbHVkZURhdGFzLmNvbmNhdChhd2FpdCB0aGlzLmluaXQoZmlsZURvYywgb3B0cykpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWVbXCJjb21wb25lbnRcIl0pIHtcbiAgICAgICAgICAgICAgICBjb25zdCB7ZG9tYWluLCBwb3J0LCBwcm9qZWN0UGF0aCwgY29tcG9uZW50TmFtZSwgcmVmLCBpc0xvY2FsQ29tcG9uZW50fSA9IHRoaXMucGFyc2VJbmNsdWRlQ29tcG9uZW50KHZhbHVlW1wiY29tcG9uZW50XCJdLCBnaXREYXRhKTtcbiAgICAgICAgICAgICAgICAvLyBjb252ZXJ0cyBjb21wb25lbnQgdG8gcHJvamVjdC4gZ2l0bGFiIGFsbG93cyB0d28gZGlmZmVyZW50IGZpbGUgcGF0aCB3YXlzIHRvIGluY2x1ZGUgYSBjb21wb25lbnRcbiAgICAgICAgICAgICAgICBsZXQgZmlsZXMgPSBbYCR7Y29tcG9uZW50TmFtZX0ueW1sYCwgYCR7Y29tcG9uZW50TmFtZX0vdGVtcGxhdGUueW1sYCwgbnVsbF07XG5cbiAgICAgICAgICAgICAgICAvLyBJZiBhIGZpbGUgaXMgcHJlc2VudCBsb2NhbGx5LCBrZWVwIG9ubHkgdGhhdCBvbmUgaW4gdGhlIGZpbGVzIGFycmF5IHRvIGF2b2lkIGRvd25sb2FkaW5nIHRoZSBvdGhlciBvbmUgdGhhdCBuZXZlciBleGlzdHNcbiAgICAgICAgICAgICAgICBpZiAoIWFyZ3YuZmV0Y2hJbmNsdWRlcykge1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGYgb2YgZmlsZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGxvY2FsRmlsZU5hbWUgPSBgJHtjd2R9LyR7c3RhdGVEaXJ9L2luY2x1ZGVzLyR7Z2l0RGF0YS5yZW1vdGUuaG9zdH0vJHtwcm9qZWN0UGF0aH0vJHtyZWZ9LyR7Zn1gO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZzLmV4aXN0c1N5bmMobG9jYWxGaWxlTmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlcyA9IFtmXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZiBvZiBmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICBhc3NlcnQoZiAhPT0gbnVsbCwgYFRoaXMgR2l0TGFiIENJIGNvbmZpZ3VyYXRpb24gaXMgaW52YWxpZDogY29tcG9uZW50OiBcXGAke3ZhbHVlW1wiY29tcG9uZW50XCJdfVxcYC4gT25lIG9mIHRoZSBmaWxlcyBbJHtmaWxlc31dIG11c3QgZXhpc3QgaW4gXFxgJHtkb21haW59YCArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBvcnQgPyBgOiR7cG9ydH1gIDogXCJcIikgKyBgLyR7cHJvamVjdFBhdGh9XFxgYCk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGlzTG9jYWxDb21wb25lbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGxvY2FsQ29tcG9uZW50SW5jbHVkZSA9IGAke2N3ZH0vJHtmfWA7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIShhd2FpdCBmcy5wYXRoRXhpc3RzKGxvY2FsQ29tcG9uZW50SW5jbHVkZSkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBQYXJzZXIubG9hZFlhbWwobG9jYWxDb21wb25lbnRJbmNsdWRlLCB7aW5wdXRzOiB2YWx1ZS5pbnB1dHMgfHwge319LCBleHBhbmRWYXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZURhdGFzID0gaW5jbHVkZURhdGFzLmNvbmNhdChhd2FpdCB0aGlzLmluaXQoY29udGVudCwgb3B0cykpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBsb2NhbEZpbGVOYW1lID0gYCR7Y3dkfS8ke3N0YXRlRGlyfS9pbmNsdWRlcy8ke2dpdERhdGEucmVtb3RlLmhvc3R9LyR7cHJvamVjdFBhdGh9LyR7cmVmfS8ke2Z9YDtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENoZWNrIHJlbW90ZWx5IG9ubHkgaWYgdGhlIGZpbGUgZG9lcyBub3QgZXhpc3QgbG9jYWxseVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKGxvY2FsRmlsZU5hbWUpICYmICEoYXdhaXQgVXRpbHMucmVtb3RlRmlsZUV4aXN0KGN3ZCwgZiwgcmVmLCBkb21haW4sIHByb2plY3RQYXRoLCBnaXREYXRhLnJlbW90ZS5zY2hlbWEsIGdpdERhdGEucmVtb3RlLnBvcnQpKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmaWxlRG9jID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGU6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvamVjdDogcHJvamVjdFBhdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGU6IGYsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZjogcmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dHM6IHZhbHVlLmlucHV0cyB8fCB7fSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVEYXRhcyA9IGluY2x1ZGVEYXRhcy5jb25jYXQo