UNPKG

@tunnckocore/execa

Version:

Thin layer on top of `execa` that allows executing multiple commands in parallel or in sequence with control for concurrency

124 lines (118 loc) 3.63 kB
import { execaCommand } from 'execa'; import pMap from 'p-map'; /** * Uses [execa][], `{ execaCommand }` method. * As stated there, think of it as mix of `child_process`'s `.execFile` and `.spawn`. * It is pretty similar to the `.shell` method too, but only visually because * it does not uses the system's shell, meaning it does not have access to * the system's environment variables. You also can control concurrency by * passing `options.concurrency` option. For example, pass `concurrency: 1` to run in series * instead of in parallel which is the default behavior. * * > It also can accept array of multiple strings of commands that will be * executed in series or in parallel (default). * * @example * import { exec } from '@tunnckocore/execa'; * // or * // const { exec } = require('@tunnckocore/execa'); * * async function main() { * await exec('echo "hello world"', { stdio: 'inherit' }); * * // executes in series (because `concurrency` option is set to `1`) * await exec([ * 'prettier-eslint --write foobar.js', * 'eslint --format codeframe foobar.js --fix' * ], { stdio: 'inherit', preferLocal: true, concurrency: 1 }); * } * * main(); * * @name .exec * @param {string|string[]} `cmds` a string or array of string commands to execute in parallel or series * @param {object} `[options]` directly passed to [execa][] and so to `child_process` * @return {Promise} resolved or rejected promises * @public */ export async function exec(cmds, options) { const commands = [cmds].flat().filter(Boolean); const { concurrency = Number.POSITIVE_INFINITY, ...opts } = { preferLocal: true, ...options, all: true, }; return pMap(commands, async (cmd) => execaCommand(cmd, opts), { concurrency, }); } /** * Similar to `exec`, but also **can** access the system's environment variables from the command. * * @example * import { shell } from '@tunnckocore/execa'; * // or * // const { shell } = require('@tunnckocore/execa'); * * async function main() { * // executes in series * await shell([ * 'echo unicorns', * 'echo "foo-$HOME-bar"', * 'echo dragons' * ], { stdio: 'inherit' }); * * // exits with code 3 * try { * await shell([ * 'exit 3', * 'echo nah' * ]); * } catch (er) { * console.error(er); * // => { * // message: 'Command failed: /bin/sh -c exit 3' * // killed: false, * // code: 3, * // signal: null, * // cmd: '/bin/sh -c exit 3', * // stdout: '', * // stderr: '', * // timedOut: false * // } * } * } * * main(); * * @name .shell * @param {string|string[]} cmds a commands to execute in parallel or series * @param {object} options directly passed to `execa` * @return {Promise} resolved or rejected promises * @public */ export async function shell(cmds, options) { return exec(cmds, { ...options, shell: true }); } /** * All [execa][] named exports, see its documentation. * Think of this as a mix of `child_process.execFile()` and `child_process.spawn()`. * * @example * import { execa, execaCommand, execaNode } from '@tunnckocore/execa'; * // or * // const { execa } = require('@tunnckocore/execa'); * * async function main() { * await execa('npm', ['install', '--save-dev', 'react'], { stdio: 'inherit' }); * } * * main(); * * @name .execa * @param {string} file executable to run * @param {Array<string>} args arguments / flags to be passed to `file` * @param {object} options optional options, passed to `child_process`'s methods * @public */ export * from 'execa';