Skip to content

Commit

Permalink
Add async flavors for runCommand and runBuck2 utilities (facebook#48371)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#48371

Changelog: [internal]

Adds a new favor for `runCommand` and `runBuck2` that works asynchronously and support parsing their output in real time.

Differential Revision: D67600614
  • Loading branch information
rubennorte authored and facebook-github-bot committed Dec 23, 2024
1 parent 29a9e03 commit 33a5e38
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 9 deletions.
4 changes: 2 additions & 2 deletions packages/react-native-fantom/runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/

import type {TestSuiteResult} from '../runtime/setup';
import type {ConsoleLogMessage} from './utils';
import type {ConsoleLogMessage, SyncCommandResult} from './utils';

import entrypointTemplate from './entrypoint-template';
import getFantomTestConfig from './getFantomTestConfig';
Expand Down Expand Up @@ -43,7 +43,7 @@ const BUILD_OUTPUT_PATH = fs.mkdtempSync(

const PRINT_FANTOM_OUTPUT: false = false;

function parseRNTesterCommandResult(result: ReturnType<typeof runBuck2Sync>): {
function parseRNTesterCommandResult(result: SyncCommandResult): {
logs: $ReadOnlyArray<ConsoleLogMessage>,
testResult: TestSuiteResult,
} {
Expand Down
76 changes: 69 additions & 7 deletions packages/react-native-fantom/runner/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* @oncall react_native
*/

import {spawnSync} from 'child_process';
import {spawn, spawnSync} from 'child_process';
import crypto from 'crypto';
import fs from 'fs';
import os from 'os';
Expand Down Expand Up @@ -44,12 +44,61 @@ export function getBuckModesForPlatform(
return ['@//xplat/mode/react-force-cxx-platform', osPlatform];
}

type SyncCommandResult = {
...ReturnType<typeof spawnSync>,
export type AsyncCommandResult = {
originalCommand: string,
...
childProcess: ReturnType<typeof spawn>,
done: Promise<AsyncCommandResult>,
pid: number,
status: ?number,
signal: ?string,
error: ?Error,
};

export type SyncCommandResult = {
originalCommand: string,
pid: number,
status: number,
signal: ?string,
error: ?Error,
stdout: string,
stderr: string,
};

export function runCommand(
command: string,
args: Array<string>,
): AsyncCommandResult {
const childProcess = spawn(command, args, {
encoding: 'utf8',
env: {
...process.env,
PATH: `/usr/local/bin:${process.env.PATH ?? ''}`,
},
});

const result: AsyncCommandResult = {
childProcess,
done: new Promise(resolve => {
childProcess.on('close', (code: number, signal: string) => {
result.status = code;
result.signal = signal;
resolve(result);
});
}),
originalCommand: `${command} ${args.join(' ')}`,
pid: childProcess.pid,
status: null,
signal: null,
error: null,
};

childProcess.on('error', error => {
result.error = error;
});

return result;
}

export function runCommandSync(
command: string,
args: Array<string>,
Expand All @@ -63,8 +112,13 @@ export function runCommandSync(
});

return {
...result,
originalCommand: `${command} ${args.join(' ')}`,
pid: result.pid,
status: result.status,
signal: result.signal,
error: result.error,
stdout: result.stdout.toString(),
stderr: result.stderr.toString(),
};
}

Expand Down Expand Up @@ -95,18 +149,26 @@ export function getDebugInfoFromCommandResult(
return logLines.join('\n');
}

export function runBuck2(args: Array<string>): AsyncCommandResult {
return runCommand('buck2', processArgsForBuck(args));
}

export function runBuck2Sync(args: Array<string>): SyncCommandResult {
return runCommandSync('buck2', processArgsForBuck(args));
}

function processArgsForBuck(args: Array<string>): Array<string> {
// If these tests are already running from withing a buck2 process, e.g. when
// they are scheduled by a `buck2 test` wrapper, calling `buck2` again would
// cause a daemon-level deadlock.
// To prevent this - explicitly pass custom `--isolation-dir`. Reuse the same
// dir across tests (even running in different jest processes) to properly
// employ caching.
if (process.env.BUCK2_WRAPPER != null) {
args.unshift('--isolation-dir', BUCK_ISOLATION_DIR);
return ['--isolation-dir', BUCK_ISOLATION_DIR].concat(args);
}

return runCommandSync('buck2', args);
return args;
}

export function getShortHash(contents: string): string {
Expand Down

0 comments on commit 33a5e38

Please sign in to comment.