@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
102 lines • 4.6 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import { Flags as flags } from './flags.js';
import { ArgumentProcessor } from '../argument-processor.js';
import { container } from 'tsyringe-neo';
import { InjectTokens } from '../core/dependency-injection/inject-tokens.js';
/**
* Helper function to convert a flag object to CLI option string
* @param flag - The command flag
* @returns CLI option string (e.g., '--deployment')
*/
export function optionFromFlag(flag) {
return `--${flag.name}`;
}
/**
* Helper function to create base argv array for command execution
* @returns Base argv array
*/
export function newArgv() {
return ['${PATH}/node', '${SOLO_ROOT}/solo.ts'];
}
/**
* Helper function to append global flags to argv
* @param argv - The argument array to append to
* @param cacheDirectory - Optional cache directory path
* @returns Updated argv array
*/
export function argvPushGlobalFlags(argv, cacheDirectory = '') {
// Only propagate flags if they are explicitly set to true in the parent command
const configManager = container.resolve(InjectTokens.ConfigManager);
const developmentMode = configManager.getFlag(flags.devMode);
if (typeof developmentMode === 'boolean' && developmentMode) {
argv.push(optionFromFlag(flags.devMode));
}
const quiet = configManager.getFlag(flags.quiet);
if (typeof quiet === 'boolean' && quiet) {
argv.push(optionFromFlag(flags.quiet));
}
if (typeof cacheDirectory === 'string' && cacheDirectory.length > 0) {
argv.push(optionFromFlag(flags.cacheDir), cacheDirectory);
}
return argv;
}
/**
* Helper function to invoke a Solo command with proper task integration
* @param title - Task title to display
* @param commandName - Command name for task tracking
* @param callback - Function that returns the argv array
* @param taskList - TaskList instance for managing parent-child task relationships
* @param skipCallback - Optional function to determine if task should be skipped
* @returns Task object for Listr
*/
export function invokeSoloCommand(title, commandName, callback, taskList, skipCallback) {
return {
title,
skip: skipCallback || (() => false),
task: async (_context, taskListWrapper) => {
return taskListWrapper.newListr([
{
title,
task: async (_isolatedContext, isolatedTaskWrapper) => {
return subTaskSoloCommand(commandName, isolatedTaskWrapper, callback, taskList);
},
},
], {
ctx: {},
});
},
};
}
/**
* Helper function to execute a Solo command and return child tasks
* @param commandName - Command name for task tracking
* @param taskListWrapper - Task list wrapper from Listr
* @param callback - Function that returns the argv array
* @param taskList - TaskList instance for managing parent-child task relationships
* @returns Child tasks from command execution
*/
export async function subTaskSoloCommand(commandName, taskListWrapper, callback, taskList) {
// one-shot can launch the same subcommand name in parallel (for example in
// nested/parallel Listr branches). A single map slot per command name caused
// last-writer-wins behavior, where one invocation overwrote another and task
// output got attached to the wrong parent. Queueing preserves 1:1 pairing.
const taskNode = { taskListWrapper };
const pendingTaskNodes = taskList.parentTaskListMap.get(commandName) ?? [];
pendingTaskNodes.push(taskNode);
taskList.parentTaskListMap.set(commandName, pendingTaskNodes);
const newArgv = await callback();
const configManager = container.resolve(InjectTokens.ConfigManager);
const scopedConfig = configManager.cloneActiveConfig();
// Subcommands run in parallel during one-shot flows. values-file is component-specific
// and must come from each subcommand argv, not inherited from sibling command state.
delete scopedConfig.flags[flags.valuesFile.name];
// ArgumentProcessor/command handlers read and write config flags deeply via
// ConfigManager and Flags helpers. Running under a scoped copy keeps each
// subcommand immutable from the perspective of siblings and removes shared
// global-state races while still preserving existing call signatures.
await configManager.runWithScopedConfig(scopedConfig, async () => {
await ArgumentProcessor.process(newArgv);
});
return taskNode.children;
}
//# sourceMappingURL=command-helpers.js.map