UNPKG

@zombienet/cli

Version:

ZombieNet aim to be a testing framework for substrate based blockchains, providing a simple cli tool that allow users to spawn and test ephemeral Substrate based networks

274 lines (273 loc) • 13.3 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.setup = setup; const utils_1 = require("@zombienet/utils"); const cli_progress_1 = __importDefault(require("cli-progress")); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const debug = require("debug")("zombie-cli::setup"); const POLKADOT_SDK = "polkadot-sdk"; const POLKADOT = "polkadot"; const POLKADOT_PREPARE_WORKER = "polkadot-prepare-worker"; const POLKADOT_EXECUTE_WORKER = "polkadot-execute-worker"; const POLKADOT_PARACHAIN = "polkadot-parachain"; const POSSIBLE_BINARIES = [POLKADOT, POLKADOT_PARACHAIN]; const POLKADOT_WORKERS = [POLKADOT_PREPARE_WORKER, POLKADOT_EXECUTE_WORKER]; const options = {}; /** * Setup - easily download latest artifacts and make them executable in order to use them with zombienet * Read more here: https://paritytech.github.io/zombienet/cli/setup.html * @param params binaries that willbe downloaded and set up. Possible values: `polkadot` `polkadot-parachain` * @param opts Options from cli, currently only support `yes` to bypass the confirmation to download the binaries * @returns */ function setup(params, opts) { return __awaiter(this, void 0, void 0, function* () { // If the platform is MacOS (intel) then the repos needs to be cloned and run locally by the user // as polkadot and/or polkadot-parachain do not release a valid binaries for MacOS if (process.platform === "darwin" && process.arch !== "arm64") { console.log(`${utils_1.decorators.red("\n\n------------------------------------------------------------------------\n\nNote: ")} You are using MacOS (intel). Please, clone Polkadot SDK from ` + utils_1.decorators.cyan("https://github.com/paritytech/polkadot-sdk") + ` \n in order to build the polkadot and/or polkadot-parachain locally.\n At the moment there is no binaries for MacOs as releases.` + utils_1.decorators.red(`\n\n------------------------------------------------------------------------`)); return; } console.log(utils_1.decorators.green("\n\n🧟🧟🧟 ZombieNet Setup 🧟🧟🧟\n\n")); if (!isValidHost()) { console.log("Zombienet setup currently supports only linux(x64) and MacOS (arm64). \n Alternative, you can use k8s or podman. For more read here: https://github.com/paritytech/zombienet#requirements-by-provider"); return; } console.log(utils_1.decorators.green("Gathering latest releases' versions...\n")); const arch_sufix = process.arch === "arm64" ? "aarch64-apple-darwin" : ""; const allReleases = yield getAllReleases(POLKADOT_SDK); yield new Promise((resolve) => { latestPolkadotReleaseURL(POLKADOT_SDK, `${POLKADOT}${arch_sufix ? "-" + arch_sufix : ""}`, allReleases).then((res) => { options[POLKADOT] = { name: POLKADOT, url: res[0], size: res[1], }; resolve(); }); }); yield new Promise((resolve) => { latestPolkadotReleaseURL(POLKADOT_SDK, `${POLKADOT_PREPARE_WORKER}${arch_sufix ? "-" + arch_sufix : ""}`, allReleases).then((res) => { options[POLKADOT_PREPARE_WORKER] = { name: POLKADOT_PREPARE_WORKER, url: res[0], size: res[1], }; resolve(); }); }); yield new Promise((resolve) => { latestPolkadotReleaseURL(POLKADOT_SDK, `${POLKADOT_EXECUTE_WORKER}${arch_sufix ? "-" + arch_sufix : ""}`, allReleases).then((res) => { options[POLKADOT_EXECUTE_WORKER] = { name: POLKADOT_EXECUTE_WORKER, url: res[0], size: res[1], }; resolve(); }); }); yield new Promise((resolve) => { latestPolkadotReleaseURL(POLKADOT_SDK, `${POLKADOT_PARACHAIN}${arch_sufix ? "-" + arch_sufix : ""}`, allReleases).then((res) => { options[POLKADOT_PARACHAIN] = { name: POLKADOT_PARACHAIN, url: res[0], size: res[1], }; resolve(); }); }); if (params[0] === "all") { params = [POLKADOT, POLKADOT_PARACHAIN]; } if (params.length === 0) { console.log(utils_1.decorators.green("No binaries to download. Exiting...")); return; } let count = 0; console.log("Setup will start to download binaries:"); params.forEach((a) => { var _a, _b; if (!POSSIBLE_BINARIES.includes(a)) { params = params.filter((param) => param !== a); console.log(utils_1.decorators.red(`"${a}" is not one of the possible options for this setup and will be skipped;`), utils_1.decorators.green(` Valid options: 'polkadot', 'polkadot-parachain', 'all'`)); return; } let size = 0; if (a === POLKADOT) { size = parseInt(((_a = options[a]) === null || _a === void 0 ? void 0 : _a.size) || "0", 10); count += size; console.log("-", a, "\t\t\t Approx. size ", size, " MB"); POLKADOT_WORKERS.forEach((b) => { var _a; params.push(b); size = parseInt(((_a = options[b]) === null || _a === void 0 ? void 0 : _a.size) || "0", 10); count += size; console.log("-", b, "\t Approx. size ", size, " MB"); }); } else { size = parseInt(((_b = options[a]) === null || _b === void 0 ? void 0 : _b.size) || "0", 10); count += size; console.log("-", a, "\t\t Approx. size ", size, " MB"); } }); console.log("Total approx. size:\t\t\t ", count, "MB"); if (!(opts === null || opts === void 0 ? void 0 : opts.yes)) { const response = yield (0, utils_1.askQuestion)(utils_1.decorators.yellow("\nDo you want to continue? (y/n)")); if (response.toLowerCase() !== "n" && response.toLowerCase() !== "y") { console.log("Invalid input. Exiting..."); return; } if (response.toLowerCase() === "n") { return; } } downloadBinaries(params); return; }); } // helper fns // Check if the host is a valid platform/arch const isValidHost = () => { const isValid = process.platform === "linux" && process.arch === "x64" ? true : process.platform === "darwin" && process.arch === "arm64" ? true : false; return isValid; }; // Download the binaries const downloadBinaries = (binaries) => __awaiter(void 0, void 0, void 0, function* () { try { console.log(utils_1.decorators.yellow("\nStart download...\n")); const promises = []; const multibar = new cli_progress_1.default.MultiBar({ clearOnComplete: false, hideCursor: true, format: utils_1.decorators.yellow("{bar} - {percentage}%") + " | " + utils_1.decorators.cyan("Binary name:") + " {filename}", }, cli_progress_1.default.Presets.shades_grey); debug("Download info:", options); for (const binary of binaries) { promises.push(new Promise((resolve) => __awaiter(void 0, void 0, void 0, function* () { var _a; const result = options[binary]; if (!result) { console.log("options", options, "binary", binary); throw new Error("Binary is not defined"); } const { url, name } = result; const filepath = path_1.default.resolve(name); if (!url) throw new Error("No url for downloading, was provided"); const response = yield fetch(url); if (!response.ok) throw Error(response.status + " " + response.statusText); const contentLength = response.headers.get("content-length"); let loaded = 0; const progressBar = multibar.create(parseInt(contentLength, 10), 0); const reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader(); const writer = fs_1.default.createWriteStream(filepath); let i = true; while (i) { const read = yield (reader === null || reader === void 0 ? void 0 : reader.read()); if (read === null || read === void 0 ? void 0 : read.done) { writer.close(); i = false; resolve(); } if (read === null || read === void 0 ? void 0 : read.value) { loaded += read.value.length; progressBar.increment(); progressBar.update(loaded, { filename: name, }); writer.write(read.value); } } // make the file exec yield fs_1.default.promises.chmod(filepath, 755); }))); } yield Promise.all(promises); multibar.stop(); console.log(utils_1.decorators.cyan(`\n\nPlease add the current dir to your $PATH by running the command:\n`), utils_1.decorators.blue(`export PATH=${process.cwd()}:$PATH\n\n`)); // set exit code process.exitCode = 0; } catch (err) { console.log(`\n ${utils_1.decorators.red("Unexpected error: ")} \t ${utils_1.decorators.bright(err)}\n`); } }); const getAllReleases = (repo) => __awaiter(void 0, void 0, void 0, function* () { // allow to read releases from file if (process.env.ZOMBIE_RELEASES_FILE) { const content = yield fs_1.default.promises.readFile(process.env.ZOMBIE_RELEASES_FILE); return JSON.parse(content.toString()); } const release_url = `https://api.github.com/repos/paritytech/${repo}/releases`; debug(`release url: ${release_url}`); const headers = { Accept: "application/vnd.github+json", }; if (process.env.GH_TOKEN) { headers["Authorization"] = `Bearer ${process.env.GH_TOKEN}`; } const releases = yield fetch(`https://api.github.com/repos/paritytech/${repo}/releases`, headers); const allReleases = yield releases.json(); if (process.env.ZOMBIE_TRACE) { debug(`all releases: \n ${JSON.stringify(allReleases)}`); } return allReleases; }); // Retrieve the latest release for polkadot const latestPolkadotReleaseURL = (repo, name, allReleases) => __awaiter(void 0, void 0, void 0, function* () { var _a; try { let obj; const release = allReleases.find((r) => { var _a; obj = (_a = r === null || r === void 0 ? void 0 : r.assets) === null || _a === void 0 ? void 0 : _a.find((a) => a.name === name); return Boolean(obj); }); if (!release) { throw Error(`In repo '${repo}', there is no release for: '${name}'! Exiting...`); } const { tag_name } = release; if (!tag_name) { throw new Error("Should never come to this point. Tag_name should never be undefined!"); } return [obj.browser_download_url, (0, utils_1.convertBytes)(obj.size)]; } catch (err) { if (err.code === "ENOTFOUND") { throw new Error("Network error."); } else if (err.response && err.response.status === 404) { throw new Error("Could not find a release. Error 404 (not found) detected"); } else if (err.response) { throw new Error(`Error status: ${(_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.status}. Error message: ${err === null || err === void 0 ? void 0 : err.response}`); } // fallthrough throw new Error(`Error: ${err}`); } });