UNPKG

gitlab-ci-local

Version:

Tired of pushing to test your .gitlab-ci.yml?

387 lines 73.1 kB
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; // cache the parsed component, because parseIncludeComponent is expensive and we would call it twice otherwise const componentParseCache = new Map(); 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 [index, value] of include.entries()) { 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)); } else if (value["component"]) { const component = this.parseIncludeComponent(value["component"], gitData); componentParseCache.set(index, component); if (!component.isLocal) { promises.push(this.downloadIncludeComponent(cwd, stateDir, component.projectPath, component.ref, component.name, gitData, fetchIncludes)); } } } await Promise.all(promises); for (const [index, value] of include.entries()) { 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.expandInnerLocalIncludes(fileDoc["include"], value["project"], value["ref"], opts); includeDatas = includeDatas.concat(await this.init(fileDoc, opts)); } } else if (value["component"]) { const component = componentParseCache.get(index); assert(component !== undefined, `Internal error, component parse cache missing entry [${index}]`); // Gitlab allows two different file paths to include a component const files = [`${component.name}.yml`, `${component.name}/template.yml`]; let file = null; for (const f of files) { let searchPath = `${cwd}/${f}`; if (!component.isLocal) { searchPath = `${cwd}/${stateDir}/includes/${gitData.remote.host}/${component.projectPath}/${component.ref}/${f}`; } if (fs.existsSync(searchPath)) { file = searchPath; } } assert(file !== null, `This GitLab CI configuration is invalid: component: \`${value["component"]}\`. One of the files [${files}] must exist in \`${component.domain}` + (component.port ? `:${component.port}` : "") + `/${component.projectPath}\``); const fileDoc = await Parser.loadYaml(file, { inputs: value.inputs || {} }, expandVariables); // Expand local includes inside to a "project"-like include fileDoc["include"] = this.expandInnerLocalIncludes(fileDoc["include"], component.projectPath, component.ref, opts); includeDatas = includeDatas.concat(await this.init(fileDoc, opts)); } 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; if (gitData.remote.schema == "git" || gitData.remote.schema == "ssh") { stdout = Utils.syncSpawn(["git", "ls-remote", "--tags", `git@${domain}:${projectPath}`]).stdout; } else { stdout = Utils.syncSpawn(["git", "ls-remote", "--tags", `${gitData.remote.schema}://${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, name: `templates/${gitRemoteMatch.groups["componentName"]}`, ref: ref, isLocal: isLocalComponent, }; } // Expand local includes inside to a "project"-like include static expandInnerLocalIncludes(fileIncludes, projectPath, ref, opts) { const { argv } = opts; const updatedIncludes = this.expandInclude(fileIncludes, opts.variables); updatedIncludes.forEach((inner, i) => { if (!inner["local"]) return; if (inner["rules"]) { const rulesResult = Utils.getRulesResult({ argv, cwd: opts.cwd, variables: opts.variables, rules: inner["rules"] }, opts.gitData); if (rulesResult.when === "never") { return; } } updatedIncludes[i] = { project: projectPath, file: inner["local"].replace(/^\//, ""), ref: ref, inputs: inner.inputs || {}, }; }); return updatedIncludes; } 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 axiosConfig = { headers: { "User-Agent": "gitlab-ci-local" }, ...Utils.getAxiosProxyConfig(), }; const res = await axios.get(url, axiosConfig); 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(/^\/+/, ""); let tmpDir = null; 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}`)); tmpDir = `${cwd}/${target}.${ext}`; 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 ${tmpDir}`, `cd ${tmpDir}`, `git sparse-checkout set --no-cone ${normalizedFile}`, "git checkout", `cd ${cwd}/${stateDir}`, `cp ${tmpDir}/${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}` }); } finally { if (tmpDir !== null) { // always cleanup temporary directory (if created) await fs.rm(tmpDir, { recursive: true, force: true }); } } } static async downloadIncludeComponent(cwd, stateDir, project, ref, componentName, gitData, fetchIncludes) { const remote = gitData.remote; const files = [`${componentName}.yml`, `${componentName}/template.yml`]; let tmpDir = null; try { const target = `${stateDir}/includes/${remote.host}/${project}/${ref}`; if (!fetchIncludes && (await fs.pathExists(`${cwd}/${target}/${files[0]}`) || await fs.pathExists(`${cwd}/${target}/${files[1]}`))) return; if (remote.schema.startsWith("http")) { const ext = "tmp-" + Math.random(); await fs.mkdirp(path.dirname(`${cwd}/${target}/templates`)); tmpDir = `${cwd}/${target}.${ext}`; 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 ${tmpDir}`, `cd ${tmpDir}`, `git sparse-checkout set --no-cone ${files[0]} ${files[1]}`, "git checkout", `cd ${cwd}/${stateDir}`, `mkdir -p ${tmpDir}/templates`, // create templates subdir (if it doesn't exist), as the check out may not create it `cp -r ${tmpDir}/templates ${cwd}/${target}`, ], cwd); } else { // git archive fails if the paths do not exist, to work around this we use a wildcard "templates/component*.yml" // this resolves to either "templates/component.yml" or "templates/component/template.yml" // if both exist "templates/component.yml" will be pulled // Drawback: also pulls all other .yml files from templates/component/ directory const componentWildcard = `${componentName}*.yml`; await fs.mkdirp(`${cwd}/${target}`); await Utils.bash(`set -eou pipefail; git archive --remote=ssh://git@${remote.host}:${remote.port}/${project}.git ${ref} ${componentWildcard} | tar -f - -xC ${target}/`, cwd); } } catch (e) { throw new AssertionError({ message: `Component include could not be fetched { project: ${project}, ref: ${ref}, file: ${files} }\n${e}` }); } finally { if (tmpDir !== null) { // always cleanup temporary directory (if created) await fs.rm(tmpDir, { recursive: true, force: true }); } } } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2VyLWluY2x1ZGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicGFyc2VyLWluY2x1ZGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBQyxLQUFLLEVBQUMsTUFBTSxZQUFZLENBQUM7QUFDakMsT0FBTyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRzFCLE9BQU8sTUFBTSxFQUFFLEVBQUMsY0FBYyxFQUFDLE1BQU0sUUFBUSxDQUFDO0FBQzlDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sYUFBYSxDQUFDO0FBQ25DLE9BQU8sS0FBMkIsTUFBTSxPQUFPLENBQUM7QUFDaEQsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUM1QixPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sT0FBTyxDQUFDO0FBdUI1QixNQUFNLE9BQU8sY0FBYztJQUNmLE1BQU0sQ0FBQyxLQUFLLEdBQVcsQ0FBQyxDQUFDO0lBRWpDLE1BQU0sQ0FBQyxVQUFVO1FBQ2IsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUVPLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBRSxVQUFlLEVBQUUsSUFBK0I7UUFDcEYsTUFBTSxFQUFDLFlBQVksRUFBQyxHQUFHLElBQUksQ0FBQztRQUM1QixLQUFLLE1BQU0sQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBTSxVQUFVLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUNyRSxJQUFJLE9BQU8sT0FBTyxDQUFDLE9BQU8sRUFBRSxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQy9DLE9BQU8sQ0FBQyxPQUFPLENBQUMsT0FBTyxHQUFHLENBQUM7d0JBQ3ZCLEtBQUssRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU87cUJBQ2pDLENB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LENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUNILE9BQU8sS0FBSyxDQUFDO0FBQ2pCLENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLG1CQUFtQixDQUFFLE9BQWUsRUFBRSxHQUFXO0lBQ25FLE1BQU0sU0FBUyxHQUFHLE1BQU0sY0FBYyxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRS9ELElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztRQUFFLE9BQU8sR0FBRyxJQUFJLE9BQU8sRUFBRSxDQUFDLENBQUMsaUNBQWlDO0lBQ3hGLE9BQU8sR0FBRyxHQUFHLEdBQUcsR0FBRyxPQUFPLEVBQUUsQ0FBQztJQUU3QiwwQ0FBMEM7SUFDMUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMscUJBQXFCLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFFekQsd0JBQXdCO0lBQ3hCLE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQztJQUN2QixPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFFakQsc0NBQXNDO0lBQ3RDLE1BQU0sc0JBQXNCLEdBQUcsVUFBVSxDQUFDO0lBQzFDLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxzQkFBc0IsQ0FBQyxDQUFDO0lBRTNELE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQzNDLE9BQU8sU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzFELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FyZ3Z9IGZyb20gXCIuL2FyZ3YuanNcIjtcbmltcG9ydCB7VXRpbHN9IGZyb20gXCIuL3V0aWxzLmpzXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzLWV4dHJhXCI7XG5pbXBvcnQge1dyaXRlU3RyZWFtc30gZnJvbSBcIi4vd3JpdGUtc3RyZWFtcy5qc1wiO1xuaW1wb3J0IHtHaXREYXRhfSBmcm9tIFwiLi9naXQtZGF0YS5qc1wiO1xuaW1wb3J0IGFzc2VydCwge0Fzc2VydGlvbkVycm9yfSBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQge1BhcnNlcn0gZnJvbSBcIi4vcGFyc2VyLmpzXCI7XG5pbXBvcnQgYXhpb3MsIHtBeGlvc1JlcXVlc3RDb25maWd9IGZyb20gXCJheGlvc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCBzZW12ZXIgZnJvbSBcInNlbXZlclwiO1xuaW1wb3J0IHtSRTJKU30gZnJvbSBcInJlMmpzXCI7XG5cbnR5cGUgUGFyc2VySW5jbHVkZXNJbml0T3B0aW9ucyA9IHtcbiAgICBhcmd2OiBBcmd2O1xuICAgIGN3ZDogc3RyaW5nO1xuICAgIHN0YXRlRGlyOiBzdHJpbmc7XG4gICAgd3JpdGVTdHJlYW1zOiBXcml0ZVN0cmVhbXM7XG4gICAgZ2l0RGF0YTogR2l0RGF0YTtcbiAgICBmZXRjaEluY2x1ZGVzOiBib29sZWFuO1xuICAgIHZhcmlhYmxlczoge1trZXk6IHN0cmluZ106IHN0cmluZ307XG4gICAgZXhwYW5kVmFyaWFibGVzOiBib29sZWFuO1xuICAgIG1heGltdW1JbmNsdWRlczogbnVtYmVyO1xufTtcblxudHlwZSBQYXJzZWRDb21wb25lbnQgPSB7XG4gICAgZG9tYWluOiBzdHJpbmc7XG4gICAgcG9ydDogc3RyaW5nO1xuICAgIHByb2plY3RQYXRoOiBzdHJpbmc7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIHJlZjogc3RyaW5nO1xuICAgIGlzTG9jYWw6IGJvb2xlYW47XG59O1xuXG5leHBvcnQgY2xhc3MgUGFyc2VySW5jbHVkZXMge1xuICAgIHByaXZhdGUgc3RhdGljIGNvdW50OiBudW1iZXIgPSAwO1xuXG4gICAgc3RhdGljIHJlc2V0Q291bnQgKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmNvdW50ID0gMDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBub3JtYWxpemVUcmlnZ2VySW5jbHVkZSAoZ2l0bGFiRGF0YTogYW55LCBvcHRzOiBQYXJzZXJJbmNsdWRlc0luaXRPcHRpb25zKSB7XG4gICAgICAgIGNvbnN0IHt3cml0ZVN0cmVhbXN9ID0gb3B0cztcbiAgICAgICAgZm9yIChjb25zdCBbam9iTmFtZSwgam9iRGF0YV0gb2YgT2JqZWN0LmVudHJpZXM8YW55PihnaXRsYWJEYXRhID8/IHt9KSkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBqb2JEYXRhLnRyaWdnZXI/LmluY2x1ZGUgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgICBqb2JEYXRhLnRyaWdnZXIuaW5jbHVkZSA9IFt7XG4gICAgICAgICAgICAgICAgICAgIGxvY2FsOiBqb2JEYXRhLnRyaWdnZXIuaW5jbHVkZSxcbiAgICAgICAgICAgICAgICB9IF07XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGpvYkRhdGEudHJpZ2dlcj8ucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIHdyaXRlU3RyZWFtcy5tZW1vU3Rkb3V0KGNoYWxrYHtiZ1llbGxvd0JyaWdodCAgV0FSTiB9IFRoZSBqb2I6IFxcYHtibHVlQnJpZ2h0ICR7am9iTmFtZX19XFxgIHdpbGwgYmUgbm8tb3AuIE11bHRpLXByb2plY3QgcGlwZWxpbmUgaXMgbm90IHN1cHBvcnRlZCBieSBnaXRsYWItY2ktbG9jYWxcXG5gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHN0YXRpYyBhc3luYyBpbml0IChnaXRsYWJEYXRhOiBhbnksIG9wdHM6IFBhcnNlckluY2x1ZGVzSW5pdE9wdGlvbnMpOiBQcm9taXNlPGFueVtdPiB7XG4gICAgICAgIGNvbnN0IHthcmd2fSA9IG9wdHM7XG4gICAgICAgIHRoaXMuY291bnQrKztcbiAgICAgICAgYXNzZXJ0KFxuICAgICAgICAgICAgdGhpcy5jb3VudCA8PSBvcHRzLm1heGltdW1JbmNsdWRlcyArIDEsIC8vIDFzdCBpbml0IGNhbGwgaXMgbm90IGNvdW50ZWRcbiAgICAgICAgICAgIGNoYWxrYFRoaXMgR2l0TGFiIENJIGNvbmZpZ3VyYXRpb24gaXMgaW52YWxpZDogTWF4aW11bSBvZiB7Ymx1ZUJyaWdodCAke29wdHMubWF4aW11bUluY2x1ZGVzfX0gbmVzdGVkIGluY2x1ZGVzIGFyZSBhbGxvd2VkIS4gVGhpcyBsaW1pdCBjYW4gYmUgaW5jcmVhc2VkIHdpdGggdGhlIC0tbWF4aW11bS1pbmNsdWRlcyBjbGkgZmxhZ3MuYCxcbiAgICAgICAgKTtcbiAgICAgICAgbGV0IGluY2x1ZGVEYXRhczogYW55W10gPSBbXTtcbiAgICAgICAgY29uc3QgcHJvbWlzZXMgPSBbXTtcbiAgICAgICAgY29uc3Qge3N0YXRlRGlyLCBjd2QsIGZldGNoSW5jbHVkZXMsIGdpdERhdGEsIGV4cGFuZFZhcmlhYmxlc30gPSBvcHRzO1xuICAgICAgICAvLyBjYWNoZSB0aGUgcGFyc2VkIGNvbXBvbmVudCwgYmVjYXVzZSBwYXJzZUluY2x1ZGVDb21wb25lbnQgaXMgZXhwZW5zaXZlIGFuZCB3ZSB3b3VsZCBjYWxsIGl0IHR3aWNlIG90aGVyd2lzZVxuICAgICAgICBjb25zdCBjb21wb25lbnRQYXJzZUNhY2hlID0gbmV3IE1hcDxudW1iZXIsIFBhcnNlZENvbXBvbmVudD4oKTtcblxuICAgICAgICBjb25zdCBpbmNsdWRlID0gdGhpcy5leHBhbmRJbmNsdWRlKGdpdGxhYkRhdGE/LmluY2x1ZGUsIG9wdHMudmFyaWFibGVzKTtcblxuICAgICAgICB0aGlzLm5vcm1hbGl6ZVRyaWdnZXJJbmNsdWRlKGdpdGxhYkRhdGEsIG9wdHMpO1xuICAgICAgICAvLyBGaW5kIGZpbGVzIHRvIGZldGNoIGZyb20gcmVtb3RlIGFuZCBwbGFjZSBpbiAuZ2l0bGFiLWNpLWxvY2FsL2luY2x1ZGVzXG4gICAgICAgIGZvciAoY29uc3QgW2luZGV4LCB2YWx1ZV0gb2YgaW5jbHVkZS5lbnRyaWVzKCkpIHtcbiAgICAgICAgICAgIGlmICh2YWx1ZVtcInJ1bGVzXCJdKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5jbHVkZV9ydWxlcyA9IHZhbHVlW1wicnVsZXNcIl07XG4gICAgICAgICAgICAgICAgY29uc3QgcnVsZXNSZXN1bHQgPSBVdGlscy5nZXRSdWxlc1Jlc3VsdCh7YXJndiwgY3dkLCBydWxlczogaW5jbHVkZV9ydWxlcywgdmFyaWFibGVzOiBvcHRzLnZhcmlhYmxlc30sIGdpdERhdGEpO1xuICAgICAgICAgICAgICAgIGlmIChydWxlc1Jlc3VsdC53aGVuID09PSBcIm5ldmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHZhbHVlW1wiZmlsZVwiXSkge1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgZmlsZVZhbHVlIG9mIEFycmF5LmlzQXJyYXkodmFsdWVbXCJmaWxlXCJdKSA/IHZhbHVlW1wiZmlsZVwiXSA6IFt2YWx1ZVtcImZpbGVcIl1dKSB7XG4gICAgICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2godGhpcy5kb3dubG9hZEluY2x1ZGVQcm9qZWN0RmlsZShjd2QsIHN0YXRlRGlyLCB2YWx1ZVtcInByb2plY3RcIl0sIHZhbHVlW1wicmVmXCJdIHx8IFwiSEVBRFwiLCBmaWxlVmFsdWUsIGdpdERhdGEsIGZldGNoSW5jbHVkZXMpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlW1widGVtcGxhdGVcIl0pIHtcbiAgICAgICAgICAgICAgICBjb25zdCB7cHJvamVjdCwgcmVmLCBmaWxlLCBkb21haW59ID0gdGhpcy5jb3ZlcnRUZW1wbGF0ZVRvUHJvamVjdEZpbGUodmFsdWVbXCJ0ZW1wbGF0ZVwiXSk7XG4gICAgICAgICAgICAgICAgY29uc3QgdXJsID0gYGh0dHBzOi8vJHtkb21haW59LyR7cHJvamVjdH0vLS9yYXcvJHtyZWZ9LyR7ZmlsZX1gO1xuICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2godGhpcy5kb3dubG9hZEluY2x1ZGVSZW1vdGUoY3dkLCBzdGF0ZURpciwgdXJsLCBmZXRjaEluY2x1ZGVzKSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlW1wicmVtb3RlXCJdKSB7XG4gICAgICAgICAgICAgICAgcHJvbWlzZXMucHVzaCh0aGlzLmRvd25sb2FkSW5jbHVkZVJlbW90ZShjd2QsIHN0YXRlRGlyLCB2YWx1ZVtcInJlbW90ZVwiXSwgZmV0Y2hJbmNsdWRlcykpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZVtcImNvbXBvbmVudFwiXSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGNvbXBvbmVudCA9IHRoaXMucGFyc2VJbmNsdWRlQ29tcG9uZW50KHZhbHVlW1wiY29tcG9uZW50XCJdLCBnaXREYXRhKTtcbiAgICAgICAgICAgICAgICBjb21wb25lbnRQYXJzZUNhY2hlLnNldChpbmRleCwgY29tcG9uZW50KTtcbiAgICAgICAgICAgICAgICBpZiAoIWNvbXBvbmVudC5pc0xvY2FsKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgcHJvbWlzZXMucHVzaCh0aGlzLmRvd25sb2FkSW5jbHVkZUNvbXBvbmVudChjd2QsIHN0YXRlRGlyLCBjb21wb25lbnQucHJvamVjdFBhdGgsIGNvbXBvbmVudC5yZWYsIGNvbXBvbmVudC5uYW1lLCBnaXREYXRhLCBmZXRjaEluY2x1ZGVzKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG5cbiAgICAgICAgZm9yIChjb25zdCBbaW5kZXgsIHZhbH