From 33a5e38472ce8383cbf9fe8f1a4492c8dbb4cdc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Mon, 23 Dec 2024 09:20:02 -0800 Subject: [PATCH] Add async flavors for runCommand and runBuck2 utilities (#48371) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/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 --- packages/react-native-fantom/runner/runner.js | 4 +- packages/react-native-fantom/runner/utils.js | 76 +++++++++++++++++-- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/packages/react-native-fantom/runner/runner.js b/packages/react-native-fantom/runner/runner.js index eb46e4653a4cac..754b5a0f761155 100644 --- a/packages/react-native-fantom/runner/runner.js +++ b/packages/react-native-fantom/runner/runner.js @@ -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'; @@ -43,7 +43,7 @@ const BUILD_OUTPUT_PATH = fs.mkdtempSync( const PRINT_FANTOM_OUTPUT: false = false; -function parseRNTesterCommandResult(result: ReturnType): { +function parseRNTesterCommandResult(result: SyncCommandResult): { logs: $ReadOnlyArray, testResult: TestSuiteResult, } { diff --git a/packages/react-native-fantom/runner/utils.js b/packages/react-native-fantom/runner/utils.js index 4e426a10cdaee9..794f169c01fb80 100644 --- a/packages/react-native-fantom/runner/utils.js +++ b/packages/react-native-fantom/runner/utils.js @@ -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'; @@ -44,12 +44,61 @@ export function getBuckModesForPlatform( return ['@//xplat/mode/react-force-cxx-platform', osPlatform]; } -type SyncCommandResult = { - ...ReturnType, +export type AsyncCommandResult = { originalCommand: string, - ... + childProcess: ReturnType, + done: Promise, + 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, +): 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, @@ -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(), }; } @@ -95,7 +149,15 @@ export function getDebugInfoFromCommandResult( return logLines.join('\n'); } +export function runBuck2(args: Array): AsyncCommandResult { + return runCommand('buck2', processArgsForBuck(args)); +} + export function runBuck2Sync(args: Array): SyncCommandResult { + return runCommandSync('buck2', processArgsForBuck(args)); +} + +function processArgsForBuck(args: Array): Array { // 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. @@ -103,10 +165,10 @@ export function runBuck2Sync(args: Array): SyncCommandResult { // 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 {