@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
JavaScript
;
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}`);
}
});