import {awaitedBlockingMap} from '@augment-vir/common'; import {join} from 'node:path'; import {KillOn, runCommands, type Command, type Exit} from 'runstorm'; import {findLongestCommonPath} from '../../augments/path.js'; import {MonoCliInputError} from '../../cli/mono-cli-input.error.js'; import {type CommandInputs, type CommandOutput} from '../command.js'; import {getRelativePosixPackagePathTreeInDependencyOrder} from '../workspace-packages/get-package-dependency-order.js'; import {runForEachCommand} from './for-each.command.js'; /** * Run the command for each package in dependency order, running any packages not dependent on each * other in parallel. * * @category Internal */ export async function runForEachTreeCommand({ cwd, commandInputs, maxConcurrency, exclude, }: Readonly): Promise { if (maxConcurrency === 1) { return await runForEachCommand({cwd, commandInputs, exclude}); } const relativePackagePathsInOrder = await getRelativePosixPackagePathTreeInDependencyOrder( cwd, exclude, ); const shellCommand = commandInputs.join(' '); if (!shellCommand) { throw new MonoCliInputError(`No inputs were given to the for-each-tree command.`); } const commonPath = findLongestCommonPath(relativePackagePathsInOrder.flat()); const commandLayers = relativePackagePathsInOrder.map((layer) => { return layer.map((relativePackagePath): Omit => { return { command: shellCommand, cwd: join(cwd, relativePackagePath), name: relativePackagePath.replace(commonPath, '').replace(/^\//, ''), }; }); }); const exitCodes: Exit[] = []; let highestExitCode = 0; await awaitedBlockingMap(commandLayers, async (commandLayer) => { const result = await runCommands(commandLayer, { killOn: KillOn.Failure, maxConcurrency, }); exitCodes.push(...result.exitCodes); highestExitCode = Math.max(result.highestExitCode, highestExitCode); }); return { exitCodes, highestExitCode, }; }