UNPKG

@memlab/cli

Version:

command line interface for memlab

186 lines (185 loc) 7.92 kB
"use strict"; /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format * @oncall memory_lab */ 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.CommandDispatcher = void 0; const core_1 = require("@memlab/core"); const HelperCommand_1 = __importDefault(require("./commands/helper/HelperCommand")); const UniversalOptions_1 = __importDefault(require("./options/lib/UniversalOptions")); const CommandLoader_1 = __importDefault(require("./CommandLoader")); const helperCommand = new HelperCommand_1.default(); class CommandDispatcher { constructor(options = {}) { var _a; this.resetData(); // auto load all command modules const commandLoader = (_a = options.commandLoader) !== null && _a !== void 0 ? _a : new CommandLoader_1.default(); this.modules = commandLoader.getModules(); } resetData() { this.executedCommands = new Set(); this.executingCommandStack = []; } dispatch(args) { return __awaiter(this, void 0, void 0, function* () { this.resetData(); // triggered by `memlab` (without specific command) if (!args._ || !(args._.length >= 1)) { core_1.info.error('\n command argument missing'); yield this.helper(args); return; } const command = args._[0]; // invalid command, e.g., `memlab xyz` if (!this.modules.has(command)) { yield this.helper(args); return; } // `memlab <COMMAND> <SUB-COMMAND> -h` if (args.h || args.help) { yield this.helper(args); return; } // `memlab help <COMMAND> <SUB-COMMAND>` if (command === helperCommand.getCommandName()) { yield this.helper(Object.assign(Object.assign({}, args), { _: args._.slice(1) })); return; } const module = this.modules.get(command); this.executedCommands = new Set(); this.executingCommandStack = []; yield this.runCommand(module, args); }); } parseOptions(command, config, args) { return __awaiter(this, void 0, void 0, function* () { const options = [...UniversalOptions_1.default, ...command.getOptions()]; const configFromOptions = Object.create(null); for (const option of options) { const ret = yield option.run(config, args); if (ret) { this.mergeConfigFromOptions(configFromOptions, ret); } } return configFromOptions; }); } mergeConfigFromOptions(to, from) { for (const key in from) { if (Array.isArray(to[key]) && Array.isArray(from[key])) { // both are arrays, merge them this.mergeArrays(to[key], from[key]); } else if (from[key] == null || to[key] == null) { // one of them is null, use the other one to[key] = to[key] || from[key]; } else { // both have existing values, first one wins core_1.info.warning(`Merge conflict CLI options key: ${key}`); } } return to; } mergeArrays(arr1, arr2) { if (arr1 == null) { return arr2; } if (arr2 == null) { return arr1; } for (const v of arr2) { arr1.push(v); } return arr1; } runCommand(command_1, args_1) { return __awaiter(this, arguments, void 0, function* (command, args, runCmdOpt = { configFromOptions: {} }) { var _a; const commandName = command.getCommandName(); // make sure commands on the prerequisite are only executed once if (this.executedCommands.has(commandName)) { return; } this.executingCommandStack.push(commandName); // execute prerequisites const prerequisites = command.getPrerequisites(); for (const prereq of prerequisites) { const prereqName = prereq.getCommandName(); if (this.executingCommandStack.indexOf(prereqName) > 0) { throw new Error(`circular prerequisite reference: ${commandName} <--> ${prereqName}`); } yield this.runCommand(prereq, args, Object.assign({ isPrerequisite: true }, runCmdOpt)); } // parse command line options const c = yield this.parseOptions(command, core_1.config, args); Object.assign(runCmdOpt.configFromOptions, c); const { configFromOptions } = runCmdOpt; // execute command yield command.run({ cliArgs: args, configFromOptions }); // recommand CLI command and flags core_1.config.setRunInfo('command', process.argv.slice(2).join(' ')); if (runCmdOpt.isPrerequisite !== true) { // execute subcommands const commandIndex = ((_a = runCmdOpt.commandIndex) !== null && _a !== void 0 ? _a : 0) + 1; const runSubCmdOpt = Object.assign(Object.assign({}, runCmdOpt), { commandIndex }); yield this.runSubCommandIfAny(command, args, runSubCmdOpt); } this.executingCommandStack.pop(); this.executedCommands.add(commandName); }); } runSubCommandIfAny(command, args, runCmdOpt) { return __awaiter(this, void 0, void 0, function* () { var _a; const subCommandIndex = (_a = runCmdOpt.commandIndex) !== null && _a !== void 0 ? _a : 0; if (args._.length <= subCommandIndex) { return; } const subCommands = command.getSubCommands(); // if the command will handle the sub-commands by itself if (subCommands == null) { return; } for (const subCommand of subCommands) { if (subCommand.getCommandName() === args._[subCommandIndex]) { yield this.runCommand(subCommand, args, runCmdOpt); return; } } core_1.info.error(`Invalid sub-command \`${args._[subCommandIndex]}\` of \`${command.getCommandName()}\`\n`); yield this.helper(args, command); }); } helper(cliArgs_1) { return __awaiter(this, arguments, void 0, function* (cliArgs, command = null) { yield helperCommand.run({ modules: this.modules, command, cliArgs, indent: ' ', }); }); } } exports.CommandDispatcher = CommandDispatcher; exports.default = new CommandDispatcher();