UNPKG

@j0nnyboi/amman

Version:

A modern mandatory toolbelt to help test solana SDK libraries and apps on a locally running validator.

308 lines 11.1 kB
#!/usr/bin/env node "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const amman_client_1 = require("@j0nnyboi/amman-client"); const assert_1 = require("assert"); const child_process_1 = require("child_process"); const path_1 = __importDefault(require("path")); const helpers_1 = require("yargs/helpers"); const yargs_1 = __importDefault(require("yargs/yargs")); const storage_1 = require("../storage"); const utils_1 = require("../utils"); const http_1 = require("../utils/http"); const commands_1 = require("./commands"); const utils_2 = require("./utils"); const commands = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv)) // ----------------- // start // ----------------- .command('start', 'Launches a solana-test-validator and the amman relay and/or mock storage if so configured', (args) => { return args .positional('config', { describe: 'File containing config with `validator` property along with options for the relay and storage.', type: 'string', demandOption: false, }) .option('forceClone', { alias: 'f', describe: 'Whether or not to force updating the programs from on chain', type: 'boolean', default: false, }) .option('load', { alias: 'l', describe: 'Label of the snapshot to load from snapshots folder', type: 'string', }) .help('help', (0, commands_1.startHelp)()); }) // ----------------- // stop // ----------------- .command('stop', 'Stops the relay and storage and kills the running solana test validator') // ----------------- // logs // ----------------- .command('logs', `Launches 'solana logs' and pipes them through a prettifier`) // ----------------- // airdrop // ----------------- .command('airdrop', 'Airdrops provided Sol to the payer', (args) => args .positional('destination', { describe: 'A base58 PublicKey string or the relative path to the Keypair file of the airdrop destination', type: 'string', }) .positional('amount', { describe: 'The amount of Sol to airdrop', type: 'number', default: 1, }) .option('label', { alias: 'l', describe: 'The label to give to the account being airdropped to', type: 'string', default: 'payer', }) .option('commitment', { alias: 'c', describe: 'The commitment to use for the Airdrop transaction', type: 'string', choices: utils_1.commitments, default: 'singleGossip', }) .help('help', (0, commands_1.airdropHelp)())) // ----------------- // label // ----------------- .command('label', 'Adds labels for accounts or transactions to amman', (args) => args.help('help', (0, commands_1.labelHelp)())) // ----------------- // account // ----------------- .command('account', 'Retrieves account information for a PublicKey or a label or shows all labeled accounts', (args) => args .positional('address', { describe: 'A base58 PublicKey string or the label of the acount to retrieve.' + ' If it is not provided, all labeled accounts are shown.', type: 'string', demandOption: false, }) .option('includeTx', { alias: 't', describe: 'If to include transactions in the shown labeled accounts when no label/address is provided', type: 'boolean', default: false, }) .option('save', { alias: 's', describe: 'If set the account information is saved to a file inside ./.amman/accounts', type: 'boolean', default: false, })) // ----------------- // snapshot // ----------------- .command('snapshot', 'Creates a snapshot of the current accounts known to amman', (args) => { args.positional('label', { describe: 'The label to give to the snapshot. Default label is the account address.', type: 'string', demandOption: false, }); }) // ----------------- // run // ----------------- .command('run', 'Executes the provided command after expanding all address labels', (args) => args .option('label', { alias: 'l', describe: 'Used to label addresses found int the command output ', type: 'string', multiple: true, demandOption: false, }) .option('txOnly', { alias: 't', describe: 'Includes only transaction addresses when labeling.', type: 'string', demandOption: false, default: false, }) .option('accOnly', { alias: 'a', describe: 'Includes only account addresses when labeling.', type: 'string', demandOption: false, default: false, }) .help('help', (0, commands_1.runHelp)())); async function main() { var _a, _b; setupGracefulShutdown(); const args = await commands.parse(); const { _: cs } = args; if (cs.length === 0) { commands.showHelp(); return; } const command = cs[0]; switch (command) { // ----------------- // start // ----------------- case 'start': { const { needHelp } = await (0, commands_1.handleStartCommand)(args); if (needHelp) { (0, utils_1.logInfo)('Rerun `amman --help` for more information'); } break; } // ----------------- // stop // ----------------- case 'stop': { await stopAmman(); break; } // ----------------- // logs // ----------------- case 'logs': { (0, commands_1.handleLogsCommand)(); break; } // ----------------- // airdrop // ----------------- case 'airdrop': { const { commitment, label } = args; try { const destination = cs[1]; const maybeAmount = cs[2]; const amount = maybeAmount == null ? 1 : typeof maybeAmount === 'string' ? parseInt(maybeAmount) : maybeAmount; (0, assert_1.strict)(typeof destination === 'string', 'public key string or keypair file is required'); (0, assert_1.strict)(destination != null, 'public key string or keypair file is required'); (0, utils_1.assertCommitment)(commitment); const { connection } = await (0, commands_1.handleAirdropCommand)(destination, amount, label, commitment); await (0, utils_2.closeConnection)(connection, true); } catch (err) { (0, utils_1.logError)(err); commands.showHelp(); } break; } // ----------------- // label // ----------------- case 'label': { const labels = cs.slice(1); (0, assert_1.strict)(labels.length > 0, 'At least one label is required'); for (const label of labels) { (0, assert_1.strict)(typeof label == 'string', `All labels must be of type string 'label:publicKey' and ${label} is not`); } await (0, commands_1.handleLabelCommand)(labels); break; } // ----------------- // account // ----------------- case 'account': { const address = cs[1]; const { includeTx, save } = args; (0, assert_1.strict)(address == null || typeof address === 'string', 'provided public key or label needs to be a string'); (0, assert_1.strict)(!includeTx || address == null, '--includeTx can only be used when no address is provided'); (0, assert_1.strict)(!save || address != null, '--save requires an account address or label to be provided'); const { connection, rendered, savedAccountPath } = await (0, commands_1.handleAccountCommand)(address, includeTx, save); console.log(rendered); if (savedAccountPath != null) { (0, utils_1.logInfo)(`Saved account to ./${path_1.default.relative(process.cwd(), savedAccountPath)}`); } if (connection != null) { await (0, utils_2.closeConnection)(connection, true); } disconnectAmman(); break; } // ----------------- // snapshot // ----------------- case 'snapshot': { const label = (_a = cs[1]) === null || _a === void 0 ? void 0 : _a.toString(); const snapshotDir = await (0, commands_1.handleSnapshotCommand)(label); (0, utils_1.logInfo)(`Saved snapshot to ./${path_1.default.relative(process.cwd(), snapshotDir)}`); disconnectAmman(); break; } // ----------------- // run // ----------------- case 'run': { let labels = (_b = args.label) !== null && _b !== void 0 ? _b : []; if (!Array.isArray(labels)) { labels = [labels]; } const { txOnly, accOnly } = args; const cmdArgs = cs.slice(1); (0, assert_1.strict)(cmdArgs.length > 0, 'At least one argument is required or did you mean to `amman start`?'); try { const { stdout, stderr } = await (0, commands_1.handleRunCommand)(labels, cmdArgs, txOnly, accOnly); console.error(stderr); console.log(stdout); } catch (err) { (0, utils_1.logError)(err.toString()); } break; } default: commands.showHelp(); } } async function disconnectAmman(connection) { var _a, _b, _c; try { (_a = amman_client_1.Amman.existingInstance) === null || _a === void 0 ? void 0 : _a.disconnect(); (_b = amman_client_1.Amman.existingInstance) === null || _b === void 0 ? void 0 : _b.destroy(); } catch (_) { } try { (_c = storage_1.MockStorageServer.existingInstance) === null || _c === void 0 ? void 0 : _c.stop(); } catch (_) { } if (connection != null) { try { await (0, utils_2.closeConnection)(connection, true); } catch (_) { } } } async function stopAmman() { try { (0, child_process_1.execSync)('pkill -f solana-test-validator'); (0, utils_1.logInfo)('Killed currently running solana-test-validator'); } catch (_) { } try { await (0, http_1.killRunningServer)(amman_client_1.AMMAN_RELAY_PORT); } catch (_) { } try { await (0, http_1.killRunningServer)(amman_client_1.AMMAN_STORAGE_PORT); } catch (_) { } } function setupGracefulShutdown() { process.on('beforeExit', () => { disconnectAmman(); }); } main().catch((err) => { (0, utils_1.logError)(err); process.exit(1); }); //# sourceMappingURL=amman.js.map