UNPKG

@hashgraph/solo

Version:

An opinionated CLI tool to deploy and manage private Hedera Networks.

152 lines (129 loc) 5.43 kB
// SPDX-License-Identifier: Apache-2.0 import {SoloError} from '../errors/solo-error.js'; import {type AnyYargs, type ArgvStruct} from '../../types/aliases.js'; import {type SoloLogger} from '../logging/solo-logger.js'; import {type CommandDefinition} from '../../types/index.js'; import {type CommandFlags} from '../../types/flag-types.js'; import {Flags as flags} from '../../commands/flags.js'; import {inject, injectable} from 'tsyringe-neo'; import {InjectTokens} from '../dependency-injection/inject-tokens.js'; import {InitCommand} from '../../commands/init/init.js'; import {patchInject} from '../dependency-injection/container-helper.js'; import {type TaskList} from '../task-list/task-list.js'; import {ListrContext, ListrRendererValue} from 'listr2'; import * as constants from '../constants.js'; @injectable() export class Subcommand { // TODO: Subcommand should have its own class file public constructor( public readonly name: string, public readonly description: string, public readonly commandHandlerClass: any, public readonly commandHandler: (argv: ArgvStruct) => Promise<boolean>, public readonly flags: CommandFlags, public readonly dependencies: string[] = [], public readonly createCluster: boolean = false, @inject(InjectTokens.InitCommand) private readonly initCommand?: InitCommand, @inject(InjectTokens.TaskList) private readonly taskList?: TaskList<ListrContext, ListrRendererValue, ListrRendererValue>, ) { this.initCommand = patchInject(initCommand, InjectTokens.InitCommand, this.constructor.name); this.taskList = patchInject(taskList, InjectTokens.TaskList, this.constructor.name); } public async installDependencies(): Promise<void> { const tasks: any = this.taskList.newTaskList( [ ...this.initCommand.installDependenciesTasks({ deps: this.dependencies, createCluster: this.createCluster, }), ], constants.LISTR_DEFAULT_OPTIONS.DEFAULT, undefined, this.name, ); if (this.taskList.parentTaskListMap.size === 0) { try { await tasks.run(); } catch (error: Error | any) { throw new SoloError(`Could not install dependencies: ${error.message}`, error); } } } } // TODO: CommandGroup should have its own class file export class CommandGroup { public readonly subcommands: Subcommand[] = []; public constructor( public readonly name: string, public readonly description: string, ) {} public addSubcommand(subcommand: Subcommand): CommandGroup { this.subcommands.push(subcommand); return this; } } // TODO: CommandBuilder should have its own class file export class CommandBuilder { private readonly commandGroups: CommandGroup[] = []; public constructor( private readonly name: string, private readonly description: string, private readonly logger: SoloLogger, ) {} public addCommandGroup(commandGroup: CommandGroup): CommandBuilder { this.commandGroups.push(commandGroup); return this; } public build(): CommandDefinition { const commandGroups: CommandGroup[] = this.commandGroups; const logger: SoloLogger = this.logger; const commandName: string = this.name; const commandDescription: string = this.description; const demandCommand: string = `select a ${commandName} command`; return { command: commandName, desc: commandDescription, builder: (yargs: AnyYargs): AnyYargs => { for (const commandGroup of commandGroups) { yargs.command({ command: commandGroup.name, desc: commandGroup.description, builder: (yargs: AnyYargs): AnyYargs => { for (const subcommand of commandGroup.subcommands) { const handlerDefinition: CommandDefinition = { command: subcommand.name, desc: subcommand.description, handler: async (argv): Promise<void> => { const commandPath: string = `${commandName} ${commandGroup.name} ${subcommand.name}`; logger.info(`==== Running '${commandPath}' ===`); const handlerCallback: (argv: ArgvStruct) => Promise<boolean> = subcommand.commandHandler.bind( subcommand.commandHandlerClass, ); await subcommand.installDependencies(); const response: boolean = await handlerCallback(argv); logger.info(`==== Finished running '${commandPath}'====`); if (!response) { throw new SoloError(`Error running ${commandPath}, expected return value to be true`); } }, }; if (subcommand.flags) { handlerDefinition.builder = (y: AnyYargs): void => { flags.setRequiredCommandFlags(y, ...subcommand.flags.required); flags.setOptionalCommandFlags(y, ...subcommand.flags.optional); }; } yargs.command(handlerDefinition); } yargs.demandCommand(1, `Select a ${commandName} ${commandGroup.name} command`); return yargs; }, }); } yargs.demandCommand(1, demandCommand); return yargs; }, }; } }