Skip to content

Commit

Permalink
Add result.durationMs
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Aug 23, 2024
1 parent d95242e commit 565f3c7
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 5 deletions.
13 changes: 8 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import {spawn} from 'node:child_process';
import {once} from 'node:events';
import process from 'node:process';
import {finished} from 'node:stream/promises';
import {lineIterator, combineAsyncIterators} from './utilities.js';

export default function nanoSpawn(command, commandArguments = [], options = {}) {
[commandArguments, options] = Array.isArray(commandArguments)
? [commandArguments, options]
: [[], commandArguments];
const start = process.hrtime.bigint();

const subprocess = spawn(command, commandArguments, getOptions(options));

const promise = getResult(subprocess);
const promise = getResult(subprocess, start);

const stdoutLines = lineIterator(subprocess.stdout);
const stderrLines = lineIterator(subprocess.stderr);
Expand All @@ -33,20 +35,20 @@ const getOptions = ({
stdio,
});

const getResult = async subprocess => {
const getResult = async (subprocess, start) => {
const result = {};
const onExit = waitForExit(subprocess);
const onStdoutDone = bufferOutput(subprocess.stdout, result, 'stdout');
const onStderrDone = bufferOutput(subprocess.stderr, result, 'stderr');

try {
await Promise.all([onExit, onStdoutDone, onStderrDone]);
const output = getOutput(subprocess, result);
const output = getOutput(subprocess, result, start);
checkFailure(output);
return output;
} catch (error) {
await Promise.allSettled([onExit, onStdoutDone, onStderrDone]);
throw Object.assign(error, getOutput(subprocess, result));
throw Object.assign(error, getOutput(subprocess, result, start));
}
};

Expand Down Expand Up @@ -80,12 +82,13 @@ const bufferOutput = async (stream, result, streamName) => {
await finished(stream, {cleanup: true});
};

const getOutput = ({exitCode, signalCode}, {stdout, stderr}) => ({
const getOutput = ({exitCode, signalCode}, {stdout, stderr}, start) => ({
// `exitCode` can be a negative number (`errno`) when the `error` event is emitted on the subprocess
...(exitCode === null || exitCode < 0 ? {} : {exitCode}),
...(signalCode === null ? {} : {signalName: signalCode}),
stdout: stripNewline(stdout),
stderr: stripNewline(stderr),
durationMs: Number(process.hrtime.bigint() - start) / 1e6,
});

const stripNewline = input => input?.at(-1) === '\n'
Expand Down
12 changes: 12 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,18 @@ test('Handles stderr error', async t => {
t.is(await t.throwsAsync(promise), error);
});

test('result.durationMs is set', async t => {
const {durationMs} = await nanoSpawn('node', ['--version']);
t.true(Number.isFinite(durationMs));
t.true(durationMs > 0);
});

test('error.durationMs is set', async t => {
const {durationMs} = await t.throwsAsync(nanoSpawn('node', ['--unknown']));
t.true(Number.isFinite(durationMs));
t.true(durationMs > 0);
});

if (isWindows) {
test('Can run .exe file', async t => {
t.is(path.extname(process.execPath), '.exe');
Expand Down

0 comments on commit 565f3c7

Please sign in to comment.